diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f63b33b21..99f66561c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -39,6 +39,7 @@ #include "Switch.hpp" #include "Peer.hpp" #include "NetworkConfigMaster.hpp" +#include "SelfAwareness.hpp" namespace ZeroTier { @@ -174,7 +175,23 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - const Identity id(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + + Identity id; + unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY; + + unsigned int destAddrType = ZT_PROTO_DEST_ADDRESS_TYPE_NONE; + if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field + destAddrType = (*this)[destAddrPtr++]; + + InetAddress destAddr; + switch(destAddrType) { + case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4: + destAddr.set(field(destAddrPtr,4),4,at(destAddrPtr + 4)); + break; + case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6: + destAddr.set(field(destAddrPtr,16),16,at(destAddrPtr + 16)); + break; + } if (source() != id.address()) { TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str()); @@ -245,11 +262,13 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); - // Won't get HELLO *from* supernodes, so skip this for now here. It's done in OK(HELLO). - //if (RR->topology->isSupernode(id.address())) - // RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); + if (RR->topology->isSupernode(id.address())) { + RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); + RR->sa->iam(destAddr); + } Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_HELLO); outp.append(packetId()); outp.append(timestamp); @@ -257,6 +276,23 @@ 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); + + switch(_remoteAddress.ss_family) { + case AF_INET: + outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV4); + outp.append(_remoteAddress.rawIpData(),4); + outp.append((uint16_t)_remoteAddress.port()); + break; + case AF_INET6: + outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV6); + outp.append(_remoteAddress.rawIpData(),16); + outp.append((uint16_t)_remoteAddress.port()); + break; + default: + outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_NONE); + break; + } + outp.armor(peer->key(),true); RR->node->putPacket(_remoteAddress,outp.data(),outp.size(),_linkDesperation); } catch (std::exception &ex) { diff --git a/node/Node.cpp b/node/Node.cpp index 2167d9c10..59bb3dd3b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -41,6 +41,7 @@ #include "Logger.hpp" #include "Address.hpp" #include "Identity.hpp" +#include "SelfAwareness.hpp" namespace ZeroTier { @@ -77,7 +78,9 @@ Node::Node( RR->mc = new Multicaster(RR); RR->antiRec = new AntiRecursion(); RR->topology = new Topology(RR); + RR->sa = new SelfAwareness(RR); } catch ( ... ) { + delete RR->sa; delete RR->topology; delete RR->antiRec; delete RR->mc; @@ -91,6 +94,7 @@ Node::Node( Node::~Node() { + delete RR->sa; delete RR->topology; delete RR->antiRec; delete RR->mc; diff --git a/node/Packet.hpp b/node/Packet.hpp index 7439dddcd..20a5b1450 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -175,6 +175,12 @@ */ #define ZT_PROTO_BEACON_IDX_ADDRESS 8 +// Destination address types from HELLO and OK(HELLO) +#define ZT_PROTO_DEST_ADDRESS_TYPE_NONE 0 +#define ZT_PROTO_DEST_ADDRESS_TYPE_ETHERNET 1 +#define ZT_PROTO_DEST_ADDRESS_TYPE_IPV4 4 +#define ZT_PROTO_DEST_ADDRESS_TYPE_IPV6 6 + // Field incides for parsing verbs ------------------------------------------- // Some verbs have variable-length fields. Those aren't fully defined here @@ -467,6 +473,23 @@ public: * <[2] software revision> * <[8] timestamp (ms since epoch)> * <[...] binary serialized identity (see Identity)> + * <[1] destination address type> + * [<[...] destination address>] + * + * This is the only message that ever must be sent in the clear, since it + * is used to push an identity to a new peer. + * + * The destination address is the wire address to which this packet is + * being sent, and in OK is *also* the destination address of the OK + * packet. This can be used by the receiver to detect NAT, learn its real + * external address if behind NAT, and detect changes to its external + * address that require re-establishing connectivity. + * + * Destination address types and formats (not all of these are used now): + * 0 - None -- no destination address data present + * 1 - Ethernet address -- format: <[6] Ethernet MAC> + * 4 - 6-byte IPv4 address -- format: <[4] IP>, <[2] port> + * 6 - 18-byte IPv6 address -- format: <[16] IP>, <[2] port> * * OK payload: * <[8] timestamp (echoed from original HELLO)> @@ -474,6 +497,8 @@ public: * <[1] software major version (of responder)> * <[1] software minor version (of responder)> * <[2] software revision (of responder)> + * <[1] destination address type (for this OK, not copied from HELLO)> + * [<[...] destination address>] * * ERROR has no payload. */ diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 9600b9dcc..1ca483ef1 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -44,6 +44,7 @@ class Node; class Multicaster; class AntiRecursion; class NetworkConfigMaster; +class SelfAwareness; /** * Holds global state for an instance of ZeroTier::Node @@ -69,7 +70,8 @@ public: sw((Switch *)0), mc((Multicaster *)0), antiRec((AntiRecursion *)0), - topology((Topology *)0) + topology((Topology *)0), + sa((SelfAwareness *)0) { } @@ -96,6 +98,7 @@ public: Multicaster *mc; AntiRecursion *antiRec; Topology *topology; + SelfAwareness *sa; }; } // namespace ZeroTier diff --git a/node/ExternalSurface.hpp b/node/SelfAwareness.hpp similarity index 68% rename from node/ExternalSurface.hpp rename to node/SelfAwareness.hpp index b29c5128f..93af34f43 100644 --- a/node/ExternalSurface.hpp +++ b/node/SelfAwareness.hpp @@ -25,40 +25,32 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef ZT_EXTERNALSURFACE_HPP -#define ZT_EXTERNALSURFACE_HPP +#ifndef ZT_SELFAWARENESS_HPP +#define ZT_SELFAWARENESS_HPP #include "InetAddress.hpp" namespace ZeroTier { +class RuntimeEnvironment; + /** * Tracks changes to this peer's real world addresses */ -class ExternalSurface +class SelfAwareness { public: - ExternalSurface() {} + SelfAwareness(const RuntimeEnvironment *renv); + ~SelfAwareness(); /** - * Revise our external surface image, return true if it changed + * Called when a trusted remote peer informs us of our external network address * - * @param remote Remote address as reflected by any trusted peer - * @return True if our external surface has changed + * @param physicalAddress Physical address as reflected by any trusted peer */ - inline bool update(const InetAddress &remote) - throw() - { - const unsigned long idx = (remote.isV4() ? 0 : 2) | (remote.isLinkLocal() ? 1 : 0); - if (_s[idx] != remote) { - _s[idx] = remote; - return true; - } - return false; - } + void iam(const InetAddress &physicalAddress); private: - InetAddress _s[4]; // global v4, link-local v4, global v6, link-local v6 }; } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index ca86b2e3a..6dee11bcb 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -45,7 +45,6 @@ #include "InetAddress.hpp" #include "Utils.hpp" #include "Dictionary.hpp" -#include "ExternalSurface.hpp" namespace ZeroTier { @@ -321,20 +320,6 @@ public: }; #endif - /** - * Update our knowledge of exterior network addresses - * - * If the remote peer in question is trusted, this will update our internal - * instance of ExternalSurface. If our surface has changed, this triggers a - * partial or total reset of ephemeral peer addresses and a renegotiation of - * new ones using supernodes / relays. - * - * @param remotePeer Remote peer address - * @param mirroredAddress Real-world network address the remote peer told us we have - * @param now Current time - */ - bool updateSurface(const SharedPtr &remotePeer,const InetAddress &mirroredAddress,uint64_t now); - /** * Validate a root topology dictionary against the identities specified in Defaults * @@ -356,8 +341,6 @@ private: std::vector< Address > _supernodeAddresses; std::vector< SharedPtr > _supernodePeers; - ExternalSurface _surface; - Mutex _lock; // Set to true if my identity is in _supernodes