diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/Constants.hpp | 5 | ||||
-rw-r--r-- | node/IncomingPacket.cpp | 4 | ||||
-rw-r--r-- | node/InetAddress.hpp | 22 | ||||
-rw-r--r-- | node/Path.hpp | 2 | ||||
-rw-r--r-- | node/Peer.cpp | 28 | ||||
-rw-r--r-- | node/Peer.hpp | 19 | ||||
-rw-r--r-- | node/SelfAwareness.cpp | 41 | ||||
-rw-r--r-- | node/SelfAwareness.hpp | 8 | ||||
-rw-r--r-- | node/Topology.cpp | 30 | ||||
-rw-r--r-- | node/Topology.hpp | 38 |
10 files changed, 102 insertions, 95 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp index d4944b5e..58b5f4b4 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -302,11 +302,6 @@ #define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 2) + ZT_PING_CHECK_DELAY) /** - * Path activity timeout (for non-fixed paths) - */ -#define ZT_PEER_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT - -/** * Stop relaying via peers that have not responded to direct sends * * When we send something (including frames), we generally expect a response. diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 17eb09d9..e2819f0b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -264,9 +264,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) if (RR->topology->isSupernode(id.address())) { RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); - RR->sa->iam(destAddr,true); + RR->sa->iam(_remoteAddress,destAddr,true); } else { - RR->sa->iam(destAddr,false); + RR->sa->iam(_remoteAddress,destAddr,false); } Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 2ed23761..43fcc333 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -74,21 +74,19 @@ struct InetAddress : public sockaddr_storage /** * IP address scope * - * Be sure the integer values of these start at 0 and increment - * monotonically without gaps, as they're used as an array index. - * The NONE entry must be the last, since it's the count. It's - * okay to change these since they are not exported via the API. + * Do not change these numeric index values without taking a look + * at SelfAwareness. Values 1-5 are mapped onto an array index. */ enum IpScope { - IP_SCOPE_LOOPBACK = 0, // 127.0.0.1 - IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other multicast IPs - IP_SCOPE_LINK_LOCAL = 2, // 169.254.x.x, IPv6 LL - IP_SCOPE_PRIVATE = 3, // 10.x.x.x, etc. - IP_SCOPE_PSEUDOPRIVATE = 4, // 28.x.x.x, etc. -- unofficially unrouted IP blocks often "bogarted" - IP_SCOPE_SHARED = 5, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT - IP_SCOPE_GLOBAL = 6, // globally routable IP address (all others) - IP_SCOPE_NONE = 7 // not an IP address -- also the number of classes, must be last entry + IP_SCOPE_NONE = 0, // not an IP address -- also the number of classes, must be last entry + IP_SCOPE_LINK_LOCAL = 1, // 169.254.x.x, IPv6 LL + IP_SCOPE_PRIVATE = 2, // 10.x.x.x, etc. + IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IP blocks often "bogarted" + IP_SCOPE_SHARED = 4, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT + IP_SCOPE_GLOBAL = 5, // globally routable IP address (all others) + IP_SCOPE_LOOPBACK = 6, // 127.0.0.1 + IP_SCOPE_MULTICAST = 7 // 224.0.0.0 and other multicast IPs }; InetAddress() throw() { memset(this,0,sizeof(InetAddress)); } diff --git a/node/Path.hpp b/node/Path.hpp index a5ee6aa9..7837ba4e 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -145,7 +145,7 @@ public: inline bool active(uint64_t now) const throw() { - return ( (_fixed) || ((now - _lastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT) ); + return ( (_fixed) || ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT) ); } /** diff --git a/node/Peer.cpp b/node/Peer.cpp index debb4533..beaa9d3b 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -192,6 +192,34 @@ void Peer::clearPaths(bool fixedToo) } } +void Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope scope,uint64_t now) +{ + unsigned int np = _numPaths; + unsigned int x = 0; + unsigned int y = 0; + while (x < np) { + if (_paths[x].address().ipScope() == scope) { + if (_paths[x].fixed()) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_NOP); + outp.armor(_key,false); + RR->node->putPacket(_paths[x].address(),outp.data(),outp.size(),_paths[x].desperation(now)); + _paths[y++] = _paths[x]; // keep fixed paths + } + } else { + _paths[y++] = _paths[x]; // keep paths not in this scope + } + ++x; + } + _numPaths = y; + + if ((y < np)&&(alive(now))) { + // Try to re-establish direct connectivity to this peer if it's alive + // and we have forgotten paths to it. + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_NOP); + RR->sw->send(outp,true); + } +} + void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const { uint64_t bestV4 = 0,bestV6 = 0; diff --git a/node/Peer.hpp b/node/Peer.hpp index 147ce571..31964c39 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -230,10 +230,9 @@ public: inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; } /** - * @param now Current time - * @return True if peer has received something within ZT_PEER_ACTIVITY_TIMEOUT ms + * @return True if peer has received an actual data frame within ZT_PEER_ACTIVITY_TIMEOUT milliseconds */ - inline bool alive(uint64_t now) const throw() { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline uint64_t alive(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Current latency or 0 if unknown (max: 65535) @@ -293,6 +292,20 @@ public: void clearPaths(bool fixedToo); /** + * Reset paths within a given scope + * + * For fixed paths in this scope, a packet is sent. Non-fixed paths in this + * scope are forgotten. If there are no paths remaining, a message is sent + * indirectly to reestablish connectivity if we're actively exchanging + * data with this peer (alive). + * + * @param RR Runtime environment + * @param scope IP scope of paths to reset + * @param now Current time + */ + void resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope scope,uint64_t now); + + /** * @return 256-bit secret symmetric encryption key */ inline const unsigned char *key() const throw() { return _key; } diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index c8b700a0..74c9f182 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -25,6 +25,10 @@ * LLC. Start here: http://www.zerotier.com/ */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + #include "Constants.hpp" #include "SelfAwareness.hpp" #include "RuntimeEnvironment.hpp" @@ -35,17 +39,52 @@ namespace ZeroTier { +class _ResetWithinScope +{ +public: + _ResetWithinScope(const RuntimeEnvironment *renv,uint64_t now,InetAddress::IpScope scope) : + RR(renv), + _now(now), + _scope(scope) {} + inline void operator()(Topology &t,const SharedPtr<Peer> &p) { p->resetWithinScope(RR,_scope,_now); } +private: + const RuntimeEnvironment *RR; + uint64_t _now; + InetAddress::IpScope _scope; +}; + SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : RR(renv) { + memset(_lastPhysicalAddress,0,sizeof(_lastPhysicalAddress)); } SelfAwareness::~SelfAwareness() { } -void SelfAwareness::iam(const InetAddress &physicalAddress,bool trusted) +void SelfAwareness::iam(const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted) { + const unsigned int scope = (unsigned int)myPhysicalAddress.ipScope(); + + // This code depends on the numeric values assigned to scopes in InetAddress.hpp + if ((scope > 0)&&(scope < (unsigned int)InetAddress::IP_SCOPE_LOOPBACK)) { + /* For now only trusted peers are permitted to inform us of changes to + * our global Internet IP or to changes of NATed IPs. We'll let peers on + * private, shared, or link-local networks inform us of changes as long + * as they too are at the same scope. This discrimination avoids a DoS + * attack in which an attacker could force us to reset our connections. */ + if ( (!trusted) && ((scope == (unsigned int)InetAddress::IP_SCOPE_GLOBAL)||(scope != (unsigned int)reporterPhysicalAddress.ipScope())) ) + return; + + InetAddress &lastPhy = _lastPhysicalAddress[scope - 1]; + if ((lastPhy)&&(lastPhy != myPhysicalAddress)) { + lastPhy = myPhysicalAddress; + _ResetWithinScope rset(RR,RR->node->now(),(InetAddress::IpScope)scope); + RR->topology->eachPeer<_ResetWithinScope &>(rset); + } + } + Mutex::Lock _l(_lock); } diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 6d0b9ebb..eadc2149 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -47,14 +47,16 @@ public: /** * Called when a trusted remote peer informs us of our external network address * - * @param physicalAddress Physical address as reflected by any trusted peer - * @param trusted True if this peer is trusted + * @param reporterPhysicalAddress Physical address that reporting peer seems to have + * @param myPhysicalAddress Physical address that peer says we have + * @param trusted True if this peer is trusted as an authority to inform us of external address changes */ - void iam(const InetAddress &physicalAddress,bool trusted); + void iam(const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted); private: const RuntimeEnvironment *RR; Mutex _lock; + InetAddress _lastPhysicalAddress[5]; // 5 == the number of address classes we care about, see InetAddress.hpp and SelfAwareness.cpp }; } // namespace ZeroTier diff --git a/node/Topology.cpp b/node/Topology.cpp index 8b3d2e71..295c3c8a 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -253,36 +253,6 @@ void Topology::clean(uint64_t now) } } -/* -bool Topology::updateSurface(const SharedPtr<Peer> &remotePeer,const InetAddress &mirroredAddress,uint64_t now) -{ - Mutex::Lock _l(_lock); - - if (std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),remotePeer->address()) == _supernodeAddresses.end()) - return false; - - if (_surface.update(mirroredAddress)) { - // Clear non-fixed paths for all peers -- will force reconnect on next activity - for(std::map< Address,SharedPtr<Peer> >::const_iterator ap(_activePeers.begin());ap!=_activePeers.end();++ap) - ap->second->clearPaths(false); - - // Reset TCP tunneling if our global addressing has changed - if (!mirroredAddress.isLinkLocal()) - (const_cast <RuntimeEnvironment *>(RR))->tcpTunnelingEnabled = false; - - // Ping supernodes now (other than the one we might have just heard from) - for(std::vector< SharedPtr<Peer> >::const_iterator sn(_supernodePeers.begin());sn!=_supernodePeers.end();++sn) { - if (remotePeer != *sn) - (*sn)->sendPing(RR,now); - } - - return true; - } - - return false; -} -*/ - bool Topology::authenticateRootTopology(const Dictionary &rt) { try { diff --git a/node/Topology.hpp b/node/Topology.hpp index 6dee11bc..d099d93b 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -280,44 +280,6 @@ public: uint64_t _now; const RuntimeEnvironment *RR; }; - - /** - * Function object to forget direct links to active peers and then ping them indirectly - */ - class ResetActivePeers - { - public: - ResetActivePeers(const RuntimeEnvironment *renv,uint64_t now) throw() : - _now(now), - _supernode(renv->topology->getBestSupernode()), - _supernodeAddresses(renv->topology->supernodeAddresses()), - RR(renv) {} - - inline void operator()(Topology &t,const SharedPtr<Peer> &p) - { - p->clearPaths(false); // false means don't forget 'fixed' paths e.g. supernodes - - Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(p->key(),false); // no need to encrypt a NOP - - if (std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),p->address()) != _supernodeAddresses.end()) { - // Send NOP directly to supernodes - p->send(RR,outp.data(),outp.size(),_now); - } else { - // Send NOP indirectly to regular peers if still active, triggering a new RENDEZVOUS - if (((_now - p->lastFrame()) < ZT_PEER_PATH_ACTIVITY_TIMEOUT)&&(_supernode)) { - TRACE("sending reset NOP to %s",p->address().toString().c_str()); - _supernode->send(RR,outp.data(),outp.size(),_now); - } - } - } - - private: - uint64_t _now; - SharedPtr<Peer> _supernode; - std::vector<Address> _supernodeAddresses; - const RuntimeEnvironment *RR; - }; #endif /** |