From 9617208e4027bec8a72e72a1fd89aa19ea9367d8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 09:53:43 -0700 Subject: Some cleanup, and use VERB_PUSH_DIRECT_PATHS to redirect newer peers. --- node/IncomingPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c8526dfb..d8f458e8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -280,8 +280,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // VALID -- if we made it here, packet passed identity and authenticity checks! - peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); + peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); if (destAddr) RR->sa->iam(id.address(),_remoteAddress,destAddr,RR->topology->isRoot(id),RR->node->now()); -- cgit v1.2.3 From 700c3166b7dcdec61b0dc47a4649776b9ba046e8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 10:51:11 -0700 Subject: Fix inverted sense bug. --- node/IncomingPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index d8f458e8..5ade8517 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -888,7 +888,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha { try { const uint64_t now = RR->node->now(); - if ((now - peer->lastDirectPathPushReceived()) >= ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL) { + if ((now - peer->lastDirectPathPushReceived()) < ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): too frequent!",source().toString().c_str(),_remoteAddress.toString().c_str()); return true; } -- cgit v1.2.3 From 54a99d8e32e3ee0aed222069e961d44ddd748399 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 11:14:07 -0700 Subject: Well that was broken. --- node/IncomingPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5ade8517..51e88364 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -622,7 +622,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr)); + const uint64_t nwid(at(ptr)); const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); RR->mc->add(now,nwid,group,peer->address()); #ifdef ZT_ENABLE_CLUSTER -- cgit v1.2.3 From a1a0ee4edb0933c9b82abad8715def6a63049658 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 12:01:00 -0700 Subject: Fix infinite loop in Cluster, clean up some stuff elsewhere, and back out rate limiting in PUSH_DIRECT_PATHS for now (but we will do something else to mitigate amplification attacks) --- node/Cluster.cpp | 5 ++-- node/Constants.hpp | 7 +----- node/IncomingPacket.cpp | 12 +++------- node/Peer.cpp | 1 - node/Peer.hpp | 17 ++------------ node/SelfAwareness.cpp | 12 +++++----- node/Topology.cpp | 62 +------------------------------------------------ 7 files changed, 16 insertions(+), 100 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index bd455933..eef02bc7 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -239,7 +239,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) const MAC mac(dmsg.field(ptr,6),6); ptr += 6; const uint32_t adi = dmsg.at(ptr); ptr += 4; RR->mc->add(RR->node->now(),nwid,MulticastGroup(mac,adi),address); - TRACE("[%u] %s likes %s/%.8x on %.16llu",(unsigned int)fromMemberId,address.toString().c_str(),mac.toString().c_str(),(unsigned int)adi,nwid); + TRACE("[%u] %s likes %s/%.8x on %.16llx",(unsigned int)fromMemberId,address.toString().c_str(),mac.toString().c_str(),(unsigned int)adi,nwid); } break; case STATE_MESSAGE_COM: { @@ -376,11 +376,12 @@ bool Cluster::sendViaCluster(const Address &fromPeerAddress,const Address &toPee Mutex::Lock _l2(_peerAffinities_m); std::vector<_PeerAffinity>::iterator i(std::lower_bound(_peerAffinities.begin(),_peerAffinities.end(),_PeerAffinity(toPeerAddress,0,0))); // O(log(n)) while ((i != _peerAffinities.end())&&(i->address() == toPeerAddress)) { - uint16_t mid = i->clusterMemberId(); + const uint16_t mid = i->clusterMemberId(); if ((mid != _id)&&(i->timestamp > mostRecentTimestamp)) { mostRecentTimestamp = i->timestamp; canHasPeer = mid; } + ++i; } } diff --git a/node/Constants.hpp b/node/Constants.hpp index 3ad07e4c..bef1183a 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -324,11 +324,6 @@ */ #define ZT_DIRECT_PATH_PUSH_INTERVAL 120000 -/** - * Minimum interval between direct path pushes from a given peer or we will ignore them - */ -#define ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL 2000 - /** * How long (max) to remember network certificates of membership? * @@ -355,7 +350,7 @@ /** * Maximum number of endpoints to contact per address type (to limit pushes like GitHub issue #235) */ -#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 8 +#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 2 /** * A test pseudo-network-ID that can be joined diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 51e88364..2514cd64 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -622,7 +622,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr)); + const uint64_t nwid = at(ptr); const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); RR->mc->add(now,nwid,group,peer->address()); #ifdef ZT_ENABLE_CLUSTER @@ -888,12 +888,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha { try { const uint64_t now = RR->node->now(); - if ((now - peer->lastDirectPathPushReceived()) < ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): too frequent!",source().toString().c_str(),_remoteAddress.toString().c_str()); - return true; - } - peer->setLastDirectPathPushReceived(now); - const RemotePath *currentBest = peer->getBestPath(now); unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); @@ -916,7 +910,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); if (v4Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) { if ((!currentBest)||(currentBest->address() != a)) - peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); + peer->attemptToContactAt(RR,_localAddress,a,now); } } } break; @@ -926,7 +920,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); if (v6Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) { if ((!currentBest)||(currentBest->address() != a)) - peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); + peer->attemptToContactAt(RR,_localAddress,a,now); } } } break; diff --git a/node/Peer.cpp b/node/Peer.cpp index f16f1421..d5367b17 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -55,7 +55,6 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastAnnouncedTo(0), _lastPathConfirmationSent(0), _lastDirectPathPushSent(0), - _lastDirectPathPushReceived(0), _lastPathSort(0), _vProto(0), _vMajor(0), diff --git a/node/Peer.hpp b/node/Peer.hpp index 0aca70b4..04b541af 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -407,16 +407,6 @@ public: */ bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime); - /** - * @return Time last direct path push was received - */ - inline uint64_t lastDirectPathPushReceived() const throw() { return _lastDirectPathPushReceived; } - - /** - * @param t New time of last direct path push received - */ - inline void setLastDirectPathPushReceived(uint64_t t) throw() { _lastDirectPathPushReceived = t; } - /** * Perform periodic cleaning operations */ @@ -450,7 +440,7 @@ public: const unsigned int recSizePos = b.size(); b.addSize(4); // space for uint32_t field length - b.append((uint16_t)1); // version of serialized Peer data + b.append((uint16_t)0); // version of serialized Peer data _id.serialize(b,false); @@ -461,7 +451,6 @@ public: b.append((uint64_t)_lastAnnouncedTo); b.append((uint64_t)_lastPathConfirmationSent); b.append((uint64_t)_lastDirectPathPushSent); - b.append((uint64_t)_lastDirectPathPushReceived); b.append((uint64_t)_lastPathSort); b.append((uint16_t)_vProto); b.append((uint16_t)_vMajor); @@ -513,7 +502,7 @@ public: const unsigned int recSize = b.template at(p); p += 4; if ((p + recSize) > b.size()) return SharedPtr(); // size invalid - if (b.template at(p) != 1) + if (b.template at(p) != 0) return SharedPtr(); // version mismatch p += 2; @@ -531,7 +520,6 @@ public: np->_lastAnnouncedTo = b.template at(p); p += 8; np->_lastPathConfirmationSent = b.template at(p); p += 8; np->_lastDirectPathPushSent = b.template at(p); p += 8; - np->_lastDirectPathPushReceived = b.template at(p); p += 8; np->_lastPathSort = b.template at(p); p += 8; np->_vProto = b.template at(p); p += 2; np->_vMajor = b.template at(p); p += 2; @@ -581,7 +569,6 @@ private: uint64_t _lastAnnouncedTo; uint64_t _lastPathConfirmationSent; uint64_t _lastDirectPathPushSent; - uint64_t _lastDirectPathPushReceived; uint64_t _lastPathSort; uint16_t _vProto; uint16_t _vMajor; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 1b70f17c..81d19369 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -123,16 +123,16 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi // For all peers for whom we forgot an address, send a packet indirectly if // they are still considered alive so that we will re-establish direct links. - SharedPtr sn(RR->topology->getBestRoot()); - if (sn) { - RemotePath *snp = sn->getBestPath(now); - if (snp) { + SharedPtr r(RR->topology->getBestRoot()); + if (r) { + RemotePath *rp = r->getBestPath(now); + if (rp) { for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->alive(now)) { - TRACE("sending indirect NOP to %s via %s(%s) to re-establish link",(*p)->address().toString().c_str(),sn->address().toString().c_str(),snp->address().toString().c_str()); + TRACE("sending indirect NOP to %s via %s to re-establish link",(*p)->address().toString().c_str(),r->address().toString().c_str()); Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); outp.armor((*p)->key(),true); - snp->send(RR,outp.data(),outp.size(),now); + rp->send(RR,outp.data(),outp.size(),now); } } } diff --git a/node/Topology.cpp b/node/Topology.cpp index 7bb4b449..09668ef5 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -254,68 +254,8 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou return *bestOverall; } - /* - unsigned int l,bestLatency = 65536; - uint64_t lds,ldr; - - // First look for a best root by comparing latencies, but exclude - // root servers that have not responded to direct messages in order to - // try to exclude any that are dead or unreachable. - for(std::vector< SharedPtr >::const_iterator sn(_rootPeers.begin());sn!=_rootPeers.end();) { - // Skip explicitly avoided relays - for(unsigned int i=0;iaddress()) - goto keep_searching_for_roots; - } - - // Skip possibly comatose or unreachable relays - lds = (*sn)->lastDirectSend(); - ldr = (*sn)->lastDirectReceive(); - if ((lds)&&(lds > ldr)&&((lds - ldr) > ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD)) - goto keep_searching_for_roots; - - if ((*sn)->hasActiveDirectPath(now)) { - l = (*sn)->latency(); - if (bestRoot) { - if ((l)&&(l < bestLatency)) { - bestLatency = l; - bestRoot = *sn; - } - } else { - if (l) - bestLatency = l; - bestRoot = *sn; - } - } - -keep_searching_for_roots: - ++sn; - } - - if (bestRoot) { - bestRoot->use(now); - return bestRoot; - } else if (strictAvoid) - return SharedPtr(); - - // If we have nothing from above, just pick one without avoidance criteria. - for(std::vector< SharedPtr >::const_iterator sn=_rootPeers.begin();sn!=_rootPeers.end();++sn) { - if ((*sn)->hasActiveDirectPath(now)) { - unsigned int l = (*sn)->latency(); - if (bestRoot) { - if ((l)&&(l < bestLatency)) { - bestLatency = l; - bestRoot = *sn; - } - } else { - if (l) - bestLatency = l; - bestRoot = *sn; - } - } - } - */ } + return SharedPtr(); } -- cgit v1.2.3 From 16bc3e03982286232e1df2da17d8b2fc3c5a5c55 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 15:00:16 -0700 Subject: Factor out RemotePath subclass of Path -- no longer needed, just cruft. --- include/ZeroTierOne.h | 3 +- node/Cluster.cpp | 1 + node/IncomingPacket.cpp | 5 +- node/Multicaster.cpp | 1 + node/Network.cpp | 1 + node/Node.cpp | 14 ++--- node/Node.hpp | 6 +- node/Path.cpp | 45 ++++++++++++++ node/Path.hpp | 117 +++++++++++++++++++++++++++++++++-- node/Peer.cpp | 32 +++++----- node/Peer.hpp | 24 ++++---- node/RemotePath.hpp | 161 ------------------------------------------------ node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 2 +- objects.mk | 1 + service/OneService.cpp | 4 +- 16 files changed, 208 insertions(+), 211 deletions(-) create mode 100644 node/Path.cpp delete mode 100644 node/RemotePath.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 3457634b..01c8bcde 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1356,11 +1356,10 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); * reject bad, empty, and unusable addresses. * * @param addr Local interface address - * @param metric Local interface metric * @param trust How much do you trust the local network under this interface? * @return Boolean: non-zero if address was accepted and added */ -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust); +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,enum ZT_LocalInterfaceAddressTrust trust); /** * Clear local interface addresses diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 73ff5846..07ca0ba1 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -48,6 +48,7 @@ #include "Topology.hpp" #include "Packet.hpp" #include "Switch.hpp" +#include "Node.hpp" namespace ZeroTier { diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2514cd64..7015535a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -44,6 +44,7 @@ #include "SHA512.hpp" #include "World.hpp" #include "Cluster.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -888,7 +889,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha { try { const uint64_t now = RR->node->now(); - const RemotePath *currentBest = peer->getBestPath(now); + const Path *currentBest = peer->getBestPath(now); unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; @@ -1036,7 +1037,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - RemotePath *const rp = nhp->getBestPath(now); + Path *const rp = nhp->getBestPath(now); if (rp) nextHopBestPathAddress[h] = rp->address(); } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 6e6cd628..e43d7d88 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -37,6 +37,7 @@ #include "Peer.hpp" #include "C25519.hpp" #include "CertificateOfMembership.hpp" +#include "Node.hpp" namespace ZeroTier { diff --git a/node/Network.cpp b/node/Network.cpp index cd30e386..afbe1074 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -37,6 +37,7 @@ #include "Packet.hpp" #include "Buffer.hpp" #include "NetworkController.hpp" +#include "Node.hpp" #include "../version.h" diff --git a/node/Node.cpp b/node/Node.cpp index 87871e20..82cda66d 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -448,10 +448,10 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; - std::vector paths(pi->second->paths()); - RemotePath *bestPath = pi->second->getBestPath(_now); + std::vector paths(pi->second->paths()); + Path *bestPath = pi->second->getBestPath(_now); p->pathCount = 0; - for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { + for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage)); p->paths[p->pathCount].lastSend = path->lastSend(); p->paths[p->pathCount].lastReceive = path->lastReceived(); @@ -499,11 +499,11 @@ void Node::freeQueryResult(void *qr) ::free(qr); } -int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust) +int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,ZT_LocalInterfaceAddressTrust trust) { if (Path::isAddressValidForPath(*(reinterpret_cast(addr)))) { Mutex::Lock _l(_directPaths_m); - _directPaths.push_back(Path(*(reinterpret_cast(addr)),metric,(Path::Trust)trust)); + _directPaths.push_back(*(reinterpret_cast(addr))); std::sort(_directPaths.begin(),_directPaths.end()); _directPaths.erase(std::unique(_directPaths.begin(),_directPaths.end()),_directPaths.end()); return 1; @@ -900,10 +900,10 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr) } catch ( ... ) {} } -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust) +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,enum ZT_LocalInterfaceAddressTrust trust) { try { - return reinterpret_cast(node)->addLocalInterfaceAddress(addr,metric,trust); + return reinterpret_cast(node)->addLocalInterfaceAddress(addr,trust); } catch ( ... ) { return 0; } diff --git a/node/Node.hpp b/node/Node.hpp index 4094a79e..48c5ead8 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -105,7 +105,7 @@ public: ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; ZT_VirtualNetworkList *networks() const; void freeQueryResult(void *qr); - int addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust); + int addLocalInterfaceAddress(const struct sockaddr_storage *addr,ZT_LocalInterfaceAddressTrust trust); void clearLocalInterfaceAddresses(); void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); @@ -207,7 +207,7 @@ public: /** * @return Potential direct paths to me a.k.a. local interface addresses */ - inline std::vector directPaths() const + inline std::vector directPaths() const { Mutex::Lock _l(_directPaths_m); return _directPaths; @@ -285,7 +285,7 @@ private: std::vector< ZT_CircuitTest * > _circuitTests; Mutex _circuitTests_m; - std::vector _directPaths; + std::vector _directPaths; Mutex _directPaths_m; Mutex _backgroundTasksLock; diff --git a/node/Path.cpp b/node/Path.cpp new file mode 100644 index 00000000..e2475751 --- /dev/null +++ b/node/Path.cpp @@ -0,0 +1,45 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#include "Path.hpp" +#include "AntiRecursion.hpp" +#include "RuntimeEnvironment.hpp" +#include "Node.hpp" + +namespace ZeroTier { + +bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) +{ + if (RR->node->putPacket(_localAddress,address(),data,len)) { + sent(now); + RR->antiRec->logOutgoingZT(data,len); + return true; + } + return false; +} + +} // namespace ZeroTier diff --git a/node/Path.hpp b/node/Path.hpp index 6fa3c52e..99f6590b 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -28,12 +28,19 @@ #ifndef ZT_PATH_HPP #define ZT_PATH_HPP +#include +#include + +#include +#include + #include "Constants.hpp" #include "InetAddress.hpp" -#include "Utils.hpp" namespace ZeroTier { +class RuntimeEnvironment; + /** * Base class for paths * @@ -67,19 +74,87 @@ public: }; Path() : + _lastSend(0), + _lastReceived(0), _addr(), + _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE), - _trust(TRUST_NORMAL) + _trust(TRUST_NORMAL), + _flags(0) { } - Path(const InetAddress &addr,int metric,Trust trust) : + Path(const InetAddress &localAddress,const InetAddress &addr,Trust trust) : + _lastSend(0), + _lastReceived(0), _addr(addr), + _localAddress(localAddress), _ipScope(addr.ipScope()), - _trust(trust) + _trust(trust), + _flags(0) + { + } + + /** + * Called when a packet is sent to this remote path + * + * This is called automatically by Path::send(). + * + * @param t Time of send + */ + inline void sent(uint64_t t) + throw() { + _lastSend = t; } + /** + * Called when a packet is received from this remote path + * + * @param t Time of receive + */ + inline void received(uint64_t t) + throw() + { + _lastReceived = t; + } + + /** + * @param now Current time + * @return True if this path appears active + */ + inline bool active(uint64_t now) const + throw() + { + return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT); + } + + /** + * Send a packet via this path + * + * @param RR Runtime environment + * @param data Packet data + * @param len Packet length + * @param now Current time + * @return True if transport reported success + */ + bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now); + + /** + * @return Address of local side of this path or NULL if unspecified + */ + inline const InetAddress &localAddress() const throw() { return _localAddress; } + + /** + * @return Time of last send to this path + */ + inline uint64_t lastSend() const throw() { return _lastSend; } + + /** + * @return Time of last receive from this path + */ + inline uint64_t lastReceived() const throw() { return _lastReceived; } + /** * @return Physical address */ @@ -157,10 +232,42 @@ public: return false; } -protected: + template + inline void serialize(Buffer &b) const + { + b.append((uint8_t)0); // version + b.append((uint64_t)_lastSend); + b.append((uint64_t)_lastReceived); + _addr.serialize(b); + _localAddress.serialize(b); + b.append((uint8_t)_trust); + b.append((uint16_t)_flags); + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + unsigned int p = startAt; + if (b[p++] != 0) + throw std::invalid_argument("invalid serialized Path"); + _lastSend = b.template at(p); p += 8; + _lastReceived = b.template at(p); p += 8; + p += _addr.deserialize(b,p); + p += _localAddress.deserialize(b,p); + _ipScope = _addr.ipScope(); + _trust = (Path::Trust)b[p++]; + _flags = b.template at(p); p += 2; + return (p - startAt); + } + +private: + uint64_t _lastSend; + uint64_t _lastReceived; InetAddress _addr; + InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often Trust _trust; + uint16_t _flags; }; } // namespace ZeroTier diff --git a/node/Peer.cpp b/node/Peer.cpp index 009e2be5..ebdb6026 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -169,7 +169,7 @@ void Peer::received( if (!pathIsConfirmed) { if (verb == Packet::VERB_OK) { - RemotePath *slot = (RemotePath *)0; + Path *slot = (Path *)0; if (np < ZT_MAX_PEER_NETWORK_PATHS) { slot = &(_paths[np++]); } else { @@ -182,7 +182,7 @@ void Peer::received( } } if (slot) { - *slot = RemotePath(localAddr,remoteAddr); + *slot = Path(localAddr,remoteAddr,Path::TRUST_NORMAL); slot->received(now); _numPaths = np; pathIsConfirmed = true; @@ -240,7 +240,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily) { - RemotePath *p = (RemotePath *)0; + Path *p = (Path *)0; Mutex::Lock _l(_lock); if (inetAddressFamily != 0) { @@ -268,7 +268,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet return false; } -void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) +void Peer::pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,bool force) { #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection @@ -281,7 +281,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ if (((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) { _lastDirectPathPushSent = now; - std::vector dps(RR->node->directPaths()); + std::vector dps(RR->node->directPaths()); if (dps.empty()) return; @@ -291,13 +291,13 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ for(std::vector::const_iterator p(dps.begin());p!=dps.end();++p) { if (ps.length() > 0) ps.push_back(','); - ps.append(p->address().toString()); + ps.append(p->toString()); } TRACE("pushing %u direct paths to %s: %s",(unsigned int)dps.size(),_id.address().toString().c_str(),ps.c_str()); } #endif - std::vector::const_iterator p(dps.begin()); + std::vector::const_iterator p(dps.begin()); while (p != dps.end()) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); outp.addSize(2); // leave room for count @@ -305,7 +305,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ unsigned int count = 0; while ((p != dps.end())&&((outp.size() + 24) < ZT_PROTO_MAX_PACKET_LENGTH)) { uint8_t addressType = 4; - switch(p->address().ss_family) { + switch(p->ss_family) { case AF_INET: break; case AF_INET6: @@ -317,6 +317,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ } uint8_t flags = 0; + /* TODO: path trust is not implemented yet switch(p->trust()) { default: break; @@ -327,13 +328,14 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ flags |= (0x04 | 0x08); // no encryption, no authentication (redundant but go ahead and set both) break; } + */ outp.append(flags); outp.append((uint16_t)0); // no extensions outp.append(addressType); outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->address().rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->address().port()); + outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); + outp.append((uint16_t)p->port()); ++count; ++p; @@ -506,7 +508,7 @@ struct _SortPathsByQuality { uint64_t _now; _SortPathsByQuality(const uint64_t now) : _now(now) {} - inline bool operator()(const RemotePath &a,const RemotePath &b) const + inline bool operator()(const Path &a,const Path &b) const { const uint64_t qa = ( ((uint64_t)a.active(_now) << 63) | @@ -526,7 +528,7 @@ void Peer::_sortPaths(const uint64_t now) std::sort(&(_paths[0]),&(_paths[_numPaths]),_SortPathsByQuality(now)); } -RemotePath *Peer::_getBestPath(const uint64_t now) +Path *Peer::_getBestPath(const uint64_t now) { // assumes _lock is locked if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL) @@ -538,10 +540,10 @@ RemotePath *Peer::_getBestPath(const uint64_t now) if (_paths[0].active(now)) return &(_paths[0]); } - return (RemotePath *)0; + return (Path *)0; } -RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) +Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) { // assumes _lock is locked if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL) @@ -553,7 +555,7 @@ RemotePath *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) } _sortPaths(now); } - return (RemotePath *)0; + return (Path *)0; } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 04b541af..aa75b3f4 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -41,7 +41,7 @@ #include "RuntimeEnvironment.hpp" #include "CertificateOfMembership.hpp" -#include "RemotePath.hpp" +#include "Path.hpp" #include "Address.hpp" #include "Utils.hpp" #include "Identity.hpp" @@ -135,7 +135,7 @@ public: * @param now Current time * @return Best path or NULL if there are no active direct paths */ - inline RemotePath *getBestPath(uint64_t now) + inline Path *getBestPath(uint64_t now) { Mutex::Lock _l(_lock); return _getBestPath(now); @@ -150,14 +150,14 @@ public: * @param now Current time * @return Path used on success or NULL on failure */ - inline RemotePath *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) + inline Path *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) { - RemotePath *bestPath = getBestPath(now); + Path *bestPath = getBestPath(now); if (bestPath) { if (bestPath->send(RR,data,len,now)) return bestPath; } - return (RemotePath *)0; + return (Path *)0; } /** @@ -191,14 +191,14 @@ public: * @param now Current time * @param force If true, push regardless of rate limit */ - void pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force); + void pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,bool force); /** * @return All known direct paths to this peer */ - inline std::vector paths() const + inline std::vector paths() const { - std::vector pp; + std::vector pp; Mutex::Lock _l(_lock); for(unsigned int p=0,np=_numPaths;p_paths[np->_numPaths++].deserialize(b,p); } else { // Skip any paths beyond max, but still read stream - RemotePath foo; + Path foo; p += foo.deserialize(b,p); } } @@ -557,8 +557,8 @@ public: private: void _sortPaths(const uint64_t now); - RemotePath *_getBestPath(const uint64_t now); - RemotePath *_getBestPath(const uint64_t now,int inetAddressFamily); + Path *_getBestPath(const uint64_t now); + Path *_getBestPath(const uint64_t now,int inetAddressFamily); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized @@ -575,7 +575,7 @@ private: uint16_t _vMinor; uint16_t _vRevision; Identity _id; - RemotePath _paths[ZT_MAX_PEER_NETWORK_PATHS]; + Path _paths[ZT_MAX_PEER_NETWORK_PATHS]; unsigned int _numPaths; unsigned int _latency; diff --git a/node/RemotePath.hpp b/node/RemotePath.hpp deleted file mode 100644 index 8b37621a..00000000 --- a/node/RemotePath.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_REMOTEPATH_HPP -#define ZT_REMOTEPATH_HPP - -#include -#include - -#include -#include - -#include "Path.hpp" -#include "Node.hpp" -#include "AntiRecursion.hpp" -#include "RuntimeEnvironment.hpp" - -namespace ZeroTier { - -/** - * Path to a remote peer - * - * This extends Path to include status information about path activity. - */ -class RemotePath : public Path -{ -public: - RemotePath() : - Path(), - _lastSend(0), - _lastReceived(0), - _localAddress(), - _flags(0) {} - - RemotePath(const InetAddress &localAddress,const InetAddress &addr) : - Path(addr,0,TRUST_NORMAL), - _lastSend(0), - _lastReceived(0), - _localAddress(localAddress), - _flags(0) {} - - inline const InetAddress &localAddress() const throw() { return _localAddress; } - - inline uint64_t lastSend() const throw() { return _lastSend; } - inline uint64_t lastReceived() const throw() { return _lastReceived; } - - /** - * Called when a packet is sent to this remote path - * - * This is called automatically by RemotePath::send(). - * - * @param t Time of send - */ - inline void sent(uint64_t t) - throw() - { - _lastSend = t; - } - - /** - * Called when a packet is received from this remote path - * - * @param t Time of receive - */ - inline void received(uint64_t t) - throw() - { - _lastReceived = t; - } - - /** - * @param now Current time - * @return True if this path appears active - */ - inline bool active(uint64_t now) const - throw() - { - return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT); - } - - /** - * Send a packet via this path - * - * @param RR Runtime environment - * @param data Packet data - * @param len Packet length - * @param now Current time - * @return True if transport reported success - */ - inline bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) - { - if (RR->node->putPacket(_localAddress,address(),data,len)) { - sent(now); - RR->antiRec->logOutgoingZT(data,len); - return true; - } - return false; - } - - template - inline void serialize(Buffer &b) const - { - b.append((uint8_t)1); // version - _addr.serialize(b); - b.append((uint8_t)_trust); - b.append((uint64_t)_lastSend); - b.append((uint64_t)_lastReceived); - _localAddress.serialize(b); - b.append((uint16_t)_flags); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - if (b[p++] != 1) - throw std::invalid_argument("invalid serialized RemotePath"); - p += _addr.deserialize(b,p); - _ipScope = _addr.ipScope(); - _trust = (Path::Trust)b[p++]; - _lastSend = b.template at(p); p += 8; - _lastReceived = b.template at(p); p += 8; - p += _localAddress.deserialize(b,p); - _flags = b.template at(p); p += 2; - return (p - startAt); - } - -protected: - uint64_t _lastSend; - uint64_t _lastReceived; - InetAddress _localAddress; - uint16_t _flags; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 81d19369..b4841544 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -125,7 +125,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi // they are still considered alive so that we will re-establish direct links. SharedPtr r(RR->topology->getBestRoot()); if (r) { - RemotePath *rp = r->getBestPath(now); + Path *rp = r->getBestPath(now); if (rp) { for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->alive(now)) { diff --git a/node/Switch.cpp b/node/Switch.cpp index 772eaf02..2f72f57a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -736,7 +736,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) return false; // sanity check: unconfigured network? why are we trying to talk to it? } - RemotePath *viaPath = peer->getBestPath(now); + Path *viaPath = peer->getBestPath(now); SharedPtr relay; if (!viaPath) { // See if this network has a preferred relay (if packet has an associated network) diff --git a/objects.mk b/objects.mk index 6dd5ea30..540072d5 100644 --- a/objects.mk +++ b/objects.mk @@ -15,6 +15,7 @@ OBJS=\ node/Node.o \ node/OutboundMulticast.o \ node/Packet.o \ + node/Path.o \ node/Peer.o \ node/Poly1305.o \ node/Salsa20.o \ diff --git a/service/OneService.cpp b/service/OneService.cpp index 1765b5c4..4e3f24c7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -731,7 +731,7 @@ public: #ifdef ZT_USE_MINIUPNPC std::vector upnpAddresses(_upnpClient->get()); for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); #endif struct ifaddrs *ifatbl = (struct ifaddrs *)0; @@ -749,7 +749,7 @@ public: if (!isZT) { InetAddress ip(ifa->ifa_addr); ip.setPort(_port); - _node->addLocalInterfaceAddress(reinterpret_cast(&ip),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + _node->addLocalInterfaceAddress(reinterpret_cast(&ip),ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); } } ifa = ifa->ifa_next; -- cgit v1.2.3 From 88b100e5d0db5df16622fa48899cf652e09b3e91 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 17:59:17 -0700 Subject: More cleanup. --- node/IncomingPacket.cpp | 49 ++++++++++++++++++++++++++++++++----------------- node/InetAddress.hpp | 11 ++++++++--- 2 files changed, 40 insertions(+), 20 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7015535a..b1a9af3b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -45,6 +45,7 @@ #include "World.hpp" #include "Cluster.hpp" #include "Node.hpp" +#include "AntiRecursion.hpp" namespace ZeroTier { @@ -122,7 +123,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_OBJ_NOT_FOUND: if (inReVerb == Packet::VERB_WHOIS) { - if (RR->topology->isRoot(peer->identity())) + if (RR->topology->isUpstream(peer->identity())) RR->sw->cancelWhoisRequest(Address(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH)); } else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); @@ -155,6 +156,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); nconf->com().serialize(outp); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } @@ -202,13 +204,13 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id; - InetAddress destAddr; + InetAddress externalSurfaceAddress; uint64_t worldId = ZT_WORLD_ID_NULL; uint64_t worldTimestamp = 0; { unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); if (ptr < size()) // ZeroTier One < 1.0.3 did not include physical destination address info - ptr += destAddr.deserialize(*this,ptr); + ptr += externalSurfaceAddress.deserialize(*this,ptr); if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps worldId = at(ptr); ptr += 8; worldTimestamp = at(ptr); @@ -281,11 +283,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // VALID -- if we made it here, packet passed identity and authenticity checks! - peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); - peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); - - if (destAddr) - RR->sa->iam(id.address(),_remoteAddress,destAddr,RR->topology->isRoot(id),RR->node->now()); + if (externalSurfaceAddress) + RR->sa->iam(id.address(),_remoteAddress,externalSurfaceAddress,RR->topology->isRoot(id),RR->node->now()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_HELLO); @@ -308,7 +307,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) } outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + + peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); + peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -332,12 +335,17 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); + if (vProto < ZT_PROTO_VERSION_MIN) { + TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } + const bool trusted = RR->topology->isRoot(peer->identity()); - InetAddress destAddr; + InetAddress externalSurfaceAddress; unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; if (ptr < size()) // ZeroTier One < 1.0.3 did not include this field - ptr += destAddr.deserialize(*this,ptr); + ptr += externalSurfaceAddress.deserialize(*this,ptr); if ((trusted)&&((ptr + 2) <= size())) { // older versions also did not include this field, and right now we only use if from a root World worldUpdate; const unsigned int worldLen = at(ptr); ptr += 2; @@ -348,18 +356,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } } - if (vProto < ZT_PROTO_VERSION_MIN) { - TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); - return true; - } - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((destAddr) ? destAddr.toString().c_str() : "(none)")); peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - if (destAddr) - RR->sa->iam(peer->address(),_remoteAddress,destAddr,trusted,RR->node->now()); + if (externalSurfaceAddress) + RR->sa->iam(peer->address(),_remoteAddress,externalSurfaceAddress,trusted,RR->node->now()); } break; case Packet::VERB_WHOIS: { @@ -443,6 +446,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr outp.append(packetId()); queried.serialize(outp,false); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); @@ -451,6 +455,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(payload(),ZT_ADDRESS_LENGTH); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } else { @@ -608,6 +613,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append((unsigned char)Packet::VERB_ECHO); outp.append((uint64_t)pid); outp.append(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP); } catch ( ... ) { @@ -693,6 +699,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { // sanity check TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length()); } else { + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } @@ -705,6 +712,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(nwid); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } break; @@ -715,6 +723,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); outp.append(nwid); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } break; @@ -737,6 +746,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } catch ( ... ) { @@ -781,6 +791,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar outp.append((uint32_t)mg.adi()); if (RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit)) { outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } @@ -873,6 +884,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share outp.append((unsigned char)0x02); // flag 0x02 = contains gather results if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } @@ -1173,6 +1185,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const outp.append((uint16_t)sizeof(result)); outp.append(result,sizeof(result)); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); @@ -1180,6 +1193,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const outp.append(pid); outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } break; @@ -1285,6 +1299,7 @@ void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); outp.armor(peer->key(),true); + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index ecafcf51..fcbed4b1 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -346,14 +346,19 @@ struct InetAddress : public sockaddr_storage } /** + * Performs an IP-only comparison or, if that is impossible, a memcmp() + * * @param a InetAddress to compare again * @return True if only IP portions are equal (false for non-IP or null addresses) */ inline bool ipsEqual(const InetAddress &a) const { - switch(ss_family) { - case AF_INET: return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); - case AF_INET6: return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0); + if (ss_family == a.ss_family) { + if (ss_family == AF_INET) + return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); + if (ss_family == AF_INET6) + return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0); + return (memcmp(this,&a,sizeof(InetAddress)) == 0); } return false; } -- cgit v1.2.3 From cdc99bfee10ac58a8dab1aabcb85e69f3862b7ad Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Oct 2015 18:18:26 -0700 Subject: Add a circuit breaker for VERB_PUSH_DIRECT_PATHS. --- node/Constants.hpp | 26 ++++++++++++++++++++------ node/IncomingPacket.cpp | 5 +++++ node/Peer.cpp | 2 ++ node/Peer.hpp | 31 +++++++++++++++++++++++++++++-- 4 files changed, 56 insertions(+), 8 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 4b06db44..53cc64c7 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -319,11 +319,6 @@ */ #define ZT_MIN_PATH_CONFIRMATION_INTERVAL 1000 -/** - * Interval between direct path pushes in milliseconds - */ -#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000 - /** * How long (max) to remember network certificates of membership? * @@ -347,10 +342,29 @@ */ #define ZT_MAX_BRIDGE_SPAM 16 +/** + * Interval between direct path pushes in milliseconds + */ +#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000 + /** * Maximum number of endpoints to contact per address type (to limit pushes like GitHub issue #235) */ -#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 4 +#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 5 + +/** + * Time horizon for push direct paths cutoff + */ +#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 + +/** + * Maximum number of direct path pushes within cutoff time + * + * This limits response to PUSH_DIRECT_PATHS to CUTOFF_LIMIT responses + * per CUTOFF_TIME milliseconds per peer to prevent this from being + * useful for DOS amplification attacks. + */ +#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 /** * A test pseudo-network-ID that can be joined diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b1a9af3b..e985b34c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -901,6 +901,11 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha { try { const uint64_t now = RR->node->now(); + if (!peer->shouldRespondToDirectPathPush(now)) { + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } + const Path *currentBest = peer->getBestPath(now); unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); diff --git a/node/Peer.cpp b/node/Peer.cpp index 99eb32c7..976c7c44 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -55,6 +55,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastAnnouncedTo(0), _lastPathConfirmationSent(0), _lastDirectPathPushSent(0), + _lastDirectPathPushReceive(0), _lastPathSort(0), _vProto(0), _vMajor(0), @@ -63,6 +64,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _id(peerIdentity), _numPaths(0), _latency(0), + _directPathPushCutoffCount(0), _networkComs(4), _lastPushedComs(4) { diff --git a/node/Peer.hpp b/node/Peer.hpp index 69343f20..d9ef5fcb 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -431,6 +431,27 @@ public: _numPaths = y; } + /** + * Update direct path push stats and return true if we should respond + * + * This is a circuit breaker to make VERB_PUSH_DIRECT_PATHS not particularly + * useful as a DDOS amplification attack vector. Otherwise a malicious peer + * could send loads of these and cause others to bombard arbitrary IPs with + * traffic. + * + * @param now Current time + * @return True if we should respond + */ + inline bool shouldRespondToDirectPathPush(const uint64_t now) + { + Mutex::Lock _l(_lock); + if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) + ++_directPathPushCutoffCount; + else _directPathPushCutoffCount = 0; + _lastDirectPathPushReceive = now; + return (_directPathPushCutoffCount >= ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -459,7 +480,7 @@ public: const unsigned int recSizePos = b.size(); b.addSize(4); // space for uint32_t field length - b.append((uint16_t)0); // version of serialized Peer data + b.append((uint16_t)1); // version of serialized Peer data _id.serialize(b,false); @@ -470,12 +491,14 @@ public: b.append((uint64_t)_lastAnnouncedTo); b.append((uint64_t)_lastPathConfirmationSent); b.append((uint64_t)_lastDirectPathPushSent); + b.append((uint64_t)_lastDirectPathPushReceive); b.append((uint64_t)_lastPathSort); b.append((uint16_t)_vProto); b.append((uint16_t)_vMajor); b.append((uint16_t)_vMinor); b.append((uint16_t)_vRevision); b.append((uint32_t)_latency); + b.append((uint16_t)_directPathPushCutoffCount); b.append((uint16_t)_numPaths); for(unsigned int i=0;i<_numPaths;++i) @@ -521,7 +544,7 @@ public: const unsigned int recSize = b.template at(p); p += 4; if ((p + recSize) > b.size()) return SharedPtr(); // size invalid - if (b.template at(p) != 0) + if (b.template at(p) != 1) return SharedPtr(); // version mismatch p += 2; @@ -539,12 +562,14 @@ public: np->_lastAnnouncedTo = b.template at(p); p += 8; np->_lastPathConfirmationSent = b.template at(p); p += 8; np->_lastDirectPathPushSent = b.template at(p); p += 8; + np->_lastDirectPathPushReceive = b.template at(p); p += 8; np->_lastPathSort = b.template at(p); p += 8; np->_vProto = b.template at(p); p += 2; np->_vMajor = b.template at(p); p += 2; np->_vMinor = b.template at(p); p += 2; np->_vRevision = b.template at(p); p += 2; np->_latency = b.template at(p); p += 4; + np->_directPathPushCutoffCount = b.template at(p); p += 2; const unsigned int numPaths = b.template at(p); p += 2; for(unsigned int i=0;i Date: Wed, 28 Oct 2015 09:11:30 -0700 Subject: Clean up PUSH_DIRECT_PATH limits a bit more and make them a bit smarter. --- node/Constants.hpp | 10 +++++----- node/IncomingPacket.cpp | 25 +++++++++++++++---------- node/InetAddress.hpp | 8 +++++++- 3 files changed, 27 insertions(+), 16 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 53cc64c7..5a4d4a4d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -347,11 +347,6 @@ */ #define ZT_DIRECT_PATH_PUSH_INTERVAL 120000 -/** - * Maximum number of endpoints to contact per address type (to limit pushes like GitHub issue #235) - */ -#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 5 - /** * Time horizon for push direct paths cutoff */ @@ -366,6 +361,11 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 +/** + * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) + */ +#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 1 + /** * A test pseudo-network-ID that can be joined * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e985b34c..f06eb30c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -901,16 +901,19 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha { try { const uint64_t now = RR->node->now(); + + // First, subject this to a rate limit if (!peer->shouldRespondToDirectPathPush(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str()); return true; } - const Path *currentBest = peer->getBestPath(now); + // Second, limit addresses by scope and type + uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6 + memset(countPerScope,0,sizeof(countPerScope)); unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; - unsigned int v4Count = 0,v6Count = 0; while (count--) { // if ptr overflows Buffer will throw // TODO: some flags are not yet implemented @@ -925,20 +928,22 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha case 4: { InetAddress a(field(ptr,4),4,at(ptr + 4)); if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) { - TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - if (v4Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) { - if ((!currentBest)||(currentBest->address() != a)) - peer->attemptToContactAt(RR,_localAddress,a,now); + if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); + peer->attemptToContactAt(RR,_localAddress,a,now); + } else { + TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; case 6: { InetAddress a(field(ptr,16),16,at(ptr + 16)); if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) { - TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - if (v6Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) { - if ((!currentBest)||(currentBest->address() != a)) - peer->attemptToContactAt(RR,_localAddress,a,now); + if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); + peer->attemptToContactAt(RR,_localAddress,a,now); + } else { + TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index fcbed4b1..5e5eb06e 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -42,6 +42,11 @@ namespace ZeroTier { +/** + * Maximum integer value of enum IpScope + */ +#define ZT_INETADDRESS_MAX_SCOPE 7 + /** * Extends sockaddr_storage with friendly C++ methods * @@ -66,7 +71,8 @@ struct InetAddress : public sockaddr_storage * IP address scope * * Note that these values are in ascending order of path preference and - * MUST remain that way or Path must be changed to reflect. + * MUST remain that way or Path must be changed to reflect. Also be sure + * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. */ enum IpScope { -- cgit v1.2.3 From 938d0a970b84c6a50465bb6ebb64798e4ffec202 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 28 Oct 2015 10:01:32 -0700 Subject: TRACE build fixes. --- node/IncomingPacket.cpp | 2 +- node/SelfAwareness.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f06eb30c..b0d65159 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -356,7 +356,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } } - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((destAddr) ? destAddr.toString().c_str() : "(none)")); + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 856892ff..d8eca071 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -129,7 +129,6 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi // other relay. for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->alive(now)) { - TRACE("sending indirect NOP to %s via %s to re-establish link",(*p)->address().toString().c_str(),r->address().toString().c_str()); Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); RR->sw->send(outp,true,0); } -- cgit v1.2.3 From f1b6427e63d71b6be79e55bd1abf44ec519e2d11 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 2 Nov 2015 09:32:56 -0800 Subject: Decided to make this 1.1.0 (semantic versioning increment is warranted), and add a legacy hack for older clients working with clusters. --- node/IncomingPacket.cpp | 31 ++++++++++++++++++++++++++++++- node/Packet.hpp | 7 ++++--- version.h | 4 ++-- 3 files changed, 36 insertions(+), 6 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b0d65159..32229ba6 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -294,7 +294,36 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - _remoteAddress.serialize(outp); + if (protoVersion >= 5) { + _remoteAddress.serialize(outp); + } else { + /* LEGACY COMPATIBILITY HACK: + * + * For a while now (since 1.0.3), ZeroTier has recognized changes in + * its network environment empirically by examining its external network + * address as reported by trusted peers. In versions prior to 1.1.0 + * (protocol version < 5), they did this by saving a snapshot of this + * information (in SelfAwareness.hpp) keyed by reporting device ID and + * address type. + * + * This causes problems when clustering is combined with symmetric NAT. + * Symmetric NAT remaps ports, so different endpoints in a cluster will + * report back different exterior addresses. Since the old code keys + * this by device ID and not sending physical address and compares the + * entire address including port, it constantly thinks its external + * surface is changing and resets connections when talking to a cluster. + * + * In new code we key by sending physical address and device and we also + * take the more conservative position of only interpreting changes in + * IP address (neglecting port) as a change in network topology that + * necessitates a reset. But we can make older clients work here by + * nulling out the port field. Since this info is only used for empirical + * detection of link changes, it doesn't break anything else. + */ + InetAddress tmpa(_remoteAddress); + tmpa.setPort(0); + tmpa.serialize(outp); + } if ((worldId != ZT_WORLD_ID_NULL)&&(RR->topology->worldTimestamp() > worldTimestamp)&&(worldId == RR->topology->worldId())) { World w(RR->topology->world()); diff --git a/node/Packet.hpp b/node/Packet.hpp index 985d25d0..63c49ce3 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -57,10 +57,11 @@ * + New crypto completely changes key agreement cipher * 4 - 0.6.0 ... 1.0.6 * + New identity format based on hashcash design - * 5 - 1.0.6 ... CURRENT + * 5 - 1.1.0 ... CURRENT * + Supports circuit test, proof of work, and echo - * + Supports in-band world (root definition) updates - * + Otherwise backward compatible with 4 + * + Supports in-band world (root server definition) updates + * + Clustering! (Though this will work with protocol v4 clients.) + * + Otherwise backward compatible with protocol v4 */ #define ZT_PROTO_VERSION 5 diff --git a/version.h b/version.h index 4c36cb5e..e2773877 100644 --- a/version.h +++ b/version.h @@ -36,11 +36,11 @@ /** * Minor version */ -#define ZEROTIER_ONE_VERSION_MINOR 0 +#define ZEROTIER_ONE_VERSION_MINOR 1 /** * Revision */ -#define ZEROTIER_ONE_VERSION_REVISION 6 +#define ZEROTIER_ONE_VERSION_REVISION 0 #endif -- cgit v1.2.3