From b3e3d4cacca37a4850e4e1a91fb8c42a5b13cb26 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 11 Jan 2016 10:17:44 -0800 Subject: Instead of using binary packet comparison, add a callback to the API to explicitly check whether paths should be used. Check in with this callback (if present) when learning new paths or sending initial packets. --- node/IncomingPacket.cpp | 10 ++++++---- node/InetAddress.cpp | 24 ++++++++++++++++++++++++ node/InetAddress.hpp | 8 ++++++++ node/Node.cpp | 26 +++++++++++++++++++++++++- node/Node.hpp | 9 +++++++++ node/Peer.cpp | 2 +- 6 files changed, 73 insertions(+), 6 deletions(-) (limited to 'node') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5c9279dd..c63d70b7 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -507,10 +507,12 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); + InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); - RR->sw->rendezvous(withPeer,_localAddress,atAddr); + if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) + RR->sw->rendezvous(withPeer,_localAddress,atAddr); } else { TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -941,7 +943,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha switch(addrType) { case 4: { InetAddress a(field(ptr,4),4,at(ptr + 4)); - if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) ) { + if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) { 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->sendHELLO(_localAddress,a,now); @@ -952,7 +954,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha } break; case 6: { InetAddress a(field(ptr,16),16,at(ptr + 16)); - if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) ) { + if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) { 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->sendHELLO(_localAddress,a,now); diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index f35eb9c3..1b3a8064 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -280,6 +280,30 @@ InetAddress InetAddress::network() const return r; } +bool InetAddress::containsAddress(const InetAddress &addr) const +{ + if (addr.ss_family == ss_family) { + switch(ss_family) { + case AF_INET: { + const unsigned int bits = netmaskBits(); + return ( (Utils::ntoh((uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) >> (32 - bits)) ); + } + case AF_INET6: { + const InetAddress mask(netmask()); + const uint8_t *m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); + const uint8_t *a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); + const uint8_t *b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + for(unsigned int i=0;i<16;++i) { + if ((a[i] & m[i]) != b[i]) + return false; + } + return true; + } + } + } + return false; +} + bool InetAddress::isNetwork() const throw() { diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 2573e694..201271f7 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -325,6 +325,14 @@ struct InetAddress : public sockaddr_storage */ InetAddress network() const; + /** + * Test whether this IP/netmask contains this address + * + * @param addr Address to check + * @return True if this IP/netmask (route) contains this address + */ + bool containsAddress(const InetAddress &addr) const; + /** * @return True if this is an IPv4 address */ diff --git a/node/Node.cpp b/node/Node.cpp index 19675bb5..f65aa843 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -64,6 +64,7 @@ Node::Node( ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, + ZT_PathCheckFunction pathCheckFunction, ZT_EventCallback eventCallback) : _RR(this), RR(&_RR), @@ -73,6 +74,7 @@ Node::Node( _wirePacketSendFunction(wirePacketSendFunction), _virtualNetworkFrameFunction(virtualNetworkFrameFunction), _virtualNetworkConfigFunction(virtualNetworkConfigFunction), + _pathCheckFunction(pathCheckFunction), _eventCallback(eventCallback), _networks(), _networks_m(), @@ -671,6 +673,27 @@ std::string Node::dataStoreGet(const char *name) return r; } +bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress) +{ + { + Mutex::Lock _l(_networks_m); + for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) { + SharedPtr nc(i->second->config2()); + if (nc) { + for(std::vector::const_iterator a(nc->staticIps().begin());a!=nc->staticIps().end();++a) { + if (a->containsAddress(remoteAddress)) { + return false; + } + } + } + } + } + + if (_pathCheckFunction) + return (_pathCheckFunction(reinterpret_cast(this),_uPtr,reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0); + else return true; +} + #ifdef ZT_TRACE void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) { @@ -743,11 +766,12 @@ enum ZT_ResultCode ZT_Node_new( ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, + ZT_PathCheckFunction pathCheckFunction, ZT_EventCallback eventCallback) { *node = (ZT_Node *)0; try { - *node = reinterpret_cast(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback)); + *node = reinterpret_cast(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,pathCheckFunction,eventCallback)); return ZT_RESULT_OK; } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; diff --git a/node/Node.hpp b/node/Node.hpp index 15295139..b6b32363 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -71,6 +71,7 @@ public: ZT_WirePacketSendFunction wirePacketSendFunction, ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, + ZT_PathCheckFunction pathCheckFunction, ZT_EventCallback eventCallback); ~Node(); @@ -189,6 +190,13 @@ public: len); } + /** + * @param localAddress Local address + * @param remoteAddress Remote address + * @return True if path should be used + */ + bool shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress); + inline SharedPtr network(uint64_t nwid) const { Mutex::Lock _l(_networks_m); @@ -288,6 +296,7 @@ private: ZT_WirePacketSendFunction _wirePacketSendFunction; ZT_VirtualNetworkFrameFunction _virtualNetworkFrameFunction; ZT_VirtualNetworkConfigFunction _virtualNetworkConfigFunction; + ZT_PathCheckFunction _pathCheckFunction; ZT_EventCallback _eventCallback; std::vector< std::pair< uint64_t, SharedPtr > > _networks; diff --git a/node/Peer.cpp b/node/Peer.cpp index 04e5bdf0..c75a3e46 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -156,7 +156,7 @@ void Peer::received( } } - if (!pathIsConfirmed) { + if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(localAddr,remoteAddr))) { if (verb == Packet::VERB_OK) { Path *slot = (Path *)0; -- cgit v1.2.3