diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/Constants.hpp | 13 | ||||
-rw-r--r-- | node/Multicaster.hpp | 43 | ||||
-rw-r--r-- | node/PacketDecoder.cpp | 140 | ||||
-rw-r--r-- | node/Peer.cpp | 5 | ||||
-rw-r--r-- | node/Peer.hpp | 20 | ||||
-rw-r--r-- | node/Switch.cpp | 34 | ||||
-rw-r--r-- | node/Topology.cpp | 2 | ||||
-rw-r--r-- | node/Topology.hpp | 2 |
8 files changed, 167 insertions, 92 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp index 4d720d5d..1745ef6b 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -314,14 +314,19 @@ error_no_byte_order_defined; #define ZT_TCP_TUNNEL_FAILOVER_TIMEOUT (ZT_STARTUP_AGGRO * 5) /** + * Timeout for overall peer activity (measured from last receive) + */ +#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_DIRECT_PING_DELAY * 2) + ZT_PING_CHECK_DELAY) +#define ZT_PEER_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT /** * Close TCP sockets if unused for this long (SocketManager) */ -#define ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT ZT_PEER_PATH_ACTIVITY_TIMEOUT +#define ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT /** * Stop relaying via peers that have not responded to direct sends @@ -387,14 +392,14 @@ error_no_byte_order_defined; #define ZT_UPDATE_MIN_INTERVAL 120000 /** - * Maximum interval between checks for new versions (2 hours) + * Maximum interval between checks for new versions */ #define ZT_UPDATE_MAX_INTERVAL 7200000 /** * Software update HTTP timeout in seconds */ -#define ZT_UPDATE_HTTP_TIMEOUT 30 +#define ZT_UPDATE_HTTP_TIMEOUT 120 /** * Sanity limit on maximum bridge routes diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 7d67aada..262f0304 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -40,6 +40,7 @@ #include "Constants.hpp" #include "Mutex.hpp" #include "MulticastGroup.hpp" +#include "Topology.hpp" #include "Address.hpp" #include "Buffer.hpp" @@ -112,6 +113,7 @@ public: * @param nwid Network ID * @param mg Multicast group * @param nextHopFunc Function to call for each address, search stops if it returns false + * @tparam F Function to receive each next hop address */ template<typename F> inline void getNextHops(uint64_t nwid,const MulticastGroup &mg,F nextHopFunc) @@ -151,20 +153,40 @@ public: * @param origin Originating address * @param prefixBits Number of bits in propagation restriction prefix * @param prefix Propagation restrition prefix + * @param topology Topology database + * @param now Current time */ - AddToPropagationQueue(unsigned char **ptr,unsigned char *end,unsigned char *bloom,uint16_t bloomNonce,const Address &origin,unsigned int prefixBits,uint64_t prefix) - throw() : + AddToPropagationQueue( + unsigned char **ptr, + unsigned char *end, + unsigned char *bloom, + uint16_t bloomNonce, + const Address &origin, + unsigned int prefixBits, + uint64_t prefix, + const Topology *topology, + uint64_t now) + throw() : _origin(origin), _bloomNonce((uint64_t)bloomNonce), _prefix(prefix), + _now(now), _ptr(ptr), _end(end), _bloom(bloom), + _topology(topology), _prefixBits(prefixBits) {} + /** + * @param a Address to (possibly) add + * @return True if FIFO still contains room for more possible addresses + */ inline bool operator()(const Address &a) throw() { + if (*_ptr >= _end) + return false; + // Exclude original sender -- obviously they've already seen it if (a == _origin) return true; @@ -173,27 +195,36 @@ public: if (!a.withinMulticastPropagationPrefix(_prefix,_prefixBits)) return true; - // Exclude addresses remembered in bloom filter -- or else remember them + // Exclude addresses remembered in bloom filter uint64_t aint = a.toInt() + _bloomNonce; const unsigned int bit = (unsigned int)(aint ^ (aint >> 13) ^ (aint >> 26) ^ (aint >> 39)) & 0x1fff; unsigned char *const bbyte = _bloom + (bit >> 3); // note: bloom filter size == 1024 is hard-coded here const unsigned char bmask = 1 << (bit & 7); if ((*bbyte & bmask)) + return true; // address already visited + + // Exclude peers that don't appear to be online + SharedPtr<Peer> p(_topology->getPeer(a)); + if ((!p)||(!p->alive(_now))) return true; - else *bbyte |= bmask; + + // Remember address in bloom filter + *bbyte |= bmask; a.copyTo(*_ptr,ZT_ADDRESS_LENGTH); - return ((*_ptr += ZT_ADDRESS_LENGTH) != _end); + return ((*_ptr += ZT_ADDRESS_LENGTH) < _end); } private: const Address _origin; const uint64_t _bloomNonce; const uint64_t _prefix; + const uint64_t _now; unsigned char **const _ptr; unsigned char *const _end; unsigned char *const _bloom; - unsigned int _prefixBits; + const Topology *const _topology; + const unsigned int _prefixBits; }; private: diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 1e62664e..369eda7b 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -530,7 +530,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared return false; } - // These fields change + // These fields in the packet are changed by each forwarder unsigned int depth = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH); unsigned char *const fifo = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO); unsigned char *const bloom = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM); @@ -568,6 +568,9 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared */ SharedPtr<Network> network(_r->nc->network(nwid)); + SharedPtr<NetworkConfig> nconf; + if (network) + nconf = network->config2(); /* Grab, verify, and learn certificate of network membership if any -- provided we are * a member of this network. Note: we can do this before verification of the actual @@ -679,50 +682,30 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared // be the case unless we're a supernode), check to see if we should // inject the packet. This also gives us an opportunity to check things // like multicast bandwidth constraints. - if (network) { - SharedPtr<NetworkConfig> nconf(network->config2()); - if (nconf) { - // Learn real maxDepth from netconf - maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,nconf->multicastDepth()); - if (!maxDepth) - maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH; - - if (!network->isAllowed(origin)) { - // Papers, please... - Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); - outp.append(packetId()); - outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(nwid); - outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); - TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,origin.toString().c_str()); - return true; - } - - if (MAC(origin,network->id()) != sourceMac) { - if (!nconf->permitsBridging(origin)) { -#ifdef ZT_TRACE_MULTICAST - Utils::snprintf(mct,sizeof(mct), - "%.16llx %.2u %.3u%s %c %s dropped: bridging not allowed", - guid, - prefix, - depth, - mctdepth, - (_r->topology->amSupernode() ? 'S' : '-'), - _r->identity.address().toString().c_str()); - _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct)); -#endif - TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str()); - return true; - } - network->learnBridgeRoute(sourceMac,origin); - } + if ((network)&&(nconf)) { + // Learn real maxDepth from netconf + maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,nconf->multicastDepth()); + if (!maxDepth) + maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH; + + if (!network->isAllowed(origin)) { + // Papers, please... + Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); + outp.append(packetId()); + outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(nwid); + outp.armor(peer->key(),true); + _fromSock->send(_remoteAddress,outp.data(),outp.size()); + TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,origin.toString().c_str()); + return true; + } - if (!nconf->permitsEtherType(etherType)) { + if (MAC(origin,network->id()) != sourceMac) { + if (!nconf->permitsBridging(origin)) { #ifdef ZT_TRACE_MULTICAST Utils::snprintf(mct,sizeof(mct), - "%.16llx %.2u %.3u%s %c %s dropped: ethertype not allowed", + "%.16llx %.2u %.3u%s %c %s dropped: bridging not allowed", guid, prefix, depth, @@ -731,31 +714,48 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared _r->identity.address().toString().c_str()); _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct)); #endif - TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType); + TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str()); return true; } + network->learnBridgeRoute(sourceMac,origin); + } - if (!network->updateAndCheckMulticastBalance(origin,dest,frameLen)) { - // Rate limits can only be checked by members of this network, but - // there should be enough of them that over-limit multicasts get - // their propagation aborted. + if (!nconf->permitsEtherType(etherType)) { #ifdef ZT_TRACE_MULTICAST - Utils::snprintf(mct,sizeof(mct), - "%.16llx %.2u %.3u%s %c %s dropped: rate limits exceeded", - guid, - prefix, - depth, - mctdepth, - (_r->topology->amSupernode() ? 'S' : '-'), - _r->identity.address().toString().c_str()); - _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct)); + Utils::snprintf(mct,sizeof(mct), + "%.16llx %.2u %.3u%s %c %s dropped: ethertype not allowed", + guid, + prefix, + depth, + mctdepth, + (_r->topology->amSupernode() ? 'S' : '-'), + _r->identity.address().toString().c_str()); + _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct)); #endif - TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str()); - return true; - } + TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType); + return true; + } - network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen); + if (!network->updateAndCheckMulticastBalance(origin,dest,frameLen)) { + // Rate limits can only be checked by members of this network, but + // there should be enough of them that over-limit multicasts get + // their propagation aborted. +#ifdef ZT_TRACE_MULTICAST + Utils::snprintf(mct,sizeof(mct), + "%.16llx %.2u %.3u%s %c %s dropped: rate limits exceeded", + guid, + prefix, + depth, + mctdepth, + (_r->topology->amSupernode() ? 'S' : '-'), + _r->identity.address().toString().c_str()); + _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct)); +#endif + TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str()); + return true; } + + network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen); } } @@ -816,11 +816,27 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared } else break; } - // Add any next hops we know about to FIFO + // Add any other next hops we know about to FIFO #ifdef ZT_TRACE_MULTICAST unsigned char *beforeAdd = newFifoPtr; #endif - _r->mc->getNextHops(nwid,dest,Multicaster::AddToPropagationQueue(&newFifoPtr,newFifoEnd,bloom,bloomNonce,origin,prefixBits,prefix)); + Multicaster::AddToPropagationQueue appender( + &newFifoPtr, + newFifoEnd, + bloom, + bloomNonce, + origin, + prefixBits, + prefix, + _r->topology, + Utils::now()); + if (nconf) { + for(std::set<Address>::const_iterator ab(nconf->activeBridges().begin());ab!=nconf->activeBridges().end();++ab) { + if (!appender(*ab)) + break; + } + } + _r->mc->getNextHops(nwid,dest,appender); #ifdef ZT_TRACE_MULTICAST unsigned int numAdded = (unsigned int)(newFifoPtr - beforeAdd) / ZT_ADDRESS_LENGTH; #endif diff --git a/node/Peer.cpp b/node/Peer.cpp index 54e30a74..e61631e2 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -35,6 +35,7 @@ namespace ZeroTier { Peer::Peer() : _lastUsed(0), + _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), _lastAnnouncedTo(0), @@ -47,6 +48,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) throw(std::runtime_error) : _id(peerIdentity), _lastUsed(0), + _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), _lastAnnouncedTo(0), @@ -73,6 +75,9 @@ void Peer::receive( // Update system-wide last packet receive time *((const_cast<uint64_t *>(&(_r->timeOfLastPacketReceived)))) = now; + // Global last receive time regardless of path + _lastReceive = now; + // Learn paths from direct packets (hops == 0) if (!hops) { { diff --git a/node/Peer.hpp b/node/Peer.hpp index a950b2fc..edb66e21 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -50,7 +50,7 @@ #include "NonCopyable.hpp" #include "Mutex.hpp" -#define ZT_PEER_SERIALIZATION_VERSION 8 +#define ZT_PEER_SERIALIZATION_VERSION 9 namespace ZeroTier { @@ -247,6 +247,11 @@ public: } /** + * @return Time of last receive of anything, whether direct or relayed + */ + inline uint64_t lastReceive() const throw() { return _lastReceive; } + + /** * @return Time of most recent unicast frame received */ inline uint64_t lastUnicastFrame() const throw() { return _lastUnicastFrame; } @@ -267,6 +272,16 @@ 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 + */ + inline bool alive(uint64_t now) const + throw() + { + return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); + } + + /** * @return Current latency or 0 if unknown (max: 65535) */ inline unsigned int latency() const @@ -424,6 +439,7 @@ public: _id.serialize(b,false); b.append(_key,sizeof(_key)); b.append(_lastUsed); + b.append(_lastReceive); b.append(_lastUnicastFrame); b.append(_lastMulticastFrame); b.append(_lastAnnouncedTo); @@ -448,6 +464,7 @@ public: p += _id.deserialize(b,p); memcpy(_key,b.field(p,sizeof(_key)),sizeof(_key)); p += sizeof(_key); _lastUsed = b.template at<uint64_t>(p); p += sizeof(uint64_t); + _lastReceive = b.template at<uint64_t>(p); p += sizeof(uint64_t); _lastUnicastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t); _lastMulticastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t); _lastAnnouncedTo = b.template at<uint64_t>(p); p += sizeof(uint64_t); @@ -472,6 +489,7 @@ private: std::vector<Path> _paths; volatile uint64_t _lastUsed; + volatile uint64_t _lastReceive; // direct or indirect volatile uint64_t _lastUnicastFrame; volatile uint64_t _lastMulticastFrame; volatile uint64_t _lastAnnouncedTo; diff --git a/node/Switch.cpp b/node/Switch.cpp index 46fb0b49..9b0e3e6e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -164,26 +164,26 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c memset(bloom,0,sizeof(bloom)); unsigned char *fifoPtr = fifo; - // All multicasts visit all active bridges first -- this is one of the two active/passive bridge differences + // Add all active bridges and then next hops we know about to propagation queue + Multicaster::AddToPropagationQueue appender( + &fifoPtr, + fifoEnd, + bloom, + bloomNonce, + _r->identity.address(), + nconf->multicastPrefixBits(), + prefix, + _r->topology, + now); for(std::set<Address>::const_iterator ab(nconf->activeBridges().begin());ab!=nconf->activeBridges().end();++ab) { - if ((*ab != _r->identity.address())&&(ab->withinMulticastPropagationPrefix(prefix,nconf->multicastPrefixBits()))) { - SharedPtr<Peer> abPeer(_r->topology->getPeer(*ab)); - if ((abPeer)&&(abPeer->hasActiveDirectPath(now))) { - ab->copyTo(fifoPtr,ZT_ADDRESS_LENGTH); - if ((fifoPtr += ZT_ADDRESS_LENGTH) == fifoEnd) - break; - } - } + if (!appender(*ab)) + break; } + _r->mc->getNextHops(network->id(),mg,appender); - // Then visit next hops according to multicaster (if there's room... almost certainly will be) - if (fifoPtr != fifoEnd) { - _r->mc->getNextHops(network->id(),mg,Multicaster::AddToPropagationQueue(&fifoPtr,fifoEnd,bloom,bloomNonce,_r->identity.address(),nconf->multicastPrefixBits(),prefix)); - - // Pad remainder of FIFO with zeroes - while (fifoPtr != fifoEnd) - *(fifoPtr++) = (unsigned char)0; - } + // Pad remainder of FIFO with zeroes + while (fifoPtr != fifoEnd) + *(fifoPtr++) = (unsigned char)0; // First element in FIFO is first hop, rest of FIFO is sent in packet *to* first hop Address firstHop(fifo,ZT_ADDRESS_LENGTH); diff --git a/node/Topology.cpp b/node/Topology.cpp index d88b64ca..d74179fe 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -89,7 +89,7 @@ SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer) return p; } -SharedPtr<Peer> Topology::getPeer(const Address &zta) +SharedPtr<Peer> Topology::getPeer(const Address &zta) const { if (zta == _r->identity.address()) { TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); diff --git a/node/Topology.hpp b/node/Topology.hpp index 74db8b50..293ac446 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -82,7 +82,7 @@ public: * @param zta ZeroTier address of peer * @return Peer or NULL if not found */ - SharedPtr<Peer> getPeer(const Address &zta); + SharedPtr<Peer> getPeer(const Address &zta) const; /** * Get an identity if cached or available in a peer record |