From 7e6e56e2bce240a8d3a4f2825d3f110109a541b6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 3 Aug 2016 18:04:08 -0700 Subject: [PATCH] Bunch of work on pushing and replication of tags and capabilities, and protocol cleanup. --- include/ZeroTierOne.h | 20 ++-- node/Capability.hpp | 5 + node/Filter.cpp | 34 +++++-- node/Filter.hpp | 22 ++-- node/IncomingPacket.cpp | 127 +++++++++--------------- node/IncomingPacket.hpp | 7 +- node/Membership.hpp | 154 ++++++++++++++++++++++++++++ node/Network.cpp | 2 + node/NetworkConfig.hpp | 78 ++++++++++----- node/Packet.cpp | 4 +- node/Packet.hpp | 215 ++++++++++++++++++---------------------- node/Peer.hpp | 169 +------------------------------ node/Topology.cpp | 33 +----- service/OneService.cpp | 3 + 14 files changed, 409 insertions(+), 464 deletions(-) create mode 100644 node/Membership.hpp diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index db405c083..9679cf649 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -96,11 +96,6 @@ extern "C" { */ #define ZT_MAX_NETWORK_SPECIALISTS 256 -/** - * Maximum number of static physical to ZeroTier address mappings (typically relays, etc.) - */ -#define ZT_MAX_NETWORK_PINNED 16 - /** * Maximum number of multicast group subscriptions per network */ @@ -111,6 +106,16 @@ extern "C" { */ #define ZT_MAX_NETWORK_RULES 256 +/** + * Maximum number of per-node capabilities per network + */ +#define ZT_MAX_NETWORK_CAPABILITIES 64 + +/** + * Maximum number of per-node tags per network + */ +#define ZT_MAX_NETWORK_TAGS 16 + /** * Maximum number of direct network paths to a given peer */ @@ -126,11 +131,6 @@ extern "C" { */ #define ZT_MAX_CAPABILITY_RULES 64 -/** - * Maximum length of a capbility's short descriptive name - */ -#define ZT_MAX_CAPABILITY_NAME_LENGTH 63 - /** * Global maximum length for capability chain of custody (including initial issue) */ diff --git a/node/Capability.hpp b/node/Capability.hpp index 823428745..d050b2b8c 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -109,6 +109,11 @@ public: */ inline uint64_t networkId() const { return _nwid; } + /** + * @return Expiration time relative to network config timestamp + */ + inline uint64_t expiration() const { return _expiration; } + /** * Sign this capability and add signature to its chain of custody * diff --git a/node/Filter.cpp b/node/Filter.cpp index d86d1a14f..2980149b8 100644 --- a/node/Filter.cpp +++ b/node/Filter.cpp @@ -19,15 +19,8 @@ #include #include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "Address.hpp" -#include "MAC.hpp" -#include "InetAddress.hpp" #include "Filter.hpp" -#include "Packet.hpp" -#include "Switch.hpp" -#include "Topology.hpp" -#include "Node.hpp" +#include "InetAddress.hpp" // Returns true if packet appears valid; pos and proto will be set static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) @@ -61,8 +54,8 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig namespace ZeroTier { bool Filter::run( - const RuntimeEnvironment *RR, const uint64_t nwid, + const bool receiving, const Address &ztSource, const Address &ztDest, const MAC &macSource, @@ -72,8 +65,13 @@ bool Filter::run( const unsigned int etherType, const unsigned int vlanId, const ZT_VirtualNetworkRule *rules, - const unsigned int ruleCount) + const unsigned int ruleCount, + const Tag *tags, + const unsigned int tagCount, + Address &sendCopyOfPacketTo) { + sendCopyOfPacketTo.zero(); + // For each set of rules we start by assuming that they match (since no constraints // yields a 'match all' rule). uint8_t thisSetMatches = 1; @@ -92,6 +90,8 @@ bool Filter::run( // This set did match, so perform action! if (rt != ZT_NETWORK_RULE_ACTION_DROP) { if ((rt == ZT_NETWORK_RULE_ACTION_TEE)||(rt == ZT_NETWORK_RULE_ACTION_REDIRECT)) { + sendCopyOfPacketTo = rules[rn].v.zt; + /* // Tee and redirect both want this frame copied to somewhere else. Packet outp(Address(rules[rn].v.zt),RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(nwid); @@ -102,6 +102,7 @@ bool Filter::run( outp.append(frameData,frameLen); outp.compress(); RR->sw->send(outp,true,nwid); + */ } // For REDIRECT we will want to DROP at this node. For TEE we ACCEPT at this node but // also forward it along as we just did. @@ -244,9 +245,20 @@ bool Filter::run( thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); break; case ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE: - break; case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL: case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY: + for(unsigned int i=0;i= rules[rn].v.tag.value[0])&&(tags[i].value() <= rules[rn].v.tag.value[1])); + } else if (rt == ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL) { + thisRuleMatches = (uint8_t)((tags[i].value() & rules[rn].v.tag.value[0]) == rules[rn].v.tag.value[0]); + } else if (rt == ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY) { + thisRuleMatches = (uint8_t)((tags[i].value() & rules[rn].v.tag.value[0]) != 0); + } + break; + } + } break; } diff --git a/node/Filter.hpp b/node/Filter.hpp index f8b661345..06aae55f0 100644 --- a/node/Filter.hpp +++ b/node/Filter.hpp @@ -21,15 +21,16 @@ #include +#include + #include "Constants.hpp" #include "../include/ZeroTierOne.h" +#include "Address.hpp" +#include "MAC.hpp" +#include "Tag.hpp" namespace ZeroTier { -class Address; -class RuntimeEnvironment; -class MAC; - /** * Network packet filter for rules engine */ @@ -42,8 +43,8 @@ public: * This returns whether or not the packet should be accepted and may also * take other actions for e.g. the TEE and REDIRECT targets. * - * @param RR ZeroTier runtime environment (context) * @param nwid ZeroTier network ID + * @param receiving True if on receiving side, false on sending side * @param ztSource Source ZeroTier address * @param ztDest Destination ZeroTier address * @param macSource Ethernet layer source address @@ -54,10 +55,14 @@ public: * @param vlanId 16-bit VLAN ID * @param rules Pointer to array of rules * @param ruleCount Number of rules + * @param tags Tags associated with this node on this network + * @param tagCount Number of tags + * @param sendCopyOfPacketTo Result parameter: if non-NULL send a copy of this packet to another node + * @return True if packet should be accepted for send or receive */ static bool run( - const RuntimeEnvironment *RR, const uint64_t nwid, + const bool receiving, const Address &ztSource, const Address &ztDest, const MAC &macSource, @@ -67,7 +72,10 @@ public: const unsigned int etherType, const unsigned int vlanId, const ZT_VirtualNetworkRule *rules, - const unsigned int ruleCount); + const unsigned int ruleCount, + const Tag *tags, + const unsigned int tagCount, + Address &sendCopyOfPacketTo); }; } // namespace ZeroTier diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e52b3f919..352e4faa8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -38,6 +38,9 @@ #include "Node.hpp" #include "DeferredPackets.hpp" #include "Filter.hpp" +#include "CertificateOfMembership.hpp" +#include "Capability.hpp" +#include "Tag.hpp" namespace ZeroTier { @@ -106,7 +109,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred) case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,peer); case Packet::VERB_ECHO: return _doECHO(RR,peer); case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer); - case Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return _doNETWORK_MEMBERSHIP_CERTIFICATE(RR,peer); + case Packet::VERB_NETWORK_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); @@ -155,22 +158,10 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_IDENTITY_COLLISION: - if (RR->topology->isRoot(peer->identity())) + if (RR->topology->isUpstream(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; - case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - /* Note: certificates are public so it's safe to push them to anyone - * who asks. */ - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->hasConfig())&&(network->config().com)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - network->config().com.serialize(outp); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - } - } break; - case Packet::ERROR_NETWORK_ACCESS_DENIED_: { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) @@ -218,9 +209,13 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer 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 + + // Get external surface address if present (was not in old versions) + if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps + + // Get world ID and world timestamp if present (was not in old versions) + if ((ptr + 16) <= size()) { worldId = at(ptr); ptr += 8; worldTimestamp = at(ptr); } @@ -295,7 +290,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } if (externalSurfaceAddress) - RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isRoot(id),RR->node->now()); + RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_HELLO); @@ -379,13 +374,15 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p return true; } - const bool trusted = RR->topology->isRoot(peer->identity()); - 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 + + // Get reported external surface address if present (was not on old versions) + if (ptr < size()) 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 + + // Handle world updates from root servers if present (was not on old versions) + if (((ptr + 2) <= size())&&(RR->topology->isRoot(peer->identity()))) { World worldUpdate; const unsigned int worldLen = at(ptr); ptr += 2; if (worldLen > 0) { @@ -401,17 +398,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if (externalSurfaceAddress) - RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,trusted,RR->node->now()); + RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: { - if (RR->topology->isRoot(peer->identity())) { + if (RR->topology->isUpstream(peer->identity())) { const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); - // Right now we can skip this since OK(WHOIS) is only accepted from - // roots. In the future it should be done if we query less trusted - // sources. - //if (id.locallyValidate()) - RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR,RR->identity,id)))); + RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR,RR->identity,id)))); } } break; @@ -544,7 +537,6 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { if (!network->isAllowed(peer)) { TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCertificate(RR,peer,network->id()); return true; } @@ -599,7 +591,6 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

isAllowed(peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id()); - _sendErrorNeedCertificate(RR,peer,network->id()); return true; } @@ -704,20 +695,34 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared return true; } -bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { CertificateOfMembership com; + Capability cap; + Tag tag; - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; - while (ptr < size()) { - ptr += com.deserialize(*this,ptr); + unsigned int p = ZT_PACKET_IDX_PAYLOAD; + while ((p < size())&&((*this)[p])) { + p += com.deserialize(*this,p); peer->validateAndSetNetworkMembershipCertificate(com.networkId(),com); } + ++p; // skip trailing 0 after COMs if present - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP); + if (p < size()) { // check if new capabilities and tags fields are present + const unsigned int numCapabilities = at(p); p += 2; + for(unsigned int i=0;i(p); p += 2; + for(unsigned int i=0;ireceived(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP); } catch ( ... ) { - TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } return true; } @@ -859,7 +864,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share // that cert might be what we needed. if (!network->isAllowed(peer)) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCertificate(RR,peer,network->id()); return true; } @@ -1069,22 +1073,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt // into the one we send along to next hops. const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf; - // Get previous hop's credential, if any - const unsigned int previousHopCredentialLength = at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); - CertificateOfMembership previousHopCom; - if (previousHopCredentialLength >= 1) { - switch((*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]) { - case 0x01: { // network certificate of membership for previous hop - const unsigned int phcl = previousHopCom.deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 32 + vlf); - if (phcl != (previousHopCredentialLength - 1)) { - TRACE("dropped CIRCUIT_TEST from %s(%s): previous hop COM invalid (%u != %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),phcl,(previousHopCredentialLength - 1)); - return true; - } - } break; - default: break; - } - } - vlf += previousHopCredentialLength; + // Add length of second "additional fields" section. + vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); // Check credentials (signature already verified) NetworkConfig originatorCredentialNetworkConfig; @@ -1166,13 +1156,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (breadth > 0) { Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature); - const unsigned int previousHopCredentialPos = outp.size(); - outp.append((uint16_t)0); // no previous hop credentials: default - if ((originatorCredentialNetworkConfig)&&(!originatorCredentialNetworkConfig.isPublic())&&(originatorCredentialNetworkConfig.com)) { - outp.append((uint8_t)0x01); // COM - originatorCredentialNetworkConfig.com.serialize(outp); - outp.setAt(previousHopCredentialPos,(uint16_t)(outp.size() - (previousHopCredentialPos + 2))); - } + outp.append((uint16_t)0); // no additional fields if (remainingHopsPtr < size()) outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr); @@ -1241,7 +1225,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const try { // If this were allowed from anyone, it would itself be a DOS vector. Right // now we only allow it from roots and controllers of networks you have joined. - bool allowed = RR->topology->isRoot(peer->identity()); + bool allowed = RR->topology->isUpstream(peer->identity()); if (!allowed) { std::vector< SharedPtr > allNetworks(RR->node->allNetworks()); for(std::vector< SharedPtr >::const_iterator n(allNetworks.begin());n!=allNetworks.end();++n) { @@ -1300,16 +1284,6 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const return true; } -bool IncomingPacket::_doREQUEST_OBJECT(const RuntimeEnvironment *RR,const SharedPtr &peer) -{ - return true; -} - -bool IncomingPacket::_doOBJECT_UPDATED(const RuntimeEnvironment *RR,const SharedPtr &peer) -{ - return true; -} - void IncomingPacket::computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16]) { unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function @@ -1388,15 +1362,4 @@ bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficult return true; } -void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid) -{ - Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)verb()); - outp.append(packetId()); - outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(nwid); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); -} - } // namespace ZeroTier diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index ab7afd512..bfb30a5eb 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -172,7 +172,7 @@ private: bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); @@ -180,11 +180,6 @@ private: bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doREQUEST_OBJECT(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doOBJECT_UPDATED(const RuntimeEnvironment *RR,const SharedPtr &peer); - - // Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to communicate - void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid); uint64_t _receiveTime; InetAddress _localAddress; diff --git a/node/Membership.hpp b/node/Membership.hpp new file mode 100644 index 000000000..93d347e73 --- /dev/null +++ b/node/Membership.hpp @@ -0,0 +1,154 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * + * 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 . + */ + +#ifndef ZT_MEMBERSHIP_HPP +#define ZT_MEMBERSHIP_HPP + +#include + +#include +#include + +#include "Constants.hpp" +#include "../include/ZeroTierOne.h" +#include "CertificateOfMembership.hpp" +#include "Capability.hpp" +#include "Tag.hpp" +#include "Hashtable.hpp" +#include "NetworkConfig.hpp" + +namespace ZeroTier { + +class Peer; + +/** + * Information related to a peer's participation on a network + * + * This structure is not thread-safe and must be locked during use. + */ +class Membership +{ +private: + struct TState + { + TState() : lastPushed(0),lastReceived(0) {} + // Last time we pushed this tag to this peer + uint64_t lastPushed; + // Last time we received this tag from this peer + uint64_t lastReceived; + // Tag from peer + Tag tag; + }; + + struct CState + { + CState() : lastPushed(0),lastReceived(0) {} + // Last time we pushed this capability to this peer + uint64_t lastPushed; + // Last time we received this capability from this peer + uint64_t lastReceived; + // Capability from peer + Capability cap; + }; + +public: + Membership() : + _lastPushedCom(0), + _com(), + _caps(8), + _tags(8) + { + } + + /** + * Send COM and other credentials to this peer if needed + * + * This checks last pushed times for our COM and for other credentials and + * sends VERB_NETWORK_CREDENTIALS if the recipient might need them. + * + * @param peer Peer that "owns" this membership + * @param nconf Network configuration + * @param now Current time + * @param capIds Capability IDs that this peer might need + * @param capCount Number of capability IDs + * @param tagIds Tag IDs that this peer might need + * @param tagCount Number of tag IDs + */ + void sendCredentialsIfNeeded(const Peer &peer,const NetworkConfig &nconf,const uint64_t now,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) const; + + /** + * @param nconf Network configuration + * @param id Tag ID + * @return Pointer to tag or NULL if not found + */ + inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const + { + const TState *t = _tags.get(id); + return ((t) ? (((t->lastReceived != 0)&&(t->tag.expiration() < nconf.timestamp)) ? &(t->tag) : (const Tag *)0) : (const Tag *)0); + } + + /** + * @param nconf Network configuration + * @param id Capablity ID + * @return Pointer to capability or NULL if not found + */ + inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const + { + const CState *c = _caps.get(id); + return ((c) ? (((c->lastReceived != 0)&&(c->cap.expiration() < nconf.timestamp)) ? &(c->cap) : (const Capability *)0) : (const Capability *)0); + } + + /** + * Clean up old or stale entries + */ + inline void clean(const uint64_t now) + { + uint32_t *i = (uint32_t *)0; + CState *cs = (CState *)0; + Hashtable::Iterator csi(_caps); + while (csi.next(i,cs)) { + if ((now - std::max(cs->lastPushed,cs->lastReceived)) > (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 3)) + _caps.erase(*i); + } + + i = (uint32_t *)0; + TState *ts = (TState *)0; + Hashtable::Iterator tsi(_tags); + while (tsi.next(i,ts)) { + if ((now - std::max(ts->lastPushed,ts->lastReceived)) > (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 3)) + _tags.erase(*i); + } + } + +private: + // Last time we pushed our COM to this peer + uint64_t _lastPushedCom; + + // COM from this peer + CertificateOfMembership _com; + + // Capability-related state + Hashtable _caps; + + // Tag-related state + Hashtable _tags; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Network.cpp b/node/Network.cpp index 251166479..061cca073 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -216,6 +216,8 @@ void Network::requestConfiguration() rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_ONE_VERSION_REVISION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES); if (controller() == RR->identity.address()) { if (RR->localNetworkController) { diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index af7ce93bd..6158c5666 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -35,6 +35,8 @@ #include "MulticastGroup.hpp" #include "Address.hpp" #include "CertificateOfMembership.hpp" +#include "Capability.hpp" +#include "Tag.hpp" #include "Dictionary.hpp" /** @@ -76,6 +78,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION "majv" #define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION "minv" #define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION "revv" +#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES "Mr" +#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES "Mcr" // These dictionary keys are short so they don't take up much room. @@ -288,6 +292,32 @@ public: inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); } inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); } + /** + * Add a specialist or mask flags if already present + * + * This masks the existing flags if the specialist is already here or adds + * it otherwise. + * + * @param a Address of specialist + * @param f Flags (OR of specialist role/type flags) + * @return True if successfully masked or added + */ + inline bool addSpecialist(const Address &a,const uint64_t f) + { + const uint64_t aint = a.toInt(); + for(unsigned int i=0;i * <[...] error-dependent payload> */ - VERB_ERROR = 2, + VERB_ERROR = 0x02, /** * Success response: @@ -583,7 +587,7 @@ public: * <[8] in-re packet ID> * <[...] request-specific payload> */ - VERB_OK = 3, + VERB_OK = 0x03, /** * Query an identity by address: @@ -598,7 +602,7 @@ public: * If the address is not found, no response is generated. WHOIS requests * will time out much like ARP requests and similar do in L2. */ - VERB_WHOIS = 4, + VERB_WHOIS = 0x04, /** * Meet another node at a given protocol address: @@ -626,7 +630,7 @@ public: * * No OK or ERROR is generated. */ - VERB_RENDEZVOUS = 5, + VERB_RENDEZVOUS = 0x05, /** * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): @@ -642,31 +646,29 @@ public: * ERROR may be generated if a membership certificate is needed for a * closed network. Payload will be network ID. */ - VERB_FRAME = 6, + VERB_FRAME = 0x06, /** * Full Ethernet frame with MAC addressing and optional fields: * <[8] 64-bit network ID> * <[1] flags> - * [<[...] certificate of network membership>] + * [<[...] certificate of network membership (DEPRECATED)>] * <[6] destination MAC or all zero for destination node> * <[6] source MAC or all zero for node of origin> * <[2] 16-bit ethertype> * <[...] ethernet payload> * * Flags: - * 0x01 - Certificate of network membership is attached + * 0x01 - Certificate of network membership attached (DEPRECATED) * * An extended frame carries full MAC addressing, making them a * superset of VERB_FRAME. They're used for bridging or when we * want to attach a certificate since FRAME does not support that. * - * Multicast frames may not be sent as EXT_FRAME. - * * ERROR may be generated if a membership certificate is needed for a * closed network. Payload will be network ID. */ - VERB_EXT_FRAME = 7, + VERB_EXT_FRAME = 0x07, /** * ECHO request (a.k.a. ping): @@ -676,7 +678,7 @@ public: * is generated. Response to ECHO requests is optional and ECHO may be * ignored if a node detects a possible flood. */ - VERB_ECHO = 8, + VERB_ECHO = 0x08, /** * Announce interest in multicast group(s): @@ -690,45 +692,76 @@ public: * controllers and root servers. In the current network, root servers * will provide the service of final multicast cache. * - * If sending LIKEs to root servers for backward compatibility reasons, - * VERB_NETWORK_MEMBERSHIP_CERTIFICATE must be sent as well ahead of - * time so that roots can authenticate GATHER requests. + * VERB_NETWORK_CREDENTIALS should be pushed along with this, especially + * if using upstream (e.g. root) nodes as multicast databases. This allows + * GATHERs to be authenticated. * * OK/ERROR are not generated. */ - VERB_MULTICAST_LIKE = 9, + VERB_MULTICAST_LIKE = 0x09, /** - * Network member certificate replication/push: + * Network membership credential push: * <[...] serialized certificate of membership> - * [ ... additional certificates may follow ...] + * [<[...] additional certificates of membership>] + * <[1] null byte for backward compatibility (see below)> + * <[2] 16-bit number of capabilities> + * <[...] one or more serialized Capability> + * <[2] 16-bit number of tags> + * <[...] one or more serialized Tags> * * This is sent in response to ERROR_NEED_MEMBERSHIP_CERTIFICATE and may * be pushed at any other time to keep exchanged certificates up to date. * + * Protocol versions prior to 8 do not support capabilities or tags and + * just expect an array of COMs. Adding a single NULL byte after the COM + * array causes these older versions to harmlessly abort parsing and + * ignore the newer fields. The new version checks for this null byte to + * indicate the end of the COM array, since all serialized COMs begin with + * non-zero bytes (see CertificateOfMembership). + * * OK/ERROR are not generated. */ - VERB_NETWORK_MEMBERSHIP_CERTIFICATE = 10, + VERB_NETWORK_CREDENTIALS = 0x0a, /** - * DEPRECATED but still supported, interpreted as an object request: + * Network configuration request: + * <[8] 64-bit network ID> + * <[2] 16-bit length of request meta-data dictionary> + * <[...] string-serialized request meta-data> + * [<[8] 64-bit timestamp of netconf we currently have>] * - * /controller/network//member/ - * - * When received in this manner the response is sent via the old - * OK(NETWORK_CONFIG_REQUEST) instead of OK(REQUEST_OBJECT). If the - * response is too large, a dictionary is sent with the single key - * OVF set to 1. In this case REQUEST_OBJECT must be used. + * This message requests network configuration from a node capable of + * providing it. If the optional revision is included, a response is + * only generated if there is a newer network configuration available. * * OK response payload: * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary> - * <[...] network configuration dictionary> + * <[2] 16-bit length of network configuration dictionary field> + * <[...] network configuration dictionary (or fragment)> + * [<[4] 32-bit total length of assembled dictionary>] + * [<[4] 32-bit index of fragment in this reply>] + * + * Fields after the dictionary are extensions to support multipart + * sending of large network configs. If they are not present the + * sent config must be assumed to be whole. * * ERROR response payload: * <[8] 64-bit network ID> */ - VERB_NETWORK_CONFIG_REQUEST = 11, + VERB_NETWORK_CONFIG_REQUEST = 0x0b, + + /** + * Network configuration refresh request: + * <[...] array of 64-bit network IDs> + * + * This can be sent by the network controller to inform a node that it + * should now make a NETWORK_CONFIG_REQUEST. + * + * It does not generate an OK or ERROR message, and is treated only as + * a hint to refresh now. + */ + VERB_NETWORK_CONFIG_REFRESH = 0x0c, /** * Request endpoints for multicast distribution: @@ -737,10 +770,10 @@ public: * <[6] MAC address of multicast group being queried> * <[4] 32-bit ADI for multicast group being queried> * <[4] 32-bit requested max number of multicast peers> - * [<[...] network certificate of membership>] + * [<[...] network certificate of membership (DEPRECATED)>] * * Flags: - * 0x01 - Network certificate of membership is attached + * 0x01 - COM is attached (DEPRECATED) * * This message asks a peer for additional known endpoints that have * LIKEd a given multicast group. It's sent when the sender wishes @@ -750,6 +783,9 @@ public: * More than one OK response can occur if the response is broken up across * multiple packets or if querying a clustered node. * + * Send VERB_NETWORK_CREDENTIALS prior to GATHERing if doing so from + * upstream nodes like root servers that are not involved in our network. + * * OK response payload: * <[8] 64-bit network ID> * <[6] MAC address of multicast group being queried> @@ -761,13 +797,13 @@ public: * * ERROR is not generated; queries that return no response are dropped. */ - VERB_MULTICAST_GATHER = 13, + VERB_MULTICAST_GATHER = 0x0d, /** * Multicast frame: * <[8] 64-bit network ID> * <[1] flags> - * [<[...] network certificate of membership>] + * [<[...] network certificate of membership (DEPRECATED)>] * [<[4] 32-bit implicit gather limit>] * [<[6] source MAC>] * <[6] destination MAC (multicast address)> @@ -776,7 +812,7 @@ public: * <[...] ethernet payload> * * Flags: - * 0x01 - Network certificate of membership is attached + * 0x01 - Network certificate of membership attached (DEPRECATED) * 0x02 - Implicit gather limit field is present * 0x04 - Source MAC is specified -- otherwise it's computed from sender * @@ -791,11 +827,11 @@ public: * <[6] MAC address of multicast group> * <[4] 32-bit ADI for multicast group> * <[1] flags> - * [<[...] network certficate of membership>] + * [<[...] network certficate of membership (DEPRECATED)>] * [<[...] implicit gather results if flag 0x01 is set>] * * OK flags (same bits as request flags): - * 0x01 - OK includes certificate of network membership + * 0x01 - OK includes certificate of network membership (DEPRECATED) * 0x02 - OK includes implicit gather results * * ERROR response payload: @@ -803,7 +839,9 @@ public: * <[6] multicast group MAC> * <[4] 32-bit multicast group ADI> */ - VERB_MULTICAST_FRAME = 14, + VERB_MULTICAST_FRAME = 0x0e, + + // 0x0f is reserved for an old deprecated message /** * Push of potential endpoints for direct communication: @@ -839,7 +877,7 @@ public: * * OK and ERROR are not generated. */ - VERB_PUSH_DIRECT_PATHS = 16, + VERB_PUSH_DIRECT_PATHS = 0x10, /** * Source-routed circuit test message: @@ -855,9 +893,8 @@ public: * [ ... end of signed portion of request ... ] * <[2] 16-bit length of signature of request> * <[...] signature of request by originator> - * <[2] 16-bit previous hop credential length (including type)> - * [[1] previous hop credential type] - * [[...] previous hop credential] + * <[2] 16-bit length of additional fields> + * [[...] additional fields] * <[...] next hop(s) in path> * * Flags: @@ -867,9 +904,6 @@ public: * Originator credential types: * 0x01 - 64-bit network ID for which originator is controller * - * Previous hop credential types: - * 0x01 - Certificate of network membership - * * Path record format: * <[1] 8-bit flags (unused, must be zero)> * <[1] 8-bit breadth (number of next hops)> @@ -918,7 +952,7 @@ public: * <[8] 64-bit timestamp (echoed from original> * <[8] 64-bit test ID (echoed from original)> */ - VERB_CIRCUIT_TEST = 17, + VERB_CIRCUIT_TEST = 0x11, /** * Circuit test hop report: @@ -955,7 +989,7 @@ public: * If a test report is received and no circuit test was sent, it should be * ignored. This message generates no OK or ERROR response. */ - VERB_CIRCUIT_TEST_REPORT = 18, + VERB_CIRCUIT_TEST_REPORT = 0x12, /** * Request proof of work: @@ -998,63 +1032,7 @@ public: * * ERROR has no payload. */ - VERB_REQUEST_PROOF_OF_WORK = 19, - - /** - * Request an object or a chunk of an object with optional meta-data: - * <[8] 64-bit chunk offset> - * <[2] 16-bit chunk length or 0 for any / sender-preferred> - * <[2] 16-bit object path length in bytes> - * <[...] object path> - * <[2] 16-bit length of request meta-data dictionary> - * <[...] request meta-data dictionary> - * - * This is used to request an object. Objects can be things like network - * configs, software updates, etc. This provides an in-band way to - * distribute such things and obsoletes the network config specific - * messages. (They are still supported for backward compatibility.) - * - * The use of path and request/response meta-data makes the semantics of - * this analogous to HTTP POST, and it could therefore be mapped to - * HTTP POST requests to permit plugins that leverage the ZT protocol - * to do out-of-band things like special authentication, etc. - * - * Large objects can be transferred via repeated calls with higher and - * higher chunk offsets and then SHA-512 verified on receipt, but this is - * not efficient. It should not be used heavily as an alternative to - * TCP. It's a bit more like X-Modem and other old-school SEND/ACK - * protocols. It is potentially a good idea for software updates since - * it means that ZT can update itself even on networks with no "vanilla" - * Internet access. - * - * OK and ERROR responses are optional but recommended. ERROR responses - * can include OBJECT_NOT_FOUND. - * - * OK response payload: - * <[16] first 16 bytes of SHA-512 of complete object> - * <[8] 64-bit total object size> - * <[8] 64-bit chunk offset> - * <[2] 16-bit length of chunk payload> - * <[...] chunk payload> - */ - VERB_REQUEST_OBJECT = 20, - - /** - * Notification of a remote object update: - * <[8] 64-bit total object size or 0 if unspecified here> - * <[16] first 16 bytes of SHA-512 of object (if size specified)> - * <[2] 16-bit length of object path> - * <[...] object path> - * <[2] 16-bit length of meta-data dictionary> - * <[...] meta-data dictionary> - * - * This can be sent to notify another peer that an object has updated and - * should be re-requested. The receiving peer is not required to do anything - * or send anything in response to this. If the first size field is zero, the - * SHA-512 hash is also unspecified and should be zero. This means that the - * object was updated but must be re-requested. - */ - VERB_OBJECT_UPDATED = 21 + VERB_REQUEST_PROOF_OF_WORK = 0x13 }; /** @@ -1063,31 +1041,28 @@ public: enum ErrorCode { /* No error, not actually used in transit */ - ERROR_NONE = 0, + ERROR_NONE = 0x00, /* Invalid request */ - ERROR_INVALID_REQUEST = 1, + ERROR_INVALID_REQUEST = 0x01, /* Bad/unsupported protocol version */ - ERROR_BAD_PROTOCOL_VERSION = 2, + ERROR_BAD_PROTOCOL_VERSION = 0x02, /* Unknown object queried */ - ERROR_OBJ_NOT_FOUND = 3, + ERROR_OBJ_NOT_FOUND = 0x03, /* HELLO pushed an identity whose address is already claimed */ - ERROR_IDENTITY_COLLISION = 4, + ERROR_IDENTITY_COLLISION = 0x04, /* Verb or use case not supported/enabled by this node */ - ERROR_UNSUPPORTED_OPERATION = 5, - - /* Message to private network rejected -- no unexpired certificate on file */ - ERROR_NEED_MEMBERSHIP_CERTIFICATE = 6, + ERROR_UNSUPPORTED_OPERATION = 0x05, /* Tried to join network, but you're not a member */ - ERROR_NETWORK_ACCESS_DENIED_ = 7, /* extra _ to avoid Windows name conflict */ + ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ /* Multicasts to this group are not wanted */ - ERROR_UNWANTED_MULTICAST = 8 + ERROR_UNWANTED_MULTICAST = 0x08 }; //#ifdef ZT_TRACE diff --git a/node/Peer.hpp b/node/Peer.hpp index 445535c8f..d8c44ebe4 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -31,7 +31,6 @@ #include "../include/ZeroTierOne.h" #include "RuntimeEnvironment.hpp" -#include "CertificateOfMembership.hpp" #include "Path.hpp" #include "Address.hpp" #include "Utils.hpp" @@ -44,10 +43,6 @@ #include "Mutex.hpp" #include "NonCopyable.hpp" -// Very rough computed estimate: (8 + 256 + 80 + (16 * 64) + (128 * 256) + (128 * 16)) -// 1048576 provides tons of headroom -- overflow would just cause peer not to be persisted -#define ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE 1048576 - namespace ZeroTier { /** @@ -362,31 +357,6 @@ public: */ void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; - /** - * Check network COM agreement with this peer - * - * @param nwid Network ID - * @param com Another certificate of membership - * @return True if supplied COM agrees with ours, false if not or if we don't have one - */ - bool networkMembershipCertificatesAgree(uint64_t nwid,const CertificateOfMembership &com) const; - - /** - * Check the validity of the COM and add/update if valid and new - * - * @param nwid Network ID - * @param com Externally supplied COM - */ - bool validateAndSetNetworkMembershipCertificate(uint64_t nwid,const CertificateOfMembership &com); - - /** - * @param nwid Network ID - * @param now Current time - * @param updateLastPushedTime If true, go ahead and update the last pushed time regardless of return value - * @return Whether or not this peer needs another COM push from us - */ - bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime); - /** * Perform periodic cleaning operations * @@ -434,138 +404,12 @@ public: else return std::pair(); } - template - inline void serialize(Buffer &b) const - { - Mutex::Lock _l(_networkComs_m); - - 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 - - _id.serialize(b,false); - - b.append((uint64_t)_lastUsed); - b.append((uint64_t)_lastReceive); - b.append((uint64_t)_lastUnicastFrame); - b.append((uint64_t)_lastMulticastFrame); - b.append((uint64_t)_lastAnnouncedTo); - 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) - _paths[i].serialize(b); - - b.append((uint32_t)_networkComs.size()); - { - uint64_t *k = (uint64_t *)0; - _NetworkCom *v = (_NetworkCom *)0; - Hashtable::Iterator i(const_cast(this)->_networkComs); - while (i.next(k,v)) { - b.append((uint64_t)*k); - b.append((uint64_t)v->ts); - v->com.serialize(b); - } - } - - b.append((uint32_t)_lastPushedComs.size()); - { - uint64_t *k = (uint64_t *)0; - uint64_t *v = (uint64_t *)0; - Hashtable::Iterator i(const_cast(this)->_lastPushedComs); - while (i.next(k,v)) { - b.append((uint64_t)*k); - b.append((uint64_t)*v); - } - } - - b.template setAt(recSizePos,(uint32_t)(b.size() - (recSizePos + 4))); // set size - } - - /** - * Create a new Peer from a serialized instance - * - * @param renv Runtime environment - * @param myIdentity This node's identity - * @param b Buffer containing serialized Peer data - * @param p Pointer to current position in buffer, will be updated in place as buffer is read (value/result) - * @return New instance of Peer or NULL if serialized data was corrupt or otherwise invalid (may also throw an exception via Buffer) - */ - template - static inline SharedPtr deserializeNew(const RuntimeEnvironment *renv,const Identity &myIdentity,const Buffer &b,unsigned int &p) - { - 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) - return SharedPtr(); // version mismatch - p += 2; - - Identity npid; - p += npid.deserialize(b,p); - if (!npid) - return SharedPtr(); - - SharedPtr np(new Peer(renv,myIdentity,npid)); - - np->_lastUsed = b.template at(p); p += 8; - np->_lastReceive = b.template at(p); p += 8; - np->_lastUnicastFrame = b.template at(p); p += 8; - np->_lastMulticastFrame = b.template at(p); p += 8; - np->_lastAnnouncedTo = 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_paths[np->_numPaths++].deserialize(b,p); - } else { - // Skip any paths beyond max, but still read stream - Path foo; - p += foo.deserialize(b,p); - } - } - - const unsigned int numNetworkComs = b.template at(p); p += 4; - for(unsigned int i=0;i_networkComs[b.template at(p)]; p += 8; - c.ts = b.template at(p); p += 8; - p += c.com.deserialize(b,p); - } - - const unsigned int numLastPushed = b.template at(p); p += 4; - for(unsigned int i=0;i(p); p += 8; - const uint64_t ts = b.template at(p); p += 8; - np->_lastPushedComs.set(nwid,ts); - } - - return np; - } - private: void _doDeadPathDetection(Path &p,const uint64_t now); 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 + unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; const RuntimeEnvironment *RR; uint64_t _lastUsed; @@ -586,17 +430,6 @@ private: unsigned int _latency; unsigned int _directPathPushCutoffCount; - struct _NetworkCom - { - _NetworkCom() {} - _NetworkCom(uint64_t t,const CertificateOfMembership &c) : ts(t),com(c) {} - uint64_t ts; - CertificateOfMembership com; - }; - Hashtable _networkComs; - Hashtable _lastPushedComs; - Mutex _networkComs_m; - AtomicCounter __refCount; }; diff --git a/node/Topology.cpp b/node/Topology.cpp index 9b434732b..725eed319 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -47,36 +47,7 @@ Topology::Topology(const RuntimeEnvironment *renv) : _trustedPathCount(0), _amRoot(false) { - std::string alls(RR->node->dataStoreGet("peers.save")); - const uint8_t *all = reinterpret_cast(alls.data()); - RR->node->dataStoreDelete("peers.save"); - - Buffer *deserializeBuf = new Buffer(); - unsigned int ptr = 0; - while ((ptr + 4) < alls.size()) { - try { - const unsigned int reclen = ( // each Peer serialized record is prefixed by a record length - ((((unsigned int)all[ptr]) & 0xff) << 24) | - ((((unsigned int)all[ptr + 1]) & 0xff) << 16) | - ((((unsigned int)all[ptr + 2]) & 0xff) << 8) | - (((unsigned int)all[ptr + 3]) & 0xff) - ); - unsigned int pos = 0; - deserializeBuf->copyFrom(all + ptr,reclen + 4); - SharedPtr p(Peer::deserializeNew(RR,RR->identity,*deserializeBuf,pos)); - ptr += pos; - if (!p) - break; // stop if invalid records - if (p->address() != RR->identity.address()) - _peers.set(p->address(),p); - } catch ( ... ) { - break; // stop if invalid records - } - } - delete deserializeBuf; - - clean(RR->node->now()); - + // Get cached world if present std::string dsWorld(RR->node->dataStoreGet("world")); World cachedWorld; if (dsWorld.length() > 0) { @@ -87,6 +58,8 @@ Topology::Topology(const RuntimeEnvironment *renv) : cachedWorld = World(); // clear if cached world is invalid } } + + // Use default or cached world depending on which is shinier World defaultWorld; { Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); diff --git a/service/OneService.cpp b/service/OneService.cpp index 13820f5ca..460eb1c93 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -705,6 +705,9 @@ public: } authToken = _trimString(authToken); + // Clean up any legacy files if present + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + "peers.save").c_str()); + _node = new Node( OSUtils::now(), this,