diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 9499bb9b7..41efcee5a 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -98,7 +98,12 @@ extern "C" { /****************************************************************************/ /** - * Function return values: OK or various error conditions + * Function return code: OK (0) or error results + * + * Fatal errors should be interpreted to mean that the node is no longer + * working correctly. They indicate serious problems such as build problems, + * an inaccessible data store, system configuration issues, or out of + * memory. */ enum ZT1_ResultCode { @@ -107,51 +112,101 @@ enum ZT1_ResultCode */ ZT1_RESULT_OK = 0, - /** - * Our identity collides with another on the network - * - * This is profoundly unlikely: once in about 2^39 identities. If this - * happens to you, delete identity.public and identity.secret from your - * data store / home path and restart. You might also avoid shark infested - * waters, hide during thunderstorms, and consider playing the lottery. - */ - ZT1_RESULT_ERROR_IDENTITY_COLLISION = 1, + // Fatal errors (>0, <1000) /** * Ran out of memory */ - ZT1_RESULT_ERROR_OUT_OF_MEMORY = 2, + ZT1_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 1, /** * Data store is not writable or has failed */ - ZT1_RESULT_ERROR_DATA_STORE_FAILED = 3, + ZT1_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 2, /** * Internal error (e.g. unexpected exception, build problem, link problem, etc.) */ - ZT1_RESULT_ERROR_INTERNAL = 4, + ZT1_RESULT_FATAL_ERROR_INTERNAL = 3, + + // Non-fatal errors (>1000) /** * Invalid packet or failed authentication */ - ZT1_RESULT_PACKET_INVALID = 5 + ZT1_RESULT_ERROR_PACKET_INVALID = 1000 }; /** * Status codes sent to status update callback when things happen */ -enum ZT1_NodeStatusCode +enum ZT1_Event { /** - * Node is offline -- nothing is reachable + * Node has been initialized + * + * This is the first event generated, and is always sent. It may occur + * before Node's constructor returns. */ - ZT1_NODE_STATUS_OFFLINE = 0, + ZT1_EVENT_UP = 0, /** - * Node is online -- at least one upstream is reachable + * Node is offline -- network does not seem to be reachable by any available strategy */ - ZT1_NODE_STATUS_ONLINE = 1 + ZT1_EVENT_OFFLINE = 1, + + /** + * Node is online -- at least one upstream node appears reachable + */ + ZT1_EVENT_ONLINE = 2, + + /** + * Node is shutting down + * + * This is generated within Node's destructor when it is being shut down. + * It's done for convenience, since cleaning up other state in the event + * handler may appear more idiomatic. + */ + ZT1_EVENT_DOWN = 3, + + /** + * Your identity has collided with another node's ZeroTier address + * + * This happens if two different public keys both hash (via the algorithm + * in Identity::generate()) to the same 40-bit ZeroTier address. + * + * This is something you should "never" see, where "never" is defined as + * once per 2^39 new node initializations / identity creations. If you do + * see it, you're going to see it very soon after a node is first + * initialized. + * + * This is reported as an event rather than a return code since it's + * detected asynchronously via error messages from authoritative nodes. + * + * If this occurs, you must shut down and delete the node, delete the + * identity.secret record/file from the data store, and restart to generate + * a new identity. If you don't do this, you will not be able to communicate + * with other nodes. + * + * We'd automate this process, but we don't think silently deleting + * private keys or changing our address without telling the calling code + * is good form. It violates the principle of least surprise. + * + * You can technically get away with not handling this, but we recommend + * doing so in a mature reliable application. Besides, handling this + * condition is a good way to make sure it never arises. It's like how + * umbrellas prevent rain and smoke detectors prevent fires. They do, right? + */ + ZT1_EVENT_FATAL_ERROR_IDENTITY_COLLISION = 4, + + /** + * A more recent version was observed on the network + * + * Right now this is only triggered if a hub or supernode reports a + * more recent version, and only once. It can be used to trigger a + * software update check. + */ + ZT1_EVENT_SAW_MORE_RECENT_VERSION = 5 }; /** @@ -487,7 +542,7 @@ typedef void (*ZT1_VirtualNetworkConfigCallback)(ZT1_Node *,uint64_t,const ZT1_V * * This is called whenever the node's status changes in some significant way. */ -typedef void (*ZT1_StatusCallback)(ZT1_Node *,enum ZT1_NodeStatusCode); +typedef void (*ZT1_StatusCallback)(ZT1_Node *,enum ZT1_Event); /** * Function to get an object from the data store @@ -576,6 +631,16 @@ enum ZT1_ResultCode ZT1_Node_new( ZT1_VirtualNetworkConfigCallback virtualNetworkConfigCallback, ZT1_StatusCallback statusCallback); +/** + * Delete a node and free all resources it consumes + * + * If you are using multiple threads, all other threads must be shut down + * first. This can crash if processXXX() methods are in progress. + * + * @param node Node to delete + */ +void ZT1_Node_delete(ZT1_Node *node); + /** * Process a packet received from the physical wire * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 28f6eb183..f63b33b21 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -38,8 +38,6 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Peer.hpp" -#include "NodeConfig.hpp" -#include "SoftwareUpdater.hpp" #include "NetworkConfigMaster.hpp" namespace ZeroTier { @@ -70,7 +68,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(verb()) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),verb(),0,Packet::VERB_NOP); return true; case Packet::VERB_HELLO: return _doHELLO(RR); case Packet::VERB_ERROR: return _doERROR(RR,peer); @@ -101,9 +99,9 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; - uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); - Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; + const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; + const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); + const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); @@ -111,10 +109,10 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_OBJ_NOT_FOUND: if (inReVerb == Packet::VERB_WHOIS) { - if (RR->topology->isSupernode(source())) + if (RR->topology->isSupernode(peer->address())) RR->sw->cancelWhoisRequest(Address(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH)); } else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - SharedPtr network(RR->nc->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == source())) network->setNotFound(); } @@ -122,32 +120,32 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_UNSUPPORTED_OPERATION: if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - SharedPtr network(RR->nc->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == source())) network->setNotFound(); } break; case Packet::ERROR_IDENTITY_COLLISION: - // TODO: if it comes from a supernode, regenerate a new identity - // if (RR->topology->isSupernode(source())) {} + if (RR->topology->isSupernode(peer->address())) + RR->node->postEvent(ZT1_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - SharedPtr network(RR->nc->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if (network) { SharedPtr nconf(network->config2()); if (nconf) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); nconf->com().serialize(outp); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } } break; case Packet::ERROR_NETWORK_ACCESS_DENIED_: { - SharedPtr network(RR->nc->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == source())) network->setAccessDenied(); } break; @@ -159,7 +157,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb); } catch (std::exception &ex) { TRACE("dropped ERROR from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -171,15 +169,20 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) { try { - unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; - unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; - unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; - unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); - uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - Identity id(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; + const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; + const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); + const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); + const Identity id(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + + if (source() != id.address()) { + TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -193,18 +196,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - LOG("rejected HELLO from %s(%s): address already claimed",source().toString().c_str(),_remoteAddress.toString().c_str()); - Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); + LOG("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_HELLO); outp.append(packetId()); outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } else { - LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str()); + LOG("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } } else { - LOG("rejected HELLO from %s(%s): key agreement failed",source().toString().c_str(),_remoteAddress.toString().c_str()); + LOG("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } return true; @@ -212,40 +215,41 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str()); + LOG("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } - // If packet was valid, continue below... + // Continue at // VALID } } else { // We don't already have an identity with this address -- validate and learn it if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } SharedPtr newPeer(new Peer(RR->identity,id)); if (!dearmor(newPeer->key())) { - LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str()); + LOG("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } peer = RR->topology->addPeer(newPeer); - // New peer learned, continue below... + // Continue at // VALID } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP,Utils::now()); + // VALID -- continues here + + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); - // If a supernode has a version higher than ours, this causes a software - // update check to run now. - if ((RR->updater)&&(RR->topology->isSupernode(peer->address()))) - RR->updater->sawRemoteVersion(vMajor,vMinor,vRevision); + // Won't get HELLO *from* supernodes, so skip this for now here. It's done in OK(HELLO). + //if (RR->topology->isSupernode(id.address())) + // RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); - Packet outp(source(),RR->identity.address(),Packet::VERB_OK); + Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_HELLO); outp.append(packetId()); outp.append(timestamp); @@ -254,11 +258,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } catch (std::exception &ex) { - TRACE("dropped HELLO from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); + TRACE("dropped HELLO from %s(%s): %s",id.address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { - TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): unexpected exception",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } return true; } @@ -266,19 +270,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; - uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; + const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { case Packet::VERB_HELLO: { - unsigned int latency = std::min((unsigned int)(Utils::now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP)),(unsigned int)0xffff); - unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; - unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; - unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; - unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); + const unsigned int latency = std::min((unsigned int)(RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP)),(unsigned int)0xffff); + const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; + const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; + const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); if (vProto < ZT_PROTO_VERSION_MIN) { TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); @@ -290,28 +294,26 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - // If a supernode has a version higher than ours, this causes a software - // update check to run now. - if ((RR->updater)&&(RR->topology->isSupernode(peer->address()))) - RR->updater->sawRemoteVersion(vMajor,vMinor,vRevision); + if (RR->topology->isSupernode(peer->address())) + RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); } break; case Packet::VERB_WHOIS: { // Right now only supernodes are allowed to send OK(WHOIS) to prevent // poisoning attacks. Further decentralization will require some other // kind of trust mechanism. - if (RR->topology->isSupernode(source())) { - Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); + if (RR->topology->isSupernode(peer->address())) { + const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); if (id.locallyValidate()) RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR->identity,id)))); } } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { - SharedPtr nw(RR->node->network(at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID))); - if ((nw)&&(nw->controller() == source())) { - unsigned int dictlen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); - std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen); + const SharedPtr nw(RR->node->network(at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID))); + if ((nw)&&(nw->controller() == peer->address())) { + const unsigned int dictlen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); + const std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen); if (dict.length()) { if (nw->setConfiguration(Dictionary(dict)) == 2) { // 2 == accepted and actually new /* If this configuration was indeed new, we do another @@ -325,16 +327,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p * versions <= 1.0.3, since those regenerate a new netconf * with a new revision every time. In that case this double * confirmation would create a race condition. */ - if ((peer->atLeastVersion(1,0,3))&&(nc->revision() > 0)) { - SharedPtr nc(nw->config2()); - if ((nc)&&(nc->timestamp() > 0)) { // sanity check - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append((uint64_t)nw->id()); - outp.append((uint16_t)0); // no meta-data - outp.append((uint64_t)nc->revision()); - outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); - } + const SharedPtr nc(nw->config2()); + if ((peer->atLeastVersion(1,0,3))&&(nc)&&(nc->revision() > 0)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append((uint64_t)nw->id()); + outp.append((uint16_t)0); // no meta-data + outp.append((uint64_t)nc->revision()); + outp.armor(peer->key(),true); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str()); @@ -343,20 +343,19 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } break; case Packet::VERB_MULTICAST_GATHER: { - uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),size()); - - unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(Utils::now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } break; case Packet::VERB_MULTICAST_FRAME: { - unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; - uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); - MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),flags); + TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),flags); unsigned int offset = 0; @@ -364,7 +363,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p // OK(MULTICAST_FRAME) includes certificate of membership update CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - SharedPtr network(RR->nc->network(nwid)); + SharedPtr network(RR->node->network(nwid)); if ((network)&&(com.hasRequiredFields())) network->addMembershipCertificate(com,false); } @@ -374,14 +373,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; unsigned int totalKnown = at(offset); offset += 4; unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(Utils::now(),nwid,mg,field(offset,count * 5),count,totalKnown); + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); } } break; default: break; } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb); } catch (std::exception &ex) { TRACE("dropped OK from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -394,14 +393,14 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr { try { if (payloadLength() == ZT_ADDRESS_LENGTH) { - SharedPtr queried(RR->topology->getPeer(Address(payload(),ZT_ADDRESS_LENGTH))); + const SharedPtr queried(RR->topology->getPeer(Address(payload(),ZT_ADDRESS_LENGTH))); if (queried) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); outp.append(packetId()); queried->identity().serialize(outp,false); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_WHOIS); @@ -409,12 +408,12 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(payload(),ZT_ADDRESS_LENGTH); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } else { TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str()); } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -437,30 +436,30 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< * So if we diversify relays, we'll need some way of deciding whether the * sender is someone we should trust with a RENDEZVOUS hint. */ - if (RR->topology->isSupernode(source())) { - Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - SharedPtr withPeer(RR->topology->getPeer(with)); + if (RR->topology->isSupernode(peer->address())) { + const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + const SharedPtr withPeer(RR->topology->getPeer(with)); if (withPeer) { - unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); - unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; + const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); + const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",source().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,Utils::now()); - RR->sw->contact(withPeer,atAddr); + TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); + RR->sw->contact(withPeer,atAddr,_linkDesperation); } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",source().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); } } else { - TRACE("ignored RENDEZVOUS from %s(%s): source not supernode",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s): source not supernode",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } } catch (std::exception &ex) { - TRACE("dropped RENDEZVOUS from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); + TRACE("dropped RENDEZVOUS from %s(%s): %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { - TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } return true; } @@ -468,7 +467,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - SharedPtr network(RR->nc->network(at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID))); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID))); if (network) { if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { if (!network->isAllowed(peer->address())) { @@ -477,17 +476,17 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr return true; } - unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); if (!network->config()->permitsEtherType(etherType)) { TRACE("dropped FRAME from %s(%s): ethertype %.4x not allowed on %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); return true; } - unsigned int payloadLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - network->tapPut(MAC(peer->address(),network->id()),network->mac(),etherType,field(ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); + const unsigned int payloadLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + RR->node->putFrame(network->id(),MAC(peer->address(),network->id()),network->mac(),etherType,0,field(ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP); } else { TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -502,10 +501,10 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - SharedPtr network(RR->nc->network(at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID))); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID))); if (network) { if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; + const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; unsigned int comLen = 0; if ((flags & 0x01) != 0) { @@ -524,7 +523,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); + const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); if (!network->config()->permitsEtherType(etherType)) { TRACE("dropped EXT_FRAME from %s(%s): ethertype %.4x not allowed on network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); return true; @@ -559,12 +558,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

tapPut(from,to,etherType,field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); + const unsigned int payloadLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); + RR->node->putFrame(network->id(),from,to,etherType,0,field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -579,13 +577,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&peer) { try { - uint64_t now = Utils::now(); + const uint64_t now = RR->node->now(); // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptrmc->add(now,at(ptr),MulticastGroup(MAC(field(ptr + 8,6),6),at(ptr + 14)),peer->address()); - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,now); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP); } catch (std::exception &ex) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -603,13 +601,13 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment while (ptr < size()) { ptr += com.deserialize(*this,ptr); if (com.hasRequiredFields()) { - SharedPtr network(RR->nc->network(com.networkId())); + SharedPtr network(RR->node->network(com.networkId())); if (network) network->addMembershipCertificate(com,false); } } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP); } catch (std::exception &ex) { TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -621,22 +619,20 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); - unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); - Dictionary metaData((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength),metaDataLength); - uint64_t haveRevision = 0; - if ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) - haveRevision = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength); + const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); + const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); + const Dictionary metaData((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength),metaDataLength); + const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL; const unsigned int h = hops(); - uint64_t pid = packetId(); - peer->received(RR,_fromSock,_remoteAddress,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,RR->node->now()); + const uint64_t pid = packetId(); + peer->received(RR,_remoteAddress,_linkDesperation,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); if (RR->netconfMaster) { Dictionary netconf; switch(RR->netconfMaster->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,peer->identity(),nwid,metaData,haveRevision,netconf)) { case NetworkConfigMaster::NETCONF_QUERY_OK: { - std::string netconfStr(netconf.toString()); + const std::string netconfStr(netconf.toString()); if (netconfStr.length() > 0xffff) { // sanity check since field ix 16-bit LOG("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length()); } else { @@ -650,7 +646,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { LOG("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length()); } else { - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } } break; @@ -663,7 +659,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(nwid); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } break; case NetworkConfigMaster::NETCONF_QUERY_ACCESS_DENIED: { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); @@ -672,7 +668,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); outp.append(nwid); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } break; case NetworkConfigMaster::NETCONF_QUERY_INTERNAL_SERVER_ERROR: LOG("NETWORK_CONFIG_REQUEST failed: internal error: %s",netconf.get("error","(unknown)").c_str()); @@ -688,7 +684,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } catch (std::exception &exc) { TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); @@ -704,12 +700,12 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; while ((ptr + 8) <= size()) { uint64_t nwid = at(ptr); - SharedPtr nw(RR->nc->network(nwid)); - if ((nw)&&(source() == nw->controller())) + SharedPtr nw(RR->node->network(nwid)); + if ((nw)&&(peer->address() == nw->controller())) nw->requestConfiguration(); ptr += 8; } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -721,9 +717,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); - MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); - unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); + const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); //TRACE("<mc->gather(peer->address(),nwid,mg,outp,gatherLimit)) { outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -752,10 +748,10 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); - unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; - SharedPtr network(RR->nc->network(nwid)); // will be NULL if not a member + const SharedPtr network(RR->node->network(nwid)); if (network) { // Offset -- size of optional fields added to position of later fields unsigned int offset = 0; @@ -789,9 +785,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share from.fromAddress(peer->address(),nwid); } - MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); - unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); - unsigned int payloadLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); + const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); + const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); + const unsigned int payloadLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); //TRACE("<address().toString().c_str(),flags,payloadLen); @@ -814,7 +810,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } } - network->tapPut(from,to.mac(),etherType,field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,payloadLen),payloadLen); + RR->node->putFrame(network->id(),from,to.mac(),etherType,0,field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,payloadLen),payloadLen); } if (gatherLimit) { @@ -827,12 +823,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share outp.append((unsigned char)0x02); // flag 0x02 = contains gather results if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } } // else ignore -- not a member of this network - peer->received(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,Utils::now()); + peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -849,7 +845,7 @@ void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } } // namespace ZeroTier diff --git a/node/Node.cpp b/node/Node.cpp index 4297a2ec6..7e4bc6429 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -44,6 +44,10 @@ namespace ZeroTier { +/****************************************************************************/ +/* Public Node interface (C++, exposed via CAPI bindings) */ +/****************************************************************************/ + Node::Node( uint64_t now, ZT1_DataStoreGetFunction dataStoreGetFunction, @@ -63,6 +67,10 @@ Node::Node( _networks_m(), _now(now) { + _newestVersionSeen[0] = ZEROTIER_ONE_VERSION_MAJOR; + _newestVersionSeen[1] = ZEROTIER_ONE_VERSION_MINOR; + _newestVersionSeen[2] = ZEROTIER_ONE_VERSION_REVISION; + try { RR->prng = new CMWC4096(); RR->sw = new Switch(RR); @@ -176,8 +184,30 @@ void Node::setNetconfMaster(void *networkConfigMasterInstance) RR->netconfMaster = reinterpret_cast(networkConfigMasterInstance); } +/****************************************************************************/ +/* Node methods used only within node/ */ +/****************************************************************************/ + +std::string Node::dataStoreGet(const char *name) +{ +} + +void Node::postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev) +{ + if (Peer::compareVersion(major,minor,rev,_newestVersionSeen[0],_newestVersionSeen[1],_newestVersionSeen[2]) > 0) { + _newestVersionSeen[0] = major; + _newestVersionSeen[1] = minor; + _newestVersionSeen[2] = rev; + this->postEvent(ZT1_EVENT_SAW_MORE_RECENT_VERSION); + } +} + } // namespace ZeroTier +/****************************************************************************/ +/* CAPI bindings */ +/****************************************************************************/ + extern "C" { enum ZT1_ResultCode ZT1_Node_new( @@ -195,14 +225,21 @@ enum ZT1_ResultCode ZT1_Node_new( *node = reinterpret_cast(new ZeroTier::Node(now,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigCallback,statusCallback)); return ZT1_RESULT_OK; } catch (std::bad_alloc &exc) { - return ZT1_RESULT_ERROR_OUT_OF_MEMORY; + return ZT1_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch (std::runtime_error &exc) { - return ZT1_RESULT_ERROR_DATA_STORE_FAILED; + return ZT1_RESULT_FATAL_ERROR_DATA_STORE_FAILED; } catch ( ... ) { - return ZT1_RESULT_ERROR_INTERNAL; + return ZT1_RESULT_FATAL_ERROR_INTERNAL; } } +void ZT1_Node_delete(ZT1_Node *node) +{ + try { + delete (reinterpret_cast(node)); + } catch ( ... ) {} +} + enum ZT1_ResultCode ZT1_Node_processWirePacket( ZT1_Node *node, uint64_t now, @@ -215,9 +252,9 @@ enum ZT1_ResultCode ZT1_Node_processWirePacket( try { return reinterpret_cast(node)->processWirePacket(now,remoteAddress,linkDesperation,packetData,packetLength,nextCallDeadline); } catch (std::bad_alloc &exc) { - return ZT1_RESULT_ERROR_OUT_OF_MEMORY; + return ZT1_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { - return ZT1_RESULT_PACKET_INVALID; + return ZT1_RESULT_ERROR_PACKET_INVALID; } } diff --git a/node/Node.hpp b/node/Node.hpp index 2dbf64b25..49871f5aa 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -115,12 +115,16 @@ public: */ inline bool putPacket(const InetAddress &addr,const void *data,unsigned int len,unsigned int desperation) { - return (_wirePacketSendFunction( - reinterpret_cast(this), - reinterpret_cast(&addr), - desperation, - data, - len) == 0); + try { + return (_wirePacketSendFunction( + reinterpret_cast(this), + reinterpret_cast(&addr), + desperation, + data, + len) == 0); + } catch ( ... ) { // callbacks should not throw + return false; + } } /** @@ -136,21 +140,19 @@ public: */ inline void putFrame(uint64_t nwid,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { - _virtualNetworkFrameFunction( - reinterpret_cast(this), - nwid, - source.toInt(), - dest.toInt(), - etherType, - vlanId, - data, - len); + try { + _virtualNetworkFrameFunction( + reinterpret_cast(this), + nwid, + source.toInt(), + dest.toInt(), + etherType, + vlanId, + data, + len); + } catch ( ... ) {} // callbacks should not throw } - /** - * @param nwid Network ID - * @return Network instance - */ inline SharedPtr network(uint64_t nwid) { Mutex::Lock _l(_networks_m); @@ -160,12 +162,12 @@ public: inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast(this),name,data,len,(int)secure) == 0); } inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } - - inline std::string dataStoreGet(const char *name) - { - } - inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast(this),name,(const void *)0,0,0); } + std::string dataStoreGet(const char *name); + + inline void postEvent(ZT1_Event ev) { _statusCallback(reinterpret_cast(this),ev); } + + void postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev); private: RuntimeEnvironment *RR; @@ -184,6 +186,7 @@ private: Mutex _networks_m; volatile uint64_t _now; // time of last run() + unsigned int _newestVersionSeen[3]; // major, minor, revision }; } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index fce725b22..147ce5714 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -379,6 +379,31 @@ public: else return std::pair(); } + /** + * Compare Peer version tuples + */ + static inline int compareVersion(unsigned int maj1,unsigned int min1,unsigned int rev1,unsigned int maj2,unsigned int min2,unsigned int rev2) + throw() + { + if (maj1 > maj2) + return 1; + else if (maj1 < maj2) + return -1; + else { + if (min1 > min2) + return 1; + else if (min1 < min2) + return -1; + else { + if (rev1 > rev2) + return 1; + else if (rev1 < rev2) + return -1; + else return 0; + } + } + } + private: void _announceMulticastGroups(const RuntimeEnvironment *RR,uint64_t now);