From a2821e90007ac7af490f044f0c2579309f6c8a01 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Apr 2015 20:17:21 -0700 Subject: Add code to check external surface against reported surface from other trusted peers, and also rename ExternalSurface to SelfAwareness because lulz. --- node/ExternalSurface.hpp | 66 --------------------------------------------- node/IncomingPacket.cpp | 44 +++++++++++++++++++++++++++--- node/Node.cpp | 4 +++ node/Packet.hpp | 25 +++++++++++++++++ node/RuntimeEnvironment.hpp | 5 +++- node/SelfAwareness.hpp | 58 +++++++++++++++++++++++++++++++++++++++ node/Topology.hpp | 17 ------------ 7 files changed, 131 insertions(+), 88 deletions(-) delete mode 100644 node/ExternalSurface.hpp create mode 100644 node/SelfAwareness.hpp (limited to 'node') diff --git a/node/ExternalSurface.hpp b/node/ExternalSurface.hpp deleted file mode 100644 index b29c5128..00000000 --- a/node/ExternalSurface.hpp +++ /dev/null @@ -1,66 +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_EXTERNALSURFACE_HPP -#define ZT_EXTERNALSURFACE_HPP - -#include "InetAddress.hpp" - -namespace ZeroTier { - -/** - * Tracks changes to this peer's real world addresses - */ -class ExternalSurface -{ -public: - ExternalSurface() {} - - /** - * Revise our external surface image, return true if it changed - * - * @param remote Remote address as reflected by any trusted peer - * @return True if our external surface has changed - */ - 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; - } - -private: - InetAddress _s[4]; // global v4, link-local v4, global v6, link-local v6 -}; - -} // namespace ZeroTier - -#endif diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f63b33b2..99f66561 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 2167d9c1..59bb3dd3 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 7439dddc..20a5b145 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 9600b9dc..1ca483ef 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/SelfAwareness.hpp b/node/SelfAwareness.hpp new file mode 100644 index 00000000..93af34f4 --- /dev/null +++ b/node/SelfAwareness.hpp @@ -0,0 +1,58 @@ +/* + * 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_SELFAWARENESS_HPP +#define ZT_SELFAWARENESS_HPP + +#include "InetAddress.hpp" + +namespace ZeroTier { + +class RuntimeEnvironment; + +/** + * Tracks changes to this peer's real world addresses + */ +class SelfAwareness +{ +public: + SelfAwareness(const RuntimeEnvironment *renv); + ~SelfAwareness(); + + /** + * Called when a trusted remote peer informs us of our external network address + * + * @param physicalAddress Physical address as reflected by any trusted peer + */ + void iam(const InetAddress &physicalAddress); + +private: +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Topology.hpp b/node/Topology.hpp index ca86b2e3..6dee11bc 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 -- cgit v1.2.3