From a4bc40542bf11a6688b5e0e8aa0e06a7bc4fe544 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 14 Aug 2017 11:43:39 -0700 Subject: GCC/G++ build fixes, GitHub issue #563 --- node/AtomicCounter.hpp | 2 +- node/Node.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'node') diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index abb342fe..34b58e91 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -50,7 +50,7 @@ public: inline int load() const { #ifdef __GNUC__ - return __sync_or_and_fetch(&_v,0); + return __sync_or_and_fetch(const_cast(&_v),0); #else return _v.load(); #endif diff --git a/node/Node.cpp b/node/Node.cpp index 0df3a97a..366ddbf0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -100,7 +100,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } else { idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); - if ((n > 0)&&(n < sizeof(RR->publicIdentityStr))&&(n < sizeof(tmp))) { + if ((n > 0)&&(n < (int)sizeof(RR->publicIdentityStr))&&(n < (int)sizeof(tmp))) { if (memcmp(tmp,RR->publicIdentityStr,n)) stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr)); } -- cgit v1.2.3 From fcaf1d89c260943d3c9c4021b9ab6fe89c1c4de8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 13:59:22 -0700 Subject: Get rid of some noisy remote traces that should not be needed. --- node/IncomingPacket.cpp | 13 ++++---- node/Membership.cpp | 3 -- node/Trace.cpp | 79 ++----------------------------------------------- node/Trace.hpp | 9 +----- 4 files changed, 10 insertions(+), 94 deletions(-) (limited to 'node') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e5e10476..3788708d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -66,10 +66,9 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // packets are dropped on the floor. const uint64_t tpid = trustedPathId(); if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { - RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,true); trusted = true; } else { - RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,false); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted"); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -81,7 +80,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); return true; } } @@ -246,10 +245,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); } } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid identity"); } return true; @@ -257,7 +256,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); return true; } @@ -282,7 +281,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index a1453307..17de6554 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -147,7 +147,6 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_REJECTED; case 0: _com = com; - RR->t->credentialAccepted(tPtr,com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -179,7 +178,6 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot RR->t->credentialRejected(tPtr,cred,"invalid"); return Membership::ADD_REJECTED; case 0: - RR->t->credentialAccepted(tPtr,cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -205,7 +203,6 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { - RR->t->credentialAccepted(tPtr,rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } diff --git a/node/Trace.cpp b/node/Trace.cpp index 98a4adcb..8e78b676 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -164,12 +164,7 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) -{ - // TODO -} - -void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops) +void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) { char tmp[128]; Dictionary d; @@ -179,6 +174,8 @@ void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const Sh d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); _send(tPtr,d,0); } @@ -344,76 +341,6 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char * _send(tPtr,d,c.networkId()); } -void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - _send(tPtr,d,0); -} - -void Trace::credentialAccepted(void *const tPtr,const Capability &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const Tag &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const Revocation &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); - _send(tPtr,d,c.networkId()); -} - void Trace::_send(void *const tPtr,const Dictionary &d) { #ifdef ZT_TRACE diff --git a/node/Trace.hpp b/node/Trace.hpp index d66d0871..a7b2b194 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -108,8 +108,7 @@ public: void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); - void incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); - void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops); + void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); @@ -142,12 +141,6 @@ public: void credentialRejected(void *const tPtr,const Capability &c,const char *reason); void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); - void credentialAccepted(void *const tPtr,const CertificateOfMembership &c); - void credentialAccepted(void *const tPtr,const CertificateOfOwnership &c); - void credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c); - void credentialAccepted(void *const tPtr,const Capability &c); - void credentialAccepted(void *const tPtr,const Tag &c); - void credentialAccepted(void *const tPtr,const Revocation &c); private: const RuntimeEnvironment *const RR; -- cgit v1.2.3 From 64758c46b672f8b3182c370aed6b81a07780c093 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 13:40:51 -0700 Subject: Implement peer serialization and deserialization. --- node/Peer.cpp | 2 +- node/Peer.hpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ node/Topology.cpp | 31 +++++++++++++++---- node/Topology.hpp | 2 ++ service/OneService.cpp | 25 ++++++++++++--- 5 files changed, 132 insertions(+), 12 deletions(-) (limited to 'node') diff --git a/node/Peer.cpp b/node/Peer.cpp index 986e52ef..127f222c 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -369,7 +369,7 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) - attemptToContactAt(tPtr,InetAddress(),mp,now,true,0); + attemptToContactAt(tPtr,-1,mp,now,true,0); } } diff --git a/node/Peer.hpp b/node/Peer.hpp index c6423a59..af9163a5 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -439,6 +439,90 @@ public: return false; } + /** + * Serialize a peer for storage in local cache + * + * This does not serialize everything, just identity and addresses where the peer + * may be reached. + */ + template + inline void serialize(Buffer &b) const + { + b.append((uint8_t)0); + + _id.serialize(b); + + b.append(_lastReceive); + b.append(_lastNontrivialReceive); + b.append(_lastTriedMemorizedPath); + b.append(_lastDirectPathPushSent); + b.append(_lastDirectPathPushReceive); + b.append(_lastCredentialRequestSent); + b.append(_lastWhoisRequestReceived); + b.append(_lastEchoRequestReceived); + b.append(_lastComRequestReceived); + b.append(_lastComRequestSent); + b.append(_lastCredentialsReceived); + b.append(_lastTrustEstablishedPacketReceived); + + b.append((uint16_t)_vProto); + b.append((uint16_t)_vMajor); + b.append((uint16_t)_vMinor); + b.append((uint16_t)_vRevision); + + { + Mutex::Lock _l(_paths_m); + unsigned int pcount = 0; + if (_v4Path.p) ++pcount; + if (_v6Path.p) ++pcount; + b.append((uint8_t)pcount); + if (_v4Path.p) _v4Path.p->address().serialize(b); + if (_v6Path.p) _v6Path.p->address().serialize(b); + } + + b.append((uint16_t)0); + } + + template + inline static SharedPtr deserializeFromCache(uint64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) + { + try { + unsigned int ptr = 0; + if (b[ptr++] != 0) + return SharedPtr(); + + Identity id; + ptr += id.deserialize(b,ptr); + if (!id) + return SharedPtr(); + + SharedPtr p(new Peer(renv,renv->identity,id)); + + ptr += 12 * 8; // skip deserializing ephemeral state in this case + + p->_vProto = b.template at(ptr); ptr += 2; + p->_vMajor = b.template at(ptr); ptr += 2; + p->_vMinor = b.template at(ptr); ptr += 2; + p->_vRevision = b.template at(ptr); ptr += 2; + + const unsigned int pcount = (unsigned int)b[ptr++]; + for(unsigned int i=0;iattemptToContactAt(tPtr,-1,inaddr,now,true,0); + } catch ( ... ) { + break; + } + } + + return p; + } catch ( ... ) { + return SharedPtr(); + } + } + private: struct _PeerPath { diff --git a/node/Topology.cpp b/node/Topology.cpp index edca0180..aeca59a7 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -88,6 +88,15 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : addWorld(tPtr,defaultPlanet,false); } +Topology::~Topology() +{ + Hashtable< Address,SharedPtr >::Iterator i(_peers); + Address *a = (Address *)0; + SharedPtr *p = (SharedPtr *)0; + while (i.next(a,p)) + _savePeer((void *)0,*p); +} + SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { SharedPtr np; @@ -113,23 +122,21 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return *ap; } - /* try { - char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; + Buffer buf; uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; - int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf)); + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE); if (len > 0) { Mutex::Lock _l(_peers_m); SharedPtr &ap = _peers[zta]; if (ap) return ap; - ap = Peer::createFromStateUpdate(RR,tPtr,buf,len); + ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); if (!ap) _peers.erase(zta); return ap; } } catch ( ... ) {} // ignore invalid identities or other strage failures - */ return SharedPtr(); } @@ -383,8 +390,10 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { + _savePeer(tPtr,*p); _peers.erase(*a); + } } } @@ -440,4 +449,14 @@ void Topology::_memoizeUpstreams(void *tPtr) _cor.sign(RR->identity,RR->node->now()); } +void Topology::_savePeer(void *tPtr,const SharedPtr &peer) +{ + try { + Buffer buf; + peer->serialize(buf); + uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); + } catch ( ... ) {} // sanity check, discard invalid entries +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 30e58abc..04dfb1cc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -59,6 +59,7 @@ class Topology { public: Topology(const RuntimeEnvironment *renv,void *tPtr); + ~Topology(); /** * Add a peer to database @@ -419,6 +420,7 @@ public: private: Identity _getIdentity(void *tPtr,const Address &zta); void _memoizeUpstreams(void *tPtr); + void _savePeer(void *tPtr,const SharedPtr &peer); const RuntimeEnvironment *const RR; diff --git a/service/OneService.cpp b/service/OneService.cpp index f5f8700a..cd33e399 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2047,6 +2047,8 @@ public: char p[1024]; FILE *f; bool secure = false; + char dirname[1024]; + dirname[0] = 0; switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: @@ -2060,12 +2062,18 @@ public: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); secure = true; break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); + break; default: return; } @@ -2084,6 +2092,10 @@ public: } f = fopen(p,"w"); + if ((!f)&&(dirname[0])) { // create subdirectory if it does not exist + OSUtils::mkdir(dirname); + f = fopen(p,"w"); + } if (f) { if (fwrite(data,len,1,f) != 1) fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); @@ -2108,15 +2120,18 @@ public: case ZT_STATE_OBJECT_IDENTITY_SECRET: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); - break; case ZT_STATE_OBJECT_PLANET: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id); break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d/%.10llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + break; default: return -1; } -- cgit v1.2.3 From 9cfc10952748487bed318ec11221eeccbb285c89 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 14:00:08 -0700 Subject: Tighten a few timings. --- node/Constants.hpp | 4 ++-- node/Switch.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'node') diff --git a/node/Constants.hpp b/node/Constants.hpp index 3f050ead..27dce075 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -226,12 +226,12 @@ /** * Delay between WHOIS retries in ms */ -#define ZT_WHOIS_RETRY_DELAY 1000 +#define ZT_WHOIS_RETRY_DELAY 500 /** * Maximum identity WHOIS retries (each attempt tries consulting a different peer) */ -#define ZT_MAX_WHOIS_RETRIES 4 +#define ZT_MAX_WHOIS_RETRIES 5 /** * Transmit queue entry timeout diff --git a/node/Switch.cpp b/node/Switch.cpp index 053f793e..0d39bee9 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -630,9 +630,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); - else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { + } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); } else ++txi; -- cgit v1.2.3 From a156a4dbe2ffe5fc5f870144fe80efc172901d8e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 15:12:00 -0700 Subject: Symmetric NAT cleanup. --- node/SelfAwareness.cpp | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'node') diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index cdbb6303..0af0d691 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -147,13 +147,14 @@ std::vector SelfAwareness::getSymmetricNatPredictions() * read or modify traffic, but they could gather meta-data for forensics * purpsoes or use this as a DOS attack vector. */ - std::map< uint32_t,std::pair > maxPortByIp; + std::map< uint32_t,unsigned int > maxPortByIp; InetAddress theOneTrueSurface; - bool symmetric = false; { Mutex::Lock _l(_phy_m); - { // First get IPs from only trusted peers, and perform basic NAT type characterization + // First check to see if this is a symmetric NAT and enumerate external IPs learned from trusted peers + bool symmetric = false; + { Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceEntry *e = (PhySurfaceEntry *)0; @@ -163,42 +164,47 @@ std::vector SelfAwareness::getSymmetricNatPredictions() theOneTrueSurface = e->mySurface; else if (theOneTrueSurface != e->mySurface) symmetric = true; - maxPortByIp[reinterpret_cast(&(e->mySurface))->sin_addr.s_addr] = std::pair(e->ts,e->mySurface.port()); + maxPortByIp[reinterpret_cast(&(e->mySurface))->sin_addr.s_addr] = e->mySurface.port(); } } } + if (!symmetric) + return std::vector(); - { // Then find max port per IP from a trusted peer + { // Then find the highest issued port per IP Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceEntry *e = (PhySurfaceEntry *)0; while (i.next(k,e)) { if ((e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - std::map< uint32_t,std::pair >::iterator mp(maxPortByIp.find(reinterpret_cast(&(e->mySurface))->sin_addr.s_addr)); - if ((mp != maxPortByIp.end())&&(mp->second.first < e->ts)) { - mp->second.first = e->ts; - mp->second.second = e->mySurface.port(); - } + const unsigned int port = e->mySurface.port(); + std::map< uint32_t,unsigned int >::iterator mp(maxPortByIp.find(reinterpret_cast(&(e->mySurface))->sin_addr.s_addr)); + if ((mp != maxPortByIp.end())&&(mp->second < port)) + mp->second = port; } } } } - if (symmetric) { - std::vector r; - for(unsigned int k=1;k<=3;++k) { - for(std::map< uint32_t,std::pair >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { - unsigned int p = i->second.second + k; - if (p > 65535) p -= 64511; - InetAddress pred(&(i->first),4,p); - if (std::find(r.begin(),r.end(),pred) == r.end()) - r.push_back(pred); - } - } - return r; + std::vector r; + + // Try next port up from max for each + for(std::map< uint32_t,unsigned int >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { + unsigned int p = i->second + 1; + if (p > 65535) p -= 64511; + const InetAddress pred(&(i->first),4,p); + if (std::find(r.begin(),r.end(),pred) == r.end()) + r.push_back(pred); + } + + // Try a random port for each -- there are only 65535 so eventually it should work + for(std::map< uint32_t,unsigned int >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { + const InetAddress pred(&(i->first),4,1024 + ((unsigned int)RR->node->prng() % 64511)); + if (std::find(r.begin(),r.end(),pred) == r.end()) + r.push_back(pred); } - return std::vector(); + return r; } } // namespace ZeroTier -- cgit v1.2.3 From b1d94c9f9324a31887dc6edc99ed58d4f9b187db Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 15:19:26 -0700 Subject: Performance improvement to RX queue ring buffer. --- node/Switch.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'node') diff --git a/node/Switch.hpp b/node/Switch.hpp index 114bc5e1..88415541 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -174,19 +174,20 @@ private: // Returns matching or next available RX queue entry inline RXQueueEntry *_findRXQueueEntry(uint64_t packetId) { - unsigned int ptr = static_cast(_rxQueuePtr.load()); - for(unsigned int k=0;k(_rxQueuePtr.load()); + for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) { + RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]); if ((rq->packetId == packetId)&&(rq->timestamp)) return rq; } - return &(_rxQueue[static_cast(++_rxQueuePtr) % ZT_RX_QUEUE_SIZE]); + ++_rxQueuePtr; + return &(_rxQueue[static_cast(current) % ZT_RX_QUEUE_SIZE]); } - // Returns next RX queue entry in ring buffer and increments ring counter + // Returns current entry in rx queue ring buffer and increments ring pointer inline RXQueueEntry *_nextRXQueueEntry() { - return &(_rxQueue[static_cast(++_rxQueuePtr) % ZT_RX_QUEUE_SIZE]); + return &(_rxQueue[static_cast((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]); } // ZeroTier-layer TX queue entry -- cgit v1.2.3 From 6ee201865b12f5b0f16208f6d696b1bf00197eaf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:42:17 -0700 Subject: Clean up WHOIS code. --- node/Capability.cpp | 3 +- node/CertificateOfMembership.cpp | 3 +- node/CertificateOfOwnership.cpp | 3 +- node/Constants.hpp | 9 +-- node/IncomingPacket.cpp | 4 +- node/Node.cpp | 26 ++++---- node/Revocation.cpp | 3 +- node/Switch.cpp | 132 ++++++++++++++++++++------------------- node/Switch.hpp | 24 +++---- node/Tag.cpp | 3 +- node/Topology.cpp | 35 +++-------- node/Topology.hpp | 14 +---- 12 files changed, 115 insertions(+), 144 deletions(-) (limited to 'node') diff --git a/node/Capability.cpp b/node/Capability.cpp index 0e02025a..47dca1fc 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -59,7 +60,7 @@ int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) return -1; } else { - RR->sw->requestWhois(tPtr,_custody[c].from); + RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from); return 1; } } diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 100253e1..dedcccff 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -29,6 +29,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -223,7 +224,7 @@ int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) con const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 31d0ae18..eeb0d99c 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) cons return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Constants.hpp b/node/Constants.hpp index 27dce075..cda1af3b 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -228,20 +228,15 @@ */ #define ZT_WHOIS_RETRY_DELAY 500 -/** - * Maximum identity WHOIS retries (each attempt tries consulting a different peer) - */ -#define ZT_MAX_WHOIS_RETRIES 5 - /** * Transmit queue entry timeout */ -#define ZT_TRANSMIT_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +#define ZT_TRANSMIT_QUEUE_TIMEOUT 5000 /** * Receive queue entry timeout */ -#define ZT_RECEIVE_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +#define ZT_RECEIVE_QUEUE_TIMEOUT 5000 /** * Maximum latency to allow for OK(HELLO) before packet is discarded diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3788708d..685f2f09 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -115,7 +115,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) case Packet::VERB_REMOTE_TRACE: return _doREMOTE_TRACE(RR,tPtr,peer); } } else { - RR->sw->requestWhois(tPtr,sourceAddress); + RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); return false; } } catch ( ... ) { @@ -556,7 +556,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar ++count; } else { // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(tPtr,addr); + RR->sw->requestWhois(tPtr,RR->node->now(),addr); } } diff --git a/node/Node.cpp b/node/Node.cpp index 366ddbf0..09260172 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -249,6 +249,19 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint try { _lastPingCheck = now; + // Do pings and keepalives + Hashtable< Address,std::vector > upstreamsToContact; + RR->topology->getUpstreamsToContact(upstreamsToContact); + _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); + RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); + + // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) + Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); + Address *upstreamAddress = (Address *)0; + std::vector *upstreamStableEndpoints = (std::vector *)0; + while (i.next(upstreamAddress,upstreamStableEndpoints)) + RR->sw->requestWhois(tptr,now,*upstreamAddress); + // Get networks that need config without leaving mutex locked { std::vector< std::pair< SharedPtr,bool > > nwl; @@ -268,19 +281,6 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } } - // Do pings and keepalives - Hashtable< Address,std::vector > upstreamsToContact; - RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); - RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); - - // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) - Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(tptr,*upstreamAddress); - // Update online status, post status change as event const bool oldOnline = _online; _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 026058da..89a2db95 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Switch.cpp b/node/Switch.cpp index 0d39bee9..8446602c 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -50,7 +50,6 @@ namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : RR(renv), _lastBeaconResponse(0), - _outstandingWhoisRequests(32), _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine { } @@ -229,8 +228,8 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } } } else { - relayTo = RR->topology->getUpstreamPeer(&source,1,true); - if (relayTo) + relayTo = RR->topology->getUpstreamPeer(); + if ((relayTo)&&(relayTo->address() != source)) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } } @@ -553,33 +552,35 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) } } -void Switch::requestWhois(void *tPtr,const Address &addr) +void Switch::requestWhois(void *tPtr,const uint64_t now,const Address &addr) { if (addr == RR->identity.address()) return; - bool inserted = false; + { - Mutex::Lock _l(_outstandingWhoisRequests_m); - WhoisRequest &r = _outstandingWhoisRequests[addr]; - if (r.lastSent) { - r.retries = 0; // reset retry count if entry already existed, but keep waiting and retry again after normal timeout - } else { - r.lastSent = RR->node->now(); - inserted = true; - } + Mutex::Lock _l(_lastSentWhoisRequest_m); + uint64_t &last = _lastSentWhoisRequest[addr]; + if ((now - last) < ZT_WHOIS_RETRY_DELAY) + return; + else last = now; + } + + const SharedPtr upstream(RR->topology->getUpstreamPeer()); + if (upstream) { + Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); + addr.appendTo(outp); + RR->node->expectReplyTo(outp.packetId()); + send(tPtr,outp,true); } - if (inserted) - _sendWhoisRequest(tPtr,addr,(const Address *)0,0); } void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) { - { // cancel pending WHOIS since we now know this peer - Mutex::Lock _l(_outstandingWhoisRequests_m); - _outstandingWhoisRequests.erase(peer->address()); + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + _lastSentWhoisRequest.erase(peer->address()); } - // finish processing any packets waiting on peer's public key / identity const uint64_t now = RR->node->now(); for(unsigned int ptr=0;ptr &peer) } } - { // finish sending any packets waiting on peer's public key / identity + { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); - else ++txi; - } else ++txi; - } - } -} - -unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) -{ - unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - - { // Retry outstanding WHOIS requests - Mutex::Lock _l(_outstandingWhoisRequests_m); - Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests); - Address *a = (Address *)0; - WhoisRequest *r = (WhoisRequest *)0; - while (i.next(a,r)) { - const unsigned long since = (unsigned long)(now - r->lastSent); - if (since >= ZT_WHOIS_RETRY_DELAY) { - if (r->retries >= ZT_MAX_WHOIS_RETRIES) { - _outstandingWhoisRequests.erase(*a); } else { - r->lastSent = now; - r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); - ++r->retries; - nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); + ++txi; } } else { - nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since); + ++txi; } } } +} - { // Time out TX queue packets that never got WHOIS lookups or other info. +unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) +{ + const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; + if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) + return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); + _lastCheckedQueues = now; + + { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); - _txQueue.erase(txi++); - } else ++txi; + _txQueue.erase(txi); + ++txi; + } else if (!RR->topology->getPeer(tPtr,txi->dest)) { + requestWhois(tPtr,now,txi->dest); + ++txi; + } else { + ++txi; + } + } + } + + for(unsigned int ptr=0;ptrtimestamp)&&(rq->complete)) { + if ((rq->frag0.tryDecode(RR,tPtr))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { + rq->timestamp = 0; + } else { + const Address src(rq->frag0.source()); + if (!RR->topology->getPeer(tPtr,src)) + requestWhois(tPtr,now,src); + } } } - { // Remove really old last unite attempt entries to keep table size controlled + { Mutex::Lock _l(_lastUniteAttempt_m); Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt); _LastUniteKey *k = (_LastUniteKey *)0; @@ -650,7 +655,18 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) } } - return nextDelay; + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + Hashtable< Address,uint64_t >::Iterator i(_lastSentWhoisRequest); + Address *a = (Address *)0; + uint64_t *ts = (uint64_t *)0; + while (i.next(a,ts)) { + if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) + _lastSentWhoisRequest.erase(*a); + } + } + + return ZT_WHOIS_RETRY_DELAY; } bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination) @@ -664,18 +680,6 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address return false; } -Address Switch::_sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) -{ - SharedPtr upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); - if (upstream) { - Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); - addr.appendTo(outp); - RR->node->expectReplyTo(outp.packetId()); - send(tPtr,outp,true); - } - return Address(); -} - bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; @@ -709,7 +713,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - requestWhois(tPtr,destination); + requestWhois(tPtr,now,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } diff --git a/node/Switch.hpp b/node/Switch.hpp index 88415541..2420607d 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -111,9 +111,10 @@ public: * Request WHOIS on a given address * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time * @param addr Address to look up */ - void requestWhois(void *tPtr,const Address &addr); + void requestWhois(void *tPtr,const uint64_t now,const Address &addr); /** * Run any processes that are waiting for this peer's identity @@ -139,34 +140,27 @@ public: private: bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); - Address _sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; + uint64_t _lastCheckedQueues; - // Outstanding WHOIS requests and how many retries they've undergone - struct WhoisRequest - { - WhoisRequest() : lastSent(0),retries(0) {} - uint64_t lastSent; - Address peersConsulted[ZT_MAX_WHOIS_RETRIES]; // by retry - unsigned int retries; // 0..ZT_MAX_WHOIS_RETRIES - }; - Hashtable< Address,WhoisRequest > _outstandingWhoisRequests; - Mutex _outstandingWhoisRequests_m; + // Time we last sent a WHOIS request for each address + Hashtable< Address,uint64_t > _lastSentWhoisRequest; + Mutex _lastSentWhoisRequest_m; // Packets waiting for WHOIS replies or other decode info or missing fragments struct RXQueueEntry { RXQueueEntry() : timestamp(0) {} - uint64_t timestamp; // 0 if entry is not in use - uint64_t packetId; + volatile uint64_t timestamp; // 0 if entry is not in use + volatile uint64_t packetId; IncomingPacket frag0; // head of packet Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) unsigned int totalFragments; // 0 if only frag0 received, waiting for frags uint32_t haveFragments; // bit mask, LSB to MSB - bool complete; // if true, packet is complete + volatile bool complete; // if true, packet is complete }; RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE]; AtomicCounter _rxQueuePtr; diff --git a/node/Tag.cpp b/node/Tag.cpp index 39b17f2a..bde41a70 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Topology.cpp b/node/Topology.cpp index aeca59a7..ee5d969d 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -154,13 +154,11 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) return Identity(); } -SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) +SharedPtr Topology::getUpstreamPeer() { const uint64_t now = RR->node->now(); - unsigned int bestQualityOverall = ~((unsigned int)0); - unsigned int bestQualityNotAvoid = ~((unsigned int)0); - const SharedPtr *bestOverall = (const SharedPtr *)0; - const SharedPtr *bestNotAvoid = (const SharedPtr *)0; + unsigned int bestq = ~((unsigned int)0); + const SharedPtr *best = (const SharedPtr *)0; Mutex::Lock _l1(_peers_m); Mutex::Lock _l2(_upstreams_m); @@ -168,32 +166,17 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { const SharedPtr *p = _peers.get(*a); if (p) { - bool avoiding = false; - for(unsigned int i=0;iaddress()) { - avoiding = true; - break; - } - } const unsigned int q = (*p)->relayQuality(now); - if (q <= bestQualityOverall) { - bestQualityOverall = q; - bestOverall = &(*p); - } - if ((!avoiding)&&(q <= bestQualityNotAvoid)) { - bestQualityNotAvoid = q; - bestNotAvoid = &(*p); + if (q <= bestq) { + bestq = q; + best = p; } } } - if (bestNotAvoid) { - return *bestNotAvoid; - } else if ((!strictAvoid)&&(bestOverall)) { - return *bestOverall; - } - - return SharedPtr(); + if (!best) + return SharedPtr(); + return *best; } bool Topology::isUpstream(const Identity &id) const diff --git a/node/Topology.hpp b/node/Topology.hpp index 04dfb1cc..43921896 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -127,19 +127,9 @@ public: /** * Get the current best upstream peer * - * @return Root server with lowest latency or NULL if none + * @return Upstream or NULL if none available */ - inline SharedPtr getUpstreamPeer() { return getUpstreamPeer((const Address *)0,0,false); } - - /** - * Get the current best upstream peer, avoiding those in the supplied avoid list - * - * @param avoid Nodes to avoid - * @param avoidCount Number of nodes to avoid - * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available - * @return Root server or NULL if none available - */ - SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); + SharedPtr getUpstreamPeer(); /** * @param id Identity to check -- cgit v1.2.3 From 180049a27725523e18004769d145ba88a68c799b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:55:22 -0700 Subject: Fix pointer bug. --- node/Switch.cpp | 3 +-- node/Switch.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'node') diff --git a/node/Switch.cpp b/node/Switch.cpp index 8446602c..388ed672 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -620,8 +620,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) _txQueue.erase(txi++); } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); - _txQueue.erase(txi); - ++txi; + _txQueue.erase(txi++); } else if (!RR->topology->getPeer(tPtr,txi->dest)) { requestWhois(tPtr,now,txi->dest); ++txi; diff --git a/node/Switch.hpp b/node/Switch.hpp index 2420607d..c258a255 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -144,7 +144,7 @@ private: const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; - uint64_t _lastCheckedQueues; + volatile uint64_t _lastCheckedQueues; // Time we last sent a WHOIS request for each address Hashtable< Address,uint64_t > _lastSentWhoisRequest; -- cgit v1.2.3 From 0a9c3b557181a77f059d4b2957f6a02f7cc5bde5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:59:31 -0700 Subject: Fix possible deadlock. --- node/Switch.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'node') diff --git a/node/Switch.cpp b/node/Switch.cpp index 388ed672..62c3f450 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -613,6 +613,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); _lastCheckedQueues = now; + std::vector
needWhois; { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { @@ -621,14 +622,15 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); - } else if (!RR->topology->getPeer(tPtr,txi->dest)) { - requestWhois(tPtr,now,txi->dest); - ++txi; } else { + if (!RR->topology->getPeer(tPtr,txi->dest)) + needWhois.push_back(txi->dest); ++txi; } } } + for(std::vector
::const_iterator i(needWhois.begin());i!=needWhois.end();++i) + requestWhois(tPtr,now,*i); for(unsigned int ptr=0;ptr Date: Wed, 23 Aug 2017 17:14:06 -0700 Subject: Fix another deadlock. --- node/Switch.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'node') diff --git a/node/Switch.cpp b/node/Switch.cpp index 62c3f450..fce12622 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -544,11 +544,16 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const void Switch::send(void *tPtr,Packet &packet,bool encrypt) { - if (packet.destination() == RR->identity.address()) + const Address dest(packet.destination()); + if (dest == RR->identity.address()) return; if (!_trySend(tPtr,packet,encrypt)) { - Mutex::Lock _l(_txQueue_m); - _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); + { + Mutex::Lock _l(_txQueue_m); + _txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt)); + } + if (!RR->topology->getPeer(tPtr,dest)) + requestWhois(tPtr,RR->node->now(),dest); } } @@ -714,7 +719,6 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - requestWhois(tPtr,now,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } -- cgit v1.2.3 From dd8b03a5c55baf7349ce075c8f4cad1d59cbe988 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 18:28:40 -0700 Subject: Threading issue fix? --- node/Peer.cpp | 7 +++++-- node/Switch.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'node') diff --git a/node/Peer.cpp b/node/Peer.cpp index 127f222c..b3020854 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -424,18 +424,21 @@ void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remo SharedPtr op; SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + np->received(now); attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); { Mutex::Lock _l(_paths_m); if (remoteAddress.ss_family == AF_INET) { op = _v4Path.p; - _v4Path.p = np; + _v4Path.lr = now; _v4Path.sticky = now; + _v4Path.p = np; } else if (remoteAddress.ss_family == AF_INET6) { op = _v6Path.p; - _v6Path.p = np; + _v6Path.lr = now; _v6Path.sticky = now; + _v6Path.p = np; } } diff --git a/node/Switch.cpp b/node/Switch.cpp index fce12622..952bdef8 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -719,7 +719,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly + return false; } unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); -- cgit v1.2.3 From 49fa30d495c0524a15ba86668f4fee12b9715089 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 18:52:32 -0700 Subject: Ticket lock for x64/gcc/clang platforms. --- node/Mutex.hpp | 84 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 21 deletions(-) (limited to 'node') diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 854f321a..b16f53f7 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -32,32 +32,84 @@ #ifdef __UNIX_LIKE__ +#include #include #include namespace ZeroTier { +#if defined(__GNUC__) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) + +// Inline ticket lock on x64 systems with GCC and CLANG (Mac, Linux) -- this is really fast as long as locking durations are very short class Mutex : NonCopyable { public: - Mutex() + Mutex() : + nextTicket(0), + nowServing(0) { - pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); } - ~Mutex() + inline void lock() const { - pthread_mutex_destroy(&_mh); + const uint16_t myTicket = __sync_fetch_and_add(&(const_cast(this)->nextTicket),1); + while (nowServing != myTicket) { + __asm__ __volatile__("rep;nop"::); + __asm__ __volatile__("":::"memory"); + } } - inline void lock() + inline void unlock() const { - pthread_mutex_lock(&_mh); + ++(const_cast(this)->nowServing); } - inline void unlock() + /** + * Uses C++ contexts and constructor/destructor to lock/unlock automatically + */ + class Lock : NonCopyable { - pthread_mutex_unlock(&_mh); + public: + Lock(Mutex &m) : + _m(&m) + { + m.lock(); + } + + Lock(const Mutex &m) : + _m(const_cast(&m)) + { + _m->lock(); + } + + ~Lock() + { + _m->unlock(); + } + + private: + Mutex *const _m; + }; + +private: + uint16_t nextTicket; + uint16_t nowServing; +}; + +#else + +// libpthread based mutex lock +class Mutex : NonCopyable +{ +public: + Mutex() + { + pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); + } + + ~Mutex() + { + pthread_mutex_destroy(&_mh); } inline void lock() const @@ -70,9 +122,6 @@ public: (const_cast (this))->unlock(); } - /** - * Uses C++ contexts and constructor/destructor to lock/unlock automatically - */ class Lock : NonCopyable { public: @@ -101,6 +150,8 @@ private: pthread_mutex_t _mh; }; +#endif + } // namespace ZeroTier #endif // Apple / Linux @@ -112,6 +163,7 @@ private: namespace ZeroTier { +// Windows critical section based lock class Mutex : NonCopyable { public: @@ -125,16 +177,6 @@ public: DeleteCriticalSection(&_cs); } - inline void lock() - { - EnterCriticalSection(&_cs); - } - - inline void unlock() - { - LeaveCriticalSection(&_cs); - } - inline void lock() const { (const_cast (this))->lock(); -- cgit v1.2.3 From 02ed84774c2b9eb23995d722349476a1e5a6870f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 31 Aug 2017 20:47:44 -0400 Subject: Non-x86 build fix. --- node/Mutex.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'node') diff --git a/node/Mutex.hpp b/node/Mutex.hpp index b16f53f7..b68e5d93 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -114,12 +114,12 @@ public: inline void lock() const { - (const_cast (this))->lock(); + pthread_mutex_lock(&((const_cast (this))->_mh)); } inline void unlock() const { - (const_cast (this))->unlock(); + pthread_mutex_unlock(&((const_cast (this))->_mh)); } class Lock : NonCopyable -- cgit v1.2.3 From b1fb020aea80ea70ed801b876ad01beb09e218e1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Sep 2017 10:43:44 -0700 Subject: Raise chunk size to max packet size for network configs. Chunking breaks really ancient clients, so this helps them live a little longer. No real downside for new clients. --- node/Node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node') diff --git a/node/Node.cpp b/node/Node.cpp index 09260172..34609fd4 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -592,7 +592,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de const unsigned int totalSize = dconf->sizeBytes(); unsigned int chunkIndex = 0; while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256))); + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256))); Packet outp(destination,RR->identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); if (requestPacketId) { outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); -- cgit v1.2.3 From 2d858b05ac8554ba11374fefaeb583a0bbc0546b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Sep 2017 12:03:31 -0700 Subject: Another fix for ye old tyme clients. --- include/ZeroTierOne.h | 11 ++++++++++- node/Constants.hpp | 9 --------- node/NetworkConfig.cpp | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'node') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 2a970d5b..b889ade0 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -92,6 +92,15 @@ extern "C" { */ #define ZT_MAX_MTU 10000 +/** + * Default payload MTU for UDP packets + * + * This is 1500 - IPv6 UDP overhead - PPPoE overhead and is safe for 99.9% of + * all Internet links. + */ +#define ZT_DEFAULT_PHYSMTU 1444 +#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 + /** * Maximum physical UDP payload */ @@ -103,7 +112,7 @@ extern "C" { #define ZT_MAX_HEADROOM 224 /** - * Maximum physical MTU + * Maximum payload MTU for UDP packets */ #define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) diff --git a/node/Constants.hpp b/node/Constants.hpp index cda1af3b..651fe50d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -171,15 +171,6 @@ */ #define ZT_ADDRESS_RESERVED_PREFIX 0xff -/** - * Default payload MTU for UDP packets - * - * In the future we might support UDP path MTU discovery, but for now we - * set a maximum that is equal to 1500 minus 8 (for PPPoE overhead, common - * in some markets) minus 48 (IPv6 UDP overhead). - */ -#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 - /** * Default MTU used for Ethernet tap device */ diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 0bf4bc19..110a20b0 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -35,6 +35,7 @@ namespace ZeroTier { bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const { Buffer *tmp = new Buffer(); + char tmp2[128]; try { d.clear(); @@ -46,8 +47,8 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; -- cgit v1.2.3 From f8014413a376551b7853baae81072f969a755e46 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Sep 2017 16:25:34 -0700 Subject: Add UDP MTU configurability. --- include/ZeroTierOne.h | 55 +++++++++++++++-------------- node/Multicaster.cpp | 2 +- node/Network.cpp | 1 - node/Node.cpp | 14 ++++---- node/Node.hpp | 2 +- node/Packet.hpp | 6 +--- node/Switch.cpp | 13 ++++--- node/Topology.cpp | 2 +- node/Topology.hpp | 95 ++++++++++++++++++++++++++++++++++++++------------ service/OneService.cpp | 25 ++++++------- service/README.md | 3 +- 11 files changed, 134 insertions(+), 84 deletions(-) (limited to 'node') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index b889ade0..7cbebb32 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -93,13 +93,17 @@ extern "C" { #define ZT_MAX_MTU 10000 /** - * Default payload MTU for UDP packets + * Minimum UDP payload size allowed + */ +#define ZT_MIN_PHYSMTU 1400 + +/** + * Default UDP payload size (physical path MTU) not including UDP and IP overhead * * This is 1500 - IPv6 UDP overhead - PPPoE overhead and is safe for 99.9% of * all Internet links. */ #define ZT_DEFAULT_PHYSMTU 1444 -#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 /** * Maximum physical UDP payload @@ -172,9 +176,9 @@ extern "C" { #define ZT_MAX_PEER_NETWORK_PATHS 4 /** - * Maximum number of trusted physical network paths + * Maximum number of path configurations that can be set */ -#define ZT_MAX_TRUSTED_PATHS 16 +#define ZT_MAX_CONFIGURABLE_PATHS 32 /** * Maximum number of rules per capability @@ -1058,11 +1062,6 @@ typedef struct */ unsigned int mtu; - /** - * Recommended MTU to avoid fragmentation at the physical layer (hint) - */ - unsigned int physicalMtu; - /** * If nonzero, the network this port belongs to indicates DHCP availability * @@ -1132,6 +1131,21 @@ typedef struct unsigned long networkCount; } ZT_VirtualNetworkList; +/** + * Physical path configuration + */ +typedef struct { + /** + * If non-zero set this physical network path to be trusted to disable encryption and authentication + */ + uint64_t trustedPathId; + + /** + * Physical path MTU from ZT_MIN_PHYSMTU and ZT_MAX_PHYSMTU or <= 0 to use default + */ + int mtu; +} ZT_PhysicalPathConfiguration; + /** * Physical network path to a peer */ @@ -1856,27 +1870,14 @@ ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,ui ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); /** - * Set trusted paths - * - * A trusted path is a physical network (network/bits) over which both - * encryption and authentication can be skipped to improve performance. - * Each trusted path must have a non-zero unique ID that is the same across - * all participating nodes. - * - * We don't recommend using trusted paths at all unless you really *need* - * near-bare-metal performance. Even on a LAN authentication and encryption - * are never a bad thing, and anything that introduces an "escape hatch" - * for encryption should be treated with the utmost care. - * - * Calling with NULL pointers for networks and ids and a count of zero clears - * all trusted paths. + * Set configuration for a given physical path * * @param node Node instance - * @param networks Array of [count] networks - * @param ids Array of [count] corresponding non-zero path IDs (zero path IDs are ignored) - * @param count Number of trusted paths-- values greater than ZT_MAX_TRUSTED_PATHS are clipped + * @param pathNetwork Network/CIDR of path or NULL to clear the cache and reset all paths to default + * @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL + * @return OK or error code */ -ZT_SDK_API void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); +ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); /** * Get ZeroTier One version diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index fb7b068f..e8c8613a 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -111,7 +111,7 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const // Members are returned in random order so that repeated gather queries // will return different subsets of a large multicast group. k = 0; - while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_UDP_DEFAULT_PAYLOAD_MTU)) { + while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) { rptr = (unsigned int)RR->node->prng(); restart_member_scan: diff --git a/node/Network.cpp b/node/Network.cpp index f7b144e3..16155c33 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1346,7 +1346,6 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->status = _status(); ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; - ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16); ec->dhcp = 0; std::vector
ab(_config.activeBridges()); ec->bridge = ((_config.allowPassiveBridging())||(std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end())) ? 1 : 0; diff --git a/node/Node.cpp b/node/Node.cpp index 34609fd4..871fb21b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -561,9 +561,9 @@ uint64_t Node::prng() return z + y; } -void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) +ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig) { - RR->topology->setTrustedPaths(reinterpret_cast(networks),ids,count); + return ZT_RESULT_OK; } World Node::planet() const @@ -815,7 +815,7 @@ enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,u } } -ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) +enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) { try { return reinterpret_cast(node)->deorbit(tptr,moonWorldId); @@ -902,11 +902,13 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } -void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) +enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig) { try { - reinterpret_cast(node)->setTrustedPaths(networks,ids,count); - } catch ( ... ) {} + return reinterpret_cast(node)->setPhysicalPathConfiguration(pathNetwork,pathConfig); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } void ZT_version(int *major,int *minor,int *revision) diff --git a/node/Node.hpp b/node/Node.hpp index 9658174f..1aa01c9a 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -192,7 +192,7 @@ public: inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); - void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); + ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); World planet() const; std::vector moons() const; diff --git a/node/Packet.hpp b/node/Packet.hpp index 5fc631b1..db70e06f 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -225,12 +225,8 @@ /** * Packet buffer size (can be changed) - * - * The current value is big enough for ZT_MAX_PACKET_FRAGMENTS, the pragmatic - * packet fragment limit, times the default UDP MTU. Most packets won't be - * this big. */ -#define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_UDP_DEFAULT_PAYLOAD_MTU) +#define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_DEFAULT_PHYSMTU) /** * Minimum viable packet length (a.k.a. header length) diff --git a/node/Switch.cpp b/node/Switch.cpp index 952bdef8..f46b3e73 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -722,10 +722,13 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) return false; } - unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); + unsigned int mtu = ZT_DEFAULT_PHYSMTU; + uint64_t trustedPathId = 0; + RR->topology->getOutboundPathInfo(viaPath->address(),mtu,trustedPathId); + + unsigned int chunkSize = std::min(packet.size(),mtu); packet.setFragmented(chunkSize < packet.size()); - const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); if (trustedPathId) { packet.setTrusted(trustedPathId); } else { @@ -737,13 +740,13 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) // Too big for one packet, fragment the rest unsigned int fragStart = chunkSize; unsigned int remaining = packet.size() - chunkSize; - unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); - if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) + unsigned int fragsRemaining = (remaining / (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)); + if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) ++fragsRemaining; const unsigned int totalFragments = fragsRemaining + 1; for(unsigned int fno=1;fnosend(RR,tPtr,frag.data(),frag.size(),now); fragStart += chunkSize; diff --git a/node/Topology.cpp b/node/Topology.cpp index ee5d969d..905b6a91 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -65,7 +65,7 @@ static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x0 Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : RR(renv), - _trustedPathCount(0), + _numConfiguredPhysicalPaths(0), _amRoot(false) { uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; diff --git a/node/Topology.hpp b/node/Topology.hpp index 43921896..34df28a1 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -339,6 +339,41 @@ public: */ inline bool amRoot() const { return _amRoot; } + /** + * Get info about a path + * + * The supplied result variables are not modified if no special config info is found. + * + * @param physicalAddress Physical endpoint address + * @param mtu Variable set to MTU + * @param trustedPathId Variable set to trusted path ID + */ + inline void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId) + { + for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i ZT_MAX_TRUSTED_PATHS) - count = ZT_MAX_TRUSTED_PATHS; - Mutex::Lock _l(_trustedPaths_m); - for(unsigned int i=0;i cpaths; + for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i ZT_MAX_PHYSMTU) + pc.mtu = ZT_MAX_PHYSMTU; + + cpaths[*(reinterpret_cast(pathNetwork))] = pc; + } else { + cpaths.erase(*(reinterpret_cast(pathNetwork))); + } + + unsigned int cnt = 0; + for(std::map::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cntfirst; + _physicalPathConfig[cnt].second = i->second; + ++cnt; + } + _numConfiguredPhysicalPaths = cnt; } - _trustedPathCount = count; } /** @@ -414,10 +467,8 @@ private: const RuntimeEnvironment *const RR; - uint64_t _trustedPathIds[ZT_MAX_TRUSTED_PATHS]; - InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; - unsigned int _trustedPathCount; - Mutex _trustedPaths_m; + std::pair _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS]; + volatile unsigned int _numConfiguredPhysicalPaths; Hashtable< Address,SharedPtr > _peers; Mutex _peers_m; diff --git a/service/OneService.cpp b/service/OneService.cpp index 093d9ee8..66e9a9c8 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -564,16 +564,14 @@ public: // Read local configuration { - uint64_t trustedPathIds[ZT_MAX_TRUSTED_PATHS]; - InetAddress trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; - unsigned int trustedPathCount = 0; + std::map ppc; // LEGACY: support old "trustedpaths" flat file FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(),"r"); if (trustpaths) { fprintf(stderr,"WARNING: 'trustedpaths' flat file format is deprecated in favor of path definitions in local.conf" ZT_EOL_S); char buf[1024]; - while ((fgets(buf,sizeof(buf),trustpaths))&&(trustedPathCount < ZT_MAX_TRUSTED_PATHS)) { + while (fgets(buf,sizeof(buf),trustpaths)) { int fno = 0; char *saveptr = (char *)0; uint64_t trustedPathId = 0; @@ -587,9 +585,8 @@ public: ++fno; } if ( (trustedPathId != 0) && ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathNetwork.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (trustedPathNetwork.netmaskBits() > 0) ) { - trustedPathIds[trustedPathCount] = trustedPathId; - trustedPathNetworks[trustedPathCount] = trustedPathNetwork; - ++trustedPathCount; + ppc[trustedPathNetwork].trustedPathId = trustedPathId; + ppc[trustedPathNetwork].mtu = 0; // use default } } fclose(trustpaths); @@ -618,12 +615,10 @@ public: if (phy.value().is_object()) { uint64_t tpid; if ((tpid = OSUtils::jsonInt(phy.value()["trustedPathId"],0ULL)) != 0ULL) { - if ( ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (net.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (net.netmaskBits() > 0) ) { - trustedPathIds[trustedPathCount] = tpid; - trustedPathNetworks[trustedPathCount] = net; - ++trustedPathCount; - } + if ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) + ppc[net].trustedPathId = tpid; } + ppc[net].mtu = (int)OSUtils::jsonInt(phy.value()["mtu"],0ULL); // 0 means use default } } } @@ -638,8 +633,10 @@ public: } // Set trusted paths if there are any - if (trustedPathCount) - _node->setTrustedPaths(reinterpret_cast(trustedPathNetworks),trustedPathIds,trustedPathCount); + if (ppc.size() > 0) { + for(std::map::iterator i(ppc.begin());i!=ppc.end();++i) + _node->setPhysicalPathConfiguration(reinterpret_cast(&(i->first)),&(i->second)); + } } // Apply other runtime configuration from local.conf diff --git a/service/README.md b/service/README.md index f5223f2d..77085a6f 100644 --- a/service/README.md +++ b/service/README.md @@ -14,7 +14,8 @@ Settings available in `local.conf` (this is not valid JSON, and JSON does not al "physical": { /* Settings that apply to physical L2/L3 network paths. */ "NETWORK/bits": { /* Network e.g. 10.0.0.0/24 or fd00::/32 */ "blacklist": true|false, /* If true, blacklist this path for all ZeroTier traffic */ - "trustedPathId": 0|!0 /* If present and nonzero, define this as a trusted path (see below) */ + "trustedPathId": 0|!0, /* If present and nonzero, define this as a trusted path (see below) */ + "mtu": 0|!0 /* if present and non-zero, set UDP maximum payload MTU for this path */ } /* ,... additional networks */ }, "virtual": { /* Settings applied to ZeroTier virtual network devices (VL1) */ -- cgit v1.2.3 From 52916eebcfae2559966d12d4be4b5376289a982d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 14 Sep 2017 20:56:50 -0700 Subject: Keep attemting to upgrade direct path if path is not private to facilitate better use of LANs and backplane networks. --- node/Peer.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'node') diff --git a/node/Peer.cpp b/node/Peer.cpp index b3020854..a954b716 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -194,8 +194,12 @@ void Peer::received( } } } - } else if (this->trustEstablished(now)) { - // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) + } + + // If we are being relayed or if we're using a global address, send PUSH_DIRECT_PATHS. + // In the global address case we push only configured direct paths to accomplish + // fall-forward to local backplane networks over e.g. LAN or Amazon VPC. + if ( ((hops > 0)||(path->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) && (this->trustEstablished(now)) ) { if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; @@ -205,13 +209,15 @@ void Peer::received( for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) pathsToPush.push_back(*i); - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; + if (hops > 0) { + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } } } -- cgit v1.2.3