From 7404eb46c4279b1e2ecce29aece14e15fbedbffd Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 25 Jul 2016 16:51:10 -0700 Subject: Integration of Filter into inbound and outbound packet path. --- node/IncomingPacket.cpp | 81 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 16 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 37af8425..b666e42c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -37,6 +37,7 @@ #include "Cluster.hpp" #include "Node.hpp" #include "DeferredPackets.hpp" +#include "Filter.hpp" namespace ZeroTier { @@ -550,13 +551,27 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr } const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - if (!network->config().permitsEtherType(etherType)) { - TRACE("dropped FRAME from %s(%s): ethertype %.4x not allowed on %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); - return true; + const MAC sourceMac(peer->address(),network->id()); + const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + if (Filter::run( + RR, + network->id(), + peer->address(), + RR->identity.address(), + sourceMac, + network->mac(), + frameData, + frameLen, + etherType, + 0, + network->config().rules, + network->config().ruleCount)) + { + RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + } else { + TRACE("dropped FRAME from %s(%s): Filter::run() == false (will still log packet as received)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); } - - const unsigned int payloadLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - RR->node->putFrame(network->id(),network->userPtr(),MAC(peer->address(),network->id()),network->mac(),etherType,0,field(ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); } peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP); @@ -594,10 +609,6 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); - if (!network->config().permitsEtherType(etherType)) { - TRACE("dropped EXT_FRAME from %s(%s): ethertype %.4x not allowed on network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); - return true; - } const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); @@ -626,8 +637,26 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); + const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); + const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); + if (Filter::run( + RR, + network->id(), + peer->address(), + RR->identity.address(), + from, + to, + frameData, + frameLen, + etherType, + 0, + network->config().rules, + network->config().ruleCount)) + { + RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + } else { + TRACE("dropped EXT_FRAME from %s(%s): Filter::run() == false (will still log packet as received)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); + } } peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP); @@ -870,11 +899,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); - const unsigned int payloadLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); + const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); - //TRACE("<address().toString().c_str(),flags,payloadLen); + //TRACE("<address().toString().c_str(),flags,frameLen); - if ((payloadLen > 0)&&(payloadLen <= ZT_IF_MTU)) { + if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); return true; @@ -893,7 +922,27 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } } - RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,payloadLen),payloadLen); + const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); + if (Filter::run( + RR, + network->id(), + peer->address(), + RR->identity.address(), + from, + to.mac(), + frameData, + frameLen, + etherType, + 0, + network->config().rules, + network->config().ruleCount)) + { + RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); + } else { + TRACE("dropped MULTICAST_FRAME from %s(%s): Filter::run() == false (will still do implicit gather)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); + // Note: we continue here since we still do implicit gather in this case... we just do not putFrame() if it + // fails the filter check. + } } if (gatherLimit) { -- cgit v1.2.3 From 4929be08f77dbdc2c0277dc99c2b5438ede4b137 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 26 Jul 2016 12:33:51 -0700 Subject: Cleanup and stub out new object transfer messages. --- node/IncomingPacket.cpp | 32 ++++++---------- node/IncomingPacket.hpp | 3 +- node/Packet.cpp | 3 +- node/Packet.hpp | 98 +++++++++++++++++++++++++++++++------------------ 4 files changed, 77 insertions(+), 59 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b666e42c..e52b3f91 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -108,7 +108,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred) 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_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); @@ -162,8 +161,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { /* Note: certificates are public so it's safe to push them to anyone - * who asks. We won't communicate unless we also get a certificate - * from the remote that agrees. */ + * 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); @@ -805,24 +803,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons return true; } -bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer) -{ - try { - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; - while ((ptr + 8) <= size()) { - uint64_t nwid = at(ptr); - SharedPtr nw(RR->node->network(nwid)); - if ((nw)&&(peer->address() == nw->controller())) - nw->requestConfiguration(); - ptr += 8; - } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP); - } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); - } - return true; -} - bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { @@ -1320,6 +1300,16 @@ 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 diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index cd0b7dcf..ab7afd51 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -174,13 +174,14 @@ private: bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); 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); diff --git a/node/Packet.cpp b/node/Packet.cpp index 3330a927..5152f572 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -40,13 +40,14 @@ const char *Packet::verbString(Verb v) case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE"; case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; - case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST"; case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT"; case VERB_REQUEST_PROOF_OF_WORK: return "REQUEST_PROOF_OF_WORK"; + case VERB_REQUEST_OBJECT: return "REQUEST_OBJECT"; + case VERB_OBJECT_UPDATED: return "OBJECT_UPDATED"; } return "(unknown)"; } diff --git a/node/Packet.hpp b/node/Packet.hpp index 3d95b0ba..211c3aa5 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -715,53 +715,23 @@ public: VERB_NETWORK_MEMBERSHIP_CERTIFICATE = 10, /** - * 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 revision of netconf we currently have>] + * DEPRECATED but still supported, interpreted as an object request: + * + * /controller/network//member/ * - * 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. + * When received in this manner the response is sent via the old + * OK(NETWORK_CONFIG_REQUEST) instead of OK(REQUEST_OBJECT). * * OK response payload: * <[8] 64-bit network ID> * <[2] 16-bit length of network configuration dictionary> * <[...] network configuration dictionary> * - * OK returns a Dictionary (string serialized) containing the network's - * configuration and IP address assignment information for the querying - * node. It also contains a membership certificate that the querying - * node can push to other peers to demonstrate its right to speak on - * a given network. - * - * When a new network configuration is received, another config request - * should be sent with the new netconf's revision. This confirms receipt - * and also causes any subsequent changes to rapidly propagate as this - * cycle will repeat until there are no changes. This is optional but - * recommended behavior. - * * ERROR response payload: * <[8] 64-bit network ID> - * - * UNSUPPORTED_OPERATION is returned if this service is not supported, - * and OBJ_NOT_FOUND if the queried network ID was not found. */ VERB_NETWORK_CONFIG_REQUEST = 11, - /** - * 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 = 12, - /** * Request endpoints for multicast distribution: * <[8] 64-bit network ID> @@ -1030,7 +1000,63 @@ public: * * ERROR has no payload. */ - VERB_REQUEST_PROOF_OF_WORK = 19 + 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 }; /** -- cgit v1.2.3 From 7e6e56e2bce240a8d3a4f2825d3f110109a541b6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 3 Aug 2016 18:04:08 -0700 Subject: 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 (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index db405c08..9679cf64 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 82342874..d050b2b8 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 d86d1a14..2980149b 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 f8b66134..06aae55f 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 e52b3f91..352e4faa 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 + + 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_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP); + peer->received(_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 ab7afd51..bfb30a5e 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 00000000..93d347e7 --- /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 25116647..061cca07 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 af7ce93b..6158c566 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: - * - * /controller/network//member/ + * 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>] * - * 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 445535c8..d8c44ebe 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 9b434732..725eed31 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 13820f5c..460eb1c9 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, -- cgit v1.2.3 From f057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 09:02:35 -0700 Subject: More work on tags and capabilities. --- node/Capability.cpp | 52 +++++++++++++++++++++ node/Capability.hpp | 38 +++++++++------ node/CertificateOfMembership.cpp | 33 ++++++-------- node/CertificateOfMembership.hpp | 12 +++-- node/IncomingPacket.cpp | 27 +++++++---- node/LockingPtr.hpp | 99 ++++++++++++++++++++++++++++++++++++++++ node/Membership.hpp | 92 +++++++++++++++++++++++++++++++++++-- node/Peer.hpp | 33 ++++++++++++++ node/Tag.cpp | 45 ++++++++++++++++++ node/Tag.hpp | 11 +++-- node/Topology.cpp | 4 +- objects.mk | 3 ++ 12 files changed, 396 insertions(+), 53 deletions(-) create mode 100644 node/Capability.cpp create mode 100644 node/LockingPtr.hpp create mode 100644 node/Tag.cpp (limited to 'node/IncomingPacket.cpp') diff --git a/node/Capability.cpp b/node/Capability.cpp new file mode 100644 index 00000000..07eb41a9 --- /dev/null +++ b/node/Capability.cpp @@ -0,0 +1,52 @@ +/* + * 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 . + */ + +#include "Capability.hpp" +#include "RuntimeEnvironment.hpp" +#include "Identity.hpp" +#include "Topology.hpp" +#include "Switch.hpp" + +namespace ZeroTier { + +int Capability::verify(const RuntimeEnvironment *RR) const +{ + try { + Buffer<(sizeof(Capability) * 2)> tmp; + this->serialize(tmp,true); + for(unsigned int c=0;ctopology->getIdentity(_custody[c].from)); + if (id) { + if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) + return -1; + } else { + RR->sw->requestWhois(_custody[c].from); + return 1; + } + } + return 0; + } catch ( ... ) { + return -1; + } +} + +} // namespace ZeroTier diff --git a/node/Capability.hpp b/node/Capability.hpp index d050b2b8..48282708 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -130,11 +130,11 @@ public: inline bool sign(const Identity &from,const Address &to) { try { - Buffer<(sizeof(Capability) * 2)> tmp; for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i tmp; this->serialize(tmp,true); _custody[i].signature = from.sign(tmp.data(),tmp.size()); return true; @@ -145,22 +145,12 @@ public: } /** - * Verify this capability's chain of custody - * - * This returns a tri-state result. A return value of zero indicates that - * the chain of custody is valid and all signatures are okay. A positive - * return value means at least one WHOIS was issued for a missing signing - * identity and we should retry later. A negative return value means that - * this chain or one of its signature is BAD and this capability should - * be discarded. - * - * Note that the entire chain is checked regardless of verifyInChain. + * Verify this capability's chain of custody and signatures * * @param RR Runtime environment to provide for peer lookup, etc. - * @param verifyInChain Also check to ensure that this capability was at some point properly issued to this peer (if non-null) * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ - int verify(const RuntimeEnvironment *RR,const Address &verifyInChain) const; + int verify(const RuntimeEnvironment *RR) const; template static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) @@ -403,9 +393,31 @@ public: return (p - startAt); } + /** + * Check to see if a given address is a 'to' address in the custody chain + * + * This does not actually do certificate checking. That must be done with verify(). + * + * @param a Address to check + * @return True if address is present + */ + inline bool wasIssuedTo(const Address &a) const + { + for(unsigned int i=0;i ZT_NETWORK_COM_MAX_QUALIFIERS)) + return -1; - uint64_t *const buf = new uint64_t[_qualifierCount * 3]; + const Identity id(RR->topology->getIdentity(_signedBy)); + if (!id) { + RR->sw->requestWhois(_signedBy); + return 1; + } + + uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; unsigned int ptr = 0; for(unsigned int i=0;i<_qualifierCount;++i) { buf[ptr++] = Utils::hton(_qualifiers[i].id); buf[ptr++] = Utils::hton(_qualifiers[i].value); buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); } - - bool valid = false; - try { - valid = id.verify(buf,ptr * sizeof(uint64_t),_signature); - delete [] buf; - } catch ( ... ) { - delete [] buf; - } - return valid; + return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1); } } // namespace ZeroTier diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 8fae8b08..a04f8255 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -46,10 +46,12 @@ /** * Maximum number of qualifiers allowed in a COM (absolute max: 65535) */ -#define ZT_NETWORK_COM_MAX_QUALIFIERS 256 +#define ZT_NETWORK_COM_MAX_QUALIFIERS 8 namespace ZeroTier { +class RuntimeEnvironment; + /** * Certificate of network membership * @@ -275,12 +277,12 @@ public: bool sign(const Identity &with); /** - * Verify certificate against an identity + * Verify this COM and its signature * - * @param id Identity to verify against - * @return True if certificate is signed by this identity and verification was successful + * @param RR Runtime environment for looking up peers + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - bool verify(const Identity &id) const; + int verify(const RuntimeEnvironment *RR) const; /** * @return True if signed diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 352e4faa..6548bda6 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -443,11 +443,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p unsigned int offset = 0; - if ((flags & 0x01) != 0) { - // OK(MULTICAST_FRAME) includes certificate of membership update + if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - peer->validateAndSetNetworkMembershipCertificate(nwid,com); + LockingPtr m = peer->membership(com.networkId(),true); + if (m) m->addCredential(RR,RR->node->now(),com); } if ((flags & 0x02) != 0) { @@ -583,10 +583,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

validateAndSetNetworkMembershipCertificate(network->id(),com); + LockingPtr m = peer->membership(com.networkId(),true); + if (m) m->addCredential(RR,RR->node->now(),com); } if (!network->isAllowed(peer)) { @@ -698,6 +699,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { + const uint64_t now = RR->node->now(); CertificateOfMembership com; Capability cap; Tag tag; @@ -705,7 +707,9 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p])) { p += com.deserialize(*this,p); - peer->validateAndSetNetworkMembershipCertificate(com.networkId(),com); + LockingPtr m = peer->membership(com.networkId(),true); + if (!m) return true; // sanity check + m->addCredential(RR,now,com); } ++p; // skip trailing 0 after COMs if present @@ -713,10 +717,16 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i m = peer->membership(cap.networkId(),true); + if (!m) return true; // sanity check + m->addCredential(RR,now,cap); } const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i m = peer->membership(tag.networkId(),true); + if (!m) return true; // sanity check + m->addCredential(RR,now,tag); } } @@ -854,10 +864,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share // Offset -- size of optional fields added to position of later fields unsigned int offset = 0; - if ((flags & 0x01) != 0) { + if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - peer->validateAndSetNetworkMembershipCertificate(nwid,com); + LockingPtr m = peer->membership(com.networkId(),true); + if (m) m->addCredential(RR,RR->node->now(),com); } // Check membership after we've read any included COM, since diff --git a/node/LockingPtr.hpp b/node/LockingPtr.hpp new file mode 100644 index 00000000..c373129a --- /dev/null +++ b/node/LockingPtr.hpp @@ -0,0 +1,99 @@ +/* + * 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_LOCKINGPTR_HPP +#define ZT_LOCKINGPTR_HPP + +#include "Mutex.hpp" + +namespace ZeroTier { + +/** + * A simple pointer that locks and holds a mutex until destroyed + * + * Care must be taken when using this. It's not very sophisticated and does + * not handle being copied except for the simple return use case. When it is + * copied it hands off the mutex to the copy and clears it in the original, + * meaning that the mutex is unlocked when the last LockingPtr<> in a chain + * of such handoffs is destroyed. If this chain of handoffs "forks" (more than + * one copy is made) then non-determinism may ensue. + * + * This does not delete or do anything else with the pointer. It also does not + * take care of locking the lock. That must be done beforehand. + */ +template +class LockingPtr +{ +public: + LockingPtr() : + _ptr((T *)0), + _lock((Mutex *)0) + { + } + + LockingPtr(T *obj,Mutex *lock) : + _ptr(obj), + _lock(lock) + { + } + + LockingPtr(const LockingPtr &p) : + _ptr(p._ptr), + _lock(p._lock) + { + const_cast(&p)->_lock = (Mutex *)0; + } + + ~LockingPtr() + { + if (_lock) + _lock->unlock(); + } + + inline LockingPtr &operator=(const LockingPtr &p) + { + _ptr = p._ptr; + _lock = p._lock; + const_cast(&p)->_lock = (Mutex *)0; + return *this; + } + + inline operator bool() const throw() { return (_ptr != (T *)0); } + inline T &operator*() const throw() { return *_ptr; } + inline T *operator->() const throw() { return _ptr; } + + /** + * @return Raw pointer to held object + */ + inline T *ptr() const throw() { return _ptr; } + + inline bool operator==(const LockingPtr &sp) const throw() { return (_ptr == sp._ptr); } + inline bool operator!=(const LockingPtr &sp) const throw() { return (_ptr != sp._ptr); } + inline bool operator>(const LockingPtr &sp) const throw() { return (_ptr > sp._ptr); } + inline bool operator<(const LockingPtr &sp) const throw() { return (_ptr < sp._ptr); } + inline bool operator>=(const LockingPtr &sp) const throw() { return (_ptr >= sp._ptr); } + inline bool operator<=(const LockingPtr &sp) const throw() { return (_ptr <= sp._ptr); } + +private: + T *_ptr; + Mutex *_lock; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Membership.hpp b/node/Membership.hpp index 93d347e7..642d46c6 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -32,9 +32,16 @@ #include "Hashtable.hpp" #include "NetworkConfig.hpp" +// Expiration time for capability and tag cache +#define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 4) + +// Expiration time for Memberships (used in Peer::clean()) +#define ZT_MEMBERSHIP_EXPIRATION_TIME (ZT_MEMBERSHIP_STATE_EXPIRATION_TIME * 4) + namespace ZeroTier { class Peer; +class RuntimeEnvironment; /** * Information related to a peer's participation on a network @@ -81,15 +88,17 @@ public: * This checks last pushed times for our COM and for other credentials and * sends VERB_NETWORK_CREDENTIALS if the recipient might need them. * + * @param RR Runtime environment + * @param now Current time * @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 + * @return True if we pushed something */ - 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; + bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) const; /** * @param nconf Network configuration @@ -113,26 +122,99 @@ public: return ((c) ? (((c->lastReceived != 0)&&(c->cap.expiration() < nconf.timestamp)) ? &(c->cap) : (const Capability *)0) : (const Capability *)0); } + /** + * Validate and add a credential if signature is okay and it's otherwise good + * + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com) + { + if (com.issuedTo() != RR->identity.address()) + return -1; + if (_com == com) + return 0; + const int vr = com.verify(RR); + if (vr == 0) + _com = com; + return vr; + } + + /** + * Validate and add a credential if signature is okay and it's otherwise good + * + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag) + { + if (tag.issuedTo() != RR->identity.address()) + return -1; + TState *t = _tags.get(tag.networkId()); + if ((t)&&(t->lastReceived != 0)&&(t->tag == tag)) + return 0; + const int vr = tag.verify(RR); + if (vr == 0) { + if (!t) + t = &(_tags[tag.networkId()]); + t->lastReceived = now; + t->tag = tag; + } + return vr; + } + + /** + * Validate and add a credential if signature is okay and it's otherwise good + * + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap) + { + if (!cap.wasIssuedTo(RR->identity.address())) + return -1; + CState *c = _caps.get(cap.networkId()); + if ((c)&&(c->lastReceived != 0)&&(c->cap == cap)) + return 0; + const int vr = cap.verify(RR); + if (vr == 0) { + if (!c) + c = &(_caps[cap.networkId()]); + c->lastReceived = now; + c->cap = cap; + } + return vr; + } + /** * Clean up old or stale entries + * + * @return Time of most recent activity in this Membership */ - inline void clean(const uint64_t now) + inline uint64_t clean(const uint64_t now) { + uint64_t lastAct = _lastPushedCom; + 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)) + const uint64_t la = std::max(cs->lastPushed,cs->lastReceived); + if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) _caps.erase(*i); + else if (la > lastAct) + lastAct = la; } 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)) + const uint64_t la = std::max(ts->lastPushed,ts->lastReceived); + if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) _tags.erase(*i); + else if (la > lastAct) + lastAct = la; } + + return lastAct; } private: diff --git a/node/Peer.hpp b/node/Peer.hpp index d8c44ebe..8b50f429 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -40,8 +40,10 @@ #include "SharedPtr.hpp" #include "AtomicCounter.hpp" #include "Hashtable.hpp" +#include "Membership.hpp" #include "Mutex.hpp" #include "NonCopyable.hpp" +#include "LockingPtr.hpp" namespace ZeroTier { @@ -384,6 +386,34 @@ public: return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); } + /** + * Get the membership record for this network, possibly creating if missing + * + * @param networkId Network ID + * @param createIfMissing If true, create a Membership record if there isn't one + * @return Single-scope locking pointer (see LockingPtr.hpp) to Membership or NULL if not found and createIfMissing is false + */ + inline LockingPtr membership(const uint64_t networkId,bool createIfMissing) + { + _memberships_m.lock(); + try { + if (createIfMissing) { + return LockingPtr(&(_memberships[networkId]),&_memberships_m); + } else { + Membership *m = _memberships.get(networkId); + if (m) { + return LockingPtr(m,&_memberships_m); + } else { + _memberships_m.unlock(); + return LockingPtr(); + } + } + } catch ( ... ) { + _memberships_m.unlock(); + throw; + } + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -430,6 +460,9 @@ private: unsigned int _latency; unsigned int _directPathPushCutoffCount; + Hashtable _memberships; + Mutex _memberships_m; + AtomicCounter __refCount; }; diff --git a/node/Tag.cpp b/node/Tag.cpp new file mode 100644 index 00000000..1ad17251 --- /dev/null +++ b/node/Tag.cpp @@ -0,0 +1,45 @@ +/* + * 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 . + */ + +#include "Tag.hpp" +#include "RuntimeEnvironment.hpp" +#include "Identity.hpp" +#include "Topology.hpp" +#include "Switch.hpp" + +namespace ZeroTier { + +int Tag::verify(const RuntimeEnvironment *RR) const +{ + if (!_signedBy) + return -1; + const Identity id(RR->topology->getIdentity(_signedBy)); + if (!id) { + RR->sw->requestWhois(_signedBy); + return 1; + } + try { + Buffer<(sizeof(Tag) * 2)> tmp; + this->serialize(tmp,true); + return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); + } catch ( ... ) { + return -1; + } +} + +} // namespace ZeroTier diff --git a/node/Tag.hpp b/node/Tag.hpp index a4bc4479..dcf2eb20 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -76,7 +76,6 @@ public: { } - inline uint64_t networkId() const { return _nwid; } inline uint64_t expiration() const { return _expiration; } inline uint32_t id() const { return _id; } @@ -106,9 +105,9 @@ public: * Check this tag's signature * * @param RR Runtime environment to allow identity lookup for signedBy - * @return True if signature is present and valid + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag */ - bool verify(const RuntimeEnvironment *RR); + int verify(const RuntimeEnvironment *RR) const; template inline void serialize(Buffer &b,const bool forSign = false) const @@ -156,6 +155,12 @@ public: return (p - startAt); } + // Provides natural sort order by ID + inline bool operator<(const Tag &t) const { return (_id < t._id); } + + inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); } + inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); } + private: uint64_t _nwid; uint64_t _expiration; diff --git a/node/Topology.cpp b/node/Topology.cpp index 725eed31..ef1c1698 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -169,7 +169,9 @@ SharedPtr Topology::getPeer(const Address &zta) Identity Topology::getIdentity(const Address &zta) { - { + if (zta == RR->identity.address()) { + return RR->identity; + } else { Mutex::Lock _l(_lock); const SharedPtr *const ap = _peers.get(zta); if (ap) diff --git a/objects.mk b/objects.mk index da4fda1c..18e330b3 100644 --- a/objects.mk +++ b/objects.mk @@ -1,5 +1,6 @@ OBJS=\ node/C25519.o \ + node/Capability.o \ node/CertificateOfMembership.o \ node/Cluster.o \ node/DeferredPackets.o \ @@ -7,6 +8,7 @@ OBJS=\ node/Identity.o \ node/IncomingPacket.o \ node/InetAddress.o \ + node/Membership.o \ node/Multicaster.o \ node/Network.o \ node/NetworkConfig.o \ @@ -20,6 +22,7 @@ OBJS=\ node/SelfAwareness.o \ node/SHA512.o \ node/Switch.o \ + node/Tag.o \ node/Topology.o \ node/Utils.o \ osdep/BackgroundResolver.o \ -- cgit v1.2.3 From 404a0bbddd90ef2fbd624a0089076aac7e9184b4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 09:51:15 -0700 Subject: ... --- node/Constants.hpp | 11 +--- node/IncomingPacket.cpp | 7 +-- node/Membership.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ node/Membership.hpp | 62 +++++++--------------- node/NetworkConfig.hpp | 18 +++++++ node/Packet.hpp | 9 +--- 6 files changed, 176 insertions(+), 64 deletions(-) create mode 100644 node/Membership.cpp (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index dc36b3a1..489203fe 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -309,13 +309,6 @@ */ #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000 -/** - * How long (max) to remember network certificates of membership? - * - * This only applies to networks we don't belong to. - */ -#define ZT_PEER_NETWORK_COM_EXPIRATION 3600000 - /** * Sanity limit on maximum bridge routes * @@ -330,7 +323,7 @@ /** * If there is no known route, spam to up to this many active bridges */ -#define ZT_MAX_BRIDGE_SPAM 16 +#define ZT_MAX_BRIDGE_SPAM 32 /** * Interval between direct path pushes in milliseconds @@ -357,7 +350,7 @@ #define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 /** - * Enable support for old Dictionary based network configs + * Enable support for older network configurations from older (pre-1.1.6) controllers */ #define ZT_SUPPORT_OLD_STYLE_NETCONF 1 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 6548bda6..c7e6e439 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -709,7 +709,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += com.deserialize(*this,p); LockingPtr m = peer->membership(com.networkId(),true); if (!m) return true; // sanity check - m->addCredential(RR,now,com); + if (m->addCredential(RR,now,com) == 1) return false; // wait for WHOIS } ++p; // skip trailing 0 after COMs if present @@ -719,14 +719,15 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += cap.deserialize(*this,p); LockingPtr m = peer->membership(cap.networkId(),true); if (!m) return true; // sanity check - m->addCredential(RR,now,cap); + if (m->addCredential(RR,now,cap) == 1) return false; // wait for WHOIS } + const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i m = peer->membership(tag.networkId(),true); if (!m) return true; // sanity check - m->addCredential(RR,now,tag); + if (m->addCredential(RR,now,tag) == 1) return false; // wait for WHOIS } } diff --git a/node/Membership.cpp b/node/Membership.cpp new file mode 100644 index 00000000..91cf693a --- /dev/null +++ b/node/Membership.cpp @@ -0,0 +1,133 @@ +/* + * 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 . + */ + +#include "Membership.hpp" +#include "RuntimeEnvironment.hpp" +#include "Peer.hpp" +#include "Topology.hpp" +#include "Switch.hpp" +#include "Packet.hpp" +#include "Node.hpp" + +#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 2) + +namespace ZeroTier { + +bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) +{ + try { + Buffer capsAndTags; + + capsAndTags.addSize(2); + unsigned int appendedCaps = 0; + for(unsigned int i=0;ilastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) { + if ((capsAndTags.size() + sizeof(Capability)) > (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) + break; + const Capability *c = nconf.capability(capIds[i]); + if (c) { + c->serialize(capsAndTags); + ++appendedCaps; + cs->lastPushed = now; + } + } + } + capsAndTags.setAt(0,(uint16_t)appendedCaps); + + const unsigned int tagCountPos = capsAndTags.size(); + capsAndTags.addSize(2); + unsigned int appendedTags = 0; + for(unsigned int i=0;ilastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) { + if ((capsAndTags.size() + sizeof(Tag)) > (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) + break; + const Tag *t = nconf.tag(tagIds[i]); + if (t) { + t->serialize(capsAndTags); + ++appendedTags; + ts->lastPushed = now; + } + } + } + capsAndTags.setAt(tagCountPos,(uint16_t)appendedTags); + + if (((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)||(appendedCaps)||(appendedTags)) { + Packet outp(peer.address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + nconf.com.serialize(outp); + outp.append((uint8_t)0x00); + outp.append(capsAndTags.data(),capsAndTags.size()); + outp.compress(); + RR->sw->send(outp,true,0); + _lastPushedCom = now; + return true; + } + } catch ( ... ) { + TRACE("unable to send credentials due to unexpected exception"); + return false; + } +} + +int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com) +{ + if (com.issuedTo() != RR->identity.address()) + return -1; + if (_com == com) + return 0; + const int vr = com.verify(RR); + if (vr == 0) + _com = com; + return vr; +} + +int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag) +{ + if (tag.issuedTo() != RR->identity.address()) + return -1; + TState *t = _tags.get(tag.networkId()); + if ((t)&&(t->lastReceived != 0)&&(t->tag == tag)) + return 0; + const int vr = tag.verify(RR); + if (vr == 0) { + if (!t) + t = &(_tags[tag.networkId()]); + t->lastReceived = now; + t->tag = tag; + } + return vr; +} + +int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap) +{ + if (!cap.wasIssuedTo(RR->identity.address())) + return -1; + CState *c = _caps.get(cap.networkId()); + if ((c)&&(c->lastReceived != 0)&&(c->cap == cap)) + return 0; + const int vr = cap.verify(RR); + if (vr == 0) { + if (!c) + c = &(_caps[cap.networkId()]); + c->lastReceived = now; + c->cap = cap; + } + return vr; +} + +} // namespace ZeroTier diff --git a/node/Membership.hpp b/node/Membership.hpp index 642d46c6..abfff9e3 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -98,7 +98,21 @@ public: * @param tagCount Number of tag IDs * @return True if we pushed something */ - bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) const; + bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount); + + /** + * Send COM if needed + * + * @param RR Runtime environment + * @param now Current time + * @param peer Peer that "owns" this membership + * @param nconf Network configuration + * @return True if we pushed something + */ + inline bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf) + { + return sendCredentialsIfNeeded(RR,now,peer,nconf,(const uint32_t *)0,0,(const uint32_t *)0,0); + } /** * @param nconf Network configuration @@ -127,61 +141,21 @@ public: * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com) - { - if (com.issuedTo() != RR->identity.address()) - return -1; - if (_com == com) - return 0; - const int vr = com.verify(RR); - if (vr == 0) - _com = com; - return vr; - } + int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag) - { - if (tag.issuedTo() != RR->identity.address()) - return -1; - TState *t = _tags.get(tag.networkId()); - if ((t)&&(t->lastReceived != 0)&&(t->tag == tag)) - return 0; - const int vr = tag.verify(RR); - if (vr == 0) { - if (!t) - t = &(_tags[tag.networkId()]); - t->lastReceived = now; - t->tag = tag; - } - return vr; - } + int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag); /** * Validate and add a credential if signature is okay and it's otherwise good * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap) - { - if (!cap.wasIssuedTo(RR->identity.address())) - return -1; - CState *c = _caps.get(cap.networkId()); - if ((c)&&(c->lastReceived != 0)&&(c->cap == cap)) - return 0; - const int vr = cap.verify(RR); - if (vr == 0) { - if (!c) - c = &(_caps[cap.networkId()]); - c->lastReceived = now; - c->cap = cap; - } - return vr; - } + int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap); /** * Clean up old or stale entries diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 6158c566..7bbedf20 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -318,6 +318,24 @@ public: return false; } + const Capability *capability(const uint32_t id) const + { + for(unsigned int i=0;i * [<[...] additional certificates of membership>] - * <[1] null byte for backward compatibility (see below)> + * <[1] 0x00, null byte marking end of COM array> * <[2] 16-bit number of capabilities> * <[...] one or more serialized Capability> * <[2] 16-bit number of tags> @@ -713,13 +713,6 @@ public: * 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_CREDENTIALS = 0x0a, -- cgit v1.2.3 From 5cf410490e677f524eda5fd5c790e37f81ba7753 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 10:18:33 -0700 Subject: . --- node/CertificateOfMembership.cpp | 3 ++ node/IncomingPacket.cpp | 12 +++---- node/Membership.hpp | 5 +++ node/Network.cpp | 69 +++++++++++++++++++++------------------- node/Topology.hpp | 8 +++++ 5 files changed, 58 insertions(+), 39 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 7b99f2c7..0c36aa45 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -155,6 +155,9 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c unsigned int myidx = 0; unsigned int otheridx = 0; + if ((_qualifierCount == 0)||(other._qualifierCount == 0)) + return false; + while (myidx < _qualifierCount) { // Fail if we're at the end of other, since this means the field is // missing. diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c7e6e439..029570f1 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -446,7 +446,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - LockingPtr m = peer->membership(com.networkId(),true); + LockingPtr m(peer->membership(com.networkId(),true)); if (m) m->addCredential(RR,RR->node->now(),com); } @@ -586,7 +586,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

m = peer->membership(com.networkId(),true); + LockingPtr m(peer->membership(com.networkId(),true)); if (m) m->addCredential(RR,RR->node->now(),com); } @@ -707,7 +707,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p])) { p += com.deserialize(*this,p); - LockingPtr m = peer->membership(com.networkId(),true); + LockingPtr m(peer->membership(com.networkId(),true)); if (!m) return true; // sanity check if (m->addCredential(RR,now,com) == 1) return false; // wait for WHOIS } @@ -717,7 +717,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i m = peer->membership(cap.networkId(),true); + LockingPtr m(peer->membership(cap.networkId(),true)); if (!m) return true; // sanity check if (m->addCredential(RR,now,cap) == 1) return false; // wait for WHOIS } @@ -725,7 +725,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i m = peer->membership(tag.networkId(),true); + LockingPtr m(peer->membership(tag.networkId(),true)); if (!m) return true; // sanity check if (m->addCredential(RR,now,tag) == 1) return false; // wait for WHOIS } @@ -868,7 +868,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - LockingPtr m = peer->membership(com.networkId(),true); + LockingPtr m(peer->membership(com.networkId(),true)); if (m) m->addCredential(RR,RR->node->now(),com); } diff --git a/node/Membership.hpp b/node/Membership.hpp index abfff9e3..0e72b7b1 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -114,6 +114,11 @@ public: return sendCredentialsIfNeeded(RR,now,peer,nconf,(const uint32_t *)0,0,(const uint32_t *)0,0); } + /** + * @return This peer's COM if they have sent one + */ + inline const CertificateOfMembership &com() const { return _com; } + /** * @param nconf Network configuration * @param id Tag ID diff --git a/node/Network.cpp b/node/Network.cpp index 061cca07..d9ad7838 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -29,6 +29,7 @@ #include "Buffer.hpp" #include "NetworkController.hpp" #include "Node.hpp" +#include "Peer.hpp" #include "../version.h" @@ -384,17 +385,20 @@ bool Network::_isAllowed(const SharedPtr &peer) const { // Assumes _lock is locked try { - if (!_config) - return false; - if (_config.isPublic()) - return true; - return ((_config.com)&&(peer->networkMembershipCertificatesAgree(_id,_config.com))); - } catch (std::exception &exc) { - TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer->address().toString().c_str(),exc.what()); + if (_config) { + if (_config.isPublic()) { + return true; + } else { + LockingPtr m(peer->membership(_id,false)); + if (m) { + return _config.com.agreesWith(m->com()); + } + } + } } catch ( ... ) { - TRACE("isAllowed() check failed for peer %s: unexpected exception: unknown exception",peer->address().toString().c_str()); + TRACE("isAllowed() check failed for peer %s: unexpected exception: unexpected exception",peer->address().toString().c_str()); } - return false; // default position on any failure + return false; } class _MulticastAnnounceAll @@ -405,13 +409,13 @@ public: _controller(nw->controller()), _network(nw), _anchors(nw->config().anchors()), - _rootAddresses(renv->topology->rootAddresses()) + _upstreamAddresses(renv->topology->upstreamAddresses()) {} inline void operator()(Topology &t,const SharedPtr &p) { - if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed + if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed, which isn't terrible but is a bit stupid (p->address() == _controller) || - (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) || + (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),p->address()) != _upstreamAddresses.end()) || (std::find(_anchors.begin(),_anchors.end(),p->address()) != _anchors.end()) ) { peers.push_back(p); } @@ -422,7 +426,7 @@ private: const Address _controller; Network *const _network; const std::vector

_anchors; - const std::vector
_rootAddresses; + const std::vector
_upstreamAddresses; }; void Network::_announceMulticastGroups() { @@ -438,31 +442,30 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: { // Assumes _lock is locked - // We push COMs ahead of MULTICAST_LIKE since they're used for access control -- a COM is a public - // credential so "over-sharing" isn't really an issue (and we only do so with roots). - if ((_config)&&(_config.com)&&(!_config.isPublic())&&(peer->needsOurNetworkMembershipCertificate(_id,RR->node->now(),true))) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - _config.com.serialize(outp); - RR->sw->send(outp,true,0); - } - + // Anyone we announce multicast groups to will need our COM to authenticate GATHER requests. { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); + LockingPtr m(peer->membership(_id,false)); + if (m) m->sendCredentialsIfNeeded(RR,RR->node->now(),*peer,_config); + } - for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { - if ((outp.size() + 18) >= ZT_UDP_DEFAULT_PAYLOAD_MTU) { - RR->sw->send(outp,true,0); - outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); - } + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); - // network ID, MAC, ADI - outp.append((uint64_t)_id); - mg->mac().appendTo(outp); - outp.append((uint32_t)mg->adi()); + for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { + if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { + outp.compress(); + RR->sw->send(outp,true,0); + outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } - if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) - RR->sw->send(outp,true,0); + // network ID, MAC, ADI + outp.append((uint64_t)_id); + mg->mac().appendTo(outp); + outp.append((uint32_t)mg->adi()); + } + + if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) { + outp.compress(); + RR->sw->send(outp,true,0); } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 03c491e5..b8213cf8 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -153,6 +153,14 @@ public: return _rootAddresses; } + /** + * @return Vector of active upstream addresses (including roots) + */ + inline std::vector
upstreamAddresses() const + { + return rootAddresses(); + } + /** * @return Current World (copy) */ -- cgit v1.2.3 From 98152d974ada42e659e65590dec9a53d0a28ef54 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 11:40:38 -0700 Subject: More cleanup and removal of DeferredPackets, will do the latter in a more elegant way. --- include/ZeroTierOne.h | 21 ---------- node/Capability.cpp | 4 ++ node/Capability.hpp | 62 +++++++++++++-------------- node/DeferredPackets.cpp | 100 -------------------------------------------- node/DeferredPackets.hpp | 85 ------------------------------------- node/IncomingPacket.cpp | 20 +++------ node/IncomingPacket.hpp | 13 +----- node/Node.cpp | 24 ----------- node/Node.hpp | 9 ---- node/RuntimeEnvironment.hpp | 9 ---- node/Switch.cpp | 8 ++-- objects.mk | 1 - service/OneService.cpp | 4 -- 13 files changed, 45 insertions(+), 315 deletions(-) delete mode 100644 node/DeferredPackets.cpp delete mode 100644 node/DeferredPackets.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 9679cf64..88e83a6e 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1902,27 +1902,6 @@ void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs); */ void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); -/** - * Do things in the background until Node dies - * - * This function can be called from one or more background threads to process - * certain tasks in the background to improve foreground performance. It will - * not return until the Node is shut down. If threading is not enabled in - * this build it will return immediately and will do nothing. - * - * This is completely optional. If this is never called, all processing is - * done in the foreground in the various processXXXX() methods. - * - * This does NOT replace or eliminate the need to call the normal - * processBackgroundTasks() function in your main loop. This mechanism is - * used to offload the processing of expensive mssages onto background - * handler threads to prevent foreground performance degradation under - * high load. - * - * @param node Node instance - */ -void ZT_Node_backgroundThreadMain(ZT_Node *node); - /** * Get ZeroTier One version * diff --git a/node/Capability.cpp b/node/Capability.cpp index ee798a6c..0a736ca8 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -28,9 +28,11 @@ namespace ZeroTier { int Capability::verify(const RuntimeEnvironment *RR) const { try { + // There must be at least one entry, and sanity check for bad chain max length if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) return -1; + // Validate all entries in chain of custody Buffer<(sizeof(Capability) * 2)> tmp; this->serialize(tmp,true); for(unsigned int c=0;c<_maxCustodyChainLength;++c) { @@ -53,6 +55,8 @@ int Capability::verify(const RuntimeEnvironment *RR) const return 1; } } + + // We reached max custody chain length and everything was valid return 0; } catch ( ... ) {} return -1; diff --git a/node/Capability.hpp b/node/Capability.hpp index 48282708..d9b49121 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -114,6 +114,23 @@ public: */ inline uint64_t expiration() const { return _expiration; } + /** + * Check to see if a given address is a 'to' address in the custody chain + * + * This does not actually do certificate checking. That must be done with verify(). + * + * @param a Address to check + * @return True if address is present + */ + inline bool wasIssuedTo(const Address &a) const + { + for(unsigned int i=0;i tmp; this->serialize(tmp,true); + _custody[i].to = to; + _custody[i].from = from.address(); _custody[i].signature = from.sign(tmp.data(),tmp.size()); return true; } @@ -255,22 +272,21 @@ public: b.append(_id); b.append(_nwid); b.append(_expiration); - serializeRules(b,_rules,_ruleCount); - b.append((uint8_t)_maxCustodyChainLength); - for(unsigned int i=0;;++i) { - if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { - _custody[i].to.appendTo(b); - _custody[i].from.appendTo(b); - if (!forSign) { + + if (!forSign) { + for(unsigned int i=0;;++i) { + if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { + _custody[i].to.appendTo(b); + _custody[i].from.appendTo(b); b.append((uint8_t)1); // 1 == Ed25519 signature b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN); + } else { + b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain + break; } - } else { - b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain - break; } } @@ -369,10 +385,9 @@ public: _id = b.template at(p); p += 4; _nwid = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; - deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES); - _maxCustodyChainLength = (unsigned int)b[p++]; + if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) throw std::runtime_error("invalid max custody chain length"); for(unsigned int i;;++i) { @@ -393,25 +408,6 @@ public: return (p - startAt); } - /** - * Check to see if a given address is a 'to' address in the custody chain - * - * This does not actually do certificate checking. That must be done with verify(). - * - * @param a Address to check - * @return True if address is present - */ - inline bool wasIssuedTo(const Address &a) const - { - for(unsigned int i=0;i. - */ - -#include "Constants.hpp" -#include "DeferredPackets.hpp" -#include "IncomingPacket.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" - -namespace ZeroTier { - -DeferredPackets::DeferredPackets(const RuntimeEnvironment *renv) : - RR(renv), - _waiting(0), - _die(false) -{ -} - -DeferredPackets::~DeferredPackets() -{ - _q_m.lock(); - _die = true; - _q_m.unlock(); - - for(;;) { - _q_s.post(); - - _q_m.lock(); - if (_waiting <= 0) { - _q_m.unlock(); - break; - } else { - _q_m.unlock(); - } - } -} - -bool DeferredPackets::enqueue(IncomingPacket *pkt) -{ - { - Mutex::Lock _l(_q_m); - if (_q.size() >= ZT_DEFFEREDPACKETS_MAX) - return false; - _q.push_back(*pkt); - } - _q_s.post(); - return true; -} - -int DeferredPackets::process() -{ - std::list pkt; - - _q_m.lock(); - - if (_die) { - _q_m.unlock(); - return -1; - } - - while (_q.empty()) { - ++_waiting; - _q_m.unlock(); - _q_s.wait(); - _q_m.lock(); - --_waiting; - if (_die) { - _q_m.unlock(); - return -1; - } - } - - // Move item from _q list to a dummy list here to avoid copying packet - pkt.splice(pkt.end(),_q,_q.begin()); - - _q_m.unlock(); - - try { - pkt.front().tryDecode(RR,true); - } catch ( ... ) {} // drop invalids - - return 1; -} - -} // namespace ZeroTier diff --git a/node/DeferredPackets.hpp b/node/DeferredPackets.hpp deleted file mode 100644 index a9855396..00000000 --- a/node/DeferredPackets.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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_DEFERREDPACKETS_HPP -#define ZT_DEFERREDPACKETS_HPP - -#include - -#include "Constants.hpp" -#include "SharedPtr.hpp" -#include "Mutex.hpp" -#include "DeferredPackets.hpp" -#include "BinarySemaphore.hpp" - -/** - * Maximum number of deferred packets - */ -#define ZT_DEFFEREDPACKETS_MAX 256 - -namespace ZeroTier { - -class IncomingPacket; -class RuntimeEnvironment; - -/** - * Deferred packets - * - * IncomingPacket can defer its decoding this way by enqueueing itself here. - * When this is done, deferredDecode() is called later. This is done for - * operations that may be expensive to allow them to potentially be handled - * in the background or rate limited to maintain quality of service for more - * routine operations. - */ -class DeferredPackets -{ -public: - DeferredPackets(const RuntimeEnvironment *renv); - ~DeferredPackets(); - - /** - * Enqueue a packet - * - * @param pkt Packet to process later (possibly in the background) - * @return False if queue is full - */ - bool enqueue(IncomingPacket *pkt); - - /** - * Wait for and then process a deferred packet - * - * If we are shutting down (in destructor), this returns -1 and should - * not be called again. Otherwise it returns the number of packets - * processed. - * - * @return Number processed or -1 if shutting down - */ - int process(); - -private: - std::list _q; - const RuntimeEnvironment *const RR; - volatile int _waiting; - volatile bool _die; - Mutex _q_m; - BinarySemaphore _q_s; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 029570f1..ca609418 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -36,7 +36,6 @@ #include "World.hpp" #include "Cluster.hpp" #include "Node.hpp" -#include "DeferredPackets.hpp" #include "Filter.hpp" #include "CertificateOfMembership.hpp" #include "Capability.hpp" @@ -44,7 +43,7 @@ namespace ZeroTier { -bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred) +bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) { const Address sourceAddress(source()); @@ -64,18 +63,11 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred) return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { - // Unencrypted HELLOs require some potentially expensive verification, so - // do this in the background if background processing is enabled. - if ((RR->dpEnabled > 0)&&(!deferred)) { - RR->dp->enqueue(this); - return true; // 'handled' via deferring to background thread(s) - } else { - // A null pointer for peer to _doHELLO() tells it to run its own - // special internal authentication logic. This is done for unencrypted - // HELLOs to learn new identities, etc. - SharedPtr tmp; - return _doHELLO(RR,tmp); - } + // A null pointer for peer to _doHELLO() tells it to run its own + // special internal authentication logic. This is done for unencrypted + // HELLOs to learn new identities, etc. + SharedPtr tmp; + return _doHELLO(RR,tmp); } SharedPtr peer(RR->topology->getPeer(sourceAddress)); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index bfb30a5e..558dfaa2 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -118,21 +118,12 @@ public: * about whether the packet was valid. A rejection is 'complete.' * * Once true is returned, this must not be called again. The packet's state - * may no longer be valid. The only exception is deferred decoding. In this - * case true is returned to indicate to the normal decode path that it is - * finished with the packet. The packet will have added itself to the - * deferred queue and will expect tryDecode() to be called one more time - * with deferred set to true. - * - * Deferred decoding is performed by DeferredPackets.cpp and should not be - * done elsewhere. Under deferred decoding packets only get one shot and - * so the return value of tryDecode() is ignored. + * may no longer be valid. * * @param RR Runtime environment - * @param deferred If true, this is a deferred decode and the return is ignored * @return True if decoding and processing is complete, false if caller should try again */ - bool tryDecode(const RuntimeEnvironment *RR,bool deferred); + bool tryDecode(const RuntimeEnvironment *RR); /** * @return Time of packet receipt / start of decode diff --git a/node/Node.cpp b/node/Node.cpp index e5d04e31..f04559db 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -37,7 +37,6 @@ #include "Identity.hpp" #include "SelfAwareness.hpp" #include "Cluster.hpp" -#include "DeferredPackets.hpp" const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; @@ -108,9 +107,7 @@ Node::Node( RR->mc = new Multicaster(RR); RR->topology = new Topology(RR); RR->sa = new SelfAwareness(RR); - RR->dp = new DeferredPackets(RR); } catch ( ... ) { - delete RR->dp; delete RR->sa; delete RR->topology; delete RR->mc; @@ -127,8 +124,6 @@ Node::~Node() _networks.clear(); // ensure that networks are destroyed before shutdow - RR->dpEnabled = 0; - delete RR->dp; delete RR->sa; delete RR->topology; delete RR->mc; @@ -621,18 +616,6 @@ void Node::clusterStatus(ZT_ClusterStatus *cs) memset(cs,0,sizeof(ZT_ClusterStatus)); } -void Node::backgroundThreadMain() -{ - ++RR->dpEnabled; - for(;;) { - try { - if (RR->dp->process() < 0) - break; - } catch ( ... ) {} // sanity check -- should not throw - } - --RR->dpEnabled; -} - /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -1009,13 +992,6 @@ void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networ } catch ( ... ) {} } -void ZT_Node_backgroundThreadMain(ZT_Node *node) -{ - try { - reinterpret_cast(node)->backgroundThreadMain(); - } catch ( ... ) {} -} - void ZT_version(int *major,int *minor,int *revision) { if (major) *major = ZEROTIER_ONE_VERSION_MAJOR; diff --git a/node/Node.hpp b/node/Node.hpp index 0a39d1ee..98c4fd7c 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -117,18 +117,9 @@ public: void clusterRemoveMember(unsigned int memberId); void clusterHandleIncomingMessage(const void *msg,unsigned int len); void clusterStatus(ZT_ClusterStatus *cs); - void backgroundThreadMain(); // Internal functions ------------------------------------------------------ - /** - * Convenience threadMain() for easy background thread launch - * - * This allows background threads to be launched with Thread::start - * that will run against this node. - */ - inline void threadMain() throw() { this->backgroundThreadMain(); } - /** * @return Time as of last call to run() */ diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 1f527733..7ba1c989 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -35,7 +35,6 @@ class Multicaster; class NetworkController; class SelfAwareness; class Cluster; -class DeferredPackets; /** * Holds global state for an instance of ZeroTier::Node @@ -51,11 +50,9 @@ public: ,mc((Multicaster *)0) ,topology((Topology *)0) ,sa((SelfAwareness *)0) - ,dp((DeferredPackets *)0) #ifdef ZT_ENABLE_CLUSTER ,cluster((Cluster *)0) #endif - ,dpEnabled(0) { } @@ -82,15 +79,9 @@ public: Multicaster *mc; Topology *topology; SelfAwareness *sa; - DeferredPackets *dp; - #ifdef ZT_ENABLE_CLUSTER Cluster *cluster; #endif - - // This is set to >0 if background threads are waiting on deferred - // packets, otherwise 'dp' should not be used. - volatile int dpEnabled; }; } // namespace ZeroTier diff --git a/node/Switch.cpp b/node/Switch.cpp index 41756aa9..33b08429 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -165,7 +165,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - if (rq->frag0.tryDecode(RR,false)) { + if (rq->frag0.tryDecode(RR)) { rq->timestamp = 0; // packet decoded, free entry } else { rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something @@ -264,7 +264,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from for(unsigned int f=1;ftotalFragments;++f) rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - if (rq->frag0.tryDecode(RR,false)) { + if (rq->frag0.tryDecode(RR)) { rq->timestamp = 0; // packet decoded, free entry } else { rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something @@ -277,7 +277,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } else { // Packet is unfragmented, so just process it IncomingPacket packet(data,len,localAddr,fromAddr,now); - if (!packet.tryDecode(RR,false)) { + if (!packet.tryDecode(RR)) { Mutex::Lock _l(_rxQueue_m); RXQueueEntry *rq = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]); unsigned long i = ZT_RX_QUEUE_SIZE - 1; @@ -705,7 +705,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) while (i) { RXQueueEntry *rq = &(_rxQueue[--i]); if ((rq->timestamp)&&(rq->complete)) { - if (rq->frag0.tryDecode(RR,false)) + if (rq->frag0.tryDecode(RR)) rq->timestamp = 0; } } diff --git a/objects.mk b/objects.mk index 18e330b3..99cf1a72 100644 --- a/objects.mk +++ b/objects.mk @@ -3,7 +3,6 @@ OBJS=\ node/Capability.o \ node/CertificateOfMembership.o \ node/Cluster.o \ - node/DeferredPackets.o \ node/Filter.o \ node/Identity.o \ node/IncomingPacket.o \ diff --git a/service/OneService.cpp b/service/OneService.cpp index 460eb1c9..0c9b0b8e 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -864,10 +864,6 @@ public: } } - // Start two background threads to handle expensive ops out of line - Thread::start(_node); - Thread::start(_node); - _nextBackgroundTaskDeadline = 0; uint64_t clockShouldBe = OSUtils::now(); _lastRestart = clockShouldBe; -- cgit v1.2.3 From 331382cf2f3a3da9c5ec6821f9d63d3f3452202a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 12:14:13 -0700 Subject: More cleanup and a tiny federation prep item. --- node/IncomingPacket.cpp | 15 ++++++++++----- node/Network.cpp | 6 +----- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ca609418..aea110d5 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -465,12 +465,13 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr { try { if (payloadLength() == ZT_ADDRESS_LENGTH) { - Identity queried(RR->topology->getIdentity(Address(payload(),ZT_ADDRESS_LENGTH))); - if (queried) { + const Address addr(payload(),ZT_ADDRESS_LENGTH); + const Identity id(RR->topology->getIdentity(addr)); + if (id) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); outp.append(packetId()); - queried.serialize(outp,false); + id.serialize(outp,false); outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } else { @@ -478,6 +479,10 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr if (RR->cluster) RR->cluster->sendDistributedQuery(*this); #endif + if (!RR->topology->amRoot()) { + RR->sw->requestWhois(addr); + return false; // packet parse will be attempted again if we get a reply from upstream + } } } else { TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str()); @@ -492,7 +497,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - if (RR->topology->isUpstream(peer->identity())) { + if (RR->topology->isUpstream(peer->identity())) { // only upstream peers can tell us to rendezvous, otherwise this opens a potential amplification attack vector const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); const SharedPtr withPeer(RR->topology->getPeer(with)); if (withPeer) { @@ -501,7 +506,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< 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); + const 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()); if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) RR->sw->rendezvous(withPeer,_localAddress,atAddr); diff --git a/node/Network.cpp b/node/Network.cpp index d9ad7838..485a598b 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -50,10 +50,6 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : { char confn[128],mcdbn[128]; Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id); - Utils::snprintf(mcdbn,sizeof(mcdbn),"networks.d/%.16llx.mcerts",_id); - - // These files are no longer used, so clean them. - RR->node->dataStoreDelete(mcdbn); if (_id == ZT_TEST_NETWORK_ID) { applyConfiguration(NetworkConfig::createTestNetworkConfig(RR->identity.address())); @@ -144,7 +140,7 @@ bool Network::tryAnnounceMulticastGroupsTo(const SharedPtr &peer) if ( (_isAllowed(peer)) || (peer->address() == this->controller()) || - (RR->topology->isRoot(peer->identity())) + (RR->topology->isUpstream(peer->identity())) ) { _announceMulticastGroupsTo(peer,_allMulticastGroups()); return true; -- cgit v1.2.3 From 4d9b74b171d243abe2d2d6a0039865ece8a4a00c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 15:27:20 -0700 Subject: . --- include/ZeroTierOne.h | 5 +++++ node/Filter.cpp | 7 +++--- node/IncomingPacket.cpp | 60 ++++--------------------------------------------- 3 files changed, 13 insertions(+), 59 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 88e83a6e..2a70417e 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -164,6 +164,11 @@ extern "C" { */ #define ZT_CLUSTER_MAX_MESSAGE_LENGTH (1500 - 48) +/** + * Packet characteristics flag: packet direction, 1 for incoming 0 for outgoing + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_0_INBOUND 0x0000000000000001ULL + /** * A null/empty sockaddr (all zero) to signify an unspecified socket address */ diff --git a/node/Filter.cpp b/node/Filter.cpp index 286a0144..b8b0bd2a 100644 --- a/node/Filter.cpp +++ b/node/Filter.cpp @@ -239,9 +239,10 @@ bool Filter::run( thisRuleMatches = 0; } break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - // TODO: not supported yet - break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { + uint64_t cf = (receiving) ? ZT_RULE_PACKET_CHARACTERISTICS_0_INBOUND : 0ULL; + thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics[0]) == rules[rn].v.characteristics[1]); + } break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); break; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index aea110d5..c2df7ee2 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -36,7 +36,6 @@ #include "World.hpp" #include "Cluster.hpp" #include "Node.hpp" -#include "Filter.hpp" #include "CertificateOfMembership.hpp" #include "Capability.hpp" #include "Tag.hpp" @@ -541,23 +540,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const MAC sourceMac(peer->address(),network->id()); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (Filter::run( - RR, - network->id(), - peer->address(), - RR->identity.address(), - sourceMac, - network->mac(), - frameData, - frameLen, - etherType, - 0, - network->config().rules, - network->config().ruleCount)) - { + if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) { RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - } else { - TRACE("dropped FRAME from %s(%s): Filter::run() == false (will still log packet as received)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); } } @@ -600,11 +584,6 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - return true; - } - if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); return true; @@ -626,23 +605,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

id(), - peer->address(), - RR->identity.address(), - from, - to, - frameData, - frameLen, - etherType, - 0, - network->config().rules, - network->config().ruleCount)) - { + + if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); - } else { - TRACE("dropped EXT_FRAME from %s(%s): Filter::run() == false (will still log packet as received)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); } } @@ -916,25 +881,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (Filter::run( - RR, - network->id(), - peer->address(), - RR->identity.address(), - from, - to.mac(), - frameData, - frameLen, - etherType, - 0, - network->config().rules, - network->config().ruleCount)) - { + if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0)) { RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); - } else { - TRACE("dropped MULTICAST_FRAME from %s(%s): Filter::run() == false (will still do implicit gather)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id()); - // Note: we continue here since we still do implicit gather in this case... we just do not putFrame() if it - // fails the filter check. } } -- cgit v1.2.3 From 00fd9c3a15f9ac0981cf79c98515df888b3bd109 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 Aug 2016 17:33:26 -0700 Subject: It builds... almost ready to test some rules engine stuff. --- node/Capability.hpp | 35 ++++++++++++++++++------------- node/IncomingPacket.cpp | 55 +++++++++++++++++++++++++------------------------ node/Membership.cpp | 22 +++++++++++--------- node/Membership.hpp | 6 +++--- node/Multicaster.cpp | 15 +------------- node/Multicaster.hpp | 2 -- node/Network.cpp | 2 +- node/Network.hpp | 36 ++++++++++++++++++++++++++++++++ node/Packet.cpp | 5 ++--- node/Packet.hpp | 4 ++-- node/Peer.cpp | 4 +--- node/Switch.cpp | 53 +++++++---------------------------------------- node/Tag.hpp | 8 ++++++- node/Topology.cpp | 28 ------------------------- 14 files changed, 121 insertions(+), 154 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Capability.hpp b/node/Capability.hpp index 53457d4d..42d4ce63 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -71,16 +71,18 @@ public: /** * @param id Capability ID * @param nwid Network ID + * @param ts Timestamp (at controller) * @param expiration Expiration relative to network config timestamp * @param name Capability short name (max strlen == ZT_MAX_CAPABILITY_NAME_LENGTH, overflow ignored) * @param mccl Maximum custody chain length (1 to create non-transferrable capability) * @param rules Network flow rules for this capability * @param ruleCount Number of flow rules */ - Capability(uint32_t id,uint64_t nwid,uint64_t expiration,const char *name,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) + Capability(uint32_t id,uint64_t nwid,uint64_t ts,uint64_t expiration,const char *name,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) { memset(this,0,sizeof(Capability)); _nwid = nwid; + _ts = ts; _expiration = expiration; _id = id; _maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1; @@ -115,20 +117,22 @@ public: inline uint64_t expiration() const { return _expiration; } /** - * Check to see if a given address is a 'to' address in the custody chain - * - * This does not actually do certificate checking. That must be done with verify(). - * - * @param a Address to check - * @return True if address is present + * @return Timestamp + */ + inline uint64_t timestamp() const { return _ts; } + + /** + * @return Last 'to' address in chain of custody */ - inline bool wasIssuedTo(const Address &a) const + inline Address issuedTo() const { + Address i2; for(unsigned int i=0;i(p); p += 4; _nwid = b.template at(p); p += 8; + _ts = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; + _id = b.template at(p); p += 4; deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES); _maxCustodyChainLength = (unsigned int)b[p++]; if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) throw std::runtime_error("invalid max custody chain length"); - for(unsigned int i;;++i) { + for(unsigned int i=0;;++i) { const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (!to) break; @@ -409,6 +415,7 @@ public: private: uint64_t _nwid; + uint64_t _ts; uint64_t _expiration; uint32_t _id; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c2df7ee2..29d0964c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -437,8 +437,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - LockingPtr m(peer->membership(com.networkId(),true)); - if (m) m->addCredential(RR,RR->node->now(),com); + if (com) { + SharedPtr network(RR->node->network(com.networkId())); + if (network) + network->addCredential(com); + } } if ((flags & 0x02) != 0) { @@ -567,8 +570,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

m(peer->membership(com.networkId(),true)); - if (m) m->addCredential(RR,RR->node->now(),com); + if (com) + network->addCredential(com); } if (!network->isAllowed(peer)) { @@ -661,7 +664,6 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const uint64_t now = RR->node->now(); CertificateOfMembership com; Capability cap; Tag tag; @@ -669,9 +671,13 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p])) { p += com.deserialize(*this,p); - LockingPtr m(peer->membership(com.networkId(),true)); - if (!m) return true; // sanity check - if (m->addCredential(RR,now,com) == 1) return false; // wait for WHOIS + if (com) { + SharedPtr network(RR->node->network(com.networkId())); + if (network) { + if (network->addCredential(com) == 1) + return false; // wait for WHOIS + } + } } ++p; // skip trailing 0 after COMs if present @@ -679,17 +685,21 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i m(peer->membership(cap.networkId(),true)); - if (!m) return true; // sanity check - if (m->addCredential(RR,now,cap) == 1) return false; // wait for WHOIS + SharedPtr network(RR->node->network(cap.networkId())); + if (network) { + if (network->addCredential(cap) == 1) + return false; // wait for WHOIS + } } const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i m(peer->membership(tag.networkId(),true)); - if (!m) return true; // sanity check - if (m->addCredential(RR,now,tag) == 1) return false; // wait for WHOIS + SharedPtr network(RR->node->network(tag.networkId())); + if (network) { + if (network->addCredential(tag) == 1) + return false; // wait for WHOIS + } } } @@ -830,8 +840,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - LockingPtr m(peer->membership(com.networkId(),true)); - if (m) m->addCredential(RR,RR->node->now(),com); + if (com) + network->addCredential(com); } // Check membership after we've read any included COM, since @@ -1037,17 +1047,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt NetworkConfig originatorCredentialNetworkConfig; if (originatorCredentialNetworkId) { if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) { - SharedPtr nw(RR->node->network(originatorCredentialNetworkId)); - if ((nw)&&(nw->hasConfig())) { - originatorCredentialNetworkConfig = nw->config(); - if ( ( (originatorCredentialNetworkConfig.isPublic()) || (peer->address() == originatorAddress) || ((originatorCredentialNetworkConfig.com)&&(previousHopCom)&&(originatorCredentialNetworkConfig.com.agreesWith(previousHopCom))) ) ) { - TRACE("CIRCUIT_TEST %.16llx received from hop %s(%s) and originator %s with valid network ID credential %.16llx (verified from originator and next hop)",testId,source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and previous hop %s did not supply a valid COM",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId,peer->address().toString().c_str()); - return true; - } - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + if (!RR->node->network(originatorCredentialNetworkId)) { + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member of that network",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); return true; } } else { diff --git a/node/Membership.cpp b/node/Membership.cpp index 79b1e1bc..e12bce3c 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -79,19 +79,19 @@ bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint return false; } -int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com) +int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com) { if (com.issuedTo() != RR->identity.address()) return -1; if (_com == com) return 0; const int vr = com.verify(RR); - if (vr == 0) + if ((vr == 0)&&(com.revision() > _com.revision())) _com = com; return vr; } -int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag) +int Membership::addCredential(const RuntimeEnvironment *RR,const Tag &tag) { if (tag.issuedTo() != RR->identity.address()) return -1; @@ -102,15 +102,17 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,co if (vr == 0) { if (!t) t = &(_tags[tag.id()]); - t->lastReceived = now; - t->tag = tag; + if (t->tag.timestamp() <= tag.timestamp()) { + t->lastReceived = RR->node->now(); + t->tag = tag; + } } return vr; } -int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap) +int Membership::addCredential(const RuntimeEnvironment *RR,const Capability &cap) { - if (!cap.wasIssuedTo(RR->identity.address())) + if (cap.issuedTo() != RR->identity.address()) return -1; std::map::iterator c(_caps.find(cap.id())); if ((c != _caps.end())&&(c->second.lastReceived != 0)&&(c->second.cap == cap)) @@ -119,10 +121,10 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,co if (vr == 0) { if (c == _caps.end()) { CState &c2 = _caps[cap.id()]; - c2.lastReceived = now; + c2.lastReceived = RR->node->now(); c2.cap = cap; - } else { - c->second.lastReceived = now; + } else if (c->second.cap.timestamp() <= cap.timestamp()) { + c->second.lastReceived = RR->node->now(); c->second.cap = cap; } } diff --git a/node/Membership.hpp b/node/Membership.hpp index 664cd2ad..e9f9d488 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -180,21 +180,21 @@ public: * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com); + int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag); + int addCredential(const RuntimeEnvironment *RR,const Tag &tag); /** * Validate and add a credential if signature is okay and it's otherwise good * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap); + int addCredential(const RuntimeEnvironment *RR,const Capability &cap); /** * Clean up old or stale entries diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index e1d4567a..9e583e34 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -152,7 +152,6 @@ std::vector

Multicaster::getMembers(uint64_t nwid,const MulticastGroup } void Multicaster::send( - const CertificateOfMembership *com, unsigned int limit, uint64_t now, uint64_t nwid, @@ -194,7 +193,6 @@ void Multicaster::send( RR, now, nwid, - com, limit, 1, // we'll still gather a little from peers to keep multicast list fresh src, @@ -236,22 +234,12 @@ void Multicaster::send( if (!p) continue; //TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str()); - - const CertificateOfMembership *com = (CertificateOfMembership *)0; - { - SharedPtr nw(RR->node->network(nwid)); - if ((nw)&&(nw->hasConfig())&&(nw->config().com)&&(nw->config().isPrivate())&&(p->needsOurNetworkMembershipCertificate(nwid,now,true))) - com = &(nw->config().com); - } - Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER); outp.append(nwid); - outp.append((uint8_t)(com ? 0x01 : 0x00)); + outp.append((uint8_t)0x00); mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); outp.append((uint32_t)gatherLimit); - if (com) - com->serialize(outp); RR->sw->send(outp,true,0); } gatherLimit = 0; @@ -264,7 +252,6 @@ void Multicaster::send( RR, now, nwid, - com, limit, gatherLimit, src, diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index c43c8d93..51dabc69 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -150,7 +150,6 @@ public: /** * Send a multicast * - * @param com Certificate of membership to include or NULL for none * @param limit Multicast limit * @param now Current time * @param nwid Network ID @@ -162,7 +161,6 @@ public: * @param len Length of packet data */ void send( - const CertificateOfMembership *com, unsigned int limit, uint64_t now, uint64_t nwid, diff --git a/node/Network.cpp b/node/Network.cpp index a8165d3e..fd2fac2b 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -348,7 +348,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : _netconfFailure(NETCONF_FAILURE_NONE), _portError(0) { - char confn[128],mcdbn[128]; + char confn[128]; Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id); if (_id == ZT_TEST_NETWORK_ID) { diff --git a/node/Network.hpp b/node/Network.hpp index 06fd7735..16f07163 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -336,6 +336,42 @@ public: */ void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now); + /** + * @param com Certificate of membership + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const CertificateOfMembership &com) + { + if (com.networkId() != _id) + return -1; + Mutex::Lock _l(_lock); + return _memberships[com.issuedTo()].addCredential(RR,com); + } + + /** + * @param cap Capability + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const Capability &cap) + { + if (cap.networkId() != _id) + return -1; + Mutex::Lock _l(_lock); + return _memberships[cap.issuedTo()].addCredential(RR,cap); + } + + /** + * @param cap Tag + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const Tag &tag) + { + if (tag.networkId() != _id) + return -1; + Mutex::Lock _l(_lock); + return _memberships[tag.issuedTo()].addCredential(RR,tag); + } + /** * Destroy this network * diff --git a/node/Packet.cpp b/node/Packet.cpp index 4aebf6a9..eda60757 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -22,7 +22,7 @@ namespace ZeroTier { const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -//#ifdef ZT_TRACE +#ifdef ZT_TRACE const char *Packet::verbString(Verb v) throw() @@ -60,14 +60,13 @@ const char *Packet::errorString(ErrorCode e) case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; - case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; } return "(unknown)"; } -//#endif // ZT_TRACE +#endif // ZT_TRACE void Packet::armor(const void *key,bool encryptPayload) { diff --git a/node/Packet.hpp b/node/Packet.hpp index 6789580e..dce9f208 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1060,12 +1060,12 @@ public: ERROR_UNWANTED_MULTICAST = 0x08 }; -//#ifdef ZT_TRACE +#ifdef ZT_TRACE static const char *verbString(Verb v) throw(); static const char *errorString(ErrorCode e) throw(); -//#endif +#endif template Packet(const Buffer &b) : diff --git a/node/Peer.cpp b/node/Peer.cpp index ba47a0be..89dce570 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -53,9 +53,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _id(peerIdentity), _numPaths(0), _latency(0), - _directPathPushCutoffCount(0), - _networkComs(4), - _lastPushedComs(4) + _directPathPushCutoffCount(0) { if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); diff --git a/node/Switch.cpp b/node/Switch.cpp index 33b08429..167c7928 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -35,7 +35,6 @@ #include "Peer.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" -#include "Filter.hpp" #include "Cluster.hpp" namespace ZeroTier { @@ -438,26 +437,12 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len); - if (!Filter::run( - RR, - network->id(), - RR->identity.address(), - Address(), // 0 destination ZT address for multicasts since this is unknown at time of send - from, - to, - (const uint8_t *)data, - len, - etherType, - vlanId, - network->config().rules, - network->config().ruleCount)) - { - TRACE("%.16llx: %s -> %s %s packet not sent: Filter::run() == false (multicast)",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + if (!network->filterOutgoingPacket(RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { + TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } RR->mc->send( - ((!network->config().isPublic())&&(network->config().com)) ? &(network->config().com) : (const CertificateOfMembership *)0, network->config().multicastLimit, RR->node->now(), network->id(), @@ -477,34 +462,15 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this SharedPtr toPeer(RR->topology->getPeer(toZT)); - if (!Filter::run( - RR, - network->id(), - RR->identity.address(), - toZT, - from, - to, - (const uint8_t *)data, - len, - etherType, - vlanId, - network->config().rules, - network->config().ruleCount)) - { - TRACE("%.16llx: %s -> %s %s packet not sent: Filter::run() == false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + if (!network->filterOutgoingPacket(RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { + TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } - const bool includeCom = ( (network->config().isPrivate()) && (network->config().com) && ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ); - if ((fromBridged)||(includeCom)) { + if (fromBridged) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - if (includeCom) { - outp.append((unsigned char)0x01); // 0x01 -- COM included - network->config().com.serialize(outp); - } else { - outp.append((unsigned char)0x00); - } + outp.append((unsigned char)0x00); to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); @@ -564,12 +530,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c SharedPtr bridgePeer(RR->topology->getPeer(bridges[b])); Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - if ( (network->config().isPrivate()) && (network->config().com) && ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ) { - outp.append((unsigned char)0x01); // 0x01 -- COM included - network->config().com.serialize(outp); - } else { - outp.append((unsigned char)0); - } + outp.append((uint8_t)0x00); to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); diff --git a/node/Tag.hpp b/node/Tag.hpp index a9f6f57e..b4bc63c4 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -61,13 +61,15 @@ public: /** * @param nwid Network ID + * @param ts Timestamp * @param expiration Tag expiration relative to network config timestamp * @param issuedTo Address to which this tag was issued * @param id Tag ID * @param value Tag value */ - Tag(const uint64_t nwid,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) : + Tag(const uint64_t nwid,const uint64_t ts,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) : _nwid(nwid), + _ts(ts), _expiration(expiration), _id(id), _value(value), @@ -78,6 +80,7 @@ public: inline uint64_t networkId() const { return _nwid; } inline uint64_t expiration() const { return _expiration; } + inline uint64_t timestamp() const { return _ts; } inline uint32_t id() const { return _id; } inline const uint32_t &value() const { return _value; } inline const Address &issuedTo() const { return _issuedTo; } @@ -115,6 +118,7 @@ public: if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append(_nwid); + b.append(_ts); b.append(_expiration); b.append(_id); b.append(_value); @@ -136,6 +140,7 @@ public: unsigned int p = startAt; _nwid = b.template at(p); p += 8; + _ts = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; _id = b.template at(p); p += 4; _value = b.template at(p); p += 4; @@ -163,6 +168,7 @@ public: private: uint64_t _nwid; + uint64_t _ts; uint64_t _expiration; uint32_t _id; uint32_t _value; diff --git a/node/Topology.cpp b/node/Topology.cpp index ef1c1698..6e0fe90c 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -74,34 +74,6 @@ Topology::Topology(const RuntimeEnvironment *renv) : Topology::~Topology() { - Buffer *pbuf = 0; - try { - pbuf = new Buffer(); - std::string all; - - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - Hashtable< Address,SharedPtr >::Iterator i(_peers); - while (i.next(a,p)) { - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) { - pbuf->clear(); - try { - (*p)->serialize(*pbuf); - try { - all.append((const char *)pbuf->data(),pbuf->size()); - } catch ( ... ) { - return; // out of memory? just skip - } - } catch ( ... ) {} // peer too big? shouldn't happen, but it so skip - } - } - - RR->node->dataStorePut("peers.save",all,true); - - delete pbuf; - } catch ( ... ) { - delete pbuf; - } } SharedPtr Topology::addPeer(const SharedPtr &peer) -- cgit v1.2.3 From 2ba93436077b4f4901db81687df2e03d7ce6c8c5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 08:32:42 -0700 Subject: Encode and decode of tags and capabilities in NetworkConfig. --- node/Capability.hpp | 74 ++++---- node/IncomingPacket.cpp | 2 +- node/Network.cpp | 15 +- node/NetworkConfig.cpp | 436 +++++++++++++++++++-------------------------- node/NetworkConfig.hpp | 36 +++- node/NetworkController.hpp | 2 +- node/Tag.hpp | 7 + 7 files changed, 267 insertions(+), 305 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Capability.hpp b/node/Capability.hpp index 42d4ce63..fd6ae091 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -264,40 +264,6 @@ public: } } - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append(_nwid); - b.append(_ts); - b.append(_expiration); - b.append(_id); - serializeRules(b,_rules,_ruleCount); - b.append((uint8_t)_maxCustodyChainLength); - - if (!forSign) { - for(unsigned int i=0;;++i) { - if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { - _custody[i].to.appendTo(b); - _custody[i].from.appendTo(b); - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature - b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN); - } else { - b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain - break; - } - } - } - - // This is the size of any additional fields. If it is nonzero, - // the last 2 bytes of the next field will be another size field. - b.append((uint16_t)0); - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - template static inline void deserializeRules(const Buffer &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount) { @@ -373,6 +339,41 @@ public: } } + template + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + // These are the same between Tag and Capability + b.append(_nwid); + b.append(_ts); + b.append(_expiration); + b.append(_id); + + serializeRules(b,_rules,_ruleCount); + b.append((uint8_t)_maxCustodyChainLength); + + if (!forSign) { + for(unsigned int i=0;;++i) { + if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { + _custody[i].to.appendTo(b); + _custody[i].from.appendTo(b); + b.append((uint8_t)1); // 1 == Ed25519 signature + b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature + b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN); + } else { + b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain + break; + } + } + } + + // This is the size of any additional fields, currently 0. + b.append((uint16_t)0); + + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + template inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) { @@ -380,15 +381,18 @@ public: unsigned int p = startAt; + // These are the same between Tag and Capability _nwid = b.template at(p); p += 8; _ts = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; _id = b.template at(p); p += 4; + deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES); - _maxCustodyChainLength = (unsigned int)b[p++]; + _maxCustodyChainLength = (unsigned int)b[p++]; if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) throw std::runtime_error("invalid max custody chain length"); + for(unsigned int i=0;;++i) { const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (!to) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 29d0964c..fae689d1 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -717,7 +717,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); - const Dictionary metaData(metaDataBytes,metaDataLength); + const Dictionary metaData(metaDataBytes,metaDataLength); //const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL; diff --git a/node/Network.cpp b/node/Network.cpp index fd2fac2b..0fbdf5ba 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -358,18 +358,21 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : RR->node->dataStorePut(confn,"\n",1,false); } else { bool gotConf = false; + Dictionary *dconf = new Dictionary(); + NetworkConfig *nconf = new NetworkConfig(); try { std::string conf(RR->node->dataStoreGet(confn)); if (conf.length()) { - Dictionary dconf(conf.c_str()); - NetworkConfig nconf; - if (nconf.fromDictionary(dconf)) { - this->setConfiguration(nconf,false); + dconf->load(conf.c_str()); + if (nconf->fromDictionary(*dconf)) { + this->setConfiguration(*nconf,false); _lastConfigUpdate = 0; // we still want to re-request a new config from the network gotConf = true; } } } catch ( ... ) {} // ignore invalids, we'll re-request + delete nconf; + delete dconf; if (!gotConf) { // Save a one-byte CR to persist membership while we request a real netconf @@ -591,14 +594,16 @@ void Network::requestConfiguration() if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config return; - Dictionary rmd; + Dictionary rmd; rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION); 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_NETWORK_CAPABILITIES,(uint64_t)ZT_MAX_NETWORK_CAPABILITIES); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS,(uint64_t)ZT_MAX_NETWORK_TAGS); if (controller() == RR->identity.address()) { if (RR->localNetworkController) { diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index a8ab4dac..07e9bd4f 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -18,6 +18,8 @@ #include +#include + #include "NetworkConfig.hpp" #include "Utils.hpp" @@ -25,204 +27,152 @@ namespace ZeroTier { bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const { - Buffer tmp; + Buffer *tmp = new Buffer(); - d.clear(); + try { + d.clear(); - // Try to put the more human-readable fields first + // Try to put the more human-readable fields first - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false; #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - if (includeLegacy) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD,this->allowPassiveBridging())) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) return false; - - std::string v4s; - for(unsigned int i=0;istaticIps[i].ss_family == AF_INET) { - if (v4s.length() > 0) - v4s.push_back(','); - v4s.append(this->staticIps[i].toString()); + if (includeLegacy) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD,this->allowPassiveBridging())) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) return false; + + std::string v4s; + for(unsigned int i=0;istaticIps[i].ss_family == AF_INET) { + if (v4s.length() > 0) + v4s.push_back(','); + v4s.append(this->staticIps[i].toString()); + } } - } - if (v4s.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) return false; - } - std::string v6s; - for(unsigned int i=0;istaticIps[i].ss_family == AF_INET6) { - if (v6s.length() > 0) - v6s.push_back(','); - v6s.append(this->staticIps[i].toString()); + if (v4s.length() > 0) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) return false; + } + std::string v6s; + for(unsigned int i=0;istaticIps[i].ss_family == AF_INET6) { + if (v6s.length() > 0) + v6s.push_back(','); + v6s.append(this->staticIps[i].toString()); + } + } + if (v6s.length() > 0) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) return false; } - } - if (v6s.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) return false; - } - std::string ets; - unsigned int et = 0; - ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT; - for(unsigned int i=0;i 0) - ets.push_back(','); - char tmp[16]; - Utils::snprintf(tmp,sizeof(tmp),"%x",et); - ets.append(tmp); + std::string ets; + unsigned int et = 0; + ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT; + for(unsigned int i=0;i 0) + ets.push_back(','); + char tmp2[16]; + Utils::snprintf(tmp2,sizeof(tmp2),"%x",et); + ets.append(tmp2); + } + et = 0; } - et = 0; + lastrt = rt; + } + if (ets.length() > 0) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) return false; } - lastrt = rt; - } - if (ets.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) return false; - } - if (this->com) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) return false; - } + if (this->com) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) return false; + } - std::string ab; - for(unsigned int i=0;ispecialistCount;++i) { - if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { - if (ab.length() > 0) - ab.push_back(','); - ab.append(Address(this->specialists[i]).toString().c_str()); + std::string ab; + for(unsigned int i=0;ispecialistCount;++i) { + if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { + if (ab.length() > 0) + ab.push_back(','); + ab.append(Address(this->specialists[i]).toString().c_str()); + } + } + if (ab.length() > 0) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) return false; } } - if (ab.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) return false; - } - } #endif // ZT_SUPPORT_OLD_STYLE_NETCONF - // Then add binary blobs + // Then add binary blobs - if (this->com) { - tmp.clear(); - this->com.serialize(tmp); - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,tmp)) return false; - } + if (this->com) { + tmp->clear(); + this->com.serialize(*tmp); + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false; + } - tmp.clear(); - for(unsigned int i=0;ispecialistCount;++i) { - tmp.append((uint64_t)this->specialists[i]); - } - if (tmp.size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,tmp)) return false; - } + tmp->clear(); + for(unsigned int i=0;icapabilityCount;++i) + this->capabilities[i].serialize(*tmp); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false; + } - tmp.clear(); - for(unsigned int i=0;irouteCount;++i) { - reinterpret_cast(&(this->routes[i].target))->serialize(tmp); - reinterpret_cast(&(this->routes[i].via))->serialize(tmp); - tmp.append((uint16_t)this->routes[i].flags); - tmp.append((uint16_t)this->routes[i].metric); - } - if (tmp.size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,tmp)) return false; - } + tmp->clear(); + for(unsigned int i=0;itagCount;++i) + this->tags[i].serialize(*tmp); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false; + } - tmp.clear(); - for(unsigned int i=0;istaticIpCount;++i) { - this->staticIps[i].serialize(tmp); - } - if (tmp.size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,tmp)) return false; - } + tmp->clear(); + for(unsigned int i=0;ispecialistCount;++i) + tmp->append((uint64_t)this->specialists[i]); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false; + } - tmp.clear(); - for(unsigned int i=0;iruleCount;++i) { - tmp.append((uint8_t)rules[i].t); - switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f)) { - //case ZT_NETWORK_RULE_ACTION_DROP: - //case ZT_NETWORK_RULE_ACTION_ACCEPT: - default: - tmp.append((uint8_t)0); - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - tmp.append((uint8_t)5); - Address(rules[i].v.zt).appendTo(tmp); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - tmp.append((uint8_t)2); - tmp.append((uint16_t)rules[i].v.vlanId); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - tmp.append((uint8_t)1); - tmp.append((uint8_t)rules[i].v.vlanPcp); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - tmp.append((uint8_t)1); - tmp.append((uint8_t)rules[i].v.vlanDei); - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - tmp.append((uint8_t)2); - tmp.append((uint16_t)rules[i].v.etherType); - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - tmp.append((uint8_t)6); - tmp.append(rules[i].v.mac,6); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - tmp.append((uint8_t)5); - tmp.append(&(rules[i].v.ipv4.ip),4); - tmp.append((uint8_t)rules[i].v.ipv4.mask); - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - tmp.append((uint8_t)17); - tmp.append(rules[i].v.ipv6.ip,16); - tmp.append((uint8_t)rules[i].v.ipv6.mask); - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - tmp.append((uint8_t)1); - tmp.append((uint8_t)rules[i].v.ipTos); - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - tmp.append((uint8_t)1); - tmp.append((uint8_t)rules[i].v.ipProtocol); - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - tmp.append((uint8_t)4); - tmp.append((uint16_t)rules[i].v.port[0]); - tmp.append((uint16_t)rules[i].v.port[1]); - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - tmp.append((uint8_t)16); - tmp.append((uint64_t)rules[i].v.characteristics[0]); - tmp.append((uint64_t)rules[i].v.characteristics[1]); - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - tmp.append((uint8_t)4); - tmp.append((uint16_t)rules[i].v.frameSize[0]); - tmp.append((uint16_t)rules[i].v.frameSize[1]); - break; + tmp->clear(); + for(unsigned int i=0;irouteCount;++i) { + reinterpret_cast(&(this->routes[i].target))->serialize(*tmp); + reinterpret_cast(&(this->routes[i].via))->serialize(*tmp); + tmp->append((uint16_t)this->routes[i].flags); + tmp->append((uint16_t)this->routes[i].metric); } - } - if (tmp.size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,tmp)) return false; + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false; + } + + tmp->clear(); + for(unsigned int i=0;istaticIpCount;++i) + this->staticIps[i].serialize(*tmp); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false; + } + + if (this->ruleCount) { + tmp->clear(); + Capability::serializeRules(*tmp,rules,ruleCount); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false; + } + } + + delete tmp; + } catch ( ... ) { + delete tmp; + throw; } return true; @@ -230,26 +180,31 @@ bool NetworkConfig::toDictionary(Dictionary &d,b bool NetworkConfig::fromDictionary(const Dictionary &d) { - try { - Buffer tmp; - char tmp2[ZT_NETWORKCONFIG_DICT_CAPACITY]; + Buffer *tmp = new Buffer(); + try { memset(this,0,sizeof(NetworkConfig)); // Fields that are always present, new or old this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0); - if (!this->networkId) + if (!this->networkId) { + delete tmp; return false; + } this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0); this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0); this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0); - if (!this->issuedTo) + if (!this->issuedTo) { + delete tmp; return false; + } this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF + char tmp2[1024]; + // Decode legacy fields if version is old if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD)) this->flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; @@ -305,6 +260,7 @@ bool NetworkConfig::fromDictionary(const Dictionaryflags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0); this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE); - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,tmp)) { - this->com.deserialize(tmp,0); + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) + this->com.deserialize(*tmp,0); + + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) { + try { + unsigned int p = 0; + while (p < tmp->size()) { + Capability cap; + p += cap.deserialize(*tmp,p); + this->capabilities[this->capabilityCount++] = cap; + } + } catch ( ... ) {} + std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount])); + } + + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) { + try { + unsigned int p = 0; + while (p < tmp->size()) { + Tag tag; + p += tag.deserialize(*tmp,p); + this->tags[this->tagCount++] = tag; + } + } catch ( ... ) {} + std::sort(&(this->tags[0]),&(this->tags[this->tagCount])); } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,tmp)) { + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { unsigned int p = 0; - while (((p + 8) <= tmp.size())&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) { - this->specialists[this->specialistCount++] = tmp.at(p); + while (((p + 8) <= tmp->size())&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) { + this->specialists[this->specialistCount++] = tmp->at(p); p += 8; } } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,tmp)) { + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) { unsigned int p = 0; - while ((p < tmp.size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { - p += reinterpret_cast(&(this->routes[this->routeCount].target))->deserialize(tmp,p); - p += reinterpret_cast(&(this->routes[this->routeCount].via))->deserialize(tmp,p); - this->routes[this->routeCount].flags = tmp.at(p); p += 2; - this->routes[this->routeCount].metric = tmp.at(p); p += 2; + while ((p < tmp->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { + p += reinterpret_cast(&(this->routes[this->routeCount].target))->deserialize(*tmp,p); + p += reinterpret_cast(&(this->routes[this->routeCount].via))->deserialize(*tmp,p); + this->routes[this->routeCount].flags = tmp->at(p); p += 2; + this->routes[this->routeCount].metric = tmp->at(p); p += 2; ++this->routeCount; } } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,tmp)) { + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) { unsigned int p = 0; - while ((p < tmp.size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - p += this->staticIps[this->staticIpCount++].deserialize(tmp,p); + while ((p < tmp->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + p += this->staticIps[this->staticIpCount++].deserialize(*tmp,p); } } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,tmp)) { + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) { + this->ruleCount = 0; unsigned int p = 0; - while ((p < tmp.size())&&(ruleCount < ZT_MAX_NETWORK_RULES)) { - rules[ruleCount].t = (uint8_t)tmp[p++]; - unsigned int fieldLen = (unsigned int)tmp[p++]; - switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x7f)) { - default: - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - rules[ruleCount].v.zt = Address(tmp.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - rules[ruleCount].v.vlanId = tmp.at(p); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - rules[ruleCount].v.vlanPcp = (uint8_t)tmp[p]; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - rules[ruleCount].v.vlanDei = (uint8_t)tmp[p]; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - rules[ruleCount].v.etherType = tmp.at(p); - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - memcpy(rules[ruleCount].v.mac,tmp.field(p,6),6); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - memcpy(&(rules[ruleCount].v.ipv4.ip),tmp.field(p,4),4); - rules[ruleCount].v.ipv4.mask = (uint8_t)tmp[p + 4]; - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - memcpy(rules[ruleCount].v.ipv6.ip,tmp.field(p,16),16); - rules[ruleCount].v.ipv6.mask = (uint8_t)tmp[p + 16]; - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - rules[ruleCount].v.ipTos = (uint8_t)tmp[p]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - rules[ruleCount].v.ipProtocol = (uint8_t)tmp[p]; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - rules[ruleCount].v.port[0] = tmp.at(p); - rules[ruleCount].v.port[1] = tmp.at(p + 2); - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - rules[ruleCount].v.characteristics[0] = tmp.at(p); - rules[ruleCount].v.characteristics[1] = tmp.at(p + 8); - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - rules[ruleCount].v.frameSize[0] = tmp.at(p); - rules[ruleCount].v.frameSize[0] = tmp.at(p + 2); - break; - } - p += fieldLen; - ++ruleCount; - } + Capability::deserializeRules(*tmp,p,this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES); } } @@ -412,8 +332,10 @@ bool NetworkConfig::fromDictionary(const Dictionary &metaData, + const Dictionary &metaData, NetworkConfig &nc) = 0; }; diff --git a/node/Tag.hpp b/node/Tag.hpp index b4bc63c4..bb019474 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -117,11 +117,14 @@ public: { if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + // These are the same between Tag and Capability b.append(_nwid); b.append(_ts); b.append(_expiration); b.append(_id); + b.append(_value); + _issuedTo.appendTo(b); _signedBy.appendTo(b); if (!forSign) { @@ -129,6 +132,7 @@ public: b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); } + b.append((uint16_t)0); // length of additional fields, currently 0 if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); @@ -139,11 +143,14 @@ public: { unsigned int p = startAt; + // These are the same between Tag and Capability _nwid = b.template at(p); p += 8; _ts = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; _id = b.template at(p); p += 4; + _value = b.template at(p); p += 4; + _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (b[p++] != 1) -- cgit v1.2.3 From bcd05fbdfa7e340ef4df962773bb7c32cf5013c2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 09:34:13 -0700 Subject: Chunking of network config replies. --- node/Dictionary.hpp | 34 ++++++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 48 +++++++++++++++++++++++++++++------------------- node/NetworkConfig.hpp | 2 ++ node/Packet.hpp | 14 +++++--------- 4 files changed, 70 insertions(+), 28 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 59fc4bbf..5d453fd9 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -23,6 +23,7 @@ #include "Utils.hpp" #include "Buffer.hpp" #include "Address.hpp" +#include "C25519.hpp" #include @@ -443,6 +444,39 @@ public: return found; } + /** + * Sign this Dictionary, replacing any previous signature + * + * @param sigKey Key to use for signature in dictionary + * @param kp Key pair to sign with + */ + inline void wrapWithSignature(const char *sigKey,const C25519::Pair &kp) + { + this->erase(sigKey); + C25519::Signature sig(C25519::sign(kp,this->data(),this->sizeBytes())); + this->add(sigKey,sig.data,ZT_C25519_SIGNATURE_LEN); + } + + /** + * Verify signature (and erase signature key) + * + * This erases this Dictionary's signature key (if present) and verifies + * the signature. The key is erased to render the Dictionary into the + * original unsigned form it was signed in for verification purposes. + * + * @param sigKey Key to use for signature in dictionary + * @param pk Public key to check against + * @return True if signature was present and valid + */ + inline bool unwrapAndVerify(const char *sigKey,const C25519::Public &pk) + { + char sig[ZT_C25519_SIGNATURE_LEN+1]; + if (this->get(sigKey,sig,sizeof(sig)) != ZT_C25519_SIGNATURE_LEN) + return false; + this->erase(sigKey); + return C25519::verify(pk,this->data(),this->sizeBytes(),sig); + } + /** * @return Dictionary data as a 0-terminated C-string */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index fae689d1..147f54da 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -719,35 +719,46 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); const Dictionary metaData(metaDataBytes,metaDataLength); - //const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL; - const unsigned int h = hops(); - const uint64_t pid = packetId(); - peer->received(_localAddress,_remoteAddress,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); + const uint64_t requestPacketId = packetId(); + peer->received(_localAddress,_remoteAddress,h,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); if (RR->localNetworkController) { NetworkConfig netconf; switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,netconf)) { case NetworkController::NETCONF_QUERY_OK: { - Dictionary dconf; - if (netconf.toDictionary(dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(pid); - outp.append(nwid); - const unsigned int dlen = dconf.sizeBytes(); - outp.append((uint16_t)dlen); - outp.append((const void *)dconf.data(),dlen); - outp.compress(); - RR->sw->send(outp,true,0); + Dictionary *dconf = new Dictionary(); + try { + if (netconf.toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { + const unsigned int totalSize = dconf->sizeBytes(); + unsigned int chunkPtr = 0; + while (chunkPtr < totalSize) { + const unsigned int chunkLen = std::min(totalSize - chunkPtr,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PROTO_MIN_PACKET_LENGTH + 32))); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + outp.append(nwid); + outp.append((uint16_t)chunkLen); + outp.append((const void *)(dconf->data() + chunkPtr),chunkLen); + outp.append((uint32_t)totalSize); + outp.append((uint32_t)chunkPtr); + outp.compress(); + RR->sw->send(outp,true,0); + chunkPtr += chunkLen; + } + } + delete dconf; + } catch ( ... ) { + delete dconf; + throw; } } break; case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(pid); + outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(nwid); outp.armor(peer->key(),true); @@ -757,7 +768,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(pid); + outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); outp.append(nwid); outp.armor(peer->key(),true); @@ -765,7 +776,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons } break; case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: - // TRACE("NETWORK_CONFIG_REQUEST failed: internal error: %s",netconf.get("error","(unknown)").c_str()); break; case NetworkController::NETCONF_QUERY_IGNORE: @@ -779,7 +789,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(pid); + outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); outp.armor(peer->key(),true); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 907da936..3682c466 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -135,6 +135,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES "CAP" // tags (binary blobs) #define ZT_NETWORKCONFIG_DICT_KEY_TAGS "TAG" +// curve25519 signature +#define ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE "C25519" // Legacy fields -- these are obsoleted but are included when older clients query diff --git a/node/Packet.hpp b/node/Packet.hpp index dce9f208..9d4c8289 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -724,7 +724,7 @@ public: * <[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>] + * <[8] 64-bit timestamp of netconf we currently have> * * This message requests network configuration from a node capable of * providing it. If the optional revision is included, a response is @@ -732,14 +732,10 @@ public: * * OK response payload: * <[8] 64-bit network ID> - * <[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. + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk in this reply> * * ERROR response payload: * <[8] 64-bit network ID> -- cgit v1.2.3 From 4d498b3765695f1b82a2448f0e8efe698b33667d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 13:14:38 -0700 Subject: Handling of multi-part chunked network configs on the inbound side. --- node/Identity.hpp | 5 +++++ node/IncomingPacket.cpp | 16 ++++++++-------- node/Network.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++++- node/Network.hpp | 18 ++++++++++++++++++ node/NetworkConfig.cpp | 12 +++++++++++- node/NetworkConfig.hpp | 6 ++++-- 6 files changed, 93 insertions(+), 12 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Identity.hpp b/node/Identity.hpp index 4aa93b87..ef7f2d77 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -282,6 +282,11 @@ public: bool fromString(const char *str); inline bool fromString(const std::string &str) { return fromString(str.c_str()); } + /** + * @return C25519 public key + */ + inline const C25519::Public &publicKey() const { return _publicKey; } + /** * @return True if this identity contains something */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 147f54da..e25cb058 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -402,15 +402,15 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_NETWORK_CONFIG_REQUEST: { const SharedPtr nw(RR->node->network(at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID))); if ((nw)&&(nw->controller() == peer->address())) { - const unsigned int nclen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); - if (nclen) { - Dictionary dconf((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,nclen),nclen); - NetworkConfig nconf; - if (nconf.fromDictionary(dconf)) { - nw->setConfiguration(nconf,true); - TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str()); - } + const unsigned int chunkLen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); + const void *chunkData = field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,chunkLen); + unsigned int chunkIndex = 0; + unsigned int totalSize = chunkLen; + if ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen) < size()) { + totalSize = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen); + chunkIndex = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4); } + nw->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize); } } break; diff --git a/node/Network.cpp b/node/Network.cpp index 0fbdf5ba..b84756aa 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -343,6 +343,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : _id(nwid), _mac(renv->identity.address(),nwid), _portInitialized(false), + _inboundConfigPacketId(0), _lastConfigUpdate(0), _destroyed(false), _netconfFailure(NETCONF_FAILURE_NONE), @@ -364,7 +365,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : std::string conf(RR->node->dataStoreGet(confn)); if (conf.length()) { dconf->load(conf.c_str()); - if (nconf->fromDictionary(*dconf)) { + if (nconf->fromDictionary(Identity(),*dconf)) { this->setConfiguration(*nconf,false); _lastConfigUpdate = 0; // we still want to re-request a new config from the network gotConf = true; @@ -589,6 +590,47 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) return 0; } +void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize) +{ + std::string newConfig; + if ((_inboundConfigPacketId == inRePacketId)&&(totalSize < ZT_NETWORKCONFIG_DICT_CAPACITY)&&((chunkIndex + chunkSize) < totalSize)) { + Mutex::Lock _l(_lock); + TRACE("got %u bytes at position %u of network config request %.16llx, total expected length %u",chunkSize,chunkIndex,inRePacketId,totalSize); + _inboundConfigChunks[chunkIndex].append((const char *)data,chunkSize); + unsigned int totalWeHave = 0; + for(std::map::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c) + totalWeHave += (unsigned int)c->second.length(); + if (totalWeHave == totalSize) { + TRACE("have all chunks for network config request %.16llx, assembling...",inRePacketId); + for(std::map::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c) + newConfig.append(c->second); + _inboundConfigPacketId = 0; + _inboundConfigChunks.clear(); + } else if (totalWeHave > totalSize) { + _inboundConfigPacketId = 0; + _inboundConfigChunks.clear(); + } + } + + if (newConfig.length() > 0) { + if (newConfig.length() < ZT_NETWORKCONFIG_DICT_CAPACITY) { + Dictionary *dict = new Dictionary(newConfig.c_str()); + try { + Identity controllerId(RR->topology->getIdentity(this->controller())); + if (controllerId) { + NetworkConfig nc; + if (nc.fromDictionary(controllerId,*dict)) + this->setConfiguration(nc,true); + } + delete dict; + } catch ( ... ) { + delete dict; + throw; + } + } + } +} + void Network::requestConfiguration() { if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config @@ -637,6 +679,10 @@ void Network::requestConfiguration() outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0); outp.compress(); RR->sw->send(outp,true,0); + + // Expect replies with this in-re packet ID + _inboundConfigPacketId = outp.packetId(); + _inboundConfigChunks.clear(); } void Network::clean() diff --git a/node/Network.hpp b/node/Network.hpp index 16f07163..d13918cf 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -214,6 +214,21 @@ public: */ int setConfiguration(const NetworkConfig &nconf,bool saveToDisk); + /** + * Handle an inbound network config chunk + * + * Only chunks whose inRePacketId matches the packet ID of the last request + * are handled. If this chunk completes the config, it is decoded and + * setConfiguration() is called. + * + * @param inRePacketId In-re packet ID from OK(NETWORK_CONFIG_REQUEST) + * @param data Chunk data + * @param chunkSize Size of data[] + * @param chunkIndex Index of chunk in full config + * @param totalSize Total size of network config + */ + void handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize); + /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this */ @@ -411,6 +426,9 @@ private: Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) + uint64_t _inboundConfigPacketId; + std::map _inboundConfigChunks; + NetworkConfig _config; volatile uint64_t _lastConfigUpdate; diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 07e9bd4f..a4fddf40 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -178,8 +178,18 @@ bool NetworkConfig::toDictionary(Dictionary &d,b return true; } -bool NetworkConfig::fromDictionary(const Dictionary &d) +bool NetworkConfig::fromDictionary(const Identity &controllerId,Dictionary &d) { + if ((d.contains(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE))&&(controllerId)) { + // FIXME: right now signature are optional since network configs are only + // accepted directly from the controller and the protocol already guarantees + // the sender. In the future these might be made non-optional once old + // controllers that do not sign are gone and if we ever support peer caching + // of network configs. + if (!d.unwrapAndVerify(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE,controllerId.publicKey())) + return false; + } + Buffer *tmp = new Buffer(); try { diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 3682c466..18244ec9 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -38,6 +38,7 @@ #include "Capability.hpp" #include "Tag.hpp" #include "Dictionary.hpp" +#include "Identity.hpp" /** * Flag: allow passive bridging (experimental) @@ -239,10 +240,11 @@ public: /** * Read this network config from a dictionary * - * @param d Dictionary + * @param controllerId Controller identity for verification of any signature or NULL identity to skip + * @param d Dictionary (non-const since it might be modified during parse, should not be used after call) * @return True if dictionary was valid and network config successfully initialized */ - bool fromDictionary(const Dictionary &d); + bool fromDictionary(const Identity &controllerId,Dictionary &d); /** * @return True if passive bridging is allowed (experimental) -- cgit v1.2.3 From 774c7e0ea57784fb39e9194246ca0b927637f8ba Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 13:52:08 -0700 Subject: Put CONFIG_REFRESH back. --- node/IncomingPacket.cpp | 136 ++++++++++++++++++++++++++++-------------------- node/IncomingPacket.hpp | 1 + 2 files changed, 80 insertions(+), 57 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e25cb058..41a9aeea 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -102,6 +102,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(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_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); @@ -724,67 +725,70 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons peer->received(_localAddress,_remoteAddress,h,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); if (RR->localNetworkController) { - NetworkConfig netconf; - switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,netconf)) { - - case NetworkController::NETCONF_QUERY_OK: { - Dictionary *dconf = new Dictionary(); - try { - if (netconf.toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { - const unsigned int totalSize = dconf->sizeBytes(); - unsigned int chunkPtr = 0; - while (chunkPtr < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkPtr,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PROTO_MIN_PACKET_LENGTH + 32))); - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append(nwid); - outp.append((uint16_t)chunkLen); - outp.append((const void *)(dconf->data() + chunkPtr),chunkLen); - outp.append((uint32_t)totalSize); - outp.append((uint32_t)chunkPtr); - outp.compress(); - RR->sw->send(outp,true,0); - chunkPtr += chunkLen; + NetworkConfig *netconf = new NetworkConfig(); + try { + switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,*netconf)) { + + case NetworkController::NETCONF_QUERY_OK: { + Dictionary *dconf = new Dictionary(); + try { + if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { + const unsigned int totalSize = dconf->sizeBytes(); + unsigned int chunkIndex = 0; + while (chunkIndex < totalSize) { + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PROTO_MIN_PACKET_LENGTH + 32))); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + outp.append(nwid); + outp.append((uint16_t)chunkLen); + outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); + outp.append((uint32_t)totalSize); + outp.append((uint32_t)chunkIndex); + outp.compress(); + RR->sw->send(outp,true,0); + chunkIndex += chunkLen; + } } + delete dconf; + } catch ( ... ) { + delete dconf; + throw; } - delete dconf; - } catch ( ... ) { - delete dconf; - throw; - } - } break; - - case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); - outp.append(nwid); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - } break; - - case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); - outp.append(nwid); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - } break; - - case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: - break; - - case NetworkController::NETCONF_QUERY_IGNORE: - break; + } break; - default: - TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()"); - break; + case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); + outp.append(nwid); + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } break; + case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); + outp.append(nwid); + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } break; + + case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: + break; + case NetworkController::NETCONF_QUERY_IGNORE: + break; + default: + TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()"); + break; + } + delete netconf; + } catch ( ... ) { + delete netconf; + throw; } } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); @@ -801,6 +805,24 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons return true; } +bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer) +{ + try { + unsigned int p = ZT_PACKET_IDX_PAYLOAD; + while ((p + 8) <= size()) { + const uint64_t nwid = at(p); p += 8; + if (Network::controllerFor(nwid) == peer->address()) { + SharedPtr network(RR->node->network(nwid)); + if (network) + network->requestConfiguration(); + } + } + } catch ( ... ) { + TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + } + return true; +} + bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 558dfaa2..303ac5f8 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -165,6 +165,7 @@ private: bool _doMULTICAST_LIKE(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 _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); -- cgit v1.2.3 From dee7f75f7e0ed33997299fdbab0de4b63a9a69d6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 14:46:11 -0700 Subject: Minor cleanup. --- node/IncomingPacket.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 41a9aeea..b6ec2d3f 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -150,7 +150,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_IDENTITY_COLLISION: - if (RR->topology->isUpstream(peer->identity())) + if (RR->topology->isRoot(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; @@ -421,7 +421,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),size()); + //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } break; @@ -720,14 +720,14 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); const Dictionary metaData(metaDataBytes,metaDataLength); - const unsigned int h = hops(); + const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - peer->received(_localAddress,_remoteAddress,h,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); if (RR->localNetworkController) { NetworkConfig *netconf = new NetworkConfig(); try { - switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,*netconf)) { + switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,*netconf)) { case NetworkController::NETCONF_QUERY_OK: { Dictionary *dconf = new Dictionary(); @@ -736,7 +736,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const unsigned int totalSize = dconf->sizeBytes(); unsigned int chunkIndex = 0; while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PROTO_MIN_PACKET_LENGTH + 32))); + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 32))); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append(requestPacketId); -- cgit v1.2.3 From e1310a764a39d0ed1f29f213c6e75c4e2d7a8aba Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 15:45:26 -0700 Subject: More cleanup and removal of cruft due to obsolete network-specific relays (will be replaced with federation stuff). --- node/IncomingPacket.cpp | 16 ++++++---- node/Membership.cpp | 2 +- node/Multicaster.cpp | 2 +- node/Network.cpp | 8 ++--- node/Node.cpp | 4 +-- node/OutboundMulticast.cpp | 2 +- node/Peer.cpp | 8 ++--- node/Peer.hpp | 3 +- node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 76 ++++++---------------------------------------- node/Switch.hpp | 42 ++----------------------- 11 files changed, 37 insertions(+), 128 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b6ec2d3f..df224c19 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -510,9 +510,13 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); const 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()); - if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) - RR->sw->rendezvous(withPeer,_localAddress,atAddr); + TRACE("RENDEZVOUS from %s says %s might be at %s, attempting to contact",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { + const uint64_t now = RR->node->now(); + peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) + if (!peer->pushDirectPaths(_localAddress,atAddr,now,true)) + peer->sendHELLO(_localAddress,atAddr,now); + } } else { TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -746,7 +750,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((uint32_t)totalSize); outp.append((uint32_t)chunkIndex); outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); chunkIndex += chunkLen; } } @@ -1139,7 +1143,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt nextHop[h].appendTo(outp); nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress } - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } // If there are next hops, forward the test along through the graph @@ -1154,7 +1158,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid outp.newInitializationVector(); outp.setDestination(nextHop[h]); - RR->sw->send(outp,true,originatorCredentialNetworkId); + RR->sw->send(outp,true); } } } diff --git a/node/Membership.cpp b/node/Membership.cpp index e12bce3c..dbba7f0d 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -69,7 +69,7 @@ bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint outp.append((uint8_t)0x00); outp.append(capsAndTags.data(),capsAndTags.size()); outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); _lastPushedCom = now; return true; } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 9e583e34..aeee0a85 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -240,7 +240,7 @@ void Multicaster::send( mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); outp.append((uint32_t)gatherLimit); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } gatherLimit = 0; } diff --git a/node/Network.cpp b/node/Network.cpp index b84756aa..e098c1fd 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -127,7 +127,7 @@ static int _doZtFilter( outp.append((uint16_t)etherType); outp.append(frameData,frameLen); outp.compress(); - RR->sw->send(outp,true,nwid); + RR->sw->send(outp,true); if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { return -1; // match, drop packet (we redirected it) @@ -678,7 +678,7 @@ void Network::requestConfiguration() outp.append((const void *)rmd.data(),rmdSize); outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0); outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); // Expect replies with this in-re packet ID _inboundConfigPacketId = outp.packetId(); @@ -894,7 +894,7 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } @@ -906,7 +906,7 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } } diff --git a/node/Node.cpp b/node/Node.cpp index f04559db..4da79347 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -237,7 +237,7 @@ public: // way whatsoever. This will e.g. find network preferred relays that lack // stable endpoints by using root servers. Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); @@ -520,7 +520,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[0].breadth;++a) { outp.newInitializationVector(); outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index a5856164..c9952927 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -90,7 +90,7 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr); - RR->sw->send(_packet,true,_nwid); + RR->sw->send(_packet,true); } } diff --git a/node/Peer.cpp b/node/Peer.cpp index 89dce570..77e1d0b5 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -241,7 +241,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) return false; } -bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force,bool includePrivatePaths) +bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force) { #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection @@ -258,10 +258,8 @@ bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAdd std::vector pathsToPush; std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) { - if ((includePrivatePaths)||(i->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) - pathsToPush.push_back(*i); - } + for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) + pathsToPush.push_back(*i); std::vector sym(RR->sa->getSymmetricNatPredictions()); for(unsigned long i=0,added=0;i >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->activelyTransferringFrames(now)) { Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } } } else { diff --git a/node/Switch.cpp b/node/Switch.cpp index 167c7928..37daff27 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -476,14 +476,14 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append((uint16_t)etherType); outp.append(data,len); outp.compress(); - send(outp,true,network->id()); + send(outp,true); } else { Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); outp.append((uint16_t)etherType); outp.append(data,len); outp.compress(); - send(outp,true,network->id()); + send(outp,true); } //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); @@ -536,23 +536,21 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append((uint16_t)etherType); outp.append(data,len); outp.compress(); - send(outp,true,network->id()); + send(outp,true); } } } -void Switch::send(const Packet &packet,bool encrypt,uint64_t nwid) +void Switch::send(const Packet &packet,bool encrypt) { if (packet.destination() == RR->identity.address()) { TRACE("BUG: caught attempt to send() to self, ignored"); return; } - //TRACE(">> %s to %s (%u bytes, encrypt==%d, nwid==%.16llx)",Packet::verbString(packet.verb()),packet.destination().toString().c_str(),packet.size(),(int)encrypt,nwid); - - if (!_trySend(packet,encrypt,nwid)) { + if (!_trySend(packet,encrypt)) { Mutex::Lock _l(_txQueue_m); - _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt,nwid)); + _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); } } @@ -625,17 +623,6 @@ bool Switch::unite(const Address &p1,const Address &p2) return true; } -void Switch::rendezvous(const SharedPtr &peer,const InetAddress &localAddr,const InetAddress &atAddr) -{ - TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); - const uint64_t now = RR->node->now(); - peer->sendHELLO(localAddr,atAddr,now,2); // first attempt: send low-TTL packet to 'open' local NAT - { - Mutex::Lock _l(_contactQueue_m); - _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,localAddr,atAddr)); - } -} - void Switch::requestWhois(const Address &addr) { bool inserted = false; @@ -676,7 +663,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(txi->packet,txi->encrypt,txi->nwid)) + if (_trySend(txi->packet,txi->encrypt)) _txQueue.erase(txi++); else ++txi; } else ++txi; @@ -688,42 +675,6 @@ unsigned long Switch::doTimerTasks(uint64_t now) { unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - { // Iterate through NAT traversal strategies for entries in contact queue - Mutex::Lock _l(_contactQueue_m); - for(std::list::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { - if (now >= qi->fireAtTime) { - if (!qi->peer->pushDirectPaths(qi->localAddr,qi->inaddr,now,true,false)) - qi->peer->sendHELLO(qi->localAddr,qi->inaddr,now); - _contactQueue.erase(qi++); - continue; - /* Old symmetric NAT buster code, obsoleted by port prediction alg in SelfAwareness but left around for now in case we revert - if (qi->strategyIteration == 0) { - // First strategy: send packet directly to destination - qi->peer->sendHELLO(qi->localAddr,qi->inaddr,now); - } else if (qi->strategyIteration <= 3) { - // Strategies 1-3: try escalating ports for symmetric NATs that remap sequentially - InetAddress tmpaddr(qi->inaddr); - int p = (int)qi->inaddr.port() + qi->strategyIteration; - if (p > 65535) - p -= 64511; - tmpaddr.setPort((unsigned int)p); - qi->peer->sendHELLO(qi->localAddr,tmpaddr,now); - } else { - // All strategies tried, expire entry - _contactQueue.erase(qi++); - continue; - } - ++qi->strategyIteration; - qi->fireAtTime = now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY; - nextDelay = std::min(nextDelay,(unsigned long)ZT_NAT_T_TACTICAL_ESCALATION_DELAY); - */ - } else { - nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now)); - } - ++qi; // if qi was erased, loop will have continued before here - } - } - { // Retry outstanding WHOIS requests Mutex::Lock _l(_outstandingWhoisRequests_m); Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests); @@ -751,7 +702,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(txi->packet,txi->encrypt,txi->nwid)) + if (_trySend(txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); @@ -787,20 +738,13 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread return Address(); } -bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) +bool Switch::_trySend(const Packet &packet,bool encrypt) { SharedPtr peer(RR->topology->getPeer(packet.destination())); if (peer) { const uint64_t now = RR->node->now(); - SharedPtr network; - if (nwid) { - network = RR->node->network(nwid); - if ((!network)||(!network->hasConfig())) - return false; // we probably just left this network, let its packets die - } - Path *viaPath = peer->getBestPath(now); SharedPtr relay; @@ -811,7 +755,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) } if (relay) { - peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false,( (network)&&(network->isAllowed(peer)) )); + peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false); viaPath->sent(now); } diff --git a/node/Switch.hpp b/node/Switch.hpp index ce4f00a1..7c903ef9 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -92,15 +92,10 @@ public: * Needless to say, the packet's source must be this node. Otherwise it * won't be encrypted right. (This is not used for relaying.) * - * The network ID should only be specified for frames and other actual - * network traffic. Other traffic such as controller requests and regular - * protocol messages should specify zero. - * * @param packet Packet to send * @param encrypt Encrypt packet payload? (always true except for HELLO) - * @param nwid Related network ID or 0 if message is not in-network traffic */ - void send(const Packet &packet,bool encrypt,uint64_t nwid); + void send(const Packet &packet,bool encrypt); /** * Send RENDEZVOUS to two peers to permit them to directly connect @@ -113,15 +108,6 @@ public: */ bool unite(const Address &p1,const Address &p2); - /** - * Attempt NAT traversal to peer at a given physical address - * - * @param peer Peer to contact - * @param localAddr Local interface address - * @param atAddr Address of peer - */ - void rendezvous(const SharedPtr &peer,const InetAddress &localAddr,const InetAddress &atAddr); - /** * Request WHOIS on a given address * @@ -151,7 +137,7 @@ public: private: Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); - bool _trySend(const Packet &packet,bool encrypt,uint64_t nwid); + bool _trySend(const Packet &packet,bool encrypt); const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; @@ -205,16 +191,14 @@ private: struct TXQueueEntry { TXQueueEntry() {} - TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,uint64_t nw) : + TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc) : dest(d), creationTime(ct), - nwid(nw), packet(p), encrypt(enc) {} Address dest; uint64_t creationTime; - uint64_t nwid; Packet packet; // unencrypted/unMAC'd packet -- this is done at send time bool encrypt; }; @@ -241,26 +225,6 @@ private: }; Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior Mutex _lastUniteAttempt_m; - - // Active attempts to contact remote peers, including state of multi-phase NAT traversal - struct ContactQueueEntry - { - ContactQueueEntry() {} - ContactQueueEntry(const SharedPtr &p,uint64_t ft,const InetAddress &laddr,const InetAddress &a) : - peer(p), - fireAtTime(ft), - inaddr(a), - localAddr(laddr), - strategyIteration(0) {} - - SharedPtr peer; - uint64_t fireAtTime; - InetAddress inaddr; - InetAddress localAddr; - unsigned int strategyIteration; - }; - std::list _contactQueue; - Mutex _contactQueue_m; }; } // namespace ZeroTier -- cgit v1.2.3 From c9d7845fea15ffe0e09295aedba6389de1bcb59b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 17:00:01 -0700 Subject: Minor bug fix and some instrumentation stuff for testing. --- node/IncomingPacket.cpp | 2 +- node/Network.cpp | 7 ++++++- node/Packet.hpp | 1 + node/SelfAwareness.cpp | 42 ++++++++++++++++++++++++++++++++++++------ node/SelfAwareness.hpp | 5 +++-- 5 files changed, 47 insertions(+), 10 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index df224c19..53f6b88a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -84,7 +84,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } const Packet::Verb v = verb(); - //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" diff --git a/node/Network.cpp b/node/Network.cpp index e098c1fd..b9a2ca1d 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -676,7 +676,12 @@ void Network::requestConfiguration() const unsigned int rmdSize = rmd.sizeBytes(); outp.append((uint16_t)rmdSize); outp.append((const void *)rmd.data(),rmdSize); - outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0); + if (_config) { + outp.append((uint64_t)_config.revision); + outp.append((uint64_t)_config.timestamp); + } else { + outp.append((unsigned char)0,16); + } outp.compress(); RR->sw->send(outp,true); diff --git a/node/Packet.hpp b/node/Packet.hpp index 9d4c8289..0524139d 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -724,6 +724,7 @@ public: * <[8] 64-bit network ID> * <[2] 16-bit length of request meta-data dictionary> * <[...] string-serialized request meta-data> + * <[8] 64-bit revision of netconf we currently have> * <[8] 64-bit timestamp of netconf we currently have> * * This message requests network configuration from a node capable of diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index a4fae3d5..05df53fe 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -79,9 +79,10 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope + TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str()); entry.mySurface = myPhysicalAddress; entry.ts = now; - TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str()); + entry.trusted = trusted; // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' // due to multiple reports of endpoint change. @@ -113,6 +114,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc // Otherwise just update DB to use to determine external surface info entry.mySurface = myPhysicalAddress; entry.ts = now; + entry.trusted = trusted; } } @@ -148,22 +150,50 @@ std::vector SelfAwareness::getSymmetricNatPredictions() bool symmetric = false; { Mutex::Lock _l(_phy_m); + Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceEntry *e = (PhySurfaceEntry *)0; + InetAddress lastTrustedSurface; while (i.next(k,e)) { if ((e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { std::set &s = surfaces[k->receivedOnLocalAddress]; - s.insert(e->mySurface); + + /* MINOR SECURITY FIX: + * + * If the surface was not reported by a trusted (upstream) peer, we do + * not use its report of our surface IP for symmetric NAT prediction. + * Otherwise a peer could poison our external surface cache and then + * use this to coax us into suggesting their IP as an endpoint. This + * in turn could allow them to relay traffic for us. They could not + * decrypt or otherwise mess with it, but they could DOS us or record + * meta-data without anything appearing amiss. + * + * So for surfaces reported by untrusted peers we use the IP reported + * by a trusted peer and then just use the port. + * + * As far as we know this has never been exploited. We discovered it + * because certain weird configurations, such as load balancers and + * gateways that do not preserve IP information, can coax a node into + * reporting back false surface information. */ + if (e->trusted) { + s.insert(e->mySurface); + lastTrustedSurface = e->mySurface; + } else if (lastTrustedSurface) { + InetAddress tmp(lastTrustedSurface); + tmp.setPort(e->mySurface.port()); + s.insert(tmp); + } + symmetric = symmetric||(s.size() > 1); } } } - // If we appear to be symmetrically NATed, generate and return extrapolations - // of those surfaces. Since PUSH_DIRECT_PATHS is sent multiple times, we - // probabilistically generate extrapolations of anywhere from +1 to +5 to - // increase the odds that it will work "eventually". + /* If we appear to be symmetrically NATed, generate and return extrapolations + * of those surfaces. Since PUSH_DIRECT_PATHS is sent multiple times, we + * probabilistically generate extrapolations of anywhere from +1 to +5 to + * increase the odds that it will work "eventually". */ if (symmetric) { std::vector r; for(std::map< InetAddress,std::set >::iterator si(surfaces.begin());si!=surfaces.end();++si) { diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 06c264a9..c7bde87e 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -82,9 +82,10 @@ private: { InetAddress mySurface; uint64_t ts; + bool trusted; - PhySurfaceEntry() : mySurface(),ts(0) {} - PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t) {} + PhySurfaceEntry() : mySurface(),ts(0),trusted(false) {} + PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t),trusted(false) {} }; const RuntimeEnvironment *RR; -- cgit v1.2.3 From d166b494ee4eee8f054f23508c1fbfac5a8bfc04 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 10 Aug 2016 13:41:22 -0700 Subject: Rule parse fix. --- node/Capability.hpp | 57 +++++++++++++++++++++++++------------------------ node/IncomingPacket.cpp | 51 +++++++++++++++++++++---------------------- node/Network.cpp | 38 ++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 68 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Capability.hpp b/node/Capability.hpp index fd6ae091..c129485d 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -176,7 +176,6 @@ public: template static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) { - b.append((uint16_t)ruleCount); for(unsigned int i=0;i static inline void deserializeRules(const Buffer &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount) { - ruleCount = b.template at(p); p += 2; - if (ruleCount > maxRuleCount) - throw std::runtime_error("rule count overflow"); - for(unsigned int i=0;i(p); + rules[ruleCount].v.vlanId = b.template at(p); break; case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - rules[i].v.vlanPcp = (uint8_t)b[p]; + rules[ruleCount].v.vlanPcp = (uint8_t)b[p]; break; case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - rules[i].v.vlanDei = (uint8_t)b[p]; + rules[ruleCount].v.vlanDei = (uint8_t)b[p]; break; case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - rules[i].v.etherType = b.template at(p); + rules[ruleCount].v.etherType = b.template at(p); break; case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: case ZT_NETWORK_RULE_MATCH_MAC_DEST: - memcpy(rules[i].v.mac,b.field(p,6),6); + memcpy(rules[ruleCount].v.mac,b.field(p,6),6); break; case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - memcpy(&(rules[i].v.ipv4.ip),b.field(p,4),4); - rules[i].v.ipv4.mask = (uint8_t)b[p + 4]; + memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4); + rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4]; break; case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - memcpy(rules[i].v.ipv6.ip,b.field(p,16),16); - rules[i].v.ipv6.mask = (uint8_t)b[p + 16]; + memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16); + rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16]; break; case ZT_NETWORK_RULE_MATCH_IP_TOS: - rules[i].v.ipTos = (uint8_t)b[p]; + rules[ruleCount].v.ipTos = (uint8_t)b[p]; break; case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - rules[i].v.ipProtocol = (uint8_t)b[p]; + rules[ruleCount].v.ipProtocol = (uint8_t)b[p]; break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - rules[i].v.port[0] = b.template at(p); - rules[i].v.port[1] = b.template at(p + 2); + rules[ruleCount].v.port[0] = b.template at(p); + rules[ruleCount].v.port[1] = b.template at(p + 2); break; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - rules[i].v.characteristics[0] = b.template at(p); - rules[i].v.characteristics[1] = b.template at(p + 8); + rules[ruleCount].v.characteristics[0] = b.template at(p); + rules[ruleCount].v.characteristics[1] = b.template at(p + 8); break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - rules[i].v.frameSize[0] = b.template at(p); - rules[i].v.frameSize[0] = b.template at(p + 2); + rules[ruleCount].v.frameSize[0] = b.template at(p); + rules[ruleCount].v.frameSize[0] = b.template at(p + 2); break; case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - rules[i].v.tag.id = b.template at(p); - rules[i].v.tag.value = b.template at(p + 4); + rules[ruleCount].v.tag.id = b.template at(p); + rules[ruleCount].v.tag.value = b.template at(p + 4); break; } p += fieldLen; + ++ruleCount; } } @@ -350,6 +347,7 @@ public: b.append(_expiration); b.append(_id); + b.append((uint16_t)_ruleCount); serializeRules(b,_rules,_ruleCount); b.append((uint8_t)_maxCustodyChainLength); @@ -387,7 +385,10 @@ public: _expiration = b.template at(p); p += 8; _id = b.template at(p); p += 4; - deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES); + const unsigned int rc = b.template at(p); p += 2; + if (rc > ZT_MAX_CAPABILITY_RULES) + throw std::runtime_error("rule overflow"); + deserializeRules(b,p,_rules,_ruleCount,rc); _maxCustodyChainLength = (unsigned int)b[p++]; if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 53f6b88a..5c9e80f8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -84,7 +84,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } const Packet::Verb v = verb(); - TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" @@ -401,8 +401,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { - const SharedPtr nw(RR->node->network(at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID))); - if ((nw)&&(nw->controller() == peer->address())) { + const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + if ((network)&&(network->controller() == peer->address())) { const unsigned int chunkLen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); const void *chunkData = field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,chunkLen); unsigned int chunkIndex = 0; @@ -411,7 +412,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p totalSize = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen); chunkIndex = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4); } - nw->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize); + TRACE("%s(%s): OK(NETWORK_CONFIG_REQUEST) chunkLen==%u chunkIndex==%u totalSize==%u",source().toString().c_str(),_remoteAddress.toString().c_str(),chunkLen,chunkIndex,totalSize); + network->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize); } } break; @@ -500,33 +502,32 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - if (RR->topology->isUpstream(peer->identity())) { // only upstream peers can tell us to rendezvous, otherwise this opens a potential amplification attack vector - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr withPeer(RR->topology->getPeer(with)); - if (withPeer) { - 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); - - const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - TRACE("RENDEZVOUS from %s says %s might be at %s, attempting to contact",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { - const uint64_t now = RR->node->now(); - peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) - if (!peer->pushDirectPaths(_localAddress,atAddr,now,true)) - peer->sendHELLO(_localAddress,atAddr,now); - } + const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + const SharedPtr withPeer(RR->topology->getPeer(with)); + if (withPeer) { + 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))) { + const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); + if (!RR->topology->isUpstream(peer->identity())) { + TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + } else if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { + const uint64_t now = RR->node->now(); + peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) + if (!peer->pushDirectPaths(_localAddress,atAddr,now,true)) + peer->sendHELLO(_localAddress,atAddr,now); + TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } } else { - RR->sw->requestWhois(with); - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); + TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } } else { - TRACE("ignored RENDEZVOUS from %s(%s): not a root server or a network relay",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); } + + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/Network.cpp b/node/Network.cpp index b9a2ca1d..4d588a30 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -593,13 +593,15 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize) { std::string newConfig; - if ((_inboundConfigPacketId == inRePacketId)&&(totalSize < ZT_NETWORKCONFIG_DICT_CAPACITY)&&((chunkIndex + chunkSize) < totalSize)) { + if ((_inboundConfigPacketId == inRePacketId)&&(totalSize < ZT_NETWORKCONFIG_DICT_CAPACITY)&&((chunkIndex + chunkSize) <= totalSize)) { Mutex::Lock _l(_lock); - TRACE("got %u bytes at position %u of network config request %.16llx, total expected length %u",chunkSize,chunkIndex,inRePacketId,totalSize); + _inboundConfigChunks[chunkIndex].append((const char *)data,chunkSize); + unsigned int totalWeHave = 0; for(std::map::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c) totalWeHave += (unsigned int)c->second.length(); + if (totalWeHave == totalSize) { TRACE("have all chunks for network config request %.16llx, assembling...",inRePacketId); for(std::map::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c) @@ -610,23 +612,29 @@ void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *d _inboundConfigPacketId = 0; _inboundConfigChunks.clear(); } + } else { + return; } - if (newConfig.length() > 0) { - if (newConfig.length() < ZT_NETWORKCONFIG_DICT_CAPACITY) { - Dictionary *dict = new Dictionary(newConfig.c_str()); - try { - Identity controllerId(RR->topology->getIdentity(this->controller())); - if (controllerId) { - NetworkConfig nc; - if (nc.fromDictionary(controllerId,*dict)) - this->setConfiguration(nc,true); + if ((newConfig.length() > 0)&&(newConfig.length() < ZT_NETWORKCONFIG_DICT_CAPACITY)) { + Dictionary *dict = new Dictionary(newConfig.c_str()); + NetworkConfig *nc = new NetworkConfig(); + try { + Identity controllerId(RR->topology->getIdentity(this->controller())); + if (controllerId) { + if (nc->fromDictionary(controllerId,*dict)) { + this->setConfiguration(*nc,true); + } else { + TRACE("error parsing new config with length %u: deserialization of NetworkConfig failed (certificate error?)",(unsigned int)newConfig.length()); } - delete dict; - } catch ( ... ) { - delete dict; - throw; } + delete nc; + delete dict; + } catch ( ... ) { + TRACE("error parsing new config with length %u: unexpected exception",(unsigned int)newConfig.length()); + delete nc; + delete dict; + throw; } } } -- cgit v1.2.3 From faa9a06bf5302b246805ead12690b38c3036d802 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 17 Aug 2016 17:37:37 -0700 Subject: Controller fixes... --- controller/EmbeddedNetworkController.cpp | 219 +++++++++++++++++++------------ controller/README.md | 2 +- node/IncomingPacket.cpp | 6 +- service/OneService.cpp | 4 + 4 files changed, 148 insertions(+), 83 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 30072f95..649ff094 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -60,6 +60,50 @@ using json = nlohmann::json; namespace ZeroTier { +static uint64_t _jI(const json &jv,const uint64_t dfl) +{ + if (jv.is_number()) { + return (uint64_t)jv; + } else if (jv.is_string()) { + std::string s = jv; + return Utils::strToU64(s.c_str()); + } else if (jv.is_boolean()) { + return ((bool)jv ? 1ULL : 0ULL); + } + return dfl; +} +static bool _jB(const json &jv,const bool dfl) +{ + if (jv.is_boolean()) { + return (bool)jv; + } else if (jv.is_number()) { + return ((uint64_t)jv > 0ULL); + } else if (jv.is_string()) { + std::string s = jv; + if (s.length() > 0) { + switch(s[0]) { + case 't': + case 'T': + case '1': + return true; + } + } + return false; + } + return dfl; +} +static std::string _jS(const json &jv,const char *dfl) +{ + if (jv.is_string()) { + return jv; + } else if (jv.is_number()) { + return jv; + } else if (jv.is_boolean()) { + return ((bool)jv ? std::string("1") : std::string("0")); + } + return std::string((dfl) ? dfl : ""); +} + static json _renderRule(ZT_VirtualNetworkRule &rule) { char tmp[128]; @@ -190,7 +234,7 @@ static bool _parseRule(const json &r,ZT_VirtualNetworkRule &rule) return false; std::string t = r["type"]; memset(&rule,0,sizeof(ZT_VirtualNetworkRule)); - if (r.value("not",false)) + if (_jB(r["not"],false)) rule.t = 0x80; else rule.t = 0x00; if (t == "ACTION_DROP") { @@ -201,91 +245,91 @@ static bool _parseRule(const json &r,ZT_VirtualNetworkRule &rule) return true; } else if (t == "ACTION_TEE") { rule.t |= ZT_NETWORK_RULE_ACTION_TEE; - rule.v.zt = Utils::hexStrToU64(r.value("zt","0").c_str()) & 0xffffffffffULL; + rule.v.zt = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL; return true; } else if (t == "ACTION_REDIRECT") { rule.t |= ZT_NETWORK_RULE_ACTION_REDIRECT; - rule.v.zt = Utils::hexStrToU64(r.value("zt","0").c_str()) & 0xffffffffffULL; + rule.v.zt = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL; return true; } else if (t == "MATCH_SOURCE_ZEROTIER_ADDRESS") { rule.t |= ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS; - rule.v.zt = Utils::hexStrToU64(r.value("zt","0").c_str()) & 0xffffffffffULL; + rule.v.zt = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL; return true; } else if (t == "MATCH_DEST_ZEROTIER_ADDRESS") { rule.t |= ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS; - rule.v.zt = Utils::hexStrToU64(r.value("zt","0").c_str()) & 0xffffffffffULL; + rule.v.zt = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL; return true; } else if (t == "MATCH_VLAN_ID") { rule.t |= ZT_NETWORK_RULE_MATCH_VLAN_ID; - rule.v.vlanId = (uint16_t)(r.value("vlanId",0ULL) & 0xffffULL); + rule.v.vlanId = (uint16_t)(_jI(r["vlanId"],0ULL) & 0xffffULL); return true; } else if (t == "MATCH_VLAN_PCP") { rule.t |= ZT_NETWORK_RULE_MATCH_VLAN_PCP; - rule.v.vlanPcp = (uint8_t)(r.value("vlanPcp",0ULL) & 0xffULL); + rule.v.vlanPcp = (uint8_t)(_jI(r["vlanPcp"],0ULL) & 0xffULL); return true; } else if (t == "MATCH_VLAN_DEI") { rule.t |= ZT_NETWORK_RULE_MATCH_VLAN_DEI; - rule.v.vlanDei = (uint8_t)(r.value("vlanDei",0ULL) & 0xffULL); + rule.v.vlanDei = (uint8_t)(_jI(r["vlanDei"],0ULL) & 0xffULL); return true; } else if (t == "MATCH_ETHERTYPE") { rule.t |= ZT_NETWORK_RULE_MATCH_ETHERTYPE; - rule.v.etherType = (uint16_t)(r.value("etherType",0ULL) & 0xffffULL); + rule.v.etherType = (uint16_t)(_jI(r["etherType"],0ULL) & 0xffffULL); return true; } else if (t == "MATCH_MAC_SOURCE") { rule.t |= ZT_NETWORK_RULE_MATCH_MAC_SOURCE; - const std::string mac(r.value("mac","0")); + const std::string mac(_jS(r["mac"],"0")); Utils::unhex(mac.c_str(),(unsigned int)mac.length(),rule.v.mac,6); return true; } else if (t == "MATCH_MAC_DEST") { rule.t |= ZT_NETWORK_RULE_MATCH_MAC_DEST; - const std::string mac(r.value("mac","0")); + const std::string mac(_jS(r["mac"],"0")); Utils::unhex(mac.c_str(),(unsigned int)mac.length(),rule.v.mac,6); return true; } else if (t == "MATCH_IPV4_SOURCE") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV4_SOURCE; - InetAddress ip(r.value("ip","0.0.0.0")); + InetAddress ip(_jS(r["ip"],"0.0.0.0")); rule.v.ipv4.ip = reinterpret_cast(&ip)->sin_addr.s_addr; rule.v.ipv4.mask = Utils::ntoh(reinterpret_cast(&ip)->sin_port) & 0xff; if (rule.v.ipv4.mask > 32) rule.v.ipv4.mask = 32; return true; } else if (t == "MATCH_IPV4_DEST") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV4_DEST; - InetAddress ip(r.value("ip","0.0.0.0")); + InetAddress ip(_jS(r["ip"],"0.0.0.0")); rule.v.ipv4.ip = reinterpret_cast(&ip)->sin_addr.s_addr; rule.v.ipv4.mask = Utils::ntoh(reinterpret_cast(&ip)->sin_port) & 0xff; if (rule.v.ipv4.mask > 32) rule.v.ipv4.mask = 32; return true; } else if (t == "MATCH_IPV6_SOURCE") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV6_SOURCE; - InetAddress ip(r.value("ip","::0")); + InetAddress ip(_jS(r["ip"],"::0")); memcpy(rule.v.ipv6.ip,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); rule.v.ipv6.mask = Utils::ntoh(reinterpret_cast(&ip)->sin6_port) & 0xff; if (rule.v.ipv6.mask > 128) rule.v.ipv6.mask = 128; return true; } else if (t == "MATCH_IPV6_DEST") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV6_DEST; - InetAddress ip(r.value("ip","::0")); + InetAddress ip(_jS(r["ip"],"::0")); memcpy(rule.v.ipv6.ip,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); rule.v.ipv6.mask = Utils::ntoh(reinterpret_cast(&ip)->sin6_port) & 0xff; if (rule.v.ipv6.mask > 128) rule.v.ipv6.mask = 128; return true; } else if (t == "MATCH_IP_TOS") { rule.t |= ZT_NETWORK_RULE_MATCH_IP_TOS; - rule.v.ipTos = (uint8_t)(r.value("ipTos",0ULL) & 0xffULL); + rule.v.ipTos = (uint8_t)(_jI(r["ipTos"],0ULL) & 0xffULL); return true; } else if (t == "MATCH_IP_PROTOCOL") { rule.t |= ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - rule.v.ipProtocol = (uint8_t)(r.value("ipProtocol",0ULL) & 0xffULL); + rule.v.ipProtocol = (uint8_t)(_jI(r["ipProtocol"],0ULL) & 0xffULL); return true; } else if (t == "MATCH_IP_SOURCE_PORT_RANGE") { rule.t |= ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE; - rule.v.port[0] = (uint16_t)(r.value("start",0ULL) & 0xffffULL); - rule.v.port[1] = (uint16_t)(r.value("end",(uint64_t)rule.v.port[0]) & 0xffffULL); + rule.v.port[0] = (uint16_t)(_jI(r["start"],0ULL) & 0xffffULL); + rule.v.port[1] = (uint16_t)(_jI(r["end"],(uint64_t)rule.v.port[0]) & 0xffffULL); return true; } else if (t == "MATCH_IP_DEST_PORT_RANGE") { rule.t |= ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; - rule.v.port[0] = (uint16_t)(r.value("start",0ULL) & 0xffffULL); - rule.v.port[1] = (uint16_t)(r.value("end",(uint64_t)rule.v.port[0]) & 0xffffULL); + rule.v.port[0] = (uint16_t)(_jI(r["start"],0ULL) & 0xffffULL); + rule.v.port[1] = (uint16_t)(_jI(r["end"],(uint64_t)rule.v.port[0]) & 0xffffULL); return true; } else if (t == "MATCH_CHARACTERISTICS") { rule.t |= ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; @@ -310,28 +354,28 @@ static bool _parseRule(const json &r,ZT_VirtualNetworkRule &rule) return true; } else if (t == "MATCH_FRAME_SIZE_RANGE") { rule.t |= ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE; - rule.v.frameSize[0] = (uint16_t)(r.value("start",0ULL) & 0xffffULL); - rule.v.frameSize[1] = (uint16_t)(r.value("end",(uint64_t)rule.v.frameSize[0]) & 0xffffULL); + rule.v.frameSize[0] = (uint16_t)(_jI(r["start"],0ULL) & 0xffffULL); + rule.v.frameSize[1] = (uint16_t)(_jI(r["end"],(uint64_t)rule.v.frameSize[0]) & 0xffffULL); return true; } else if (t == "MATCH_TAGS_SAMENESS") { rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS; - rule.v.tag.id = (uint32_t)(r.value("id",0ULL) & 0xffffffffULL); - rule.v.tag.value = (uint32_t)(r.value("value",0ULL) & 0xffffffffULL); + rule.v.tag.id = (uint32_t)(_jI(r["id"],0ULL) & 0xffffffffULL); + rule.v.tag.value = (uint32_t)(_jI(r["value"],0ULL) & 0xffffffffULL); return true; } else if (t == "MATCH_TAGS_BITWISE_AND") { rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND; - rule.v.tag.id = (uint32_t)(r.value("id",0ULL) & 0xffffffffULL); - rule.v.tag.value = (uint32_t)(r.value("value",0ULL) & 0xffffffffULL); + rule.v.tag.id = (uint32_t)(_jI(r["id"],0ULL) & 0xffffffffULL); + rule.v.tag.value = (uint32_t)(_jI(r["value"],0ULL) & 0xffffffffULL); return true; } else if (t == "MATCH_TAGS_BITWISE_OR") { rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR; - rule.v.tag.id = (uint32_t)(r.value("id",0ULL) & 0xffffffffULL); - rule.v.tag.value = (uint32_t)(r.value("value",0ULL) & 0xffffffffULL); + rule.v.tag.id = (uint32_t)(_jI(r["id"],0ULL) & 0xffffffffULL); + rule.v.tag.value = (uint32_t)(_jI(r["value"],0ULL) & 0xffffffffULL); return true; } else if (t == "MATCH_TAGS_BITWISE_XOR") { rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR; - rule.v.tag.id = (uint32_t)(r.value("id",0ULL) & 0xffffffffULL); - rule.v.tag.value = (uint32_t)(r.value("value",0ULL) & 0xffffffffULL); + rule.v.tag.id = (uint32_t)(_jI(r["id"],0ULL) & 0xffffffffULL); + rule.v.tag.value = (uint32_t)(_jI(r["value"],0ULL) & 0xffffffffULL); return true; } return false; @@ -613,7 +657,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( json member(_readJson(memberJP)); { - std::string haveIdStr = member.value("identity",""); + std::string haveIdStr(_jS(member["identity"],"")); if (haveIdStr.length() > 0) { try { if (Identity(haveIdStr.c_str()) != identity) @@ -630,13 +674,18 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( member["id"] = identity.address().toString(); member["address"] = member["id"]; member["nwid"] = network["id"]; - member["memberRevision"] = member.value("memberRevision",0ULL) + 1; + member["lastModified"] = now; + { + auto revj = member["revision"]; + const uint64_t rev = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); + member["revision"] = rev; + } // Determine whether and how member is authorized const char *authorizedBy = (const char *)0; - if (!network.value("private",true)) { + if (!_jB(network["private"],true)) { authorizedBy = "networkIsPublic"; - } else if (member.value("authorized",false)) { + } else if (_jB(member["authorized"],false)) { authorizedBy = "memberIsAuthorized"; } else { char atok[256]; @@ -648,8 +697,8 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( for(unsigned long i=0;i now)) && (tok.length() > 0) && (tok == atok) ) { authorizedBy = "token"; break; @@ -700,14 +749,14 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( // If we made it this far, they are authorized. nc.networkId = nwid; - nc.type = network.value("private",true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; + nc.type = _jB(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; nc.timestamp = now; - nc.revision = network.value("revision",0ULL); + nc.revision = _jI(network["revision"],0ULL); nc.issuedTo = identity.address(); - if (network.value("enableBroadcast",true)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - if (network.value("allowPassiveBridging",false)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; - Utils::scopy(nc.name,sizeof(nc.name),network.value("name","").c_str()); - nc.multicastLimit = (unsigned int)network.value("multicastLimit",32ULL); + if (_jB(network["enableBroadcast"],true)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; + if (_jB(network["allowPassiveBridging"],false)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; + Utils::scopy(nc.name,sizeof(nc.name),_jS(network["name"],"").c_str()); + nc.multicastLimit = (unsigned int)_jI(network["multicastLimit"],32ULL); bool amActiveBridge = false; { @@ -732,11 +781,11 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( auto rules = network["rules"]; if (v6AssignMode.is_object()) { - if ((v6AssignMode.value("rfc4193",false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + if ((_jB(v6AssignMode["rfc4193"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt()); nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; } - if ((v6AssignMode.value("6plane",false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + if ((_jB(v6AssignMode["6plane"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt()); nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; } @@ -757,8 +806,8 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( if (nc.routeCount >= ZT_MAX_NETWORK_ROUTES) break; auto route = routes[i]; - InetAddress t(route.value("target","")); - InetAddress v(route.value("via","")); + InetAddress t(_jS(route["target"],"")); + InetAddress v(_jS(route["via"],"")); if ((t)&&(v)&&(t.ss_family == v.ss_family)) { ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]); *(reinterpret_cast(&(r->target))) = t; @@ -803,13 +852,13 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( std::set allocatedIps; bool allocatedIpsLoaded = false; - if ( (ipAssignmentPools.is_array()) && ((v6AssignMode.is_object())&&(v6AssignMode.value("zt",false))) && (!haveManagedIpv6AutoAssignment) && (!amActiveBridge) ) { + if ( (ipAssignmentPools.is_array()) && ((v6AssignMode.is_object())&&(_jB(v6AssignMode["zt"],false))) && (!haveManagedIpv6AutoAssignment) && (!amActiveBridge) ) { if (!allocatedIpsLoaded) allocatedIps = _getAlreadyAllocatedIps(nwid); for(unsigned long p=0;((p(&ipRangeStart)->sin_addr.s_addr)); uint32_t ipRangeEnd = Utils::ntoh((uint32_t)(reinterpret_cast(&ipRangeEnd)->sin_addr.s_addr)); @@ -921,7 +970,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } } - if (network.value("private",true)) { + if (_jB(network["private"],true)) { CertificateOfMembership com(now,ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA,nwid,identity.address()); if (com.sign(signingId)) { nc.com = com; @@ -983,8 +1032,10 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); responseBody.append(*i); responseBody.append("\":"); - const std::string rc = member.value("memberRevision","0"); - responseBody.append(rc); + auto rev = member["revision"]; + if (rev.is_number()) + responseBody.append(rev); + else responseBody.push_back('0'); } } } @@ -1006,7 +1057,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( auto recentLog = member["recentLog"]; if ((recentLog.is_array())&&(recentLog.size() > 0)) { auto mostRecentLog = recentLog[0]; - if ((mostRecentLog.is_object())&&((uint64_t)mostRecentLog.value("ts",0ULL) >= threshold)) { + if ((mostRecentLog.is_object())&&(_jI(mostRecentLog["ts"],0ULL) >= threshold)) { responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); responseBody.append(*i); responseBody.append("\":"); @@ -1116,8 +1167,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json member(_readJson(_memberJP(nwid,Address(address),true))); try { - if (b.count("authorized")) member["authorized"] = b.value("authorized",false); - if ((b.count("identity"))&&(!member.count("identity"))) member["identity"] = b.value("identity",""); // allow identity to be populated only if not already known + if (b.count("authorized")) member["authorized"] = _jB(b["authorized"],false); + if ((b.count("identity"))&&(!member.count("identity"))) member["identity"] = _jS(b["identity"],""); // allow identity to be populated only if not already known if (b.count("ipAssignments")) { auto ipa = b["ipAssignments"]; @@ -1144,12 +1195,17 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( member["id"] = addrs; member["address"] = addrs; // legacy member["nwid"] = nwids; - member["memberRevision"] = member.value("memberRevision",0ULL) + 1; member["objtype"] = "member"; + member["lastModified"] = OSUtils::now(); + { + auto revj = member["revision"]; + const uint64_t rev = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); + member["revision"] = rev; + } _writeJson(_memberJP(nwid,Address(address),true).c_str(),member); - member["clock"] = OSUtils::now(); + member["clock"] = member["lastModified"]; responseBody = member.dump(2); responseContentType = "application/json"; return 200; @@ -1178,7 +1234,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } } } - test->reportAtEveryHop = (b.value("reportAtEveryHop",true) ? 1 : 0); + test->reportAtEveryHop = (_jB(b["reportAtEveryHop"],true) ? 1 : 0); if (!test->hopCount) { ::free((void *)test); @@ -1226,11 +1282,11 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json network(_readJson(_networkJP(nwid,true))); try { - if (b.count("name")) network["name"] = b.value("name",""); - if (b.count("private")) network["private"] = b.value("private",true); - if (b.count("enableBroadcast")) network["enableBroadcast"] = b.value("enableBroadcast",false); - if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = b.value("allowPassiveBridging",false); - if (b.count("multicastLimit")) network["multicastLimit"] = b.value("multicastLimit",32ULL); + if (b.count("name")) network["name"] = _jS(b["name"],""); + if (b.count("private")) network["private"] = _jB(b["private"],true); + if (b.count("enableBroadcast")) network["enableBroadcast"] = _jB(b["enableBroadcast"],false); + if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = _jB(b["allowPassiveBridging"],false); + if (b.count("multicastLimit")) network["multicastLimit"] = _jI(b["multicastLimit"],32ULL); if (b.count("activeBridges")) { auto ab = b["activeBridges"]; @@ -1249,10 +1305,10 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( auto nv4m = network["v4AssignMode"]; if (!nv4m.is_object()) nv4m = json::object(); if (b["v4AssignMode"].is_string()) { // backward compatibility - nv4m["zt"] = (b.value("v4AssignMode","") == "zt"); + nv4m["zt"] = (_jS(b["v4AssignMode"],"") == "zt"); } else if (b["v4AssignMode"].is_object()) { auto v4m = b["v4AssignMode"]; - if (v4m.count("zt")) nv4m["zt"] = v4m.value("zt",false); + if (v4m.count("zt")) nv4m["zt"] = _jB(v4m["zt"],false); } if (!nv4m.count("zt")) nv4m["zt"] = false; } @@ -1261,7 +1317,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( auto nv6m = network["v6AssignMode"]; if (!nv6m.is_object()) nv6m = json::object(); if (b["v6AssignMode"].is_string()) { // backward compatibility - std::vector v6m(Utils::split(b.value("v6AssignMode","").c_str(),",","","")); + std::vector v6m(Utils::split(_jS(b["v6AssignMode"],"").c_str(),",","","")); std::sort(v6m.begin(),v6m.end()); v6m.erase(std::unique(v6m.begin(),v6m.end()),v6m.end()); for(std::vector::iterator i(v6m.begin());i!=v6m.end();++i) { @@ -1274,9 +1330,9 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } } else if (b["v6AssignMode"].is_object()) { auto v6m = b["v6AssignMode"]; - if (v6m.count("rfc4193")) nv6m["rfc4193"] = v6m.value("rfc4193",false); - if (v6m.count("zt")) nv6m["rfc4193"] = v6m.value("zt",false); - if (v6m.count("6plane")) nv6m["rfc4193"] = v6m.value("6plane",false); + if (v6m.count("rfc4193")) nv6m["rfc4193"] = _jB(v6m["rfc4193"],false); + if (v6m.count("zt")) nv6m["rfc4193"] = _jB(v6m["zt"],false); + if (v6m.count("6plane")) nv6m["rfc4193"] = _jB(v6m["6plane"],false); } if (!nv6m.count("rfc4193")) nv6m["rfc4193"] = false; if (!nv6m.count("zt")) nv6m["zt"] = false; @@ -1289,8 +1345,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( for(unsigned long i=0;i 0) { json t = json::object(); t["token"] = tstr; - t["expires"] = token.value("expires",0ULL); + t["expires"] = _jI(token["expires"],0ULL); nat.push_back(t); } } @@ -1372,8 +1428,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (!network.count("creationTime")) network["creationTime"] = OSUtils::now(); if (!network.count("name")) network["name"] = ""; if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32; - if (!network.count("v4AssignMode")) network["v4AssignMode"] = "{\"zt\":false}"_json; - if (!network.count("v6AssignMode")) network["v6AssignMode"] = "{\"rfc4193\":false,\"zt\":false,\"6plane\":false}"_json; + if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}}; + if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}}; if (!network.count("activeBridges")) network["activeBridges"] = json::array(); if (!network.count("authTokens")) network["authTokens"] = json::array(); @@ -1387,7 +1443,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( network["id"] = nwids; network["nwid"] = nwids; // legacy - network["revision"] = network.value("revision",0ULL) + 1ULL; + auto rev = network["revision"]; + network["revision"] = (rev.is_number() ? ((uint64_t)rev + 1ULL) : 1ULL); network["objtype"] = "network"; _writeJson(_networkJP(nwid,true),network); diff --git a/controller/README.md b/controller/README.md index 2c7541ae..0b57dd25 100644 --- a/controller/README.md +++ b/controller/README.md @@ -5,7 +5,7 @@ ZeroTier's 16-digit network IDs are really just a concatenation of the 10-digit This code implements the *node/NetworkController.hpp* interface to provide an embedded microservice configurable via the same local HTTP control plane as ZeroTier One iteself. It is built by default in ZeroTier One in desktop and server builds. This is the same code we use to run [my.zerotier.com](https://my.zerotier.com/), which is a web UI and API that runs in front of a pool of controllers. -Data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, tar'd, placed in `git`, or edited in place, though we do not recommend doing the latter while the controller is running. Also take care if editing in place that you do not save corrupted JSON since the controller may then lose data when it attempts to load, modify, and save. +Data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, tar'd, placed in `git`, etc. Technically the JSON files under `controller.d` can also be edited in place, but we do not recommend doing this under a running controller since data loss or corruption might result. Also take care to keep JSON values of the correct types or data loss may also result. ### Scalability and Reliability diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5c9e80f8..e4f09106 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -804,8 +804,12 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } + } catch (std::exception &exc) { + fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); + TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + fprintf(stderr,"WARNING: network config request failed with exception: unknown exception" ZT_EOL_S); + TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } return true; } diff --git a/service/OneService.cpp b/service/OneService.cpp index 74628168..7ce45beb 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1705,7 +1705,11 @@ public: if (_controlPlane) scode = _controlPlane->handleRequest(tc->from,tc->parser.method,tc->url,tc->headers,tc->body,data,contentType); else scode = 500; + } catch (std::exception &exc) { + fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: %s" ZT_EOL_S,exc.what()); + scode = 500; } catch ( ... ) { + fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: unknown exceptino" ZT_EOL_S); scode = 500; } -- cgit v1.2.3 From 0dfc08b31724fe42ad7dc6253b3b673aec90c838 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 23 Aug 2016 11:29:02 -0700 Subject: Tidy up a few minor protocol things, improve documentation in Packet.hpp. --- node/IncomingPacket.cpp | 71 ++++++++++++++++++++++++++++++++----------------- node/Multicaster.cpp | 38 +++++++++++++++++--------- node/NetworkConfig.hpp | 20 ++++++++++++++ node/Packet.hpp | 59 +++++++++++++++++++--------------------- 4 files changed, 120 insertions(+), 68 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e4f09106..e188784a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -469,29 +469,40 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - if (payloadLength() == ZT_ADDRESS_LENGTH) { - const Address addr(payload(),ZT_ADDRESS_LENGTH); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_WHOIS); + outp.append(packetId()); + + unsigned int count = 0; + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; + while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { + const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + ptr += ZT_ADDRESS_LENGTH; + const Identity id(RR->topology->getIdentity(addr)); if (id) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_WHOIS); - outp.append(packetId()); id.serialize(outp,false); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + ++count; } else { + // If I am not the root and don't know this identity, ask upstream. Downstream + // peer may re-request in the future and if so we will be able to provide it. + if (!RR->topology->amRoot()) + RR->sw->requestWhois(addr); + #ifdef ZT_ENABLE_CLUSTER + // Distribute WHOIS queries across a cluster if we do not know the ID. + // This may result in duplicate OKs to the querying peer, which is fine. if (RR->cluster) RR->cluster->sendDistributedQuery(*this); #endif - if (!RR->topology->amRoot()) { - RR->sw->requestWhois(addr); - return false; // packet parse will be attempted again if we get a reply from upstream - } } - } else { - TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str()); } + + if (count > 0) { + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); @@ -836,11 +847,26 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar { try { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); //TRACE("< network(RR->node->network(nwid)); + if (network) + network->addCredential(com); + } + } catch ( ... ) { + TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + } + } + if (gatherLimit) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); @@ -854,6 +880,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } + // If we are a member of a cluster, distribute this GATHER across it #ifdef ZT_ENABLE_CLUSTER if ((RR->cluster)&&(gatheredLocally < gatherLimit)) RR->cluster->sendDistributedQuery(*this); @@ -862,7 +889,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP); } catch ( ... ) { - TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } return true; } @@ -878,7 +905,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share // Offset -- size of optional fields added to position of later fields unsigned int offset = 0; - if ((flags & 0x01) != 0) { // deprecated but still used by older peers + if ((flags & 0x01) != 0) { + // This is deprecated but may still be sent by old peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); if (com) @@ -1053,7 +1081,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt // Tracks total length of variable length fields, initialized to originator credential length below unsigned int vlf; - // Originator credentials + // Originator credentials -- right now only a network ID for which the originator is controller or is authorized by controller is allowed const unsigned int originatorCredentialLength = vlf = at(ZT_PACKET_IDX_PAYLOAD + 23); uint64_t originatorCredentialNetworkId = 0; if (originatorCredentialLength >= 1) { @@ -1085,15 +1113,10 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); // Check credentials (signature already verified) - NetworkConfig originatorCredentialNetworkConfig; if (originatorCredentialNetworkId) { - if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) { - if (!RR->node->network(originatorCredentialNetworkId)) { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member of that network",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - return true; - } - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID as credential, is not controller for %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + SharedPtr network(RR->node->network(originatorCredentialNetworkId)); + if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); return true; } } else { diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index aeee0a85..a6bff6aa 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -224,25 +224,37 @@ void Multicaster::send( if ((gs.members.empty())||((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY)) { gs.lastExplicitGather = now; - SharedPtr explicitGatherPeers[2]; - explicitGatherPeers[0] = RR->topology->getBestRoot(); - const Address nwidc(Network::controllerFor(nwid)); - if (nwidc != RR->identity.address()) - explicitGatherPeers[1] = RR->topology->getPeer(nwidc); - for(unsigned int k=0;k<2;++k) { - const SharedPtr &p = explicitGatherPeers[k]; - if (!p) - continue; - //TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str()); - Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER); + + Address explicitGatherPeers[16]; + unsigned int numExplicitGatherPeers = 0; + SharedPtr bestRoot(RR->topology->getBestRoot()); + if (bestRoot) + explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address(); + explicitGatherPeers[numExplicitGatherPeers++] = Network::controllerFor(nwid); + SharedPtr network(RR->node->network(nwid)); + if (network) { + std::vector
anchors(network->config().anchors()); + for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) { + if (*a != RR->identity.address()) { + explicitGatherPeers[numExplicitGatherPeers++] = *a; + if (numExplicitGatherPeers == 16) + break; + } + } + } + + for(unsigned int k=0;kconfig())&&(network->config().isPrivate())) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; + Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER); outp.append(nwid); - outp.append((uint8_t)0x00); + outp.append((uint8_t)((com) ? 0x01 : 0x00)); mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); outp.append((uint32_t)gatherLimit); + if (com) + com->serialize(outp); RR->sw->send(outp,true); } - gatherLimit = 0; } gs.txQueue.push_back(OutboundMulticast()); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 0ada4710..9b12aa0e 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -65,6 +65,11 @@ */ #define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL +/** + * Device can send CIRCUIT_TESTs for this network + */ +#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_CIRCUIT_TESTER 0x0000080000000000ULL + namespace ZeroTier { // Dictionary capacity needed for max size network config @@ -273,6 +278,21 @@ public: return false; } + /** + * @param byPeer Address to check + * @return True if this peer is allowed to do circuit tests on this network (controller is always true) + */ + inline bool circuitTestingAllowed(const Address &byPeer) const + { + if (byPeer.toInt() == ((networkId >> 24) & 0xffffffffffULL)) + return true; + for(unsigned int i=0;i * <[...] binary serialized identity (see Identity)> * <[1] destination address type> - * [<[...] destination address>] + * [<[...] destination address to which packet was sent>] * <[8] 64-bit world ID of current world> * <[8] 64-bit timestamp of current world> * @@ -592,20 +593,24 @@ public: /** * Query an identity by address: * <[5] address to look up> + * [<[...] additional addresses to look up> * * OK response payload: * <[...] binary serialized identity> + * [<[...] additional binary serialized identities>] * * If querying a cluster, duplicate OK responses may occasionally occur. - * These should be discarded. + * These must be tolerated, which is easy since they'll have info you + * already have. * - * If the address is not found, no response is generated. WHOIS requests - * will time out much like ARP requests and similar do in L2. + * If the address is not found, no response is generated. The semantics + * of WHOIS is similar to ARP and NDP in that persistent retrying can + * be performed. */ VERB_WHOIS = 0x04, /** - * Meet another node at a given protocol address: + * Relay-mediated NAT traversal or firewall punching initiation: * <[1] flags (unused, currently 0)> * <[5] ZeroTier address of peer that might be found at this address> * <[2] 16-bit protocol address port> @@ -619,15 +624,6 @@ public: * * Upon receipt a peer sends HELLO to establish a direct link. * - * Nodes should implement rate control, limiting the rate at which they - * respond to these packets to prevent their use in DDOS attacks. Nodes - * may also ignore these messages if a peer is not known or is not being - * actively communicated with. - * - * Unfortunately the physical address format in this message pre-dates - * InetAddress's serialization format. :( ZeroTier is four years old and - * yes we've accumulated a tiny bit of cruft here and there. - * * No OK or ERROR is generated. */ VERB_RENDEZVOUS = 0x05, @@ -652,7 +648,6 @@ public: * Full Ethernet frame with MAC addressing and optional fields: * <[8] 64-bit network ID> * <[1] flags> - * [<[...] 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> @@ -715,6 +710,9 @@ public: * 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. * + * COMs and other credentials need not be for the same network, since each + * includes its own network ID and signature. + * * OK/ERROR are not generated. */ VERB_NETWORK_CREDENTIALS = 0x0a, @@ -762,10 +760,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 (DEPRECATED)>] + * [<[...] network certificate of membership>] * * Flags: - * 0x01 - COM is attached (DEPRECATED) + * 0x01 - COM is attached * * This message asks a peer for additional known endpoints that have * LIKEd a given multicast group. It's sent when the sender wishes @@ -775,8 +773,8 @@ 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. + * The COM should be included so that upstream nodes that are not + * members of our network can validate our request. * * OK response payload: * <[8] 64-bit network ID> @@ -795,7 +793,6 @@ public: * Multicast frame: * <[8] 64-bit network ID> * <[1] flags> - * [<[...] network certificate of membership (DEPRECATED)>] * [<[4] 32-bit implicit gather limit>] * [<[6] source MAC>] * <[6] destination MAC (multicast address)> @@ -890,7 +887,7 @@ public: * <[...] next hop(s) in path> * * Flags: - * 0x01 - Report back to originator at middle hops + * 0x01 - Report back to originator at all hops * 0x02 - Report back to originator at last hop * * Originator credential types: @@ -948,21 +945,21 @@ public: /** * Circuit test hop report: - * <[8] 64-bit timestamp (from original test)> - * <[8] 64-bit test ID (from original test)> + * <[8] 64-bit timestamp (echoed from original test)> + * <[8] 64-bit test ID (echoed from original test)> * <[8] 64-bit reserved field (set to 0, currently unused)> * <[1] 8-bit vendor ID (set to 0, currently unused)> * <[1] 8-bit reporter protocol version> - * <[1] 8-bit reporter major version> - * <[1] 8-bit reporter minor version> - * <[2] 16-bit reporter revision> - * <[2] 16-bit reporter OS/platform> - * <[2] 16-bit reporter architecture> + * <[1] 8-bit reporter software major version> + * <[1] 8-bit reporter software minor version> + * <[2] 16-bit reporter software revision> + * <[2] 16-bit reporter OS/platform or 0 if not specified> + * <[2] 16-bit reporter architecture or 0 if not specified> * <[2] 16-bit error code (set to 0, currently unused)> * <[8] 64-bit report flags (set to 0, currently unused)> - * <[8] 64-bit source packet ID> - * <[5] upstream ZeroTier address from which test was received> - * <[1] 8-bit source packet hop count (ZeroTier hop count)> + * <[8] 64-bit packet ID of received CIRCUIT_TEST packet> + * <[5] upstream ZeroTier address from which CIRCUIT_TEST was received> + * <[1] 8-bit packet hop count of received CIRCUIT_TEST> * <[...] local wire address on which packet was received> * <[...] remote wire address from which packet was received> * <[2] 16-bit length of additional fields> -- cgit v1.2.3 From 70368312039f37d08ba687b07a5caad1c57cd8de Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 23 Aug 2016 11:57:56 -0700 Subject: Sign Dictionary in doNETWORK_CONFIG_REQUEST. --- node/Dictionary.hpp | 2 +- node/Identity.hpp | 13 +++++++++++++ node/IncomingPacket.cpp | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 5d453fd9..eab2b162 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -454,7 +454,7 @@ public: { this->erase(sigKey); C25519::Signature sig(C25519::sign(kp,this->data(),this->sizeBytes())); - this->add(sigKey,sig.data,ZT_C25519_SIGNATURE_LEN); + this->add(sigKey,reinterpret_cast(sig.data),ZT_C25519_SIGNATURE_LEN); } /** diff --git a/node/Identity.hpp b/node/Identity.hpp index ef7f2d77..e4522732 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -287,6 +287,19 @@ public: */ inline const C25519::Public &publicKey() const { return _publicKey; } + /** + * @return C25519 key pair (only returns valid pair if private key is present in this Identity object) + */ + inline const C25519::Pair privateKeyPair() const + { + C25519::Pair pair; + pair.pub = _publicKey; + if (_privateKey) + pair.priv = *_privateKey; + else memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN); + return pair; + } + /** * @return True if this identity contains something */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e188784a..139661db 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -749,6 +749,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons Dictionary *dconf = new Dictionary(); try { if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { + dconf->wrapWithSignature(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE,RR->identity.privateKeyPair()); const unsigned int totalSize = dconf->sizeBytes(); unsigned int chunkIndex = 0; while (chunkIndex < totalSize) { -- cgit v1.2.3 From 0a7a33ef8fb8cd3cdf25c48bd221298279e690c2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 23 Aug 2016 13:46:36 -0700 Subject: Instantaneous blacklisting and credential revocation. --- node/IncomingPacket.cpp | 23 +++++++++++++------- node/Membership.hpp | 56 ++++++++++++++++++++++++++++++++++++++++++------- node/Network.cpp | 12 ++++------- node/Network.hpp | 11 ++++++++++ node/NetworkConfig.hpp | 12 ----------- node/Packet.hpp | 25 +++++++++++++++------- 6 files changed, 96 insertions(+), 43 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 139661db..0ecc68be 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -829,13 +829,22 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - unsigned int p = ZT_PACKET_IDX_PAYLOAD; - while ((p + 8) <= size()) { - const uint64_t nwid = at(p); p += 8; - if (Network::controllerFor(nwid) == peer->address()) { - SharedPtr network(RR->node->network(nwid)); - if (network) - network->requestConfiguration(); + const uint64_t nwid = at(ZT_PACKET_IDX_PAYLOAD); + + if (Network::controllerFor(nwid) == peer->address()) { + SharedPtr network(RR->node->network(nwid)); + if (network) { + network->requestConfiguration(); + } else { + TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid); + return true; + } + + const unsigned int blacklistCount = at(ZT_PACKET_IDX_PAYLOAD + 8); + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 10; + for(unsigned int i=0;iblacklistBefore(Address(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH),at(ptr + 5)); + ptr += 13; } } } catch ( ... ) { diff --git a/node/Membership.hpp b/node/Membership.hpp index a845b992..dc525483 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -42,7 +42,10 @@ namespace ZeroTier { class RuntimeEnvironment; /** - * A container for certificates of membership and other credentials for peer participation on networks + * A container for certificates of membership and other network credentials + * + * This is kind of analogous to a join table between Peer and Network. It is + * presently held by the Network object for each participating Peer. */ class Membership { @@ -73,12 +76,13 @@ private: public: /** - * A wrapper to iterate through capabilities in ascending order of capability ID + * A wrapper to iterate through member capabilities in ascending order of capability ID and return only valid ones */ class CapabilityIterator { public: CapabilityIterator(const Membership &m) : + _m(m), _i(m._caps.begin()), _e(m._caps.end()) { @@ -87,7 +91,7 @@ public: inline const Capability *next(const NetworkConfig &nconf) { while (_i != _e) { - if ((_i->second.lastReceived)&&(nconf.isCredentialTimestampValid(_i->second.cap))) + if ((_i->second.lastReceived)&&(_m.isCredentialTimestampValid(nconf,_i->second.cap))) return &((_i++)->second.cap); else ++_i; } @@ -95,12 +99,14 @@ public: } private: + const Membership &_m; std::map::const_iterator _i,_e; }; friend class CapabilityIterator; Membership() : _lastPushedCom(0), + _blacklistBefore(0), _com(), _caps(), _tags(8) @@ -125,9 +131,30 @@ public: bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const CertificateOfMembership &com,const Capability *cap,const Tag **tags,const unsigned int tagCount); /** - * @return This peer's COM if they have sent one + * @param nconf Our network config + * @return True if this peer is allowed on this network at all + */ + inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const + { + if (nconf.isPublic()) + return true; + if ((_blacklistBefore)&&(_com.timestamp().first <= _blacklistBefore)) + return false; + return nconf.com.agreesWith(_com); + } + + /** + * Check whether a capability or tag is expired + * + * @param cred Credential to check -- must have timestamp() accessor method + * @return True if credential is NOT expired */ - inline const CertificateOfMembership &com() const { return _com; } + template + inline bool isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred) const + { + const uint64_t ts = cred.timestamp(); + return ( ( (ts >= nconf.timestamp) || ((nconf.timestamp - ts) <= nconf.credentialTimeToLive) ) && (ts > _blacklistBefore) ); + } /** * @param nconf Network configuration @@ -137,7 +164,7 @@ public: inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const { const TState *t = _tags.get(id); - return ((t) ? (((t->lastReceived != 0)&&(nconf.isCredentialTimestampValid(t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0); + return ((t) ? (((t->lastReceived != 0)&&(isCredentialTimestampValid(nconf,t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0); } /** @@ -154,7 +181,7 @@ public: TState *ts = (TState *)0; Hashtable::Iterator i(const_cast(this)->_tags); while (i.next(id,ts)) { - if ((ts->lastReceived)&&(nconf.isCredentialTimestampValid(ts->tag))) { + if ((ts->lastReceived)&&(isCredentialTimestampValid(nconf,ts->tag))) { if (n >= maxTags) return n; ids[n] = *id; @@ -172,7 +199,7 @@ public: inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const { std::map::const_iterator c(_caps.find(id)); - return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(nconf.isCredentialTimestampValid(c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0); + return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(isCredentialTimestampValid(nconf,c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0); } /** @@ -196,6 +223,16 @@ public: */ int addCredential(const RuntimeEnvironment *RR,const Capability &cap); + /** + * Blacklist COM, tags, and capabilities before this time + * + * @param ts Blacklist cutoff + */ + inline void blacklistBefore(const uint64_t ts) + { + _blacklistBefore = ts; + } + /** * Clean up old or stale entries * @@ -234,6 +271,9 @@ private: // Last time we pushed our COM to this peer uint64_t _lastPushedCom; + // Time before which to blacklist credentials from this peer + uint64_t _blacklistBefore; + // COM from this peer CertificateOfMembership _com; diff --git a/node/Network.cpp b/node/Network.cpp index d8e3b07a..1319df4e 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -888,16 +888,12 @@ bool Network::_isAllowed(const SharedPtr &peer) const // Assumes _lock is locked try { if (_config) { - if (_config.isPublic()) { - return true; - } else { - const Membership *m = _memberships.get(peer->address()); - if (m) - return _config.com.agreesWith(m->com()); - } + const Membership *const m = _memberships.get(peer->address()); + if (m) + return m->isAllowedOnNetwork(_config); } } catch ( ... ) { - TRACE("isAllowed() check failed for peer %s: unexpected exception: unexpected exception",peer->address().toString().c_str()); + TRACE("isAllowed() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); } return false; } diff --git a/node/Network.hpp b/node/Network.hpp index d13918cf..37154dc7 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -387,6 +387,17 @@ public: return _memberships[tag.issuedTo()].addCredential(RR,tag); } + /** + * Blacklist COM, tags, and capabilities before this time + * + * @param ts Blacklist cutoff + */ + inline void blacklistBefore(const Address &peerAddress,const uint64_t ts) + { + Mutex::Lock _l(_lock); + _memberships[peerAddress].blacklistBefore(ts); + } + /** * Destroy this network * diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index e1a4e302..22ffb1cf 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -360,18 +360,6 @@ public: return (Tag *)0; } - /** - * Check whether a capability or tag is expired - * - * @param cred Credential to check -- must have timestamp() accessor method - * @return True if credential is NOT expired - */ - template - inline bool isCredentialTimestampValid(const C &cred) const - { - return ( (cred.timestamp() >= timestamp) || ((timestamp - cred.timestamp()) <= credentialTimeToLive) ); - } - /* inline void dump() const { diff --git a/node/Packet.hpp b/node/Packet.hpp index c2e6da00..fed6aacf 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -742,14 +742,23 @@ public: 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. + * Network configuration update push: + * <[8] network ID to refresh> + * <[2] 16-bit number of address/timestamp pairs to blacklist> + * [<[5] ZeroTier address of peer being revoked>] + * [<[8] blacklist credentials older than this timestamp>] + * [<[...] additional address/timestamp pairs>] + * + * This can be sent by a network controller to both request that a network + * config be updated and push instantaneous revocations of specific peers + * or peer credentials. + * + * Specific revocations can be pushed to blacklist a specific peer's + * credentials (COM, tags, and capabilities) if older than a specified + * timestamp. This can be used to accomplish expedited revocation of + * a peer's access to things on a network or to the network itself among + * those other peers that can currently reach the controller. This is not + * the only mechanism for revocation of course, but it's the fastest. */ VERB_NETWORK_CONFIG_REFRESH = 0x0c, -- cgit v1.2.3 From 0ee4d3554a072863caa59ca2b45122996258617e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 23 Aug 2016 14:38:20 -0700 Subject: Stub out USER_MESSAGE. --- node/IncomingPacket.cpp | 2 ++ node/Packet.cpp | 1 + node/Packet.hpp | 13 ++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0ecc68be..1aecfdb7 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -109,6 +109,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer); + case Packet::VERB_USER_MESSAGE: + return true; } } else { RR->sw->requestWhois(sourceAddress); diff --git a/node/Packet.cpp b/node/Packet.cpp index aadee00b..9630e5bb 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -47,6 +47,7 @@ const char *Packet::verbString(Verb v) case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST"; case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT"; case VERB_REQUEST_PROOF_OF_WORK: return "REQUEST_PROOF_OF_WORK"; + case VERB_USER_MESSAGE: return "USER_MESSAGE"; } return "(unknown)"; } diff --git a/node/Packet.hpp b/node/Packet.hpp index fed6aacf..0a5d3fec 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1030,7 +1030,18 @@ public: * * ERROR has no payload. */ - VERB_REQUEST_PROOF_OF_WORK = 0x13 + VERB_REQUEST_PROOF_OF_WORK = 0x13, + + /** + * A message with arbitrary user-definable content: + * <[8] 64-bit arbitrary message type ID> + * [<[...] message payload>] + * + * This can be used to send arbitrary messages over VL1. It generates no + * OK or ERROR and has no special semantics outside of whatever the user + * (via the ZeroTier core API) chooses to give it. + */ + VERB_USER_MESSAGE = 0x14 }; /** -- cgit v1.2.3 From c476285bd638da01e0297c76951609c70f4ab3cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 24 Aug 2016 16:16:39 -0700 Subject: Harden PUSH_DIRECT_PATHS and simplify things by only doing it on receive when hops>0 and trust has been established. --- node/IncomingPacket.cpp | 78 ++++++++++++---------- node/Peer.cpp | 171 ++++++++++++++++++++++++------------------------ node/Peer.hpp | 18 ++--- node/Switch.cpp | 5 -- 4 files changed, 135 insertions(+), 137 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1aecfdb7..8faa62fb 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -88,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; case Packet::VERB_HELLO: return _doHELLO(RR,peer); @@ -172,7 +172,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -339,7 +339,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -461,7 +461,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -505,7 +505,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -527,8 +527,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } else if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { const uint64_t now = RR->node->now(); peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) - if (!peer->pushDirectPaths(_localAddress,atAddr,now,true)) - peer->sendHELLO(_localAddress,atAddr,now); + peer->sendHELLO(_localAddress,atAddr,now); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -540,7 +539,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -555,19 +554,17 @@ 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()); - return true; - } - - const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),network->id()); - const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) { - RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); + } else { + const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + const MAC sourceMac(peer->address(),network->id()); + const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) + RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); } } - - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP); } else { TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -595,6 +592,7 @@ 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()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -608,6 +606,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -616,24 +615,24 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - - if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { + if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); - } - } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + } } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -654,7 +653,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -673,7 +672,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -722,7 +721,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -740,7 +739,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); if (RR->localNetworkController) { NetworkConfig *netconf = new NetworkConfig(); @@ -899,7 +898,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -929,6 +928,7 @@ 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()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -955,10 +955,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -967,6 +969,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -990,9 +993,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } - } // else ignore -- not a member of this network - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + } else { + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1007,6 +1012,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // 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()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1069,7 +1075,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1113,6 +1119,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1129,10 +1136,12 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1203,7 +1212,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1248,6 +1257,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S } RR->node->postCircuitTestReport(&report); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1308,7 +1318,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const break; } - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); } else { TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 77e1d0b5..7691408e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -66,7 +66,8 @@ void Peer::received( uint64_t packetId, Packet::Verb verb, uint64_t inRePacketId, - Packet::Verb inReVerb) + Packet::Verb inReVerb, + const bool trustEstablished) { #ifdef ZT_ENABLE_CLUSTER bool suboptimalPath = false; @@ -184,6 +185,8 @@ void Peer::received( } } + } else if (trustEstablished) { + _pushDirectPaths(localAddr,remoteAddr,now); } if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { @@ -241,90 +244,6 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) return false; } -bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force) -{ -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - if (RR->cluster) - return false; -#endif - - if (!force) { - if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL) - return false; - else _lastDirectPathPushSent = now; - } - - std::vector pathsToPush; - - std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) - pathsToPush.push_back(*i); - - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; - } - } - if (pathsToPush.empty()) - return false; - -#ifdef ZT_TRACE - { - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); - } -#endif - - std::vector::const_iterator p(pathsToPush.begin()); - while (p != pathsToPush.end()) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.addSize(2); // leave room for count - - unsigned int count = 0; - while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { - uint8_t addressType = 4; - switch(p->ss_family) { - case AF_INET: - break; - case AF_INET6: - addressType = 6; - break; - default: // we currently only push IP addresses - ++p; - continue; - } - - outp.append((uint8_t)0); // no flags - outp.append((uint16_t)0); // no extensions - outp.append(addressType); - outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->port()); - - ++count; - ++p; - } - - if (count) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true); - RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0); - } - } - - return true; -} - bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) { unsigned int np = _numPaths; @@ -453,4 +372,86 @@ Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) return bestPath; } +bool Peer::_pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now) +{ +#ifdef ZT_ENABLE_CLUSTER + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + if (RR->cluster) + return false; +#endif + + if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL) + return false; + else _lastDirectPathPushSent = now; + + std::vector pathsToPush; + + std::vector dps(RR->node->directPaths()); + for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) + pathsToPush.push_back(*i); + + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } + } + if (pathsToPush.empty()) + return false; + +#ifdef ZT_TRACE + { + std::string ps; + for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { + if (ps.length() > 0) + ps.push_back(','); + ps.append(p->toString()); + } + TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); + } +#endif + + std::vector::const_iterator p(pathsToPush.begin()); + while (p != pathsToPush.end()) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); + outp.addSize(2); // leave room for count + + unsigned int count = 0; + while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { + uint8_t addressType = 4; + switch(p->ss_family) { + case AF_INET: + break; + case AF_INET6: + addressType = 6; + break; + default: // we currently only push IP addresses + ++p; + continue; + } + + outp.append((uint8_t)0); // no flags + outp.append((uint16_t)0); // no extensions + outp.append(addressType); + outp.append((uint8_t)((addressType == 4) ? 6 : 18)); + outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); + outp.append((uint16_t)p->port()); + + ++count; + ++p; + } + + if (count) { + outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); + outp.armor(_key,true); + RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0); + } + } + + return true; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 200c5ac4..a6940737 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -104,6 +104,7 @@ public: * @param verb Packet verb * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) + * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established */ void received( const InetAddress &localAddr, @@ -111,8 +112,9 @@ public: unsigned int hops, uint64_t packetId, Packet::Verb verb, - uint64_t inRePacketId = 0, - Packet::Verb inReVerb = Packet::VERB_NOP); + uint64_t inRePacketId, + Packet::Verb inReVerb, + const bool trustEstablished); /** * Get the current best direct path to this peer @@ -192,17 +194,6 @@ public: */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); - /** - * Push direct paths back to self if we haven't done so in the configured timeout - * - * @param localAddr Local address - * @param toAddress Remote address to send push to (usually from path) - * @param now Current time - * @param force If true, push regardless of rate limit - * @return True if something was actually sent - */ - bool pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force); - /** * @return All known direct paths to this peer (active or inactive) */ @@ -407,6 +398,7 @@ private: void _doDeadPathDetection(Path &p,const uint64_t now); Path *_getBestPath(const uint64_t now); Path *_getBestPath(const uint64_t now,int inetAddressFamily); + bool _pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; diff --git a/node/Switch.cpp b/node/Switch.cpp index f6e4d1ab..546c9157 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -761,11 +761,6 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) return false; } - if (relay) { - peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false); - viaPath->sent(now); - } - Packet tmp(packet); unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); -- cgit v1.2.3 From 347ebcd899cb7182895a5d28e2be6159167e455c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 24 Aug 2016 17:48:13 -0700 Subject: Set trust flag in network controllers if remote query is accepted to allow NATed network controllers to better traverse. --- node/IncomingPacket.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 8faa62fb..b74f7c8b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -739,7 +739,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); + bool netconfOk = false; if (RR->localNetworkController) { NetworkConfig *netconf = new NetworkConfig(); @@ -747,6 +747,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,*netconf)) { case NetworkController::NETCONF_QUERY_OK: { + netconfOk = true; Dictionary *dconf = new Dictionary(); try { if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { @@ -817,6 +818,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } + + peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); -- cgit v1.2.3 From cd3683f2bae5e706b5afdf40eee2b5f486f5aedb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 24 Aug 2016 17:50:51 -0700 Subject: Fix a missing receive(). --- node/IncomingPacket.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b74f7c8b..0804f04a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -841,6 +841,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons network->requestConfiguration(); } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); return true; } @@ -851,6 +852,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons ptr += 13; } } + + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } -- cgit v1.2.3 From f0636ffd4a86336f00bbf77a3e303def6261b518 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 29 Aug 2016 15:54:06 -0700 Subject: EXT_FRAME messages should always be accepted if we are the destination for a matching TEE or REDIRECT rule. --- node/IncomingPacket.cpp | 46 +++++++++++++++++++++++----------------------- node/Network.cpp | 35 ++++++++++++++++++----------------- node/Network.hpp | 4 ++-- 3 files changed, 43 insertions(+), 42 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0804f04a..c75125d3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -596,13 +596,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); - const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); + const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); + const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); @@ -610,27 +608,29 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

address(),network->id())) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } - } else if (to != network->mac()) { - if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay - return true; - } + switch (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { + case 1: + if (from != MAC(peer->address(),network->id())) { + if (network->config().permitsBridging(peer->address())) { + network->learnBridgeRoute(from,peer->address()); + } else { + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + return true; + } + } else if (to != network->mac()) { + if (!network->config().permitsBridging(RR->identity.address())) { + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + return true; + } + } + // fall through -- 2 means accept regardless of bridging state + case 2: + RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + break; } - const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); - const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) - RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } } else { diff --git a/node/Network.cpp b/node/Network.cpp index 5fd7ac8c..fa8cad80 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -77,7 +77,9 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) } static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,bool noRedirect,bool inbound,const Address &ztSource,const Address &ztDest,const MAC &macSource,const MAC &macDest,const std::vector &dlog,unsigned int frameLen,unsigned int etherType,const char *msg) { - printf("!! %c %s inbound=%d noRedirect=%d frameLen=%u etherType=%u" ZT_EOL_S, + static volatile unsigned long cnt = 0; + printf("%.6lu %c %s inbound=%d noRedirect=%d frameLen=%u etherType=%u" ZT_EOL_S, + cnt, ((thisSetMatches) ? 'Y' : '.'), ruleName, (int)inbound, @@ -86,8 +88,8 @@ static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,b etherType ); for(std::vector::const_iterator m(dlog.begin());m!=dlog.end();++m) - printf(" | %s" ZT_EOL_S,m->c_str()); - printf(" + %c %s->%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x->%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" ZT_EOL_S, + printf(" | %s" ZT_EOL_S,m->c_str()); + printf(" + %c %s->%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x->%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" ZT_EOL_S, ((thisSetMatches) ? 'Y' : '.'), ztSource.toString().c_str(), ztDest.toString().c_str(), @@ -105,7 +107,7 @@ static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,b (unsigned int)macDest[5] ); if (msg) - printf(" + (%s)" ZT_EOL_S,msg); + printf(" + (%s)" ZT_EOL_S,msg); } #else #define FILTER_TRACE(f,...) {} @@ -140,7 +142,7 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig return false; // overflow == invalid } -// 0 == no match, -1 == match/drop, 1 == match/accept +// 0 == no match, -1 == match/drop, 1 == match/accept, 2 == match/accept even if bridged static int _doZtFilter( const RuntimeEnvironment *RR, const bool noRedirect, @@ -212,9 +214,8 @@ static int _doZtFilter( // REDIRECT as DROP since we are the destination. #ifdef ZT_RULES_ENGINE_DEBUGGING _dumpFilterTrace(_rtn(rt),thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"ignored since we are the destination"); - dlog.clear(); #endif // ZT_RULES_ENGINE_DEBUGGING - thisSetMatches = 1; + return 2; // we should "super-accept" this packet since we are the TEE or REDIRECT destination } else { if (!noRedirect) { Packet outp(fwdAddr,RR->identity.address(),Packet::VERB_EXT_FRAME); @@ -580,6 +581,7 @@ bool Network::filterOutgoingPacket( m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,(const Capability *)0); return false; case 1: + case 2: if (ztDest) m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,(const Capability *)0); return true; @@ -592,6 +594,7 @@ bool Network::filterOutgoingPacket( m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,(const Capability *)0); return false; case 1: + case 2: if (ztDest) m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,&(_config.capabilities[c])); return true; @@ -601,7 +604,7 @@ bool Network::filterOutgoingPacket( return false; } -bool Network::filterIncomingPacket( +int Network::filterIncomingPacket( const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, @@ -620,24 +623,22 @@ bool Network::filterIncomingPacket( const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); switch (_doZtFilter(RR,false,_config,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: - return false; - case 1: - return true; + case -1: return 0; + case 1: return 1; + case 2: return 2; } Membership::CapabilityIterator mci(m); const Capability *c; while ((c = mci.next(_config))) { switch(_doZtFilter(RR,false,_config,false,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: - return false; - case 1: - return true; + case -1: return 0; + case 1: return 1; + case 2: return 2; } } - return false; + return 0; } bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const diff --git a/node/Network.hpp b/node/Network.hpp index c5e7d570..aa4b67f8 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -124,9 +124,9 @@ public: * @param frameLen Ethernet frame payload length * @param etherType 16-bit ethernet type ID * @param vlanId 16-bit VLAN ID - * @return True if packet should be accepted locally + * @return 0 == drop, 1 == accept, 2 == accept even if bridged */ - bool filterIncomingPacket( + int filterIncomingPacket( const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, -- cgit v1.2.3 From 74afef8eb1d96aec291c6dfeca31e69a2ad33d69 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 31 Aug 2016 16:50:22 -0700 Subject: Think through and refine a few things in rules, especially edge case TEE and REDIRECT behavior and semantics. --- controller/EmbeddedNetworkController.cpp | 2 - node/Capability.hpp | 2 +- node/IncomingPacket.cpp | 6 +- node/Network.cpp | 290 +++++++++++++++++++++++-------- node/Network.hpp | 11 +- node/OutboundMulticast.cpp | 5 +- node/Packet.hpp | 5 +- node/Switch.cpp | 5 +- 8 files changed, 229 insertions(+), 97 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 29dd8ad7..ff2f34ec 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -144,7 +144,6 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) r["type"] = "ACTION_REDIRECT"; r["address"] = Address(rule.v.fwd.address).toString(); r["flags"] = (unsigned int)rule.v.fwd.flags; - r["length"] = (unsigned int)rule.v.fwd.length; break; case ZT_NETWORK_RULE_ACTION_DEBUG_LOG: r["type"] = "ACTION_DEBUG_LOG"; @@ -308,7 +307,6 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) rule.t |= ZT_NETWORK_RULE_ACTION_REDIRECT; rule.v.fwd.address = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL; rule.v.fwd.flags = (uint32_t)(_jI(r["flags"],0ULL) & 0xffffffffULL); - rule.v.fwd.length = (uint16_t)(_jI(r["length"],0ULL) & 0xffffULL); return true; } else if (t == "ACTION_DEBUG_LOG") { rule.t |= ZT_NETWORK_RULE_ACTION_DEBUG_LOG; diff --git a/node/Capability.hpp b/node/Capability.hpp index 8e749e80..e23d7943 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -178,7 +178,7 @@ public: b.append((uint8_t)14); b.append((uint64_t)rules[i].v.fwd.address); b.append((uint32_t)rules[i].v.fwd.flags); - b.append((uint16_t)rules[i].v.fwd.length); + b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect break; case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c75125d3..4b013078 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -560,7 +560,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const MAC sourceMac(peer->address(),network->id()); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) + if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); } @@ -625,7 +625,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); break; @@ -981,7 +981,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0)) { + if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } } diff --git a/node/Network.cpp b/node/Network.cpp index f8b7c1d5..5a9b07cf 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -76,15 +76,14 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) default: return "BAD_RULE_TYPE"; } } -static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,bool noRedirect,bool inbound,const Address &ztSource,const Address &ztDest,const MAC &macSource,const MAC &macDest,const std::vector &dlog,unsigned int frameLen,unsigned int etherType,const char *msg) +static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,bool inbound,const Address &ztSource,const Address &ztDest,const MAC &macSource,const MAC &macDest,const std::vector &dlog,unsigned int frameLen,unsigned int etherType,const char *msg) { static volatile unsigned long cnt = 0; - printf("%.6lu %c %s inbound=%d noRedirect=%d frameLen=%u etherType=%u" ZT_EOL_S, + printf("%.6lu %c %s %s frameLen=%u etherType=%u" ZT_EOL_S, cnt++, ((thisSetMatches) ? 'Y' : '.'), ruleName, - (int)inbound, - (int)noRedirect, + ((inbound) ? "INBOUND" : "OUTBOUND"), frameLen, etherType ); @@ -143,14 +142,20 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig return false; // overflow == invalid } -// 0 == no match, -1 == match/drop, 1 == match/accept, 2 == match/accept even if bridged -static int _doZtFilter( +enum _doZtFilterResult +{ + DOZTFILTER_NO_MATCH = 0, + DOZTFILTER_DROP = 1, + DOZTFILTER_REDIRECT = 2, + DOZTFILTER_ACCEPT = 3, + DOZTFILTER_SUPER_ACCEPT = 4 +}; +static _doZtFilterResult _doZtFilter( const RuntimeEnvironment *RR, - const bool noRedirect, const NetworkConfig &nconf, const bool inbound, const Address &ztSource, - const Address &ztDest, + Address &ztDest, // MUTABLE const MAC &macSource, const MAC &macDest, const uint8_t *const frameData, @@ -163,7 +168,9 @@ static int _doZtFilter( const unsigned int localTagCount, const uint32_t *const remoteTagIds, const uint32_t *const remoteTagValues, - const unsigned int remoteTagCount) + const unsigned int remoteTagCount, + Address &cc, // MUTABLE + unsigned int &ccLength) // MUTABLE { // For each set of rules we start by assuming that they match (since no constraints // yields a 'match all' rule). @@ -181,75 +188,83 @@ static int _doZtFilter( case ZT_NETWORK_RULE_ACTION_DROP: if (thisSetMatches) { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_DROP",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); + _dumpFilterTrace("ACTION_DROP",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); #endif // ZT_RULES_ENGINE_DEBUGGING - return -1; // match, drop packet + return DOZTFILTER_DROP; } else { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_DROP",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); + _dumpFilterTrace("ACTION_DROP",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); dlog.clear(); #endif // ZT_RULES_ENGINE_DEBUGGING - thisSetMatches = 1; // no match, evaluate next set + thisSetMatches = 1; } continue; + case ZT_NETWORK_RULE_ACTION_ACCEPT: if (thisSetMatches) { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_ACCEPT",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); + _dumpFilterTrace("ACTION_ACCEPT",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); #endif // ZT_RULES_ENGINE_DEBUGGING - return 1; // match, accept packet + return DOZTFILTER_ACCEPT; // match, accept packet } else { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_ACCEPT",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); + _dumpFilterTrace("ACTION_ACCEPT",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); dlog.clear(); #endif // ZT_RULES_ENGINE_DEBUGGING - thisSetMatches = 1; // no match, evaluate next set + thisSetMatches = 1; } continue; + case ZT_NETWORK_RULE_ACTION_TEE: case ZT_NETWORK_RULE_ACTION_REDIRECT: { const Address fwdAddr(rules[rn].v.fwd.address); - if (fwdAddr == RR->identity.address()) { - // If we are the TEE or REDIRECT destination, don't TEE or REDIRECT - // to self. We should also accept here instead of interpreting - // REDIRECT as DROP since we are the destination. + if (fwdAddr == ztSource) { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"TEE/REDIRECT resulted in 'super-accept' since we are destination"); + _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"TEE/REDIRECT ignored since source is target"); #endif // ZT_RULES_ENGINE_DEBUGGING - return 2; // we should "super-accept" this packet since we are the TEE or REDIRECT destination - } else { - if (!noRedirect) { - Packet outp(fwdAddr,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(nconf.networkId); - outp.append((uint8_t)( ((rt == ZT_NETWORK_RULE_ACTION_REDIRECT) ? 0x04 : 0x02) | (inbound ? 0x08 : 0x00) )); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,(rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen); - outp.compress(); - RR->sw->send(outp,true); + thisSetMatches = 1; + } else if (fwdAddr == RR->identity.address()) { + if (inbound) { +#ifdef ZT_RULES_ENGINE_DEBUGGING + _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"TEE/REDIRECT interpreted as super-accept since we are target"); +#endif // ZT_RULES_ENGINE_DEBUGGING + return DOZTFILTER_SUPER_ACCEPT; + } else { +#ifdef ZT_RULES_ENGINE_DEBUGGING + _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"TEE/REDIRECT ignored on outbound since we are target"); +#endif // ZT_RULES_ENGINE_DEBUGGING + thisSetMatches = 1; } - + } else if (fwdAddr == ztDest) { +#ifdef ZT_RULES_ENGINE_DEBUGGING + _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"TEE/REDIRECT ignored since destination is target"); +#endif // ZT_RULES_ENGINE_DEBUGGING + thisSetMatches = 1; + } else { if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_REDIRECT",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(noRedirect) ? "second-pass match, not actually redirecting" : (const char *)0); + _dumpFilterTrace("ACTION_REDIRECT",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); #endif // ZT_RULES_ENGINE_DEBUGGING - return -1; // match, drop packet (we redirected it) + ztDest = fwdAddr; + return DOZTFILTER_REDIRECT; } else { #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_TEE",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(noRedirect) ? "second-pass match, not actually teeing" : (const char *)0); + _dumpFilterTrace("ACTION_TEE",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); dlog.clear(); #endif // ZT_RULES_ENGINE_DEBUGGING - thisSetMatches = 1; // TEE does not terminate evaluation + cc = fwdAddr; + ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; + thisSetMatches = 1; } } } continue; + case ZT_NETWORK_RULE_ACTION_DEBUG_LOG: // a no-op target specifically for debugging purposes #ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_DEBUG_LOG",thisSetMatches,noRedirect,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); + _dumpFilterTrace("ACTION_DEBUG_LOG",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); dlog.clear(); #endif // ZT_RULES_ENGINE_DEBUGGING - thisSetMatches = 1; // DEBUG_LOG does not terminate evaluation + thisSetMatches = 1; continue; default: break; @@ -547,7 +562,7 @@ static int _doZtFilter( thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); } - return 0; + return DOZTFILTER_NO_MATCH; } const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); @@ -614,7 +629,7 @@ Network::~Network() } bool Network::filterOutgoingPacket( - const bool noRedirect, + const bool noTee, const Address &ztSource, const Address &ztDest, const MAC &macSource, @@ -626,39 +641,94 @@ bool Network::filterOutgoingPacket( { uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; + Address ztDest2(ztDest); + Address cc; + unsigned int ccLength = 0; + bool mainRuleTableMatch = false; + bool accept = false; Mutex::Lock _l(_lock); Membership &m = _memberships[ztDest]; const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); - switch(_doZtFilter(RR,noRedirect,_config,false,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: - if (ztDest) - m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,(const Capability *)0); + switch(_doZtFilter(RR,_config,false,ztSource,ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + case DOZTFILTER_NO_MATCH: + break; + case DOZTFILTER_DROP: return false; - case 1: - case 2: - if (ztDest) - m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,(const Capability *)0); - return true; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side + mainRuleTableMatch = true; + accept = true; + break; } - for(unsigned int c=0;c<_config.capabilityCount;++c) { - switch (_doZtFilter(RR,noRedirect,_config,false,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: - if (ztDest) - m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,(const Capability *)0); - return false; - case 1: - case 2: - if (ztDest) - m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,&(_config.capabilities[c])); - return true; + const Capability *relevantCap = (const Capability *)0; + if (!mainRuleTableMatch) { + for(unsigned int c=0;c<_config.capabilityCount;++c) { + ztDest2 = ztDest; // sanity check + Address cc2; + unsigned int ccLength2 = 0; + switch (_doZtFilter(RR,_config,false,ztSource,ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + case DOZTFILTER_NO_MATCH: + case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern + break; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side + if ((!noTee)&&(cc2)) { + Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength2); + outp.compress(); + RR->sw->send(outp,true); + } + relevantCap = &(_config.capabilities[c]); + accept = true; + break; + } + if (accept) + break; } } - return false; + if (accept) { + if (ztDest2) + m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest2,_config,relevantCap); + + if ((!noTee)&&(cc)) { + Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength); + outp.compress(); + RR->sw->send(outp,true); + } + + if (ztDest != ztDest2) { + Packet outp(ztDest2,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,frameLen); + outp.compress(); + RR->sw->send(outp,true); + return false; // DROP locally, since we redirected + } + } + + return accept; } int Network::filterIncomingPacket( @@ -673,29 +743,97 @@ int Network::filterIncomingPacket( { uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; + Address ztDest2(ztDest); + Address cc; + unsigned int ccLength = 0; + bool mainRuleTableMatch = false; + int accept = 0; Mutex::Lock _l(_lock); Membership &m = _memberships[ztDest]; const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); - switch (_doZtFilter(RR,false,_config,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: return 0; // DROP - case 1: return 1; // ACCEPT - case 2: return 2; // super-ACCEPT + switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + case DOZTFILTER_NO_MATCH: + break; + case DOZTFILTER_DROP: + return 0; // DROP + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + mainRuleTableMatch = true; + accept = 1; // ACCEPT + break; + case DOZTFILTER_SUPER_ACCEPT: + mainRuleTableMatch = true; + accept = 2; // super-ACCEPT + break; } - Membership::CapabilityIterator mci(m); - const Capability *c; - while ((c = mci.next(_config))) { - switch(_doZtFilter(RR,false,_config,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: return 0; // DROP - case 1: return 1; // ACCEPT - case 2: return 2; // super-ACCEPT + if (!mainRuleTableMatch) { + Membership::CapabilityIterator mci(m); + const Capability *c; + while ((c = mci.next(_config))) { + ztDest2 = ztDest; // sanity check + Address cc2; + unsigned int ccLength2 = 0; + switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + case DOZTFILTER_NO_MATCH: + case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern + break; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; // ACCEPT + break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; // super-ACCEPT + break; + } + if (accept) { + if (cc2) { + Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength2); + outp.compress(); + RR->sw->send(outp,true); + } + break; + } + } + } + + if (accept) { + if (cc) { + Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,ccLength); + outp.compress(); + RR->sw->send(outp,true); + } + + if (ztDest != ztDest2) { + Packet outp(ztDest2,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,frameLen); + outp.compress(); + RR->sw->send(outp,true); + return 0; // DROP locally, since we redirected } } - return 0; // DROP + return accept; } bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const diff --git a/node/Network.hpp b/node/Network.hpp index aa4b67f8..45a51bf2 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -82,11 +82,10 @@ public: * Apply filters to an outgoing packet * * This applies filters from our network config and, if that doesn't match, - * our capabilities in ascending order of capability ID. If there is a match - * certain actions may be taken such as pushing credentials to ztDest and - * sending a copy of the packet to a TEE or REDIRECT target. + * our capabilities in ascending order of capability ID. Additional actions + * such as TEE may be taken, and credentials may be pushed. * - * @param noRedirect If true, do not TEE or REDIRECT -- this is set for secondary filtrations done in multicast and bridge send paths + * @param noTee If true, do not TEE anything anywhere * @param ztSource Source ZeroTier address * @param ztDest Destination ZeroTier address * @param macSource Ethernet layer source address @@ -95,10 +94,10 @@ public: * @param frameLen Ethernet frame payload length * @param etherType 16-bit ethernet type ID * @param vlanId 16-bit VLAN ID - * @return True if packet should be sent to destination peer + * @return True if packet should be sent, false if dropped or redirected */ bool filterOutgoingPacket( - const bool noRedirect, + const bool noTee, const Address &ztSource, const Address &ztDest, const MAC &macSource, diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 6b583e7c..33c28f65 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -86,10 +86,11 @@ void OutboundMulticast::init( void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toAddr) { const SharedPtr nw(RR->node->network(_nwid)); - if ((nw)&&(nw->filterOutgoingPacket(true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { + Address toAddr2(toAddr); + if ((nw)&&(nw->filterOutgoingPacket(true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); - _packet.setDestination(toAddr); + _packet.setDestination(toAddr2); RR->sw->send(_packet,true); } } diff --git a/node/Packet.hpp b/node/Packet.hpp index 570bace9..27e289fd 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -655,9 +655,8 @@ public: * * Flags: * 0x01 - Certificate of network membership attached (DEPRECATED) - * 0x02 - Packet is a TEE'd packet - * 0x04 - Packet is a REDIRECT'ed packet - * 0x08 - TEE/REDIRECT'ed packet is on inbound side of connection + * 0x02 - This is a TEE'd or REDIRECT'ed packet + * 0x04 - TEE/REDIRECT'ed packet is from inbound side * * An extended frame carries full MAC addressing, making them a * superset of VERB_FRAME. They're used for bridging or when we diff --git a/node/Switch.cpp b/node/Switch.cpp index 546c9157..8e41c89f 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -437,10 +437,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len); - // We filter with a NULL destination ZeroTier address first. Filtrations - // for each ZT destination are also done in OutboundMulticast, but these - // set noRedirect to true. This prevents multiple TEEs and REDIRECTs for - // multicast packets. + // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; -- cgit v1.2.3 From e8f6b4b5d33e7b762b952d599e8cc9e730b21c03 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 11:51:33 -0700 Subject: Rest of big Path canonicalization refactor. --- node/Constants.hpp | 36 ++--- node/IncomingPacket.cpp | 290 ++++++++++++++++++++-------------------- node/Node.cpp | 18 +-- node/Path.hpp | 82 ++++-------- node/Peer.cpp | 348 ++++++++++++++++++++++++++---------------------- node/Peer.hpp | 166 ++++++++++------------- node/Switch.cpp | 24 ++-- 7 files changed, 461 insertions(+), 503 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 8a596fb3..6d6f44e0 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -238,46 +238,38 @@ */ #define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000 -/** - * Default maximum number of peers to address with a single multicast (if unspecified in network config) - */ -#define ZT_MULTICAST_DEFAULT_LIMIT 32 - -/** - * How frequently to send a zero-byte UDP keepalive packet - * - * There are NATs with timeouts as short as 20 seconds, so this turns out - * to be needed. - */ -#define ZT_NAT_KEEPALIVE_DELAY 19000 - /** * Delay between scans of the topology active peer DB for peers that need ping * * This is also how often pings will be retried to upstream peers (relays, roots) * constantly until something is heard. */ -#define ZT_PING_CHECK_INVERVAL 9500 +#define ZT_PING_CHECK_INVERVAL 8000 /** - * Delay between ordinary case pings of direct links + * How frequently to send heartbeats over in-use paths */ -#define ZT_PEER_DIRECT_PING_DELAY 60000 +#define ZT_PATH_HEARTBEAT_PERIOD 18000 /** - * Timeout for overall peer activity (measured from last receive) + * Paths are considered inactive if they have not received traffic in this long */ -#define ZT_PEER_ACTIVITY_TIMEOUT 500000 +#define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_HEARTBEAT_PERIOD * 2) + 2000) /** - * No answer timeout to trigger dead path detection + * Delay between full-fledge pings of directly connected peers */ -#define ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT 2000 +#define ZT_PEER_PING_PERIOD 60000 /** - * Probation threshold after which a path becomes dead + * Peers forget paths that have not spoken in this long */ -#define ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION 3 +#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 3) + 3000) + +/** + * Timeout for overall peer activity (measured from last receive) + */ +#define ZT_PEER_ACTIVITY_TIMEOUT 500000 /** * Delay between requests for updated network autoconf information diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 4b013078..fafd5679 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -54,11 +54,11 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) // If this is marked as a packet via a trusted path, check source address and path ID. // Obviously if no trusted paths are configured this always returns false and such // packets are dropped on the floor. - if (RR->topology->shouldInboundPathBeTrusted(_remoteAddress,trustedPathId())) { + if (RR->topology->shouldInboundPathBeTrusted(_path->address(),trustedPathId())) { trusted = true; - TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId()); + TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId()); } else { - TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId(),_remoteAddress.toString().c_str()); + TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId(),_path->address().toString().c_str()); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -73,42 +73,42 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { - TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),size()); + TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); return true; } } if (!uncompress()) { - TRACE("dropped packet from %s(%s), compressed data invalid",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped packet from %s(%s), compressed data invalid",sourceAddress.toString().c_str(),_path->address().toString().c_str()); return true; } const Packet::Verb v = verb(); - //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_path->address().toString().c_str()); switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,peer); - case Packet::VERB_ERROR: return _doERROR(RR,peer); - case Packet::VERB_OK: return _doOK(RR,peer); - case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); - case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer); - case Packet::VERB_FRAME: return _doFRAME(RR,peer); - 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_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); - case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); - case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); - case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); - case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); - case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); - case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer); + case Packet::VERB_HELLO: return _doHELLO(RR,peer); + case Packet::VERB_ERROR: return _doERROR(RR,peer); + case Packet::VERB_OK: return _doOK(RR,peer); + case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); + case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer); + case Packet::VERB_FRAME: return _doFRAME(RR,peer); + 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_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); + case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); + case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); + case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); + case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); + case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); + case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); + case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); + case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer); case Packet::VERB_USER_MESSAGE: return true; } @@ -119,7 +119,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } catch ( ... ) { // Exceptions are more informatively caught in _do...() handlers but // this outer try/catch will catch anything else odd. - TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_path->address().toString().c_str()); return true; } } @@ -131,7 +131,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); + //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(errorCode) { @@ -172,9 +172,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -216,11 +216,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; } @@ -235,18 +235,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_path->address().toString().c_str()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_HELLO); outp.append((uint64_t)pid); outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); } } else { - TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_path->address().toString().c_str()); } return true; @@ -254,7 +254,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } @@ -265,14 +265,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // Check identity proof of work if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } // Check packet integrity and authentication SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } peer = RR->topology->addPeer(newPeer); @@ -284,7 +284,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } if (externalSurfaceAddress) - RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); + RR->sa->iam(id.address(),_path->localAddress(),_path->address(),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); @@ -295,7 +295,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); if (protoVersion >= 5) { - _remoteAddress.serialize(outp); + _path->address().serialize(outp); } else { /* LEGACY COMPATIBILITY HACK: * @@ -320,7 +320,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer * 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); + InetAddress tmpa(_path->address()); tmpa.setPort(0); tmpa.serialize(outp); } @@ -336,12 +336,12 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -352,7 +352,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); + //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { @@ -364,7 +364,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p 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()); + TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_path->address().toString().c_str()); return true; } @@ -386,13 +386,13 @@ 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,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if (externalSurfaceAddress) - RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: { @@ -414,7 +414,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p totalSize = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen); chunkIndex = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4); } - TRACE("%s(%s): OK(NETWORK_CONFIG_REQUEST) chunkLen==%u chunkIndex==%u totalSize==%u",source().toString().c_str(),_remoteAddress.toString().c_str(),chunkLen,chunkIndex,totalSize); + TRACE("%s(%s): OK(NETWORK_CONFIG_REQUEST) chunkLen==%u chunkIndex==%u totalSize==%u",source().toString().c_str(),_path->address().toString().c_str(),chunkLen,chunkIndex,totalSize); network->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize); } } break; @@ -425,7 +425,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),size()); + //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } break; @@ -435,7 +435,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),flags); + //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); unsigned int offset = 0; @@ -461,9 +461,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -502,12 +502,12 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr if (count > 0) { outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -524,24 +524,22 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (!RR->topology->isUpstream(peer->identity())) { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { - const uint64_t now = RR->node->now(); - peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) - peer->sendHELLO(_localAddress,atAddr,now); + } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { + RR->node->putPacket(_path->localAddress(),atAddr,"NATSUX",6,2); // send low-TTL packet to 'open' local NAT(s) + peer->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); } } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -553,8 +551,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr if (network) { 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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); } else { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); const MAC sourceMac(peer->address(),network->id()); @@ -562,14 +560,14 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); } } } else { - TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } } catch ( ... ) { - TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -591,8 +589,8 @@ 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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -603,8 +601,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -614,14 +612,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -631,13 +629,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } } else { - TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } } catch ( ... ) { - TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -652,10 +650,10 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -672,9 +670,9 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -721,9 +719,9 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped NETWORK_CREDENTIALS 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(),_path->address().toString().c_str()); } return true; } @@ -744,7 +742,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons if (RR->localNetworkController) { NetworkConfig *netconf = new NetworkConfig(); try { - switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,*netconf)) { + switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) { case NetworkController::NETCONF_QUERY_OK: { netconfOk = true; @@ -783,7 +781,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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } break; case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { @@ -793,7 +791,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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } break; case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: @@ -816,16 +814,16 @@ 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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); + TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { fprintf(stderr,"WARNING: network config request failed with exception: unknown exception" ZT_EOL_S); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -840,8 +838,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons if (network) { network->requestConfiguration(); } else { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); return true; } @@ -853,9 +851,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -868,7 +866,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); if ((flags & 0x01) != 0) { try { @@ -880,7 +878,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar network->addCredential(com); } } catch ( ... ) { - TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); } } @@ -892,9 +890,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); - if (gatheredLocally) { + if (gatheredLocally > 0) { outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } // If we are a member of a cluster, distribute this GATHER across it @@ -904,9 +902,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -933,8 +931,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share // Check membership after we've read any included COM, since // 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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -960,13 +958,13 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -974,8 +972,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -996,16 +994,16 @@ 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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { - TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1017,8 +1015,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // 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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1044,12 +1042,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimalPathForAddressFamily(a); + peer->makeExclusive(a); } else { redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->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(InetAddress(),a,now); @@ -1063,12 +1061,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimalPathForAddressFamily(a); + peer->makeExclusive(a); } else { redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->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(InetAddress(),a,now); @@ -1081,9 +1079,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1124,8 +1122,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt // Verify signature -- only tests signed by their originators are allowed const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { - TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1141,13 +1139,13 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (originatorCredentialNetworkId) { SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1165,9 +1163,9 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - Path *const rp = nhp->getBestPath(now); - if (rp) - nextHopBestPathAddress[h] = rp->address(); + SharedPtr nhbp(nhp->getBestPath(now,false)); + if (nhbp) + nextHopBestPathAddress[h] = nhbp->address(); } } } @@ -1190,8 +1188,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint64_t)packetId()); peer->address().appendTo(outp); outp.append((uint8_t)hops()); - _localAddress.serialize(outp); - _remoteAddress.serialize(outp); + _path->localAddress().serialize(outp); + _path->address().serialize(outp); outp.append((uint16_t)0); // no additional fields outp.append((uint8_t)breadth); for(unsigned int h=0;hreceived(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1263,9 +1261,9 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S } RR->node->postCircuitTestReport(&report); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1308,28 +1306,28 @@ 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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); outp.append(pid); outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } break; default: - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_path->address().toString().c_str()); break; } - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); } else { - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); } } catch ( ... ) { - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } diff --git a/node/Node.cpp b/node/Node.cpp index ff564eee..39e24325 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -415,16 +415,16 @@ 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()); - Path *bestPath = pi->second->getBestPath(_now); + std::vector< SharedPtr > paths(pi->second->paths()); + SharedPtr bestp(pi->second->getBestPath(_now,true)); p->pathCount = 0; - 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(); - p->paths[p->pathCount].active = path->active(_now) ? 1 : 0; - p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0; - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->address()); + for(std::vector< SharedPtr >::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)->lastOut(); + p->paths[p->pathCount].lastReceive = (*path)->lastIn(); + p->paths[p->pathCount].active = (*path)->alive(_now) ? 1 : 0; + p->paths[p->pathCount].preferred = (*path == bestp) ? 1 : 0; + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); ++p->pathCount; } } diff --git a/node/Path.hpp b/node/Path.hpp index f8d84d4b..68a630c3 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -105,8 +105,7 @@ public: _lastIn(0), _addr(), _localAddress(), - _ipScope(InetAddress::IP_SCOPE_NONE), - _clusterSuboptimal(false) + _ipScope(InetAddress::IP_SCOPE_NONE) { } @@ -115,27 +114,10 @@ public: _lastIn(0), _addr(addr), _localAddress(localAddress), - _ipScope(addr.ipScope()), - _clusterSuboptimal(false) + _ipScope(addr.ipScope()) { } - inline Path &operator=(const Path &p) - { - if (this != &p) - memcpy(this,&p,sizeof(Path)); - return *this; - } - - /** - * 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(const uint64_t t) { _lastOut = t; } - /** * Called when a packet is received from this remote path, regardless of content * @@ -157,37 +139,22 @@ public: /** * @return Address of local side of this path or NULL if unspecified */ - inline const InetAddress &localAddress() const throw() { return _localAddress; } + inline const InetAddress &localAddress() const { return _localAddress; } /** * @return Physical address */ - inline const InetAddress &address() const throw() { return _addr; } + inline const InetAddress &address() const { return _addr; } /** * @return IP scope -- faster shortcut for address().ipScope() */ - inline InetAddress::IpScope ipScope() const throw() { return _ipScope; } - - /** - * @param f Is this path cluster-suboptimal? - */ - inline void setClusterSuboptimal(const bool f) { _clusterSuboptimal = f; } - - /** - * @return True if cluster-suboptimal (for someone) - */ - inline bool isClusterSuboptimal() const { return _clusterSuboptimal; } - - /** - * @return True if cluster-optimal (for someone) (the default) - */ - inline bool isClusterOptimal() const { return (!(_clusterSuboptimal)); } + inline InetAddress::IpScope ipScope() const { return _ipScope; } /** * @return Preference rank, higher == better (will be less than 255) */ - inline unsigned int preferenceRank() const throw() + inline unsigned int preferenceRank() const { /* First, since the scope enum values in InetAddress.hpp are in order of * use preference rank, we take that. Then we multiple by two, yielding @@ -201,20 +168,9 @@ public: /** * @return This path's overall quality score (higher is better) */ - inline uint64_t score() const throw() + inline uint64_t score() const { - // This is a little bit convoluted because we try to be branch-free, using multiplication instead of branches for boolean flags - - // Start with the last time this path was active, and add a fudge factor to prevent integer underflow if _lastReceived is 0 - uint64_t score = _lastIn + (ZT_PEER_DIRECT_PING_DELAY * (ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION + 1)); - - // Increase score based on path preference rank, which is based on IP scope and address family - score += preferenceRank() * (ZT_PEER_DIRECT_PING_DELAY / ZT_PATH_MAX_PREFERENCE_RANK); - - // Decrease score if this is known to be a sub-optimal path to a cluster - score -= ((uint64_t)_clusterSuboptimal) * ZT_PEER_DIRECT_PING_DELAY; - - return score; + return (_lastIn + (preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))); } /** @@ -227,7 +183,6 @@ public: * @return True if address is good for ZeroTier path use */ static inline bool isAddressValidForPath(const InetAddress &a) - throw() { if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) { switch(a.ipScope()) { @@ -258,6 +213,26 @@ public: return false; } + /** + * @return True if path appears alive + */ + inline bool alive(const uint64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } + + /** + * @return True if this path needs a heartbeat + */ + inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) > ZT_PATH_HEARTBEAT_PERIOD); } + + /** + * @return Last time we sent something + */ + inline uint64_t lastOut() const { return _lastOut; } + + /** + * @return Last time we received anything + */ + inline uint64_t lastIn() const { return _lastIn; } + private: uint64_t _lastOut; uint64_t _lastIn; @@ -265,7 +240,6 @@ private: InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often AtomicCounter __refCount; - bool _clusterSuboptimal; }; } // namespace ZeroTier diff --git a/node/Peer.cpp b/node/Peer.cpp index 01492be1..251c5a5f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,8 +27,6 @@ #include "Cluster.hpp" #include "Packet.hpp" -#include - #define ZT_PEER_PATH_SORT_INTERVAL 5000 namespace ZeroTier { @@ -45,7 +43,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastAnnouncedTo(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), - _lastPathSort(0), _vProto(0), _vMajor(0), _vMinor(0), @@ -60,8 +57,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident } void Peer::received( - const InetAddress &localAddr, - const InetAddress &remoteAddr, + const SharedPtr &path, unsigned int hops, uint64_t packetId, Packet::Verb verb, @@ -69,13 +65,15 @@ void Peer::received( Packet::Verb inReVerb, const bool trustEstablished) { + const uint64_t now = RR->node->now(); + #ifdef ZT_ENABLE_CLUSTER bool suboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { // Note: findBetterEndpoint() is first since we still want to check // for a better endpoint even if we don't actually send a redirect. InetAddress redirectTo; - if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),remoteAddr,false)) ) { + if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),path->address(),false)) ) { if (_vProto >= 5) { // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS. Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); @@ -93,7 +91,7 @@ void Peer::received( } outp.append((uint16_t)redirectTo.port()); outp.armor(_key,true); - RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); + path->send(RR,outp.data(),outp.size(),now); } else { // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -108,14 +106,13 @@ void Peer::received( outp.append(redirectTo.rawIpData(),16); } outp.armor(_key,true); - RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); + path->send(RR,outp.data(),outp.size(),now); } suboptimalPath = true; } } #endif - const uint64_t now = RR->node->now(); _lastReceive = now; if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME)) _lastUnicastFrame = now; @@ -124,53 +121,47 @@ void Peer::received( if (hops == 0) { bool pathIsConfirmed = false; - unsigned int np = _numPaths; - for(unsigned int p=0;pnode->shouldUsePathForZeroTierTraffic(localAddr,remoteAddr))) { + if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address()))) { if (verb == Packet::VERB_OK) { + Mutex::Lock _l(_paths_m); - Path *slot = (Path *)0; - if (np < ZT_MAX_PEER_NETWORK_PATHS) { - slot = &(_paths[np++]); + unsigned int slot = 0; + if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { + slot = _numPaths++; } else { - uint64_t slotWorstScore = 0xffffffffffffffffULL; - for(unsigned int p=0;preceived(now); -#ifdef ZT_ENABLE_CLUSTER - slot->setClusterSuboptimal(suboptimalPath); -#endif - _numPaths = np; + slot = oldestPath; } + _paths[slot].path = path; + _paths[slot].lastReceive = now; #ifdef ZT_ENABLE_CLUSTER + _paths[slot].clusterSuboptimal = suboptimalPath; + if (RR->cluster) RR->cluster->broadcastHavePeer(_id); #endif - } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str()); @@ -178,15 +169,15 @@ void Peer::received( if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); outp.armor(_key,true); - RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); + path->send(RR,outp.data(),outp.size(),now); } else { - sendHELLO(localAddr,remoteAddr,now); + sendHELLO(path->localAddress(),path->address(),now); } } } } else if (trustEstablished) { - _pushDirectPaths(localAddr,remoteAddr,now); + _pushDirectPaths(path,now); } if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { @@ -197,7 +188,96 @@ void Peer::received( } } -void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl) +bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const +{ + Mutex::Lock _l(_paths_m); + for(unsigned int p=0;p<_numPaths;++p) { + if ( (_paths[p].path->address() == addr) && (_paths[p].path->alive(now)) ) + return true; + } + return false; +} + +void Peer::makeExclusive(const InetAddress &addr) +{ + Mutex::Lock _l(_paths_m); + + bool have = false; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->address() == addr) { + have = true; + break; + } + } + + if (have) { + unsigned int np = _numPaths; + unsigned int x = 0; + unsigned int y = 0; + while (x < np) { + if ((_paths[x].path->address().ss_family != addr.ss_family)||(_paths[x].path->address() == addr)) { + if (y != x) { + _paths[y].path = _paths[x].path; + _paths[y].lastReceive = _paths[x].lastReceive; + #ifdef ZT_ENABLE_CLUSTER + _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; + #endif + } + ++y; + } + ++x; + } + _numPaths = y; + } +} + +bool Peer::send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +{ + Mutex::Lock _l(_paths_m); + + int bestp = -1; + uint64_t best = 0ULL; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->alive(now)||(forceEvenIfDead)) { + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; + } + } + } + + if (bestp >= 0) { + return _paths[bestp].path->send(RR,data,len,now); + } else { + return false; + } +} + +SharedPtr Peer::getBestPath(uint64_t now,bool forceEvenIfDead) +{ + Mutex::Lock _l(_paths_m); + + int bestp = -1; + uint64_t best = 0ULL; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->alive(now)||(forceEvenIfDead)) { + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; + } + } + } + + if (bestp >= 0) { + return _paths[bestp].path; + } else { + return SharedPtr(); + } +} + +void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); outp.append((unsigned char)ZT_PROTO_VERSION); @@ -209,51 +289,56 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u atAddress.serialize(outp); outp.append((uint64_t)RR->topology->worldId()); outp.append((uint64_t)RR->topology->worldTimestamp()); - outp.armor(_key,false); // HELLO is sent in the clear - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size(),ttl); + RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { - Path *p = (Path *)0; - - if (inetAddressFamily != 0) { - p = _getBestPath(now,inetAddressFamily); - } else { - p = _getBestPath(now); - } - - if (p) { - if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { - //TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); - sendHELLO(p->localAddress(),p->address(),now); - p->sent(now); - p->pinged(now); - } else if ((now - std::max(p->lastSend(),p->lastKeepalive())) >= ZT_NAT_KEEPALIVE_DELAY) { - //TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); + bool somethingAlive = false; + Mutex::Lock _l(_paths_m); + for(unsigned int p=0;p<_numPaths;++p) { + if ((now - _paths[p].lastReceive) >= ZT_PEER_PING_PERIOD) { + sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); + } else if (_paths[p].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); - p->sentKeepalive(now); + _paths[p].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); } - return true; + somethingAlive |= _paths[p].path->alive(now); } + return somethingAlive; +} +bool Peer::hasActiveDirectPath(uint64_t now) const +{ + Mutex::Lock _l(_paths_m); + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->alive(now)) + return true; + } return false; } bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) { + Mutex::Lock _l(_paths_m); unsigned int np = _numPaths; unsigned int x = 0; unsigned int y = 0; while (x < np) { - if (_paths[x].address().ipScope() == scope) { + if (_paths[x].path->address().ipScope() == scope) { // Resetting a path means sending a HELLO and then forgetting it. If we // get OK(HELLO) then it will be re-learned. - sendHELLO(_paths[x].localAddress(),_paths[x].address(),now); + sendHELLO(_paths[x].path->localAddress(),_paths[x].path->address(),now); } else { - _paths[y++] = _paths[x]; + if (x != y) { + _paths[y].path = _paths[x].path; + _paths[y].lastReceive = _paths[x].lastReceive; +#ifdef ZT_ENABLE_CLUSTER + _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; +#endif + } + ++y; } ++x; } @@ -263,114 +348,55 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const { - uint64_t bestV4 = 0,bestV6 = 0; - for(unsigned int p=0,np=_numPaths;p= bestV4) { - bestV4 = lr; - v4 = _paths[p].address(); - } - } else if (_paths[p].address().isV6()) { - if (lr >= bestV6) { - bestV6 = lr; - v6 = _paths[p].address(); - } - } + Mutex::Lock _l(_paths_m); + + int bestp4 = -1,bestp6 = -1; + uint64_t best4 = 0ULL,best6 = 0ULL; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->address().ss_family == AF_INET) { + const uint64_t s = _paths[p].path->score(); + if (s >= best4) { + best4 = s; + bestp4 = (int)p; + } + } else if (_paths[p].path->address().ss_family == AF_INET6) { + const uint64_t s = _paths[p].path->score(); + if (s >= best6) { + best6 = s; + bestp6 = (int)p; } } } + + if (bestp4 >= 0) + v4 = _paths[bestp4].path->address(); + if (bestp6 >= 0) + v6 = _paths[bestp6].path->address(); } void Peer::clean(uint64_t now) { + Mutex::Lock _l(_paths_m); unsigned int np = _numPaths; unsigned int x = 0; unsigned int y = 0; while (x < np) { - if (_paths[x].active(now)) - _paths[y++] = _paths[x]; + if ((now - _paths[x].lastReceive) <= ZT_PEER_PATH_EXPIRATION) { + if (y != x) { + _paths[y].path = _paths[x].path; + _paths[y].lastReceive = _paths[x].lastReceive; +#ifdef ZT_ENABLE_CLUSTER + _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; +#endif + } + ++y; + } ++x; } _numPaths = y; } -void Peer::_doDeadPathDetection(Path &p,const uint64_t now) -{ - /* Dead path detection: if we have sent something to this peer and have not - * yet received a reply, double check this path. The majority of outbound - * packets including Ethernet frames do generate some kind of reply either - * immediately or at some point in the near future. This will occasionally - * (every NO_ANSWER_TIMEOUT ms) check paths unnecessarily if traffic that - * does not generate a response is being sent such as multicast announcements - * or frames belonging to unidirectional UDP protocols, but the cost is very - * tiny and the benefit in reliability is very large. This takes care of many - * failure modes including crap NATs that forget links and spurious changes - * to physical network topology that cannot be otherwise detected. - * - * Each time we do this we increment a probation counter in the path. This - * counter is reset on any packet receive over this path. If it reaches the - * MAX_PROBATION threshold the path is considred dead. */ - - if ( - (p.lastSend() > p.lastReceived()) && - ((p.lastSend() - p.lastReceived()) >= ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT) && - ((now - p.lastPing()) >= ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT) && - (!p.isClusterSuboptimal()) && - (!RR->topology->amRoot()) - ) { - TRACE("%s(%s) does not seem to be answering in a timely manner, checking if dead (probation == %u)",_id.address().toString().c_str(),p.address().toString().c_str(),p.probation()); - - if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); - outp.armor(_key,true); - p.send(RR,outp.data(),outp.size(),now); - p.pinged(now); - } else { - sendHELLO(p.localAddress(),p.address(),now); - p.sent(now); - p.pinged(now); - } - - p.increaseProbation(); - } -} - -Path *Peer::_getBestPath(const uint64_t now) -{ - Path *bestPath = (Path *)0; - uint64_t bestPathScore = 0; - for(unsigned int i=0;i<_numPaths;++i) { - const uint64_t score = _paths[i].score(); - if ((score >= bestPathScore)&&(_paths[i].active(now))) { - bestPathScore = score; - bestPath = &(_paths[i]); - } - } - if (bestPath) - _doDeadPathDetection(*bestPath,now); - return bestPath; -} - -Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) -{ - Path *bestPath = (Path *)0; - uint64_t bestPathScore = 0; - for(unsigned int i=0;i<_numPaths;++i) { - const uint64_t score = _paths[i].score(); - if (((int)_paths[i].address().ss_family == inetAddressFamily)&&(score >= bestPathScore)&&(_paths[i].active(now))) { - bestPathScore = score; - bestPath = &(_paths[i]); - } - } - if (bestPath) - _doDeadPathDetection(*bestPath,now); - return bestPath; -} - -bool Peer::_pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now) +bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) { #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection @@ -445,7 +471,7 @@ bool Peer::_pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAd if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); outp.armor(_key,true); - RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0); + path->send(RR,outp.data(),outp.size(),now); } } diff --git a/node/Peer.hpp b/node/Peer.hpp index a6940737..ff32184f 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -96,9 +96,7 @@ public: * This is called by the decode pipe when a packet is proven to be authentic * and appears to be valid. * - * @param RR Runtime environment - * @param localAddr Local address - * @param remoteAddr Internet address of sender + * @param path Path over which packet was received * @param hops ZeroTier (not IP) hops * @param packetId Packet ID * @param verb Packet verb @@ -107,8 +105,7 @@ public: * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established */ void received( - const InetAddress &localAddr, - const InetAddress &remoteAddr, + const SharedPtr &path, unsigned int hops, uint64_t packetId, Packet::Verb verb, @@ -116,43 +113,19 @@ public: Packet::Verb inReVerb, const bool trustEstablished); - /** - * Get the current best direct path to this peer - * - * @param now Current time - * @return Best path or NULL if there are no active direct paths - */ - inline Path *getBestPath(uint64_t now) { return _getBestPath(now); } - /** * @param now Current time * @param addr Remote address * @return True if we have an active path to this destination */ - inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const - { - for(unsigned int p=0;p<_numPaths;++p) { - if ((_paths[p].active(now))&&(_paths[p].address() == addr)) - return true; - } - return false; - } + bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; /** - * Set all paths in the same ss_family that are not this one to cluster suboptimal - * - * Addresses in other families are not affected. + * If we have a confirmed path to this address, forget all others within the same address family * * @param addr Address to make exclusive */ - inline void setClusterOptimalPathForAddressFamily(const InetAddress &addr) - { - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].address().ss_family == addr.ss_family) { - _paths[p].setClusterSuboptimal(_paths[p].address() != addr); - } - } - } + void makeExclusive(const InetAddress &addr); /** * Send via best path @@ -160,30 +133,30 @@ public: * @param data Packet data * @param len Packet length * @param now Current time - * @return Path used on success or NULL on failure + * @param forceEvenIfDead If true, send even if the path is not 'alive' + * @return True if we actually sent something */ - inline Path *send(const void *data,unsigned int len,uint64_t now) - { - Path *const bestPath = getBestPath(now); - if (bestPath) { - if (bestPath->send(RR,data,len,now)) - return bestPath; - } - return (Path *)0; - } + bool send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + + /** + * Get the best current direct path + * + * @param now Current time + * @param forceEvenIfDead If true, pick even if path is not alive + * @return Best current path or NULL if none + */ + SharedPtr getBestPath(uint64_t now,bool forceEvenIfDead); /** * Send a HELLO to this peer at a specified physical address * - * This does not update any statistics. It's used to send initial HELLOs - * for NAT traversal and path verification. + * No statistics or sent times are updated here. * * @param localAddr Local address * @param atAddress Destination address * @param now Current time - * @param ttl Desired IP TTL (default: 0 to leave alone) */ - void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl = 0); + void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); /** * Send pings or keepalives depending on configured timeouts @@ -194,14 +167,49 @@ public: */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); + /** + * @param now Current time + * @return True if this peer has at least one active direct path + */ + bool hasActiveDirectPath(uint64_t now) const; + + /** + * Reset paths within a given scope + * + * @param scope IP scope of paths to reset + * @param now Current time + * @return True if at least one path was forgotten + */ + bool resetWithinScope(InetAddress::IpScope scope,uint64_t now); + + /** + * Get most recently active path addresses for IPv4 and/or IPv6 + * + * Note that v4 and v6 are not modified if they are not found, so + * initialize these to a NULL address to be able to check. + * + * @param now Current time + * @param v4 Result parameter to receive active IPv4 address, if any + * @param v6 Result parameter to receive active IPv6 address, if any + */ + void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + + /** + * Perform periodic cleaning operations + * + * @param now Current time + */ + void clean(uint64_t now); + /** * @return All known direct paths to this peer (active or inactive) */ - inline std::vector paths() const + inline std::vector< SharedPtr > paths() const { - std::vector pp; + std::vector< SharedPtr > pp; + Mutex::Lock _l(_paths_m); for(unsigned int p=0,np=_numPaths;palive(now)) && (!_paths[p].clusterSuboptimal) ) return true; } return false; } #endif - /** - * Reset paths within a given scope - * - * @param scope IP scope of paths to reset - * @param now Current time - * @return True if at least one path was forgotten - */ - bool resetWithinScope(InetAddress::IpScope scope,uint64_t now); - /** * @return 256-bit secret symmetric encryption key */ @@ -335,25 +321,6 @@ public: inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } - /** - * Get most recently active path addresses for IPv4 and/or IPv6 - * - * Note that v4 and v6 are not modified if they are not found, so - * initialize these to a NULL address to be able to check. - * - * @param now Current time - * @param v4 Result parameter to receive active IPv4 address, if any - * @param v6 Result parameter to receive active IPv6 address, if any - */ - void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; - - /** - * Perform periodic cleaning operations - * - * @param now Current time - */ - void clean(uint64_t now); - /** * Update direct path push stats and return true if we should respond * @@ -395,10 +362,7 @@ public: } private: - void _doDeadPathDetection(Path &p,const uint64_t now); - Path *_getBestPath(const uint64_t now); - Path *_getBestPath(const uint64_t now,int inetAddressFamily); - bool _pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now); + bool _pushDirectPaths(const SharedPtr &path,uint64_t now); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -410,13 +374,19 @@ private: uint64_t _lastAnnouncedTo; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; - uint64_t _lastPathSort; uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; Identity _id; - Path _paths[ZT_MAX_PEER_NETWORK_PATHS]; + struct { + SharedPtr path; + uint64_t lastReceive; +#ifdef ZT_ENABLE_CLUSTER + bool clusterSuboptimal; +#endif + } _paths[ZT_MAX_PEER_NETWORK_PATHS]; + Mutex _paths_m; unsigned int _numPaths; unsigned int _latency; unsigned int _directPathPushCutoffCount; diff --git a/node/Switch.cpp b/node/Switch.cpp index dc238607..ab07d353 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -112,7 +112,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now))) { + if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now,true))) { #ifdef ZT_ENABLE_CLUSTER if (RR->cluster) { RR->cluster->sendViaCluster(Address(),destination,fragment.data(),fragment.size(),false); @@ -123,7 +123,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Don't know peer or no direct path -- so relay via root server relayTo = RR->topology->getBestRoot(); if (relayTo) - relayTo->send(fragment.data(),fragment.size(),now); + relayTo->send(fragment.data(),fragment.size(),now,true); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -210,7 +210,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from packet.incrementHops(); SharedPtr relayTo = RR->topology->getPeer(destination); - if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now)))) { + if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now,true)))) { Mutex::Lock _l(_lastUniteAttempt_m); uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)]; if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) { @@ -234,7 +234,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from #endif relayTo = RR->topology->getBestRoot(&source,1,true); if (relayTo) - relayTo->send(packet.data(),packet.size(),now); + relayTo->send(packet.data(),packet.size(),now,true); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -251,7 +251,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from rq->timestamp = now; rq->packetId = packetId; - rq->frag0.init(data,len,localAddr,fromAddr,now); + rq->frag0.init(data,len,path,now); rq->totalFragments = 0; rq->haveFragments = 1; rq->complete = false; @@ -607,7 +607,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.first.rawIpData(),4); } outp.armor(p1p->key(),true); - p1p->send(outp.data(),outp.size(),now); + p1p->send(outp.data(),outp.size(),now,true); } else { // Tell p2 where to find p1. Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -622,7 +622,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.second.rawIpData(),4); } outp.armor(p2p->key(),true); - p2p->send(outp.data(),outp.size(),now); + p2p->send(outp.data(),outp.size(),now,true); } ++alt; // counts up and also flips LSB } @@ -739,7 +739,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); outp.armor(root->key(),true); - if (root->send(outp.data(),outp.size(),RR->node->now())) + if (root->send(outp.data(),outp.size(),RR->node->now(),true)) return root->address(); } return Address(); @@ -752,12 +752,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) if (peer) { const uint64_t now = RR->node->now(); - Path *viaPath = peer->getBestPath(now); - SharedPtr relay; - + SharedPtr viaPath(peer->getBestPath(now,false)); if (!viaPath) { - relay = RR->topology->getBestRoot(); - if ( (!relay) || (!(viaPath = relay->getBestPath(now))) ) + SharedPtr relay(RR->topology->getBestRoot()); + if ( (!relay) || (!(viaPath = relay->getBestPath(now,true))) ) return false; } -- cgit v1.2.3 From 4f8253dcdb9e6ff2ae18639556811d13729fae2b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 13:33:56 -0700 Subject: Tweaks to path handling... --- node/IncomingPacket.cpp | 4 ++-- node/Node.cpp | 2 +- node/Peer.cpp | 39 ++++++++++++++++++++++++--------------- node/Peer.hpp | 7 +++---- node/Switch.cpp | 21 +++++++++++---------- 5 files changed, 41 insertions(+), 32 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index fafd5679..7ba34566 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1163,8 +1163,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - SharedPtr nhbp(nhp->getBestPath(now,false)); - if (nhbp) + SharedPtr nhbp(nhp->getBestPath(now)); + if ((nhbp)&&(nhbp->alive(now))) nextHopBestPathAddress[h] = nhbp->address(); } } diff --git a/node/Node.cpp b/node/Node.cpp index 39e24325..d2840bd0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -416,7 +416,7 @@ ZT_PeerList *Node::peers() const p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; std::vector< SharedPtr > paths(pi->second->paths()); - SharedPtr bestp(pi->second->getBestPath(_now,true)); + SharedPtr bestp(pi->second->getBestPath(_now)); p->pathCount = 0; for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); diff --git a/node/Peer.cpp b/node/Peer.cpp index 9b5d84fc..a23d0822 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -229,7 +229,7 @@ void Peer::makeExclusive(const InetAddress &addr) } } -bool Peer::send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) { Mutex::Lock _l(_paths_m); @@ -252,19 +252,17 @@ bool Peer::send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfD } } -SharedPtr Peer::getBestPath(uint64_t now,bool forceEvenIfDead) +SharedPtr Peer::getBestPath(uint64_t now) { Mutex::Lock _l(_paths_m); int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->alive(now)||(forceEvenIfDead)) { - const uint64_t s = _paths[p].path->score(); - if (s >= best) { - best = s; - bestp = (int)p; - } + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; } } @@ -293,18 +291,29 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { - bool somethingAlive = false; Mutex::Lock _l(_paths_m); + + int bestp = -1; + uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ((now - _paths[p].lastReceive) >= ZT_PEER_PING_PERIOD) { - sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); - } else if (_paths[p].path->needsHeartbeat(now)) { + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; + } + } + + if (bestp >= 0) { + if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { + sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - _paths[p].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); + _paths[bestp].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); } - somethingAlive |= _paths[p].path->alive(now); + return true; + } else { + return false; } - return somethingAlive; } bool Peer::hasActiveDirectPath(uint64_t now) const diff --git a/node/Peer.hpp b/node/Peer.hpp index ff32184f..87aea486 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -128,7 +128,7 @@ public: void makeExclusive(const InetAddress &addr); /** - * Send via best path + * Send via best direct path * * @param data Packet data * @param len Packet length @@ -136,16 +136,15 @@ public: * @param forceEvenIfDead If true, send even if the path is not 'alive' * @return True if we actually sent something */ - bool send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); /** * Get the best current direct path * * @param now Current time - * @param forceEvenIfDead If true, pick even if path is not alive * @return Best current path or NULL if none */ - SharedPtr getBestPath(uint64_t now,bool forceEvenIfDead); + SharedPtr getBestPath(uint64_t now); /** * Send a HELLO to this peer at a specified physical address diff --git a/node/Switch.cpp b/node/Switch.cpp index ab07d353..125c4b69 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -75,6 +75,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from SharedPtr path(RR->topology->getPath(localAddr,fromAddr)); path->received(now); + printf("<< %s %u\n",fromAddr.toString().c_str(),len); if (len == 13) { /* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast @@ -112,7 +113,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now,true))) { + if ((!relayTo)||(!relayTo->sendDirect(fragment.data(),fragment.size(),now,false))) { #ifdef ZT_ENABLE_CLUSTER if (RR->cluster) { RR->cluster->sendViaCluster(Address(),destination,fragment.data(),fragment.size(),false); @@ -123,7 +124,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Don't know peer or no direct path -- so relay via root server relayTo = RR->topology->getBestRoot(); if (relayTo) - relayTo->send(fragment.data(),fragment.size(),now,true); + relayTo->sendDirect(fragment.data(),fragment.size(),now,true); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -210,7 +211,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from packet.incrementHops(); SharedPtr relayTo = RR->topology->getPeer(destination); - if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now,true)))) { + if ((relayTo)&&((relayTo->sendDirect(packet.data(),packet.size(),now,false)))) { Mutex::Lock _l(_lastUniteAttempt_m); uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)]; if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) { @@ -234,7 +235,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from #endif relayTo = RR->topology->getBestRoot(&source,1,true); if (relayTo) - relayTo->send(packet.data(),packet.size(),now,true); + relayTo->sendDirect(packet.data(),packet.size(),now,true); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -607,7 +608,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.first.rawIpData(),4); } outp.armor(p1p->key(),true); - p1p->send(outp.data(),outp.size(),now,true); + p1p->sendDirect(outp.data(),outp.size(),now,true); } else { // Tell p2 where to find p1. Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -622,7 +623,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.second.rawIpData(),4); } outp.armor(p2p->key(),true); - p2p->send(outp.data(),outp.size(),now,true); + p2p->sendDirect(outp.data(),outp.size(),now,true); } ++alt; // counts up and also flips LSB } @@ -739,7 +740,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); outp.armor(root->key(),true); - if (root->send(outp.data(),outp.size(),RR->node->now(),true)) + if (root->sendDirect(outp.data(),outp.size(),RR->node->now(),true)) return root->address(); } return Address(); @@ -752,10 +753,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) if (peer) { const uint64_t now = RR->node->now(); - SharedPtr viaPath(peer->getBestPath(now,false)); - if (!viaPath) { + SharedPtr viaPath(peer->getBestPath(now)); + if ( (!viaPath) || ((!viaPath->alive(now))&&(!RR->topology->isRoot(peer->identity()))) ) { SharedPtr relay(RR->topology->getBestRoot()); - if ( (!relay) || (!(viaPath = relay->getBestPath(now,true))) ) + if ( (!relay) || (!(viaPath = relay->getBestPath(now))) ) return false; } -- cgit v1.2.3 From 4992ac2d9f568a08ecd04b316a926c9d320750df Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 14:20:55 -0700 Subject: Cluster sub-optimal is in fact necessary... --- node/IncomingPacket.cpp | 4 ++-- node/Path.hpp | 8 -------- node/Peer.cpp | 40 +++++++++++++--------------------------- node/Peer.hpp | 11 +++++++---- 4 files changed, 22 insertions(+), 41 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7ba34566..a84b2beb 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1042,7 +1042,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->makeExclusive(a); + peer->setClusterOptimal(a); } else { redundant = peer->hasActivePathTo(now,a); } @@ -1061,7 +1061,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->makeExclusive(a); + peer->setClusterOptimal(a); } else { redundant = peer->hasActivePathTo(now,a); } diff --git a/node/Path.hpp b/node/Path.hpp index 68a630c3..d0e1d737 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -165,14 +165,6 @@ public: return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); } - /** - * @return This path's overall quality score (higher is better) - */ - inline uint64_t score() const - { - return (_lastIn + (preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))); - } - /** * Check whether this address is valid for a ZeroTier path * diff --git a/node/Peer.cpp b/node/Peer.cpp index a23d0822..ecf2a870 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -156,9 +156,10 @@ void Peer::received( _paths[slot].lastReceive = now; #ifdef ZT_ENABLE_CLUSTER _paths[slot].clusterSuboptimal = suboptimalPath; - if (RR->cluster) RR->cluster->broadcastHavePeer(_id); +#else + _paths[slot].clusterSuboptimal = false; #endif } else { @@ -196,36 +197,21 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const return false; } -void Peer::makeExclusive(const InetAddress &addr) +void Peer::setClusterOptimal(const InetAddress &addr) { Mutex::Lock _l(_paths_m); - bool have = false; + int have = -1; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address() == addr) { - have = true; + have = (int)p; break; } } - if (have) { - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if ((_paths[x].path->address().ss_family != addr.ss_family)||(_paths[x].path->address() == addr)) { - if (y != x) { - _paths[y].path = _paths[x].path; - _paths[y].lastReceive = _paths[x].lastReceive; - #ifdef ZT_ENABLE_CLUSTER - _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; - #endif - } - ++y; - } - ++x; - } - _numPaths = y; + if (have >= 0) { + for(unsigned int p=0;p<_numPaths;++p) + _paths[p].clusterSuboptimal = (p != have); } } @@ -237,7 +223,7 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->alive(now)||(forceEvenIfDead)) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best) { best = s; bestp = (int)p; @@ -259,7 +245,7 @@ SharedPtr Peer::getBestPath(uint64_t now) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best) { best = s; bestp = (int)p; @@ -296,7 +282,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best) { best = s; bestp = (int)p; @@ -361,13 +347,13 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) uint64_t best4 = 0ULL,best6 = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best4) { best4 = s; bestp4 = (int)p; } } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best6) { best6 = s; bestp6 = (int)p; diff --git a/node/Peer.hpp b/node/Peer.hpp index 294a4913..efe34825 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -121,11 +121,11 @@ public: bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; /** - * If we have a confirmed path to this address, forget all others within the same address family + * If we have a confirmed path to this address, mark others as cluster suboptimal * * @param addr Address to make exclusive */ - void makeExclusive(const InetAddress &addr); + void setClusterOptimal(const InetAddress &addr); /** * Send via best direct path @@ -363,6 +363,11 @@ public: private: bool _pushDirectPaths(const SharedPtr &path,uint64_t now); + inline uint64_t _pathScore(const unsigned int p) const + { + return ( (_paths[p].path->lastIn() + (_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))) - ((ZT_PEER_PING_PERIOD * 10) * (uint64_t)_paths[p].clusterSuboptimal) ); + } + unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; const RuntimeEnvironment *RR; @@ -381,9 +386,7 @@ private: struct { SharedPtr path; uint64_t lastReceive; -#ifdef ZT_ENABLE_CLUSTER bool clusterSuboptimal; -#endif } _paths[ZT_MAX_PEER_NETWORK_PATHS]; Mutex _paths_m; unsigned int _numPaths; -- cgit v1.2.3 From 48a374c82c89b69a71d1922c4396265394e9045f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Sep 2016 14:05:58 -0700 Subject: (1) fix crazy bug introduced in doRENDEZVOUS(), (2) reclaim Paths after paths[] condense, (3) fix an edge case around symmetric NAT and external IP change detection. --- node/IncomingPacket.cpp | 12 ++++++------ node/Path.hpp | 3 ++- node/Peer.cpp | 6 +++++- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a84b2beb..3d2d586e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -283,7 +283,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // VALID -- if we made it here, packet passed identity and authenticity checks! } - if (externalSurfaceAddress) + if ((externalSurfaceAddress)&&(hops() == 0)) RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); @@ -391,7 +391,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - if (externalSurfaceAddress) + if ((externalSurfaceAddress)&&(hops() == 0)) RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; @@ -516,8 +516,8 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< { try { const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr withPeer(RR->topology->getPeer(with)); - if (withPeer) { + const SharedPtr rendezvousWith(RR->topology->getPeer(with)); + if (rendezvousWith) { 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))) { @@ -525,8 +525,8 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< if (!RR->topology->isUpstream(peer->identity())) { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { - RR->node->putPacket(_path->localAddress(),atAddr,"NATSUX",6,2); // send low-TTL packet to 'open' local NAT(s) - peer->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); + RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); diff --git a/node/Path.hpp b/node/Path.hpp index 8151ed27..129913e1 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -29,6 +29,7 @@ #include "InetAddress.hpp" #include "SharedPtr.hpp" #include "AtomicCounter.hpp" +#include "NonCopyable.hpp" /** * Maximum return value of preferenceRank() @@ -42,7 +43,7 @@ class RuntimeEnvironment; /** * A path across the physical network */ -class Path +class Path : NonCopyable { friend class SharedPtr; diff --git a/node/Peer.cpp b/node/Peer.cpp index ab287d05..c56dbca9 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -339,7 +339,9 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) ++x; } _numPaths = y; - return (y < np); + while (y < ZT_MAX_PEER_NETWORK_PATHS) + _paths[y++].path.zero(); // let go of unused SmartPtr<>'s + return (_numPaths < np); } void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const @@ -390,6 +392,8 @@ void Peer::clean(uint64_t now) ++x; } _numPaths = y; + while (y < ZT_MAX_PEER_NETWORK_PATHS) + _paths[y++].path.zero(); // let go of unused SmartPtr<>'s } bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) -- cgit v1.2.3 From b5c86b6ba4112b23e46170fe241b4688532b493e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 11:13:17 -0700 Subject: Bunch more path refactoring. Peers no longer forget paths, but do not normally use expired paths. Expired paths might still be tried if nothing else is reachable. --- include/ZeroTierOne.h | 5 ++ node/Constants.hpp | 18 ++++++-- node/IncomingPacket.cpp | 2 +- node/Node.cpp | 25 ++++------ node/Peer.cpp | 117 ++++++++++++++++++----------------------------- node/Peer.hpp | 46 ++++++++++--------- node/SelfAwareness.cpp | 22 ++++----- node/SelfAwareness.hpp | 1 - node/Switch.cpp | 22 ++++++--- node/Topology.cpp | 5 +- service/ControlPlane.cpp | 6 ++- 11 files changed, 126 insertions(+), 143 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 583abfe4..0c22ae9d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1053,6 +1053,11 @@ typedef struct */ uint64_t trustedPathId; + /** + * Is path expired? + */ + int expired; + /** * Is path preferred? */ diff --git a/node/Constants.hpp b/node/Constants.hpp index ea4c434d..67e6fb58 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -244,17 +244,22 @@ * This is also how often pings will be retried to upstream peers (relays, roots) * constantly until something is heard. */ -#define ZT_PING_CHECK_INVERVAL 9000 +#define ZT_PING_CHECK_INVERVAL 10000 /** * How frequently to send heartbeats over in-use paths */ -#define ZT_PATH_HEARTBEAT_PERIOD 15000 +#define ZT_PATH_HEARTBEAT_PERIOD 10000 /** * Paths are considered inactive if they have not received traffic in this long */ -#define ZT_PATH_ALIVE_TIMEOUT 35000 +#define ZT_PATH_ALIVE_TIMEOUT 25000 + +/** + * Minimum time between attempts to check dead paths to see if they can be re-awakened + */ +#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 /** * Delay between full-fledge pings of directly connected peers @@ -262,10 +267,15 @@ #define ZT_PEER_PING_PERIOD 60000 /** - * Peers forget paths that have not spoken in this long + * Paths are considered expired if they have not produced a real packet in this long */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) +/** + * How often to retry expired paths that we're still remembering + */ +#define ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD (ZT_PEER_PING_PERIOD * 10) + /** * Timeout for overall peer activity (measured from last receive) */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3d2d586e..891607ed 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1163,7 +1163,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - SharedPtr nhbp(nhp->getBestPath(now)); + SharedPtr nhbp(nhp->getBestPath(now,false)); if ((nhbp)&&(nhbp->alive(now))) nextHopBestPathAddress[h] = nhbp->address(); } diff --git a/node/Node.cpp b/node/Node.cpp index a7d4cfa9..edd48575 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -202,14 +202,6 @@ public: } } - if (!upstream) { - // If I am a root server, only ping other root servers -- roots don't ping "down" - // since that would just be a waste of bandwidth and could potentially cause route - // flapping in Cluster mode. - if (RR->topology->amRoot()) - return; - } - if (upstream) { // "Upstream" devices are roots and relays and get special treatment -- they stay alive // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them. @@ -415,15 +407,16 @@ 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< SharedPtr > paths(pi->second->paths()); - SharedPtr bestp(pi->second->getBestPath(_now)); + std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); + SharedPtr bestp(pi->second->getBestPath(_now,false)); p->pathCount = 0; - for(std::vector< SharedPtr >::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)->lastOut(); - p->paths[p->pathCount].lastReceive = (*path)->lastIn(); - p->paths[p->pathCount].preferred = (*path == bestp) ? 1 : 0; - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); + for(std::vector< std::pair< SharedPtr,bool > >::iterator path(paths.begin());path!=paths.end();++path) { + memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); + p->paths[p->pathCount].lastSend = path->first->lastOut(); + p->paths[p->pathCount].lastReceive = path->first->lastIn(); + p->paths[p->pathCount].expired = path->second; + p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); ++p->pathCount; } } diff --git a/node/Peer.cpp b/node/Peer.cpp index abbbea72..a2a91769 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,6 +27,14 @@ #include "Cluster.hpp" #include "Packet.hpp" +#ifndef AF_MAX +#if AF_INET > AF_INET6 +#define AF_MAX AF_INET +#else +#define AF_MAX AF_INET6 +#endif +#endif + namespace ZeroTier { // Used to send varying values for NAT keepalive @@ -150,7 +158,7 @@ void Peer::received( uint64_t worstScore = 0xffffffffffffffffULL; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address().ss_family == path->address().ss_family) { - const uint64_t s = _pathScore(p); + const uint64_t s = _pathScore(p,now); if (s < worstScore) { worstScore = s; worstSlot = (int)p; @@ -163,7 +171,7 @@ void Peer::received( // If we can't find one with the same family, replace the worst of any family slot = ZT_MAX_PEER_NETWORK_PATHS - 1; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); + const uint64_t s = _pathScore(p,now); if (s < worstScore) { worstScore = s; slot = p; @@ -210,7 +218,7 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address() == addr) && (_paths[p].path->alive(now)) ) + if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) return true; } return false; @@ -223,8 +231,8 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->alive(now)||(forceEvenIfDead)) { - const uint64_t s = _pathScore(p); + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) { + const uint64_t s = _pathScore(p,now); if (s >= best) { best = s; bestp = (int)p; @@ -239,17 +247,19 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE } } -SharedPtr Peer::getBestPath(uint64_t now) +SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); - if (s >= best) { - best = s; - bestp = (int)p; + if ( ((now - _paths[p].lastReceive) < ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { + const uint64_t s = _pathScore(p,now); + if (s >= best) { + best = s; + bestp = (int)p; + } } } @@ -283,8 +293,8 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) { - const uint64_t s = _pathScore(p); + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) { + const uint64_t s = _pathScore(p,now); if (s >= best) { best = s; bestp = (int)p; @@ -293,7 +303,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) } if (bestp >= 0) { - if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { + if ((now - _paths[best].lastReceive) >= ZT_PEER_PING_PERIOD) { sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads @@ -309,39 +319,24 @@ bool Peer::hasActiveDirectPath(uint64_t now) const { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->alive(now)) + if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now))) return true; } return false; } -bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) +bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) { Mutex::Lock _l(_paths_m); - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if (_paths[x].path->address().ipScope() == scope) { - // Resetting a path means sending a HELLO and then forgetting it. If we - // get OK(HELLO) then it will be re-learned. - sendHELLO(_paths[x].path->localAddress(),_paths[x].path->address(),now); - } else { - if (x != y) { - _paths[y].lastReceive = _paths[x].lastReceive; - _paths[y].path = _paths[x].path; -#ifdef ZT_ENABLE_CLUSTER - _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal; -#endif - } - ++y; + bool resetSomething = false; + for(unsigned int p=0;p<_numPaths;++p) { + if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { + sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); + _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic + resetSomething = true; } - ++x; } - _numPaths = y; - while (y < ZT_MAX_PEER_NETWORK_PATHS) - _paths[y++].path.zero(); // let go of unused SmartPtr<>'s - return (_numPaths < np); + return resetSomething; } void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const @@ -351,17 +346,19 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) int bestp4 = -1,bestp6 = -1; uint64_t best4 = 0ULL,best6 = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _pathScore(p); - if (s >= best4) { - best4 = s; - bestp4 = (int)p; - } - } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _pathScore(p); - if (s >= best6) { - best6 = s; - bestp6 = (int)p; + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) { + if (_paths[p].path->address().ss_family == AF_INET) { + const uint64_t s = _pathScore(p,now); + if (s >= best4) { + best4 = s; + bestp4 = (int)p; + } + } else if (_paths[p].path->address().ss_family == AF_INET6) { + const uint64_t s = _pathScore(p,now); + if (s >= best6) { + best6 = s; + bestp6 = (int)p; + } } } } @@ -372,30 +369,6 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) v6 = _paths[bestp6].path->address(); } -void Peer::clean(uint64_t now) -{ - Mutex::Lock _l(_paths_m); - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if ((now - _paths[x].lastReceive) <= ZT_PEER_PATH_EXPIRATION) { - if (y != x) { - _paths[y].lastReceive = _paths[x].lastReceive; - _paths[y].path = _paths[x].path; -#ifdef ZT_ENABLE_CLUSTER - _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal; -#endif - } - ++y; - } - ++x; - } - _numPaths = y; - while (y < ZT_MAX_PEER_NETWORK_PATHS) - _paths[y++].path.zero(); // let go of unused SmartPtr<>'s -} - bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) { #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Peer.hpp b/node/Peer.hpp index 3ffabb05..6e1d378f 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -149,9 +149,10 @@ public: * Get the best current direct path * * @param now Current time + * @param includeDead If true, include even expired paths * @return Best current path or NULL if none */ - SharedPtr getBestPath(uint64_t now); + SharedPtr getBestPath(uint64_t now,bool includeExpired); /** * Send a HELLO to this peer at a specified physical address @@ -175,18 +176,22 @@ public: /** * @param now Current time - * @return True if this peer has at least one active direct path + * @return True if this peer has at least one active and alive direct path */ bool hasActiveDirectPath(uint64_t now) const; /** - * Reset paths within a given scope + * Reset paths within a given IP scope and address family * - * @param scope IP scope of paths to reset + * Resetting a path involves sending a HELLO to it and then de-prioritizing + * it vs. other paths. + * + * @param scope IP scope + * @param inetAddressFamily Family e.g. AF_INET * @param now Current time - * @return True if at least one path was forgotten + * @return True if we forgot at least one path */ - bool resetWithinScope(InetAddress::IpScope scope,uint64_t now); + bool resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); /** * Get most recently active path addresses for IPv4 and/or IPv6 @@ -201,21 +206,15 @@ public: void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; /** - * Perform periodic cleaning operations - * * @param now Current time + * @return All known direct paths to this peer and whether they are expired (true == expired) */ - void clean(uint64_t now); - - /** - * @return All known direct paths to this peer (active or inactive) - */ - inline std::vector< SharedPtr > paths() const + inline std::vector< std::pair< SharedPtr,bool > > paths(const uint64_t now) const { - std::vector< SharedPtr > pp; + std::vector< std::pair< SharedPtr,bool > > pp; Mutex::Lock _l(_paths_m); for(unsigned int p=0,np=_numPaths;p,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION)); return pp; } @@ -370,11 +369,12 @@ public: private: bool _pushDirectPaths(const SharedPtr &path,uint64_t now); - inline uint64_t _pathScore(const unsigned int p) const + inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const { - uint64_t s = ZT_PEER_PING_PERIOD; + uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); + if (_paths[p].path->address().ss_family == AF_INET) { - s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); + s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); } else if (_paths[p].path->address().ss_family == AF_INET6) { uint64_t clusterWeight = ZT_PEER_PING_PERIOD; const uint8_t *a = reinterpret_cast(reinterpret_cast(&(_paths[p].path->address()))->sin6_addr.s6_addr); @@ -384,13 +384,15 @@ private: break; } } - s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + clusterWeight; - } else { - s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); + s += clusterWeight; } + + s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now); + #ifdef ZT_ENABLE_CLUSTER s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; #endif + return s; } diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index b9ab9d67..6bf50720 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -33,37 +33,31 @@ #include "Switch.hpp" // Entry timeout -- make it fairly long since this is just to prevent stale buildup -#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 3600000 +#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 namespace ZeroTier { class _ResetWithinScope { public: - _ResetWithinScope(uint64_t now,InetAddress::IpScope scope) : + _ResetWithinScope(uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : _now(now), + _family(inetAddressFamily), _scope(scope) {} - inline void operator()(Topology &t,const SharedPtr &p) - { - if (p->resetWithinScope(_scope,_now)) - peersReset.push_back(p); - } + inline void operator()(Topology &t,const SharedPtr &p) { if (p->resetWithinScope(_scope,_family,_now)) peersReset.push_back(p); } std::vector< SharedPtr > peersReset; private: uint64_t _now; + int _family; InetAddress::IpScope _scope; }; SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : RR(renv), - _phy(32) -{ -} - -SelfAwareness::~SelfAwareness() + _phy(128) { } @@ -98,8 +92,8 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc } } - // Reset all paths within this scope - _ResetWithinScope rset(now,(InetAddress::IpScope)scope); + // Reset all paths within this scope and address family + _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); // Send a NOP to all peers for whom we forgot a path. This will cause direct diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index c7bde87e..4bdafeb2 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -36,7 +36,6 @@ class SelfAwareness { public: SelfAwareness(const RuntimeEnvironment *renv); - ~SelfAwareness(); /** * Called when a trusted remote peer informs us of our external network address diff --git a/node/Switch.cpp b/node/Switch.cpp index 28a2564b..21d0b3c9 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -747,14 +747,20 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread bool Switch::_trySend(const Packet &packet,bool encrypt) { - SharedPtr peer(RR->topology->getPeer(packet.destination())); - + const SharedPtr peer(RR->topology->getPeer(packet.destination())); if (peer) { const uint64_t now = RR->node->now(); - SharedPtr viaPath(peer->getBestPath(now)); + // First get the best path, and if it's dead (and this is not a root) + // we attempt to re-activate that path but this packet will flow + // upstream. If the path comes back alive, it will be used in the future. + // For roots we don't do the alive check since roots are not required + // to send heartbeats "down" and because we have to at least try to + // go somewhere. + + SharedPtr viaPath(peer->getBestPath(now,false)); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) { - if ((now - viaPath->lastOut()) > 5000) { + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) >> 2,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ECHO); outp.armor(peer->key(),true); viaPath->send(RR,outp.data(),outp.size(),now); @@ -763,8 +769,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) } if (!viaPath) { SharedPtr relay(RR->topology->getBestRoot()); - if ( (!relay) || (!(viaPath = relay->getBestPath(now))) ) - return false; + if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { + if (!(viaPath = peer->getBestPath(now,true))) + return false; + } } Packet tmp(packet); @@ -787,7 +795,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) ++fragsRemaining; - unsigned int totalFragments = fragsRemaining + 1; + const unsigned int totalFragments = fragsRemaining + 1; for(unsigned int fno=1;fno *p = (SharedPtr *)0; while (i.next(a,p)) { - if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) { + if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) _peers.erase(*a); - } else { - (*p)->clean(now); - } } } { diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index a24e3eb4..b443a7fa 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -183,14 +183,16 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath * "%s\t\"address\": \"%s\",\n" "%s\t\"lastSend\": %llu,\n" "%s\t\"lastReceive\": %llu,\n" - "%s\t\"active\": true,\n" + "%s\t\"active\": %s,\n" + "%s\t\"expired\": %s,\n" "%s\t\"preferred\": %s,\n" "%s\t\"trustedPathId\": %llu\n" "%s}", prefix,_jsonEscape(reinterpret_cast(&(pp[i].address))->toString()).c_str(), prefix,pp[i].lastSend, prefix,pp[i].lastReceive, - prefix, + prefix,(pp[i].expired != 0) ? "false" : "true", + prefix,(pp[i].expired == 0) ? "false" : "true", prefix,(pp[i].preferred == 0) ? "false" : "true", prefix,pp[i].trustedPathId, prefix); -- cgit v1.2.3 From a7d988745bcca4a0f9c838ec493e658b098d241d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 12:01:03 -0700 Subject: Use ECHO instead of HELLO where possible. --- node/IncomingPacket.cpp | 6 +++--- node/Path.hpp | 7 +++++++ node/Peer.cpp | 31 ++++++++++++++++++------------- node/Peer.hpp | 11 +++++++++++ 4 files changed, 39 insertions(+), 16 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 891607ed..0857fb3d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -526,7 +526,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1050,7 +1050,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->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(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1069,7 +1069,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->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(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } diff --git a/node/Path.hpp b/node/Path.hpp index 129913e1..27cff645 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -137,6 +137,13 @@ public: */ bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now); + /** + * Manually update last sent time + * + * @param t Time of send + */ + inline void sent(const uint64_t t) { _lastOut = t; } + /** * @return Address of local side of this path or NULL if unspecified */ diff --git a/node/Peer.cpp b/node/Peer.cpp index c24d4246..3d3ca247 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -189,16 +189,8 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - - if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { - // Newer than 1.1.0 can use ECHO, which is smaller - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); - outp.armor(_key,true); - path->send(RR,outp.data(),outp.size(),now); - } else { - // For backward compatibility we send HELLO to ancient nodes - sendHELLO(path->localAddress(),path->address(),now); - } + attemptToContactAt(path->localAddress(),path->address(),now); + path->sent(now); } } } else if (trustEstablished) { @@ -254,7 +246,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) < ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { const uint64_t s = _pathScore(p,now); if (s >= best) { best = s; @@ -286,6 +278,17 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } +void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) +{ + if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); + outp.armor(_key,true); + RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + } else { + sendHELLO(localAddr,atAddress,now); + } +} + bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); @@ -304,7 +307,8 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { - sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + _paths[bestp].path->sent(now); } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads _paths[bestp].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); @@ -331,7 +335,8 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin bool resetSomething = false; for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); + attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now); + _paths[p].path->sent(now); _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic resetSomething = true; } diff --git a/node/Peer.hpp b/node/Peer.hpp index 6e1d378f..7a7453ae 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -165,6 +165,17 @@ public: */ void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + /** + * Send ECHO (or HELLO for older peers) to this peer at the given address + * + * No statistics or sent times are updated here. + * + * @param localAddr Local address + * @param atAddress Destination address + * @param now Current time + */ + void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + /** * Send pings or keepalives depending on configured timeouts * -- cgit v1.2.3 From 1908aa55f51d63bceb7ed5d4211a4274d732de63 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 15:15:52 -0700 Subject: Refactor MULTICAST_LIKE pushing to eliminate redundant and unnecessary pushes and simplify code. --- node/Constants.hpp | 28 +++++------- node/IncomingPacket.cpp | 93 +++++++++++++++++++++------------------ node/Membership.cpp | 7 ++- node/Membership.hpp | 49 ++++++++++++--------- node/Network.cpp | 115 ++++++++++++++++++++++-------------------------- node/Network.hpp | 46 ++++++------------- node/Node.cpp | 6 +-- node/Peer.cpp | 21 +++------ node/Peer.hpp | 19 ++++---- 9 files changed, 182 insertions(+), 202 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 67e6fb58..a625b480 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -180,14 +180,14 @@ #define ZT_PEER_SECRET_KEY_LENGTH 32 /** - * How often Topology::clean() and Network::clean() and similar are called, in ms + * Minimum delay between timer task checks to prevent thrashing */ -#define ZT_HOUSEKEEPING_PERIOD 120000 +#define ZT_CORE_TIMER_TASK_GRANULARITY 500 /** - * Overriding granularity for timer tasks to prevent CPU-intensive thrashing on every packet + * How often Topology::clean() and Network::clean() and similar are called, in ms */ -#define ZT_CORE_TIMER_TASK_GRANULARITY 500 +#define ZT_HOUSEKEEPING_PERIOD 120000 /** * How long to remember peer records in RAM if they haven't been used @@ -226,6 +226,11 @@ */ #define ZT_MULTICAST_LIKE_EXPIRE 600000 +/** + * Period for multicast LIKE announcements + */ +#define ZT_MULTICAST_ANNOUNCE_PERIOD 120000 + /** * Delay between explicit MULTICAST_GATHER requests for a given multicast channel */ @@ -239,12 +244,9 @@ #define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000 /** - * Delay between scans of the topology active peer DB for peers that need ping - * - * This is also how often pings will be retried to upstream peers (relays, roots) - * constantly until something is heard. + * Delay between checks of peer pings, etc., and also related housekeeping tasks */ -#define ZT_PING_CHECK_INVERVAL 10000 +#define ZT_PING_CHECK_INVERVAL 5000 /** * How frequently to send heartbeats over in-use paths @@ -298,14 +300,6 @@ */ #define ZT_MIN_UNITE_INTERVAL 30000 -/** - * Delay between initial direct NAT-t packet and more aggressive techniques - * - * This may also be a delay before sending the first packet if we determine - * that we should wait for the remote to initiate rendezvous first. - */ -#define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000 - /** * Sanity limit on maximum bridge routes * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0857fb3d..97e1abe3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,6 +42,8 @@ namespace ZeroTier { +static const SharedPtr NULL_NETWORK; + bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) { const Address sourceAddress(source()); @@ -88,7 +90,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; case Packet::VERB_HELLO: return _doHELLO(RR,peer); @@ -172,7 +174,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -339,7 +341,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -461,7 +463,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -505,7 +507,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -537,7 +539,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } else { TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -547,25 +549,27 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID))); + const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + bool approved = false; if (network) { 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(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); } else { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),network->id()); + const MAC sourceMac(peer->address(),nwid); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); + RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + approved = true; // this means approved on the network in general, not this packet per se } } } else { - TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved,network); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -575,7 +579,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID))); + const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); if (network) { if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; @@ -590,7 +595,7 @@ 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(),_path->address().toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,network); return true; } @@ -602,37 +607,38 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } switch (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { case 1: - if (from != MAC(peer->address(),network->id())) { + if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } } // fall through -- 2 means accept regardless of bridging checks or other restrictions case 2: - RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + RR->node->putFrame(nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); break; } - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); } } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); } } catch ( ... ) { TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -651,7 +657,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); - peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -670,7 +676,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -719,7 +725,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -817,7 +823,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk,NULL_NETWORK); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -839,7 +845,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons network->requestConfiguration(); } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } @@ -851,7 +857,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -902,7 +908,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -932,7 +938,7 @@ 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(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,network); return true; } @@ -959,28 +965,28 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } - if (from != MAC(peer->address(),network->id())) { + if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { - RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); + RR->node->putFrame(nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } } @@ -998,9 +1004,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); } else { - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1016,7 +1022,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // 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(),_path->address().toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } @@ -1079,7 +1085,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1123,7 +1129,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } vlf += signatureLength; @@ -1140,12 +1146,12 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } @@ -1216,7 +1222,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1261,7 +1267,8 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S } RR->node->postCircuitTestReport(&report); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1322,7 +1329,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const break; } - peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false,NULL_NETWORK); } else { TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Membership.cpp b/node/Membership.cpp index e809e2bd..74a01350 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -89,21 +89,26 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint } } -int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com) +int Membership::addCredential(const RuntimeEnvironment *RR,const Network *network,const CertificateOfMembership &com) { if (_com == com) { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); + sendCredentialsIfNeeded(RR,RR->node->now(),com.issuedTo(),network->config(),(const Capability *)0); return 0; } + const int vr = com.verify(RR); + if (vr == 0) { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); if (com.timestamp().first > _com.timestamp().first) { _com = com; } + sendCredentialsIfNeeded(RR,RR->node->now(),com.issuedTo(),network->config(),(const Capability *)0); } else { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (%d)",com.issuedTo().toString().c_str(),com.networkId(),vr); } + return vr; } diff --git a/node/Membership.hpp b/node/Membership.hpp index 293fa4d8..324f92a6 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -31,15 +31,10 @@ #include "Hashtable.hpp" #include "NetworkConfig.hpp" -// Expiration time for capability and tag cache -#define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA - -// Expiration time for Memberships (used in Network::clean()) -#define ZT_MEMBERSHIP_EXPIRATION_TIME ZT_PEER_IN_MEMORY_EXPIRATION - namespace ZeroTier { class RuntimeEnvironment; +class Network; /** * A container for certificates of membership and other network credentials @@ -107,6 +102,7 @@ public: friend class CapabilityIterator; Membership() : + _lastUpdatedMulticast(0), _lastPushAttempt(0), _lastPushedCom(0), _blacklistBefore(0), @@ -130,6 +126,21 @@ public: */ void sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap); + /** + * Check whether we should push MULTICAST_LIKEs to this peer + * + * @param now Current time + * @return True if we should update multicasts + */ + inline bool shouldLikeMulticasts(const uint64_t now) const { return ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD); } + + /** + * Set time we last updated multicasts for this peer + * + * @param now Current time + */ + inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; } + /** * @param nconf Our network config * @return True if this peer is allowed on this network at all @@ -206,9 +217,12 @@ public: /** * Validate and add a credential if signature is okay and it's otherwise good * + * @param RR Runtime environment + * @param network Network that owns this Membership + * @param com Certificate of membership * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com); + int addCredential(const RuntimeEnvironment *RR,const Network *network,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good @@ -237,20 +251,15 @@ public: /** * Clean up old or stale entries * - * @return Time of most recent activity in this Membership + * @param nconf Network config */ - inline uint64_t clean(const uint64_t now) + inline void clean(const NetworkConfig &nconf) { - uint64_t lastAct = _lastPushedCom; - for(std::map::iterator i(_caps.begin());i!=_caps.end();) { - const uint64_t la = std::max(i->second.lastPushed,i->second.lastReceived); - if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) { + if (!isCredentialTimestampValid(nconf,i->second.cap)) { _caps.erase(i++); } else { ++i; - if (la > lastAct) - lastAct = la; } } @@ -258,17 +267,15 @@ public: TState *ts = (TState *)0; Hashtable::Iterator tsi(_tags); while (tsi.next(i,ts)) { - const uint64_t la = std::max(ts->lastPushed,ts->lastReceived); - if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) + if (!isCredentialTimestampValid(nconf,ts->tag)) _tags.erase(*i); - else if (la > lastAct) - lastAct = la; } - - return lastAct; } private: + // Last time we pushed MULTICAST_LIKE(s) + uint64_t _lastUpdatedMulticast; + // Last time we checked if credential push was needed uint64_t _lastPushAttempt; diff --git a/node/Network.cpp b/node/Network.cpp index b18a3b22..7c2a4084 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -577,6 +577,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : RR(renv), _uPtr(uptr), _id(nwid), + _lastAnnouncedMulticastGroupsUpstream(0), _mac(renv->identity.address(),nwid), _portInitialized(false), _inboundConfigPacketId(0), @@ -872,8 +873,8 @@ void Network::multicastSubscribe(const MulticastGroup &mg) return; _myMulticastGroups.push_back(mg); std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end()); + _announceMulticastGroups(&mg); } - _announceMulticastGroups(); } void Network::multicastUnsubscribe(const MulticastGroup &mg) @@ -888,20 +889,6 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.swap(nmg); } -bool Network::tryAnnounceMulticastGroupsTo(const SharedPtr &peer) -{ - Mutex::Lock _l(_lock); - if ( - (_isAllowed(peer)) || - (peer->address() == this->controller()) || - (RR->topology->isUpstream(peer->identity())) - ) { - _announceMulticastGroupsTo(peer,_allMulticastGroups()); - return true; - } - return false; -} - bool Network::applyConfiguration(const NetworkConfig &conf) { if (_destroyed) // sanity check @@ -1094,8 +1081,9 @@ void Network::clean() Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ((now - m->clean(now)) > ZT_MEMBERSHIP_EXPIRATION_TIME) - _memberships.erase(*a); + if (RR->topology->getPeerNoCache(*a)) + m->clean(_config); + else _memberships.erase(*a); } } } @@ -1143,7 +1131,7 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _announceMulticastGroups(); + _announceMulticastGroups(&mg); } void Network::destroy() @@ -1223,61 +1211,66 @@ bool Network::_isAllowed(const SharedPtr &peer) const return false; } -class _MulticastAnnounceAll +void Network::_announceMulticastGroups(const MulticastGroup *const onlyThis) { -public: - _MulticastAnnounceAll(const RuntimeEnvironment *renv,Network *nw) : - _now(renv->node->now()), - _controller(nw->controller()), - _network(nw), - _anchors(nw->config().anchors()), - _upstreamAddresses(renv->topology->upstreamAddresses()) - {} - inline void operator()(Topology &t,const SharedPtr &p) - { - if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed, which isn't terrible but is a bit stupid - (p->address() == _controller) || - (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),p->address()) != _upstreamAddresses.end()) || - (std::find(_anchors.begin(),_anchors.end(),p->address()) != _anchors.end()) ) { - peers.push_back(p); + // Assumes _lock is locked + const uint64_t now = RR->node->now(); + + std::vector groups; + if (onlyThis) + groups.push_back(*onlyThis); + else groups = _allMulticastGroups(); + + if ((onlyThis)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { + if (!onlyThis) + _lastAnnouncedMulticastGroupsUpstream = now; + + // Announce multicast groups to upstream peers (roots, etc.) and also send + // them our COM so that MULTICAST_GATHER can be authenticated properly. + const std::vector

upstreams(RR->topology->upstreamAddresses()); + for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { + if ((_config.isPrivate())&&(_config.com)) { + Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + _config.com.serialize(outp); + outp.append((uint8_t)0x00); + RR->sw->send(outp,true); + } + _announceMulticastGroupsTo(*a,groups); } } - std::vector< SharedPtr > peers; -private: - const uint64_t _now; - const Address _controller; - Network *const _network; - const std::vector
_anchors; - const std::vector
_upstreamAddresses; -}; -void Network::_announceMulticastGroups() -{ - // Assumes _lock is locked - std::vector allMulticastGroups(_allMulticastGroups()); - _MulticastAnnounceAll gpfunc(RR,this); - RR->topology->eachPeer<_MulticastAnnounceAll &>(gpfunc); - for(std::vector< SharedPtr >::const_iterator i(gpfunc.peers.begin());i!=gpfunc.peers.end();++i) - _announceMulticastGroupsTo(*i,allMulticastGroups); -} -void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std::vector &allMulticastGroups) -{ - // Assumes _lock is locked + // Make sure that all "network anchors" have Membership records so we will + // push multicasts to them. + const std::vector
anchors(_config.anchors()); + for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) + _memberships[*a]; - // Anyone we announce multicast groups to will need our COM to authenticate GATHER requests. + // Send MULTICAST_LIKE(s) to all members of this network { - Membership *m = _memberships.get(peer->address()); - if (m) - m->sendCredentialsIfNeeded(RR,RR->node->now(),peer->address(),_config,(const Capability *)0); + Address *a = (Address *)0; + Membership *m = (Membership *)0; + Hashtable::Iterator i(_memberships); + while (i.next(a,m)) { + if ((onlyThis)||(m->shouldLikeMulticasts(now))) { + if (!onlyThis) + m->likingMulticasts(now); + m->sendCredentialsIfNeeded(RR,RR->node->now(),*a,_config,(const Capability *)0); + _announceMulticastGroupsTo(*a,groups); + } + } } +} - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); +void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups) +{ + // Assumes _lock is locked + Packet outp(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { outp.compress(); RR->sw->send(outp,true); - outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); + outp.reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } // network ID, MAC, ADI @@ -1295,7 +1288,6 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: std::vector Network::_allMulticastGroups() const { // Assumes _lock is locked - std::vector mgs; mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1); mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end()); @@ -1304,7 +1296,6 @@ std::vector Network::_allMulticastGroups() const mgs.push_back(Network::BROADCAST); std::sort(mgs.begin(),mgs.end()); mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end()); - return mgs; } diff --git a/node/Network.hpp b/node/Network.hpp index 45a51bf2..4d0e25b7 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -190,14 +190,6 @@ public: */ void multicastUnsubscribe(const MulticastGroup &mg); - /** - * Announce multicast groups to a peer if that peer is authorized on this network - * - * @param peer Peer to try to announce multicast groups to - * @return True if peer was authorized and groups were announced - */ - bool tryAnnounceMulticastGroupsTo(const SharedPtr &peer); - /** * Apply a NetworkConfig to this network * @@ -272,6 +264,15 @@ public: */ void clean(); + /** + * Announce multicast groups to all members, anchors, etc. + */ + inline void announceMulticastGroups() + { + Mutex::Lock _l(_lock); + _announceMulticastGroups((const MulticastGroup *)0); + } + /** * @return Time of last updated configuration or 0 if none */ @@ -298,23 +299,10 @@ public: /** * Get current network config * - * This returns a const reference to the network config in place, which is safe - * to concurrently access but *may* change during access. Normally this isn't a - * problem, but if it is use configCopy(). - * * @return Network configuration (may be a null config if we don't have one yet) */ inline const NetworkConfig &config() const { return _config; } - /** - * @return A thread-safe copy of our NetworkConfig instead of a const reference - */ - inline NetworkConfig configCopy() const - { - Mutex::Lock _l(_lock); - return _config; - } - /** * @return True if this network has a valid config */ @@ -323,7 +311,7 @@ public: /** * @return Ethernet MAC address for this network's local interface */ - inline const MAC &mac() const throw() { return _mac; } + inline const MAC &mac() const { return _mac; } /** * Find the node on this network that has this MAC behind it (if any) @@ -365,7 +353,7 @@ public: if (com.networkId() != _id) return -1; Mutex::Lock _l(_lock); - return _memberships[com.issuedTo()].addCredential(RR,com); + return _memberships[com.issuedTo()].addCredential(RR,this,com); } /** @@ -417,24 +405,18 @@ public: */ inline void **userPtr() throw() { return &_uPtr; } - inline bool operator==(const Network &n) const throw() { return (_id == n._id); } - inline bool operator!=(const Network &n) const throw() { return (_id != n._id); } - inline bool operator<(const Network &n) const throw() { return (_id < n._id); } - inline bool operator>(const Network &n) const throw() { return (_id > n._id); } - inline bool operator<=(const Network &n) const throw() { return (_id <= n._id); } - inline bool operator>=(const Network &n) const throw() { return (_id >= n._id); } - private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _isAllowed(const SharedPtr &peer) const; - void _announceMulticastGroups(); - void _announceMulticastGroupsTo(const SharedPtr &peer,const std::vector &allMulticastGroups); + void _announceMulticastGroups(const MulticastGroup *const onlyThis); + void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; const RuntimeEnvironment *RR; void *_uPtr; uint64_t _id; + uint64_t _lastAnnouncedMulticastGroupsUpstream; MAC _mac; // local MAC address volatile bool _portInitialized; diff --git a/node/Node.cpp b/node/Node.cpp index edd48575..233ddc02 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -261,13 +261,11 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB { Mutex::Lock _l(_networks_m); for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { - if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) { + if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - } + n->second->announceMulticastGroups(); } } - - // Request updated configuration for networks that need it for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) (*n)->requestConfiguration(); diff --git a/node/Peer.cpp b/node/Peer.cpp index 3d3ca247..43daeb13 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -45,7 +45,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), - _lastAnnouncedTo(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), RR(renv), @@ -66,12 +65,13 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident void Peer::received( const SharedPtr &path, - unsigned int hops, - uint64_t packetId, - Packet::Verb verb, - uint64_t inRePacketId, - Packet::Verb inReVerb, - const bool trustEstablished) + const unsigned int hops, + const uint64_t packetId, + const Packet::Verb verb, + const uint64_t inRePacketId, + const Packet::Verb inReVerb, + const bool trustEstablished, + const SharedPtr &network) { const uint64_t now = RR->node->now(); @@ -197,13 +197,6 @@ void Peer::received( // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) _pushDirectPaths(path,now); } - - if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { - _lastAnnouncedTo = now; - const std::vector< SharedPtr > networks(RR->node->allNetworks()); - for(std::vector< SharedPtr >::const_iterator n(networks.begin());n!=networks.end();++n) - (*n)->tryAnnounceMulticastGroupsTo(SharedPtr(this)); - } } bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const diff --git a/node/Peer.hpp b/node/Peer.hpp index 7a7453ae..19767a70 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -45,6 +45,8 @@ namespace ZeroTier { +class Network; + /** * Peer on P2P Network (virtual layer 1) */ @@ -103,15 +105,17 @@ public: * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established + * @param network Network to which this packet pertains or NULL if none */ void received( const SharedPtr &path, - unsigned int hops, - uint64_t packetId, - Packet::Verb verb, - uint64_t inRePacketId, - Packet::Verb inReVerb, - const bool trustEstablished); + const unsigned int hops, + const uint64_t packetId, + const Packet::Verb verb, + const uint64_t inRePacketId, + const Packet::Verb inReVerb, + const bool trustEstablished, + const SharedPtr &network); /** * @param now Current time @@ -407,13 +411,12 @@ private: return s; } - unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; + uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t _remoteClusterOptimal6[16]; uint64_t _lastUsed; uint64_t _lastReceive; // direct or indirect uint64_t _lastUnicastFrame; uint64_t _lastMulticastFrame; - uint64_t _lastAnnouncedTo; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; const RuntimeEnvironment *RR; -- cgit v1.2.3 From c7a4da3dd3bb429b5d2f69373388b3b22a6544cb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 15:24:53 -0700 Subject: Turns out we do not need to pass network to receive(). --- node/IncomingPacket.cpp | 70 ++++++++++++++++++++++++------------------------- node/Peer.cpp | 3 +-- node/Peer.hpp | 6 +---- 3 files changed, 36 insertions(+), 43 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 97e1abe3..39f077ff 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,8 +42,6 @@ namespace ZeroTier { -static const SharedPtr NULL_NETWORK; - bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) { const Address sourceAddress(source()); @@ -90,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; case Packet::VERB_HELLO: return _doHELLO(RR,peer); @@ -174,7 +172,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -341,7 +339,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -463,7 +461,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -507,7 +505,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -539,7 +537,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } else { TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -569,7 +567,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved,network); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -595,7 +593,7 @@ 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(),_path->address().toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,network); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -607,7 +605,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -618,13 +616,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -634,11 +632,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -657,7 +655,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); - peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -676,7 +674,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -725,7 +723,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -823,7 +821,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk,NULL_NETWORK); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -845,7 +843,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons network->requestConfiguration(); } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); return true; } @@ -857,7 +855,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -908,7 +906,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -938,7 +936,7 @@ 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(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,network); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -965,12 +963,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -979,7 +977,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -1004,9 +1002,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1022,7 +1020,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // 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(),_path->address().toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1085,7 +1083,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1129,7 +1127,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1146,12 +1144,12 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1222,7 +1220,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1268,7 +1266,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S RR->node->postCircuitTestReport(&report); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1329,7 +1327,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const break; } - peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); } else { TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 43daeb13..58faab3b 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -70,8 +70,7 @@ void Peer::received( const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished, - const SharedPtr &network) + const bool trustEstablished) { const uint64_t now = RR->node->now(); diff --git a/node/Peer.hpp b/node/Peer.hpp index 19767a70..2e64fb4d 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -45,8 +45,6 @@ namespace ZeroTier { -class Network; - /** * Peer on P2P Network (virtual layer 1) */ @@ -105,7 +103,6 @@ public: * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established - * @param network Network to which this packet pertains or NULL if none */ void received( const SharedPtr &path, @@ -114,8 +111,7 @@ public: const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished, - const SharedPtr &network); + const bool trustEstablished); /** * @param now Current time -- cgit v1.2.3 From 16df2c33631eeb3e123fefa4febf20f202fd476b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Sep 2016 19:48:05 -0700 Subject: Clean up handling of COMs, network access control, and fix a backward compatiblity issue. --- node/IncomingPacket.cpp | 8 ++--- node/Membership.cpp | 10 +++--- node/Membership.hpp | 15 +++++++++ node/Network.cpp | 81 +++++++++++++++++++++++++++---------------------- node/Network.hpp | 24 +++++++-------- node/Node.cpp | 2 +- node/Packet.cpp | 1 + node/Packet.hpp | 3 ++ 8 files changed, 86 insertions(+), 58 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 39f077ff..ac04ce96 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -552,7 +552,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr bool approved = false; if (network) { if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - if (!network->isAllowed(peer)) { + if (!network->gate(peer,verb(),packetId())) { TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); } else { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); @@ -591,7 +591,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

addCredential(com); } - if (!network->isAllowed(peer)) { + if (!network->gate(peer,verb(),packetId())) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; @@ -619,7 +619,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } - } else if (to != network->mac()) { + } else if ( (to != network->mac()) && (!to.isMulticast()) ) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay @@ -934,7 +934,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share // Check membership after we've read any included COM, since // that cert might be what we needed. - if (!network->isAllowed(peer)) { + if (!network->gate(peer,verb(),packetId())) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; diff --git a/node/Membership.cpp b/node/Membership.cpp index 25ae1d9c..4ca008e3 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -24,13 +24,13 @@ #include "Packet.hpp" #include "Node.hpp" -#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 4) +#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3) namespace ZeroTier { void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap) { - if ((now - _lastPushAttempt) < 1000ULL) + if ((now - _lastPushAttempt) < 2000ULL) return; _lastPushAttempt = now; @@ -99,9 +99,11 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMe const int vr = com.verify(RR); if (vr == 0) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); - if (com.timestamp().first > _com.timestamp().first) { + if (com.timestamp().first >= _com.timestamp().first) { + TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); _com = com; + } else { + TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED but not used (OK but older than current)",com.issuedTo().toString().c_str(),com.networkId()); } } else { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (%d)",com.issuedTo().toString().c_str(),com.networkId(),vr); diff --git a/node/Membership.hpp b/node/Membership.hpp index 22910148..55355fda 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -154,6 +154,21 @@ public: return nconf.com.agreesWith(_com); } + /** + * @return True if this member has been on this network recently (or network is public) + */ + inline bool recentlyAllowedOnNetwork(const NetworkConfig &nconf) const + { + if (nconf.isPublic()) + return true; + if (_com) { + const uint64_t a = _com.timestamp().first; + const std::pair b(nconf.com.timestamp()); + return ((a <= b.first) ? ((b.first - a) <= ZT_PEER_ACTIVITY_TIMEOUT) : true); + } + return false; + } + /** * Check whether a capability or tag is within its max delta from the timestamp of our network config and newer than any blacklist cutoff time * diff --git a/node/Network.cpp b/node/Network.cpp index 7aa2a78b..2a5f213c 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -877,7 +877,7 @@ void Network::multicastSubscribe(const MulticastGroup &mg) return; _myMulticastGroups.push_back(mg); std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end()); - _announceMulticastGroups(&mg); + _pushStateToMembers(&mg); } } @@ -1062,6 +1062,36 @@ void Network::requestConfiguration() _inboundConfigChunks.clear(); } +bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +{ + Mutex::Lock _l(_lock); + try { + if (_config) { + Membership &m = _membership(peer->address()); + const bool allow = m.isAllowedOnNetwork(_config); + if (allow) { + const uint64_t now = RR->node->now(); + m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); + if (m.shouldLikeMulticasts(now)) { + _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); + m.likingMulticasts(now); + } + } else if (m.recentlyAllowedOnNetwork(_config)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)verb); + outp.append(packetId); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(_id); + RR->sw->send(outp,true); + } + return allow; + } + } catch ( ... ) { + TRACE("gate() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); + } + return false; +} + void Network::clean() { const uint64_t now = RR->node->now(); @@ -1135,7 +1165,7 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _announceMulticastGroups(&mg); + _pushStateToMembers(&mg); } void Network::destroy() @@ -1200,33 +1230,18 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } } -bool Network::_isAllowed(const SharedPtr &peer) const -{ - // Assumes _lock is locked - try { - if (_config) { - const Membership *const m = _memberships.get(peer->address()); - if (m) - return m->isAllowedOnNetwork(_config); - } - } catch ( ... ) { - TRACE("isAllowed() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); - } - return false; -} - -void Network::_announceMulticastGroups(const MulticastGroup *const onlyThis) +void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked const uint64_t now = RR->node->now(); std::vector groups; - if (onlyThis) - groups.push_back(*onlyThis); + if (newMulticastGroup) + groups.push_back(*newMulticastGroup); else groups = _allMulticastGroups(); - if ((onlyThis)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { - if (!onlyThis) + if ((newMulticastGroup)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { + if (!newMulticastGroup) _lastAnnouncedMulticastGroupsUpstream = now; // Announce multicast groups to upstream peers (roots, etc.) and also send @@ -1255,7 +1270,7 @@ void Network::_announceMulticastGroups(const MulticastGroup *const onlyThis) // piecemeal on-demand fashion. const std::vector

anchors(_config.anchors()); for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) - _memberships[*a]; + _membership(*a); // Send MULTICAST_LIKE(s) to all members of this network { @@ -1263,11 +1278,13 @@ void Network::_announceMulticastGroups(const MulticastGroup *const onlyThis) Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ((onlyThis)||(m->shouldLikeMulticasts(now))) { - if (!onlyThis) - m->likingMulticasts(now); + if ( (m->recentlyAllowedOnNetwork(_config)) || (std::find(anchors.begin(),anchors.end(),*a) != anchors.end()) ) { m->sendCredentialsIfNeeded(RR,RR->node->now(),*a,_config,(const Capability *)0); - _announceMulticastGroupsTo(*a,groups); + if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { + if (!newMulticastGroup) + m->likingMulticasts(now); + _announceMulticastGroupsTo(*a,groups); + } } } } @@ -1314,15 +1331,7 @@ std::vector Network::_allMulticastGroups() const Membership &Network::_membership(const Address &a) { // assumes _lock is locked - const unsigned long ms = _memberships.size(); - Membership &m = _memberships[a]; - if (ms != _memberships.size()) { - const uint64_t now = RR->node->now(); - m.sendCredentialsIfNeeded(RR,now,a,_config,(const Capability *)0); - _announceMulticastGroupsTo(a,_allMulticastGroups()); - m.likingMulticasts(now); - } - return m; + return _memberships[a]; } } // namespace ZeroTier diff --git a/node/Network.hpp b/node/Network.hpp index bcef2872..c80f1cba 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -48,7 +48,6 @@ namespace ZeroTier { class RuntimeEnvironment; class Peer; -class _MulticastAnnounceAll; /** * A virtual LAN @@ -56,7 +55,6 @@ class _MulticastAnnounceAll; class Network : NonCopyable { friend class SharedPtr; - friend class _MulticastAnnounceAll; // internal function object public: /** @@ -250,14 +248,14 @@ public: void requestConfiguration(); /** + * Membership check gate for incoming packets related to this network + * * @param peer Peer to check + * @param verb Packet verb + * @param packetId Packet ID * @return True if peer is allowed to communicate on this network */ - inline bool isAllowed(const SharedPtr &peer) const - { - Mutex::Lock _l(_lock); - return _isAllowed(peer); - } + bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); /** * Perform cleanup and possibly save state @@ -265,12 +263,12 @@ public: void clean(); /** - * Announce multicast groups to all members, anchors, etc. + * Push state to members such as multicast group memberships and latest COM (if needed) */ - inline void announceMulticastGroups() + inline void pushStateToMembers() { Mutex::Lock _l(_lock); - _announceMulticastGroups((const MulticastGroup *)0); + _pushStateToMembers((const MulticastGroup *)0); } /** @@ -408,11 +406,11 @@ public: private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - bool _isAllowed(const SharedPtr &peer) const; - void _announceMulticastGroups(const MulticastGroup *const onlyThis); + bool _gate(const SharedPtr &peer); + void _pushStateToMembers(const MulticastGroup *const newMulticastGroup); void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; - Membership &_membership(const Address &a); // also lazily sends COM and MULTICAST_LIKE(s) if this is a new member + Membership &_membership(const Address &a); const RuntimeEnvironment *RR; void *_uPtr; diff --git a/node/Node.cpp b/node/Node.cpp index 233ddc02..415385f7 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -263,7 +263,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - n->second->announceMulticastGroups(); + n->second->pushStateToMembers(); } } for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) diff --git a/node/Packet.cpp b/node/Packet.cpp index 9630e5bb..9ab68968 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -62,6 +62,7 @@ const char *Packet::errorString(ErrorCode e) case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; + case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; } diff --git a/node/Packet.hpp b/node/Packet.hpp index 27e289fd..5ead2c3d 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1067,6 +1067,9 @@ public: /* Verb or use case not supported/enabled by this node */ ERROR_UNSUPPORTED_OPERATION = 0x05, + /* Network membership certificate update needed */ + ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, + /* Tried to join network, but you're not a member */ ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ -- cgit v1.2.3 From 0d4109a9f1f119e336d73039251ad17c0e2a56f4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Sep 2016 08:43:58 -0700 Subject: More refactoring to clean up code, and add a gate function to make sure we do not handle OK packets we did not expect. This hardens up a few potential edge cases around security, since such messages might be used to e.g. pollute a cache and DOS under certain conditions. --- controller/EmbeddedNetworkController.cpp | 2 - include/ZeroTierOne.h | 12 +-- node/IncomingPacket.cpp | 156 ++++++++++++++++++------------- node/Membership.hpp | 6 +- node/Multicaster.cpp | 1 + node/Network.cpp | 10 ++ node/Network.hpp | 6 ++ node/Node.cpp | 3 + node/Node.hpp | 34 +++++++ node/OutboundMulticast.cpp | 1 + node/Packet.hpp | 5 +- node/Peer.cpp | 2 + node/Switch.cpp | 11 +-- 13 files changed, 168 insertions(+), 81 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index cf6bd7c9..79560dcc 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1585,7 +1585,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes "\t\"upstream\": \"%.10llx\"," ZT_EOL_S "\t\"current\": \"%.10llx\"," ZT_EOL_S "\t\"receivedTimestamp\": %llu," ZT_EOL_S - "\t\"remoteTimestamp\": %llu," ZT_EOL_S "\t\"sourcePacketId\": \"%.16llx\"," ZT_EOL_S "\t\"flags\": %llu," ZT_EOL_S "\t\"sourcePacketHopCount\": %u," ZT_EOL_S @@ -1606,7 +1605,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes (unsigned long long)report->upstream, (unsigned long long)report->current, (unsigned long long)OSUtils::now(), - (unsigned long long)report->remoteTimestamp, (unsigned long long)report->sourcePacketId, (unsigned long long)report->flags, report->sourcePacketHopCount, diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 0c22ae9d..633db7cf 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -154,6 +154,11 @@ extern "C" { */ #define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 8 +/** + * Circuit test report flag: upstream peer authorized in path (e.g. by network COM) + */ +#define ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH 0x0000000000000001ULL + /** * Maximum number of cluster members (and max member ID plus one) */ @@ -1218,18 +1223,13 @@ typedef struct { */ uint64_t timestamp; - /** - * Timestamp on remote device - */ - uint64_t remoteTimestamp; - /** * 64-bit packet ID of packet received by the reporting device */ uint64_t sourcePacketId; /** - * Flags (currently unused, will be zero) + * Flags */ uint64_t flags; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ac04ce96..c8364415 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -156,6 +156,17 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; + case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + network->config().com.serialize(outp); + outp.append((uint8_t)0); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + } + } 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())) @@ -163,10 +174,12 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr } break; case Packet::ERROR_UNWANTED_MULTICAST: { - uint64_t nwid = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); - MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",nwid,peer->address().toString().c_str(),mg.toString().c_str()); - RR->mc->remove(nwid,mg,peer->address()); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->gate(peer,verb(),packetId()))) { + MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); + TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); + RR->mc->remove(network->id(),mg,peer->address()); + } } break; default: break; @@ -352,7 +365,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); + if (!RR->node->expectingReplyTo(inRePacketId)) { + TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); + return true; + } + + //TRACE("%s(%s): OK(%s)",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { @@ -424,10 +442,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); - const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + SharedPtr network(RR->node->network(nwid)); + if ((network)&&(network->gate(peer,verb(),packetId()))) { + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); + //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); + const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + } } break; case Packet::VERB_MULTICAST_FRAME: { @@ -437,24 +458,26 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); - unsigned int offset = 0; + SharedPtr network(RR->node->network(nwid)); + if (network) { + unsigned int offset = 0; - if ((flags & 0x01) != 0) { // deprecated but still used by older peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - if (com) { - SharedPtr network(RR->node->network(com.networkId())); - if (network) + if ((flags & 0x01) != 0) { // deprecated but still used by older peers + CertificateOfMembership com; + offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); + if (com) network->addCredential(com); } - } - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + if (network->gate(peer,verb(),packetId())) { + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); offset += 4; + unsigned int count = at(offset); offset += 2; + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + } + } } } break; @@ -515,27 +538,29 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(with)); - if (rendezvousWith) { - 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))) { - const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (!RR->topology->isUpstream(peer->identity())) { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { - RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); - TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + if (!RR->topology->isUpstream(peer->identity())) { + TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); + } else { + const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + const SharedPtr rendezvousWith(RR->topology->getPeer(with)); + if (rendezvousWith) { + 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))) { + const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); + if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { + RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); + TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + } else { + TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + } } else { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); } } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { @@ -549,25 +574,25 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr try { const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); - bool approved = false; + bool trustEstablished = false; if (network) { - if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - } else { + if (!network->gate(peer,verb(),packetId())) { + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + } else { + trustEstablished = true; + if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); const MAC sourceMac(peer->address(),nwid); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - approved = true; // this means approved on the network in general, not this packet per se } } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -580,23 +605,23 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); if (network) { - if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; + const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; - unsigned int comLen = 0; - if ((flags & 0x01) != 0) { // deprecated but still used by old peers - CertificateOfMembership com; - comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); - if (com) - network->addCredential(com); - } + unsigned int comLen = 0; + if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers + CertificateOfMembership com; + comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); + if (com) + network->addCredential(com); + } - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); - return true; - } + if (!network->gate(peer,verb(),packetId())) { + TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + return true; + } + if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); @@ -604,7 +629,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -1139,6 +1164,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt // Add length of second "additional fields" section. vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); + uint64_t reportFlags = 0; + // Check credentials (signature already verified) if (originatorCredentialNetworkId) { SharedPtr network(RR->node->network(originatorCredentialNetworkId)); @@ -1147,6 +1174,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } + if (network->gate(peer,verb(),packetId())) + reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); @@ -1188,7 +1217,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED); outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED); outp.append((uint16_t)0); // error code, currently unused - outp.append((uint64_t)0); // flags, currently unused + outp.append((uint64_t)reportFlags); outp.append((uint64_t)packetId()); peer->address().appendTo(outp); outp.append((uint8_t)hops()); @@ -1237,7 +1266,6 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); - report.remoteTimestamp = at(ZT_PACKET_IDX_PAYLOAD + 16); report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58 diff --git a/node/Membership.hpp b/node/Membership.hpp index 55355fda..d67c6822 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -163,8 +163,10 @@ public: return true; if (_com) { const uint64_t a = _com.timestamp().first; - const std::pair b(nconf.com.timestamp()); - return ((a <= b.first) ? ((b.first - a) <= ZT_PEER_ACTIVITY_TIMEOUT) : true); + if ((_blacklistBefore)&&(a <= _blacklistBefore)) + return false; + const uint64_t b = nconf.com.timestamp().first; + return ((a <= b) ? ((b - a) <= ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA) : true); } return false; } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index a6bff6aa..36d7d2d0 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -253,6 +253,7 @@ void Multicaster::send( outp.append((uint32_t)gatherLimit); if (com) com->serialize(outp); + RR->node->expectReplyTo(outp.packetId()); RR->sw->send(outp,true); } } diff --git a/node/Network.cpp b/node/Network.cpp index 2a5f213c..710e70dd 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1054,6 +1054,7 @@ void Network::requestConfiguration() } else { outp.append((unsigned char)0,16); } + RR->node->expectReplyTo(outp.packetId()); outp.compress(); RR->sw->send(outp,true); @@ -1092,6 +1093,15 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } +bool Network::recentlyAllowedOnNetwork(const SharedPtr &peer) const +{ + Mutex::Lock _l(_lock); + const Membership *m = _memberships.get(peer->address()); + if (m) + return m->recentlyAllowedOnNetwork(_config); + return false; +} + void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index c80f1cba..e8d6e2a5 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -257,6 +257,12 @@ public: */ bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + /** + * @param peer Peer to check + * @return True if peer has recently been a valid member of this network + */ + bool recentlyAllowedOnNetwork(const SharedPtr &peer) const; + /** * Perform cleanup and possibly save state */ diff --git a/node/Node.cpp b/node/Node.cpp index 415385f7..e8279c62 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -75,6 +75,9 @@ Node::Node( { _online = false; + memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); + memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); + // Use Salsa20 alone as a high-quality non-crypto PRNG { char foo[32]; diff --git a/node/Node.hpp b/node/Node.hpp index 3c0a5e92..315b5248 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -44,6 +44,10 @@ #define TRACE(f,...) {} #endif +// Bit mask for "expecting reply" hash +#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 +#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 + namespace ZeroTier { /** @@ -250,6 +254,33 @@ public: void postCircuitTestReport(const ZT_CircuitTestReport *report); void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); + /** + * Register that we are expecting a reply to a packet ID + * + * @param packetId Packet ID to expect reply to + */ + inline void expectReplyTo(const uint64_t packetId) + { + const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + _expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = packetId; + } + + /** + * Check whether a given packet ID is something we are expecting a reply to + * + * @param packetId Packet ID to check + * @return True if we're expecting a reply + */ + inline bool expectingReplyTo(const uint64_t packetId) const + { + const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { + if (_expectingRepliesTo[bucket][i] == packetId) + return true; + } + return false; + } + private: inline SharedPtr _network(uint64_t nwid) const { @@ -266,6 +297,9 @@ private: void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P + uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; + uint64_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; + ZT_DataStoreGetFunction _dataStoreGetFunction; ZT_DataStorePutFunction _dataStorePutFunction; ZT_WirePacketSendFunction _wirePacketSendFunction; diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 33c28f65..6e811581 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -91,6 +91,7 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr2); + RR->node->expectReplyTo(_packet.packetId()); RR->sw->send(_packet,true); } } diff --git a/node/Packet.hpp b/node/Packet.hpp index 5ead2c3d..2ca73a84 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -965,7 +965,7 @@ public: * <[2] 16-bit reporter OS/platform or 0 if not specified> * <[2] 16-bit reporter architecture or 0 if not specified> * <[2] 16-bit error code (set to 0, currently unused)> - * <[8] 64-bit report flags (set to 0, currently unused)> + * <[8] 64-bit report flags> * <[8] 64-bit packet ID of received CIRCUIT_TEST packet> * <[5] upstream ZeroTier address from which CIRCUIT_TEST was received> * <[1] 8-bit packet hop count of received CIRCUIT_TEST> @@ -980,6 +980,9 @@ public: * <[5] ZeroTier address of next hop> * <[...] current best direct path address, if any, 0 if none> * + * Report flags: + * 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid) + * * Circuit test reports can be sent by hops in a circuit test to report * back results. They should include information about the sender as well * as about the paths to which next hops are being sent. diff --git a/node/Peer.cpp b/node/Peer.cpp index 58faab3b..a7a9fcc3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -266,6 +266,7 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u atAddress.serialize(outp); outp.append((uint64_t)RR->topology->worldId()); outp.append((uint64_t)RR->topology->worldTimestamp()); + RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } @@ -274,6 +275,7 @@ void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &at { if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); + RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { diff --git a/node/Switch.cpp b/node/Switch.cpp index 21d0b3c9..f2a0d35b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -734,13 +734,12 @@ unsigned long Switch::doTimerTasks(uint64_t now) Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { - SharedPtr root(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); - if (root) { - Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS); + SharedPtr upstream(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); + if (upstream) { + Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); - outp.armor(root->key(),true); - if (root->sendDirect(outp.data(),outp.size(),RR->node->now(),true)) - return root->address(); + RR->node->expectReplyTo(outp.packetId()); + send(outp,true); } return Address(); } -- cgit v1.2.3 From ef8706995786f26df7bcb9f69b2a332419841964 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Sep 2016 09:32:00 -0700 Subject: Fix gating of multicast GATHER replies since these can come from upstream, etc., and fix an issue with sending ECHO to recheck marginal paths. --- node/IncomingPacket.cpp | 4 ++-- node/Network.cpp | 5 +++++ node/Network.hpp | 5 +++++ node/NetworkConfig.hpp | 13 +++++++++++++ node/Switch.cpp | 7 ++----- 5 files changed, 27 insertions(+), 7 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c8364415..1ce942c9 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -443,7 +443,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->gate(peer,verb(),packetId()))) { + if ((network)&&(network->gateMulticastGather(peer,verb(),packetId()))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -469,7 +469,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->addCredential(com); } - if (network->gate(peer,verb(),packetId())) { + if (network->gateMulticastGather(peer,verb(),packetId())) { if ((flags & 0x02) != 0) { // OK(MULTICAST_FRAME) includes implicit gather results offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; diff --git a/node/Network.cpp b/node/Network.cpp index 710e70dd..a9b14942 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1093,6 +1093,11 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } +bool Network::gateMulticastGather(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +{ + return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); +} + bool Network::recentlyAllowedOnNetwork(const SharedPtr &peer) const { Mutex::Lock _l(_lock); diff --git a/node/Network.hpp b/node/Network.hpp index e8d6e2a5..d80b13b9 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -257,6 +257,11 @@ public: */ bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + /** + * Check whether this peer is allowed to provide multicast info for this network + */ + bool gateMulticastGather(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + /** * @param peer Peer to check * @return True if peer has recently been a valid member of this network diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index b5ab9ccb..ad1cafa5 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -285,6 +285,19 @@ public: return r; } + /** + * @param a Address to check + * @return True if address is an anchor + */ + inline bool isAnchor(const Address &a) const + { + for(unsigned int i=0;i viaPath(peer->getBestPath(now,false)); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) { - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) >> 2,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ECHO); - outp.armor(peer->key(),true); - viaPath->send(RR,outp.data(),outp.size(),now); - } + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) + peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now); viaPath.zero(); } if (!viaPath) { -- cgit v1.2.3 From ab9afbc749f24f08f25dcf8bd6f4263b97c79bb9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Sep 2016 11:36:10 -0700 Subject: (1) Public networks now get COMs even though they do not gate with them since they will need them to push auth for multicast stuff, (2) added a bunch of rate limit circuit breakers for anti-DOS, (3) cleanup. --- controller/EmbeddedNetworkController.cpp | 12 +-- node/Constants.hpp | 20 ++++ node/IncomingPacket.cpp | 152 ++++++++++++++++++----------- node/IncomingPacket.hpp | 2 +- node/Membership.cpp | 2 +- node/Multicaster.cpp | 80 ++++++++++------ node/Multicaster.hpp | 40 ++++++++ node/Network.cpp | 72 ++++++++------ node/Network.hpp | 20 ++-- node/Node.cpp | 2 +- node/Path.hpp | 15 +++ node/Peer.cpp | 160 +++++++++++++++---------------- node/Peer.hpp | 43 ++++++++- 13 files changed, 393 insertions(+), 227 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 79560dcc..861792ed 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -924,13 +924,11 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } } - if (_jB(network["private"],true)) { - CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); - if (com.sign(signingId)) { - nc.com = com; - } else { - return NETCONF_QUERY_INTERNAL_SERVER_ERROR; - } + CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); + if (com.sign(signingId)) { + nc.com = com; + } else { + return NETCONF_QUERY_INTERNAL_SERVER_ERROR; } _writeJson(memberJP,member); diff --git a/node/Constants.hpp b/node/Constants.hpp index a625b480..05cd765a 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -236,6 +236,11 @@ */ #define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10) +/** + * Expiration for credentials presented for MULTICAST_LIKE or MULTICAST_GATHER (for non-network-members) + */ +#define ZT_MULTICAST_CREDENTIAL_EXPIRATON ZT_MULTICAST_LIKE_EXPIRE + /** * Timeout for outgoing multicasts * @@ -263,6 +268,11 @@ */ #define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 +/** + * Do not accept HELLOs over a given path more often than this + */ +#define ZT_PATH_HELLO_RATE_LIMIT 1000 + /** * Delay between full-fledge pings of directly connected peers */ @@ -283,6 +293,11 @@ */ #define ZT_PEER_ACTIVITY_TIMEOUT 500000 +/** + * General rate limit timeout for multiple packet types (HELLO, etc.) + */ +#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 1000 + /** * Delay between requests for updated network autoconf information * @@ -326,6 +341,11 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 +/** + * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound + */ +#define ZT_PEER_GENERAL_RATE_LIMIT 1000 + /** * Maximum number of direct path pushes within cutoff time * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1ce942c9..7f996dab 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -62,11 +62,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { - // A null pointer for peer to _doHELLO() tells it to run its own - // special internal authentication logic. This is done for unencrypted - // HELLOs to learn new identities, etc. - SharedPtr tmp; - return _doHELLO(RR,tmp); + // Only HELLO is allowed in the clear, but will still have a MAC + return _doHELLO(RR,false); } SharedPtr peer(RR->topology->getPeer(sourceAddress)); @@ -91,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,peer); + case Packet::VERB_HELLO: return _doHELLO(RR,true); case Packet::VERB_ERROR: return _doERROR(RR,peer); case Packet::VERB_OK: return _doOK(RR,peer); case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); @@ -192,16 +189,16 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr return true; } -bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer) +bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated) { - /* Note: this is the only packet ever sent in the clear, and it's also - * the only packet that we authenticate via a different path. Authentication - * occurs here and is based on the validity of the identity and the - * integrity of the packet's MAC, but it must be done after we check - * the identity since HELLO is a mechanism for learning new identities - * in the first place. */ - try { + const uint64_t now = RR->node->now(); + + if (!_path->rateGateHello(now)) { + TRACE("dropped HELLO from %s(%s): rate limiting circuit breaker for HELLO on this path tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + const uint64_t pid = packetId(); const Address fromAddress(source()); const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; @@ -228,20 +225,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } } - if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } if (fromAddress != id.address()) { TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; } + if (protoVersion < ZT_PROTO_VERSION_MIN) { + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } - if (!peer) { // peer == NULL is the normal case here - peer = RR->topology->getPeer(id.address()); - if (peer) { - // We already have an identity with this address -- check for collisions - + SharedPtr peer(RR->topology->getPeer(id.address())); + if (peer) { + // We already have an identity with this address -- check for collisions + if (!alreadyAuthenticated) { if (peer->identity() != id) { // Identity is different from the one we already have -- address collision @@ -273,31 +269,37 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // Continue at // VALID } - } else { - // We don't already have an identity with this address -- validate and learn it + } // else continue at // VALID + } else { + // We don't already have an identity with this address -- validate and learn it - // Check identity proof of work - if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } + // Sanity check: this basically can't happen + if (alreadyAuthenticated) { + TRACE("dropped HELLO from %s(%s): somehow already authenticated with unknown peer?",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } - // Check packet integrity and authentication - SharedPtr newPeer(new Peer(RR,RR->identity,id)); - if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - peer = RR->topology->addPeer(newPeer); + // Check identity proof of work + if (!id.locallyValidate()) { + TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } - // Continue at // VALID + // Check packet integrity and authentication + SharedPtr newPeer(new Peer(RR,RR->identity,id)); + if (!dearmor(newPeer->key())) { + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; } + peer = RR->topology->addPeer(newPeer); - // VALID -- if we made it here, packet passed identity and authenticity checks! + // Continue at // VALID } + // VALID -- if we made it here, packet passed identity and authenticity checks! + if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); + RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_HELLO); @@ -349,7 +351,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); @@ -443,7 +445,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->gateMulticastGather(peer,verb(),packetId()))) { + if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -469,7 +471,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->addCredential(com); } - if (network->gateMulticastGather(peer,verb(),packetId())) { + if (network->gateMulticastGatherReply(peer,verb(),packetId())) { if ((flags & 0x02) != 0) { // OK(MULTICAST_FRAME) includes implicit gather results offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; @@ -494,6 +496,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { + if (!peer->rateGateInboundWhoisRequest(RR->node->now())) { + TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); outp.append(packetId()); @@ -672,6 +679,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&peer) { try { + if (!peer->rateGateEchoRequest(RR->node->now())) { + TRACE("dropped ECHO from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + const uint64_t pid = packetId(); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_ECHO); @@ -680,6 +692,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -692,11 +705,35 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared try { const uint64_t now = RR->node->now(); + uint64_t authOnNetwork[256]; + unsigned int authOnNetworkCount = 0; + SharedPtr network; + // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); - const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); - RR->mc->add(now,nwid,group,peer->address()); + + bool auth = false; + for(unsigned int i=0;iid() != nwid)) + network = RR->node->network(nwid); + if ( ((network)&&(network->gate(peer,verb(),packetId()))) || RR->mc->cacheAuthorized(peer->address(),nwid,now) ) { + auth = true; + if (authOnNetworkCount < 256) // sanity check, packets can't really be this big + authOnNetwork[authOnNetworkCount++] = nwid; + } + } + + if (auth) { + const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); + RR->mc->add(now,nwid,group,peer->address()); + } } peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); @@ -721,7 +758,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S if (network) { if (network->addCredential(com) == 1) return false; // wait for WHOIS - } + } else RR->mc->addCredential(com,false); } } ++p; // skip trailing 0 after COMs if present @@ -759,22 +796,21 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons { try { const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); - - const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); - const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); - const Dictionary metaData(metaDataBytes,metaDataLength); - const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - bool netconfOk = false; + bool trustEstablished = false; if (RR->localNetworkController) { + const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); + const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); + const Dictionary metaData(metaDataBytes,metaDataLength); + NetworkConfig *netconf = new NetworkConfig(); try { switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) { case NetworkController::NETCONF_QUERY_OK: { - netconfOk = true; + trustEstablished = true; Dictionary *dconf = new Dictionary(); try { if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { @@ -846,7 +882,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,trustEstablished); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -897,21 +933,23 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); + const SharedPtr network(RR->node->network(nwid)); + if ((flags & 0x01) != 0) { try { CertificateOfMembership com; com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); if (com) { - SharedPtr network(RR->node->network(nwid)); if (network) network->addCredential(com); + else RR->mc->addCredential(com,false); } } catch ( ... ) { TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); } } - if (gatherLimit) { + if ( ( ((network)&&(network->gate(peer,verb(),packetId()))) || (RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now())) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); outp.append(packetId()); @@ -1043,7 +1081,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha const uint64_t now = RR->node->now(); // First, subject this to a rate limit - if (!peer->shouldRespondToDirectPathPush(now)) { + if (!peer->rateGatePushDirectPaths(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 35438f4f..dbaf67b8 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -136,7 +136,7 @@ private: // These are called internally to handle packet contents once it has // been authenticated, decrypted, decompressed, and classified. bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer); // can be called with NULL peer, while all others cannot + bool _doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated); bool _doOK(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer); diff --git a/node/Membership.cpp b/node/Membership.cpp index 4ca008e3..8c2ba673 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -71,7 +71,7 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint } capsAndTags.setAt(tagCountPos,(uint16_t)appendedTags); - const bool needCom = ((nconf.isPrivate())&&(nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)); + const bool needCom = ((nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)); if ( (needCom) || (appendedCaps) || (appendedTags) ) { Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); if (needCom) { diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 36d7d2d0..fc8fa1bd 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -34,8 +34,8 @@ namespace ZeroTier { Multicaster::Multicaster(const RuntimeEnvironment *renv) : RR(renv), - _groups(1024), - _groups_m() + _groups(256), + _gatherAuth(256) { } @@ -244,7 +244,7 @@ void Multicaster::send( } for(unsigned int k=0;kconfig())&&(network->config().isPrivate())) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; + const CertificateOfMembership *com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER); outp.append(nwid); outp.append((uint8_t)((com) ? 0x01 : 0x00)); @@ -301,42 +301,62 @@ void Multicaster::send( void Multicaster::clean(uint64_t now) { - Mutex::Lock _l(_groups_m); - - Multicaster::Key *k = (Multicaster::Key *)0; - MulticastGroupStatus *s = (MulticastGroupStatus *)0; - Hashtable::Iterator mm(_groups); - while (mm.next(k,s)) { - for(std::list::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { - if ((tx->expired(now))||(tx->atLimit())) - s->txQueue.erase(tx++); - else ++tx; - } + { + Mutex::Lock _l(_groups_m); + Multicaster::Key *k = (Multicaster::Key *)0; + MulticastGroupStatus *s = (MulticastGroupStatus *)0; + Hashtable::Iterator mm(_groups); + while (mm.next(k,s)) { + for(std::list::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { + if ((tx->expired(now))||(tx->atLimit())) + s->txQueue.erase(tx++); + else ++tx; + } - unsigned long count = 0; - { - std::vector::iterator reader(s->members.begin()); - std::vector::iterator writer(reader); - while (reader != s->members.end()) { - if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { - *writer = *reader; - ++writer; - ++count; + unsigned long count = 0; + { + std::vector::iterator reader(s->members.begin()); + std::vector::iterator writer(reader); + while (reader != s->members.end()) { + if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { + *writer = *reader; + ++writer; + ++count; + } + ++reader; } - ++reader; + } + + if (count) { + s->members.resize(count); + } else if (s->txQueue.empty()) { + _groups.erase(*k); + } else { + s->members.clear(); } } + } - if (count) { - s->members.resize(count); - } else if (s->txQueue.empty()) { - _groups.erase(*k); - } else { - s->members.clear(); + { + Mutex::Lock _l(_gatherAuth_m); + _GatherAuthKey *k = (_GatherAuthKey *)0; + uint64_t *ts = (uint64_t *)ts; + Hashtable<_GatherAuthKey,uint64_t>::Iterator i(_gatherAuth); + while (i.next(k,ts)) { + if ((now - *ts) >= ZT_MULTICAST_CREDENTIAL_EXPIRATON) + _gatherAuth.erase(*k); } } } +void Multicaster::addCredential(const CertificateOfMembership &com,bool alreadyValidated) +{ + if ((alreadyValidated)||(com.verify(RR) == 0)) { + Mutex::Lock _l(_gatherAuth_m); + _gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now(); + } +} + void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) { // assumes _groups_m is locked diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 51dabc69..8be3b736 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -179,12 +179,52 @@ public: */ void clean(uint64_t now); + /** + * Add an authorization credential + * + * The Multicaster keeps its own track of when valid credentials of network + * membership are presented. This allows it to control MULTICAST_LIKE + * GATHER authorization for networks this node does not belong to. + * + * @param com Certificate of membership + * @param alreadyValidated If true, COM has already been checked and found to be valid and signed + */ + void addCredential(const CertificateOfMembership &com,bool alreadyValidated); + + /** + * Check authorization for GATHER and LIKE for non-network-members + * + * @param a Address of peer + * @param nwid Network ID + * @param now Current time + * @return True if GATHER and LIKE should be allowed + */ + bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const + { + Mutex::Lock _l(_gatherAuth_m); + const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a)); + return ((p)&&((now - *p) < ZT_MULTICAST_CREDENTIAL_EXPIRATON)); + } + private: void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); const RuntimeEnvironment *RR; + Hashtable _groups; Mutex _groups_m; + + struct _GatherAuthKey + { + _GatherAuthKey() : member(0),networkId(0) {} + _GatherAuthKey(const uint64_t nwid,const Address &a) : member(a.toInt()),networkId(nwid) {} + inline unsigned long hashCode() const { return (member ^ networkId); } + inline bool operator==(const _GatherAuthKey &k) const { return ((member == k.member)&&(networkId == k.networkId)); } + uint64_t member; + uint64_t networkId; + }; + Hashtable< _GatherAuthKey,uint64_t > _gatherAuth; + Mutex _gatherAuth_m; }; } // namespace ZeroTier diff --git a/node/Network.cpp b/node/Network.cpp index a9b14942..146f2962 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -866,31 +866,24 @@ bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBr return true; else if (includeBridgedGroups) return _multicastGroupsBehindMe.contains(mg); - else return false; + return false; } void Network::multicastSubscribe(const MulticastGroup &mg) { - { - Mutex::Lock _l(_lock); - if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) - return; - _myMulticastGroups.push_back(mg); - std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end()); - _pushStateToMembers(&mg); + Mutex::Lock _l(_lock); + if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { + _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg); + _sendUpdatesToMembers(&mg); } } void Network::multicastUnsubscribe(const MulticastGroup &mg) { Mutex::Lock _l(_lock); - std::vector nmg; - for(std::vector::const_iterator i(_myMulticastGroups.begin());i!=_myMulticastGroups.end();++i) { - if (*i != mg) - nmg.push_back(*i); - } - if (nmg.size() != _myMulticastGroups.size()) - _myMulticastGroups.swap(nmg); + std::vector::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)); + if ( (i != _myMulticastGroups.end()) && (*i == mg) ) + _myMulticastGroups.erase(i); } bool Network::applyConfiguration(const NetworkConfig &conf) @@ -1054,30 +1047,29 @@ void Network::requestConfiguration() } else { outp.append((unsigned char)0,16); } - RR->node->expectReplyTo(outp.packetId()); - outp.compress(); - RR->sw->send(outp,true); - // Expect replies with this in-re packet ID - _inboundConfigPacketId = outp.packetId(); + RR->node->expectReplyTo(_inboundConfigPacketId = outp.packetId()); _inboundConfigChunks.clear(); + + outp.compress(); + RR->sw->send(outp,true); } bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) { + const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); try { if (_config) { Membership &m = _membership(peer->address()); const bool allow = m.isAllowedOnNetwork(_config); if (allow) { - const uint64_t now = RR->node->now(); m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); if (m.shouldLikeMulticasts(now)) { _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); m.likingMulticasts(now); } - } else if (m.recentlyAllowedOnNetwork(_config)) { + } else if (m.recentlyAllowedOnNetwork(_config)&&peer->rateGateRequestCredentials(now)) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)verb); outp.append(packetId); @@ -1093,7 +1085,7 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } -bool Network::gateMulticastGather(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) { return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); } @@ -1180,7 +1172,22 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _pushStateToMembers(&mg); + _sendUpdatesToMembers(&mg); +} + +int Network::addCredential(const CertificateOfMembership &com) +{ + if (com.networkId() != _id) + return -1; + const Address a(com.issuedTo()); + Mutex::Lock _l(_lock); + Membership &m = _membership(a); + const int result = m.addCredential(RR,com); + if (result == 0) { + m.sendCredentialsIfNeeded(RR,RR->node->now(),a,_config,(const Capability *)0); + RR->mc->addCredential(com,true); + } + return result; } void Network::destroy() @@ -1245,7 +1252,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } } -void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) +void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked const uint64_t now = RR->node->now(); @@ -1263,7 +1270,7 @@ void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) // them our COM so that MULTICAST_GATHER can be authenticated properly. const std::vector

upstreams(RR->topology->upstreamAddresses()); for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { - if ((_config.isPrivate())&&(_config.com)) { + if (_config.com) { Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); _config.com.serialize(outp); outp.append((uint8_t)0x00); @@ -1272,12 +1279,17 @@ void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) _announceMulticastGroupsTo(*a,groups); } - // Announce to controller, which does not need our COM since it obviously - // knows if we are a member. Of course if we already did or are going to - // below then we can skip it here. + // Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it const Address c(controller()); - if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) ) + if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) ) { + if (_config.com) { + Packet outp(c,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + _config.com.serialize(outp); + outp.append((uint8_t)0x00); + RR->sw->send(outp,true); + } _announceMulticastGroupsTo(c,groups); + } } // Make sure that all "network anchors" have Membership records so we will diff --git a/node/Network.hpp b/node/Network.hpp index d80b13b9..7a4065ff 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -260,7 +260,7 @@ public: /** * Check whether this peer is allowed to provide multicast info for this network */ - bool gateMulticastGather(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); /** * @param peer Peer to check @@ -276,10 +276,10 @@ public: /** * Push state to members such as multicast group memberships and latest COM (if needed) */ - inline void pushStateToMembers() + inline void sendUpdatesToMembers() { Mutex::Lock _l(_lock); - _pushStateToMembers((const MulticastGroup *)0); + _sendUpdatesToMembers((const MulticastGroup *)0); } /** @@ -332,9 +332,7 @@ public: { Mutex::Lock _l(_lock); const Address *const br = _remoteBridgeRoutes.get(mac); - if (br) - return *br; - return Address(); + return ((br) ? *br : Address()); } /** @@ -357,13 +355,7 @@ public: * @param com Certificate of membership * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - inline int addCredential(const CertificateOfMembership &com) - { - if (com.networkId() != _id) - return -1; - Mutex::Lock _l(_lock); - return _membership(com.issuedTo()).addCredential(RR,com); - } + int addCredential(const CertificateOfMembership &com); /** * @param cap Capability @@ -418,7 +410,7 @@ private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _gate(const SharedPtr &peer); - void _pushStateToMembers(const MulticastGroup *const newMulticastGroup); + void _sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup); void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; Membership &_membership(const Address &a); diff --git a/node/Node.cpp b/node/Node.cpp index e8279c62..59794854 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -266,7 +266,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - n->second->pushStateToMembers(); + n->second->sendUpdatesToMembers(); } } for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) diff --git a/node/Path.hpp b/node/Path.hpp index 27cff645..6278532d 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -104,6 +104,7 @@ public: Path() : _lastOut(0), _lastIn(0), + _lastHello(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -113,6 +114,7 @@ public: Path(const InetAddress &localAddress,const InetAddress &addr) : _lastOut(0), _lastIn(0), + _lastHello(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -229,9 +231,22 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } + /** + * @return True if we should allow HELLO via this path + */ + inline bool rateGateHello(const uint64_t now) + { + if ((now - _lastHello) >= ZT_PATH_HELLO_RATE_LIMIT) { + _lastHello = now; + return true; + } + return false; + } + private: uint64_t _lastOut; uint64_t _lastIn; + uint64_t _lastHello; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index a7a9fcc3..0e6ef333 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -47,6 +47,9 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastMulticastFrame(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), + _lastCredentialRequestSent(0), + _lastWhoisRequestReceived(0), + _lastEchoRequestReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), @@ -194,7 +197,80 @@ void Peer::received( } } else if (trustEstablished) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) - _pushDirectPaths(path,now); +#ifdef ZT_ENABLE_CLUSTER + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + const bool haveCluster = (RR->cluster); +#else + const bool haveCluster = false; +#endif + if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { + _lastDirectPathPushSent = now; + + std::vector pathsToPush; + + std::vector dps(RR->node->directPaths()); + for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) + pathsToPush.push_back(*i); + + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } + } + + if (pathsToPush.size() > 0) { +#ifdef ZT_TRACE + std::string ps; + for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { + if (ps.length() > 0) + ps.push_back(','); + ps.append(p->toString()); + } + TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); +#endif + + std::vector::const_iterator p(pathsToPush.begin()); + while (p != pathsToPush.end()) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); + outp.addSize(2); // leave room for count + + unsigned int count = 0; + while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { + uint8_t addressType = 4; + switch(p->ss_family) { + case AF_INET: + break; + case AF_INET6: + addressType = 6; + break; + default: // we currently only push IP addresses + ++p; + continue; + } + + outp.append((uint8_t)0); // no flags + outp.append((uint16_t)0); // no extensions + outp.append(addressType); + outp.append((uint8_t)((addressType == 4) ? 6 : 18)); + outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); + outp.append((uint16_t)p->port()); + + ++count; + ++p; + } + + if (count) { + outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); + outp.armor(_key,true); + path->send(RR,outp.data(),outp.size(),now); + } + } + } + } } } @@ -368,86 +444,4 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) v6 = _paths[bestp6].path->address(); } -bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) -{ -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - if (RR->cluster) - return false; -#endif - - if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL) - return false; - else _lastDirectPathPushSent = now; - - std::vector pathsToPush; - - std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) - pathsToPush.push_back(*i); - - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; - } - } - if (pathsToPush.empty()) - return false; - -#ifdef ZT_TRACE - { - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); - } -#endif - - std::vector::const_iterator p(pathsToPush.begin()); - while (p != pathsToPush.end()) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.addSize(2); // leave room for count - - unsigned int count = 0; - while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { - uint8_t addressType = 4; - switch(p->ss_family) { - case AF_INET: - break; - case AF_INET6: - addressType = 6; - break; - default: // we currently only push IP addresses - ++p; - continue; - } - - outp.append((uint8_t)0); // no flags - outp.append((uint16_t)0); // no extensions - outp.append(addressType); - outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->port()); - - ++count; - ++p; - } - - if (count) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true); - path->send(RR,outp.data(),outp.size(),now); - } - } - - return true; -} - } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 2e64fb4d..d714b937 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -348,7 +348,7 @@ public: * @param now Current time * @return True if we should respond */ - inline bool shouldRespondToDirectPathPush(const uint64_t now) + inline bool rateGatePushDirectPaths(const uint64_t now) { if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) ++_directPathPushCutoffCount; @@ -357,6 +357,42 @@ public: return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); } + /** + * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE + */ + inline bool rateGateRequestCredentials(const uint64_t now) + { + if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastCredentialRequestSent = now; + return true; + } + return false; + } + + /** + * Rate limit gate for inbound WHOIS requests + */ + inline bool rateGateInboundWhoisRequest(const uint64_t now) + { + if ((now - _lastWhoisRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastWhoisRequestReceived = now; + return true; + } + return false; + } + + /** + * Rate limit gate for inbound ECHO requests + */ + inline bool rateGateEchoRequest(const uint64_t now) + { + if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastEchoRequestReceived = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -378,8 +414,6 @@ public: } private: - bool _pushDirectPaths(const SharedPtr &path,uint64_t now); - inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const { uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); @@ -415,6 +449,9 @@ private: uint64_t _lastMulticastFrame; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; + uint64_t _lastCredentialRequestSent; + uint64_t _lastWhoisRequestReceived; + uint64_t _lastEchoRequestReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; -- cgit v1.2.3 From debc4c45ee138f7e59ec3adbc031cd6e0b77eae0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Sep 2016 11:45:34 -0700 Subject: Set trust established flag in MULTICAST_GATHER. --- node/IncomingPacket.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7f996dab..a1458a80 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -949,7 +949,8 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar } } - if ( ( ((network)&&(network->gate(peer,verb(),packetId()))) || (RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now())) ) && (gatherLimit > 0) ) { + const bool trustEstablished = ((network)&&(network->gate(peer,verb(),packetId()))); + if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); outp.append(packetId()); @@ -969,7 +970,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -995,8 +996,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->addCredential(com); } - // Check membership after we've read any included COM, since - // that cert might be what we needed. if (!network->gate(peer,verb(),packetId())) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); -- cgit v1.2.3 From ea1da3321a8f95eb2f42b62d805841e2d8379e21 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 12 Sep 2016 15:19:21 -0700 Subject: Rate gate requests for COM. --- node/IncomingPacket.cpp | 13 ++++++++----- node/Peer.cpp | 1 + node/Peer.hpp | 13 +++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a1458a80..eff87350 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -156,11 +156,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - network->config().com.serialize(outp); - outp.append((uint8_t)0); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + const uint64_t now = RR->node->now(); + if (peer->rateGateComRequest(now)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + network->config().com.serialize(outp); + outp.append((uint8_t)0); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),now); + } } } break; diff --git a/node/Peer.cpp b/node/Peer.cpp index 0e6ef333..f7a21ab1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -50,6 +50,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastCredentialRequestSent(0), _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), + _lastComRequestReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), diff --git a/node/Peer.hpp b/node/Peer.hpp index d714b937..a804dd91 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -393,6 +393,18 @@ public: return false; } + /** + * Rate gate requests for network COM + */ + inline bool rateGateComRequest(const uint64_t now) + { + if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastComRequestReceived = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -452,6 +464,7 @@ private: uint64_t _lastCredentialRequestSent; uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; + uint64_t _lastComRequestReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; -- cgit v1.2.3 From cba37c610786417ad73f455cfb3b6c5d0daf07e8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Sep 2016 10:13:23 -0700 Subject: Add a few more rate limit gates for anti-DOS hardening. --- node/Constants.hpp | 20 +++++++++++++----- node/IncomingPacket.cpp | 54 ++++++++++++++++++++++++++++++++++++++++--------- node/Peer.cpp | 4 +++- node/Peer.hpp | 24 +++++++++++++--------- 4 files changed, 77 insertions(+), 25 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 05cd765a..afd2e4ec 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -341,11 +341,6 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 -/** - * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound - */ -#define ZT_PEER_GENERAL_RATE_LIMIT 1000 - /** * Maximum number of direct path pushes within cutoff time * @@ -355,6 +350,21 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 +/** + * Time horizon for VERB_NETWORK_CREDENTIALS cutoff + */ +#define ZT_PEER_CREDENTIALS_CUTOFF_TIME 60000 + +/** + * Maximum number of VERB_NETWORK_CREDENTIALS within cutoff time + */ +#define ZT_PEER_CREDEITIALS_CUTOFF_LIMIT 15 + +/** + * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound + */ +#define ZT_PEER_GENERAL_RATE_LIMIT 1000 + /** * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index eff87350..84503406 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -133,6 +133,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr switch(errorCode) { case Packet::ERROR_OBJ_NOT_FOUND: + // Object not found, currently only meaningful from network controllers. if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) @@ -141,6 +142,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_UNSUPPORTED_OPERATION: + // This can be sent in response to any operation, though right now we only + // consider it meaningful from network controllers. This would indicate + // that the queried node does not support acting as a controller. if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) @@ -149,11 +153,18 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_IDENTITY_COLLISION: + // Roots are the only peers currently permitted to state authoritatively + // that an identity has collided. When this occurs the node should be shut + // down and a new identity created. The odds of this ever happening are + // very low. if (RR->topology->isRoot(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + // This error can be sent in response to any packet that fails network + // authorization. We only listen to it if it's from a peer that has recently + // been authorized on this network. SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { const uint64_t now = RR->node->now(); @@ -168,12 +179,15 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr } break; case Packet::ERROR_NETWORK_ACCESS_DENIED_: { + // Network controller: network access denied. SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) network->setAccessDenied(); } break; case Packet::ERROR_UNWANTED_MULTICAST: { + // Members of networks can use this error to indicate that they no longer + // want to receive multicasts on a given channel. SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->gate(peer,verb(),packetId()))) { MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); @@ -301,6 +315,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // VALID -- if we made it here, packet passed identity and authenticity checks! + // Learn our external surface address from other peers to help us negotiate symmetric NATs + // and detect changes to our global IP that can trigger path renegotiation. if ((externalSurfaceAddress)&&(hops() == 0)) RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); @@ -370,6 +386,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + // Don't parse OK packets that are not in response to a packet ID we sent if (!RR->node->expectingReplyTo(inRePacketId)) { TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); return true; @@ -711,6 +728,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared uint64_t authOnNetwork[256]; unsigned int authOnNetworkCount = 0; SharedPtr network; + bool trustEstablished = false; // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptrid() != nwid)) network = RR->node->network(nwid); - if ( ((network)&&(network->gate(peer,verb(),packetId()))) || RR->mc->cacheAuthorized(peer->address(),nwid,now) ) { + const bool authOnNet = ((network)&&(network->gate(peer,verb(),packetId()))); + trustEstablished |= authOnNet; + if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; if (authOnNetworkCount < 256) // sanity check, packets can't really be this big authOnNetwork[authOnNetworkCount++] = nwid; @@ -739,7 +759,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -749,9 +769,15 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { + if (!peer->rateGateCredentialsReceived(RR->node->now())) { + TRACE("dropped NETWORK_CREDENTIALS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + CertificateOfMembership com; Capability cap; Tag tag; + bool trustEstablished = false; unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p])) { @@ -759,8 +785,10 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S if (com) { SharedPtr network(RR->node->network(com.networkId())); if (network) { - if (network->addCredential(com) == 1) - return false; // wait for WHOIS + switch (network->addCredential(com)) { + case 0: trustEstablished = true; break; + case 1: return false; // wait for WHOIS + } } else RR->mc->addCredential(com,false); } } @@ -772,8 +800,10 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += cap.deserialize(*this,p); SharedPtr network(RR->node->network(cap.networkId())); if (network) { - if (network->addCredential(cap) == 1) - return false; // wait for WHOIS + switch (network->addCredential(cap)) { + case 0: trustEstablished = true; break; + case 1: return false; // wait for WHOIS + } } } @@ -782,13 +812,15 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += tag.deserialize(*this,p); SharedPtr network(RR->node->network(tag.networkId())); if (network) { - if (network->addCredential(tag) == 1) - return false; // wait for WHOIS + switch (network->addCredential(tag)) { + case 0: trustEstablished = true; break; + case 1: return false; // wait for WHOIS + } } } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -900,11 +932,13 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons { try { const uint64_t nwid = at(ZT_PACKET_IDX_PAYLOAD); + bool trustEstablished = false; if (Network::controllerFor(nwid) == peer->address()) { SharedPtr network(RR->node->network(nwid)); if (network) { network->requestConfiguration(); + trustEstablished = true; } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); @@ -919,7 +953,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Peer.cpp b/node/Peer.cpp index f7a21ab1..560ca786 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -51,6 +51,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), _lastComRequestReceived(0), + _lastCredentialsReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), @@ -60,7 +61,8 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _id(peerIdentity), _numPaths(0), _latency(0), - _directPathPushCutoffCount(0) + _directPathPushCutoffCount(0), + _credentialsCutoffCount(0) { memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) diff --git a/node/Peer.hpp b/node/Peer.hpp index a804dd91..5382e3f0 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -338,15 +338,7 @@ public: inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } /** - * 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 + * Rate limit gate for VERB_PUSH_DIRECT_PATHS */ inline bool rateGatePushDirectPaths(const uint64_t now) { @@ -357,6 +349,18 @@ public: return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); } + /** + * Rate limit gate for VERB_NETWORK_CREDENTIALS + */ + inline bool rateGateCredentialsReceived(const uint64_t now) + { + if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME) + ++_credentialsCutoffCount; + else _credentialsCutoffCount = 0; + _lastCredentialsReceived = now; + return (_directPathPushCutoffCount < ZT_PEER_CREDEITIALS_CUTOFF_LIMIT); + } + /** * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE */ @@ -465,6 +469,7 @@ private: uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; + uint64_t _lastCredentialsReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; @@ -483,6 +488,7 @@ private: unsigned int _numPaths; unsigned int _latency; unsigned int _directPathPushCutoffCount; + unsigned int _credentialsCutoffCount; AtomicCounter __refCount; }; -- cgit v1.2.3 From 0da9a9a3e01772bf9d534289c755ba96bd099ac9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Sep 2016 10:33:03 -0700 Subject: Set trustEstablished in a few more places. --- node/IncomingPacket.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 84503406..7510fec8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -385,6 +385,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + bool trustEstablished = false; // Don't parse OK packets that are not in response to a packet ID we sent if (!RR->node->expectingReplyTo(inRePacketId)) { @@ -446,6 +447,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); if ((network)&&(network->controller() == peer->address())) { + trustEstablished = true; const unsigned int chunkLen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); const void *chunkData = field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,chunkLen); unsigned int chunkIndex = 0; @@ -466,6 +468,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); SharedPtr network(RR->node->network(nwid)); if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { + trustEstablished = true; const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -492,6 +495,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } if (network->gateMulticastGatherReply(peer,verb(),packetId())) { + trustEstablished = true; if ((flags & 0x02) != 0) { // OK(MULTICAST_FRAME) includes implicit gather results offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; @@ -506,7 +510,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,trustEstablished); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } -- cgit v1.2.3 From 8ef0e4bbafbd87c32c62553bd84d87bd0eda0e06 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Sep 2016 10:46:36 -0700 Subject: Get rid of HELLO rate gate on path since its basically worthless. There are 65535 ports per IP. --- node/IncomingPacket.cpp | 13 ++++--------- node/Path.hpp | 15 --------------- 2 files changed, 4 insertions(+), 24 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7510fec8..64dccef3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -211,11 +211,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut try { const uint64_t now = RR->node->now(); - if (!_path->rateGateHello(now)) { - TRACE("dropped HELLO from %s(%s): rate limiting circuit breaker for HELLO on this path tripped",source().toString().c_str(),_path->address().toString().c_str()); - return true; - } - const uint64_t pid = packetId(); const Address fromAddress(source()); const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; @@ -258,14 +253,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut if (peer->identity() != id) { // Identity is different from the one we already have -- address collision - unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; + uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_path->address().toString().c_str()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_HELLO); + outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); - outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); + outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { @@ -296,7 +291,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } - // Check identity proof of work + // Check that identity's address is valid as per the derivation function if (!id.locallyValidate()) { TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); return true; diff --git a/node/Path.hpp b/node/Path.hpp index 6278532d..27cff645 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -104,7 +104,6 @@ public: Path() : _lastOut(0), _lastIn(0), - _lastHello(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -114,7 +113,6 @@ public: Path(const InetAddress &localAddress,const InetAddress &addr) : _lastOut(0), _lastIn(0), - _lastHello(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -231,22 +229,9 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } - /** - * @return True if we should allow HELLO via this path - */ - inline bool rateGateHello(const uint64_t now) - { - if ((now - _lastHello) >= ZT_PATH_HELLO_RATE_LIMIT) { - _lastHello = now; - return true; - } - return false; - } - private: uint64_t _lastOut; uint64_t _lastIn; - uint64_t _lastHello; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often -- cgit v1.2.3 From 5b6d27e65919cf0429feb2d8a9ce0b6164153efd Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Sep 2016 14:27:18 -0700 Subject: Implement relay policy, and setting multicast limit to 0 now disables multicast on the network as would be expected. --- include/ZeroTierOne.h | 38 ++++++++++++++++++----- node/Constants.hpp | 9 ++++-- node/IncomingPacket.cpp | 16 ++++++++-- node/Node.cpp | 22 ++++++++++++- node/Node.hpp | 3 ++ node/Path.hpp | 13 ++++++++ node/Peer.cpp | 6 ++++ node/Peer.hpp | 18 +++++++---- node/Switch.cpp | 31 +++++++++++++++++-- osdep/ManagedRoute.cpp | 80 +++++++++++++----------------------------------- osdep/ManagedRoute.hpp | 4 +-- service/ControlPlane.cpp | 2 +- 12 files changed, 159 insertions(+), 83 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 633db7cf..e4ea92b4 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -870,19 +870,28 @@ enum ZT_VirtualNetworkConfigOperation ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; +enum ZT_RelayPolicy +{ + ZT_RELAY_POLICY_NEVER = 0, + ZT_RELAY_POLICY_TRUSTED = 1, + ZT_RELAY_POLICY_ALWAYS = 2 +}; + /** * What trust hierarchy role does this peer have? */ -enum ZT_PeerRole { +enum ZT_PeerRole +{ ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_RELAY = 1, // relay node - ZT_PEER_ROLE_ROOT = 2 // root server + ZT_PEER_ROLE_UPSTREAM = 1, // upstream node + ZT_PEER_ROLE_ROOT = 2 // global root }; /** * Vendor ID */ -enum ZT_Vendor { +enum ZT_Vendor +{ ZT_VENDOR_UNSPECIFIED = 0, ZT_VENDOR_ZEROTIER = 1 }; @@ -890,7 +899,8 @@ enum ZT_Vendor { /** * Platform type */ -enum ZT_Platform { +enum ZT_Platform +{ ZT_PLATFORM_UNSPECIFIED = 0, ZT_PLATFORM_LINUX = 1, ZT_PLATFORM_WINDOWS = 2, @@ -905,13 +915,15 @@ enum ZT_Platform { ZT_PLATFORM_VXWORKS = 11, ZT_PLATFORM_FREERTOS = 12, ZT_PLATFORM_SYSBIOS = 13, - ZT_PLATFORM_HURD = 14 + ZT_PLATFORM_HURD = 14, + ZT_PLATFORM_WEB = 15 }; /** * Architecture type */ -enum ZT_Architecture { +enum ZT_Architecture +{ ZT_ARCHITECTURE_UNSPECIFIED = 0, ZT_ARCHITECTURE_X86 = 1, ZT_ARCHITECTURE_X64 = 2, @@ -926,7 +938,8 @@ enum ZT_Architecture { ZT_ARCHITECTURE_SPARC32 = 11, ZT_ARCHITECTURE_SPARC64 = 12, ZT_ARCHITECTURE_DOTNET_CLR = 13, - ZT_ARCHITECTURE_JAVA_JVM = 14 + ZT_ARCHITECTURE_JAVA_JVM = 14, + ZT_ARCHITECTURE_WEB = 15 }; /** @@ -1681,6 +1694,15 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( */ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); +/** + * Set node's relay policy + * + * @param node Node instance + * @param rp New relay policy + * @return OK(0) or error code + */ +enum ZT_ResultCode ZT_Node_setRelayPolicy(ZT_Node *node,enum ZT_RelayPolicy rp); + /** * Join a network * diff --git a/node/Constants.hpp b/node/Constants.hpp index afd2e4ec..b3c3dec0 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -350,6 +350,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 4 + /** * Time horizon for VERB_NETWORK_CREDENTIALS cutoff */ @@ -366,9 +371,9 @@ #define ZT_PEER_GENERAL_RATE_LIMIT 1000 /** - * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) + * How long is a path or peer considered to have a trust relationship with us (for e.g. relay policy) since last trusted established packet? */ -#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 +#define ZT_TRUST_EXPIRATION 600000 /** * Enable support for older network configurations from older (pre-1.1.6) controllers diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 64dccef3..9bc41d47 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -670,8 +670,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } - } else if ( (to != network->mac()) && (!to.isMulticast()) ) { - if (!network->config().permitsBridging(RR->identity.address())) { + } else if (to != network->mac()) { + if (to.isMulticast()) { + if (network->config().multicastLimit == 0) { + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + return true; + } + } else if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; @@ -1038,6 +1044,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share return true; } + if (network->config().multicastLimit == 0) { + TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + return true; + } + unsigned int gatherLimit = 0; if ((flags & 0x02) != 0) { gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); diff --git a/node/Node.cpp b/node/Node.cpp index 59794854..51f1b5c0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -71,7 +71,8 @@ Node::Node( _prngStreamPtr(0), _now(now), _lastPingCheck(0), - _lastHousekeepingRun(0) + _lastHousekeepingRun(0), + _relayPolicy(ZT_RELAY_POLICY_TRUSTED) { _online = false; @@ -118,6 +119,9 @@ Node::Node( throw; } + if (RR->topology->amRoot()) + _relayPolicy = ZT_RELAY_POLICY_ALWAYS; + postEvent(ZT_EVENT_UP); } @@ -131,6 +135,7 @@ Node::~Node() delete RR->topology; delete RR->mc; delete RR->sw; + #ifdef ZT_ENABLE_CLUSTER delete RR->cluster; #endif @@ -319,6 +324,12 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB return ZT_RESULT_OK; } +ZT_ResultCode Node::setRelayPolicy(enum ZT_RelayPolicy rp) +{ + _relayPolicy = rp; + return ZT_RESULT_OK; +} + ZT_ResultCode Node::join(uint64_t nwid,void *uptr) { Mutex::Lock _l(_networks_m); @@ -824,6 +835,15 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol } } +enum ZT_ResultCode ZT_Node_setRelayPolicy(ZT_Node *node,enum ZT_RelayPolicy rp) +{ + try { + return reinterpret_cast(node)->setRelayPolicy(rp); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr) { try { diff --git a/node/Node.hpp b/node/Node.hpp index 315b5248..56869816 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -91,6 +91,7 @@ public: unsigned int frameLength, volatile uint64_t *nextBackgroundTaskDeadline); ZT_ResultCode processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); + ZT_ResultCode setRelayPolicy(enum ZT_RelayPolicy rp); ZT_ResultCode join(uint64_t nwid,void *uptr); ZT_ResultCode leave(uint64_t nwid,void **uptr); ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); @@ -245,6 +246,7 @@ public: inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } inline bool online() const throw() { return _online; } + inline ZT_RelayPolicy relayPolicy() const { return _relayPolicy; } #ifdef ZT_TRACE void postTrace(const char *module,unsigned int line,const char *fmt,...); @@ -326,6 +328,7 @@ private: uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; + ZT_RelayPolicy _relayPolicy; bool _online; }; diff --git a/node/Path.hpp b/node/Path.hpp index 27cff645..5993be69 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -104,6 +104,7 @@ public: Path() : _lastOut(0), _lastIn(0), + _lastTrustEstablishedPacketReceived(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -113,6 +114,7 @@ public: Path(const InetAddress &localAddress,const InetAddress &addr) : _lastOut(0), _lastIn(0), + _lastTrustEstablishedPacketReceived(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -126,6 +128,11 @@ public: */ inline void received(const uint64_t t) { _lastIn = t; } + /** + * Set time last trusted packet was received (done in Peer::received()) + */ + inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; } + /** * Send a packet via this path (last out time is also updated) * @@ -159,6 +166,11 @@ public: */ inline InetAddress::IpScope ipScope() const { return _ipScope; } + /** + * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms + */ + inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + /** * @return Preference rank, higher == better */ @@ -232,6 +244,7 @@ public: private: uint64_t _lastOut; uint64_t _lastIn; + uint64_t _lastTrustEstablishedPacketReceived; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index 560ca786..78af9063 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -52,6 +52,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastEchoRequestReceived(0), _lastComRequestReceived(0), _lastCredentialsReceived(0), + _lastTrustEstablishedPacketReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), @@ -132,6 +133,11 @@ void Peer::received( else if (verb == Packet::VERB_MULTICAST_FRAME) _lastMulticastFrame = now; + if (trustEstablished) { + _lastTrustEstablishedPacketReceived = now; + path->trustedPacketReceived(now); + } + if (hops == 0) { bool pathIsConfirmed = false; { diff --git a/node/Peer.hpp b/node/Peer.hpp index 5382e3f0..1ae239bc 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -312,7 +312,7 @@ public: /** * @return 256-bit secret symmetric encryption key */ - inline const unsigned char *key() const throw() { return _key; } + inline const unsigned char *key() const { return _key; } /** * Set the currently known remote version of this peer's client @@ -330,12 +330,17 @@ public: _vRevision = (uint16_t)vrev; } - inline unsigned int remoteVersionProtocol() const throw() { return _vProto; } - inline unsigned int remoteVersionMajor() const throw() { return _vMajor; } - inline unsigned int remoteVersionMinor() const throw() { return _vMinor; } - inline unsigned int remoteVersionRevision() const throw() { return _vRevision; } + inline unsigned int remoteVersionProtocol() const { return _vProto; } + inline unsigned int remoteVersionMajor() const { return _vMajor; } + inline unsigned int remoteVersionMinor() const { return _vMinor; } + inline unsigned int remoteVersionRevision() const { return _vRevision; } - inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } + inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } + + /** + * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms + */ + inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } /** * Rate limit gate for VERB_PUSH_DIRECT_PATHS @@ -470,6 +475,7 @@ private: uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; uint64_t _lastCredentialsReceived; + uint64_t _lastTrustEstablishedPacketReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; diff --git a/node/Switch.cpp b/node/Switch.cpp index ea92c99a..beb36b6c 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -105,7 +105,18 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from const Address destination(fragment.destination()); if (destination != RR->identity.address()) { - // Fragment is not for us, so try to relay it + switch(RR->node->relayPolicy()) { + case ZT_RELAY_POLICY_ALWAYS: + break; + case ZT_RELAY_POLICY_TRUSTED: + if (!path->trustEstablished(now)) + return; + break; + // case ZT_RELAY_POLICY_NEVER: + default: + return; + } + if (fragment.hops() < ZT_RELAY_MAX_HOPS) { fragment.incrementHops(); @@ -203,9 +214,20 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); if (destination != RR->identity.address()) { + switch(RR->node->relayPolicy()) { + case ZT_RELAY_POLICY_ALWAYS: + break; + case ZT_RELAY_POLICY_TRUSTED: + if (!path->trustEstablished(now)) + return; + break; + // case ZT_RELAY_POLICY_NEVER: + default: + return; + } + Packet packet(data,len); - // Packet is not for us, so try to relay it if (packet.hops() < ZT_RELAY_MAX_HOPS) { packet.incrementHops(); @@ -327,6 +349,11 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } if (to.isMulticast()) { + if (network->config().multicastLimit == 0) { + TRACE("%.16llx: dropped multicast: not allowed on network",network->id()); + return; + } + // Destination is a multicast address (including broadcast) MulticastGroup mg(to,0); diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 711a09ed..ae20bb34 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -436,12 +436,12 @@ bool ManagedRoute::sync() } if (!_applied.count(leftt)) { - _applied.insert(leftt); + _applied[rightt] = false; // not ifscoped _routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); _routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); } if ((rightt)&&(!_applied.count(rightt))) { - _applied.insert(rightt); + _applied[rightt] = false; // not ifscoped _routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); _routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); } @@ -457,7 +457,7 @@ bool ManagedRoute::sync() } } else { if (!_applied.count(_target)) { - _applied.insert(_target); + _applied[_target] = true; // ifscoped _routeCmd("add",_target,_via,_device,(_via) ? (const char *)0 : _device); _routeCmd("change",_target,_via,_device,(_via) ? (const char *)0 : _device); } @@ -468,65 +468,27 @@ bool ManagedRoute::sync() #ifdef __LINUX__ // ---------------------------------------------------------- - //if (needBifurcation) { - if (!_applied.count(leftt)) { - _applied.insert(leftt); - _routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied.insert(rightt); - _routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device); - } - /*if (_applied.count(_target)) { - _applied.erase(_target); - _routeCmd("del",_target,_via,(_via) ? (const char *)0 : _device); - }*/ - /*} else { - if (_applied.count(leftt)) { - _applied.erase(leftt); - _routeCmd("del",leftt,_via,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(_applied.count(rightt))) { - _applied.erase(rightt); - _routeCmd("del",rightt,_via,(_via) ? (const char *)0 : _device); - } - if (!_applied.count(_target)) { - _applied.insert(_target); - _routeCmd("replace",_target,_via,(_via) ? (const char *)0 : _device); - } - }*/ + if (!_applied.count(leftt)) { + _applied[leftt] = false; // boolean unused + _routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device); + } + if ((rightt)&&(!_applied.count(rightt))) { + _applied[rightt] = false; // boolean unused + _routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device); + } #endif // __LINUX__ ---------------------------------------------------------- #ifdef __WINDOWS__ // -------------------------------------------------------- - //if (needBifurcation) { - if (!_applied.count(leftt)) { - _applied.insert(leftt); - _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied.insert(rightt); - _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); - } - /*if (_applied.count(_target)) { - _applied.erase(_target); - _winRoute(true,interfaceLuid,interfaceIndex,_target,_via); - }*/ - /*} else { - if (_applied.count(leftt)) { - _applied.erase(leftt); - _winRoute(true,interfaceLuid,interfaceIndex,leftt,_via); - } - if ((rightt)&&(_applied.count(rightt))) { - _applied.erase(rightt); - _winRoute(true,interfaceLuid,interfaceIndex,rightt,_via); - } - if (!_applied.count(_target)) { - _applied.insert(_target); - _winRoute(false,interfaceLuid,interfaceIndex,_target,_via); - } - }*/ + if (!_applied.count(leftt)) { + _applied[leftt] = false; // boolean unused + _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); + } + if ((rightt)&&(!_applied.count(rightt))) { + _applied[rightt] = false; // boolean unused + _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); + } #endif // __WINDOWS__ -------------------------------------------------------- @@ -553,9 +515,9 @@ void ManagedRoute::remove() } #endif // __BSD__ ------------------------------------------------------------ - for(std::set::iterator r(_applied.begin());r!=_applied.end();++r) { + for(std::map::iterator r(_applied.begin());r!=_applied.end();++r) { #ifdef __BSD__ // ------------------------------------------------------------ - _routeCmd("delete",*r,_via,(const char *)0,(_via) ? (const char *)0 : _device); + _routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device); #endif // __BSD__ ------------------------------------------------------------ #ifdef __LINUX__ // ---------------------------------------------------------- diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 9c7e8477..4bf56503 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace ZeroTier { @@ -105,7 +105,7 @@ private: InetAddress _target; InetAddress _via; InetAddress _systemVia; // for route overrides - std::set _applied; // routes currently applied + std::map _applied; // routes currently applied char _device[128]; char _systemDevice[128]; // for route overrides }; diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index b443a7fa..5c135636 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -215,7 +215,7 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer) const char *prole = ""; switch(peer->role) { case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break; - case ZT_PEER_ROLE_RELAY: prole = "RELAY"; break; + case ZT_PEER_ROLE_UPSTREAM: prole = "UPSTREAM"; break; case ZT_PEER_ROLE_ROOT: prole = "ROOT"; break; } -- cgit v1.2.3 From d3524f36090c47e11c2647f022b03e27d16aeb13 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 20 Sep 2016 21:21:34 -0700 Subject: Refactor COM stuff a bit, and respond to COM requests a bit more readily for rapid setup. Will need to revisit later. --- node/Constants.hpp | 7 +++- node/IncomingPacket.cpp | 25 +++++------- node/Membership.hpp | 22 +---------- node/Network.cpp | 102 ++++++++++++++++++++++++------------------------ node/Network.hpp | 11 ++---- node/Node.cpp | 2 +- node/Peer.cpp | 8 +--- node/Peer.hpp | 35 ++++++----------- node/SelfAwareness.cpp | 14 +------ node/Switch.cpp | 11 +++--- node/Topology.cpp | 11 +----- 11 files changed, 94 insertions(+), 154 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index b3c3dec0..b7042d5d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -296,7 +296,12 @@ /** * General rate limit timeout for multiple packet types (HELLO, etc.) */ -#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 1000 +#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 500 + +/** + * General limit for max RTT for requests over the network + */ +#define ZT_GENERAL_RTT_LIMIT 5000 /** * Delay between requests for updated network autoconf information diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9bc41d47..b3925773 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -153,28 +153,21 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_IDENTITY_COLLISION: - // Roots are the only peers currently permitted to state authoritatively - // that an identity has collided. When this occurs the node should be shut - // down and a new identity created. The odds of this ever happening are - // very low. + // FIXME: for federation this will need a payload with a signature or something. if (RR->topology->isRoot(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - // This error can be sent in response to any packet that fails network - // authorization. We only listen to it if it's from a peer that has recently - // been authorized on this network. + // Peers can send this in response to frames if they do not have a recent enough COM from us SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { - const uint64_t now = RR->node->now(); - if (peer->rateGateComRequest(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - network->config().com.serialize(outp); - outp.append((uint8_t)0); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),now); - } + const uint64_t now = RR->node->now(); + if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + network->config().com.serialize(outp); + outp.append((uint8_t)0); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),now); } } break; diff --git a/node/Membership.hpp b/node/Membership.hpp index d67c6822..5eb68d34 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -154,23 +154,6 @@ public: return nconf.com.agreesWith(_com); } - /** - * @return True if this member has been on this network recently (or network is public) - */ - inline bool recentlyAllowedOnNetwork(const NetworkConfig &nconf) const - { - if (nconf.isPublic()) - return true; - if (_com) { - const uint64_t a = _com.timestamp().first; - if ((_blacklistBefore)&&(a <= _blacklistBefore)) - return false; - const uint64_t b = nconf.com.timestamp().first; - return ((a <= b) ? ((b - a) <= ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA) : true); - } - return false; - } - /** * Check whether a capability or tag is within its max delta from the timestamp of our network config and newer than any blacklist cutoff time * @@ -259,10 +242,7 @@ public: * * @param ts Blacklist cutoff */ - inline void blacklistBefore(const uint64_t ts) - { - _blacklistBefore = ts; - } + inline void blacklistBefore(const uint64_t ts) { _blacklistBefore = ts; } /** * Clean up old or stale entries diff --git a/node/Network.cpp b/node/Network.cpp index 197841d9..455e185e 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -648,11 +648,12 @@ bool Network::filterOutgoingPacket( { uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; - Address ztDest2(ztDest); + Address ztFinalDest(ztDest); Address cc; const Capability *relevantCap = (const Capability *)0; unsigned int ccLength = 0; bool accept = false; + const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -663,26 +664,27 @@ bool Network::filterOutgoingPacket( remoteTagCount = m->getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); } - switch(_doZtFilter(RR,_config,false,ztSource,ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + switch(_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { case DOZTFILTER_NO_MATCH: for(unsigned int c=0;c<_config.capabilityCount;++c) { - ztDest2 = ztDest; // sanity check + ztFinalDest = ztDest; // sanity check Address cc2; unsigned int ccLength2 = 0; - switch (_doZtFilter(RR,_config,false,ztSource,ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + switch (_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side relevantCap = &(_config.capabilities[c]); accept = true; if ((!noTee)&&(cc2)) { - _membership(cc2).sendCredentialsIfNeeded(RR,RR->node->now(),cc2,_config,relevantCap); + Membership &m2 = _membership(cc2); + m2.sendCredentialsIfNeeded(RR,now,cc2,_config,relevantCap); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -705,7 +707,7 @@ bool Network::filterOutgoingPacket( case DOZTFILTER_DROP: return false; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side accept = true; @@ -714,7 +716,8 @@ bool Network::filterOutgoingPacket( if (accept) { if ((!noTee)&&(cc)) { - _membership(cc).sendCredentialsIfNeeded(RR,RR->node->now(),cc,_config,relevantCap); + Membership &m2 = _membership(cc); + m2.sendCredentialsIfNeeded(RR,now,cc,_config,relevantCap); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -727,10 +730,11 @@ bool Network::filterOutgoingPacket( RR->sw->send(outp,true); } - if ((ztDest != ztDest2)&&(ztDest2)) { - _membership(ztDest2).sendCredentialsIfNeeded(RR,RR->node->now(),ztDest2,_config,relevantCap); + if ((ztDest != ztFinalDest)&&(ztFinalDest)) { + Membership &m2 = _membership(ztFinalDest); + m2.sendCredentialsIfNeeded(RR,now,ztFinalDest,_config,relevantCap); - Packet outp(ztDest2,RR->identity.address(),Packet::VERB_EXT_FRAME); + Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 macDest.appendTo(outp); @@ -742,11 +746,13 @@ bool Network::filterOutgoingPacket( return false; // DROP locally, since we redirected } else if (m) { - m->sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,relevantCap); + m->sendCredentialsIfNeeded(RR,now,ztDest,_config,relevantCap); } - } - return accept; + return true; + } else { + return false; + } } int Network::filterIncomingPacket( @@ -761,7 +767,7 @@ int Network::filterIncomingPacket( { uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; - Address ztDest2(ztDest); + Address ztFinalDest(ztDest); Address cc; unsigned int ccLength = 0; int accept = 0; @@ -771,16 +777,16 @@ int Network::filterIncomingPacket( Membership &m = _membership(sourcePeer->address()); const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); - switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { case DOZTFILTER_NO_MATCH: { Membership::CapabilityIterator mci(m); const Capability *c; while ((c = mci.next(_config))) { - ztDest2 = ztDest; // sanity check + ztFinalDest = ztDest; // sanity check Address cc2; unsigned int ccLength2 = 0; - switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; @@ -815,7 +821,7 @@ int Network::filterIncomingPacket( case DOZTFILTER_DROP: return 0; // DROP - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: accept = 1; // ACCEPT break; @@ -839,10 +845,10 @@ int Network::filterIncomingPacket( RR->sw->send(outp,true); } - if ((ztDest != ztDest2)&&(ztDest2)) { - _membership(ztDest2).sendCredentialsIfNeeded(RR,RR->node->now(),ztDest2,_config,(const Capability *)0); + if ((ztDest != ztFinalDest)&&(ztFinalDest)) { + _membership(ztFinalDest).sendCredentialsIfNeeded(RR,RR->node->now(),ztFinalDest,_config,(const Capability *)0); - Packet outp(ztDest2,RR->identity.address(),Packet::VERB_EXT_FRAME); + Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 macDest.appendTo(outp); @@ -1063,23 +1069,26 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin Mutex::Lock _l(_lock); try { if (_config) { - Membership &m = _membership(peer->address()); - const bool allow = m.isAllowedOnNetwork(_config); - if (allow) { - m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); - if (m.shouldLikeMulticasts(now)) { + Membership *m = _memberships.get(peer->address()); + if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) { + if (!m) + m = &(_membership(peer->address())); + m->sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); + if (m->shouldLikeMulticasts(now)) { _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); - m.likingMulticasts(now); + m->likingMulticasts(now); + } + return true; + } else { + if (peer->rateGateRequestCredentials(now)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)verb); + outp.append(packetId); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(_id); + RR->sw->send(outp,true); } - } else if (m.recentlyAllowedOnNetwork(_config)&&peer->rateGateRequestCredentials(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb); - outp.append(packetId); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(_id); - RR->sw->send(outp,true); } - return allow; } } catch ( ... ) { TRACE("gate() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); @@ -1092,15 +1101,6 @@ bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet: return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); } -bool Network::recentlyAllowedOnNetwork(const SharedPtr &peer) const -{ - Mutex::Lock _l(_lock); - const Membership *m = _memberships.get(peer->address()); - if (m) - return m->recentlyAllowedOnNetwork(_config); - return false; -} - void Network::clean() { const uint64_t now = RR->node->now(); @@ -1308,13 +1308,11 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ( (m->recentlyAllowedOnNetwork(_config)) || (std::find(anchors.begin(),anchors.end(),*a) != anchors.end()) ) { - m->sendCredentialsIfNeeded(RR,RR->node->now(),*a,_config,(const Capability *)0); - if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { - if (!newMulticastGroup) - m->likingMulticasts(now); - _announceMulticastGroupsTo(*a,groups); - } + m->sendCredentialsIfNeeded(RR,now,*a,_config,(const Capability *)0); + if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { + if (!newMulticastGroup) + m->likingMulticasts(now); + _announceMulticastGroupsTo(*a,groups); } } } diff --git a/node/Network.hpp b/node/Network.hpp index 7a4065ff..c85e5993 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -248,7 +248,10 @@ public: void requestConfiguration(); /** - * Membership check gate for incoming packets related to this network + * Determine whether this peer is permitted to communicate on this network + * + * This also performs certain periodic actions such as pushing renewed + * credentials to peers or requesting them if not present. * * @param peer Peer to check * @param verb Packet verb @@ -262,12 +265,6 @@ public: */ bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); - /** - * @param peer Peer to check - * @return True if peer has recently been a valid member of this network - */ - bool recentlyAllowedOnNetwork(const SharedPtr &peer) const; - /** * Perform cleanup and possibly save state */ diff --git a/node/Node.cpp b/node/Node.cpp index 51f1b5c0..2533eeb6 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -241,7 +241,7 @@ public: } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - } else if (p->activelyTransferringFrames(_now)) { + } else if (p->isActive(_now)) { // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently p->doPingAndKeepalive(_now,-1); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 78af9063..d742964a 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -41,7 +41,6 @@ namespace ZeroTier { static uint32_t _natKeepaliveBuf = 0; Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : - _lastUsed(0), _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), @@ -408,19 +407,16 @@ bool Peer::hasActiveDirectPath(uint64_t now) const return false; } -bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) +void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) { Mutex::Lock _l(_paths_m); - bool resetSomething = false; for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now); _paths[p].path->sent(now); - _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic - resetSomething = true; + _paths[p].lastReceive = 0; // path will not be used unless it speaks again } } - return resetSomething; } void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const diff --git a/node/Peer.hpp b/node/Peer.hpp index 1ae239bc..c5ef43ed 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -68,18 +68,6 @@ public: */ Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity); - /** - * @return Time peer record was last used in any way - */ - inline uint64_t lastUsed() const throw() { return _lastUsed; } - - /** - * Log a use of this peer record (done by Topology when peers are looked up) - * - * @param now New time of last use - */ - inline void use(uint64_t now) throw() { _lastUsed = now; } - /** * @return This peer's ZT address (short for identity().address()) */ @@ -194,15 +182,14 @@ public: /** * Reset paths within a given IP scope and address family * - * Resetting a path involves sending a HELLO to it and then de-prioritizing - * it vs. other paths. + * Resetting a path involves sending an ECHO to it and then deactivating + * it until or unless it responds. * * @param scope IP scope * @param inetAddressFamily Family e.g. AF_INET * @param now Current time - * @return True if we forgot at least one path */ - bool resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + void resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); /** * Get most recently active path addresses for IPv4 and/or IPv6 @@ -232,27 +219,32 @@ public: /** * @return Time of last receive of anything, whether direct or relayed */ - inline uint64_t lastReceive() const throw() { return _lastReceive; } + inline uint64_t lastReceive() const { return _lastReceive; } + + /** + * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT + */ + inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Time of most recent unicast frame received */ - inline uint64_t lastUnicastFrame() const throw() { return _lastUnicastFrame; } + inline uint64_t lastUnicastFrame() const { return _lastUnicastFrame; } /** * @return Time of most recent multicast frame received */ - inline uint64_t lastMulticastFrame() const throw() { return _lastMulticastFrame; } + inline uint64_t lastMulticastFrame() const { return _lastMulticastFrame; } /** * @return Time of most recent frame of any kind (unicast or multicast) */ - inline uint64_t lastFrame() const throw() { return std::max(_lastUnicastFrame,_lastMulticastFrame); } + inline uint64_t lastFrame() const { return std::max(_lastUnicastFrame,_lastMulticastFrame); } /** * @return True if this peer has sent us real network traffic recently */ - inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline uint64_t isActive(uint64_t now) const { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Latency in milliseconds or 0 if unknown @@ -464,7 +456,6 @@ private: uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t _remoteClusterOptimal6[16]; - uint64_t _lastUsed; uint64_t _lastReceive; // direct or indirect uint64_t _lastUnicastFrame; uint64_t _lastMulticastFrame; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 6bf50720..e84b7b65 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -45,9 +45,7 @@ public: _family(inetAddressFamily), _scope(scope) {} - inline void operator()(Topology &t,const SharedPtr &p) { if (p->resetWithinScope(_scope,_family,_now)) peersReset.push_back(p); } - - std::vector< SharedPtr > peersReset; + inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_scope,_family,_now); } private: uint64_t _now; @@ -95,16 +93,6 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc // Reset all paths within this scope and address family _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); - - // Send a NOP to all peers for whom we forgot a path. This will cause direct - // links to be re-established if possible, possibly using a root server or some - // other relay. - for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { - if ((*p)->activelyTransferringFrames(now)) { - Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true); - } - } } else { // Otherwise just update DB to use to determine external surface info entry.mySurface = myPhysicalAddress; diff --git a/node/Switch.cpp b/node/Switch.cpp index beb36b6c..e3d57835 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -354,8 +354,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c return; } - // Destination is a multicast address (including broadcast) - MulticastGroup mg(to,0); + MulticastGroup multicastGroup(to,0); if (to.isBroadcast()) { if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) { @@ -368,7 +367,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * them into multicasts by stuffing the IP address being queried into * the 32-bit ADI field. In practice this uses our multicast pub/sub * system to implement a kind of extended/distributed ARP table. */ - mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); + multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); @@ -463,9 +462,9 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * multicast addresses on bridge interfaces and subscribing each slave. * But in that case this does no harm, as the sets are just merged. */ if (fromBridged) - network->learnBridgedMulticastGroup(mg,RR->node->now()); + network->learnBridgedMulticastGroup(multicastGroup,RR->node->now()); - //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len); + //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { @@ -478,7 +477,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c RR->node->now(), network->id(), network->config().activeBridges(), - mg, + multicastGroup, (fromBridged) ? from : MAC(), etherType, data, diff --git a/node/Topology.cpp b/node/Topology.cpp index 6e2fd071..12a7cc0b 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -96,7 +96,6 @@ SharedPtr Topology::addPeer(const SharedPtr &peer) np = hp; } - np->use(RR->node->now()); saveIdentity(np->identity()); return np; @@ -113,7 +112,6 @@ SharedPtr Topology::getPeer(const Address &zta) Mutex::Lock _l(_lock); const SharedPtr *const ap = _peers.get(zta); if (ap) { - (*ap)->use(RR->node->now()); return *ap; } } @@ -127,7 +125,6 @@ SharedPtr Topology::getPeer(const Address &zta) SharedPtr &ap = _peers[zta]; if (!ap) ap.swap(np); - ap->use(RR->node->now()); return ap; } } @@ -176,10 +173,8 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou if (_rootAddresses[p] == RR->identity.address()) { for(unsigned long q=1;q<_rootAddresses.size();++q) { const SharedPtr *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]); - if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) { - (*nextsn)->use(now); + if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) return *nextsn; - } } break; } @@ -214,10 +209,8 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou } if (bestNotAvoid) { - (*bestNotAvoid)->use(now); return *bestNotAvoid; } else if ((!strictAvoid)&&(bestOverall)) { - (*bestOverall)->use(now); return *bestOverall; } @@ -256,7 +249,7 @@ void Topology::clean(uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) + if ( (!(*p)->isAlive(now)) && (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) ) _peers.erase(*a); } } -- cgit v1.2.3 From 1f74dd4589017bd5bc34b31ff6e09e6875d5e1c7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 23 Sep 2016 16:08:38 -0700 Subject: Revocation work in progress, add WATCH which is TEE with implicit rate sync (thanks JG@DCVC!), and clean up some cruft in Network. --- controller/EmbeddedNetworkController.cpp | 12 ++ include/ZeroTierOne.h | 9 +- node/Capability.hpp | 2 + node/IncomingPacket.cpp | 76 ++++---- node/Membership.cpp | 234 +++++++++++++++---------- node/Membership.hpp | 263 +++++++++++++--------------- node/Network.cpp | 289 +++++++++++++------------------ node/Network.hpp | 189 +++++++------------- node/Packet.hpp | 63 ++++--- node/Revocation.cpp | 46 +++++ node/Revocation.hpp | 178 +++++++++++++++++++ node/Tag.cpp | 2 +- node/Tag.hpp | 30 +++- objects.mk | 1 + 14 files changed, 803 insertions(+), 591 deletions(-) create mode 100644 node/Revocation.cpp create mode 100644 node/Revocation.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 53b345b4..5ba8cf98 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -140,6 +140,12 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) r["flags"] = (unsigned int)rule.v.fwd.flags; r["length"] = (unsigned int)rule.v.fwd.length; break; + case ZT_NETWORK_RULE_ACTION_WATCH: + r["type"] = "ACTION_WATCH"; + r["address"] = Address(rule.v.fwd.address).toString(); + r["flags"] = (unsigned int)rule.v.fwd.flags; + r["length"] = (unsigned int)rule.v.fwd.length; + break; case ZT_NETWORK_RULE_ACTION_REDIRECT: r["type"] = "ACTION_REDIRECT"; r["address"] = Address(rule.v.fwd.address).toString(); @@ -303,6 +309,12 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) rule.v.fwd.flags = (uint32_t)(_jI(r["flags"],0ULL) & 0xffffffffULL); rule.v.fwd.length = (uint16_t)(_jI(r["length"],0ULL) & 0xffffULL); return true; + } else if (t == "ACTION_WATCH") { + rule.t |= ZT_NETWORK_RULE_ACTION_WATCH; + rule.v.fwd.address = Utils::hexStrToU64(_jS(r["address"],"0").c_str()) & 0xffffffffffULL; + rule.v.fwd.flags = (uint32_t)(_jI(r["flags"],0ULL) & 0xffffffffULL); + rule.v.fwd.length = (uint16_t)(_jI(r["length"],0ULL) & 0xffffULL); + return true; } else if (t == "ACTION_REDIRECT") { rule.t |= ZT_NETWORK_RULE_ACTION_REDIRECT; rule.v.fwd.address = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL; diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index e0f6ca28..e43c8541 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -516,15 +516,20 @@ enum ZT_VirtualNetworkRuleType */ ZT_NETWORK_RULE_ACTION_TEE = 2, + /** + * Exactly like TEE but frames are dropped if previous TEEs were not acknowledged by the observer + */ + ZT_NETWORK_RULE_ACTION_WATCH = 3, + /** * Drop and redirect this frame to another node (by ZT address) */ - ZT_NETWORK_RULE_ACTION_REDIRECT = 3, + ZT_NETWORK_RULE_ACTION_REDIRECT = 4, /** * Log if match and if rule debugging is enabled in the build, otherwise does nothing (for developers) */ - ZT_NETWORK_RULE_ACTION_DEBUG_LOG = 4, + ZT_NETWORK_RULE_ACTION_DEBUG_LOG = 5, /** * Maximum ID for an ACTION, anything higher is a MATCH diff --git a/node/Capability.hpp b/node/Capability.hpp index e23d7943..2cf54b5c 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -174,6 +174,7 @@ public: b.append((uint8_t)0); break; case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: case ZT_NETWORK_RULE_ACTION_REDIRECT: b.append((uint8_t)14); b.append((uint64_t)rules[i].v.fwd.address); @@ -270,6 +271,7 @@ public: default: break; case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: case ZT_NETWORK_RULE_ACTION_REDIRECT: rules[ruleCount].v.fwd.address = b.template at(p); rules[ruleCount].v.fwd.flags = b.template at(p + 8); diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b3925773..12766fe2 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -39,6 +39,7 @@ #include "CertificateOfMembership.hpp" #include "Capability.hpp" #include "Tag.hpp" +#include "Revocation.hpp" namespace ZeroTier { @@ -162,13 +163,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Peers can send this in response to frames if they do not have a recent enough COM from us SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); - if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - network->config().com.serialize(outp); - outp.append((uint8_t)0); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),now); - } + if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) + network->pushCredentialsNow(peer->address(),now); } break; case Packet::ERROR_NETWORK_ACCESS_DENIED_: { @@ -681,9 +677,17 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

node->putFrame(nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); break; } + } - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + if ((flags & 0x10) != 0) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((uint8_t)Packet::VERB_EXT_FRAME); + outp.append((uint64_t)packetId()); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } + + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); @@ -775,6 +779,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S CertificateOfMembership com; Capability cap; Tag tag; + Revocation revocation; bool trustEstablished = false; unsigned int p = ZT_PACKET_IDX_PAYLOAD; @@ -784,8 +789,14 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S SharedPtr network(RR->node->network(com.networkId())); if (network) { switch (network->addCredential(com)) { - case 0: trustEstablished = true; break; - case 1: return false; // wait for WHOIS + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } else RR->mc->addCredential(com,false); } @@ -799,8 +810,14 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S SharedPtr network(RR->node->network(cap.networkId())); if (network) { switch (network->addCredential(cap)) { - case 0: trustEstablished = true; break; - case 1: return false; // wait for WHOIS + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } } @@ -811,11 +828,25 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S SharedPtr network(RR->node->network(tag.networkId())); if (network) { switch (network->addCredential(tag)) { - case 0: trustEstablished = true; break; - case 1: return false; // wait for WHOIS + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } } + + const unsigned int numRevocations = at(p); p += 2; + for(unsigned int i=0;i network(RR->node->network(revocation.networkId())); + if (network) { + } + } } peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); @@ -932,24 +963,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons const uint64_t nwid = at(ZT_PACKET_IDX_PAYLOAD); bool trustEstablished = false; - if (Network::controllerFor(nwid) == peer->address()) { - SharedPtr network(RR->node->network(nwid)); - if (network) { - network->requestConfiguration(); - trustEstablished = true; - } else { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); - return true; - } - const unsigned int blacklistCount = at(ZT_PACKET_IDX_PAYLOAD + 8); - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 10; - for(unsigned int i=0;iblacklistBefore(Address(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH),at(ptr + 5)); - ptr += 13; - } - } peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { diff --git a/node/Membership.cpp b/node/Membership.cpp index 8c2ba673..d579d303 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include + #include "Membership.hpp" #include "RuntimeEnvironment.hpp" #include "Peer.hpp" @@ -28,28 +30,43 @@ namespace ZeroTier { -void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap) +Membership::Membership() : + _lastUpdatedMulticast(0), + _lastPushAttempt(0), + _lastPushedCom(0), + _comRevocationThreshold(0) +{ + for(unsigned int i=0;i= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) ); do { - unfinished = false; Buffer capsAndTags; unsigned int appendedCaps = 0; - if (cap) { + if (localCapabilityIndex >= 0) { capsAndTags.addSize(2); - std::map::iterator cs(_caps.find(cap->id())); - if ((cs != _caps.end())&&((now - cs->second.lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY)) { - cap->serialize(capsAndTags); - cs->second.lastPushed = now; + + if ( (_localCaps[localCapabilityIndex].id != nconf.capabilities[localCapabilityIndex].id()) || ((now - _localCaps[localCapabilityIndex].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { + _localCaps[localCapabilityIndex].lastPushed = now; + _localCaps[localCapabilityIndex].id = nconf.capabilities[localCapabilityIndex].id(); + nconf.capabilities[localCapabilityIndex].serialize(capsAndTags); ++appendedCaps; } + capsAndTags.setAt(0,(uint16_t)appendedCaps); + localCapabilityIndex = -1; // don't send this cap again on subsequent loops if force is true } else { capsAndTags.append((uint16_t)0); } @@ -57,22 +74,17 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint unsigned int appendedTags = 0; const unsigned int tagCountPos = capsAndTags.size(); capsAndTags.addSize(2); - for(unsigned int i=0;ilastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) { - if ((capsAndTags.size() + sizeof(Tag)) >= (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) { - unfinished = true; + for(;localTagPtr= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { + if ((capsAndTags.size() + sizeof(Tag)) >= (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) break; - } - nconf.tags[i].serialize(capsAndTags); - ts->lastPushed = now; + nconf.tags[localTagPtr].serialize(capsAndTags); ++appendedTags; } } capsAndTags.setAt(tagCountPos,(uint16_t)appendedTags); - const bool needCom = ((nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)); - if ( (needCom) || (appendedCaps) || (appendedTags) ) { + if (needCom||appendedCaps||appendedTags) { Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); if (needCom) { nconf.com.serialize(outp); @@ -80,110 +92,148 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint } outp.append((uint8_t)0x00); outp.append(capsAndTags.data(),capsAndTags.size()); + outp.append((uint16_t)0); // no revocations, these propagate differently outp.compress(); RR->sw->send(outp,true); + needCom = false; // don't send COM again on subsequent loops if force is true } - } while (unfinished); // if there are many tags, etc., we can send more than one + } while (localTagPtr < nconf.tagCount); } catch ( ... ) { TRACE("unable to send credentials due to unexpected exception"); } } -int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com) +const Capability *Membership::getCapability(const NetworkConfig &nconf,const uint32_t id) const { - if (_com == com) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); - return 0; + const _RemoteCapability *const *c = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)id,_RemoteCredentialSorter<_RemoteCapability>()); + return ( ((c != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*c)->id == (uint64_t)id)) ? ((((*c)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*c)->cap,**c))) ? &((*c)->cap) : (const Capability *)0) : (const Capability *)0); +} + +const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const +{ + const _RemoteTag *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialSorter<_RemoteTag>()); + return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*t)->tag,**t))) ? &((*t)->tag) : (const Tag *)0) : (const Tag *)0); +} + +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com) +{ + const uint64_t newts = com.timestamp().first; + if (newts <= _comRevocationThreshold) { + TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId()); + return ADD_REJECTED; } - const int vr = com.verify(RR); + const uint64_t oldts = _com.timestamp().first; + if (newts < oldts) { + TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId()); + return ADD_REJECTED; + } + if ((newts == oldts)&&(_com == com)) { + TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); + return ADD_ACCEPTED_REDUNDANT; + } - if (vr == 0) { - if (com.timestamp().first >= _com.timestamp().first) { + switch(com.verify(RR)) { + default: + TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId()); + return ADD_REJECTED; + case 0: TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); _com = com; - } else { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED but not used (OK but older than current)",com.issuedTo().toString().c_str(),com.networkId()); - } - } else { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (%d)",com.issuedTo().toString().c_str(),com.networkId(),vr); + return ADD_ACCEPTED_NEW; + case 1: + return ADD_DEFERRED_FOR_WHOIS; } - - return vr; } -int Membership::addCredential(const RuntimeEnvironment *RR,const Tag &tag) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag) { - TState *t = _tags.get(tag.id()); - if ((t)&&(t->lastReceived != 0)&&(t->tag == tag)) { - TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId()); - return 0; + _RemoteTag *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialSorter<_RemoteTag>()); + _RemoteTag *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteTag *)0; + if (have) { + if ( (!_isCredentialTimestampValid(nconf,tag,*have)) || (have->tag.timestamp() > tag.timestamp()) ) { + TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId()); + return ADD_REJECTED; + } + if (have->tag == tag) { + TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId()); + return ADD_ACCEPTED_REDUNDANT; + } } - const int vr = tag.verify(RR); - if (vr == 0) { - TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); - if (!t) { - while (_tags.size() >= ZT_MAX_NETWORK_TAGS) { - uint32_t oldest = 0; - uint64_t oldestLastReceived = 0xffffffffffffffffULL; - uint32_t *i = (uint32_t *)0; - TState *ts = (TState *)0; - Hashtable::Iterator tsi(_tags); - while (tsi.next(i,ts)) { - if (ts->lastReceived < oldestLastReceived) { - oldestLastReceived = ts->lastReceived; - oldest = *i; + + switch(tag.verify(RR)) { + default: + TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId()); + return ADD_REJECTED; + case 0: + TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); + if (have) { + have->lastReceived = RR->node->now(); + have->tag = tag; + } else { + uint64_t minlr = 0xffffffffffffffffULL; + for(unsigned int i=0;iid == 0xffffffffffffffffULL) { + have = _remoteTags[i]; + break; + } else if (_remoteTags[i]->lastReceived <= minlr) { + have = _remoteTags[i]; + minlr = _remoteTags[i]->lastReceived; } } - if (oldestLastReceived != 0xffffffffffffffffULL) - _tags.erase(oldest); + have->lastReceived = RR->node->now(); + have->tag = tag; + std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>()); } - t = &(_tags[tag.id()]); - } - if (t->tag.timestamp() <= tag.timestamp()) { - t->lastReceived = RR->node->now(); - t->tag = tag; - } - } else { - TRACE("addCredential(Tag) for %s on %.16llx REJECTED (%d)",tag.issuedTo().toString().c_str(),tag.networkId(),vr); + return ADD_ACCEPTED_NEW; + case 1: + return ADD_DEFERRED_FOR_WHOIS; } - return vr; } -int Membership::addCredential(const RuntimeEnvironment *RR,const Capability &cap) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap) { - std::map::iterator c(_caps.find(cap.id())); - if ((c != _caps.end())&&(c->second.lastReceived != 0)&&(c->second.cap == cap)) { - TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId()); - return 0; + _RemoteCapability *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialSorter<_RemoteCapability>()); + _RemoteCapability *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCapability *)0; + if (have) { + if ( (!_isCredentialTimestampValid(nconf,cap,*have)) || (have->cap.timestamp() > cap.timestamp()) ) { + TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId()); + return ADD_REJECTED; + } + if (have->cap == cap) { + TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId()); + return ADD_ACCEPTED_REDUNDANT; + } } - const int vr = cap.verify(RR); - if (vr == 0) { - TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId()); - if (c == _caps.end()) { - while (_caps.size() >= ZT_MAX_NETWORK_CAPABILITIES) { - std::map::iterator oldest; - uint64_t oldestLastReceived = 0xffffffffffffffffULL; - for(std::map::iterator i(_caps.begin());i!=_caps.end();++i) { - if (i->second.lastReceived < oldestLastReceived) { - oldestLastReceived = i->second.lastReceived; - oldest = i; + + switch(cap.verify(RR)) { + default: + TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId()); + return ADD_REJECTED; + case 0: + TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); + if (have) { + have->lastReceived = RR->node->now(); + have->cap = cap; + } else { + uint64_t minlr = 0xffffffffffffffffULL; + for(unsigned int i=0;iid == 0xffffffffffffffffULL) { + have = _remoteCaps[i]; + break; + } else if (_remoteCaps[i]->lastReceived <= minlr) { + have = _remoteCaps[i]; + minlr = _remoteCaps[i]->lastReceived; } } - if (oldestLastReceived != 0xffffffffffffffffULL) - _caps.erase(oldest); + have->lastReceived = RR->node->now(); + have->cap = cap; + std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>()); } - CState &c2 = _caps[cap.id()]; - c2.lastReceived = RR->node->now(); - c2.cap = cap; - } else if (c->second.cap.timestamp() <= cap.timestamp()) { - c->second.lastReceived = RR->node->now(); - c->second.cap = cap; - } - } else { - TRACE("addCredential(Capability) for %s on %.16llx REJECTED (%d)",cap.issuedTo().toString().c_str(),cap.networkId(),vr); + return ADD_ACCEPTED_NEW; + case 1: + return ADD_DEFERRED_FOR_WHOIS; } - return vr; } } // namespace ZeroTier diff --git a/node/Membership.hpp b/node/Membership.hpp index 5eb68d34..421e3ee8 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -21,14 +21,12 @@ #include -#include - #include "Constants.hpp" #include "../include/ZeroTierOne.h" #include "CertificateOfMembership.hpp" #include "Capability.hpp" #include "Tag.hpp" -#include "Hashtable.hpp" +#include "Revocation.hpp" #include "NetworkConfig.hpp" namespace ZeroTier { @@ -40,77 +38,135 @@ class Network; * A container for certificates of membership and other network credentials * * This is kind of analogous to a join table between Peer and Network. It is - * presently held by the Network object for each participating Peer. + * held by the Network object for each participating Peer. * - * This is not thread safe. It must be locked externally. + * This class is not thread safe. It must be locked externally. */ class Membership { private: // Tags and related state - struct TState + struct _RemoteTag { - TState() : lastPushed(0),lastReceived(0) {} - // Last time we pushed OUR tag to this peer (with this ID) - uint64_t lastPushed; + _RemoteTag() : id(0xffffffffffffffffULL),lastReceived(0),revocationThreshold(0) {} + // Tag ID (last 32 bits, first 32 bits are set in unused entries to sort them to end) + uint64_t id; // Last time we received THEIR tag (with this ID) uint64_t lastReceived; + // Revocation blacklist threshold or 0 if none + uint64_t revocationThreshold; // THEIR tag Tag tag; }; // Credentials and related state - struct CState + struct _RemoteCapability { - CState() : lastPushed(0),lastReceived(0) {} - // Last time we pushed OUR capability to this peer (with this ID) - uint64_t lastPushed; + _RemoteCapability() : id(0xffffffffffffffffULL),lastReceived(0),revocationThreshold(0) {} + // Capability ID (last 32 bits, first 32 bits are set in unused entries to sort them to end) + uint64_t id; // Last time we received THEIR capability (with this ID) uint64_t lastReceived; + // Revocation blacklist threshold or 0 if none + uint64_t revocationThreshold; // THEIR capability Capability cap; }; + // Comparison operator for remote credential entries + template + struct _RemoteCredentialSorter + { + inline bool operator()(const T *a,const T *b) const { return (a->id < b->id); } + inline bool operator()(const uint64_t a,const T *b) const { return (a < b->id); } + inline bool operator()(const T *a,const uint64_t b) const { return (a->id < b); } + inline bool operator()(const uint64_t a,const uint64_t b) const { return (a < b); } + }; + + // Used to track push state for network config tags[] and capabilities[] entries + struct _LocalCredentialPushState + { + _LocalCredentialPushState() : lastPushed(0),id(0) {} + uint64_t lastPushed; + uint32_t id; + }; + public: + enum AddCredentialResult + { + ADD_REJECTED, + ADD_ACCEPTED_NEW, + ADD_ACCEPTED_REDUNDANT, + ADD_DEFERRED_FOR_WHOIS + }; + /** - * A wrapper to iterate through member capabilities in ascending order of capability ID and return only valid ones + * Iterator to scan forward through capabilities in ascending order of ID */ class CapabilityIterator { public: - CapabilityIterator(const Membership &m) : - _m(m), - _i(m._caps.begin()), - _e(m._caps.end()) - { - } + CapabilityIterator(const Membership &m,const NetworkConfig &nconf) : + _m(&m), + _c(&nconf), + _i(&(m._remoteCaps[0])) {} - inline const Capability *next(const NetworkConfig &nconf) + inline const Capability *next() { - while (_i != _e) { - if ((_i->second.lastReceived)&&(_m.isCredentialTimestampValid(nconf,_i->second.cap))) - return &((_i++)->second.cap); - else ++_i; + for(;;) { + if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != 0xffffffffffffffffULL)) { + const Capability *tmp = &((*_i)->cap); + if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { + ++_i; + return tmp; + } else ++_i; + } else { + return (const Capability *)0; + } } - return (const Capability *)0; } private: - const Membership &_m; - std::map::const_iterator _i,_e; + const Membership *_m; + const NetworkConfig *_c; + const _RemoteCapability *const *_i; }; friend class CapabilityIterator; - Membership() : - _lastUpdatedMulticast(0), - _lastPushAttempt(0), - _lastPushedCom(0), - _blacklistBefore(0), - _com(), - _caps(), - _tags(8) + /** + * Iterator to scan forward through tags in ascending order of ID + */ + class TagIterator { - } + public: + TagIterator(const Membership &m,const NetworkConfig &nconf) : + _m(&m), + _c(&nconf), + _i(&(m._remoteTags[0])) {} + + inline const Tag *next() + { + for(;;) { + if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != 0xffffffffffffffffULL)) { + const Tag *tmp = &((*_i)->tag); + if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { + ++_i; + return tmp; + } else ++_i; + } else { + return (const Tag *)0; + } + } + } + + private: + const Membership *_m; + const NetworkConfig *_c; + const _RemoteTag *const *_i; + }; + friend class TagIterator; + + Membership(); /** * Send COM and other credentials to this peer if needed @@ -122,9 +178,10 @@ public: * @param now Current time * @param peerAddress Address of member peer (the one that this Membership describes) * @param nconf My network config - * @param cap Capability to send or 0 if none + * @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none + * @param force If true, send objects regardless of last push time */ - void sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap); + void pushCredentials(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); /** * Check whether we should push MULTICAST_LIKEs to this peer @@ -142,6 +199,8 @@ public: inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; } /** + * Check whether the peer represented by this Membership should be allowed on this network at all + * * @param nconf Our network config * @return True if this peer is allowed on this network at all */ @@ -149,126 +208,48 @@ public: { if (nconf.isPublic()) return true; - if ((_blacklistBefore)&&(_com.timestamp().first <= _blacklistBefore)) + if ((_comRevocationThreshold)&&(_com.timestamp().first <= _comRevocationThreshold)) return false; return nconf.com.agreesWith(_com); } /** - * Check whether a capability or tag is within its max delta from the timestamp of our network config and newer than any blacklist cutoff time - * - * @param cred Credential to check -- must have timestamp() accessor method - * @return True if credential is NOT expired + * @param nconf Network configuration + * @param id Capablity ID + * @return Pointer to capability or NULL if not found */ - template - inline bool isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred) const - { - const uint64_t ts = cred.timestamp(); - const uint64_t delta = (ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts); - return ((delta <= nconf.credentialTimeMaxDelta)&&(ts > _blacklistBefore)); - } + const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) 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)&&(isCredentialTimestampValid(nconf,t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0); - } - - /** - * @param nconf Network configuration - * @param ids Array to store IDs into - * @param values Array to store values into - * @param maxTags Capacity of ids[] and values[] - * @return Number of tags added to arrays - */ - inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const - { - unsigned int n = 0; - uint32_t *id = (uint32_t *)0; - TState *ts = (TState *)0; - Hashtable::Iterator i(const_cast(this)->_tags); - while (i.next(id,ts)) { - if ((ts->lastReceived)&&(isCredentialTimestampValid(nconf,ts->tag))) { - if (n >= maxTags) - return n; - ids[n] = *id; - values[n] = ts->tag.value(); - } - } - return n; - } - - /** - * @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 - { - std::map::const_iterator c(_caps.find(id)); - return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(isCredentialTimestampValid(nconf,c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0); - } + const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const; /** * Validate and add a credential if signature is okay and it's otherwise good - * - * @param RR Runtime environment - * @param com Certificate of membership - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good - * - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const Tag &tag); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag); /** * Validate and add a credential if signature is okay and it's otherwise good - * - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const Capability &cap); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap); - /** - * Blacklist COM, tags, and capabilities before this time - * - * @param ts Blacklist cutoff - */ - inline void blacklistBefore(const uint64_t ts) { _blacklistBefore = ts; } - - /** - * Clean up old or stale entries - * - * @param nconf Network config - */ - inline void clean(const NetworkConfig &nconf) +private: + template + inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred,const CS &state) const { - for(std::map::iterator i(_caps.begin());i!=_caps.end();) { - if (!isCredentialTimestampValid(nconf,i->second.cap)) { - _caps.erase(i++); - } else { - ++i; - } - } - - uint32_t *i = (uint32_t *)0; - TState *ts = (TState *)0; - Hashtable::Iterator tsi(_tags); - while (tsi.next(i,ts)) { - if (!isCredentialTimestampValid(nconf,ts->tag)) - _tags.erase(*i); - } + const uint64_t ts = cred.timestamp(); + return ( (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) && (ts > state.revocationThreshold) ); } -private: // Last time we pushed MULTICAST_LIKE(s) uint64_t _lastUpdatedMulticast; @@ -278,17 +259,23 @@ private: // Last time we pushed our COM to this peer uint64_t _lastPushedCom; - // Time before which to blacklist credentials from this peer - uint64_t _blacklistBefore; + // Revocation threshold for COM or 0 if none + uint64_t _comRevocationThreshold; - // COM from this peer + // Remote member's latest network COM CertificateOfMembership _com; - // Capability-related state (we need an ordered container here, hence std::map) - std::map _caps; + // Sorted (in ascending order of ID) arrays of pointers to remote tags and capabilities + _RemoteTag *_remoteTags[ZT_MAX_NETWORK_TAGS]; + _RemoteCapability *_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]; + + // This is the RAM allocated for remote tags and capabilities from which the sorted arrays are populated + _RemoteTag _tagMem[ZT_MAX_NETWORK_TAGS]; + _RemoteCapability _capMem[ZT_MAX_NETWORK_CAPABILITIES]; - // Tag-related state - Hashtable _tags; + // Local credential push state tracking + _LocalCredentialPushState _localTags[ZT_MAX_NETWORK_TAGS]; + _LocalCredentialPushState _localCaps[ZT_MAX_NETWORK_CAPABILITIES]; }; } // namespace ZeroTier diff --git a/node/Network.cpp b/node/Network.cpp index 455e185e..0fab6a27 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -36,7 +36,7 @@ #include "Peer.hpp" // Uncomment to make the rules engine dump trace info to stdout -//#define ZT_RULES_ENGINE_DEBUGGING 1 +#define ZT_RULES_ENGINE_DEBUGGING 1 namespace ZeroTier { @@ -155,24 +155,21 @@ enum _doZtFilterResult static _doZtFilterResult _doZtFilter( const RuntimeEnvironment *RR, const NetworkConfig &nconf, + const Membership *membership, // can be NULL const bool inbound, const Address &ztSource, - Address &ztDest, // MUTABLE + Address &ztDest, // MUTABLE -- is changed on REDIRECT actions const MAC &macSource, const MAC &macDest, const uint8_t *const frameData, const unsigned int frameLen, const unsigned int etherType, const unsigned int vlanId, - const ZT_VirtualNetworkRule *rules, + const ZT_VirtualNetworkRule *rules, // cannot be NULL const unsigned int ruleCount, - const Tag *localTags, - const unsigned int localTagCount, - const uint32_t *const remoteTagIds, - const uint32_t *const remoteTagValues, - const unsigned int remoteTagCount, - Address &cc, // MUTABLE - unsigned int &ccLength) // MUTABLE + Address &cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise + unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE + bool &ccWatch) // MUTABLE -- set to true for WATCH target as opposed to normal TEE { #ifdef ZT_RULES_ENGINE_DEBUGGING char dpbuf[1024]; // used by FILTER_TRACE macro @@ -204,6 +201,7 @@ static _doZtFilterResult _doZtFilter( // These are initially handled together since preliminary logic is common case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: case ZT_NETWORK_RULE_ACTION_REDIRECT: { const Address fwdAddr(rules[rn].v.fwd.address); if (fwdAddr == ztSource) { @@ -242,6 +240,7 @@ static _doZtFilterResult _doZtFilter( #endif // ZT_RULES_ENGINE_DEBUGGING cc = fwdAddr; ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; + ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); } } } continue; @@ -508,50 +507,40 @@ static _doZtFilterResult _doZtFilter( case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: { - const Tag *lt = (const Tag *)0; - for(unsigned int i=0;i 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } else { - const uint32_t *rtv = (const uint32_t *)0; - for(unsigned int i=0;i 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } else { - thisRuleMatches = 1; - FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); - } - } else { + const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); + if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { + const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); + if (remoteTag) { + const uint32_t ltv = localTag->value(); + const uint32_t rtv = remoteTag->value(); if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { - const uint32_t diff = (lt->value() > *rtv) ? (lt->value() - *rtv) : (*rtv - lt->value()); + const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); + FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { - thisRuleMatches = (uint8_t)((lt->value() & *rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); + thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); + FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { - thisRuleMatches = (uint8_t)((lt->value() | *rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); + thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); + FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { - thisRuleMatches = (uint8_t)((lt->value() ^ *rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); + thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); + FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { // sanity check, can't really happen thisRuleMatches = 0; } + } else { + if (inbound) { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); + } else { + thisRuleMatches = 1; + FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); + } } + } else { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } break; @@ -582,7 +571,6 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : _portInitialized(false), _inboundConfigPacketId(0), _lastConfigUpdate(0), - _lastRequestedConfiguration(0), _destroyed(false), _netconfFailure(NETCONF_FAILURE_NONE), _portError(0) @@ -598,7 +586,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : if (conf.length()) { dconf->load(conf.c_str()); if (nconf->fromDictionary(*dconf)) { - this->setConfiguration(*nconf,false); + this->_setConfiguration(*nconf,false); _lastConfigUpdate = 0; // we still want to re-request a new config from the network gotConf = true; } @@ -646,32 +634,27 @@ bool Network::filterOutgoingPacket( const unsigned int etherType, const unsigned int vlanId) { - uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; - uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; + const uint64_t now = RR->node->now(); Address ztFinalDest(ztDest); - Address cc; - const Capability *relevantCap = (const Capability *)0; - unsigned int ccLength = 0; + int localCapabilityIndex = -1; bool accept = false; - const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); - Membership *m = (Membership *)0; - unsigned int remoteTagCount = 0; - if (ztDest) { - m = &(_memberships[ztDest]); - remoteTagCount = m->getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); - } + Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0; - switch(_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; + switch(_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { case DOZTFILTER_NO_MATCH: for(unsigned int c=0;c<_config.capabilityCount;++c) { - ztFinalDest = ztDest; // sanity check + ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match Address cc2; unsigned int ccLength2 = 0; - switch (_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + bool ccWatch2 = false; + switch (_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; @@ -679,16 +662,16 @@ bool Network::filterOutgoingPacket( case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side - relevantCap = &(_config.capabilities[c]); + localCapabilityIndex = (int)c; accept = true; if ((!noTee)&&(cc2)) { Membership &m2 = _membership(cc2); - m2.sendCredentialsIfNeeded(RR,now,cc2,_config,relevantCap); + m2.pushCredentials(RR,now,cc2,_config,localCapabilityIndex,false); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); - outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 + outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02)); macDest.appendTo(outp); macSource.appendTo(outp); outp.append((uint16_t)etherType); @@ -715,13 +698,16 @@ bool Network::filterOutgoingPacket( } if (accept) { + if (membership) + membership->pushCredentials(RR,now,ztDest,_config,localCapabilityIndex,false); + if ((!noTee)&&(cc)) { Membership &m2 = _membership(cc); - m2.sendCredentialsIfNeeded(RR,now,cc,_config,relevantCap); + m2.pushCredentials(RR,now,cc,_config,localCapabilityIndex,false); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); - outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 + outp.append((uint8_t)(ccWatch ? 0x16 : 0x02)); macDest.appendTo(outp); macSource.appendTo(outp); outp.append((uint16_t)etherType); @@ -732,11 +718,11 @@ bool Network::filterOutgoingPacket( if ((ztDest != ztFinalDest)&&(ztFinalDest)) { Membership &m2 = _membership(ztFinalDest); - m2.sendCredentialsIfNeeded(RR,now,ztFinalDest,_config,relevantCap); + m2.pushCredentials(RR,now,ztFinalDest,_config,localCapabilityIndex,false); Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); - outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 + outp.append((uint8_t)0x04); macDest.appendTo(outp); macSource.appendTo(outp); outp.append((uint16_t)etherType); @@ -745,11 +731,9 @@ bool Network::filterOutgoingPacket( RR->sw->send(outp,true); return false; // DROP locally, since we redirected - } else if (m) { - m->sendCredentialsIfNeeded(RR,now,ztDest,_config,relevantCap); + } else { + return true; } - - return true; } else { return false; } @@ -765,28 +749,27 @@ int Network::filterIncomingPacket( const unsigned int etherType, const unsigned int vlanId) { - uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; - uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; Address ztFinalDest(ztDest); - Address cc; - unsigned int ccLength = 0; int accept = 0; Mutex::Lock _l(_lock); - Membership &m = _membership(sourcePeer->address()); - const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); + Membership &membership = _membership(sourcePeer->address()); - switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; + switch (_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { case DOZTFILTER_NO_MATCH: { - Membership::CapabilityIterator mci(m); + Membership::CapabilityIterator mci(membership,_config); const Capability *c; - while ((c = mci.next(_config))) { - ztFinalDest = ztDest; // sanity check + while ((c = mci.next())) { + ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match Address cc2; unsigned int ccLength2 = 0; - switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + bool ccWatch2 = false; + switch(_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; @@ -801,11 +784,11 @@ int Network::filterIncomingPacket( if (accept) { if (cc2) { - _membership(cc2).sendCredentialsIfNeeded(RR,RR->node->now(),cc2,_config,(const Capability *)0); + _membership(cc2).pushCredentials(RR,RR->node->now(),cc2,_config,-1,false); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); - outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 + outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08)); macDest.appendTo(outp); macSource.appendTo(outp); outp.append((uint16_t)etherType); @@ -832,11 +815,11 @@ int Network::filterIncomingPacket( if (accept) { if (cc) { - _membership(cc).sendCredentialsIfNeeded(RR,RR->node->now(),cc,_config,(const Capability *)0); + _membership(cc).pushCredentials(RR,RR->node->now(),cc,_config,-1,false); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); - outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 + outp.append((uint8_t)(ccWatch ? 0x1c : 0x08)); macDest.appendTo(outp); macSource.appendTo(outp); outp.append((uint16_t)etherType); @@ -846,11 +829,11 @@ int Network::filterIncomingPacket( } if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - _membership(ztFinalDest).sendCredentialsIfNeeded(RR,RR->node->now(),ztFinalDest,_config,(const Capability *)0); + _membership(ztFinalDest).pushCredentials(RR,RR->node->now(),ztFinalDest,_config,-1,false); Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); - outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 + outp.append((uint8_t)0x0a); macDest.appendTo(outp); macSource.appendTo(outp); outp.append((uint16_t)etherType); @@ -892,60 +875,6 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.erase(i); } -bool Network::applyConfiguration(const NetworkConfig &conf) -{ - if (_destroyed) // sanity check - return false; - try { - if ((conf.networkId == _id)&&(conf.issuedTo == RR->identity.address())) { - ZT_VirtualNetworkConfig ctmp; - bool portInitialized; - { - Mutex::Lock _l(_lock); - _config = conf; - _lastConfigUpdate = RR->node->now(); - _netconfFailure = NETCONF_FAILURE_NONE; - _externalConfig(&ctmp); - portInitialized = _portInitialized; - _portInitialized = true; - } - _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(portInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); - return true; - } else { - TRACE("ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address)",(unsigned long long)_id); - } - } catch (std::exception &exc) { - TRACE("ignored invalid configuration for network %.16llx (%s)",(unsigned long long)_id,exc.what()); - } catch ( ... ) { - TRACE("ignored invalid configuration for network %.16llx (unknown exception)",(unsigned long long)_id); - } - return false; -} - -int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) -{ - try { - { - Mutex::Lock _l(_lock); - if (_config == nconf) - return 1; // OK config, but duplicate of what we already have - } - if (applyConfiguration(nconf)) { - if (saveToDisk) { - char n[64]; - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); - Dictionary d; - if (nconf.toDictionary(d,false)) - RR->node->dataStorePut(n,(const void *)d.data(),d.sizeBytes(),true); - } - return 2; // OK and configuration has changed - } - } catch ( ... ) { - TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); - } - return 0; -} - void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize) { std::string newConfig; @@ -979,7 +908,8 @@ void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *d Identity controllerId(RR->topology->getIdentity(this->controller())); if (controllerId) { if (nc->fromDictionary(*dict)) { - this->setConfiguration(*nc,true); + Mutex::Lock _l(_lock); + this->_setConfiguration(*nc,true); } else { TRACE("error parsing new config with length %u: deserialization of NetworkConfig failed (certificate error?)",(unsigned int)newConfig.length()); } @@ -997,12 +927,6 @@ void Network::handleInboundConfigChunk(const uint64_t inRePacketId,const void *d void Network::requestConfiguration() { - // Sanity limit: do not request more often than once per second - const uint64_t now = RR->node->now(); - if ((now - _lastRequestedConfiguration) < 1000ULL) - return; - _lastRequestedConfiguration = RR->node->now(); - const Address ctrl(controller()); Dictionary rmd; @@ -1024,9 +948,10 @@ void Network::requestConfiguration() if (RR->localNetworkController) { NetworkConfig nconf; switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,nconf)) { - case NetworkController::NETCONF_QUERY_OK: - this->setConfiguration(nconf,true); - return; + case NetworkController::NETCONF_QUERY_OK: { + Mutex::Lock _l(_lock); + this->_setConfiguration(nconf,true); + } return; case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: this->setNotFound(); return; @@ -1073,7 +998,7 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) { if (!m) m = &(_membership(peer->address())); - m->sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); + m->pushCredentials(RR,now,peer->address(),_config,-1,false); if (m->shouldLikeMulticasts(now)) { _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); m->likingMulticasts(now); @@ -1124,9 +1049,8 @@ void Network::clean() Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if (RR->topology->getPeerNoCache(*a)) - m->clean(_config); - else _memberships.erase(*a); + if (!RR->topology->getPeerNoCache(*a)) + _memberships.erase(*a); } } } @@ -1177,21 +1101,25 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) _sendUpdatesToMembers(&mg); } -int Network::addCredential(const CertificateOfMembership &com) +Membership::AddCredentialResult Network::addCredential(const CertificateOfMembership &com) { if (com.networkId() != _id) - return -1; + return Membership::ADD_REJECTED; const Address a(com.issuedTo()); Mutex::Lock _l(_lock); Membership &m = _membership(a); - const int result = m.addCredential(RR,com); - if (result == 0) { - m.sendCredentialsIfNeeded(RR,RR->node->now(),a,_config,(const Capability *)0); + const Membership::AddCredentialResult result = m.addCredential(RR,_config,com); + if ((result == Membership::ADD_ACCEPTED_NEW)||(result == Membership::ADD_ACCEPTED_REDUNDANT)) { + m.pushCredentials(RR,RR->node->now(),a,_config,-1,false); RR->mc->addCredential(com,true); } return result; } +Membership::AddCredentialResult Network::addCredential(const Revocation &rev) +{ +} + void Network::destroy() { Mutex::Lock _l(_lock); @@ -1215,6 +1143,39 @@ ZT_VirtualNetworkStatus Network::_status() const } } +int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk) +{ + // assumes _lock is locked + try { + if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) + return 0; + if (_config == nconf) + return 1; // OK config, but duplicate of what we already have + + ZT_VirtualNetworkConfig ctmp; + _config = nconf; + _lastConfigUpdate = RR->node->now(); + _netconfFailure = NETCONF_FAILURE_NONE; + _externalConfig(&ctmp); + const bool oldPortInitialized = _portInitialized; + _portInitialized = true; + _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); + + if (saveToDisk) { + char n[64]; + Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); + Dictionary d; + if (nconf.toDictionary(d,false)) + RR->node->dataStorePut(n,(const void *)d.data(),d.sizeBytes(),true); + } + + return 2; // OK and configuration has changed + } catch ( ... ) { + TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); + } + return 0; +} + void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const { // assumes _lock is locked @@ -1308,7 +1269,7 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - m->sendCredentialsIfNeeded(RR,now,*a,_config,(const Capability *)0); + m->pushCredentials(RR,now,*a,_config,-1,false); if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { if (!newMulticastGroup) m->likingMulticasts(now); diff --git a/node/Network.hpp b/node/Network.hpp index c85e5993..a151fb88 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -62,6 +62,11 @@ public: */ static const MulticastGroup BROADCAST; + /** + * Compute primary controller device ID from network ID + */ + static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); } + /** * Construct a new network * @@ -76,14 +81,24 @@ public: ~Network(); + inline uint64_t id() const { return _id; } + inline Address controller() const { return Address(_id >> 24); } + inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } + inline bool hasConfig() const { return (_config); } + inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; } + inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } + inline const NetworkConfig &config() const { return _config; } + inline const MAC &mac() const { return _mac; } + /** * Apply filters to an outgoing packet * * This applies filters from our network config and, if that doesn't match, * our capabilities in ascending order of capability ID. Additional actions - * such as TEE may be taken, and credentials may be pushed. + * such as TEE may be taken, and credentials may be pushed, so this is not + * side-effect-free. It's basically step one in sending something over VL2. * - * @param noTee If true, do not TEE anything anywhere + * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) * @param ztSource Source ZeroTier address * @param ztDest Destination ZeroTier address * @param macSource Ethernet layer source address @@ -134,42 +149,10 @@ public: const unsigned int vlanId); /** - * @return Network ID - */ - inline uint64_t id() const throw() { return _id; } - - /** - * @return Address of network's controller (most significant 40 bits of ID) - */ - inline Address controller() const throw() { return Address(_id >> 24); } - - /** - * @param nwid Network ID - * @return Address of network's controller - */ - static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); } - - /** - * @return Multicast group memberships for this network's port (local, not learned via bridging) - */ - inline std::vector multicastGroups() const - { - Mutex::Lock _l(_lock); - return _myMulticastGroups; - } - - /** - * @return All multicast groups including learned groups that are behind any bridges we're attached to - */ - inline std::vector allMulticastGroups() const - { - Mutex::Lock _l(_lock); - return _allMulticastGroups(); - } - - /** + * Check whether we are subscribed to a multicast group + * * @param mg Multicast group - * @param includeBridgedGroups If true, also include any groups we've learned via bridging + * @param includeBridgedGroups If true, also check groups we've learned via bridging * @return True if this network endpoint / peer is a member */ bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const; @@ -188,37 +171,19 @@ public: */ void multicastUnsubscribe(const MulticastGroup &mg); - /** - * Apply a NetworkConfig to this network - * - * @param conf Configuration in NetworkConfig form - * @return True if configuration was accepted - */ - bool applyConfiguration(const NetworkConfig &conf); - - /** - * Set or update this network's configuration - * - * @param nconf Network configuration - * @param saveToDisk IF true (default), write config to disk - * @return 0 -- rejected, 1 -- accepted but not new, 2 -- accepted new config - */ - int setConfiguration(const NetworkConfig &nconf,bool saveToDisk); - /** * Handle an inbound network config chunk * - * Only chunks whose inRePacketId matches the packet ID of the last request - * are handled. If this chunk completes the config, it is decoded and - * setConfiguration() is called. + * This is called from IncomingPacket when we receive a chunk from a network + * controller. * - * @param inRePacketId In-re packet ID from OK(NETWORK_CONFIG_REQUEST) + * @param requestId An ID for grouping chunks, e.g. in-re packet ID for OK(NETWORK_CONFIG_REQUEST) * @param data Chunk data * @param chunkSize Size of data[] * @param chunkIndex Index of chunk in full config * @param totalSize Total size of network config */ - void handleInboundConfigChunk(const uint64_t inRePacketId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize); + void handleInboundConfigChunk(const uint64_t requestId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize); /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this @@ -230,7 +195,7 @@ public: } /** - * Set netconf failure to 'not found' -- called by PacketDecider when controller reports this + * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this */ inline void setNotFound() { @@ -240,10 +205,6 @@ public: /** * Causes this network to request an updated configuration from its master node now - * - * There is a circuit breaker here to prevent this from being done more often - * than once per second. This is to prevent things like NETWORK_CONFIG_REFRESH - * from causing multiple requests. */ void requestConfiguration(); @@ -251,7 +212,7 @@ public: * Determine whether this peer is permitted to communicate on this network * * This also performs certain periodic actions such as pushing renewed - * credentials to peers or requesting them if not present. + * credentials to peers, so like the filters it is not side-effect-free. * * @param peer Peer to check * @param verb Packet verb @@ -266,7 +227,7 @@ public: bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); /** - * Perform cleanup and possibly save state + * Do periodic cleanup and housekeeping tasks */ void clean(); @@ -279,46 +240,6 @@ public: _sendUpdatesToMembers((const MulticastGroup *)0); } - /** - * @return Time of last updated configuration or 0 if none - */ - inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; } - - /** - * @return Status of this network - */ - inline ZT_VirtualNetworkStatus status() const - { - Mutex::Lock _l(_lock); - return _status(); - } - - /** - * @param ec Buffer to fill with externally-visible network configuration - */ - inline void externalConfig(ZT_VirtualNetworkConfig *ec) const - { - Mutex::Lock _l(_lock); - _externalConfig(ec); - } - - /** - * Get current network config - * - * @return Network configuration (may be a null config if we don't have one yet) - */ - inline const NetworkConfig &config() const { return _config; } - - /** - * @return True if this network has a valid config - */ - inline bool hasConfig() const { return (_config); } - - /** - * @return Ethernet MAC address for this network's local interface - */ - inline const MAC &mac() const { return _mac; } - /** * Find the node on this network that has this MAC behind it (if any) * @@ -349,44 +270,47 @@ public: void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now); /** - * @param com Certificate of membership - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + * Validate a credential and learn it if it passes certificate and other checks */ - int addCredential(const CertificateOfMembership &com); + Membership::AddCredentialResult addCredential(const CertificateOfMembership &com); /** - * @param cap Capability - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + * Validate a credential and learn it if it passes certificate and other checks */ - inline int addCredential(const Capability &cap) + inline Membership::AddCredentialResult addCredential(const Capability &cap) { if (cap.networkId() != _id) - return -1; + return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(cap.issuedTo()).addCredential(RR,cap); + return _membership(cap.issuedTo()).addCredential(RR,_config,cap); } /** - * @param cap Tag - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + * Validate a credential and learn it if it passes certificate and other checks */ - inline int addCredential(const Tag &tag) + inline Membership::AddCredentialResult addCredential(const Tag &tag) { if (tag.networkId() != _id) - return -1; + return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(tag.issuedTo()).addCredential(RR,tag); + return _membership(tag.issuedTo()).addCredential(RR,_config,tag); } /** - * Blacklist COM, tags, and capabilities before this time + * Validate a credential and learn it if it passes certificate and other checks + */ + Membership::AddCredentialResult addCredential(const Revocation &rev); + + /** + * Force push credentials (COM, etc.) to a peer now * - * @param ts Blacklist cutoff + * @param to Destination peer address + * @param now Current time */ - inline void blacklistBefore(const Address &peerAddress,const uint64_t ts) + inline void pushCredentialsNow(const Address &to,const uint64_t now) { Mutex::Lock _l(_lock); - _membership(peerAddress).blacklistBefore(ts); + _membership(to).pushCredentials(RR,now,to,_config,-1,true); } /** @@ -399,11 +323,23 @@ public: void destroy(); /** - * @return Pointer to user PTR (modifiable user ptr used in API) + * Get this network's config for export via the ZT core API + * + * @param ec Buffer to fill with externally-visible network configuration + */ + inline void externalConfig(ZT_VirtualNetworkConfig *ec) const + { + Mutex::Lock _l(_lock); + _externalConfig(ec); + } + + /** + * @return Externally usable pointer-to-pointer exported via the core API */ inline void **userPtr() throw() { return &_uPtr; } private: + int _setConfiguration(const NetworkConfig &nconf,bool saveToDisk); ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _gate(const SharedPtr &peer); @@ -412,9 +348,9 @@ private: std::vector _allMulticastGroups() const; Membership &_membership(const Address &a); - const RuntimeEnvironment *RR; + const RuntimeEnvironment *const RR; void *_uPtr; - uint64_t _id; + const uint64_t _id; uint64_t _lastAnnouncedMulticastGroupsUpstream; MAC _mac; // local MAC address volatile bool _portInitialized; @@ -428,7 +364,6 @@ private: NetworkConfig _config; volatile uint64_t _lastConfigUpdate; - volatile uint64_t _lastRequestedConfiguration; volatile bool _destroyed; diff --git a/node/Packet.hpp b/node/Packet.hpp index 2ca73a84..03b9b113 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -655,15 +655,27 @@ public: * * Flags: * 0x01 - Certificate of network membership attached (DEPRECATED) - * 0x02 - This is a TEE'd or REDIRECT'ed packet - * 0x04 - TEE/REDIRECT'ed packet is from inbound side - * + * 0x02 - Most significant bit of subtype (see below) + * 0x04 - Middle bit of subtype (see below) + * 0x08 - Least significant bit of subtype (see below) + * 0x10 - ACK requested in the form of OK(EXT_FRAME) + * + * Subtypes (0..7): + * 0x0 - Normal frame (bridging can be determined by checking MAC) + * 0x1 - TEEd outbound frame + * 0x2 - REDIRECTed outbound frame + * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) + * 0x4 - TEEd inbound frame + * 0x5 - REDIRECTed inbound frame + * 0x6 - WATCHed inbound frame + * 0x7 - (reserved for future use) + * * 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. * - * ERROR may be generated if a membership certificate is needed for a - * closed network. Payload will be network ID. + * If the ACK flag (0x08) is set, an OK(EXT_FRAME) is sent with + * no payload to acknowledge receipt of the frame. */ VERB_EXT_FRAME = 0x07, @@ -698,7 +710,7 @@ public: VERB_MULTICAST_LIKE = 0x09, /** - * Network membership credential push: + * Network credentials push: * <[...] serialized certificate of membership> * [<[...] additional certificates of membership>] * <[1] 0x00, null byte marking end of COM array> @@ -706,12 +718,12 @@ public: * <[...] one or more serialized Capability> * <[2] 16-bit number of tags> * <[...] one or more serialized Tags> + * <[2] 16-bit number of revocations> + * <[...] one or more serialized Revocations> * - * 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. - * - * COMs and other credentials need not be for the same network, since each - * includes its own network ID and signature. + * This can be sent by anyone at any time to push network credentials. + * These will of course only be accepted if they are properly signed. + * Credentials can be for any number of networks. * * OK/ERROR are not generated. */ @@ -742,23 +754,18 @@ public: VERB_NETWORK_CONFIG_REQUEST = 0x0b, /** - * Network configuration update push: - * <[8] network ID to refresh> - * <[2] 16-bit number of address/timestamp pairs to blacklist> - * [<[5] ZeroTier address of peer being revoked>] - * [<[8] blacklist credentials older than this timestamp>] - * [<[...] additional address/timestamp pairs>] - * - * This can be sent by a network controller to both request that a network - * config be updated and push instantaneous revocations of specific peers - * or peer credentials. - * - * Specific revocations can be pushed to blacklist a specific peer's - * credentials (COM, tags, and capabilities) if older than a specified - * timestamp. This can be used to accomplish expedited revocation of - * a peer's access to things on a network or to the network itself among - * those other peers that can currently reach the controller. This is not - * the only mechanism for revocation of course, but it's the fastest. + * Network configuration push: + * <[8] 64-bit network ID> + * <[8] 64-bit value used to group chunks in this push> + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk in this reply> + * + * This is a direct push variant for network config updates. It otherwise + * carries the same payload as OK(NETWORK_CONFIG_REQUEST). There is an + * extra number after network ID in this version that is used in place of + * the in-re packet ID sent with OKs to group chunks together. */ VERB_NETWORK_CONFIG_REFRESH = 0x0c, diff --git a/node/Revocation.cpp b/node/Revocation.cpp new file mode 100644 index 00000000..420476a4 --- /dev/null +++ b/node/Revocation.cpp @@ -0,0 +1,46 @@ +/* + * 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 . + */ + +#include "Revocation.hpp" +#include "RuntimeEnvironment.hpp" +#include "Identity.hpp" +#include "Topology.hpp" +#include "Switch.hpp" +#include "Network.hpp" + +namespace ZeroTier { + +int Revocation::verify(const RuntimeEnvironment *RR) const +{ + if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) + return -1; + const Identity id(RR->topology->getIdentity(_signedBy)); + if (!id) { + RR->sw->requestWhois(_signedBy); + return 1; + } + try { + Buffer tmp; + this->serialize(tmp,true); + return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); + } catch ( ... ) { + return -1; + } +} + +} // namespace ZeroTier diff --git a/node/Revocation.hpp b/node/Revocation.hpp new file mode 100644 index 00000000..58757465 --- /dev/null +++ b/node/Revocation.hpp @@ -0,0 +1,178 @@ +/* + * 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_REVOCATION_HPP +#define ZT_REVOCATION_HPP + +#include +#include +#include +#include + +#include "Constants.hpp" +#include "../include/ZeroTierOne.h" +#include "Address.hpp" +#include "C25519.hpp" +#include "Utils.hpp" +#include "Buffer.hpp" +#include "Identity.hpp" + +/** + * Flag: fast propagation via rumor mill algorithm + */ +#define ZT_REVOCATION_FLAG_FAST_PROPAGATE 0x1ULL + +namespace ZeroTier { + +class RuntimeEnvironment; + +/** + * Revocation certificate to instantaneously revoke a COM, capability, or tag + */ +class Revocation +{ +public: + enum CredentialType + { + CREDENTIAL_TYPE_NIL = 0, + CREDENTIAL_TYPE_COM = 1, + CREDENTIAL_TYPE_CAPABILITY = 2, + CREDENTIAL_TYPE_TAG = 3 + }; + + Revocation() + { + memset(this,0,sizeof(Revocation)); + } + + Revocation(const uint64_t i,const uint64_t nwid,const uint64_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const CredentialType ct) : + _id(i), + _networkId(nwid), + _credentialId(cid), + _threshold(thr), + _flags(fl), + _target(tgt), + _signedBy(), + _type(ct) {} + + inline uint64_t id() const { return _id; } + inline uint64_t networkId() const { return _networkId; } + inline uint64_t credentialId() const { return _credentialId; } + inline uint64_t threshold() const { return _threshold; } + inline const Address &target() const { return _target; } + inline const Address &signer() const { return _signedBy; } + inline CredentialType type() const { return _type; } + + inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } + + /** + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + inline bool sign(const Identity &signer) + { + if (signer.hasPrivate()) { + Buffer tmp; + this->serialize(tmp,true); + _signedBy = signer.address(); + _signature = signer.sign(tmp.data(),tmp.size()); + return true; + } + return false; + } + + /** + * Verify this revocation's signature + * + * @param RR Runtime environment to provide for peer lookup, etc. + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain + */ + int verify(const RuntimeEnvironment *RR) const; + + template + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + b.append(_id); + b.append(_networkId); + b.append(_credentialId); + b.append(_threshold); + b.append(_flags); + _target.appendTo(b); + _signedBy.appendTo(b); + b.append((uint8_t)_type); + + if (!forSign) { + b.append((uint8_t)1); // 1 == Ed25519 signature + b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + } + + // This is the size of any additional fields, currently 0. + b.append((uint16_t)0); + + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + memset(this,0,sizeof(Revocation)); + + unsigned int p = startAt; + + _id = b.template at(p); p += 8; + _networkId = b.template at(p); p += 8; + _credentialId = b.template at(p); p += 8; + _threshold = b.template at(p); p += 8; + _flags = b.template at(p); p += 8; + _target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; + _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; + _type = (CredentialType)b[p++]; + + if (b[p++] == 1) { + if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { + p += 2; + memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); + p += ZT_C25519_SIGNATURE_LEN; + } else throw std::runtime_error("invalid signature"); + } + + p += 2 + b.template at(p); + if (p > b.size()) + throw std::runtime_error("extended field overflow"); + + return (p - startAt); + } + +private: + uint64_t _id; + uint64_t _networkId; + uint64_t _credentialId; + uint64_t _threshold; + uint64_t _flags; + Address _target; + Address _signedBy; + CredentialType _type; + C25519::Signature _signature; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Tag.cpp b/node/Tag.cpp index 352ecde8..eb4026bc 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -27,7 +27,7 @@ namespace ZeroTier { int Tag::verify(const RuntimeEnvironment *RR) const { - if ((!_signedBy)||(_signedBy != Network::controllerFor(_nwid))) + if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; const Identity id(RR->topology->getIdentity(_signedBy)); if (!id) { diff --git a/node/Tag.hpp b/node/Tag.hpp index 14cc3a5d..97228157 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -67,7 +67,7 @@ public: * @param value Tag value */ Tag(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) : - _nwid(nwid), + _networkId(nwid), _ts(ts), _id(id), _value(value), @@ -76,7 +76,7 @@ public: { } - inline uint64_t networkId() const { return _nwid; } + inline uint64_t networkId() const { return _networkId; } inline uint64_t timestamp() const { return _ts; } inline uint32_t id() const { return _id; } inline const uint32_t &value() const { return _value; } @@ -91,13 +91,13 @@ public: */ inline bool sign(const Identity &signer) { - try { - Buffer<(sizeof(Tag) * 2)> tmp; + if (signer.hasPrivate()) { + Buffer tmp; _signedBy = signer.address(); this->serialize(tmp,true); _signature = signer.sign(tmp.data(),tmp.size()); return true; - } catch ( ... ) {} + } return false; } @@ -115,7 +115,7 @@ public: if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); // These are the same between Tag and Capability - b.append(_nwid); + b.append(_networkId); b.append(_ts); b.append(_id); @@ -140,7 +140,7 @@ public: unsigned int p = startAt; // These are the same between Tag and Capability - _nwid = b.template at(p); p += 8; + _networkId = b.template at(p); p += 8; _ts = b.template at(p); p += 8; _id = b.template at(p); p += 4; @@ -168,8 +168,22 @@ public: inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); } inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); } + // For searching sorted arrays or lists of Tags by ID + struct IdComparePredicate + { + inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); } + inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); } + inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); } + inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); } + inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); } + inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); } + inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); } + inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); } + inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); } + }; + private: - uint64_t _nwid; + uint64_t _networkId; uint64_t _ts; uint32_t _id; uint32_t _value; diff --git a/objects.mk b/objects.mk index f92a907e..5738e769 100644 --- a/objects.mk +++ b/objects.mk @@ -17,6 +17,7 @@ OBJS=\ node/Path.o \ node/Peer.o \ node/Poly1305.o \ + node/Revocation.o \ node/Salsa20.o \ node/SelfAwareness.o \ node/SHA512.o \ -- cgit v1.2.3 From eac3667ec1391baaf83c64403e8a19c22c24c9f2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 26 Sep 2016 16:17:02 -0700 Subject: Bunch more refactoring and work on revocations, etc. --- include/ZeroTierOne.h | 2 +- node/IncomingPacket.cpp | 53 ++++++++++++------ node/IncomingPacket.hpp | 2 +- node/Membership.cpp | 143 ++++++++++++++++++++++++++++++++++++------------ node/Membership.hpp | 21 +++++-- node/Network.cpp | 37 ++++++++++++- node/Network.hpp | 2 +- node/Packet.cpp | 2 +- node/Packet.hpp | 28 +++++++--- node/Revocation.hpp | 2 +- 10 files changed, 220 insertions(+), 72 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index e43c8541..591ff1fe 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -517,7 +517,7 @@ enum ZT_VirtualNetworkRuleType ZT_NETWORK_RULE_ACTION_TEE = 2, /** - * Exactly like TEE but frames are dropped if previous TEEs were not acknowledged by the observer + * Exactly like TEE but mandates ACKs from observer */ ZT_NETWORK_RULE_ACTION_WATCH = 3, diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 12766fe2..c50db794 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -67,7 +67,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) return _doHELLO(RR,false); } - SharedPtr peer(RR->topology->getPeer(sourceAddress)); + const SharedPtr peer(RR->topology->getPeer(sourceAddress)); if (peer) { if (!trusted) { if (!dearmor(peer->key())) { @@ -100,7 +100,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(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_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); + case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,peer); case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); @@ -131,12 +131,18 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); + /* Security note: we do not gate doERROR() with expectingReplyTo() to + * avoid having to log every outgoing packet ID. Instead we put the + * logic to determine whether we should consider an ERROR in each + * error handler. In most cases these are only trusted in specific + * circumstances. */ + switch(errorCode) { case Packet::ERROR_OBJ_NOT_FOUND: // Object not found, currently only meaningful from network controllers. if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) network->setNotFound(); } @@ -147,7 +153,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // consider it meaningful from network controllers. This would indicate // that the queried node does not support acting as a controller. if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) network->setNotFound(); } @@ -161,7 +167,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { // Peers can send this in response to frames if they do not have a recent enough COM from us - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) network->pushCredentialsNow(peer->address(),now); @@ -169,7 +175,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_NETWORK_ACCESS_DENIED_: { // Network controller: network access denied. - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) network->setAccessDenied(); } break; @@ -177,9 +183,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_UNWANTED_MULTICAST: { // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->gate(peer,verb(),packetId()))) { - MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); } @@ -371,7 +377,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); bool trustEstablished = false; - // Don't parse OK packets that are not in response to a packet ID we sent if (!RR->node->expectingReplyTo(inRePacketId)) { TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); return true; @@ -450,7 +455,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - SharedPtr network(RR->node->network(nwid)); + const SharedPtr network(RR->node->network(nwid)); if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { trustEstablished = true; const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); @@ -467,7 +472,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); - SharedPtr network(RR->node->network(nwid)); + const SharedPtr network(RR->node->network(nwid)); if (network) { unsigned int offset = 0; @@ -683,6 +688,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

address(),RR->identity.address(),Packet::VERB_OK); outp.append((uint8_t)Packet::VERB_EXT_FRAME); outp.append((uint64_t)packetId()); + outp.append((uint64_t)nwid); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -727,7 +733,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared try { const uint64_t now = RR->node->now(); - uint64_t authOnNetwork[256]; + uint64_t authOnNetwork[256]; // cache for approved network IDs unsigned int authOnNetworkCount = 0; SharedPtr network; bool trustEstablished = false; @@ -786,7 +792,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S while ((p < size())&&((*this)[p])) { p += com.deserialize(*this,p); if (com) { - SharedPtr network(RR->node->network(com.networkId())); + const SharedPtr network(RR->node->network(com.networkId())); if (network) { switch (network->addCredential(com)) { case Membership::ADD_REJECTED: @@ -803,11 +809,11 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } ++p; // skip trailing 0 after COMs if present - if (p < size()) { // check if new capabilities and tags fields are present + if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(cap.networkId())); + const SharedPtr network(RR->node->network(cap.networkId())); if (network) { switch (network->addCredential(cap)) { case Membership::ADD_REJECTED: @@ -825,7 +831,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(tag.networkId())); + const SharedPtr network(RR->node->network(tag.networkId())); if (network) { switch (network->addCredential(tag)) { case Membership::ADD_REJECTED: @@ -843,8 +849,18 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numRevocations = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(revocation.networkId())); + const SharedPtr network(RR->node->network(revocation.networkId())); if (network) { + switch(network->addCredential(peer->address(),revocation)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } } } } @@ -879,6 +895,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons try { if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { dconf->wrapWithSignature(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE,RR->identity.privateKeyPair()); + const unsigned int totalSize = dconf->sizeBytes(); unsigned int chunkIndex = 0; while (chunkIndex < totalSize) { @@ -957,7 +974,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons return true; } -bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PACKET_IDX_PAYLOAD); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index dbaf67b8..86c2b5e7 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -146,7 +146,7 @@ private: bool _doMULTICAST_LIKE(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 _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); diff --git a/node/Membership.cpp b/node/Membership.cpp index d579d303..b7e33936 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -167,24 +167,9 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_REJECTED; case 0: TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); - if (have) { - have->lastReceived = RR->node->now(); - have->tag = tag; - } else { - uint64_t minlr = 0xffffffffffffffffULL; - for(unsigned int i=0;iid == 0xffffffffffffffffULL) { - have = _remoteTags[i]; - break; - } else if (_remoteTags[i]->lastReceived <= minlr) { - have = _remoteTags[i]; - minlr = _remoteTags[i]->lastReceived; - } - } - have->lastReceived = RR->node->now(); - have->tag = tag; - std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>()); - } + if (!have) have = _newTag(tag.id()); + have->lastReceived = RR->node->now(); + have->tag = tag; return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -212,28 +197,114 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_REJECTED; case 0: TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); - if (have) { - have->lastReceived = RR->node->now(); - have->cap = cap; - } else { - uint64_t minlr = 0xffffffffffffffffULL; - for(unsigned int i=0;iid == 0xffffffffffffffffULL) { - have = _remoteCaps[i]; - break; - } else if (_remoteCaps[i]->lastReceived <= minlr) { - have = _remoteCaps[i]; - minlr = _remoteCaps[i]->lastReceived; - } - } - have->lastReceived = RR->node->now(); - have->cap = cap; - std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>()); - } + if (!have) have = _newCapability(cap.id()); + have->lastReceived = RR->node->now(); + have->cap = cap; return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; } } +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev) +{ + switch(rev.verify(RR)) { + default: + return ADD_REJECTED; + case 0: { + const uint64_t now = RR->node->now(); + switch(rev.type()) { + default: + //case Revocation::CREDENTIAL_TYPE_ALL: + return ( (_revokeCom(rev)||_revokeCap(rev,now)||_revokeTag(rev,now)) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT ); + case Revocation::CREDENTIAL_TYPE_COM: + return (_revokeCom(rev) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); + case Revocation::CREDENTIAL_TYPE_CAPABILITY: + return (_revokeCap(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); + case Revocation::CREDENTIAL_TYPE_TAG: + return (_revokeTag(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); + } + } + case 1: + return ADD_DEFERRED_FOR_WHOIS; + } +} + +Membership::_RemoteTag *Membership::_newTag(const uint64_t id) +{ + _RemoteTag *t; + uint64_t minlr = 0xffffffffffffffffULL; + for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { + t = _remoteTags[i]; + break; + } else if (_remoteTags[i]->lastReceived <= minlr) { + t = _remoteTags[i]; + minlr = _remoteTags[i]->lastReceived; + } + } + t->id = id; + t->lastReceived = 0; + t->revocationThreshold = 0; + t->tag = Tag(); + std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>()); + return t; +} + +Membership::_RemoteCapability *Membership::_newCapability(const uint64_t id) +{ + _RemoteCapability *c; + uint64_t minlr = 0xffffffffffffffffULL; + for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { + c = _remoteCaps[i]; + break; + } else if (_remoteCaps[i]->lastReceived <= minlr) { + c = _remoteCaps[i]; + minlr = _remoteCaps[i]->lastReceived; + } + } + c->id = id; + c->lastReceived = 0; + c->revocationThreshold = 0; + c->cap = Capability(); + std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>()); + return c; +} + +bool Membership::_revokeCom(const Revocation &rev) +{ + if (rev.threshold() > _comRevocationThreshold) { + _comRevocationThreshold = rev.threshold(); + return true; + } + return false; +} + +bool Membership::_revokeCap(const Revocation &rev,const uint64_t now) +{ + _RemoteCapability *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialSorter<_RemoteCapability>()); + _RemoteCapability *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCapability *)0; + if (!have) have = _newCapability(rev.credentialId()); + if (rev.threshold() > have->revocationThreshold) { + have->lastReceived = now; + have->revocationThreshold = rev.threshold(); + return true; + } + return false; +} + +bool Membership::_revokeTag(const Revocation &rev,const uint64_t now) +{ + _RemoteTag *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialSorter<_RemoteTag>()); + _RemoteTag *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteTag *)0; + if (!have) have = _newTag(rev.credentialId()); + if (rev.threshold() > have->revocationThreshold) { + have->lastReceived = now; + have->revocationThreshold = rev.threshold(); + return true; + } + return false; +} + } // namespace ZeroTier diff --git a/node/Membership.hpp b/node/Membership.hpp index 421e3ee8..c54aec9b 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -29,6 +29,8 @@ #include "Revocation.hpp" #include "NetworkConfig.hpp" +#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL + namespace ZeroTier { class RuntimeEnvironment; @@ -48,7 +50,7 @@ private: // Tags and related state struct _RemoteTag { - _RemoteTag() : id(0xffffffffffffffffULL),lastReceived(0),revocationThreshold(0) {} + _RemoteTag() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {} // Tag ID (last 32 bits, first 32 bits are set in unused entries to sort them to end) uint64_t id; // Last time we received THEIR tag (with this ID) @@ -62,7 +64,7 @@ private: // Credentials and related state struct _RemoteCapability { - _RemoteCapability() : id(0xffffffffffffffffULL),lastReceived(0),revocationThreshold(0) {} + _RemoteCapability() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {} // Capability ID (last 32 bits, first 32 bits are set in unused entries to sort them to end) uint64_t id; // Last time we received THEIR capability (with this ID) @@ -114,7 +116,7 @@ public: inline const Capability *next() { for(;;) { - if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != 0xffffffffffffffffULL)) { + if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { const Capability *tmp = &((*_i)->cap); if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { ++_i; @@ -147,7 +149,7 @@ public: inline const Tag *next() { for(;;) { - if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != 0xffffffffffffffffULL)) { + if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { const Tag *tmp = &((*_i)->tag); if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { ++_i; @@ -242,7 +244,18 @@ public: */ AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev); + private: + _RemoteTag *_newTag(const uint64_t id); + _RemoteCapability *_newCapability(const uint64_t id); + bool _revokeCom(const Revocation &rev); + bool _revokeCap(const Revocation &rev,const uint64_t now); + bool _revokeTag(const Revocation &rev,const uint64_t now); + template inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred,const CS &state) const { diff --git a/node/Network.cpp b/node/Network.cpp index 0fab6a27..487766a7 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -36,7 +36,7 @@ #include "Peer.hpp" // Uncomment to make the rules engine dump trace info to stdout -#define ZT_RULES_ENGINE_DEBUGGING 1 +//#define ZT_RULES_ENGINE_DEBUGGING 1 namespace ZeroTier { @@ -1116,8 +1116,41 @@ Membership::AddCredentialResult Network::addCredential(const CertificateOfMember return result; } -Membership::AddCredentialResult Network::addCredential(const Revocation &rev) +Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,const Revocation &rev) { + if (rev.networkId() != _id) + return Membership::ADD_REJECTED; + + Mutex::Lock _l(_lock); + Membership &m = _membership(rev.target()); + + const Membership::AddCredentialResult result = m.addCredential(RR,_config,rev); + + if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { + /* Fast propagation is done by using a very aggressive rumor mill + * propagation algorithm. When we see a Revocation that we haven't + * seen before we blast it to every known member. This leads to + * a huge number of redundant messages, but eventually everybody + * will get it. This helps revocation speed and also helps in cases + * where the controller is under attack. It need only get one + * revocation out and the rest is history. */ + Address *a = (Address *)0; + Membership *m = (Membership *)0; + Hashtable::Iterator i(_memberships); + while (i.next(a,m)) { + if ((*a != sentFrom)&&(*a != rev.signer())) { + Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + outp.append((uint8_t)0x00); // no COM + outp.append((uint16_t)0); // no capabilities + outp.append((uint16_t)0); // no tags + outp.append((uint16_t)1); // one revocation! + rev.serialize(outp); + RR->sw->send(outp,true); + } + } + } + + return result; } void Network::destroy() diff --git a/node/Network.hpp b/node/Network.hpp index a151fb88..6a1ac801 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -299,7 +299,7 @@ public: /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(const Revocation &rev); + Membership::AddCredentialResult addCredential(const Address &sentFrom,const Revocation &rev); /** * Force push credentials (COM, etc.) to a peer now diff --git a/node/Packet.cpp b/node/Packet.cpp index 9ab68968..3b8e1387 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -40,7 +40,7 @@ const char *Packet::verbString(Verb v) case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; - case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; + case VERB_NETWORK_CONFIG: return "NETWORK_CONFIG_REFRESH"; case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; diff --git a/node/Packet.hpp b/node/Packet.hpp index 03b9b113..e76cb96c 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -674,8 +674,8 @@ public: * superset of VERB_FRAME. They're used for bridging or when we * want to attach a certificate since FRAME does not support that. * - * If the ACK flag (0x08) is set, an OK(EXT_FRAME) is sent with - * no payload to acknowledge receipt of the frame. + * OK payload (if ACK flag is set): + * <[8] 64-bit network ID> */ VERB_EXT_FRAME = 0x07, @@ -738,9 +738,14 @@ public: * <[8] 64-bit timestamp of netconf we currently have> * * 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. + * providing it. + * + * Respones to this are always whole configs intended for the recipient. + * For patches and other updates a NETWORK_CONFIG is sent instead. * + * It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always, + * but OK(NTEWORK_CONFIG_REQUEST) should be sent for compatibility. + * * OK response payload: * <[8] 64-bit network ID> * <[2] 16-bit length of network configuration dictionary chunk> @@ -754,9 +759,10 @@ public: VERB_NETWORK_CONFIG_REQUEST = 0x0b, /** - * Network configuration push: + * Network configuration data push: * <[8] 64-bit network ID> - * <[8] 64-bit value used to group chunks in this push> + * <[8] 64-bit config update ID (token to identify this update)> + * <[1] flags> * <[2] 16-bit length of network configuration dictionary chunk> * <[...] network configuration dictionary (may be incomplete)> * <[4] 32-bit total length of assembled dictionary> @@ -766,8 +772,16 @@ public: * carries the same payload as OK(NETWORK_CONFIG_REQUEST). There is an * extra number after network ID in this version that is used in place of * the in-re packet ID sent with OKs to group chunks together. + * + * Unlike OK(NETWORK_CONFIG_REQUEST) this can be sent by peers other than + * network controllers. In that case the certificate inside the Dictionary + * is used for verification purposes. + * + * Flags: + * 0x01 - Patch, not whole config + * 0x02 - Use fast P2P propagation */ - VERB_NETWORK_CONFIG_REFRESH = 0x0c, + VERB_NETWORK_CONFIG = 0x0c, /** * Request endpoints for multicast distribution: diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 58757465..18916985 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -49,7 +49,7 @@ class Revocation public: enum CredentialType { - CREDENTIAL_TYPE_NIL = 0, + CREDENTIAL_TYPE_ALL = 0, CREDENTIAL_TYPE_COM = 1, CREDENTIAL_TYPE_CAPABILITY = 2, CREDENTIAL_TYPE_TAG = 3 -- cgit v1.2.3 From 7e4b6b594b9529565b8bb3acb6d99e37c1f3db1b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 26 Sep 2016 17:05:39 -0700 Subject: It now builds. --- controller/EmbeddedNetworkController.cpp | 4 ++-- include/ZeroTierOne.h | 21 --------------------- node/IncomingPacket.cpp | 2 +- node/Node.cpp | 32 -------------------------------- node/Node.hpp | 1 - node/Packet.hpp | 11 ++++++++--- 6 files changed, 11 insertions(+), 60 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 5ba8cf98..cd8ce8bf 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -516,8 +516,8 @@ void EmbeddedNetworkController::threadMain() Mutex::Lock _l(_refreshQueue_m); while (_refreshQueue.size() > 0) { _Refresh &r = _refreshQueue.front(); - if (_node) - _node->pushNetworkRefresh(r.dest,r.nwid,r.blacklistAddresses,r.blacklistThresholds,r.numBlacklistEntries); + //if (_node) + // _node->pushNetworkRefresh(r.dest,r.nwid,r.blacklistAddresses,r.blacklistThresholds,r.numBlacklistEntries); _refreshQueue.pop_front(); if (++count >= 50) break; diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 591ff1fe..c66b9079 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1928,27 +1928,6 @@ enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,v */ void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test); -/** - * Push a network refresh - * - * This is used by network controller implementations to send a - * NETWORK_CONFIG_REFRESH message to tell a node to refresh its - * config and to optionally push one or more credential timestamp - * blacklist thresholds for members of the network. - * - * Code outside a controller implementation will have no use for - * this as these messages are ignored if they do not come from a - * controller. - * - * @param node Node instance - * @param dest ZeroTier address of destination to which to send NETWORK_CONFIG_REFRESH - * @param nwid Network ID - * @param blacklistAddresses Array of ZeroTier addresses of network members to set timestamp blacklists for - * @param blacklistBeforeTimestamps Timestamps before which to blacklist credentials for each corresponding address in blacklistAddresses[] - * @param blacklistCount Size of blacklistAddresses[] and blacklistBeforeTimestamps[] - */ -void ZT_Node_pushNetworkRefresh(ZT_Node *node,uint64_t dest,uint64_t nwid,const uint64_t *blacklistAddresses,const uint64_t *blacklistBeforeTimestamps,unsigned int blacklistCount); - /** * Initialize cluster operation * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c50db794..72dfbfd8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -982,7 +982,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,trustEstablished); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Node.cpp b/node/Node.cpp index 2533eeb6..db9b8ea0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -552,31 +552,6 @@ void Node::circuitTestEnd(ZT_CircuitTest *test) } } -void Node::pushNetworkRefresh(uint64_t dest,uint64_t nwid,const uint64_t *blacklistAddresses,const uint64_t *blacklistBeforeTimestamps,unsigned int blacklistCount) -{ - Packet outp(Address(dest),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REFRESH); - outp.append(nwid); - outp.addSize(2); - unsigned int c = 0; - for(unsigned int i=0;i= ZT_PROTO_MAX_PACKET_LENGTH) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD + 8,(uint16_t)c); - RR->sw->send(outp,true); - outp = Packet(Address(dest),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REFRESH); - outp.append(nwid); - outp.addSize(2); - c = 0; - } - Address(blacklistAddresses[i]).appendTo(outp); - outp.append(blacklistBeforeTimestamps[i]); - ++c; - } - if (c > 0) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD + 8,(uint16_t)c); - RR->sw->send(outp,true); - } -} - ZT_ResultCode Node::clusterInit( unsigned int myId, const struct sockaddr_storage *zeroTierPhysicalEndpoints, @@ -973,13 +948,6 @@ void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) } catch ( ... ) {} } -void ZT_Node_pushNetworkRefresh(ZT_Node *node,uint64_t dest,uint64_t nwid,const uint64_t *blacklistAddresses,const uint64_t *blacklistBeforeTimestamps,unsigned int blacklistCount) -{ - try { - reinterpret_cast(node)->pushNetworkRefresh(dest,nwid,blacklistAddresses,blacklistBeforeTimestamps,blacklistCount); - } catch ( ... ) {} -} - enum ZT_ResultCode ZT_Node_clusterInit( ZT_Node *node, unsigned int myId, diff --git a/node/Node.hpp b/node/Node.hpp index 56869816..11462531 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -107,7 +107,6 @@ public: void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); void circuitTestEnd(ZT_CircuitTest *test); - void pushNetworkRefresh(uint64_t dest,uint64_t nwid,const uint64_t *blacklistAddresses,const uint64_t *blacklistBeforeTimestamps,unsigned int blacklistCount); ZT_ResultCode clusterInit( unsigned int myId, const struct sockaddr_storage *zeroTierPhysicalEndpoints, diff --git a/node/Packet.hpp b/node/Packet.hpp index e76cb96c..b03ec327 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -670,9 +670,11 @@ public: * 0x6 - WATCHed inbound frame * 0x7 - (reserved for future use) * - * 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. + * An extended frame carries full MAC addressing, making it a + * superset of VERB_FRAME. It is used for bridged traffic, + * redirected or observed traffic via rules, and can in theory + * be used for multicast though MULTICAST_FRAME exists for that + * purpose and has additional options and capabilities. * * OK payload (if ACK flag is set): * <[8] 64-bit network ID> @@ -725,6 +727,9 @@ public: * These will of course only be accepted if they are properly signed. * Credentials can be for any number of networks. * + * The use of a zero byte to terminate the COM section is for legacy + * backward compatiblity. Newer fields are prefixed with a length. + * * OK/ERROR are not generated. */ VERB_NETWORK_CREDENTIALS = 0x0a, -- cgit v1.2.3 From 15c07c58b610f699fd2a7164fde96712e1595f2b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Sep 2016 11:33:48 -0700 Subject: Refactored network config chunking to sign every chunk to prevent stupid DOS attack potential, and implement network config fast propagate (though we probably will not use this for a bit). --- node/Dictionary.hpp | 42 +----------- node/IncomingPacket.cpp | 54 +++++++++------- node/Network.cpp | 167 ++++++++++++++++++++++++++++++++++-------------- node/Network.hpp | 40 +++++++----- node/Packet.hpp | 49 ++++++++++---- 5 files changed, 214 insertions(+), 138 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index eab2b162..15ab9ce3 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -23,7 +23,6 @@ #include "Utils.hpp" #include "Buffer.hpp" #include "Address.hpp" -#include "C25519.hpp" #include @@ -444,49 +443,14 @@ public: return found; } - /** - * Sign this Dictionary, replacing any previous signature - * - * @param sigKey Key to use for signature in dictionary - * @param kp Key pair to sign with - */ - inline void wrapWithSignature(const char *sigKey,const C25519::Pair &kp) - { - this->erase(sigKey); - C25519::Signature sig(C25519::sign(kp,this->data(),this->sizeBytes())); - this->add(sigKey,reinterpret_cast(sig.data),ZT_C25519_SIGNATURE_LEN); - } - - /** - * Verify signature (and erase signature key) - * - * This erases this Dictionary's signature key (if present) and verifies - * the signature. The key is erased to render the Dictionary into the - * original unsigned form it was signed in for verification purposes. - * - * @param sigKey Key to use for signature in dictionary - * @param pk Public key to check against - * @return True if signature was present and valid - */ - inline bool unwrapAndVerify(const char *sigKey,const C25519::Public &pk) - { - char sig[ZT_C25519_SIGNATURE_LEN+1]; - if (this->get(sigKey,sig,sizeof(sig)) != ZT_C25519_SIGNATURE_LEN) - return false; - this->erase(sigKey); - return C25519::verify(pk,this->data(),this->sizeBytes(),sig); - } - - /** - * @return Dictionary data as a 0-terminated C-string - */ - inline const char *data() const { return _d; } - /** * @return Value of C template parameter */ inline unsigned int capacity() const { return C; } + inline const char *data() const { return _d; } + inline char *unsafeData() { return _d; } + private: char _d[C]; }; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 72dfbfd8..3988546e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -433,21 +433,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { - const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->controller() == peer->address())) { - trustEstablished = true; - const unsigned int chunkLen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); - const void *chunkData = field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,chunkLen); - unsigned int chunkIndex = 0; - unsigned int totalSize = chunkLen; - if ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen) < size()) { - totalSize = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen); - chunkIndex = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4); - } - TRACE("%s(%s): OK(NETWORK_CONFIG_REQUEST) chunkLen==%u chunkIndex==%u totalSize==%u",source().toString().c_str(),_path->address().toString().c_str(),chunkLen,chunkIndex,totalSize); - network->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize); - } + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); + if (network) + network->handleConfigChunk(*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; //case Packet::VERB_ECHO: { @@ -894,20 +882,31 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons Dictionary *dconf = new Dictionary(); try { if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { - dconf->wrapWithSignature(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE,RR->identity.privateKeyPair()); - + uint64_t configUpdateId = RR->node->prng(); + if (!configUpdateId) ++configUpdateId; const unsigned int totalSize = dconf->sizeBytes(); unsigned int chunkIndex = 0; while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 32))); + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256))); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append(requestPacketId); + + const unsigned int sigStart = outp.size(); outp.append(nwid); outp.append((uint16_t)chunkLen); outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); + + outp.append((uint8_t)0); // no flags + outp.append((uint64_t)configUpdateId); outp.append((uint32_t)totalSize); outp.append((uint32_t)chunkIndex); + + C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart)); + outp.append((uint8_t)1); + outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN); + outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); + outp.compress(); RR->sw->send(outp,true); chunkIndex += chunkLen; @@ -977,12 +976,21 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const uint64_t nwid = at(ZT_PACKET_IDX_PAYLOAD); - bool trustEstablished = false; - - + const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); + if (network) { + const uint64_t configUpdateId = network->handleConfigChunk(*this,ZT_PACKET_IDX_PAYLOAD); + if (configUpdateId) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((uint8_t)Packet::VERB_ECHO); + outp.append((uint64_t)packetId()); + outp.append((uint64_t)network->id()); + outp.append((uint64_t)configUpdateId); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + } + } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,trustEstablished); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Network.cpp b/node/Network.cpp index 487766a7..e24e3e16 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -569,12 +569,14 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : _lastAnnouncedMulticastGroupsUpstream(0), _mac(renv->identity.address(),nwid), _portInitialized(false), - _inboundConfigPacketId(0), _lastConfigUpdate(0), _destroyed(false), _netconfFailure(NETCONF_FAILURE_NONE), _portError(0) { + for(int i=0;i::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c) - totalWeHave += (unsigned int)c->second.length(); - - if (totalWeHave == totalSize) { - TRACE("have all chunks for network config request %.16llx, assembling...",inRePacketId); - for(std::map::iterator c(_inboundConfigChunks.begin());c!=_inboundConfigChunks.end();++c) - newConfig.append(c->second); - _inboundConfigPacketId = 0; - _inboundConfigChunks.clear(); - } else if (totalWeHave > totalSize) { - _inboundConfigPacketId = 0; - _inboundConfigChunks.clear(); + const unsigned int start = ptr; + + ptr += 8; // skip network ID, which is already obviously known + const uint16_t chunkLen = chunk.at(ptr); ptr += 2; + const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen; + + Mutex::Lock _l(_lock); + + _IncomingConfigChunk *c = (_IncomingConfigChunk *)0; + uint64_t chunkId = 0; + uint64_t configUpdateId; + unsigned long totalLength,chunkIndex; + if (ptr < chunk.size()) { + const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); + configUpdateId = chunk.at(ptr); ptr += 8; + totalLength = chunk.at(ptr); ptr += 4; + chunkIndex = chunk.at(ptr); ptr += 4; + + if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end + TRACE("discarded chunk from %s: invalid length or length overflow",chunk.source().toString().c_str()); + return 0; + } + + if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) { + TRACE("discarded chunk from %s: unrecognized signature type",chunk.source().toString().c_str()); + return 0; + } + const uint8_t *sig = reinterpret_cast(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN)); + + // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use + for(unsigned int i=0;i<16;++i) + reinterpret_cast(&chunkId)[i & 7] ^= sig[i]; + + // Find existing or new slot for this update and check if this is a duplicate chunk + for(int i=0;ihaveChunks;++j) { + if (c->haveChunkIds[j] == chunkId) + return 0; + } + + break; + } else if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) { + c = &(_incomingConfigChunks[i]); + } + } + + // If it's not a duplicate, check chunk signature + const Identity controllerId(RR->topology->getIdentity(controller())); + if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? + TRACE("unable to verify chunk from %s: don't have controller identity",chunk.source().toString().c_str()); + return 0; + } + if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) { + TRACE("discarded chunk from %s: signature check failed",chunk.source().toString().c_str()); + return 0; + } + + // New properly verified chunks can be flooded "virally" through the network + if (fastPropagate) { + Address *a = (Address *)0; + Membership *m = (Membership *)0; + Hashtable::Iterator i(_memberships); + while (i.next(a,m)) { + if ((*a != chunk.source())&&(*a != controller())) { + Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG); + outp.append(reinterpret_cast(chunk.data()) + start,chunk.size() - start); + RR->sw->send(outp,true); + } + } + } + } else if (chunk.source() == controller()) { + // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers + chunkId = chunk.packetId(); + configUpdateId = chunkId; + totalLength = chunkLen; + chunkIndex = 0; + + if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY) + return 0; + + // Find oldest slot for this udpate to use buffer space + for(int i=0;its)) + c = &(_incomingConfigChunks[i]); } } else { - return; + TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); + return 0; + } + + ++c->ts; // newer is higher, that's all we need + + if (c->updateId != configUpdateId) { + c->updateId = configUpdateId; + for(int i=0;ihaveChunkIds[i] = 0; + c->haveChunks = 0; + c->haveBytes = 0; } + if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS) + return false; + c->haveChunkIds[c->haveChunks++] = chunkId; + + memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen); + c->haveBytes += chunkLen; - if ((newConfig.length() > 0)&&(newConfig.length() < ZT_NETWORKCONFIG_DICT_CAPACITY)) { - Dictionary *dict = new Dictionary(newConfig.c_str()); - NetworkConfig *nc = new NetworkConfig(); + if (c->haveBytes == totalLength) { + c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated + + NetworkConfig *const nc = new NetworkConfig(); try { - Identity controllerId(RR->topology->getIdentity(this->controller())); - if (controllerId) { - if (nc->fromDictionary(*dict)) { - Mutex::Lock _l(_lock); - this->_setConfiguration(*nc,true); - } else { - TRACE("error parsing new config with length %u: deserialization of NetworkConfig failed (certificate error?)",(unsigned int)newConfig.length()); - } + if (nc->fromDictionary(c->data)) { + this->_setConfiguration(*nc,true); + return configUpdateId; } delete nc; - delete dict; } catch ( ... ) { - TRACE("error parsing new config with length %u: unexpected exception",(unsigned int)newConfig.length()); delete nc; - delete dict; - throw; } } + + return 0; } void Network::requestConfiguration() @@ -980,10 +1061,7 @@ void Network::requestConfiguration() } else { outp.append((unsigned char)0,16); } - - RR->node->expectReplyTo(_inboundConfigPacketId = outp.packetId()); - _inboundConfigChunks.clear(); - + RR->node->expectReplyTo(outp.packetId()); outp.compress(); RR->sw->send(outp,true); } @@ -1127,13 +1205,6 @@ Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,c const Membership::AddCredentialResult result = m.addCredential(RR,_config,rev); if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { - /* Fast propagation is done by using a very aggressive rumor mill - * propagation algorithm. When we see a Revocation that we haven't - * seen before we blast it to every known member. This leads to - * a huge number of redundant messages, but eventually everybody - * will get it. This helps revocation speed and also helps in cases - * where the controller is under attack. It need only get one - * revocation out and the rest is history. */ Address *a = (Address *)0; Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); diff --git a/node/Network.hpp b/node/Network.hpp index 6a1ac801..128c4668 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -44,6 +44,9 @@ #include "NetworkConfig.hpp" #include "CertificateOfMembership.hpp" +#define ZT_NETWORK_MAX_INCOMING_UPDATES 3 +#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1) + namespace ZeroTier { class RuntimeEnvironment; @@ -174,16 +177,15 @@ public: /** * Handle an inbound network config chunk * - * This is called from IncomingPacket when we receive a chunk from a network - * controller. + * This is called from IncomingPacket to handle incoming network config + * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies + * each chunk and once assembled applies the configuration. * - * @param requestId An ID for grouping chunks, e.g. in-re packet ID for OK(NETWORK_CONFIG_REQUEST) - * @param data Chunk data - * @param chunkSize Size of data[] - * @param chunkIndex Index of chunk in full config - * @param totalSize Total size of network config + * @param chunk Packet containing chunk + * @param ptr Index of chunk and related fields in packet + * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - void handleInboundConfigChunk(const uint64_t requestId,const void *data,unsigned int chunkSize,unsigned int chunkIndex,unsigned int totalSize); + uint64_t handleConfigChunk(const Packet &chunk,unsigned int ptr); /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this @@ -353,19 +355,27 @@ private: const uint64_t _id; uint64_t _lastAnnouncedMulticastGroupsUpstream; MAC _mac; // local MAC address - volatile bool _portInitialized; + bool _portInitialized; std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap) Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) - uint64_t _inboundConfigPacketId; - std::map _inboundConfigChunks; - NetworkConfig _config; - volatile uint64_t _lastConfigUpdate; + uint64_t _lastConfigUpdate; + + struct _IncomingConfigChunk + { + uint64_t ts; + uint64_t updateId; + uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; + unsigned long haveChunks; + unsigned long haveBytes; + Dictionary data; + }; + _IncomingConfigChunk _incomingConfigChunks[ZT_NETWORK_MAX_INCOMING_UPDATES]; - volatile bool _destroyed; + bool _destroyed; enum { NETCONF_FAILURE_NONE, @@ -373,7 +383,7 @@ private: NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED } _netconfFailure; - volatile int _portError; // return value from port config callback + int _portError; // return value from port config callback Hashtable _memberships; diff --git a/node/Packet.hpp b/node/Packet.hpp index b03ec327..23597f68 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -755,8 +755,26 @@ public: * <[8] 64-bit network ID> * <[2] 16-bit length of network configuration dictionary chunk> * <[...] network configuration dictionary (may be incomplete)> + * [ ... end of legacy single chunk response ... ] + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk in this reply> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit chunk signature type> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> + * + * The chunk signature signs the entire payload of the OK response. + * Currently only one signature type is supported: ed25519 (1). + * + * Each config chunk is signed to prevent memory exhaustion or + * traffic crowding DOS attacks against config fragment assembly. + * + * If the packet is from the network controller it is permitted to end + * before the config update ID or other chunking related or signature + * fields. This is to support older controllers that don't include + * these fields and may be removed in the future. * * ERROR response payload: * <[8] 64-bit network ID> @@ -766,25 +784,30 @@ public: /** * Network configuration data push: * <[8] 64-bit network ID> - * <[8] 64-bit config update ID (token to identify this update)> - * <[1] flags> * <[2] 16-bit length of network configuration dictionary chunk> * <[...] network configuration dictionary (may be incomplete)> + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk in this reply> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit chunk signature type> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> * * This is a direct push variant for network config updates. It otherwise - * carries the same payload as OK(NETWORK_CONFIG_REQUEST). There is an - * extra number after network ID in this version that is used in place of - * the in-re packet ID sent with OKs to group chunks together. - * - * Unlike OK(NETWORK_CONFIG_REQUEST) this can be sent by peers other than - * network controllers. In that case the certificate inside the Dictionary - * is used for verification purposes. + * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same + * semantics. * * Flags: - * 0x01 - Patch, not whole config - * 0x02 - Use fast P2P propagation + * 0x01 - Use fast propagation + * + * An OK should be sent if the config is successfully received and + * accepted. + * + * OK payload: + * <[8] 64-bit network ID> + * <[8] 64-bit config update ID> */ VERB_NETWORK_CONFIG = 0x0c, -- cgit v1.2.3 From cc4bacc1995d5af6b8ab66973a6d22a229367eb4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Sep 2016 12:22:25 -0700 Subject: Cleanup, and implement compression disable flag for networks. --- node/IncomingPacket.cpp | 7 ++----- node/Multicaster.cpp | 3 +++ node/Multicaster.hpp | 2 ++ node/Network.cpp | 1 - node/NetworkConfig.hpp | 10 ++++++++++ node/OutboundMulticast.cpp | 4 +++- node/OutboundMulticast.hpp | 2 ++ node/Packet.hpp | 3 +++ node/Switch.cpp | 10 +++++++--- 9 files changed, 32 insertions(+), 10 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3988546e..0a3d58af 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -425,12 +425,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; - case Packet::VERB_WHOIS: { + case Packet::VERB_WHOIS: if (RR->topology->isUpstream(peer->identity())) { const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR,RR->identity,id)))); } - } break; + break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); @@ -438,9 +438,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->handleConfigChunk(*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; - //case Packet::VERB_ECHO: { - //} break; - case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index fc8fa1bd..8743e8f8 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -155,6 +155,7 @@ void Multicaster::send( unsigned int limit, uint64_t now, uint64_t nwid, + bool disableCompression, const std::vector

&alwaysSendTo, const MulticastGroup &mg, const MAC &src, @@ -193,6 +194,7 @@ void Multicaster::send( RR, now, nwid, + disableCompression, limit, 1, // we'll still gather a little from peers to keep multicast list fresh src, @@ -265,6 +267,7 @@ void Multicaster::send( RR, now, nwid, + disableCompression, limit, gatherLimit, src, diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 8be3b736..5c94cd3a 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -153,6 +153,7 @@ public: * @param limit Multicast limit * @param now Current time * @param nwid Network ID + * @param disableCompression Disable packet payload compression? * @param alwaysSendTo Send to these peers first and even if not included in subscriber list * @param mg Multicast group * @param src Source Ethernet MAC address or NULL to skip in packet and compute from ZT address (non-bridged mode) @@ -164,6 +165,7 @@ public: unsigned int limit, uint64_t now, uint64_t nwid, + bool disableCompression, const std::vector
&alwaysSendTo, const MulticastGroup &mg, const MAC &src, diff --git a/node/Network.cpp b/node/Network.cpp index e24e3e16..601395d0 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -962,7 +962,6 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY) return 0; - // Find oldest slot for this udpate to use buffer space for(int i=0;its)) c = &(_incomingConfigChunks[i]); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 5ad86855..a548e866 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -76,6 +76,11 @@ */ #define ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH 0x0000000000000008ULL +/** + * Flag: disable frame compression + */ +#define ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION 0x0000000000000010ULL + /** * Device is an active bridge */ @@ -255,6 +260,11 @@ public: */ inline bool ndpEmulation() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } + /** + * @return True if frames should not be compressed + */ + inline bool disableCompression() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); } + /** * @return Network type is public (no access control) */ diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 6e811581..2f6bf986 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -31,6 +31,7 @@ void OutboundMulticast::init( const RuntimeEnvironment *RR, uint64_t timestamp, uint64_t nwid, + bool disableCompression, unsigned int limit, unsigned int gatherLimit, const MAC &src, @@ -78,7 +79,8 @@ void OutboundMulticast::init( _packet.append((uint32_t)dest.adi()); _packet.append((uint16_t)etherType); _packet.append(payload,_frameLen); - _packet.compress(); + if (!disableCompression) + _packet.compress(); memcpy(_frameData,payload,_frameLen); } diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 0ded8baf..6370d0d7 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -56,6 +56,7 @@ public: * @param RR Runtime environment * @param timestamp Creation time * @param nwid Network ID + * @param disableCompression Disable compression of frame payload * @param limit Multicast limit for desired number of packets to send * @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none * @param src Source MAC address of frame or NULL to imply compute from sender ZT address @@ -69,6 +70,7 @@ public: const RuntimeEnvironment *RR, uint64_t timestamp, uint64_t nwid, + bool disableCompression, unsigned int limit, unsigned int gatherLimit, const MAC &src, diff --git a/node/Packet.hpp b/node/Packet.hpp index 23597f68..cc3d323b 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -799,6 +799,9 @@ public: * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same * semantics. * + * The legacy mode missing the additional chunking fields is not supported + * here. + * * Flags: * 0x01 - Use fast propagation * diff --git a/node/Switch.cpp b/node/Switch.cpp index e3d57835..6611d6b6 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -476,6 +476,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c network->config().multicastLimit, RR->node->now(), network->id(), + network->config().disableCompression(), network->config().activeBridges(), multicastGroup, (fromBridged) ? from : MAC(), @@ -501,14 +502,16 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c from.appendTo(outp); outp.append((uint16_t)etherType); outp.append(data,len); - outp.compress(); + if (!network->config().disableCompression()) + outp.compress(); send(outp,true); } else { Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); outp.append((uint16_t)etherType); outp.append(data,len); - outp.compress(); + if (!network->config().disableCompression()) + outp.compress(); send(outp,true); } @@ -565,7 +568,8 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c from.appendTo(outp); outp.append((uint16_t)etherType); outp.append(data,len); - outp.compress(); + if (!network->config().disableCompression()) + outp.compress(); send(outp,true); } else { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); -- cgit v1.2.3 From 9f550292fe0ebc32e61eeada9e3a69970c874724 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Sep 2016 13:49:43 -0700 Subject: Simply network auth logic and always sent error on auth failure even for unknown networks to prevent forensics. --- node/IncomingPacket.cpp | 61 ++++++++++++++++++++++++++++++------------------- node/IncomingPacket.hpp | 2 ++ node/Network.cpp | 21 +++-------------- node/Network.hpp | 15 +----------- node/Node.hpp | 8 ++++--- node/Peer.cpp | 1 + node/Peer.hpp | 17 ++++++++++++-- 7 files changed, 64 insertions(+), 61 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0a3d58af..f54752d1 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -169,7 +169,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Peers can send this in response to frames if they do not have a recent enough COM from us const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); - if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) + if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(peer->address(),now); } break; @@ -184,7 +184,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->gate(peer,verb(),packetId()))) { + if ((network)&&(network->gate(peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); @@ -375,7 +375,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - bool trustEstablished = false; if (!RR->node->expectingReplyTo(inRePacketId)) { TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); @@ -441,8 +440,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { - trustEstablished = true; + if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -468,15 +466,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->addCredential(com); } - if (network->gateMulticastGatherReply(peer,verb(),packetId())) { - trustEstablished = true; - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); - } + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); offset += 4; + unsigned int count = at(offset); offset += 2; + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -484,7 +479,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,trustEstablished); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -581,9 +576,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const SharedPtr network(RR->node->network(nwid)); bool trustEstablished = false; if (network) { - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - } else { + if (network->gate(peer)) { trustEstablished = true; if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); @@ -593,9 +586,13 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } + } else { + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + _sendErrorNeedCredentials(RR,peer,nwid); } peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { @@ -620,8 +617,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

addCredential(com); } - if (!network->gate(peer,verb(),packetId())) { + if (!network->gate(peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -681,6 +679,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { @@ -737,7 +736,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (!auth) { if ((!network)||(network->id() != nwid)) network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(peer,verb(),packetId()))); + const bool authOnNet = ((network)&&(network->gate(peer))); trustEstablished |= authOnNet; if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; @@ -986,7 +985,6 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1020,7 +1018,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar } } - const bool trustEstablished = ((network)&&(network->gate(peer,verb(),packetId()))); + const bool trustEstablished = ((network)&&(network->gate(peer))); if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); @@ -1067,8 +1065,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->addCredential(com); } - if (!network->gate(peer,verb(),packetId())) { + if (!network->gate(peer)) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -1143,6 +1142,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { @@ -1288,7 +1288,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } - if (network->gate(peer,verb(),packetId())) + if (network->gate(peer)) reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); @@ -1479,6 +1479,19 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const return true; } +void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) +{ + if (peer->rateGateOutgoingComRequest(RR->node->now())) { + Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)verb()); + outp.append(packetId()); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(nwid); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + } +} + 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 diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 86c2b5e7..c3632216 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -154,6 +154,8 @@ private: bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer); + void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); + uint64_t _receiveTime; SharedPtr _path; }; diff --git a/node/Network.cpp b/node/Network.cpp index 601395d0..52abbcf9 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -50,6 +50,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP"; case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT"; case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE"; + case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH"; case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT"; case ZT_NETWORK_RULE_ACTION_DEBUG_LOG: return "ACTION_DEBUG_LOG"; case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS"; @@ -882,7 +883,7 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) const unsigned int start = ptr; ptr += 8; // skip network ID, which is already obviously known - const uint16_t chunkLen = chunk.at(ptr); ptr += 2; + const unsigned int chunkLen = chunk.at(ptr); ptr += 2; const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen; Mutex::Lock _l(_lock); @@ -975,8 +976,6 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) if (c->updateId != configUpdateId) { c->updateId = configUpdateId; - for(int i=0;ihaveChunkIds[i] = 0; c->haveChunks = 0; c->haveBytes = 0; } @@ -1065,7 +1064,7 @@ void Network::requestConfiguration() RR->sw->send(outp,true); } -bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +bool Network::gate(const SharedPtr &peer) { const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -1081,15 +1080,6 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin m->likingMulticasts(now); } return true; - } else { - if (peer->rateGateRequestCredentials(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb); - outp.append(packetId); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(_id); - RR->sw->send(outp,true); - } } } } catch ( ... ) { @@ -1098,11 +1088,6 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } -bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) -{ - return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); -} - void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index 128c4668..527d3048 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -212,21 +212,8 @@ public: /** * Determine whether this peer is permitted to communicate on this network - * - * This also performs certain periodic actions such as pushing renewed - * credentials to peers, so like the filters it is not side-effect-free. - * - * @param peer Peer to check - * @param verb Packet verb - * @param packetId Packet ID - * @return True if peer is allowed to communicate on this network - */ - bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); - - /** - * Check whether this peer is allowed to provide multicast info for this network */ - bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + bool gate(const SharedPtr &peer); /** * Do periodic cleanup and housekeeping tasks diff --git a/node/Node.hpp b/node/Node.hpp index 11462531..ddc52651 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -267,17 +267,19 @@ public: } /** - * Check whether a given packet ID is something we are expecting a reply to + * Check whether a given packet ID is something we are expecting a reply to (and erase from list) * * @param packetId Packet ID to check * @return True if we're expecting a reply */ - inline bool expectingReplyTo(const uint64_t packetId) const + inline bool expectingReplyTo(const uint64_t packetId) { const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == packetId) + if (_expectingRepliesTo[bucket][i] == packetId) { + _expectingRepliesTo[bucket][i] = 0; return true; + } } return false; } diff --git a/node/Peer.cpp b/node/Peer.cpp index d742964a..87882dad 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -50,6 +50,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), _lastComRequestReceived(0), + _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), RR(renv), diff --git a/node/Peer.hpp b/node/Peer.hpp index c5ef43ed..d0589ccf 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -395,9 +395,9 @@ public: } /** - * Rate gate requests for network COM + * Rate gate incoming requests for network COM */ - inline bool rateGateComRequest(const uint64_t now) + inline bool rateGateIncomingComRequest(const uint64_t now) { if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestReceived = now; @@ -406,6 +406,18 @@ public: return false; } + /** + * Rate gate outgoing requests for network COM + */ + inline bool rateGateOutgoingComRequest(const uint64_t now) + { + if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastComRequestSent = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -465,6 +477,7 @@ private: uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; + uint64_t _lastComRequestSent; uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; const RuntimeEnvironment *RR; -- cgit v1.2.3 From 0b44919ba23021231dd561f530c5d30836846735 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Sep 2016 16:33:37 -0700 Subject: Clusters can send multiple OKs so we must allow this. --- node/IncomingPacket.cpp | 5 +++-- node/Node.hpp | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f54752d1..b77ead4c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1481,14 +1481,15 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) { - if (peer->rateGateOutgoingComRequest(RR->node->now())) { + const uint64_t now = RR->node->now(); + if (peer->rateGateOutgoingComRequest(now)) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)verb()); outp.append(packetId()); outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,outp.data(),outp.size(),now); } } diff --git a/node/Node.hpp b/node/Node.hpp index ddc52651..11462531 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -267,19 +267,17 @@ public: } /** - * Check whether a given packet ID is something we are expecting a reply to (and erase from list) + * Check whether a given packet ID is something we are expecting a reply to * * @param packetId Packet ID to check * @return True if we're expecting a reply */ - inline bool expectingReplyTo(const uint64_t packetId) + inline bool expectingReplyTo(const uint64_t packetId) const { const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == packetId) { - _expectingRepliesTo[bucket][i] = 0; + if (_expectingRepliesTo[bucket][i] == packetId) return true; - } } return false; } -- cgit v1.2.3 From 5ee1ccd65987353dd461f8ea27203da63c0b2cd8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Sep 2016 16:41:08 -0700 Subject: Send need credential error on more cases. --- node/IncomingPacket.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b77ead4c..dd95f8c8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -737,6 +737,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if ((!network)||(network->id() != nwid)) network = RR->node->network(nwid); const bool authOnNet = ((network)&&(network->gate(peer))); + if (!authOnNet) + _sendErrorNeedCredentials(RR,peer,nwid); trustEstablished |= authOnNet; if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; @@ -1019,6 +1021,8 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar } const bool trustEstablished = ((network)&&(network->gate(peer))); + if (!trustEstablished) + _sendErrorNeedCredentials(RR,peer,nwid); if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); -- cgit v1.2.3 From 7e90ab3534e414ef9dde93ec5a74ee2717092fb8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 28 Sep 2016 11:06:44 -0700 Subject: TRACE verbosity increase on exceptions in NETWORK_CREDENTIALS. --- node/IncomingPacket.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index dd95f8c8..e0fa3bf1 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -852,6 +852,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); + } catch (std::exception &exc) { + TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } -- cgit v1.2.3 From 93b4ac5cb28408d4bcb63433d9f93a6efe188319 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 13 Oct 2016 13:17:30 -0700 Subject: Remove unused POW code, will revisit later. --- node/IncomingPacket.cpp | 143 ------------------------------------------------ node/IncomingPacket.hpp | 22 -------- node/Packet.cpp | 1 - node/Packet.hpp | 45 --------------- 4 files changed, 211 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e0fa3bf1..5afacd0e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -106,7 +106,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); - case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer); case Packet::VERB_USER_MESSAGE: return true; } @@ -1421,70 +1420,6 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S return true; } -bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer) -{ - 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->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) { - if (peer->address() == (*n)->controller()) { - allowed = true; - break; - } - } - } - - if (allowed) { - const uint64_t pid = packetId(); - const unsigned int difficulty = (*this)[ZT_PACKET_IDX_PAYLOAD + 1]; - const unsigned int challengeLength = at(ZT_PACKET_IDX_PAYLOAD + 2); - if (challengeLength > ZT_PROTO_MAX_PACKET_LENGTH) - return true; // sanity check, drop invalid size - const unsigned char *challenge = field(ZT_PACKET_IDX_PAYLOAD + 4,challengeLength); - - switch((*this)[ZT_PACKET_IDX_PAYLOAD]) { - - // Salsa20/12+SHA512 hashcash - case 0x01: { - if (difficulty <= 14) { - unsigned char result[16]; - computeSalsa2012Sha512ProofOfWork(difficulty,challenge,challengeLength,result); - TRACE("PROOF_OF_WORK computed for %s: difficulty==%u, challengeLength==%u, result: %.16llx%.16llx",peer->address().toString().c_str(),difficulty,challengeLength,Utils::ntoh(*(reinterpret_cast(result))),Utils::ntoh(*(reinterpret_cast(result + 8)))); - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); - outp.append(pid); - outp.append((uint16_t)sizeof(result)); - outp.append(result,sizeof(result)); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); - } else { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); - outp.append(pid); - outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); - } - } break; - - default: - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_path->address().toString().c_str()); - break; - } - - peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); - } else { - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - } catch ( ... ) { - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) { const uint64_t now = RR->node->now(); @@ -1499,82 +1434,4 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,cons } } -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 - char candidatebuf[ZT_PROTO_MAX_PACKET_LENGTH + 256]; - unsigned char shabuf[ZT_SHA512_DIGEST_LEN]; - const uint64_t s20iv = 0; // zero IV for Salsa20 - char *const candidate = (char *)(( ((uintptr_t)&(candidatebuf[0])) | 0xf ) + 1); // align to 16-byte boundary to ensure that uint64_t type punning of initial nonce is okay - Salsa20 s20; - unsigned int d; - unsigned char *p; - - Utils::getSecureRandom(candidate,16); - memcpy(candidate + 16,challenge,challengeLength); - - if (difficulty > 512) - difficulty = 512; // sanity check - -try_salsa2012sha512_again: - ++*(reinterpret_cast(candidate)); - - SHA512::hash(shabuf,candidate,16 + challengeLength); - s20.init(shabuf,256,&s20iv); - memset(salsabuf,0,sizeof(salsabuf)); - s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf)); - SHA512::hash(shabuf,salsabuf,sizeof(salsabuf)); - - d = difficulty; - p = shabuf; - while (d >= 8) { - if (*(p++)) - goto try_salsa2012sha512_again; - d -= 8; - } - if (d > 0) { - if ( ((((unsigned int)*p) << d) & 0xff00) != 0 ) - goto try_salsa2012sha512_again; - } - - memcpy(result,candidate,16); -} - -bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficulty,const void *challenge,unsigned int challengeLength,const unsigned char proposedResult[16]) -{ - unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function - char candidate[ZT_PROTO_MAX_PACKET_LENGTH + 256]; - unsigned char shabuf[ZT_SHA512_DIGEST_LEN]; - const uint64_t s20iv = 0; // zero IV for Salsa20 - Salsa20 s20; - unsigned int d; - unsigned char *p; - - if (difficulty > 512) - difficulty = 512; // sanity check - - memcpy(candidate,proposedResult,16); - memcpy(candidate + 16,challenge,challengeLength); - - SHA512::hash(shabuf,candidate,16 + challengeLength); - s20.init(shabuf,256,&s20iv); - memset(salsabuf,0,sizeof(salsabuf)); - s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf)); - SHA512::hash(shabuf,salsabuf,sizeof(salsabuf)); - - d = difficulty; - p = shabuf; - while (d >= 8) { - if (*(p++)) - return false; - d -= 8; - } - if (d > 0) { - if ( ((((unsigned int)*p) << d) & 0xff00) != 0 ) - return false; - } - - return true; -} - } // namespace ZeroTier diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index c3632216..80244ea4 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -111,27 +111,6 @@ public: */ inline uint64_t receiveTime() const throw() { return _receiveTime; } - /** - * Compute the Salsa20/12+SHA512 proof of work function - * - * @param difficulty Difficulty in bits (max: 64) - * @param challenge Challenge string - * @param challengeLength Length of challenge in bytes (max allowed: ZT_PROTO_MAX_PACKET_LENGTH) - * @param result Buffer to fill with 16-byte result - */ - static void computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16]); - - /** - * Verify the result of Salsa20/12+SHA512 proof of work - * - * @param difficulty Difficulty in bits (max: 64) - * @param challenge Challenge bytes - * @param challengeLength Length of challenge in bytes (max allowed: ZT_PROTO_MAX_PACKET_LENGTH) - * @param proposedResult Result supplied by client - * @return True if result is valid - */ - static bool testSalsa2012Sha512ProofOfWorkResult(unsigned int difficulty,const void *challenge,unsigned int challengeLength,const unsigned char proposedResult[16]); - private: // These are called internally to handle packet contents once it has // been authenticated, decrypted, decompressed, and classified. @@ -152,7 +131,6 @@ private: bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); 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); void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); diff --git a/node/Packet.cpp b/node/Packet.cpp index 3b8e1387..20b80962 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -46,7 +46,6 @@ const char *Packet::verbString(Verb v) case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST"; case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT"; - case VERB_REQUEST_PROOF_OF_WORK: return "REQUEST_PROOF_OF_WORK"; case VERB_USER_MESSAGE: return "USER_MESSAGE"; } return "(unknown)"; diff --git a/node/Packet.hpp b/node/Packet.hpp index cc3d323b..a8738884 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -891,8 +891,6 @@ public: */ VERB_MULTICAST_FRAME = 0x0e, - // 0x0f is reserved for an old deprecated message - /** * Push of potential endpoints for direct communication: * <[2] 16-bit number of paths> @@ -1044,49 +1042,6 @@ public: */ VERB_CIRCUIT_TEST_REPORT = 0x12, - /** - * Request proof of work: - * <[1] 8-bit proof of work type> - * <[1] 8-bit proof of work difficulty> - * <[2] 16-bit length of proof of work challenge> - * <[...] proof of work challenge> - * - * This requests that a peer perform a proof of work calucation. It can be - * sent by highly trusted peers (e.g. root servers, network controllers) - * under suspected denial of service conditions in an attempt to filter - * out "non-serious" peers and remain responsive to those proving their - * intent to actually communicate. - * - * If the peer obliges to perform the work, it does so and responds with - * an OK containing the result. Otherwise it may ignore the message or - * response with an ERROR_INVALID_REQUEST or ERROR_UNSUPPORTED_OPERATION. - * - * Proof of work type IDs: - * 0x01 - Salsa20/12+SHA512 hashcash function - * - * Salsa20/12+SHA512 is based on the following composite hash function: - * - * (1) Compute SHA512(candidate) - * (2) Use the first 256 bits of the result of #1 as a key to encrypt - * 131072 zero bytes with Salsa20/12 (with a zero IV). - * (3) Compute SHA512(the result of step #2) - * (4) Accept this candiate if the first [difficulty] bits of the result - * from step #3 are zero. Otherwise generate a new candidate and try - * again. - * - * This is performed repeatedly on candidates generated by appending the - * supplied challenge to an arbitrary nonce until a valid candidate - * is found. This chosen prepended nonce is then returned as the result - * in OK. - * - * OK payload: - * <[2] 16-bit length of result> - * <[...] computed proof of work> - * - * ERROR has no payload. - */ - VERB_REQUEST_PROOF_OF_WORK = 0x13, - /** * A message with arbitrary user-definable content: * <[8] 64-bit arbitrary message type ID> -- cgit v1.2.3 From 226123ca08ffbb5f4e4f0699b92fb9db08576a66 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 10 Nov 2016 11:54:47 -0800 Subject: Refactor controller to permit sending of pushes as well as just replies to config requests. --- controller/EmbeddedNetworkController.cpp | 77 +++++++++++++++-------- controller/EmbeddedNetworkController.hpp | 14 +++-- node/IncomingPacket.cpp | 84 +------------------------ node/Network.cpp | 105 +++++++++++++------------------ node/Network.hpp | 10 ++- node/NetworkController.hpp | 69 +++++++++++++------- node/Node.cpp | 85 +++++++++++++++++++++++++ node/Node.hpp | 8 ++- 8 files changed, 252 insertions(+), 200 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 624c3145..91b59215 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -470,11 +470,21 @@ EmbeddedNetworkController::~EmbeddedNetworkController() { } -NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary &metaData,NetworkConfig &nc) +void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender) { - if (((!signingId)||(!signingId.hasPrivate()))||(signingId.address().toInt() != (nwid >> 24))) { - return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR; - } + this->_sender = sender; + this->_signingId = signingId; +} + +void EmbeddedNetworkController::request( + uint64_t nwid, + const InetAddress &fromAddr, + uint64_t requestPacketId, + const Identity &identity, + const Dictionary &metaData) +{ + if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) + return; const uint64_t now = OSUtils::now(); @@ -483,7 +493,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( Mutex::Lock _l(_lastRequestTime_m); uint64_t &lrt = _lastRequestTime[std::pair(identity.address().toInt(),nwid)]; if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD) - return NetworkController::NETCONF_QUERY_IGNORE; + return; lrt = now; } @@ -496,8 +506,13 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( network = _db.get("network",nwids,0); member = _db.get("network",nwids,"member",identity.address().toString(),0); } - if (!network.size()) - return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND; + + if (!network.size()) { + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND); + return; + } + + json origMember(member); // for detecting modification later _initMember(member); { @@ -507,10 +522,13 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( // a "collision" from being able to auth onto our network in place of an already // known member. try { - if (Identity(haveIdStr.c_str()) != identity) - return NetworkController::NETCONF_QUERY_ACCESS_DENIED; + if (Identity(haveIdStr.c_str()) != identity) { + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); + return; + } } catch ( ... ) { - return NetworkController::NETCONF_QUERY_ACCESS_DENIED; + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); + return; } } else { // If we do not yet know this member's identity, learn it. @@ -521,7 +539,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( // These are always the same, but make sure they are set member["id"] = identity.address().toString(); member["address"] = member["id"]; - member["nwid"] = network["id"]; + member["nwid"] = nwids; // Determine whether and how member is authorized const char *authorizedBy = (const char *)0; @@ -597,7 +615,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } // Log this request - { + if (requestPacketId) { // only log if this is a request, not for generated pushes json rlEntry = json::object(); rlEntry["ts"] = now; rlEntry["authorized"] = (authorizedBy) ? true : false; @@ -620,22 +638,27 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } } member["recentLog"] = recentLog; - } - member["lastModified"] = now; - member["lastRequestMetaData"] = metaData.data(); + // Also only do this on real requests + member["lastRequestMetaData"] = metaData.data(); + } // If they are not authorized, STOP! if (!authorizedBy) { - Mutex::Lock _l(_db_m); - _db.put("network",nwids,"member",identity.address().toString(),member); - return NetworkController::NETCONF_QUERY_ACCESS_DENIED; + if (origMember != member) { + member["lastModified"] = now; + Mutex::Lock _l(_db_m); + _db.put("network",nwids,"member",identity.address().toString(),member); + } + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); + return; } // ------------------------------------------------------------------------- // If we made it this far, they are authorized. // ------------------------------------------------------------------------- + NetworkConfig nc; _NetworkMemberInfo nmi; _getNetworkMemberInfo(now,nwid,nmi); @@ -661,8 +684,9 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( Utils::scopy(nc.name,sizeof(nc.name),_jS(network["name"],"").c_str()); nc.multicastLimit = (unsigned int)_jI(network["multicastLimit"],32ULL); - for(std::set

::const_iterator ab(nmi.activeBridges.begin());ab!=nmi.activeBridges.end();++ab) + for(std::set
::const_iterator ab(nmi.activeBridges.begin());ab!=nmi.activeBridges.end();++ab) { nc.addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); + } json &v4AssignMode = network["v4AssignMode"]; json &v6AssignMode = network["v6AssignMode"]; @@ -714,7 +738,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } } nc.capabilities[nc.capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc); - if (nc.capabilities[nc.capabilityCount].sign(signingId,identity.address())) + if (nc.capabilities[nc.capabilityCount].sign(_signingId,identity.address())) ++nc.capabilityCount; if (nc.capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES) break; @@ -733,7 +757,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( if (nc.tagCount >= ZT_MAX_NETWORK_TAGS) break; nc.tags[nc.tagCount] = Tag(nwid,now,identity.address(),t->first,t->second); - if (nc.tags[nc.tagCount].sign(signingId)) + if (nc.tags[nc.tagCount].sign(_signingId)) ++nc.tagCount; } } @@ -923,17 +947,20 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); - if (com.sign(signingId)) { + if (com.sign(_signingId)) { nc.com = com; } else { - return NETCONF_QUERY_INTERNAL_SERVER_ERROR; + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR); + return; } - { + if (member != origMember) { + member["lastModified"] = now; Mutex::Lock _l(_db_m); _db.put("network",nwids,"member",identity.address().toString(),member); } - return NetworkController::NETCONF_QUERY_OK; + + _sender->ncSendConfig(nwid,requestPacketId,identity.address(),nc,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 53d3be0f..79b919b9 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -52,13 +52,14 @@ public: EmbeddedNetworkController(Node *node,const char *dbPath); virtual ~EmbeddedNetworkController(); - virtual NetworkController::ResultCode doNetworkConfigRequest( + virtual void init(const Identity &signingId,Sender *sender); + + virtual void request( + uint64_t nwid, const InetAddress &fromAddr, - const Identity &signingId, + uint64_t requestPacketId, const Identity &identity, - uint64_t nwid, - const Dictionary &metaData, - NetworkConfig &nc); + const Dictionary &metaData); unsigned int handleControlPlaneHttpGET( const std::vector &path, @@ -157,6 +158,9 @@ private: Node *const _node; std::string _path; + NetworkController::Sender *_sender; + Identity _signingId; + struct _CircuitTestEntry { ZT_CircuitTest *test; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5afacd0e..bde5df71 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -865,92 +865,12 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - bool trustEstablished = false; if (RR->localNetworkController) { const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); const Dictionary metaData(metaDataBytes,metaDataLength); - - NetworkConfig *netconf = new NetworkConfig(); - try { - switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) { - - case NetworkController::NETCONF_QUERY_OK: { - trustEstablished = true; - Dictionary *dconf = new Dictionary(); - try { - if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { - uint64_t configUpdateId = RR->node->prng(); - if (!configUpdateId) ++configUpdateId; - const unsigned int totalSize = dconf->sizeBytes(); - unsigned int chunkIndex = 0; - while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256))); - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - - const unsigned int sigStart = outp.size(); - outp.append(nwid); - outp.append((uint16_t)chunkLen); - outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); - - outp.append((uint8_t)0); // no flags - outp.append((uint64_t)configUpdateId); - outp.append((uint32_t)totalSize); - outp.append((uint32_t)chunkIndex); - - C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart)); - outp.append((uint8_t)1); - outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); - - outp.compress(); - RR->sw->send(outp,true); - chunkIndex += chunkLen; - } - } - delete dconf; - } catch ( ... ) { - delete dconf; - throw; - } - } break; - - case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); - outp.append(nwid); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); - } break; - - case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); - outp.append(nwid); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); - } break; - - case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: - break; - case NetworkController::NETCONF_QUERY_IGNORE: - break; - default: - TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()"); - break; - } - delete netconf; - } catch ( ... ) { - delete netconf; - throw; - } + RR->localNetworkController->request(nwid,(hopCount > 0) ? InetAddress() : _path->address(),requestPacketId,peer->identity(),metaData); } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); @@ -961,7 +881,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,trustEstablished); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); diff --git a/node/Network.cpp b/node/Network.cpp index c0e4b105..1f8e7ebf 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -599,7 +599,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : if (conf.length()) { dconf->load(conf.c_str()); if (nconf->fromDictionary(*dconf)) { - this->_setConfiguration(*nconf,false); + this->setConfiguration(*nconf,false); _lastConfigUpdate = 0; // we still want to re-request a new config from the network gotConf = true; } @@ -1015,7 +1015,7 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) } if (nc) { - this->_setConfiguration(*nc,true); + this->setConfiguration(*nc,true); delete nc; return configUpdateId; } else { @@ -1025,6 +1025,46 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) return 0; } +int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) +{ + // _lock is NOT locked when this is called + try { + if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) + return 0; + if (_config == nconf) + return 1; // OK config, but duplicate of what we already have + + ZT_VirtualNetworkConfig ctmp; + bool oldPortInitialized; + { + Mutex::Lock _l(_lock); + _config = nconf; + _lastConfigUpdate = RR->node->now(); + _netconfFailure = NETCONF_FAILURE_NONE; + oldPortInitialized = _portInitialized; + _portInitialized = true; + _externalConfig(&ctmp); + } + _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); + + if (saveToDisk) { + Dictionary *d = new Dictionary(); + try { + char n[64]; + Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); + if (nconf.toDictionary(*d,false)) + RR->node->dataStorePut(n,(const void *)d->data(),d->sizeBytes(),true); + } catch ( ... ) {} + delete d; + } + + return 2; // OK and configuration has changed + } catch ( ... ) { + TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); + } + return 0; +} + void Network::requestConfiguration() { const Address ctrl(controller()); @@ -1046,26 +1086,7 @@ void Network::requestConfiguration() if (ctrl == RR->identity.address()) { if (RR->localNetworkController) { - NetworkConfig *nconf = new NetworkConfig(); - try { - switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,rmd,*nconf)) { - case NetworkController::NETCONF_QUERY_OK: - this->_setConfiguration(*nconf,true); - break; - case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: - this->setNotFound(); - break; - case NetworkController::NETCONF_QUERY_ACCESS_DENIED: - this->setAccessDenied(); - break; - default: - this->setNotFound(); - break; - } - } catch ( ... ) { - this->setNotFound(); - } - delete nconf; + RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd); } else { this->setNotFound(); } @@ -1257,46 +1278,6 @@ ZT_VirtualNetworkStatus Network::_status() const } } -int Network::_setConfiguration(const NetworkConfig &nconf,bool saveToDisk) -{ - // _lock is NOT locked when this is called - try { - if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) - return 0; - if (_config == nconf) - return 1; // OK config, but duplicate of what we already have - - ZT_VirtualNetworkConfig ctmp; - bool oldPortInitialized; - { - Mutex::Lock _l(_lock); - _config = nconf; - _lastConfigUpdate = RR->node->now(); - _netconfFailure = NETCONF_FAILURE_NONE; - oldPortInitialized = _portInitialized; - _portInitialized = true; - _externalConfig(&ctmp); - } - _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); - - if (saveToDisk) { - Dictionary *d = new Dictionary(); - try { - char n[64]; - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); - if (nconf.toDictionary(*d,false)) - RR->node->dataStorePut(n,(const void *)d->data(),d->sizeBytes(),true); - } catch ( ... ) {} - delete d; - } - - return 2; // OK and configuration has changed - } catch ( ... ) { - TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); - } - return 0; -} - void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const { // assumes _lock is locked diff --git a/node/Network.hpp b/node/Network.hpp index 527d3048..1627be58 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -187,6 +187,15 @@ public: */ uint64_t handleConfigChunk(const Packet &chunk,unsigned int ptr); + /** + * Set network configuration + * + * @param nconf Network configuration + * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. + * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new + */ + int setConfiguration(const NetworkConfig &nconf,bool saveToDisk); + /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this */ @@ -328,7 +337,6 @@ public: inline void **userPtr() throw() { return &_uPtr; } private: - int _setConfiguration(const NetworkConfig &nconf,bool saveToDisk); ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _gate(const SharedPtr &peer); diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index db95dd14..fc5db4af 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -27,7 +27,6 @@ namespace ZeroTier { -class RuntimeEnvironment; class Identity; class Address; struct InetAddress; @@ -38,45 +37,69 @@ struct InetAddress; class NetworkController { public: + enum ErrorCode + { + NC_ERROR_NONE = 0, + NC_ERROR_OBJECT_NOT_FOUND = 1, + NC_ERROR_ACCESS_DENIED = 2, + NC_ERROR_INTERNAL_SERVER_ERROR = 3 + }; + /** - * Return value of doNetworkConfigRequest + * Interface for sender used to send pushes and replies */ - enum ResultCode + class Sender { - NETCONF_QUERY_OK = 0, - NETCONF_QUERY_OBJECT_NOT_FOUND = 1, - NETCONF_QUERY_ACCESS_DENIED = 2, - NETCONF_QUERY_INTERNAL_SERVER_ERROR = 3, - NETCONF_QUERY_IGNORE = 4 + public: + /** + * Send a configuration to a remote peer + * + * @param nwid Network ID + * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG (push) + * @param destination Destination peer Address + * @param nc Network configuration to send + * @param sendLegacyFormatConfig If true, send an old-format network config + */ + virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) = 0; + + /** + * Send a network configuration request error + * + * @param nwid Network ID + * @param requestPacketId Request packet ID or 0 if none + * @param destination Destination peer Address + * @param errorCode Error code + */ + virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode) = 0; }; NetworkController() {} virtual ~NetworkController() {} /** - * Handle a network config request, sending replies if necessary - * - * This call is permitted to block, and may be called concurrently from more - * than one thread. Implementations must use locks if needed. + * Called when this is added to a Node to initialize and supply info * - * On internal server errors, the 'error' field in result can be filled in - * to indicate the error. + * @param signingId Identity for signing of network configurations, certs, etc. + * @param sender Sender implementation for sending replies or config pushes + */ + virtual void init(const Identity &signingId,Sender *sender) = 0; + + /** + * Handle a network configuration request * - * @param fromAddr Originating wire address or null address if packet is not direct (or from self) - * @param signingId Identity that should be used to sign results -- must include private key - * @param identity Originating peer ZeroTier identity * @param nwid 64-bit network ID + * @param fromAddr Originating wire address or null address if packet is not direct (or from self) + * @param requestPacketId Packet ID of request packet or 0 if not initiated by remote request + * @param identity ZeroTier identity of originating peer * @param metaData Meta-data bundled with request (if any) - * @param nc NetworkConfig to fill with results * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error */ - virtual NetworkController::ResultCode doNetworkConfigRequest( + virtual void request( + uint64_t nwid, const InetAddress &fromAddr, - const Identity &signingId, + uint64_t requestPacketId, const Identity &identity, - uint64_t nwid, - const Dictionary &metaData, - NetworkConfig &nc) = 0; + const Dictionary &metaData) = 0; }; } // namespace ZeroTier diff --git a/node/Node.cpp b/node/Node.cpp index 9314478f..69808bcf 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -490,6 +490,7 @@ void Node::clearLocalInterfaceAddresses() void Node::setNetconfMaster(void *networkControllerInstance) { RR->localNetworkController = reinterpret_cast(networkControllerInstance); + RR->localNetworkController->init(RR->identity,this); } ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) @@ -718,6 +719,90 @@ void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_ RR->topology->setTrustedPaths(reinterpret_cast(networks),ids,count); } +void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) +{ + if (destination == RR->identity.address()) { + SharedPtr n(network(nwid)); + if (!n) return; + n->setConfiguration(nc,true); + } else { + Dictionary *dconf = new Dictionary(); + try { + if (nc.toDictionary(*dconf,sendLegacyFormatConfig)) { + uint64_t configUpdateId = prng(); + if (!configUpdateId) ++configUpdateId; + + const unsigned int totalSize = dconf->sizeBytes(); + unsigned int chunkIndex = 0; + while (chunkIndex < totalSize) { + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256))); + Packet outp(destination,RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + + const unsigned int sigStart = outp.size(); + outp.append(nwid); + outp.append((uint16_t)chunkLen); + outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); + + outp.append((uint8_t)0); // no flags + outp.append((uint64_t)configUpdateId); + outp.append((uint32_t)totalSize); + outp.append((uint32_t)chunkIndex); + + C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart)); + outp.append((uint8_t)1); + outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN); + outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); + + outp.compress(); + RR->sw->send(outp,true); + chunkIndex += chunkLen; + } + } + delete dconf; + } catch ( ... ) { + delete dconf; + throw; + } + } +} + +void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode) +{ + if (destination == RR->identity.address()) { + SharedPtr n(network(nwid)); + if (!n) return; + switch(errorCode) { + case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: + case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: + n->setNotFound(); + break; + case NetworkController::NC_ERROR_ACCESS_DENIED: + n->setAccessDenied(); + break; + + default: break; + } + } else if (requestPacketId) { + Packet outp(destination,RR->identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + switch(errorCode) { + //case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: + //case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: + default: + outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); + break; + case NetworkController::NC_ERROR_ACCESS_DENIED: + outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); + break; + } + outp.append(nwid); + RR->sw->send(outp,true); + } +} + } // namespace ZeroTier /****************************************************************************/ diff --git a/node/Node.hpp b/node/Node.hpp index 11462531..e616da3d 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -36,6 +36,7 @@ #include "Network.hpp" #include "Path.hpp" #include "Salsa20.hpp" +#include "NetworkController.hpp" #undef TRACE #ifdef ZT_TRACE @@ -55,7 +56,7 @@ namespace ZeroTier { * * The pointer returned by ZT_Node_new() is an instance of this class. */ -class Node +class Node : public NetworkController::Sender { public: Node( @@ -69,7 +70,7 @@ public: ZT_PathCheckFunction pathCheckFunction, ZT_EventCallback eventCallback); - ~Node(); + virtual ~Node(); // Public API Functions ---------------------------------------------------- @@ -282,6 +283,9 @@ public: return false; } + virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); + virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); + private: inline SharedPtr _network(uint64_t nwid) const { -- cgit v1.2.3 From bf8d71e82c27eae1e47bde411054f5258df29146 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 17 Nov 2016 16:20:41 -0800 Subject: Add notion of upstream that is separate from root in Topology, etc. --- attic/CertificateOfTrust.cpp | 67 +++++++++++++++++++ attic/CertificateOfTrust.hpp | 155 +++++++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 10 +-- node/Packet.hpp | 19 ++++-- node/Topology.cpp | 87 ++++++++++++++++-------- node/Topology.hpp | 37 ++++++----- objects.mk | 1 + 7 files changed, 321 insertions(+), 55 deletions(-) create mode 100644 attic/CertificateOfTrust.cpp create mode 100644 attic/CertificateOfTrust.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/attic/CertificateOfTrust.cpp b/attic/CertificateOfTrust.cpp new file mode 100644 index 00000000..e85a91df --- /dev/null +++ b/attic/CertificateOfTrust.cpp @@ -0,0 +1,67 @@ +/* + * 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 . + */ + +#include "CertificateOfTrust.hpp" + +#include "RuntimeEnvironment.hpp" +#include "Topology.hpp" +#include "Switch.hpp" + +namespace ZeroTier { + +bool CertificateOfTrust::create(uint64_t ts,uint64_t rls,const Identity &iss,const Identity &tgt,Level l) +{ + if ((!iss)||(!iss.hasPrivate())) + return false; + + _timestamp = ts; + _roles = rls; + _issuer = iss.address(); + _target = tgt; + _level = l; + + Buffer tmp; + tmp.append(_timestamp); + tmp.append(_roles); + _issuer.appendTo(tmp); + _target.serialize(tmp,false); + tmp.append((uint16_t)_level); + _signature = iss.sign(tmp.data(),tmp.size()); + + return true; +} + +int CertificateOfTrust::verify(const RuntimeEnvironment *RR) const +{ + const Identity id(RR->topology->getIdentity(_issuer)); + if (!id) { + RR->sw->requestWhois(_issuer); + return 1; + } + + Buffer tmp; + tmp.append(_timestamp); + tmp.append(_roles); + _issuer.appendTo(tmp); + _target.serialize(tmp,false); + tmp.append((uint16_t)_level); + + return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); +} + +} // namespace ZeroTier diff --git a/attic/CertificateOfTrust.hpp b/attic/CertificateOfTrust.hpp new file mode 100644 index 00000000..6e3c8743 --- /dev/null +++ b/attic/CertificateOfTrust.hpp @@ -0,0 +1,155 @@ +/* + * 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_CERTIFICATEOFTRUST_HPP +#define ZT_CERTIFICATEOFTRUST_HPP + +#include "Constants.hpp" +#include "Identity.hpp" +#include "C25519.hpp" +#include "Buffer.hpp" + +namespace ZeroTier { + +class RuntimeEnvironment; + +/** + * Certificate of peer to peer trust + */ +class CertificateOfTrust +{ +public: + /** + * Trust levels, with 0 indicating anti-trust + */ + enum Level + { + /** + * Negative trust is reserved for informing peers that another peer is misbehaving, etc. Not currently used. + */ + LEVEL_NEGATIVE = 0, + + /** + * Default trust -- for most peers + */ + LEVEL_DEFAULT = 1, + + /** + * Above normal trust, e.g. common network membership + */ + LEVEL_MEDIUM = 25, + + /** + * High trust -- e.g. an upstream or a controller + */ + LEVEL_HIGH = 50, + + /** + * Right now ultimate is only for roots + */ + LEVEL_ULTIMATE = 100 + }; + + /** + * Role bit masks + */ + enum Role + { + /** + * Target is permitted to represent issuer on the network as a federated root / relay + */ + ROLE_UPSTREAM = 0x00000001 + }; + + CertificateOfTrust() : + _timestamp(0), + _roles(0), + _issuer(), + _target(), + _level(LEVEL_DEFAULT), + _signature() {} + + /** + * Create and sign this certificate of trust + * + * @param ts Cert timestamp + * @param rls Roles bitmap + * @param iss Issuer identity (must have secret key!) + * @param tgt Target identity + * @param l Trust level + * @return True on successful signature + */ + bool create(uint64_t ts,uint64_t rls,const Identity &iss,const Identity &tgt,Level l); + + /** + * Verify this COT and its signature + * + * @param RR Runtime environment for looking up peers + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + int verify(const RuntimeEnvironment *RR) const; + + inline bool roleUpstream() const { return ((_roles & (uint64_t)ROLE_UPSTREAM) != 0); } + + inline uint64_t timestamp() const { return _timestamp; } + inline uint64_t roles() const { return _roles; } + inline const Address &issuer() const { return _issuer; } + inline const Identity &target() const { return _target; } + inline Level level() const { return _level; } + + inline operator bool() const { return (_issuer); } + + template + inline void serialize(Buffer &b) const + { + b.append(_timestamp); + b.append(_roles); + _issuer.appendTo(b); + _target.serialize(b); + b.append((uint16_t)_level); + b.append((uint8_t)1); // 1 == ed25519 signature + b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + b.append((uint16_t)0); // length of additional fields + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + unsigned int p = startAt; + _timestamp = b.template at(p); p += 8; + _roles = b.template at(p); p += 8; + _issuer.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; + p += _target.deserialize(b,p); + _level = b.template at(p); p += 2; + p += b.template at(p); p += 2; + return (p - startAt); + } + +private: + uint64_t _timestamp; + uint64_t _roles; + Address _issuer; + Identity _target; + Level _level; + C25519::Signature _signature; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index bde5df71..c6346346 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -160,7 +160,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_IDENTITY_COLLISION: // FIXME: for federation this will need a payload with a signature or something. - if (RR->topology->isRoot(peer->identity())) + if (RR->topology->isUpstream(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; @@ -508,11 +508,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr id.serialize(outp,false); ++count; } else { - // If I am not the root and don't know this identity, ask upstream. Downstream - // peer may re-request in the future and if so we will be able to provide it. - if (!RR->topology->amRoot()) - RR->sw->requestWhois(addr); - + RR->sw->requestWhois(addr); #ifdef ZT_ENABLE_CLUSTER // Distribute WHOIS queries across a cluster if we do not know the ID. // This may result in duplicate OKs to the querying peer, which is fine. @@ -666,7 +662,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

address(),RR->identity.address(),Packet::VERB_OK); outp.append((uint8_t)Packet::VERB_EXT_FRAME); outp.append((uint64_t)packetId()); diff --git a/node/Packet.hpp b/node/Packet.hpp index a8738884..7a742aad 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -617,10 +617,8 @@ public: * <[1] protocol address length (4 for IPv4, 16 for IPv6)> * <[...] protocol address (network byte order)> * - * This is sent by a relaying node to initiate NAT traversal between two - * peers that are communicating by way of indirect relay. The relay will - * send this to both peers at the same time on a periodic basis, telling - * each where it might find the other on the network. + * An upstream node can send this to inform both sides of a relay of + * information they might use to establish a direct connection. * * Upon receipt a peer sends HELLO to establish a direct link. * @@ -1051,7 +1049,18 @@ public: * OK or ERROR and has no special semantics outside of whatever the user * (via the ZeroTier core API) chooses to give it. */ - VERB_USER_MESSAGE = 0x14 + VERB_USER_MESSAGE = 0x14, + + /** + * Information related to federation and mesh-like behavior: + * <[2] 16-bit length of Dictionary> + * <[...] topology definition info Dictionary> + * + * This message can carry information that can be used to define topology + * and implement "mesh-like" behavior. It can optionally generate OK or + * ERROR, and these carry the same payload. + */ + VERB_TOPOLOGY_HINT = 0x15 }; /** diff --git a/node/Topology.cpp b/node/Topology.cpp index 12a7cc0b..48ced7c5 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -111,9 +111,8 @@ SharedPtr Topology::getPeer(const Address &zta) { Mutex::Lock _l(_lock); const SharedPtr *const ap = _peers.get(zta); - if (ap) { + if (ap) return *ap; - } } try { @@ -158,7 +157,7 @@ void Topology::saveIdentity(const Identity &id) } } -SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid) +SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) { const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -189,22 +188,25 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou const SharedPtr *bestOverall = (const SharedPtr *)0; const SharedPtr *bestNotAvoid = (const SharedPtr *)0; - for(std::vector< SharedPtr >::const_iterator r(_rootPeers.begin());r!=_rootPeers.end();++r) { - bool avoiding = false; - for(unsigned int i=0;iaddress()) { - avoiding = true; - break; + for(std::vector

::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { + const SharedPtr *const p = _peers.get(*a); + if (p) { + bool avoiding = false; + for(unsigned int i=0;iaddress()) { + avoiding = true; + break; + } + } + const unsigned int q = (*p)->relayQuality(now); + if (q <= bestQualityOverall) { + bestQualityOverall = q; + bestOverall = &(*p); + } + if ((!avoiding)&&(q <= bestQualityNotAvoid)) { + bestQualityNotAvoid = q; + bestNotAvoid = &(*p); } - } - const unsigned int q = (*r)->relayQuality(now); - if (q <= bestQualityOverall) { - bestQualityOverall = q; - bestOverall = &(*r); - } - if ((!avoiding)&&(q <= bestQualityNotAvoid)) { - bestQualityNotAvoid = q; - bestNotAvoid = &(*r); } } @@ -219,9 +221,34 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou return SharedPtr(); } +bool Topology::isRoot(const Identity &id) const +{ + Mutex::Lock _l(_lock); + return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()); +} + bool Topology::isUpstream(const Identity &id) const { - return isRoot(id); + Mutex::Lock _l(_lock); + return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); +} + +void Topology::setUpstream(const Address &a,bool upstream) +{ + Mutex::Lock _l(_lock); + if (std::find(_rootAddresses.begin(),_rootAddresses.end(),a) == _rootAddresses.end()) { + if (upstream) { + if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),a) == _upstreamAddresses.end()) + _upstreamAddresses.push_back(a); + } else { + std::vector
ua; + for(std::vector
::iterator i(_upstreamAddresses.begin());i!=_upstreamAddresses.end();++i) { + if (a != *i) + ua.push_back(*i); + } + _upstreamAddresses.swap(ua); + } + } } bool Topology::worldUpdateIfValid(const World &newWorld) @@ -249,7 +276,7 @@ void Topology::clean(uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) ) + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) _peers.erase(*a); } } @@ -280,25 +307,33 @@ Identity Topology::_getIdentity(const Address &zta) void Topology::_setWorld(const World &newWorld) { // assumed _lock is locked (or in constructor) + + std::vector
ua; + for(std::vector
::iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { + if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) + ua.push_back(*a); + } + _world = newWorld; - _amRoot = false; _rootAddresses.clear(); - _rootPeers.clear(); + _amRoot = false; + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { _rootAddresses.push_back(r->identity.address()); + if (std::find(ua.begin(),ua.end(),r->identity.address()) == ua.end()) + ua.push_back(r->identity.address()); if (r->identity.address() == RR->identity.address()) { _amRoot = true; } else { SharedPtr *rp = _peers.get(r->identity.address()); - if (rp) { - _rootPeers.push_back(*rp); - } else { + if (!rp) { SharedPtr newrp(new Peer(RR,RR->identity,r->identity)); _peers.set(r->identity.address(),newrp); - _rootPeers.push_back(newrp); } } } + + _upstreamAddresses.swap(ua); } } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index e63766cb..573d5ca2 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -125,35 +125,27 @@ public: void saveIdentity(const Identity &id); /** - * Get the current favorite root server + * Get the current best upstream peer * * @return Root server with lowest latency or NULL if none */ - inline SharedPtr getBestRoot() { return getBestRoot((const Address *)0,0,false); } + inline SharedPtr getUpstreamPeer() { return getUpstreamPeer((const Address *)0,0,false); } /** - * Get the best root server, avoiding root servers listed in an array - * - * This will get the best root server (lowest latency, etc.) but will - * try to avoid the listed root servers, only using them if no others - * are available. + * Get the current best upstream peer, avoiding those in the supplied avoid list * * @param avoid Nodes to avoid * @param avoidCount Number of nodes to avoid * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available * @return Root server or NULL if none available */ - SharedPtr getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid); + SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); /** * @param id Identity to check * @return True if this is a designated root server in this world */ - inline bool isRoot(const Identity &id) const - { - Mutex::Lock _l(_lock); - return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()); - } + bool isRoot(const Identity &id) const; /** * @param id Identity to check @@ -161,6 +153,16 @@ public: */ bool isUpstream(const Identity &id) const; + /** + * Set whether or not an address is upstream + * + * If the address is a root this does nothing, since roots are fixed. + * + * @param a Target address + * @param upstream New upstream status + */ + void setUpstream(const Address &a,bool upstream); + /** * @return Vector of root server addresses */ @@ -175,7 +177,8 @@ public: */ inline std::vector
upstreamAddresses() const { - return rootAddresses(); + Mutex::Lock _l(_lock); + return _upstreamAddresses; } /** @@ -342,9 +345,9 @@ private: Hashtable< Address,SharedPtr > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - std::vector< Address > _rootAddresses; - std::vector< SharedPtr > _rootPeers; - bool _amRoot; + std::vector< Address > _upstreamAddresses; // includes roots + std::vector< Address > _rootAddresses; // only roots + bool _amRoot; // am I a root? Mutex _lock; }; diff --git a/objects.mk b/objects.mk index 078a92a7..16858ef3 100644 --- a/objects.mk +++ b/objects.mk @@ -4,6 +4,7 @@ OBJS=\ node/C25519.o \ node/Capability.o \ node/CertificateOfMembership.o \ + node/CertificateOfTrust.o \ node/Cluster.o \ node/Identity.o \ node/IncomingPacket.o \ -- cgit v1.2.3 From ab4021dd0ee37af0af4137dc772911ea8ec52bb2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Nov 2016 11:09:19 -0800 Subject: Do packet MAC check before locallyValidate(), and add timing measurement in selftest. --- node/IncomingPacket.cpp | 15 ++++++++------- selftest.cpp | 12 ++++++++---- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c6346346..ee4d62c0 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -275,7 +275,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // Continue at // VALID } - } // else continue at // VALID + } // else if alreadyAuthenticated then continue at // VALID } else { // We don't already have an identity with this address -- validate and learn it @@ -285,18 +285,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } + // Check packet integrity and MAC + SharedPtr newPeer(new Peer(RR,RR->identity,id)); + if (!dearmor(newPeer->key())) { + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } + // Check that identity's address is valid as per the derivation function if (!id.locallyValidate()) { TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } - // Check packet integrity and authentication - SharedPtr newPeer(new Peer(RR,RR->identity,id)); - if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } peer = RR->topology->addPeer(newPeer); // Continue at // VALID diff --git a/selftest.cpp b/selftest.cpp index 7ca4ac3b..9992d757 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -376,11 +376,15 @@ static int testIdentity() std::cout << "FAIL (1)" << std::endl; return -1; } - if (!id.locallyValidate()) { - std::cout << "FAIL (2)" << std::endl; - return -1; + const uint64_t vst = OSUtils::now(); + for(int k=0;k<10;++k) { + if (!id.locallyValidate()) { + std::cout << "FAIL (2)" << std::endl; + return -1; + } } - std::cout << "PASS" << std::endl; + const uint64_t vet = OSUtils::now(); + std::cout << "PASS (" << ((double)(vet - vst) / 10.0) << "ms per validation)" << std::endl; std::cout << "[identity] Validate known-bad identity... "; std::cout.flush(); if (!id.fromString(KNOWN_BAD_IDENTITY)) { -- cgit v1.2.3 From 2ea9f516e121ea6eb344a8d180a739a1d707aecb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Nov 2016 12:59:04 -0800 Subject: Rate gate expensive validation of new identities in HELLO. --- node/Constants.hpp | 20 ++++++++++++++++++++ node/IncomingPacket.cpp | 10 +++++++++- node/InetAddress.hpp | 24 ++++++++++++++++++++++++ node/Node.cpp | 1 + node/Node.hpp | 22 ++++++++++++++++++++++ selftest.cpp | 11 +++++++++++ 6 files changed, 87 insertions(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 6400e289..8803ecee 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -375,6 +375,26 @@ */ #define ZT_PEER_GENERAL_RATE_LIMIT 1000 +/** + * Don't do expensive identity validation more often than this + * + * IPv4 and IPv6 address prefixes are hashed down to 14-bit (0-16383) integers + * using the first 24 bits for IPv4 or the first 48 bits for IPv6. These are + * then rate limited to one identity validation per this often milliseconds. + */ +#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64) || defined(_M_AMD64)) +// AMD64 machines can do anywhere from one every 50ms to one every 10ms. This provides plenty of margin. +#define ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT 2000 +#else +#if (defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)) +// 32-bit Intel machines usually average about one every 100ms +#define ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT 5000 +#else +// This provides a safe margin for ARM, MIPS, etc. that usually average one every 250-400ms +#define ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT 10000 +#endif +#endif + /** * How long is a path or peer considered to have a trust relationship with us (for e.g. relay policy) since last trusted established packet? */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ee4d62c0..41f3e47d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -247,6 +247,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut if (peer->identity() != id) { // Identity is different from the one we already have -- address collision + // Check rate limits + if (!RR->node->rateGateIdentityVerification(now,_path->address())) + return true; + uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop @@ -285,7 +289,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } - // Check packet integrity and MAC + // Check rate limits + if (!RR->node->rateGateIdentityVerification(now,_path->address())) + return true; + + // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 6f070fbf..1dff710d 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -449,6 +449,30 @@ struct InetAddress : public sockaddr_storage bool isNetwork() const throw(); + /** + * @return 14-bit (0-16383) hash of this IP's first 24 or 48 bits (for V4 or V6) for rate limiting code, or 0 if non-IP + */ + inline unsigned long rateGateHash() const + { + unsigned long h = 0; + switch(ss_family) { + case AF_INET: + h = (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) & 0xffffff00) >> 8; + h ^= (h >> 14); + break; + case AF_INET6: { + const uint8_t *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + h = ((unsigned long)ip[0]); h <<= 1; + h += ((unsigned long)ip[1]); h <<= 1; + h += ((unsigned long)ip[2]); h <<= 1; + h += ((unsigned long)ip[3]); h <<= 1; + h += ((unsigned long)ip[4]); h <<= 1; + h += ((unsigned long)ip[5]); + } break; + } + return (h & 0x3fff); + } + /** * @return True if address family is non-zero */ diff --git a/node/Node.cpp b/node/Node.cpp index add3117e..ec719668 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -78,6 +78,7 @@ Node::Node( memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); + memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); // Use Salsa20 alone as a high-quality non-crypto PRNG { diff --git a/node/Node.hpp b/node/Node.hpp index e616da3d..ee0d6c4c 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -283,6 +283,24 @@ public: return false; } + /** + * Check whether we should do potentially expensive identity verification (rate limit) + * + * @param now Current time + * @param from Source address of packet + * @return True if within rate limits + */ + inline bool rateGateIdentityVerification(const uint64_t now,const InetAddress &from) + { + unsigned long iph = from.rateGateHash(); + printf("%s %.4lx\n",from.toString().c_str(),iph); + if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { + _lastIdentityVerification[iph] = now; + return true; + } + return false; + } + virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); @@ -302,9 +320,13 @@ private: void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P + // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; uint64_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; + // Time of last identity verification indexed by InetAddress.rateGateHash() + uint64_t _lastIdentityVerification[16384]; + ZT_DataStoreGetFunction _dataStoreGetFunction; ZT_DataStorePutFunction _dataStorePutFunction; ZT_WirePacketSendFunction _wirePacketSendFunction; diff --git a/selftest.cpp b/selftest.cpp index 9992d757..adac2f58 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -327,6 +327,17 @@ static int testCrypto() } std::cout << "PASS" << std::endl; + std::cout << "[crypto] Benchmarking C25519 ECC key agreement... "; std::cout.flush(); + C25519::Pair bp[8]; + for(int k=0;k<8;++k) + bp[k] = C25519::generate(); + const uint64_t st = OSUtils::now(); + for(unsigned int k=0;k<50;++k) { + C25519::agree(bp[~k & 7],bp[k & 7].pub,buf1,64); + } + const uint64_t et = OSUtils::now(); + std::cout << ((double)(et - st) / 50.0) << "ms per agreement." << std::endl; + std::cout << "[crypto] Testing Ed25519 ECC signatures... "; std::cout.flush(); C25519::Pair didntSign = C25519::generate(); for(unsigned int i=0;i<10;++i) { -- cgit v1.2.3 From 42ba70e79e3f1484f7bdde5832658cbd179649dc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 22 Nov 2016 10:54:58 -0800 Subject: Replace long callback arg list with struct, and implement path whitelisting, path blacklisting, and local.conf support for roles. --- include/ZeroTierOne.h | 97 ++++++++++++++++---- node/IncomingPacket.cpp | 6 +- node/Node.cpp | 88 ++++++------------ node/Node.hpp | 86 +++-------------- node/Peer.cpp | 2 +- node/Switch.cpp | 2 +- service/OneService.cpp | 238 ++++++++++++++++++++++++++++++++++++------------ 7 files changed, 302 insertions(+), 217 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 399f090c..72da53f2 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1495,8 +1495,9 @@ typedef int (*ZT_WirePacketSendFunction)( * Paramters: * (1) Node * (2) User pointer - * (3) Local interface address - * (4) Remote address + * (3) ZeroTier address or 0 for none/any + * (4) Local interface address + * (5) Remote address * * This function must return nonzero (true) if the path should be used. * @@ -1515,13 +1516,87 @@ typedef int (*ZT_WirePacketSendFunction)( typedef int (*ZT_PathCheckFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + uint64_t, /* ZeroTier address */ const struct sockaddr_storage *, /* Local address */ const struct sockaddr_storage *); /* Remote address */ +/** + * Function to get physical addresses for ZeroTier peers + * + * Parameters: + * (1) Node + * (2) User pointer + * (3) ZeroTier address (least significant 40 bits) + * (4) Desried address family or -1 for any + * (5) Buffer to fill with result + * + * If provided this function will be occasionally called to get physical + * addresses that might be tried to reach a ZeroTier address. It must + * return a nonzero (true) value if the result buffer has been filled + * with an address. + */ +typedef int (*ZT_PathLookupFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + uint64_t, /* ZeroTier address (40 bits) */ + int, /* Desired ss_family or -1 for any */ + struct sockaddr_storage *); /* Result buffer */ + /****************************************************************************/ /* C Node API */ /****************************************************************************/ +/** + * Structure for configuring ZeroTier core callback functions + */ +struct ZT_Node_Callbacks +{ + /** + * Struct version -- must currently be 0 + */ + long version; + + /** + * REQUIRED: Function to get objects from persistent storage + */ + ZT_DataStoreGetFunction dataStoreGetFunction; + + /** + * REQUIRED: Function to store objects in persistent storage + */ + ZT_DataStorePutFunction dataStorePutFunction; + + /** + * REQUIRED: Function to send packets over the physical wire + */ + ZT_WirePacketSendFunction wirePacketSendFunction; + + /** + * REQUIRED: Function to inject frames into a virtual network's TAP + */ + ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; + + /** + * REQUIRED: Function to be called when virtual networks are configured or changed + */ + ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; + + /** + * REQUIRED: Function to be called to notify external code of important events + */ + ZT_EventCallback eventCallback; + + /** + * OPTIONAL: Function to check whether a given physical path should be used + */ + ZT_PathCheckFunction pathCheckFunction; + + /** + * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses + */ + ZT_PathLookupFunction pathLookupFunction; +}; + /** * Create a new ZeroTier One node * @@ -1533,25 +1608,11 @@ typedef int (*ZT_PathCheckFunction)( * * @param node Result: pointer is set to new node instance on success * @param uptr User pointer to pass to functions/callbacks + * @param callbacks Callback function configuration * @param now Current clock in milliseconds - * @param dataStoreGetFunction Function called to get objects from persistent storage - * @param dataStorePutFunction Function called to put objects in persistent storage - * @param virtualNetworkConfigFunction Function to be called when virtual LANs are created, deleted, or their config parameters change - * @param pathCheckFunction A function to check whether a path should be used for ZeroTier traffic, or NULL to allow any path - * @param eventCallback Function to receive status updates and non-fatal error notices * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_new( - ZT_Node **node, - void *uptr, - uint64_t now, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback); +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); /** * Delete a node and free all resources it consumes diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 41f3e47d..7b828f8b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -552,7 +552,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { + if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1120,7 +1120,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now); @@ -1139,7 +1139,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now); diff --git a/node/Node.cpp b/node/Node.cpp index 263cfc6e..a180766b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,34 +46,20 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node( - uint64_t now, - void *uptr, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback) : +Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : _RR(this), RR(&_RR), _uPtr(uptr), - _dataStoreGetFunction(dataStoreGetFunction), - _dataStorePutFunction(dataStorePutFunction), - _wirePacketSendFunction(wirePacketSendFunction), - _virtualNetworkFrameFunction(virtualNetworkFrameFunction), - _virtualNetworkConfigFunction(virtualNetworkConfigFunction), - _pathCheckFunction(pathCheckFunction), - _eventCallback(eventCallback), - _networks(), - _networks_m(), _prngStreamPtr(0), _now(now), _lastPingCheck(0), _lastHousekeepingRun(0), _relayPolicy(ZT_RELAY_POLICY_TRUSTED) { + if (callbacks->version != 0) + throw std::runtime_error("callbacks struct version mismatch"); + memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); + _online = false; memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); @@ -81,30 +67,26 @@ Node::Node( memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); // Use Salsa20 alone as a high-quality non-crypto PRNG - { - char foo[32]; - Utils::getSecureRandom(foo,32); - _prng.init(foo,256,foo); - memset(_prngStream,0,sizeof(_prngStream)); - _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + char foo[32]; + Utils::getSecureRandom(foo,32); + _prng.init(foo,256,foo); + memset(_prngStream,0,sizeof(_prngStream)); + _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + + std::string idtmp(dataStoreGet("identity.secret")); + if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { + TRACE("identity.secret not found, generating..."); + RR->identity.generate(); + idtmp = RR->identity.toString(true); + if (!dataStorePut("identity.secret",idtmp,true)) + throw std::runtime_error("unable to write identity.secret"); } - - { - std::string idtmp(dataStoreGet("identity.secret")); - if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { - TRACE("identity.secret not found, generating..."); - RR->identity.generate(); - idtmp = RR->identity.toString(true); - if (!dataStorePut("identity.secret",idtmp,true)) - throw std::runtime_error("unable to write identity.secret"); - } - RR->publicIdentityStr = RR->identity.toString(false); - RR->secretIdentityStr = RR->identity.toString(true); - idtmp = dataStoreGet("identity.public"); - if (idtmp != RR->publicIdentityStr) { - if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) - throw std::runtime_error("unable to write identity.public"); - } + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + idtmp = dataStoreGet("identity.public"); + if (idtmp != RR->publicIdentityStr) { + if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) + throw std::runtime_error("unable to write identity.public"); } try { @@ -638,7 +620,7 @@ std::string Node::dataStoreGet(const char *name) std::string r; unsigned long olen = 0; do { - long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); + long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); @@ -646,7 +628,7 @@ std::string Node::dataStoreGet(const char *name) return r; } -bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) { if (!Path::isAddressValidForPath(remoteAddress)) return false; @@ -663,9 +645,7 @@ bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const } } - if (_pathCheckFunction) - return (_pathCheckFunction(reinterpret_cast(this),_uPtr,reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0); - else return true; + return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); } #ifdef ZT_TRACE @@ -822,21 +802,11 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new( - ZT_Node **node, - void *uptr, - uint64_t now, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback) +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) { *node = (ZT_Node *)0; try { - *node = reinterpret_cast(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,pathCheckFunction,eventCallback)); + *node = reinterpret_cast(new ZeroTier::Node(uptr,callbacks,now)); 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 38303f8c..7d99ff09 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -59,17 +59,7 @@ namespace ZeroTier { class Node : public NetworkController::Sender { public: - Node( - uint64_t now, - void *uptr, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback); - + Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); virtual ~Node(); // Public API Functions ---------------------------------------------------- @@ -127,24 +117,11 @@ public: // Internal functions ------------------------------------------------------ - /** - * @return Time as of last call to run() - */ inline uint64_t now() const throw() { return _now; } - /** - * Enqueue a ZeroTier message to be sent - * - * @param localAddress Local address - * @param addr Destination address - * @param data Packet data - * @param len Packet length - * @param ttl Desired TTL (default: 0 for unchanged/default TTL) - * @return True if packet appears to have been sent - */ inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { - return (_wirePacketSendFunction( + return (_cb.wirePacketSendFunction( reinterpret_cast(this), _uPtr, reinterpret_cast(&localAddress), @@ -154,21 +131,9 @@ public: ttl) == 0); } - /** - * Enqueue a frame to be injected into a tap device (port) - * - * @param nwid Network ID - * @param nuptr Network user ptr - * @param source Source MAC - * @param dest Destination MAC - * @param etherType 16-bit ethernet type - * @param vlanId VLAN ID or 0 if none - * @param data Frame data - * @param len Frame length - */ inline void putFrame(uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { - _virtualNetworkFrameFunction( + _cb.virtualNetworkFrameFunction( reinterpret_cast(this), _uPtr, nwid, @@ -181,13 +146,6 @@ 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); @@ -214,37 +172,20 @@ public: return nw; } - /** - * @return Potential direct paths to me a.k.a. local interface addresses - */ inline std::vector directPaths() const { Mutex::Lock _l(_directPaths_m); return _directPaths; } - inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } + inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } - inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } + inline void dataStoreDelete(const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } std::string dataStoreGet(const char *name); - /** - * Post an event to the external user - * - * @param ev Event type - * @param md Meta-data (default: NULL/none) - */ - inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _eventCallback(reinterpret_cast(this),_uPtr,ev,md); } + inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,ev,md); } - /** - * Update virtual network port configuration - * - * @param nwid Network ID - * @param nuptr Network user ptr - * @param op Configuration operation - * @param nc Network configuration - */ - inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } + inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } inline bool online() const throw() { return _online; } inline ZT_RelayPolicy relayPolicy() const { return _relayPolicy; } @@ -253,6 +194,9 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif + bool shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); + inline bool getPathHint(const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } + uint64_t prng(); void postCircuitTestReport(const ZT_CircuitTestReport *report); void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); @@ -317,8 +261,8 @@ private: RuntimeEnvironment _RR; RuntimeEnvironment *RR; - void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P + ZT_Node_Callbacks _cb; // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; @@ -327,14 +271,6 @@ private: // Time of last identity verification indexed by InetAddress.rateGateHash() uint64_t _lastIdentityVerification[16384]; - ZT_DataStoreGetFunction _dataStoreGetFunction; - ZT_DataStorePutFunction _dataStorePutFunction; - ZT_WirePacketSendFunction _wirePacketSendFunction; - ZT_VirtualNetworkFrameFunction _virtualNetworkFrameFunction; - ZT_VirtualNetworkConfigFunction _virtualNetworkConfigFunction; - ZT_PathCheckFunction _pathCheckFunction; - ZT_EventCallback _eventCallback; - std::vector< std::pair< uint64_t, SharedPtr > > _networks; Mutex _networks_m; diff --git a/node/Peer.cpp b/node/Peer.cpp index 94fb5298..e0bd0eac 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -160,7 +160,7 @@ void Peer::received( } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address())) ) { + if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); diff --git a/node/Switch.cpp b/node/Switch.cpp index a5dd57e4..881d7b92 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -85,7 +85,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from Address beaconAddr(reinterpret_cast(data) + 8,5); if (beaconAddr == RR->identity.address()) return; - if (!RR->node->shouldUsePathForZeroTierTraffic(localAddr,fromAddr)) + if (!RR->node->shouldUsePathForZeroTierTraffic(beaconAddr,localAddr,fromAddr)) return; SharedPtr peer(RR->topology->getPeer(beaconAddr)); if (peer) { // we'll only respond to beacons from known peers diff --git a/service/OneService.cpp b/service/OneService.cpp index efb6ff3c..7434ca67 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -160,7 +160,6 @@ static uint64_t _jI(const json &jv,const uint64_t dfl) } return dfl; } -/* static bool _jB(const json &jv,const bool dfl) { if (jv.is_boolean()) { @@ -181,7 +180,6 @@ static bool _jB(const json &jv,const bool dfl) } return dfl; } -*/ static std::string _jS(const json &jv,const char *dfl) { if (jv.is_string()) { @@ -452,7 +450,8 @@ static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name, static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure); static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); #ifdef ZT_ENABLE_CLUSTER static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len); @@ -536,11 +535,20 @@ public: const std::string _homePath; BackgroundResolver _tcpFallbackResolver; InetAddress _allowManagementFrom; - json _localConfig; EmbeddedNetworkController *_controller; Phy _phy; Node *_node; + // Local configuration and memo-ized static path definitions + json _localConfig; + Hashtable< uint64_t,std::vector > _v4Hints; + Hashtable< uint64_t,std::vector > _v6Hints; + Hashtable< uint64_t,std::vector > _v4Blacklists; + Hashtable< uint64_t,std::vector > _v6Blacklists; + std::vector< InetAddress > _globalV4Blacklist; + std::vector< InetAddress > _globalV6Blacklist; + Mutex _localConfig_m; + /* * To attempt to handle NAT/gateway craziness we use three local UDP ports: * @@ -552,7 +560,6 @@ public: * destructively with uPnP port mapping behavior in very weird buggy ways. * It's only used if uPnP/NAT-PMP is enabled in this build. */ - Binder _bindings[3]; unsigned int _ports[3]; uint16_t _portsBE[3]; // ports in big-endian network byte order as in sockaddr @@ -756,16 +763,19 @@ public: // Clean up any legacy files if present OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + "peers.save").c_str()); - _node = new Node( - OSUtils::now(), - this, - SnodeDataStoreGetFunction, - SnodeDataStorePutFunction, - SnodeWirePacketSendFunction, - SnodeVirtualNetworkFrameFunction, - SnodeVirtualNetworkConfigFunction, - SnodePathCheckFunction, - SnodeEventCallback); + { + struct ZT_Node_Callbacks cb; + cb.version = 0; + cb.dataStoreGetFunction = SnodeDataStoreGetFunction; + cb.dataStorePutFunction = SnodeDataStorePutFunction; + cb.wirePacketSendFunction = SnodeWirePacketSendFunction; + cb.virtualNetworkFrameFunction = SnodeVirtualNetworkFrameFunction; + cb.virtualNetworkConfigFunction = SnodeVirtualNetworkConfigFunction; + cb.eventCallback = SnodeEventCallback; + cb.pathCheckFunction = SnodePathCheckFunction; + cb.pathLookupFunction = SnodePathLookupFunction; + _node = new Node(this,&cb,OSUtils::now()); + } // Attempt to bind to a secondary port chosen from our ZeroTier address. // This exists because there are buggy NATs out there that fail if more @@ -842,6 +852,7 @@ public: } // Read local config file + Mutex::Lock _l2(_localConfig_m); std::string lcbuf; if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "local.conf").c_str(),lcbuf)) { try { @@ -854,19 +865,18 @@ public: } } - // Get any trusted paths in local.conf + // Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere) json &physical = _localConfig["physical"]; if (physical.is_object()) { for(json::iterator phy(physical.begin());phy!=physical.end();++phy) { - std::string nstr = phy.key(); - if (nstr.length()) { + InetAddress net(_jS(phy.key(),"")); + if (net) { if (phy.value().is_object()) { - uint64_t tpid = 0; - if ((tpid = _jI(phy.value()["trustedPathId"],0ULL))) { - InetAddress trustedPathNetwork(nstr); - if ( ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (trustedPathNetwork.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (trustedPathNetwork.netmaskBits() > 0) ) { + uint64_t tpid; + if ((tpid = _jI(phy.value()["trustedPathId"],0ULL)) != 0ULL) { + if ( ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (net.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (net.netmaskBits() > 0) ) { trustedPathIds[trustedPathCount] = tpid; - trustedPathNetworks[trustedPathCount] = trustedPathNetwork; + trustedPathNetworks[trustedPathCount] = net; ++trustedPathCount; } } @@ -878,31 +888,8 @@ public: // Set trusted paths if there are any if (trustedPathCount) _node->setTrustedPaths(reinterpret_cast(trustedPathNetworks),trustedPathIds,trustedPathCount); - - // Set any roles (upstream/federation) - json &virt = _localConfig["virtual"]; - if (virt.is_object()) { - for(json::iterator v(virt.begin());v!=virt.end();++v) { - const std::string nstr = v.key(); - if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { - const Address ztaddr(nstr.c_str()); - if (ztaddr) - _node->setRole(ztaddr.toInt(),(_jS(v.value()["role"],"") == "upstream") ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); - } - } - } - - // Set any other local config stuff - json &settings = _localConfig["settings"]; - if (settings.is_object()) { - const std::string rp(_jS(settings["relayPolicy"],"")); - if (rp == "always") - _node->setRelayPolicy(ZT_RELAY_POLICY_ALWAYS); - else if (rp == "never") - _node->setRelayPolicy(ZT_RELAY_POLICY_NEVER); - else _node->setRelayPolicy(ZT_RELAY_POLICY_TRUSTED); - } } + applyLocalConfig(); _controller = new EmbeddedNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str()); _node->setNetconfMaster((void *)_controller); @@ -1174,7 +1161,90 @@ public: return true; } - // Begin private implementation methods + // Internal implementation methods ----------------------------------------- + + void applyLocalConfig() + { + Mutex::Lock _l(_localConfig_m); + + _v4Hints.clear(); + _v6Hints.clear(); + _v4Blacklists.clear(); + _v6Blacklists.clear(); + json &virt = _localConfig["virtual"]; + if (virt.is_object()) { + for(json::iterator v(virt.begin());v!=virt.end();++v) { + const std::string nstr = v.key(); + if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { + const Address ztaddr(nstr.c_str()); + if (ztaddr) { + _node->setRole(ztaddr.toInt(),(_jS(v.value()["role"],"") == "upstream") ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); + + const uint64_t ztaddr2 = ztaddr.toInt(); + std::vector &v4h = _v4Hints[ztaddr2]; + std::vector &v6h = _v6Hints[ztaddr2]; + std::vector &v4b = _v4Blacklists[ztaddr2]; + std::vector &v6b = _v6Blacklists[ztaddr2]; + + json &tryAddrs = v.value()["try"]; + if (tryAddrs.is_array()) { + for(unsigned long i=0;i 0)) { + if (phy.value().is_object()) { + if (_jB(phy.value()["blacklist"],false)) { + if (net.ss_family == AF_INET) + _globalV4Blacklist.push_back(net); + else if (net.ss_family == AF_INET6) + _globalV6Blacklist.push_back(net); + } + } + } + } + } + + json &settings = _localConfig["settings"]; + if (settings.is_object()) { + const std::string rp(_jS(settings["relayPolicy"],"")); + if (rp == "always") + _node->setRelayPolicy(ZT_RELAY_POLICY_ALWAYS); + else if (rp == "never") + _node->setRelayPolicy(ZT_RELAY_POLICY_NEVER); + else _node->setRelayPolicy(ZT_RELAY_POLICY_TRUSTED); + } + } // Checks if a managed IP or route target is allowed bool checkIfManagedIsAllowed(const NetworkState &n,const InetAddress &target) @@ -1306,6 +1376,8 @@ public: } } + // Handlers for Node and Phy<> callbacks ----------------------------------- + inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) { #ifdef ZT_ENABLE_CLUSTER @@ -1783,21 +1855,48 @@ public: n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); } - inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) + inline int nodePathCheckFunction(uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) { - Mutex::Lock _l(_nets_m); - - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap) { - std::vector ips(n->second.tap->ips()); - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { - return 0; + // Make sure we're not trying to do ZeroTier-over-ZeroTier + { + Mutex::Lock _l(_nets_m); + for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { + if (n->second.tap) { + std::vector ips(n->second.tap->ips()); + for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { + if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { + return 0; + } } } } } - + + // Check blacklists + const Hashtable< uint64_t,std::vector > *blh = (const Hashtable< uint64_t,std::vector > *)0; + const std::vector *gbl = (const std::vector *)0; + if (remoteAddr->ss_family == AF_INET) { + blh = &_v4Blacklists; + gbl = &_globalV4Blacklist; + } else if (remoteAddr->ss_family == AF_INET6) { + blh = &_v6Blacklists; + gbl = &_globalV6Blacklist; + } + if (blh) { + Mutex::Lock _l(_localConfig_m); + const std::vector *l = blh->get(ztaddr); + if (l) { + for(std::vector::const_iterator a(l->begin());a!=l->end();++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + /* Note: I do not think we need to scan for overlap with managed routes * because of the "route forking" and interface binding that we do. This * ensures (we hope) that ZeroTier traffic will still take the physical @@ -1807,6 +1906,23 @@ public: return 1; } + inline int nodePathLookupFunction(uint64_t ztaddr,int family,struct sockaddr_storage *result) + { + const Hashtable< uint64_t,std::vector > *lh = (const Hashtable< uint64_t,std::vector > *)0; + if (family < 0) + lh = (_node->prng() & 1) ? &_v4Hints : &_v6Hints; + else if (family == AF_INET) + lh = &_v4Hints; + else if (family == AF_INET6) + lh = &_v6Hints; + else return 0; + const std::vector *l = lh->get(ztaddr); + if ((l)&&(l->size() > 0)) { + memcpy(result,&((*l)[(unsigned long)_node->prng() % l->size()]),sizeof(struct sockaddr_storage)); + return 1; + } else return 0; + } + inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { _node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); @@ -1956,8 +2072,10 @@ static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct soc { return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast(uptr)->nodePathCheckFunction(localAddr,remoteAddr); } +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) +{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) +{ return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } #ifdef ZT_ENABLE_CLUSTER static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len) -- cgit v1.2.3 From d5528e4e9a35d7f1c88a373b99c7b31a03eccd5a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 9 Jan 2017 15:55:07 -0800 Subject: Wire up VERB_USER_MESSAGE in core. --- include/ZeroTierOne.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++- node/IncomingPacket.cpp | 21 ++++++++++++++++++-- node/IncomingPacket.hpp | 1 + node/Node.cpp | 23 ++++++++++++++++++++++ node/Node.hpp | 1 + node/Packet.hpp | 4 ++++ 6 files changed, 99 insertions(+), 3 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 21544b96..8b1ee0ac 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -393,7 +393,17 @@ enum ZT_Event * * Meta-data: C string, TRACE message */ - ZT_EVENT_TRACE = 5 + ZT_EVENT_TRACE = 5, + + /** + * VERB_USER_MESSAGE received + * + * These are generated when a VERB_USER_MESSAGE packet is received via + * ZeroTier VL1. + * + * Meta-data: ZT_UserMessage structure + */ + ZT_EVENT_USER_MESSAGE = 6 }; /** @@ -406,6 +416,32 @@ enum ZT_RelayPolicy ZT_RELAY_POLICY_ALWAYS = 2 }; +/** + * User message used with ZT_EVENT_USER_MESSAGE + */ +typedef struct +{ + /** + * ZeroTier address of sender (least significant 40 bits) + */ + uint64_t origin; + + /** + * User message type ID + */ + uint64_t typeId; + + /** + * User message data (not including type ID) + */ + const void *data; + + /** + * Length of data in bytes + */ + unsigned int length; +} ZT_UserMessage; + /** * Current node status */ @@ -1853,6 +1889,20 @@ int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage */ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); +/** + * Send a VERB_USER_MESSAGE to another ZeroTier node + * + * There is no delivery guarantee here. Failure can occur if the message is + * too large or if dest is not a valid ZeroTier address. + * + * @param dest Destination ZeroTier address + * @param typeId VERB_USER_MESSAGE type ID + * @param data Payload data to attach to user message + * @param len Length of data in bytes + * @return Boolean: non-zero on success, zero on failure + */ +int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); + /** * Set peer role * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7b828f8b..562aee91 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -106,8 +106,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); - case Packet::VERB_USER_MESSAGE: - return true; + case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,peer); } } else { RR->sw->requestWhois(sourceAddress); @@ -1345,6 +1344,24 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S return true; } +bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPtr &peer) +{ + try { + if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) { + ZT_UserMessage um; + um.origin = peer->address().toInt(); + um.typeId = at(ZT_PACKET_IDX_PAYLOAD); + um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); + um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); + RR->node->postEvent(ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); + } + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + } catch ( ... ) { + TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + } + return true; +} + void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) { const uint64_t now = RR->node->now(); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 80244ea4..febff28a 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -131,6 +131,7 @@ private: bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPtr &peer); void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); diff --git a/node/Node.cpp b/node/Node.cpp index ed60817f..32d41305 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -473,6 +473,20 @@ void Node::clearLocalInterfaceAddresses() _directPaths.clear(); } +int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +{ + try { + Packet outp(Address(dest),RR->identity.address(),Packet::VERB_USER_MESSAGE); + outp.append(typeId); + outp.append(data,len); + outp.compress(); + RR->sw->send(outp,true); + return 1; + } catch ( ... ) { + return 0; + } +} + void Node::setRole(uint64_t ztAddress,ZT_PeerRole role) { RR->topology->setUpstream(Address(ztAddress),(role == ZT_PEER_ROLE_UPSTREAM)); @@ -992,6 +1006,15 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) } catch ( ... ) {} } +int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +{ + try { + return reinterpret_cast(node)->sendUserMessage(dest,typeId,data,len); + } catch ( ... ) { + return 0; + } +} + void ZT_Node_setRole(ZT_Node *node,uint64_t ztAddress,ZT_PeerRole role) { try { diff --git a/node/Node.hpp b/node/Node.hpp index eb46527d..64c9fcb4 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -98,6 +98,7 @@ public: void freeQueryResult(void *qr); int addLocalInterfaceAddress(const struct sockaddr_storage *addr); void clearLocalInterfaceAddresses(); + int sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len); void setRole(uint64_t ztAddress,ZT_PeerRole role); void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); diff --git a/node/Packet.hpp b/node/Packet.hpp index 8ff817aa..5ecbecba 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1048,6 +1048,10 @@ public: * This can be used to send arbitrary messages over VL1. It generates no * OK or ERROR and has no special semantics outside of whatever the user * (via the ZeroTier core API) chooses to give it. + * + * Message type IDs less than or equal to 65535 are reserved for use by + * ZeroTier, Inc. itself. We recommend making up random ones for your own + * implementations. */ VERB_USER_MESSAGE = 0x14 }; -- cgit v1.2.3 From 64774d0d4f552b2864abd969c6bc69c0ced3b2e1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 13:27:52 -0800 Subject: Replace piecemeal designation of upstreams with the concept of moons, which is simpler and easier to use and inherits all the cool live update stuff of worlds (now called planets) and global roots. --- include/ZeroTierOne.h | 15 +--- node/IncomingPacket.cpp | 22 ++--- node/Node.cpp | 85 ++++++-------------- node/Node.hpp | 1 - node/Peer.cpp | 12 +-- node/Switch.cpp | 2 +- node/Topology.cpp | 207 +++++++++++++++++++++++------------------------- node/Topology.hpp | 79 ++++++++++-------- node/World.hpp | 87 ++++++++++---------- service/OneService.cpp | 22 +++-- service/README.md | 1 - world/mkworld.cpp | 5 +- 12 files changed, 242 insertions(+), 296 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 8b1ee0ac..f0235b9d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -848,8 +848,8 @@ enum ZT_VirtualNetworkConfigOperation enum ZT_PeerRole { ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_UPSTREAM = 1, // upstream node - ZT_PEER_ROLE_ROOT = 2 // global root + ZT_PEER_ROLE_UPSTREAM = 1, // moon root + ZT_PEER_ROLE_ROOT = 2 // planetary root }; /** @@ -1903,17 +1903,6 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); */ int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); -/** - * Set peer role - * - * Right now this can only be used to set a peer to either LEAF or - * UPSTREAM, since roots are fixed and defined by the World. - * - * @param ztAddress ZeroTier address (least significant 40 bits) - * @param role New peer role (LEAF or UPSTREAM) - */ -void ZT_Node_setRole(ZT_Node *node,uint64_t ztAddress,enum ZT_PeerRole role); - /** * Set a network configuration master instance for this node * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 562aee91..2487a8aa 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -214,8 +214,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut Identity id; InetAddress externalSurfaceAddress; - uint64_t worldId = ZT_WORLD_ID_NULL; - uint64_t worldTimestamp = 0; + uint64_t planetWorldId = 0; + uint64_t planetWorldTimestamp = 0; { unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); @@ -223,10 +223,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Get world ID and world timestamp if present (was not in old versions) + // Get primary planet world ID and world timestamp if present if ((ptr + 16) <= size()) { - worldId = at(ptr); ptr += 8; - worldTimestamp = at(ptr); + planetWorldId = at(ptr); ptr += 8; + planetWorldTimestamp = at(ptr); } } @@ -356,14 +356,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut tmpa.serialize(outp); } - if ((worldId != ZT_WORLD_ID_NULL)&&(RR->topology->worldTimestamp() > worldTimestamp)&&(worldId == RR->topology->worldId())) { - World w(RR->topology->world()); + if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { + World w(RR->topology->planet()); const unsigned int sizeAt = outp.size(); outp.addSize(2); // make room for 16-bit size field w.serialize(outp,false); outp.setAt(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); } else { - outp.append((uint16_t)0); // no world update needed + outp.append((uint16_t)0); // no planet update needed } outp.armor(peer->key(),true); @@ -411,14 +411,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Handle world updates from root servers if present (was not on old versions) - if (((ptr + 2) <= size())&&(RR->topology->isRoot(peer->identity()))) { + // Handle planet or moon updates + if ((ptr + 2) <= size()) { World worldUpdate; const unsigned int worldLen = at(ptr); ptr += 2; if (worldLen > 0) { World w; w.deserialize(*this,ptr); - RR->topology->worldUpdateIfValid(w); + RR->topology->addWorld(w,true); } } diff --git a/node/Node.cpp b/node/Node.cpp index 0d0750ca..df22e3f2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -160,75 +160,48 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,const std::vector
&upstreams,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now) : lastReceiveFromUpstream(0), RR(renv), - _upstreams(upstreams), - _now(now), - _world(RR->topology->world()) + _now(now) { + RR->topology->getUpstreamStableEndpoints(_upstreams); } uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay inline void operator()(Topology &t,const SharedPtr &p) { - if (std::find(_upstreams.begin(),_upstreams.end(),p->address()) != _upstreams.end()) { - InetAddress stableEndpoint4,stableEndpoint6; - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - if (r->identity == p->identity()) { - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)r->stableEndpoints.size();++k) { - const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()]; - if (!stableEndpoint4) { - if (addr.ss_family == AF_INET) - stableEndpoint4 = addr; - } - if (!stableEndpoint6) { - if (addr.ss_family == AF_INET6) - stableEndpoint6 = addr; - } + const std::vector *upstreamStableEndpoints = _upstreams.get(p->address()); + if ((upstreamStableEndpoints)&&(upstreamStableEndpoints->size() > 0)) { + if (!p->doPingAndKeepalive(_now,AF_INET)) { + for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { + const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; + if (addr.ss_family == AF_INET) { + p->sendHELLO(InetAddress(),addr,_now); + break; } - break; } } - - // We keep connections to upstream peers alive forever. - bool needToContactIndirect = true; - if (p->doPingAndKeepalive(_now,AF_INET)) { - needToContactIndirect = false; - } else { - if (stableEndpoint4) { - needToContactIndirect = false; - p->sendHELLO(InetAddress(),stableEndpoint4,_now); - } - } - if (p->doPingAndKeepalive(_now,AF_INET6)) { - needToContactIndirect = false; - } else { - if (stableEndpoint6) { - needToContactIndirect = false; - p->sendHELLO(InetAddress(),stableEndpoint6,_now); + if (!p->doPingAndKeepalive(_now,AF_INET6)) { + for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { + const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; + if (addr.ss_family == AF_INET6) { + p->sendHELLO(InetAddress(),addr,_now); + break; + } } } - - // If we don't have a direct path or a static endpoint, send something indirectly to find one. - if (needToContactIndirect) { - Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true); - } - lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } else if (p->isActive(_now)) { - // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently p->doPingAndKeepalive(_now,-1); } } private: const RuntimeEnvironment *RR; - const std::vector
&_upstreams; uint64_t _now; - World _world; + Hashtable< Address,std::vector > _upstreams; }; ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) @@ -263,7 +236,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB } // Do pings and keepalives - _PingPeersThatNeedPing pfunc(RR,upstreams,now); + _PingPeersThatNeedPing pfunc(RR,now); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); // Update online status, post status change as event @@ -368,8 +341,8 @@ uint64_t Node::address() const void Node::status(ZT_NodeStatus *status) const { status->address = RR->identity.address().toInt(); - status->worldId = RR->topology->worldId(); - status->worldTimestamp = RR->topology->worldTimestamp(); + status->worldId = RR->topology->planetWorldId(); + status->worldTimestamp = RR->topology->planetWorldTimestamp(); status->publicIdentity = RR->publicIdentityStr.c_str(); status->secretIdentity = RR->secretIdentityStr.c_str(); status->relayPolicy = _relayPolicy; @@ -401,7 +374,7 @@ ZT_PeerList *Node::peers() const p->versionRev = -1; } p->latency = pi->second->latency(); - p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : (RR->topology->isUpstream(pi->second->identity()) ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); + p->role = RR->topology->role(pi->second->identity().address()); std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); SharedPtr bestp(pi->second->getBestPath(_now,false)); @@ -488,11 +461,6 @@ int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigne return 0; } -void Node::setRole(uint64_t ztAddress,ZT_PeerRole role) -{ - RR->topology->setUpstream(Address(ztAddress),(role == ZT_PEER_ROLE_UPSTREAM)); -} - void Node::setNetconfMaster(void *networkControllerInstance) { RR->localNetworkController = reinterpret_cast(networkControllerInstance); @@ -1016,13 +984,6 @@ int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const vo } } -void ZT_Node_setRole(ZT_Node *node,uint64_t ztAddress,ZT_PeerRole role) -{ - try { - reinterpret_cast(node)->setRole(ztAddress,role); - } catch ( ... ) {} -} - void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) { try { diff --git a/node/Node.hpp b/node/Node.hpp index d7b039b8..4c070014 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -105,7 +105,6 @@ public: int addLocalInterfaceAddress(const struct sockaddr_storage *addr); void clearLocalInterfaceAddresses(); int sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len); - void setRole(uint64_t ztAddress,ZT_PeerRole role); void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); void circuitTestEnd(ZT_CircuitTest *test); diff --git a/node/Peer.cpp b/node/Peer.cpp index 2ef139e1..40356034 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -37,9 +37,6 @@ namespace ZeroTier { -// Used to send varying values for NAT keepalive -static uint32_t _natKeepaliveBuf = 0; - Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : _lastReceive(0), _lastNontrivialReceive(0), @@ -355,8 +352,8 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append(now); RR->identity.serialize(outp,false); atAddress.serialize(outp); - outp.append((uint64_t)RR->topology->worldId()); - outp.append((uint64_t)RR->topology->worldTimestamp()); + outp.append((uint64_t)RR->topology->planetWorldId()); + outp.append((uint64_t)RR->topology->planetWorldTimestamp()); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); @@ -401,12 +398,9 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) } if (bestp >= 0) { - if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { + if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); _paths[bestp].path->sent(now); - } else if (_paths[bestp].path->needsHeartbeat(now)) { - _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - _paths[bestp].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); } return true; } else { diff --git a/node/Switch.cpp b/node/Switch.cpp index 7c94d438..04624f03 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -718,7 +718,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) * go somewhere. */ SharedPtr viaPath(peer->getBestPath(now,false)); - if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) { + if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now); viaPath.zero(); diff --git a/node/Topology.cpp b/node/Topology.cpp index bf51b585..be6807da 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -48,33 +48,22 @@ Topology::Topology(const RuntimeEnvironment *renv) : _trustedPathCount(0), _amRoot(false) { - // Get cached world if present - std::string dsWorld(RR->node->dataStoreGet("world")); - World cachedWorld; - if (dsWorld.length() > 0) { - try { - Buffer dswtmp(dsWorld.data(),(unsigned int)dsWorld.length()); - cachedWorld.deserialize(dswtmp,0); - } catch ( ... ) { - cachedWorld = World(); // clear if cached world is invalid - } - } - - // Use default or cached world depending on which is shinier - World defaultWorld; + World defaultPlanet; { Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top } - if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) { - _setWorld(defaultWorld); - if (dsWorld.length() > 0) - RR->node->dataStoreDelete("world"); - } else _setWorld(cachedWorld); -} + addWorld(defaultPlanet,false); -Topology::~Topology() -{ + try { + World cachedPlanet; + std::string buf(RR->node->dataStoreGet("planet")); + if (buf.length() > 0) { + Buffer dswtmp(buf.data(),(unsigned int)buf.length()); + cachedPlanet.deserialize(dswtmp,0); + } + addWorld(cachedPlanet,false); + } catch ( ... ) {} } SharedPtr Topology::addPeer(const SharedPtr &peer) @@ -161,15 +150,14 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi Mutex::Lock _l(_lock); if (_amRoot) { - /* If I am a root server, the "best" root server is the one whose address - * is numerically greater than mine (with wrap at top of list). This - * causes packets searching for a route to pretty much literally - * circumnavigate the globe rather than bouncing between just two. */ - - for(unsigned long p=0;p<_rootAddresses.size();++p) { - if (_rootAddresses[p] == RR->identity.address()) { - for(unsigned long q=1;q<_rootAddresses.size();++q) { - const SharedPtr *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]); + /* If I am a root, pick another root that isn't mine and that + * has a numerically greater ID. This causes packets to roam + * around the top rather than bouncing between just two. */ + + for(unsigned long p=0;p<_upstreamAddresses.size();++p) { + if (_upstreamAddresses[p] == RR->identity.address()) { + for(unsigned long q=1;q<_upstreamAddresses.size();++q) { + const SharedPtr *const nextsn = _peers.get(_upstreamAddresses[(p + q) % _upstreamAddresses.size()]); if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) return *nextsn; } @@ -178,8 +166,7 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi } } else { - /* Otherwise pick the best upstream from among roots and any other - * designated upstreams that we trust. */ + /* Otherwise pick the bestest looking upstream */ unsigned int bestQualityOverall = ~((unsigned int)0); unsigned int bestQualityNotAvoid = ~((unsigned int)0); @@ -219,82 +206,112 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi return SharedPtr(); } -bool Topology::isRoot(const Identity &id) const -{ - Mutex::Lock _l(_lock); - return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()); -} - bool Topology::isUpstream(const Identity &id) const { Mutex::Lock _l(_lock); return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); } -void Topology::setUpstream(const Address &a,bool upstream) +ZT_PeerRole Topology::role(const Address &ztaddr) const { - bool needWhois = false; - { - Mutex::Lock _l(_lock); - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),a) == _rootAddresses.end()) { - if (upstream) { - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),a) == _upstreamAddresses.end()) { - _upstreamAddresses.push_back(a); - const SharedPtr *p = _peers.get(a); - if (!p) { - const Identity id(_getIdentity(a)); - if (id) { - _peers.set(a,SharedPtr(new Peer(RR,RR->identity,id))); - } else { - needWhois = true; // need to do this later due to _lock - } - } - } - } else { - std::vector
ua; - for(std::vector
::iterator i(_upstreamAddresses.begin());i!=_upstreamAddresses.end();++i) { - if (a != *i) - ua.push_back(*i); - } - _upstreamAddresses.swap(ua); - } + Mutex::Lock _l(_lock); + if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + if (i->identity.address() == ztaddr) + return ZT_PEER_ROLE_ROOT; } + return ZT_PEER_ROLE_UPSTREAM; } - if (needWhois) - RR->sw->requestWhois(a); + return ZT_PEER_ROLE_LEAF; } bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const { Mutex::Lock _l(_lock); - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),ztaddr) != _rootAddresses.end()) { - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + // For roots the only permitted addresses are those defined. This adds just a little + // bit of extra security against spoofing, replaying, etc. + if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { + for(std::vector::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) { for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { if (ipaddr.ipsEqual(*e)) return false; } } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator r(m->roots().begin());r!=m->roots().end();++r) { + for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { + if (ipaddr.ipsEqual(*e)) + return false; + } + } + } return true; } return false; } -bool Topology::worldUpdateIfValid(const World &newWorld) +bool Topology::addWorld(const World &newWorld,bool updateOnly) { + if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) + return false; + Mutex::Lock _l(_lock); - if (_world.shouldBeReplacedBy(newWorld,true)) { - _setWorld(newWorld); - try { - Buffer dswtmp; - newWorld.serialize(dswtmp,false); - RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false); - } catch ( ... ) { - RR->node->dataStoreDelete("world"); + + World *existing = (World *)0; + switch(newWorld.type()) { + case World::TYPE_PLANET: + existing = &_planet; + break; + case World::TYPE_MOON: + for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) { + if (m->id() == newWorld.id()) { + existing = &(*m); + break; + } + } + break; + default: + return false; + } + + if (existing) { + if (existing->shouldBeReplacedBy(newWorld)) + *existing = newWorld; + else return false; + } else if ((newWorld.type() == World::TYPE_MOON)&&(!updateOnly)) { + _moons.push_back(newWorld); + existing = &(_moons.back()); + } else return false; + + char savePath[64]; + if (existing->type() == World::TYPE_MOON) + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx",existing->id()); + else Utils::scopy(savePath,sizeof(savePath),"planet"); + try { + Buffer dswtmp; + existing->serialize(dswtmp,false); + RR->node->dataStorePut(savePath,dswtmp.data(),dswtmp.size(),false); + } catch ( ... ) { + RR->node->dataStoreDelete(savePath); + } + + _upstreamAddresses.clear(); + _amRoot = false; + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + if (i->identity == RR->identity) + _amRoot = true; + else _upstreamAddresses.push_back(i->identity.address()); + } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + if (i->identity == RR->identity) + _amRoot = true; + else _upstreamAddresses.push_back(i->identity.address()); } - return true; } + return false; } @@ -334,34 +351,4 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } -void Topology::_setWorld(const World &newWorld) -{ - // assumed _lock is locked (or in constructor) - - std::vector
ua; - for(std::vector
::iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) - ua.push_back(*a); - } - - _world = newWorld; - _rootAddresses.clear(); - _amRoot = false; - - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - _rootAddresses.push_back(r->identity.address()); - if (std::find(ua.begin(),ua.end(),r->identity.address()) == ua.end()) - ua.push_back(r->identity.address()); - if (r->identity.address() == RR->identity.address()) { - _amRoot = true; - } else { - SharedPtr *rp = _peers.get(r->identity.address()); - if (!rp) - _peers.set(r->identity.address(),SharedPtr(new Peer(RR,RR->identity,r->identity))); - } - } - - _upstreamAddresses.swap(ua); -} - } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 90ad7083..47981248 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -50,7 +50,6 @@ class Topology { public: Topology(const RuntimeEnvironment *renv); - ~Topology(); /** * Add a peer to database @@ -141,12 +140,6 @@ public: */ SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); - /** - * @param id Identity to check - * @return True if this is a designated root server in this world - */ - bool isRoot(const Identity &id) const; - /** * @param id Identity to check * @return True if this is a root server or a network preferred relay from one of our networks @@ -154,14 +147,10 @@ public: bool isUpstream(const Identity &id) const; /** - * Set whether or not an address is upstream - * - * If the address is a root this does nothing, since roots are fixed. - * - * @param a Target address - * @param upstream New upstream status + * @param ztaddr ZeroTier address + * @return Peer role for this device */ - void setUpstream(const Address &a,bool upstream); + ZT_PeerRole role(const Address &ztaddr) const; /** * Check for prohibited endpoints @@ -179,6 +168,30 @@ public: */ bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; + /** + * @param eps Hash table to fill with addresses and their stable endpoints + */ + inline void getUpstreamStableEndpoints(Hashtable< Address,std::vector > &eps) const + { + Mutex::Lock _l(_lock); + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + std::vector &ips = eps[i->identity.address()]; + for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { + if (std::find(ips.begin(),ips.end(),*j) == ips.end()) + ips.push_back(*j); + } + } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + std::vector &ips = eps[i->identity.address()]; + for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { + if (std::find(ips.begin(),ips.end(),*j) == ips.end()) + ips.push_back(*j); + } + } + } + } + /** * @return Vector of active upstream addresses (including roots) */ @@ -189,37 +202,38 @@ public: } /** - * @return Current World (copy) + * @return Current planet */ - inline World world() const + inline World planet() const { Mutex::Lock _l(_lock); - return _world; + return _planet; } /** - * @return Current world ID + * @return Current planet's world ID */ - inline uint64_t worldId() const + inline uint64_t planetWorldId() const { - return _world.id(); // safe to read without lock, and used from within eachPeer() so don't lock + return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock } /** - * @return Current world timestamp + * @return Current planet's world timestamp */ - inline uint64_t worldTimestamp() const + inline uint64_t planetWorldTimestamp() const { - return _world.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock + return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock } /** * Validate new world and update if newer and signature is okay * - * @param newWorld Potential new world definition revision - * @return True if an update actually occurred + * @param newWorld A new or updated planet or moon to learn + * @param updateOnly If true only update currently known worlds + * @return True if it was valid and newer than current (or totally new for moons) */ - bool worldUpdateIfValid(const World &newWorld); + bool addWorld(const World &newWorld,bool updateOnly); /** * Clean and flush database @@ -284,9 +298,9 @@ public: } /** - * @return True if I am a root server in the current World + * @return True if I am a root server in a planet or moon */ - inline bool amRoot() const throw() { return _amRoot; } + inline bool amRoot() const { return _amRoot; } /** * Get the outbound trusted path ID for a physical address, or 0 if none @@ -339,7 +353,6 @@ public: private: Identity _getIdentity(const Address &zta); - void _setWorld(const World &newWorld); const RuntimeEnvironment *const RR; @@ -347,14 +360,14 @@ private: InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; unsigned int _trustedPathCount; - World _world; + World _planet; + std::vector< World > _moons; Hashtable< Address,SharedPtr > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - std::vector< Address > _upstreamAddresses; // includes roots - std::vector< Address > _rootAddresses; // only roots - bool _amRoot; // am I a root? + std::vector< Address > _upstreamAddresses; // includes root addresses of both planets and moons + bool _amRoot; // am I a root in a planet or moon? Mutex _lock; }; diff --git a/node/World.hpp b/node/World.hpp index 2f1edb00..c4682a69 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -48,16 +48,6 @@ */ #define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128) -/** - * World ID indicating null / empty World object - */ -#define ZT_WORLD_ID_NULL 0 - -/** - * World ID for a test network with ephemeral or temporary roots - */ -#define ZT_WORLD_ID_TESTNET 1 - /** * World ID for Earth * @@ -90,15 +80,23 @@ namespace ZeroTier { * orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A * world ID for Mars and nearby space is defined but not yet used, and a test * world ID is provided for testing purposes. - * - * If you absolutely must run your own "unofficial" ZeroTier network, please - * define your world IDs above 0xffffffff (4294967295). Code to make a World - * is in mkworld.cpp in the parent directory and must be edited to change - * settings. */ class World { public: + /** + * World type -- do not change IDs + */ + enum Type + { + TYPE_NULL = 0, + TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) + TYPE_MOON = 127 // Moons, which are user-created and many + }; + + /** + * Upstream server definition in world/moon + */ struct Root { Identity identity; @@ -113,45 +111,44 @@ public: * Construct an empty / null World */ World() : - _id(ZT_WORLD_ID_NULL), - _ts(0) {} + _id(0), + _ts(0), + _type(TYPE_NULL) {} /** * @return Root servers for this world and their stable endpoints */ - inline const std::vector &roots() const throw() { return _roots; } + inline const std::vector &roots() const { return _roots; } + + /** + * @return World type: planet or moon + */ + inline Type type() const { return _type; } /** * @return World unique identifier */ - inline uint64_t id() const throw() { return _id; } + inline uint64_t id() const { return _id; } /** * @return World definition timestamp */ - inline uint64_t timestamp() const throw() { return _ts; } + inline uint64_t timestamp() const { return _ts; } /** * Check whether a world update should replace this one * - * A new world update is valid if it is for the same world ID, is newer, - * and is signed by the current world's signing key. If this world object - * is null, it can always be updated. - * * @param update Candidate update - * @param fullSignatureCheck Perform full cryptographic signature check (true == yes, false == skip) - * @return True if update is newer than current and is properly signed + * @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL) */ - inline bool shouldBeReplacedBy(const World &update,bool fullSignatureCheck) + inline bool shouldBeReplacedBy(const World &update) { - if (_id == ZT_WORLD_ID_NULL) + if ((_id == 0)||(_type == TYPE_NULL)) return true; - if ((_id == update._id)&&(_ts < update._ts)) { - if (fullSignatureCheck) { - Buffer tmp; - update.serialize(tmp,true); - return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); - } else return true; + if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) { + Buffer tmp; + update.serialize(tmp,true); + return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); } return false; } @@ -159,14 +156,14 @@ public: /** * @return True if this World is non-empty */ - inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); } + inline operator bool() const { return (_type != TYPE_NULL); } template inline void serialize(Buffer &b,bool forSign = false) const { if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - b.append((uint8_t)0x01); + b.append((uint8_t)_type); b.append((uint64_t)_id); b.append((uint64_t)_ts); b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); @@ -190,14 +187,19 @@ public: _roots.clear(); - if (b[p++] != 0x01) - throw std::invalid_argument("invalid object type"); + switch((Type)b[p++]) { + case TYPE_NULL: _type = TYPE_NULL; break; // shouldn't ever really happen in serialized data but it's not invalid + case TYPE_PLANET: _type = TYPE_PLANET; break; + case TYPE_MOON: _type = TYPE_MOON; break; + default: + throw std::invalid_argument("invalid world type"); + } _id = b.template at(p); p += 8; _ts = b.template at(p); p += 8; memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN; memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - unsigned int numRoots = b[p++]; + const unsigned int numRoots = (unsigned int)b[p++]; if (numRoots > ZT_WORLD_MAX_ROOTS) throw std::invalid_argument("too many roots in World"); for(unsigned int k=0;k _roots; diff --git a/service/OneService.cpp b/service/OneService.cpp index 2932c605..6d9effa1 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -422,7 +422,7 @@ public: try { std::string authToken; { - std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S + "authtoken.secret"); + std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S "authtoken.secret"); if (!OSUtils::readFile(authTokenPath.c_str(),authToken)) { unsigned char foo[24]; Utils::getSecureRandom(foo,sizeof(foo)); @@ -442,7 +442,8 @@ public: authToken = _trimString(authToken); // Clean up any legacy files if present - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + "peers.save").c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S "peers.save").c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S "world").c_str()); { struct ZT_Node_Callbacks cb; @@ -465,7 +466,7 @@ public: unsigned int trustedPathCount = 0; // Old style "trustedpaths" flat file -- will eventually go away - FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S + "trustedpaths").c_str(),"r"); + FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(),"r"); if (trustpaths) { char buf[1024]; while ((fgets(buf,sizeof(buf),trustpaths))&&(trustedPathCount < ZT_MAX_TRUSTED_PATHS)) { @@ -493,7 +494,7 @@ public: // Read local config file Mutex::Lock _l2(_localConfig_m); std::string lcbuf; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "local.conf").c_str(),lcbuf)) { + if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lcbuf)) { try { _localConfig = OSUtils::jsonParse(lcbuf); if (!_localConfig.is_object()) { @@ -581,7 +582,7 @@ public: // Write file containing primary port to be read by CLIs, etc. char portstr[64]; Utils::snprintf(portstr,sizeof(portstr),"%u",_ports[0]); - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr)); + OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S "zerotier-one.port").c_str(),std::string(portstr)); // Attempt to bind to a secondary port chosen from our ZeroTier address. // This exists because there are buggy NATs out there that fail if more @@ -641,8 +642,8 @@ public: _node->setNetconfMaster((void *)_controller); #ifdef ZT_ENABLE_CLUSTER - if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str())) { - _clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str()); + if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S "cluster").c_str())) { + _clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S "cluster").c_str()); if (_clusterDefinition->size() > 0) { std::vector members(_clusterDefinition->members()); for(std::vector::iterator m(members.begin());m!=members.end();++m) { @@ -689,12 +690,12 @@ public: } #endif - _controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str()); + _controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S "ui").c_str()); _controlPlane->addAuthToken(authToken.c_str()); _controlPlane->setController(_controller); { // Remember networks from previous session - std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str())); + std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".conf")) @@ -919,9 +920,6 @@ public: if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { const Address ztaddr(nstr.c_str()); if (ztaddr) { - const std::string rstr(OSUtils::jsonString(v.value()["role"],"")); - _node->setRole(ztaddr.toInt(),((rstr == "upstream")||(rstr == "UPSTREAM")) ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); - const uint64_t ztaddr2 = ztaddr.toInt(); std::vector &v4h = _v4Hints[ztaddr2]; std::vector &v6h = _v6Hints[ztaddr2]; diff --git a/service/README.md b/service/README.md index d2398643..5d54b923 100644 --- a/service/README.md +++ b/service/README.md @@ -19,7 +19,6 @@ Settings available in `local.conf` (this is not valid JSON, and JSON does not al }, "virtual": { /* Settings applied to ZeroTier virtual network devices (VL1) */ "##########": { /* 10-digit ZeroTier address */ - "role": "upstream"|"leaf", /* If upstream, define this as a trusted "federated root" (default is leaf) */ "try": [ "IP/port"/*,...*/ ], /* Hints on where to reach this peer if no upstreams/roots are online */ "blacklist": [ "NETWORK/bits"/*,...*/ ] /* Blacklist a physical path for only this peer. */ } diff --git a/world/mkworld.cpp b/world/mkworld.cpp index 061d6341..2e9e621f 100644 --- a/world/mkworld.cpp +++ b/world/mkworld.cpp @@ -53,11 +53,12 @@ using namespace ZeroTier; class WorldMaker : public World { public: - static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) + static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) { WorldMaker w; w._id = id; w._ts = ts; + w._type = t; w._updateSigningKey = sk; w._roots = roots; @@ -139,7 +140,7 @@ int main(int argc,char **argv) fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); - World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP); + World nw = WorldMaker::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP); Buffer outtmp; nw.serialize(outtmp,false); -- cgit v1.2.3 From f102fd7f92225fbe39ae69dda716530a4e5457e9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 13:50:56 -0800 Subject: Extend in-band world updates to handle moons too. --- node/IncomingPacket.cpp | 40 ++++++++++++++++++++++++++++++---------- node/Packet.hpp | 13 +++++++++---- node/Peer.cpp | 11 +++++++++++ node/Topology.hpp | 9 +++++++++ node/World.hpp | 4 ++++ 5 files changed, 63 insertions(+), 14 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2487a8aa..1a60d13a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -216,6 +216,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut InetAddress externalSurfaceAddress; uint64_t planetWorldId = 0; uint64_t planetWorldTimestamp = 0; + std::vector< std::pair > moonIdsAndTimestamps; { unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); @@ -228,6 +229,16 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut planetWorldId = at(ptr); ptr += 8; planetWorldTimestamp = at(ptr); } + + // Get moon IDs and timestamps if present + if ((ptr + 2) <= size()) { + unsigned int numMoons = at(ptr); ptr += 2; + for(unsigned int i=0;i(at(ptr),at(ptr + 8))); + ptr += 16; + } + } } if (fromAddress != id.address()) { @@ -356,15 +367,24 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut tmpa.serialize(outp); } + const unsigned int worldUpdateSizeAt = outp.size(); + outp.addSize(2); // make room for 16-bit size field if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { - World w(RR->topology->planet()); - const unsigned int sizeAt = outp.size(); - outp.addSize(2); // make room for 16-bit size field - w.serialize(outp,false); - outp.setAt(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); - } else { - outp.append((uint16_t)0); // no planet update needed + RR->topology->planet().serialize(outp,false); + } + if (moonIdsAndTimestamps.size() > 0) { + std::vector moons(RR->topology->moons()); + for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { + for(std::vector< std::pair >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) { + if (i->first == m->id()) { + if (m->timestamp() > i->second) + m->serialize(outp,false); + break; + } + } + } } + outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),now); @@ -411,11 +431,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Handle planet or moon updates + // Handle planet or moon updates if present (older versions don't send this) if ((ptr + 2) <= size()) { - World worldUpdate; const unsigned int worldLen = at(ptr); ptr += 2; - if (worldLen > 0) { + const unsigned int endOfWorlds = ptr + worldLen; + while (ptr < endOfWorlds) { World w; w.deserialize(*this,ptr); RR->topology->addWorld(w,true); diff --git a/node/Packet.hpp b/node/Packet.hpp index 0be19f8a..26e87af8 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -536,12 +536,17 @@ public: * <[1] software major version> * <[1] software minor version> * <[2] software revision> - * <[8] timestamp (ms since epoch)> + * <[8] timestamp for determining latench> * <[...] binary serialized identity (see Identity)> * <[1] destination address type> * [<[...] destination address to which packet was sent>] - * <[8] 64-bit world ID of current world> - * <[8] 64-bit timestamp of current world> + * <[8] 64-bit world ID of current planet> + * <[8] 64-bit timestamp of current planet> + * <[2] 16-bit number of moons> + * [<[1] 8-bit type ID of moon>] + * [<[8] 64-bit world ID of moon>] + * [<[8] 64-bit timestamp of moon>] + * [... additional moons ...] * * 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. @@ -567,7 +572,7 @@ public: * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] * <[2] 16-bit length of world update or 0 if none> - * [[...] world update] + * [[...] updates to planets and/or moons] * * ERROR has no payload. */ diff --git a/node/Peer.cpp b/node/Peer.cpp index 40356034..441a5b33 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -345,6 +345,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); + outp.append((unsigned char)ZT_PROTO_VERSION); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); @@ -352,8 +353,18 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append(now); RR->identity.serialize(outp,false); atAddress.serialize(outp); + outp.append((uint64_t)RR->topology->planetWorldId()); outp.append((uint64_t)RR->topology->planetWorldTimestamp()); + + std::vector moons(RR->topology->moons()); + outp.append((uint16_t)moons.size()); + for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { + outp.append((uint8_t)m->type()); + outp.append((uint64_t)m->id()); + outp.append((uint64_t)m->timestamp()); + } + RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); diff --git a/node/Topology.hpp b/node/Topology.hpp index 47981248..6369c5cd 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -201,6 +201,15 @@ public: return _upstreamAddresses; } + /** + * @return Current moons + */ + inline std::vector moons() const + { + Mutex::Lock _l(_lock); + return _moons; + } + /** * @return Current planet */ diff --git a/node/World.hpp b/node/World.hpp index c4682a69..06dcb981 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -176,6 +176,8 @@ public: for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) ep->serialize(b); } + if (_type == TYPE_MOON) + b.append((uint16_t)0); // no attached dictionary (for future use) if (forSign) b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); } @@ -214,6 +216,8 @@ public: p += r.stableEndpoints.back().deserialize(b,p); } } + if (_type == TYPE_MOON) + p += b.template at(p) + 2; return (p - startAt); } -- cgit v1.2.3 From bc218f9414bd6e4124eb223c7c69c5ac254befff Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 13:52:29 -0800 Subject: little fix --- 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 1a60d13a..28b845b4 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -437,7 +437,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int endOfWorlds = ptr + worldLen; while (ptr < endOfWorlds) { World w; - w.deserialize(*this,ptr); + ptr += w.deserialize(*this,ptr); RR->topology->addWorld(w,true); } } -- cgit v1.2.3 From 9f7919f71f6b4326e73759923d2cf747affc0244 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 15:27:26 -0800 Subject: Add comments to join ("orbit") moons. --- include/ZeroTierOne.h | 22 +++++++++ node/IncomingPacket.cpp | 3 +- node/Node.cpp | 49 ++++++++++++++++++-- node/Node.hpp | 2 + node/Peer.cpp | 9 +++- node/Topology.cpp | 120 ++++++++++++++++++++++++++++++++++++++++-------- node/Topology.hpp | 39 ++++++++++++++-- service/OneService.cpp | 8 ++++ 8 files changed, 222 insertions(+), 30 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index f75638f8..6c50a0a6 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1779,6 +1779,28 @@ enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64 */ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); +/** + * Add or update a moon + * + * Moons are persisted in the data store in moons.d/, so this can persist + * across invocations if the contents of moon.d are scanned and orbit is + * called for each on startup. + * + * @param moonWorldId Moon's world ID + * @param len Length of moonWorld in bytes + * @return Error if moon was invalid or failed to be added + */ +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId); + +/** + * Remove a moon (does nothing if not present) + * + * @param node Node instance + * @param moonWorldId World ID of moon to remove + * @return Error if anything bad happened + */ +ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId); + /** * Get this node's 40-bit ZeroTier address * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 28b845b4..93bf4590 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -444,7 +444,8 @@ 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(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); - peer->addDirectLatencyMeasurment(latency); + if (!hops()) + peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) diff --git a/node/Node.cpp b/node/Node.cpp index 23271cca..f5ee1f9d 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -168,26 +168,35 @@ public: inline void operator()(Topology &t,const SharedPtr &p) { - const std::vector *upstreamStableEndpoints = _upstreams.get(p->address()); - if ((upstreamStableEndpoints)&&(upstreamStableEndpoints->size() > 0)) { + const std::vector *const upstreamStableEndpoints = _upstreams.get(p->address()); + if (upstreamStableEndpoints) { + bool contacted = false; + if (!p->doPingAndKeepalive(_now,AF_INET)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { p->sendHELLO(InetAddress(),addr,_now); + contacted = true; break; } } - } + } else contacted = true; + if (!p->doPingAndKeepalive(_now,AF_INET6)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { p->sendHELLO(InetAddress(),addr,_now); + contacted = true; break; } } - } + } else contacted = true; + + if (!contacted) + p->sendHELLO(InetAddress(),InetAddress(),_now); + lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } else if (p->isActive(_now)) { p->doPingAndKeepalive(_now,-1); @@ -224,7 +233,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) (*n)->requestConfiguration(); - // Run WHOIS on upstreams we don't know about + // Attempt to get identity for any unknown upstreams const std::vector
upstreams(RR->topology->upstreamAddresses()); for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { if (!RR->topology->getPeer(*a)) @@ -323,6 +332,18 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } +ZT_ResultCode Node::orbit(uint64_t moonWorldId) +{ + RR->topology->addMoon(moonWorldId); + return ZT_RESULT_OK; +} + +ZT_ResultCode Node::deorbit(uint64_t moonWorldId) +{ + RR->topology->removeMoon(moonWorldId); + return ZT_RESULT_OK; +} + uint64_t Node::address() const { return RR->identity.address().toInt(); @@ -893,6 +914,24 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint } } +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId) +{ + try { + return reinterpret_cast(node)->orbit(moonWorldId); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId) +{ + try { + return reinterpret_cast(node)->deorbit(moonWorldId); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + uint64_t ZT_Node_address(ZT_Node *node) { return reinterpret_cast(node)->address(); diff --git a/node/Node.hpp b/node/Node.hpp index 662abcb4..3e742092 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -95,6 +95,8 @@ public: ZT_ResultCode leave(uint64_t nwid,void **uptr); ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); + ZT_ResultCode orbit(uint64_t moonWorldId); + ZT_ResultCode deorbit(uint64_t moonWorldId); uint64_t address() const; void status(ZT_NodeStatus *status) const; ZT_PeerList *peers() const; diff --git a/node/Peer.cpp b/node/Peer.cpp index 441a5b33..50135b9f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -366,8 +366,13 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u } RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,false); // HELLO is sent in the clear - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + + if (atAddress) { + outp.armor(_key,false); + RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + } else { + RR->sw->send(outp,false); + } } void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) diff --git a/node/Topology.cpp b/node/Topology.cpp index be6807da..38afacb0 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -48,13 +48,6 @@ Topology::Topology(const RuntimeEnvironment *renv) : _trustedPathCount(0), _amRoot(false) { - World defaultPlanet; - { - Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top - } - addWorld(defaultPlanet,false); - try { World cachedPlanet; std::string buf(RR->node->dataStoreGet("planet")); @@ -64,6 +57,13 @@ Topology::Topology(const RuntimeEnvironment *renv) : } addWorld(cachedPlanet,false); } catch ( ... ) {} + + World defaultPlanet; + { + Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); + defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + } + addWorld(defaultPlanet,false); } SharedPtr Topology::addPeer(const SharedPtr &peer) @@ -287,7 +287,7 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) char savePath[64]; if (existing->type() == World::TYPE_MOON) - Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx",existing->id()); + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",existing->id()); else Utils::scopy(savePath,sizeof(savePath),"planet"); try { Buffer dswtmp; @@ -297,22 +297,71 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) RR->node->dataStoreDelete(savePath); } - _upstreamAddresses.clear(); - _amRoot = false; - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity == RR->identity) - _amRoot = true; - else _upstreamAddresses.push_back(i->identity.address()); + if (existing->type() == World::TYPE_MOON) { + std::vector
cm; + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + if (m->toInt() != ((existing->id() >> 24) & 0xffffffffffULL)) + cm.push_back(*m); + } + _contacingMoons.swap(cm); } + + _memoizeUpstreams(); + + return true; +} + +void Topology::addMoon(const uint64_t id) +{ + char savePath[64]; + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); + + try { + std::string moonBin(RR->node->dataStoreGet(savePath)); + if (moonBin.length() > 1) { + Buffer wtmp(moonBin.data(),(unsigned int)moonBin.length()); + World w; + w.deserialize(wtmp); + if (w.type() == World::TYPE_MOON) { + addWorld(w,false); + return; + } + } + } catch ( ... ) {} + + { + const Address a(id >> 24); + Mutex::Lock _l(_lock); + if (std::find(_contacingMoons.begin(),_contacingMoons.end(),a) == _contacingMoons.end()) + _contacingMoons.push_back(a); + } + RR->node->dataStorePut(savePath,"\0",1,false); // persist that we want to be a member +} + +void Topology::removeMoon(const uint64_t id) +{ + Mutex::Lock _l(_lock); + + std::vector nm; for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity == RR->identity) - _amRoot = true; - else _upstreamAddresses.push_back(i->identity.address()); + if (m->id() != id) { + nm.push_back(*m); + } else { + char savePath[64]; + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); + RR->node->dataStoreDelete(savePath); } } + _moons.swap(nm); - return false; + std::vector
cm; + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + if (m->toInt() != ((id >> 24) & 0xffffffffffULL)) + cm.push_back(*m); + } + _contacingMoons.swap(cm); + + _memoizeUpstreams(); } void Topology::clean(uint64_t now) @@ -351,4 +400,37 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } +void Topology::_memoizeUpstreams() +{ + // assumes _lock is locked + _upstreamAddresses.clear(); + _amRoot = false; + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + if (i->identity == RR->identity) { + _amRoot = true; + } else { + _upstreamAddresses.push_back(i->identity.address()); + SharedPtr &hp = _peers[i->identity.address()]; + if (!hp) { + hp = new Peer(RR,RR->identity,i->identity); + saveIdentity(i->identity); + } + } + } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + if (i->identity == RR->identity) { + _amRoot = true; + } else { + _upstreamAddresses.push_back(i->identity.address()); + SharedPtr &hp = _peers[i->identity.address()]; + if (!hp) { + hp = new Peer(RR,RR->identity,i->identity); + saveIdentity(i->identity); + } + } + } + } +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 6369c5cd..693ae12c 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -169,6 +169,11 @@ public: bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; /** + * This gets the known stable endpoints for any upstream + * + * It also adds empty entries for any upstreams we are attempting to + * contact. + * * @param eps Hash table to fill with addresses and their stable endpoints */ inline void getUpstreamStableEndpoints(Hashtable< Address,std::vector > &eps) const @@ -190,6 +195,8 @@ public: } } } + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) + eps[*m]; } /** @@ -198,7 +205,12 @@ public: inline std::vector
upstreamAddresses() const { Mutex::Lock _l(_lock); - return _upstreamAddresses; + std::vector
u(_upstreamAddresses); + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + if (std::find(u.begin(),u.end(),*m) == u.end()) + u.push_back(*m); + } + return u; } /** @@ -244,6 +256,25 @@ public: */ bool addWorld(const World &newWorld,bool updateOnly); + /** + * Add a moon + * + * This loads it from moons.d if present, and if not adds it to + * a list of moons that we want to contact. It does not actually + * send anything, though this will happen on the next background + * task loop where pings etc. are checked. + * + * @param id Moon ID + */ + void addMoon(const uint64_t id); + + /** + * Remove a moon + * + * @param id Moon's world ID + */ + void removeMoon(const uint64_t id); + /** * Clean and flush database */ @@ -362,6 +393,7 @@ public: private: Identity _getIdentity(const Address &zta); + void _memoizeUpstreams(); const RuntimeEnvironment *const RR; @@ -375,8 +407,9 @@ private: Hashtable< Address,SharedPtr > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - std::vector< Address > _upstreamAddresses; // includes root addresses of both planets and moons - bool _amRoot; // am I a root in a planet or moon? + std::vector
_contacingMoons; + std::vector
_upstreamAddresses; + bool _amRoot; Mutex _lock; }; diff --git a/service/OneService.cpp b/service/OneService.cpp index f6174d42..d2ebe6b7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -702,6 +702,14 @@ public: _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0); } } + { // Load existing moons + std::vector moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str())); + for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { + std::size_t dot = f->find_last_of('.'); + if ((dot == 16)&&(f->substr(16) == ".moon")) + _node->orbit(Utils::hexStrToU64(f->substr(0,dot).c_str())); + } + } _nextBackgroundTaskDeadline = 0; uint64_t clockShouldBe = OSUtils::now(); -- cgit v1.2.3 From 1d775af34a5efa6008256d1bfa742c28ee7152ab Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 15:35:21 -0800 Subject: Fix moon persistence. --- node/IncomingPacket.cpp | 2 +- node/Node.cpp | 2 +- node/Topology.cpp | 43 +++++++++++++++++++++---------------------- node/Topology.hpp | 9 ++++----- 4 files changed, 27 insertions(+), 29 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 93bf4590..a3fbbefc 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -438,7 +438,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p while (ptr < endOfWorlds) { World w; ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(w,true); + RR->topology->addWorld(w); } } diff --git a/node/Node.cpp b/node/Node.cpp index f5ee1f9d..c4a40395 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -220,7 +220,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB try { _lastPingCheck = now; - // Get relays and networks that need config without leaving the mutex locked + // Get networks that need config without leaving mutex locked std::vector< SharedPtr > needConfig; { Mutex::Lock _l(_networks_m); diff --git a/node/Topology.cpp b/node/Topology.cpp index 38afacb0..ece93ee6 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -55,7 +55,7 @@ Topology::Topology(const RuntimeEnvironment *renv) : Buffer dswtmp(buf.data(),(unsigned int)buf.length()); cachedPlanet.deserialize(dswtmp,0); } - addWorld(cachedPlanet,false); + addWorld(cachedPlanet); } catch ( ... ) {} World defaultPlanet; @@ -63,7 +63,7 @@ Topology::Topology(const RuntimeEnvironment *renv) : Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top } - addWorld(defaultPlanet,false); + addWorld(defaultPlanet); } SharedPtr Topology::addPeer(const SharedPtr &peer) @@ -252,7 +252,7 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa return false; } -bool Topology::addWorld(const World &newWorld,bool updateOnly) +bool Topology::addWorld(const World &newWorld) { if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) return false; @@ -280,9 +280,16 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) if (existing->shouldBeReplacedBy(newWorld)) *existing = newWorld; else return false; - } else if ((newWorld.type() == World::TYPE_MOON)&&(!updateOnly)) { + } else if ((newWorld.type() == World::TYPE_MOON)&&(std::find(_contactingMoons.begin(),_contactingMoons.end(),Address(newWorld.id() >> 24)) != _contactingMoons.end())) { _moons.push_back(newWorld); existing = &(_moons.back()); + + std::vector
cm; + for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) { + if (m->toInt() != ((existing->id() >> 24) & 0xffffffffffULL)) + cm.push_back(*m); + } + _contactingMoons.swap(cm); } else return false; char savePath[64]; @@ -297,15 +304,6 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) RR->node->dataStoreDelete(savePath); } - if (existing->type() == World::TYPE_MOON) { - std::vector
cm; - for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { - if (m->toInt() != ((existing->id() >> 24) & 0xffffffffffULL)) - cm.push_back(*m); - } - _contacingMoons.swap(cm); - } - _memoizeUpstreams(); return true; @@ -313,6 +311,13 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) void Topology::addMoon(const uint64_t id) { + { + const Address a(id >> 24); + Mutex::Lock _l(_lock); + if (std::find(_contactingMoons.begin(),_contactingMoons.end(),a) == _contactingMoons.end()) + _contactingMoons.push_back(a); + } + char savePath[64]; Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); @@ -323,18 +328,12 @@ void Topology::addMoon(const uint64_t id) World w; w.deserialize(wtmp); if (w.type() == World::TYPE_MOON) { - addWorld(w,false); + addWorld(w); return; } } } catch ( ... ) {} - { - const Address a(id >> 24); - Mutex::Lock _l(_lock); - if (std::find(_contacingMoons.begin(),_contacingMoons.end(),a) == _contacingMoons.end()) - _contacingMoons.push_back(a); - } RR->node->dataStorePut(savePath,"\0",1,false); // persist that we want to be a member } @@ -355,11 +354,11 @@ void Topology::removeMoon(const uint64_t id) _moons.swap(nm); std::vector
cm; - for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) { if (m->toInt() != ((id >> 24) & 0xffffffffffULL)) cm.push_back(*m); } - _contacingMoons.swap(cm); + _contactingMoons.swap(cm); _memoizeUpstreams(); } diff --git a/node/Topology.hpp b/node/Topology.hpp index 693ae12c..e8efe0db 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -195,7 +195,7 @@ public: } } } - for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) + for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) eps[*m]; } @@ -206,7 +206,7 @@ public: { Mutex::Lock _l(_lock); std::vector
u(_upstreamAddresses); - for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) { if (std::find(u.begin(),u.end(),*m) == u.end()) u.push_back(*m); } @@ -251,10 +251,9 @@ public: * Validate new world and update if newer and signature is okay * * @param newWorld A new or updated planet or moon to learn - * @param updateOnly If true only update currently known worlds * @return True if it was valid and newer than current (or totally new for moons) */ - bool addWorld(const World &newWorld,bool updateOnly); + bool addWorld(const World &newWorld); /** * Add a moon @@ -407,7 +406,7 @@ private: Hashtable< Address,SharedPtr > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - std::vector
_contacingMoons; + std::vector
_contactingMoons; std::vector
_upstreamAddresses; bool _amRoot; -- cgit v1.2.3 From eebd271bb1e3ab0d25f48db07a1a3f1154215bc7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 30 Jan 2017 15:40:22 -0800 Subject: Implement cross cluster sharing of network configs to make clusters able to actually join networks. --- node/Cluster.cpp | 19 +++++++++++++++++++ node/Cluster.hpp | 15 +++++++++++---- node/IncomingPacket.cpp | 9 ++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 2a261e51..55503f63 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -44,6 +44,7 @@ #include "Packet.hpp" #include "Switch.hpp" #include "Node.hpp" +#include "Network.hpp" #include "Array.hpp" namespace ZeroTier { @@ -469,6 +470,15 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) RR->sw->send(outp,true); //TRACE("[%u] proxy send %s to %s length %u",(unsigned int)fromMemberId,Packet::verbString(verb),rcpt.toString().c_str(),len); } break; + + case CLUSTER_MESSAGE_NETWORK_CONFIG: { + const SharedPtr network(RR->node->network(dmsg.at(ptr))); + if (network) { + // Copy into a Packet just to conform to Network API. Eventually + // will want to refactor. + network->handleConfigChunk(Packet(dmsg),ptr); + } + } break; } } catch ( ... ) { TRACE("invalid message of size %u type %d (inner decode), discarding",mlen,mtype); @@ -494,6 +504,15 @@ void Cluster::broadcastHavePeer(const Identity &id) } } +void Cluster::broadcastNetworkConfigChunk(const void *chunk,unsigned int len) +{ + Mutex::Lock _l(_memberIds_m); + for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { + Mutex::Lock _l2(_members[*mid].lock); + _send(*mid,CLUSTER_MESSAGE_NETWORK_CONFIG,chunk,len); + } +} + void Cluster::sendViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite) { if (len > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check diff --git a/node/Cluster.hpp b/node/Cluster.hpp index dafbf425..aba3b8a9 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -216,14 +216,13 @@ public: /** * Replicate a network config for a network we belong to: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network config> - * <[...] serialized network config> + * <[...] network config chunk> * * This is used by clusters to avoid every member having to query * for the same netconf for networks all members belong to. * - * TODO: not implemented yet! + * The first field of a network config chunk is the network ID, + * so this can be checked to look up the network on receipt. */ CLUSTER_MESSAGE_NETWORK_CONFIG = 7 }; @@ -267,6 +266,14 @@ public: */ void broadcastHavePeer(const Identity &id); + /** + * Broadcast a network config chunk to other members of cluster + * + * @param chunk Chunk data + * @param len Length of chunk + */ + void broadcastNetworkConfigChunk(const void *chunk,unsigned int len); + /** * Send this packet via another node in this cluster if another node has this peer * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a3fbbefc..e703af59 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -461,8 +461,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_NETWORK_CONFIG_REQUEST: { const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); - if (network) + if (network) { +#ifdef ZT_ENABLE_CLUSTER + RR->cluster->broadcastNetworkConfigChunk(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PROTO_VERB_OK_IDX_PAYLOAD),size() - ZT_PROTO_VERB_OK_IDX_PAYLOAD); +#endif network->handleConfigChunk(*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); + } } break; case Packet::VERB_MULTICAST_GATHER: { @@ -922,6 +926,9 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared try { const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); if (network) { +#ifdef ZT_ENABLE_CLUSTER + RR->cluster->broadcastNetworkConfigChunk(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD); +#endif const uint64_t configUpdateId = network->handleConfigChunk(*this,ZT_PACKET_IDX_PAYLOAD); if (configUpdateId) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); -- cgit v1.2.3 From ed31cb76d6c8e632456a554b79e05df0593b5e9c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 30 Jan 2017 16:04:05 -0800 Subject: Fix to cluster network configs. --- node/Cluster.cpp | 2 +- node/IncomingPacket.cpp | 13 +++---------- node/Network.cpp | 27 +++++++++++++++++++-------- node/Network.hpp | 6 ++++-- 4 files changed, 27 insertions(+), 21 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 55503f63..b9359dc6 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -476,7 +476,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) if (network) { // Copy into a Packet just to conform to Network API. Eventually // will want to refactor. - network->handleConfigChunk(Packet(dmsg),ptr); + network->handleConfigChunk(0,Address(),Packet(dmsg),ptr); } } break; } diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e703af59..c11b0377 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -461,12 +461,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_NETWORK_CONFIG_REQUEST: { const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); - if (network) { -#ifdef ZT_ENABLE_CLUSTER - RR->cluster->broadcastNetworkConfigChunk(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PROTO_VERB_OK_IDX_PAYLOAD),size() - ZT_PROTO_VERB_OK_IDX_PAYLOAD); -#endif - network->handleConfigChunk(*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); - } + if (network) + network->handleConfigChunk(packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; case Packet::VERB_MULTICAST_GATHER: { @@ -926,10 +922,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared try { const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); if (network) { -#ifdef ZT_ENABLE_CLUSTER - RR->cluster->broadcastNetworkConfigChunk(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD); -#endif - const uint64_t configUpdateId = network->handleConfigChunk(*this,ZT_PACKET_IDX_PAYLOAD); + const uint64_t configUpdateId = network->handleConfigChunk(packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); if (configUpdateId) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((uint8_t)Packet::VERB_ECHO); diff --git a/node/Network.cpp b/node/Network.cpp index ec1bcb33..320dcf39 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -34,6 +34,7 @@ #include "NetworkController.hpp" #include "Node.hpp" #include "Peer.hpp" +#include "Cluster.hpp" // Uncomment to make the rules engine dump trace info to stdout //#define ZT_RULES_ENGINE_DEBUGGING 1 @@ -908,7 +909,7 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.erase(i); } -uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) +uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) { const unsigned int start = ptr; @@ -931,12 +932,12 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) chunkIndex = chunk.at(ptr); ptr += 4; if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end - TRACE("discarded chunk from %s: invalid length or length overflow",chunk.source().toString().c_str()); + TRACE("discarded chunk from %s: invalid length or length overflow",source.toString().c_str()); return 0; } if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: unrecognized signature type",chunk.source().toString().c_str()); + TRACE("discarded chunk from %s: unrecognized signature type",source.toString().c_str()); return 0; } const uint8_t *sig = reinterpret_cast(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN)); @@ -964,30 +965,35 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) // If it's not a duplicate, check chunk signature const Identity controllerId(RR->topology->getIdentity(controller())); if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? - TRACE("unable to verify chunk from %s: don't have controller identity",chunk.source().toString().c_str()); + TRACE("unable to verify chunk from %s: don't have controller identity",source.toString().c_str()); return 0; } if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: signature check failed",chunk.source().toString().c_str()); + TRACE("discarded chunk from %s: signature check failed",source.toString().c_str()); return 0; } +#ifdef ZT_ENABLE_CLUSTER + if (source) + RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); +#endif + // New properly verified chunks can be flooded "virally" through the network if (fastPropagate) { Address *a = (Address *)0; Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ((*a != chunk.source())&&(*a != controller())) { + if ((*a != source)&&(*a != controller())) { Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG); outp.append(reinterpret_cast(chunk.data()) + start,chunk.size() - start); RR->sw->send(outp,true); } } } - } else if (chunk.source() == controller()) { + } else if ((source == controller())||(!source)) { // since old chunks aren't signed, only accept from controller itself (or via cluster backplane) // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers - chunkId = chunk.packetId(); + chunkId = packetId; configUpdateId = chunkId; totalLength = chunkLen; chunkIndex = 0; @@ -999,6 +1005,11 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) c = &(_incomingConfigChunks[i]); } + +#ifdef ZT_ENABLE_CLUSTER + if (source) + RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); +#endif } else { TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); return 0; diff --git a/node/Network.hpp b/node/Network.hpp index 1627be58..85ee6e9a 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -181,11 +181,13 @@ public: * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies * each chunk and once assembled applies the configuration. * - * @param chunk Packet containing chunk + * @param packetId Packet ID or 0 if none (e.g. via cluster path) + * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) + * @param chunk Buffer containing chunk * @param ptr Index of chunk and related fields in packet * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - uint64_t handleConfigChunk(const Packet &chunk,unsigned int ptr); + uint64_t handleConfigChunk(const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); /** * Set network configuration -- cgit v1.2.3 From beb642faa58bb3c2c283a068e6de942bfad2c314 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sat, 4 Feb 2017 10:21:31 -0800 Subject: Stub out CAN_REACH. --- node/Constants.hpp | 5 +++++ node/IncomingPacket.cpp | 7 +++++-- node/Packet.hpp | 29 +++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 6 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index a73d4d89..ab6dfb32 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -214,6 +214,11 @@ */ #define ZT_RECEIVE_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +/** + * Maximum latency to allow for OK(HELLO) before packet is discarded + */ +#define ZT_HELLO_MAX_ALLOWABLE_LATENCY 60000 + /** * Maximum number of ZT hops allowed (this is not IP hops/TTL) * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c11b0377..cecbe2fa 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -413,7 +413,10 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p switch(inReVerb) { case Packet::VERB_HELLO: { - const unsigned int latency = std::min((unsigned int)(RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP)),(unsigned int)0xffff); + const uint64_t latency = RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP); + if (latency > ZT_HELLO_MAX_ALLOWABLE_LATENCY) + return true; + const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; @@ -445,7 +448,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(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); if (!hops()) - peer->addDirectLatencyMeasurment(latency); + peer->addDirectLatencyMeasurment((unsigned int)latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) diff --git a/node/Packet.hpp b/node/Packet.hpp index 26e87af8..a5831c8d 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -536,7 +536,7 @@ public: * <[1] software major version> * <[1] software minor version> * <[2] software revision> - * <[8] timestamp for determining latench> + * <[8] timestamp for determining latency> * <[...] binary serialized identity (see Identity)> * <[1] destination address type> * [<[...] destination address to which packet was sent>] @@ -548,8 +548,9 @@ public: * [<[8] 64-bit timestamp of moon>] * [... additional moons ...] * - * 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. + * Important security note: this message is sent in the clear as it + * contains the initial identity for key agreement. It can therefore + * contain no secrets or sensitive information. * * 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 @@ -1058,7 +1059,27 @@ public: * ZeroTier, Inc. itself. We recommend making up random ones for your own * implementations. */ - VERB_USER_MESSAGE = 0x14 + VERB_USER_MESSAGE = 0x14, + + /** + * Announce that we can reach a particular address: + * <[1] protocol version> + * <[1] software major version> + * <[1] software minor version> + * <[2] software revision> + * <[...] binary serialized identity (see Identity)> + * <[1] 8-bit number of direct addresses where peer is reachable (if any)> + * [... serialized direct addresses ...] + * + * This message can be sent upstream to announce that we can reach a + * particular address. It can optionally report physical paths upstream + * to allow upstream peers to send RENDEZVOUS, but this may be omitted + * if it is not known or if endpoint address privacy is desired. + * + * The receiving peer should confirm this message by sending a message + * downstream and waiting for a reply. + */ + VERB_CAN_REACH = 0x15 }; /** -- cgit v1.2.3 From 3587aa1ea7573198168422be55511b16470fb33f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sat, 4 Feb 2017 13:17:00 -0800 Subject: Add and send certificates of representation to tell people what our valid upstreams are. These are not used yet but will be needed for future privacy modes, etc. Also some cleanup. --- node/Capability.hpp | 9 +- node/CertificateOfRepresentation.hpp | 161 +++++++++++++++++++++++++++++++++++ node/Constants.hpp | 5 ++ node/IncomingPacket.cpp | 9 ++ node/Packet.hpp | 32 ++----- node/Peer.cpp | 7 +- node/Peer.hpp | 11 ++- node/Revocation.hpp | 2 + node/Tag.hpp | 14 +-- node/Topology.cpp | 11 +++ node/Topology.hpp | 21 +++++ 11 files changed, 247 insertions(+), 35 deletions(-) create mode 100644 node/CertificateOfRepresentation.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/node/Capability.hpp b/node/Capability.hpp index 2c829ee5..ddbfd9ee 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -414,7 +414,14 @@ public: throw std::runtime_error("unterminated custody chain"); _custody[i].to = to; _custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + if (b[p++] == 1) { + if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) + throw std::runtime_error("invalid signature"); + p += 2; + memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + } else { + p += 2 + b.template at(p); + } } p += 2 + b.template at(p); diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp new file mode 100644 index 00000000..7c239a96 --- /dev/null +++ b/node/CertificateOfRepresentation.hpp @@ -0,0 +1,161 @@ +/* + * 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_CERTIFICATEOFREPRESENTATION_HPP +#define ZT_CERTIFICATEOFREPRESENTATION_HPP + +#include "Constants.hpp" +#include "Address.hpp" +#include "C25519.hpp" +#include "Identity.hpp" +#include "Buffer.hpp" + +/** + * Maximum number of addresses allowed in a COR + */ +#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS + +namespace ZeroTier { + +class CertificateOfRepresentation +{ +public: + CertificateOfRepresentation() + { + memset(this,0,sizeof(CertificateOfRepresentation)); + } + + inline uint64_t timestamp() const { return _timestamp; } + inline const Address &representative(const unsigned int i) const { return _reps[i]; } + inline unsigned int repCount() const { return _repCount; } + + inline void clear() + { + memset(this,0,sizeof(CertificateOfRepresentation)); + } + + /** + * Add a representative if space remains + * + * @param r Representative to add + * @return True if representative was added + */ + inline bool addRepresentative(const Address &r) + { + if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) { + _reps[_repCount++] = r; + return true; + } + return false; + } + + /** + * Sign this COR with my identity + * + * @param myIdentity This node's identity + * @param ts COR timestamp for establishing new vs. old + */ + inline void sign(const Identity &myIdentity,const uint64_t ts) + { + _timestamp = ts; + Buffer tmp; + this->serialize(tmp,true); + _signature = myIdentity.sign(tmp.data(),tmp.size()); + } + + /** + * Verify this COR's signature + * + * @param senderIdentity Identity of sender of COR + * @return True if COR is valid + */ + inline bool verify(const Identity &senderIdentity) + { + try { + Buffer tmp; + this->serialize(tmp,true); + return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN); + } catch ( ... ) { + return false; + } + } + + template + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + b.append((uint64_t)_timestamp); + b.append((uint16_t)_repCount); + for(unsigned int i=0;i<_repCount;++i) + _reps[i].appendTo(b); + + if (!forSign) { + b.append((uint8_t)1); // 1 == Ed25519 signature + b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + } + + b.append((uint16_t)0); // size of any additional fields, currently 0 + + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + clear(); + + unsigned int p = startAt; + + _timestamp = b.template at(p); p += 8; + const unsigned int rc = b.template at(p); p += 2; + for(unsigned int i=0;i ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc; + + if (b[p++] == 1) { + if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { + p += 2; + memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); + p += ZT_C25519_SIGNATURE_LEN; + } else throw std::runtime_error("invalid signature"); + } else { + p += 2 + b.template at(p); + } + + p += 2 + b.template at(p); + if (p > b.size()) + throw std::runtime_error("extended field overflow"); + + return (p - startAt); + } + +private: + uint64_t _timestamp; + Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES]; + unsigned int _repCount; + C25519::Signature _signature; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Constants.hpp b/node/Constants.hpp index ab6dfb32..be4eb475 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -226,6 +226,11 @@ */ #define ZT_RELAY_MAX_HOPS 3 +/** + * Maximum number of upstreams to use (far more than we should ever need) + */ +#define ZT_MAX_UPSTREAMS 64 + /** * Expire time for multicast 'likes' and indirect multicast memberships in ms */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index cecbe2fa..6b38c4ec 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -37,6 +37,7 @@ #include "Cluster.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" +#include "CertificateOfRepresentation.hpp" #include "Capability.hpp" #include "Tag.hpp" #include "Revocation.hpp" @@ -445,6 +446,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } } + // Handle COR if present (older versions don't send this) + if ((ptr + 2) <= size()) { + //const unsigned int corSize = at(ptr); ptr += 2; + ptr += 2; + CertificateOfRepresentation cor; + ptr += cor.deserialize(*this,ptr); + } + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); if (!hops()) diff --git a/node/Packet.hpp b/node/Packet.hpp index a5831c8d..7d404b25 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -531,7 +531,7 @@ public: VERB_NOP = 0x00, /** - * Announcement of a node's existence: + * Announcement of a node's existence and vitals: * <[1] protocol version> * <[1] software major version> * <[1] software minor version> @@ -547,10 +547,12 @@ public: * [<[8] 64-bit world ID of moon>] * [<[8] 64-bit timestamp of moon>] * [... additional moons ...] + * <[2] 16-bit length of certificate of representation> + * [... certificate of representation ...] * - * Important security note: this message is sent in the clear as it - * contains the initial identity for key agreement. It can therefore - * contain no secrets or sensitive information. + * HELLO is sent in the clear, and therefore cannot contain anything + * secret or highly confidential. It should contain nothing that is + * not either public or easy to obtain via other means. * * 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 @@ -1059,27 +1061,7 @@ public: * ZeroTier, Inc. itself. We recommend making up random ones for your own * implementations. */ - VERB_USER_MESSAGE = 0x14, - - /** - * Announce that we can reach a particular address: - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[...] binary serialized identity (see Identity)> - * <[1] 8-bit number of direct addresses where peer is reachable (if any)> - * [... serialized direct addresses ...] - * - * This message can be sent upstream to announce that we can reach a - * particular address. It can optionally report physical paths upstream - * to allow upstream peers to send RENDEZVOUS, but this may be omitted - * if it is not known or if endpoint address privacy is desired. - * - * The receiving peer should confirm this message by sending a message - * downstream and waiting for a reply. - */ - VERB_CAN_REACH = 0x15 + VERB_USER_MESSAGE = 0x14 }; /** diff --git a/node/Peer.cpp b/node/Peer.cpp index 129c2437..bb6b945d 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -38,6 +38,7 @@ namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : + RR(renv), _lastReceive(0), _lastNontrivialReceive(0), _lastTriedMemorizedPath(0), @@ -50,7 +51,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), - RR(renv), _remoteClusterOptimal4(0), _vProto(0), _vMajor(0), @@ -365,6 +365,11 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append((uint64_t)m->timestamp()); } + const unsigned int corSizeAt = outp.size(); + outp.addSize(2); + RR->topology->appendCertificateOfRepresentation(outp); + outp.setAt(corSizeAt,(uint16_t)((outp.size() - corSizeAt) - 2)); + RR->node->expectReplyTo(outp.packetId()); if (atAddress) { diff --git a/node/Peer.hpp b/node/Peer.hpp index bbe13a2e..e79739a3 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -439,7 +439,9 @@ private: } uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; - uint8_t _remoteClusterOptimal6[16]; + + const RuntimeEnvironment *RR; + uint64_t _lastReceive; // direct or indirect uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. uint64_t _lastTriedMemorizedPath; @@ -452,13 +454,17 @@ private: uint64_t _lastComRequestSent; uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; - const RuntimeEnvironment *RR; + + uint8_t _remoteClusterOptimal6[16]; uint32_t _remoteClusterOptimal4; + uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; + Identity _id; + struct { uint64_t lastReceive; SharedPtr path; @@ -467,6 +473,7 @@ private: #endif } _paths[ZT_MAX_PEER_NETWORK_PATHS]; Mutex _paths_m; + unsigned int _numPaths; unsigned int _latency; unsigned int _directPathPushCutoffCount; diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 18916985..bc290e75 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -152,6 +152,8 @@ public: memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; } else throw std::runtime_error("invalid signature"); + } else { + p += 2 + b.template at(p); } p += 2 + b.template at(p); diff --git a/node/Tag.hpp b/node/Tag.hpp index 97228157..65348200 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -148,12 +148,14 @@ public: _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - if (b[p++] != 1) - throw std::runtime_error("unrecognized signature type"); - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature length"); - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + if (b[p++] == 1) { + if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) + throw std::runtime_error("invalid signature length"); + p += 2; + memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + } else { + p += 2 + b.template at(p); + } p += 2 + b.template at(p); if (p > b.size()) diff --git a/node/Topology.cpp b/node/Topology.cpp index 0cd3db9e..f19d8656 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -417,6 +417,7 @@ void Topology::_memoizeUpstreams() // assumes _upstreams_m and _peers_m are locked _upstreamAddresses.clear(); _amRoot = false; + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { if (i->identity == RR->identity) { _amRoot = true; @@ -429,6 +430,7 @@ void Topology::_memoizeUpstreams() } } } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { if (i->identity == RR->identity) { @@ -443,6 +445,15 @@ void Topology::_memoizeUpstreams() } } } + + std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); + + _cor.clear(); + for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { + if (!_cor.addRepresentative(*a)) + break; + } + _cor.sign(RR->identity,RR->node->now()); } } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 78dc0fe8..dca35789 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -38,6 +38,7 @@ #include "InetAddress.hpp" #include "Hashtable.hpp" #include "World.hpp" +#include "CertificateOfRepresentation.hpp" namespace ZeroTier { @@ -383,6 +384,25 @@ public: _trustedPathCount = count; } + /** + * @return Current certificate of representation (copy) + */ + inline CertificateOfRepresentation certificateOfRepresentation() const + { + Mutex::Lock _l(_upstreams_m); + return _cor; + } + + /** + * @param buf Buffer to receive COR + */ + template + void appendCertificateOfRepresentation(Buffer &buf) + { + Mutex::Lock _l(_upstreams_m); + _cor.serialize(buf); + } + private: Identity _getIdentity(const Address &zta); void _memoizeUpstreams(); @@ -404,6 +424,7 @@ private: std::vector _moons; std::vector
_contactingMoons; std::vector
_upstreamAddresses; + CertificateOfRepresentation _cor; bool _amRoot; Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; -- cgit v1.2.3 From 43182f8f57483a47f1b44cdcf9dbb5387511afc2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sun, 5 Feb 2017 16:19:03 -0800 Subject: Docs, code cleanup, and protect the extra new fields of HELLO with encryption as a precaution. --- doc/MANUAL.md | 12 +++---- node/Constants.hpp | 5 +++ node/Identity.cpp | 6 ++-- node/IncomingPacket.cpp | 88 +++++++++++++++++++++++++++++-------------------- node/Node.cpp | 4 +-- node/Packet.cpp | 62 +++++++++++++++++++++++----------- node/Packet.hpp | 31 ++++++++++++++--- node/Peer.cpp | 22 ++++++++----- node/Peer.hpp | 3 +- node/Salsa20.cpp | 4 +-- node/Salsa20.hpp | 34 +++---------------- node/Switch.cpp | 2 +- node/Utils.cpp | 4 +-- 13 files changed, 162 insertions(+), 115 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/doc/MANUAL.md b/doc/MANUAL.md index e84146f3..e0117a4d 100644 --- a/doc/MANUAL.md +++ b/doc/MANUAL.md @@ -72,13 +72,11 @@ This manual describes the design and operation of ZeroTier and its associated se ZeroTier is a smart Ethernet switch for planet Earth. -We've re-thought networking from first principles to deliver the flat end-to-end simplicity of the original pre-NAT pre-mobility Internet in a way that meets the security and mobility requirements of the 21st century. ZeroTier transforms the world into a unified modern data center where VPN, SDN, SD-WAN, and application peer to peer networking converge and where the distinction between the cloud and the endpoint largely disappears. All the complexity of managing these networking aspects as disparate systems is replaced by the simplicity of a single virtual cloud. +We've re-thought networking from first principles to deliver the flat end-to-end simplicity of the original pre-NAT pre-mobility Internet, yet in a way that meets the security and mobility needs of the 21st century. ZeroTier erases the distinction between cloud and endpoint, bringing modern data center SDN to every device regardless of its physical location. The objectives of VPN, SDN, SD-WAN, and application peer to peer networking can all be achieved together and with reduced complexity. -At first some users struggle with this paradigm, finding it difficult to forget the fragmentation and complexity that has accreted around networking over the past decade or two. We urge skeptical users to just try it and see how many networking acronyms vanish before their eyes. +Unlike most networking products it won't take you hours, days, or weeks to test or deploy ZeroTier. Most of the time everything just works with zero configuration, and most users with some level of TCP/IP knowledge can get up and running in minutes. More advanced features like federation, rules, micro-segmentation, capability based security credentials, network monitoring, and clustering are available but you don't need to worry about them until they're needed. -Unlike most networking products it won't take you hours, days, or weeks to test or deploy ZeroTier. Most of the time everything just works with zero configuration, and most users with some level of TCP/IP knowledge can get up and running in minutes. More advanced features like rules, micro-segmentation, capability based security credentials, network monitoring, and clustering are available but you don't need to worry about them until they're needed. - -The first section (2) of this guide explains ZeroTier's design and operation in detail and is written for users with at least an intermediate knowledge of topics like TCP/IP and Ethernet networking. Reading and understanding everything in it is not mandatory but we've written it as a deep technical dive as serious IT users typically like to understand the systems they deploy and use. Sections 3 and 4 deal more concretely with the ZeroTier One endpoint service software and how to deploy for common use cases. +The first section (2) of this guide explains ZeroTier's design and operation in detail and is written for users with at least an intermediate knowledge of topics like TCP/IP and Ethernet networking. All of it is not required reading for most users, but we've created a deep technical dive to satisfy the desire of IT professionals to understand the systems that they use. Sections 3 and 4 deal more concretely with the ZeroTier One endpoint service software and how to deploy for common use cases. ## **2.** How it Works @@ -88,7 +86,7 @@ ZeroTier is comprised of two closely coupled but conceptually distinct layers [i To build a planetary data center we first had to begin with the wiring. Tunneling into the Earth's core and putting a giant wire closet down there wasn't an option, so we decided to use software to build virtual wires over the existing Internet instead. -In conventional networks L1 (OSI layer 1) refers to the actual CAT5/CAT6 cables or wireless radio channels over which data is carried and the physical transciever chips that modulate and demodulate it. VL1 is a peer to peer network that does the same thing by using encryption, authentication, and a lot of networking tricks to create virtual wires as needed. +In conventional networks L1 (OSI layer 1) refers to the actual CAT5/CAT6 cables or wireless radio channels over which data is carried and the physical transciever chips that modulate and demodulate it. VL1 is a peer to peer network that does the same thing by using encryption, authentication, and a lot of networking tricks to create virtual wires on a dyniamic as-needed basis. ### **2.1.1.** Network Topology and Peer Discovery @@ -98,7 +96,7 @@ Roots run the same software as regular endpoints but reside at fast stable locat There is only one planet. Earth's root servers are operated by ZeroTier, Inc. as a free service. Their presence defines and unifies the global data center where we all reside. -Users can create "moons." These nominate additional roots for redundancy or performance. The most common reasons for doing this are to eliminate hard dependency on ZeroTier's third party infrastructure or to designate local roots inside your building or cloud so ZeroTier can work without a connection to the Internet. Moons are by no means required and most of our users get by just fine without them. +Moons can be created by users. These nominate additional roots for redundancy or performance. The most common reasons for doing this are to eliminate hard dependency on ZeroTier's third party infrastructure or to designate local roots inside your building or cloud so ZeroTier can work without a connection to the Internet. Moons are by no means required and most of our users get by just fine without them. When peers start out they have no direct links to one another, only upstream to roots. Every peer on VL1 possesses a globally unique address, but unlike IP addresses these are opaque cryptographic identifiers that encode no routing information. To communicate peers first send packets "up" the tree, and as these packets traverse the network they trigger the opportunistic creation of direct links along the way. The tree is constantly trying to "collapse itself" to optimize itself to the pattern of traffic it is carrying. diff --git a/node/Constants.hpp b/node/Constants.hpp index be4eb475..3bda3805 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -293,6 +293,11 @@ */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) +/** + * Send a full HELLO every this often (ms) + */ +#define ZT_PEER_SEND_FULL_HELLO_EVERY (ZT_PEER_PING_PERIOD * 2) + /** * How often to retry expired paths that we're still remembering */ diff --git a/node/Identity.cpp b/node/Identity.cpp index 05b70873..89fdb836 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -46,7 +46,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub // but is not what we want for sequential memory-harndess. memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); Salsa20 s20(digest,256,(char *)digest + 32); - s20.encrypt20((char *)genmem,(char *)genmem,64); + s20.crypt20((char *)genmem,(char *)genmem,64); for(unsigned long i=64;i(ZT_PROTO_VERB_HELLO_IDX_REVISION); const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - Identity id; - InetAddress externalSurfaceAddress; - uint64_t planetWorldId = 0; - uint64_t planetWorldTimestamp = 0; - std::vector< std::pair > moonIdsAndTimestamps; - { - unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - - // Get external surface address if present (was not in old versions) - if (ptr < size()) - ptr += externalSurfaceAddress.deserialize(*this,ptr); - - // Get primary planet world ID and world timestamp if present - if ((ptr + 16) <= size()) { - planetWorldId = at(ptr); ptr += 8; - planetWorldTimestamp = at(ptr); - } - - // Get moon IDs and timestamps if present - if ((ptr + 2) <= size()) { - unsigned int numMoons = at(ptr); ptr += 2; - for(unsigned int i=0;i(at(ptr),at(ptr + 8))); - ptr += 16; - } - } + if (protoVersion < ZT_PROTO_VERSION_MIN) { + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; } + Identity id; + unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str()); - return true; - } - if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; } @@ -324,6 +299,43 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // VALID -- if we made it here, packet passed identity and authenticity checks! + // Get external surface address if present (was not in old versions) + InetAddress externalSurfaceAddress; + if (ptr < size()) + ptr += externalSurfaceAddress.deserialize(*this,ptr); + + // Get primary planet world ID and world timestamp if present + uint64_t planetWorldId = 0; + uint64_t planetWorldTimestamp = 0; + if ((ptr + 16) <= size()) { + planetWorldId = at(ptr); ptr += 8; + planetWorldTimestamp = at(ptr); + } + + std::vector< std::pair > moonIdsAndTimestamps; + if (ptr < size()) { + // Remainder of packet, if present, is encrypted + cryptField(peer->key(),ptr,size() - ptr); + + // Get moon IDs and timestamps if present + if ((ptr + 2) <= size()) { + unsigned int numMoons = at(ptr); ptr += 2; + for(unsigned int i=0;i(at(ptr),at(ptr + 8))); + ptr += 16; + } + } + + // Handle COR if present (older versions don't send this) + if ((ptr + 2) <= size()) { + //const unsigned int corSize = at(ptr); ptr += 2; + ptr += 2; + CertificateOfRepresentation cor; + ptr += cor.deserialize(*this,ptr); + } + } + // Learn our external surface address from other peers to help us negotiate symmetric NATs // and detect changes to our global IP that can trigger path renegotiation. if ((externalSurfaceAddress)&&(hops() == 0)) @@ -337,6 +349,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + if (protoVersion >= 5) { _path->address().serialize(outp); } else { @@ -387,6 +400,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut } outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); + const unsigned int corSizeAt = outp.size(); + outp.addSize(2); + RR->topology->appendCertificateOfRepresentation(outp); + outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); + outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),now); @@ -586,7 +604,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1155,7 +1173,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now,false); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1174,7 +1192,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now,false); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } diff --git a/node/Node.cpp b/node/Node.cpp index 3d5b5c3d..b8e74a52 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -70,7 +70,7 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : Utils::getSecureRandom(foo,32); _prng.init(foo,256,foo); memset(_prngStream,0,sizeof(_prngStream)); - _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); std::string idtmp(dataStoreGet("identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { @@ -686,7 +686,7 @@ uint64_t Node::prng() { unsigned int p = (++_prngStreamPtr % ZT_NODE_PRNG_BUF_SIZE); if (!p) - _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); return _prngStream[p]; } diff --git a/node/Packet.cpp b/node/Packet.cpp index 05fe8dd9..a1bb3132 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -18,9 +18,21 @@ #include #include +#include +#include +#include #include "Packet.hpp" +#ifdef _MSC_VER +#define FORCE_INLINE static __forceinline +#include +#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#else +#define FORCE_INLINE static inline +#endif + namespace ZeroTier { /************************************************************************** */ @@ -367,7 +379,7 @@ LZ4_decompress_*_continue() : #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -#include +//#include typedef struct { uint32_t hashTable[LZ4_HASH_SIZE_U32]; @@ -536,6 +548,7 @@ union LZ4_streamDecode_u { /*-************************************ * Compiler Options **************************************/ +#if 0 #ifdef _MSC_VER /* Visual Studio */ # define FORCE_INLINE static __forceinline # include @@ -550,6 +563,7 @@ union LZ4_streamDecode_u { # define FORCE_INLINE static # endif #endif /* _MSC_VER */ +#endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) @@ -564,38 +578,39 @@ union LZ4_streamDecode_u { /*-************************************ * Memory routines **************************************/ -#include /* malloc, calloc, free */ +//#include /* malloc, calloc, free */ #define ALLOCATOR(n,s) calloc(n,s) #define FREEMEM free -#include /* memset, memcpy */ +//#include /* memset, memcpy */ #define MEM_INIT memset /*-************************************ * Basic Types **************************************/ -#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# include +//#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +//# include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; -#else +/*#else typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; typedef unsigned long long U64; - typedef size_t uptrval; /* generally true, except OpenVMS-64 */ -#endif + typedef size_t uptrval; +#endif */ -#if defined(__x86_64__) - typedef U64 reg_t; /* 64-bits in x32 mode */ -#else - typedef size_t reg_t; /* 32-bits in x32 mode */ -#endif +typedef uintptr_t reg_t; +//#if defined(__x86_64__) +// typedef U64 reg_t; /* 64-bits in x32 mode */ +//#else +// typedef size_t reg_t; /* 32-bits in x32 mode */ +//#endif /*-************************************ * Reading and writing into memory @@ -606,7 +621,6 @@ static unsigned LZ4_isLittleEndian(void) return one.c[0]; } - #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) /* lie to the compiler about data alignment; use with caution */ @@ -1975,10 +1989,10 @@ void Packet::armor(const void *key,bool encryptPayload) // MAC key is always the first 32 bytes of the Salsa20 key stream // This is the same construction DJB's NaCl library uses - s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey)); + s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); if (encryptPayload) - s20.encrypt12(payload,payload,payloadLen); + s20.crypt12(payload,payload,payloadLen); Poly1305::compute(mac,payload,payloadLen,macKey); memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8); @@ -1995,20 +2009,30 @@ bool Packet::dearmor(const void *key) if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/); + Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); - s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey)); + s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); Poly1305::compute(mac,payload,payloadLen,macKey); if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8)) return false; if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) - s20.decrypt12(payload,payload,payloadLen); + s20.crypt12(payload,payload,payloadLen); return true; } else return false; // unrecognized cipher suite } +void Packet::cryptField(const void *key,unsigned int start,unsigned int len) +{ + unsigned char mangledKey[32]; + uint64_t iv = Utils::hton((uint64_t)start ^ at(ZT_PACKET_IDX_IV)); + _salsa20MangleKey((const unsigned char *)key,mangledKey); + Salsa20 s20(mangledKey,256,&iv); + unsigned char *const ptr = field(start,len); + s20.crypt12(ptr,ptr,len); +} + bool Packet::compress() { unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; diff --git a/node/Packet.hpp b/node/Packet.hpp index 7d404b25..03bd9ed3 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -542,6 +542,7 @@ public: * [<[...] destination address to which packet was sent>] * <[8] 64-bit world ID of current planet> * <[8] 64-bit timestamp of current planet> + * [... remainder if packet is encrypted using cryptField() ...] * <[2] 16-bit number of moons> * [<[1] 8-bit type ID of moon>] * [<[8] 64-bit world ID of moon>] @@ -550,9 +551,10 @@ public: * <[2] 16-bit length of certificate of representation> * [... certificate of representation ...] * - * HELLO is sent in the clear, and therefore cannot contain anything - * secret or highly confidential. It should contain nothing that is - * not either public or easy to obtain via other means. + * The initial fields of HELLO are sent in the clear. Fields after the + * planet definition (which are common knowledge) are however encrypted + * using the cryptField() function. The packet is MAC'd as usual using + * the same MAC construct as other packets. * * 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 @@ -566,7 +568,7 @@ public: * 0x04 - 6-byte IPv4 UDP address/port -- format: <[4] IP>, <[2] port> * 0x06 - 18-byte IPv6 UDP address/port -- format: <[16] IP>, <[2] port> * - * OK payload: + * OK payload (note that OK is encrypted): * <[8] timestamp (echoed from original HELLO)> * <[1] protocol version (of responder)> * <[1] software major version (of responder)> @@ -576,6 +578,8 @@ public: * [<[...] destination address>] * <[2] 16-bit length of world update or 0 if none> * [[...] updates to planets and/or moons] + * <[2] 16-bit length of certificate of representation (of responder)> + * [... certificate of representation ...] * * ERROR has no payload. */ @@ -1348,6 +1352,25 @@ public: */ bool dearmor(const void *key); + /** + * Encrypt/decrypt a separately armored portion of a packet + * + * This keys using the same key in the same way as armor/dearmor, but + * uses a different IV computed from the packet's IV plus the starting + * point index. + * + * This currently uses Salsa20/12, but any message that uses this should + * incorporate a cipher selector to permit this to be changed later. + * + * This is currently only used to mask portions of HELLO as an extra + * security precation since most of that message is sent in the clear. + * + * @param key 32-byte key + * @param start Start of encrypted portion + * @param len Length of encrypted portion + */ + void cryptField(const void *key,unsigned int start,unsigned int len); + /** * Attempt to compress payload if not already (must be unencrypted) * diff --git a/node/Peer.cpp b/node/Peer.cpp index bb6b945d..338bea10 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -203,7 +203,7 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(path->localAddress(),path->address(),now); + attemptToContactAt(path->localAddress(),path->address(),now,true); path->sent(now); } } @@ -357,6 +357,8 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append((uint64_t)RR->topology->planetWorldId()); outp.append((uint64_t)RR->topology->planetWorldTimestamp()); + const unsigned int startCryptedPortionAt = outp.size(); + std::vector moons(RR->topology->moons()); outp.append((uint16_t)moons.size()); for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { @@ -368,21 +370,23 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u const unsigned int corSizeAt = outp.size(); outp.addSize(2); RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)((outp.size() - corSizeAt) - 2)); + outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); + + outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); RR->node->expectReplyTo(outp.packetId()); if (atAddress) { - outp.armor(_key,false); + outp.armor(_key,false); // false == don't encrypt full payload, but add MAC RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { - RR->sw->send(outp,false); + RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) +void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello) { - if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { + if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true); @@ -398,7 +402,7 @@ void Peer::tryMemorizedPath(uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(_id.address(),-1,mp)) - attemptToContactAt(InetAddress(),mp,now); + attemptToContactAt(InetAddress(),mp,now,true); } } @@ -420,7 +424,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false); _paths[bestp].path->sent(now); } return true; @@ -444,7 +448,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now); + attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false); _paths[p].path->sent(now); _paths[p].lastReceive = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index e79739a3..a3ec0088 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -161,8 +161,9 @@ public: * @param localAddr Local address * @param atAddress Destination address * @param now Current time + * @param sendFullHello If true, always send a full HELLO instead of just an ECHO */ - void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello); /** * Try a memorized or statically defined path if any are known diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp index 3aa19ac6..1a4641f7 100644 --- a/node/Salsa20.cpp +++ b/node/Salsa20.cpp @@ -123,7 +123,7 @@ void Salsa20::init(const void *key,unsigned int kbits,const void *iv) #endif } -void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes) +void Salsa20::crypt12(const void *in,void *out,unsigned int bytes) throw() { uint8_t tmp[64]; @@ -623,7 +623,7 @@ void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes) } } -void Salsa20::encrypt20(const void *in,void *out,unsigned int bytes) +void Salsa20::crypt20(const void *in,void *out,unsigned int bytes) throw() { uint8_t tmp[64]; diff --git a/node/Salsa20.hpp b/node/Salsa20.hpp index 7e4c1e53..6405d450 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -56,51 +56,25 @@ public: throw(); /** - * Encrypt data using Salsa20/12 + * Encrypt/decrypt data using Salsa20/12 * * @param in Input data * @param out Output buffer * @param bytes Length of data */ - void encrypt12(const void *in,void *out,unsigned int bytes) + void crypt12(const void *in,void *out,unsigned int bytes) throw(); /** - * Encrypt data using Salsa20/20 + * Encrypt/decrypt data using Salsa20/20 * * @param in Input data * @param out Output buffer * @param bytes Length of data */ - void encrypt20(const void *in,void *out,unsigned int bytes) + void crypt20(const void *in,void *out,unsigned int bytes) throw(); - /** - * Decrypt data - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - inline void decrypt12(const void *in,void *out,unsigned int bytes) - throw() - { - encrypt12(in,out,bytes); - } - - /** - * Decrypt data - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - inline void decrypt20(const void *in,void *out,unsigned int bytes) - throw() - { - encrypt20(in,out,bytes); - } - private: union { #ifdef ZT_SALSA20_SSE diff --git a/node/Switch.cpp b/node/Switch.cpp index a769faea..346091a4 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -777,7 +777,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { #endif if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now); + peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false); viaPath->sent(now); } #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Utils.cpp b/node/Utils.cpp index 06b726cc..247dd54a 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -182,7 +182,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) #else // not __WINDOWS__ - static char randomBuf[131072]; + static char randomBuf[65536]; static unsigned int randomPtr = sizeof(randomBuf); static int devURandomFd = -1; @@ -215,7 +215,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) #endif // __WINDOWS__ or not - s20.encrypt12(buf,buf,bytes); + s20.crypt12(buf,buf,bytes); } bool Utils::scopy(char *dest,unsigned int len,const char *src) -- cgit v1.2.3 From f85a630a6438261fd21c149f32a77283e7bf76a3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Feb 2017 07:17:45 -0800 Subject: Docs and a small build fix in debug mode. --- node/IncomingPacket.cpp | 35 ++++++++++++++--------------- node/Packet.hpp | 58 ++++++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 47 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1bf70d68..49bcae11 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -212,15 +212,13 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut 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); + Identity id; + unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); if (protoVersion < ZT_PROTO_VERSION_MIN) { TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } - - Identity id; - unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - if (fromAddress != id.address()) { TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; @@ -301,8 +299,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // Get external surface address if present (was not in old versions) InetAddress externalSurfaceAddress; - if (ptr < size()) + if (ptr < size()) { ptr += externalSurfaceAddress.deserialize(*this,ptr); + if ((externalSurfaceAddress)&&(hops() == 0)) + RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + } // Get primary planet world ID and world timestamp if present uint64_t planetWorldId = 0; @@ -329,17 +330,16 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // Handle COR if present (older versions don't send this) if ((ptr + 2) <= size()) { - //const unsigned int corSize = at(ptr); ptr += 2; - ptr += 2; - CertificateOfRepresentation cor; - ptr += cor.deserialize(*this,ptr); + if (at(ptr) > 0) { + CertificateOfRepresentation cor; + ptr += 2; + ptr += cor.deserialize(*this,ptr); + } else ptr += 2; } } - // Learn our external surface address from other peers to help us negotiate symmetric NATs - // and detect changes to our global IP that can trigger path renegotiation. - if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + // Send OK(HELLO) with an echo of the packet's timestamp and some of the same + // information about us: version, sent-to address, etc. Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_HELLO); @@ -466,10 +466,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p // Handle COR if present (older versions don't send this) if ((ptr + 2) <= size()) { - //const unsigned int corSize = at(ptr); ptr += 2; - ptr += 2; - CertificateOfRepresentation cor; - ptr += cor.deserialize(*this,ptr); + if (at(ptr) > 0) { + CertificateOfRepresentation cor; + ptr += 2; + ptr += cor.deserialize(*this,ptr); + } else ptr += 2; } TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); diff --git a/node/Packet.hpp b/node/Packet.hpp index 03bd9ed3..4859dafd 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -538,8 +538,7 @@ public: * <[2] software revision> * <[8] timestamp for determining latency> * <[...] binary serialized identity (see Identity)> - * <[1] destination address type> - * [<[...] destination address to which packet was sent>] + * <[...] physical destination address of packet> * <[8] 64-bit world ID of current planet> * <[8] 64-bit timestamp of current planet> * [... remainder if packet is encrypted using cryptField() ...] @@ -547,40 +546,39 @@ public: * [<[1] 8-bit type ID of moon>] * [<[8] 64-bit world ID of moon>] * [<[8] 64-bit timestamp of moon>] - * [... additional moons ...] + * [... additional moon type/ID/timestamp tuples ...] * <[2] 16-bit length of certificate of representation> * [... certificate of representation ...] * - * The initial fields of HELLO are sent in the clear. Fields after the - * planet definition (which are common knowledge) are however encrypted - * using the cryptField() function. The packet is MAC'd as usual using - * the same MAC construct as other packets. - * - * 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): - * 0x00 - None -- no destination address data present - * 0x01 - Ethernet address -- format: <[6] Ethernet MAC> - * 0x04 - 6-byte IPv4 UDP address/port -- format: <[4] IP>, <[2] port> - * 0x06 - 18-byte IPv6 UDP address/port -- format: <[16] IP>, <[2] port> - * - * OK payload (note that OK is encrypted): - * <[8] timestamp (echoed from original HELLO)> - * <[1] protocol version (of responder)> - * <[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>] - * <[2] 16-bit length of world update or 0 if none> + * HELLO is sent in the clear as it is how peers share their identity + * public keys. A few additional fields are sent in the clear too, but + * these are things that are public info or are easy to determine. As + * of 1.2.0 we have added a few more fields, but since these could have + * the potential to be sensitive we introduced the encryption of the + * remainder of the packet. See cryptField(). Packet MAC is still + * performed of course, so authentication occurs as normal. + * + * Destination address is the actual wire address to which the packet + * was sent. See InetAddress::serialize() for format. + * + * OK payload: + * <[8] HELLO timestamp field echo> + * <[1] protocol version> + * <[1] software major version> + * <[1] software minor version> + * <[2] software revision> + * <[...] physical destination address of packet> + * <[2] 16-bit length of world update(s) or 0 if none> * [[...] updates to planets and/or moons] - * <[2] 16-bit length of certificate of representation (of responder)> + * <[2] 16-bit length of certificate of representation> * [... certificate of representation ...] * + * With the exception of the timestamp, the other fields pertain to the + * respondent who is sending OK and are not echoes. + * + * Note that OK is fully encrypted so no selective cryptField() of + * potentially sensitive fields is needed. + * * ERROR has no payload. */ VERB_HELLO = 0x01, -- cgit v1.2.3 From 435e4c4695024702a8493e66d802652f116741f8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Feb 2017 12:06:10 -0800 Subject: Fix HELLO parse 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 49bcae11..ddf93244 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -310,7 +310,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut uint64_t planetWorldTimestamp = 0; if ((ptr + 16) <= size()) { planetWorldId = at(ptr); ptr += 8; - planetWorldTimestamp = at(ptr); + planetWorldTimestamp = at(ptr); ptr += 8; } std::vector< std::pair > moonIdsAndTimestamps; -- cgit v1.2.3 From cdc289fa9c5d7d19990c14946ede5f3642e235d2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 7 Feb 2017 14:06:40 -0800 Subject: Tags work. --- node/IncomingPacket.cpp | 2 +- node/Membership.cpp | 7 ++----- node/Network.cpp | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ddf93244..02d6a140 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -78,7 +78,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } if (!uncompress()) { - TRACE("dropped packet from %s(%s), compressed data invalid",sourceAddress.toString().c_str(),_path->address().toString().c_str()); + TRACE("dropped packet from %s(%s), compressed data invalid (verb may be %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),(unsigned int)verb()); return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index 6307b85d..8c6dab64 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -83,11 +83,8 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now outp.addSize(2); unsigned int thisPacketTagCount = 0; while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 32) < ZT_PROTO_MAX_PACKET_LENGTH)) { - if ( (_localTags[tagPtr].id != nconf.tags[tagPtr].id()) || ((now - _localTags[tagPtr].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { - sendTags[tagPtr]->serialize(outp); - ++thisPacketTagCount; - } - ++tagPtr; + sendTags[tagPtr++]->serialize(outp); + ++thisPacketTagCount; } outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount); diff --git a/node/Network.cpp b/node/Network.cpp index 7412e3e7..461e1c20 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -371,11 +371,11 @@ static _doZtFilterResult _doZtFilter( //thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((frameData[1] & 0xfc) >> 2)); const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipTos,(unsigned int)((frameData[1] & 0xfc) >> 2),(unsigned int)thisRuleMatches); + FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv6) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipTos,(unsigned int)((trafficClass & 0xfc) >> 2),(unsigned int)thisRuleMatches); + FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); -- cgit v1.2.3 From 42f28bce52c3342e3aac68488260a02c71691177 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 13 Feb 2017 09:03:48 -0800 Subject: Cleanup and make moons (federated roots) a little easier to deal with. --- include/ZeroTierOne.h | 9 +++-- node/IncomingPacket.cpp | 1 + node/Node.cpp | 39 ++++++++++--------- node/Node.hpp | 2 +- node/Topology.cpp | 99 +++++++++++++++++++++++++++++------------------- node/Topology.hpp | 27 +++++-------- node/Utils.cpp | 19 +++------- node/Utils.hpp | 3 +- service/ControlPlane.cpp | 4 +- service/OneService.cpp | 2 +- 10 files changed, 107 insertions(+), 98 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 583f9b6a..38ae7d8a 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -835,9 +835,9 @@ enum ZT_VirtualNetworkConfigOperation */ enum ZT_PeerRole { - ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_UPSTREAM = 1, // moon root - ZT_PEER_ROLE_ROOT = 2 // planetary root + ZT_PEER_ROLE_LEAF = 0, // ordinary node + ZT_PEER_ROLE_MOON = 1, // moon root + ZT_PEER_ROLE_PLANET = 2 // planetary root }; /** @@ -1790,10 +1790,11 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint * called for each on startup. * * @param moonWorldId Moon's world ID + * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition * @param len Length of moonWorld in bytes * @return Error if moon was invalid or failed to be added */ -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId); +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId,uint64_t moonSeed); /** * Remove a moon (does nothing if not present) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 02d6a140..8836df9f 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -568,6 +568,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr id.serialize(outp,false); ++count; } else { + // Request unknown WHOIS from upstream from us (if we have one) RR->sw->requestWhois(addr); #ifdef ZT_ENABLE_CLUSTER // Distribute WHOIS queries across a cluster if we do not know the ID. diff --git a/node/Node.cpp b/node/Node.cpp index b8e74a52..388a4fb2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -156,23 +156,26 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : lastReceiveFromUpstream(0), RR(renv), + _upstreamsToContact(upstreamsToContact), _now(now), _bestCurrentUpstream(RR->topology->getUpstreamPeer()) { - RR->topology->getUpstreamStableEndpoints(_upstreams); } uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay inline void operator()(Topology &t,const SharedPtr &p) { - const std::vector *const upstreamStableEndpoints = _upstreams.get(p->address()); + const std::vector *const upstreamStableEndpoints = _upstreamsToContact.get(p->address()); if (upstreamStableEndpoints) { bool contacted = false; + // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow + // them to perform three way handshake introductions for both stacks. + if (!p->doPingAndKeepalive(_now,AF_INET)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; @@ -183,7 +186,6 @@ public: } } } else contacted = true; - if (!p->doPingAndKeepalive(_now,AF_INET6)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; @@ -202,6 +204,7 @@ public: } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); + _upstreamsToContact.erase(p->address()); // erase from upstreams to contact so that we can WHOIS those that remain } else if (p->isActive(_now)) { p->doPingAndKeepalive(_now,-1); } @@ -209,9 +212,9 @@ public: private: const RuntimeEnvironment *RR; + Hashtable< Address,std::vector > &_upstreamsToContact; const uint64_t _now; const SharedPtr _bestCurrentUpstream; - Hashtable< Address,std::vector > _upstreams; }; ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) @@ -238,17 +241,19 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) (*n)->requestConfiguration(); - // Attempt to get identity for any unknown upstreams - const std::vector
upstreams(RR->topology->upstreamAddresses()); - for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { - if (!RR->topology->getPeer(*a)) - RR->sw->requestWhois(*a); - } - // Do pings and keepalives - _PingPeersThatNeedPing pfunc(RR,now); + Hashtable< Address,std::vector > upstreamsToContact; + RR->topology->getUpstreamsToContact(upstreamsToContact); + _PingPeersThatNeedPing pfunc(RR,upstreamsToContact,now); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); + // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) + Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); + Address *upstreamAddress = (Address *)0; + std::vector *upstreamStableEndpoints = (std::vector *)0; + while (i.next(upstreamAddress,upstreamStableEndpoints)) + RR->sw->requestWhois(*upstreamAddress); + // Update online status, post status change as event const bool oldOnline = _online; _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); @@ -337,9 +342,9 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } -ZT_ResultCode Node::orbit(uint64_t moonWorldId) +ZT_ResultCode Node::orbit(uint64_t moonWorldId,uint64_t moonSeed) { - RR->topology->addMoon(moonWorldId); + RR->topology->addMoon(moonWorldId,Address(moonSeed)); return ZT_RESULT_OK; } @@ -919,10 +924,10 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint } } -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId) +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId,uint64_t moonSeed) { try { - return reinterpret_cast(node)->orbit(moonWorldId); + return reinterpret_cast(node)->orbit(moonWorldId,moonSeed); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } diff --git a/node/Node.hpp b/node/Node.hpp index 3e742092..d83ce968 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -95,7 +95,7 @@ public: ZT_ResultCode leave(uint64_t nwid,void **uptr); ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode orbit(uint64_t moonWorldId); + ZT_ResultCode orbit(uint64_t moonWorldId,uint64_t moonSeed); ZT_ResultCode deorbit(uint64_t moonWorldId); uint64_t address() const; void status(ZT_NodeStatus *status) const; diff --git a/node/Topology.cpp b/node/Topology.cpp index 0fde63dc..d85b6a7d 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -27,19 +27,31 @@ namespace ZeroTier { -// 2015-11-16 -- The Fabulous Four (should have named them after Beatles!) -//#define ZT_DEFAULT_WORLD_LENGTH 494 -//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0x11,0x70,0xb2,0xfb,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x80,0x31,0xa4,0x65,0x95,0x45,0x06,0x1c,0xfb,0xc2,0x4e,0x5d,0xe7,0x0a,0x40,0x7a,0x97,0xce,0x36,0xa2,0x3d,0x05,0xca,0x87,0xc7,0x59,0x27,0x5c,0x8b,0x0d,0x4c,0xb4,0xbb,0x26,0x2f,0x77,0x17,0x5e,0xb7,0x4d,0xb8,0xd3,0xb4,0xe9,0x23,0x5d,0xcc,0xa2,0x71,0xa8,0xdf,0xf1,0x23,0xa3,0xb2,0x66,0x74,0xea,0xe5,0xdc,0x8d,0xef,0xd3,0x0a,0xa9,0xac,0xcb,0xda,0x93,0xbd,0x6c,0xcd,0x43,0x1d,0xa7,0x98,0x6a,0xde,0x70,0xc0,0xc6,0x1c,0xaf,0xf0,0xfd,0x7f,0x8a,0xb9,0x76,0x13,0xe1,0xde,0x4f,0xf3,0xd6,0x13,0x04,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x01,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x01,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09}; - -// 2015-11-20 -- Alice and Bob are live, and we're now IPv6 dual-stack! -//#define ZT_DEFAULT_WORLD_LENGTH 792 -//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0x26,0x6f,0x7c,0x8a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0xe8,0x0a,0xf5,0xbc,0xf8,0x3d,0x97,0xcd,0xc3,0xf8,0xe2,0x41,0x16,0x42,0x0f,0xc7,0x76,0x8e,0x07,0xf3,0x7e,0x9e,0x7d,0x1b,0xb3,0x23,0x21,0x79,0xce,0xb9,0xd0,0xcb,0xb5,0x94,0x7b,0x89,0x21,0x57,0x72,0xf6,0x70,0xa1,0xdd,0x67,0x38,0xcf,0x45,0x45,0xc2,0x8d,0x46,0xec,0x00,0x2c,0xe0,0x2a,0x63,0x3f,0x63,0x8d,0x33,0x08,0x51,0x07,0x77,0x81,0x5b,0x32,0x49,0xae,0x87,0x89,0xcf,0x31,0xaa,0x41,0xf1,0x52,0x97,0xdc,0xa2,0x55,0xe1,0x4a,0x6e,0x3c,0x04,0xf0,0x4f,0x8a,0x0e,0xe9,0xca,0xec,0x24,0x30,0x04,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09}; - -// 2015-12-17 -- Old New York root is dead, old SF still alive -//#define ZT_DEFAULT_WORLD_LENGTH 732 -//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0xb1,0x7e,0x39,0x9d,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x8a,0xca,0xf2,0x3d,0x71,0x2e,0xc2,0x39,0x45,0x66,0xb3,0xe9,0x39,0x79,0xb1,0x55,0xc4,0xa9,0xfc,0xbc,0xfc,0x55,0xaf,0x8a,0x2f,0x38,0xc8,0xcd,0xe9,0x02,0x5b,0x86,0xa9,0x72,0xf7,0x16,0x00,0x35,0xb7,0x84,0xc9,0xfc,0xe4,0xfa,0x96,0x8b,0xf4,0x1e,0xba,0x60,0x9f,0x85,0x14,0xc2,0x07,0x4b,0xfd,0xd1,0x6c,0x19,0x69,0xd3,0xf9,0x09,0x9c,0x9d,0xe3,0xb9,0x8f,0x11,0x78,0x71,0xa7,0x4a,0x05,0xd8,0xcc,0x60,0xa2,0x06,0x66,0x9f,0x47,0xc2,0x71,0xb8,0x54,0x80,0x9c,0x45,0x16,0x10,0xa9,0xd0,0xbd,0xf7,0x03,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x02,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0xc5,0xf0,0x01,0x27,0x09}; - -// 2016-01-13 -- Old San Francisco 1.0.1 root is dead, now we're just on Alice and Bob! +/* + * 2016-01-13 ZeroTier planet definition for the third planet of Sol: + * + * There are two roots, each of which is a cluster spread across multiple + * continents and providers. They are named Alice and Bob after the + * canonical example names used in cryptography. + * + * Alice: + * + * root-alice-ams-01: Amsterdam, Netherlands + * root-alice-joh-01: Johannesburg, South Africa + * root-alice-nyc-01: New York, New York, USA + * root-alice-sao-01: Sao Paolo, Brazil + * root-alice-sfo-01: San Francisco, California, USA + * root-alice-sgp-01: Singapore + * + * Bob: + * + * root-bob-dfw-01: Dallas, Texas, USA + * root-bob-fra-01: Frankfurt, Germany + * root-bob-par-01: Paris, France + * root-bob-syd-01: Sydney, Australia + * root-bob-tok-01: Tokyo, Japan + * root-bob-tor-01: Toronto, Canada + */ #define ZT_DEFAULT_WORLD_LENGTH 634 static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x52,0x3c,0x32,0x50,0x1a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x4a,0xf7,0x86,0xa8,0x40,0xd6,0x52,0xea,0xae,0x9e,0x7a,0xbf,0x4c,0x97,0x66,0xab,0x2d,0x6f,0xaf,0xc9,0x2b,0x3a,0xff,0xed,0xd6,0x30,0x3e,0xc4,0x6a,0x65,0xf2,0xbd,0x83,0x52,0xf5,0x40,0xe9,0xcc,0x0d,0x6e,0x89,0x3f,0x9a,0xa0,0xb8,0xdf,0x42,0xd2,0x2f,0x84,0xe6,0x03,0x26,0x0f,0xa8,0xe3,0xcc,0x05,0x05,0x03,0xef,0x12,0x80,0x0d,0xce,0x3e,0xb6,0x58,0x3b,0x1f,0xa8,0xad,0xc7,0x25,0xf9,0x43,0x71,0xa7,0x5c,0x9a,0xc7,0xe1,0xa3,0xb8,0x88,0xd0,0x71,0x6c,0x94,0x99,0x73,0x41,0x0b,0x1b,0x48,0x84,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09}; @@ -219,9 +231,9 @@ ZT_PeerRole Topology::role(const Address &ztaddr) const if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { if (i->identity.address() == ztaddr) - return ZT_PEER_ROLE_ROOT; + return ZT_PEER_ROLE_PLANET; } - return ZT_PEER_ROLE_UPSTREAM; + return ZT_PEER_ROLE_MOON; } return ZT_PEER_ROLE_LEAF; } @@ -290,22 +302,32 @@ bool Topology::addWorld(const World &newWorld) if (existing->shouldBeReplacedBy(newWorld)) *existing = newWorld; else return false; - } else if ((newWorld.type() == World::TYPE_MOON)&&(std::find(_contactingMoons.begin(),_contactingMoons.end(),Address(newWorld.id() >> 24)) != _contactingMoons.end())) { - _moons.push_back(newWorld); - existing = &(_moons.back()); - - std::vector
cm; - for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) { - if (m->toInt() != ((existing->id() >> 24) & 0xffffffffffULL)) - cm.push_back(*m); + } else if (newWorld.type() == World::TYPE_MOON) { + for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { + if (m->first == newWorld.id()) { + for(std::vector::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { + if (r->identity.address() == m->second) { + _moonSeeds.erase(m); + m = _moonSeeds.end(); // cause outer loop to terminate + _moons.push_back(newWorld); + existing = &(_moons.back()); + break; + } + } + } } - _contactingMoons.swap(cm); - } else return false; + if (!existing) + return false; + } else { + return false; + } char savePath[64]; - if (existing->type() == World::TYPE_MOON) + if (existing->type() == World::TYPE_MOON) { Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",existing->id()); - else Utils::scopy(savePath,sizeof(savePath),"planet"); + } else { + Utils::scopy(savePath,sizeof(savePath),"planet"); + } try { Buffer dswtmp; existing->serialize(dswtmp,false); @@ -319,15 +341,8 @@ bool Topology::addWorld(const World &newWorld) return true; } -void Topology::addMoon(const uint64_t id) +void Topology::addMoon(const uint64_t id,const Address &seed) { - { - const Address a(id >> 24); - Mutex::Lock _l(_upstreams_m); - if (std::find(_contactingMoons.begin(),_contactingMoons.end(),a) == _contactingMoons.end()) - _contactingMoons.push_back(a); - } - char savePath[64]; Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); @@ -344,7 +359,11 @@ void Topology::addMoon(const uint64_t id) } } catch ( ... ) {} - RR->node->dataStorePut(savePath,"\0",1,false); // persist that we want to be a member + if (seed) { + Mutex::Lock _l(_upstreams_m); + if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair(id,seed)) == _moonSeeds.end()) + _moonSeeds.push_back(std::pair(id,seed)); + } } void Topology::removeMoon(const uint64_t id) @@ -364,12 +383,12 @@ void Topology::removeMoon(const uint64_t id) } _moons.swap(nm); - std::vector
cm; - for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) { - if (m->toInt() != ((id >> 24) & 0xffffffffffULL)) + std::vector< std::pair > cm; + for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { + if (m->first != id) cm.push_back(*m); } - _contactingMoons.swap(cm); + _moonSeeds.swap(cm); _memoizeUpstreams(); } diff --git a/node/Topology.hpp b/node/Topology.hpp index dca35789..2465de64 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -170,14 +170,11 @@ public: bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; /** - * This gets the known stable endpoints for any upstream - * - * It also adds empty entries for any upstreams we are attempting to - * contact. + * Gets upstreams to contact and their stable endpoints (if known) * * @param eps Hash table to fill with addresses and their stable endpoints */ - inline void getUpstreamStableEndpoints(Hashtable< Address,std::vector > &eps) const + inline void getUpstreamsToContact(Hashtable< Address,std::vector > &eps) const { Mutex::Lock _l(_upstreams_m); for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { @@ -196,8 +193,8 @@ public: } } } - for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) - eps[*m]; + for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) + eps[m->second]; } /** @@ -206,12 +203,7 @@ public: inline std::vector
upstreamAddresses() const { Mutex::Lock _l(_upstreams_m); - std::vector
u(_upstreamAddresses); - for(std::vector
::const_iterator m(_contactingMoons.begin());m!=_contactingMoons.end();++m) { - if (std::find(u.begin(),u.end(),*m) == u.end()) - u.push_back(*m); - } - return u; + return _upstreamAddresses; } /** @@ -260,13 +252,12 @@ public: * Add a moon * * This loads it from moons.d if present, and if not adds it to - * a list of moons that we want to contact. It does not actually - * send anything, though this will happen on the next background - * task loop where pings etc. are checked. + * a list of moons that we want to contact. * * @param id Moon ID + * @param seed If non-NULL, an address of any member of the moon to contact */ - void addMoon(const uint64_t id); + void addMoon(const uint64_t id,const Address &seed); /** * Remove a moon @@ -422,7 +413,7 @@ private: World _planet; std::vector _moons; - std::vector
_contactingMoons; + std::vector< std::pair > _moonSeeds; std::vector
_upstreamAddresses; CertificateOfRepresentation _cor; bool _amRoot; diff --git a/node/Utils.cpp b/node/Utils.cpp index 00b0db06..fb448dd6 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -47,21 +47,14 @@ namespace ZeroTier { const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; -static void _Utils_doBurn(char *ptr,unsigned int len) +// Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers. +static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len) { - for(unsigned int i=0;irole) { case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break; - case ZT_PEER_ROLE_UPSTREAM: prole = "UPSTREAM"; break; - case ZT_PEER_ROLE_ROOT: prole = "ROOT"; break; + case ZT_PEER_ROLE_MOON: prole = "MOON"; break; + case ZT_PEER_ROLE_PLANET: prole = "PLANET"; break; } Utils::snprintf(json,sizeof(json), diff --git a/service/OneService.cpp b/service/OneService.cpp index 9a1503e5..6465463b 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -707,7 +707,7 @@ public: for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".moon")) - _node->orbit(Utils::hexStrToU64(f->substr(0,dot).c_str())); + _node->orbit(Utils::hexStrToU64(f->substr(0,dot).c_str()),0); } } -- cgit v1.2.3 From e4b6611201bb2f69c05a4c104c77d6ec51c2c38b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 13 Feb 2017 09:46:34 -0800 Subject: Only accept world updates from upstreams. --- node/IncomingPacket.cpp | 20 ++++++++++++-------- node/Peer.cpp | 8 +++++++- node/Topology.hpp | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 9 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 8836df9f..c6cf7f36 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -449,22 +449,26 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p InetAddress externalSurfaceAddress; unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; - // Get reported external surface address if present (was not on old versions) + // Get reported external surface address if present if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Handle planet or moon updates if present (older versions don't send this) + // Handle planet or moon updates if present if ((ptr + 2) <= size()) { const unsigned int worldLen = at(ptr); ptr += 2; - const unsigned int endOfWorlds = ptr + worldLen; - while (ptr < endOfWorlds) { - World w; - ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(w); + if (RR->topology->isUpstream(peer->identity())) { + const unsigned int endOfWorlds = ptr + worldLen; + while (ptr < endOfWorlds) { + World w; + ptr += w.deserialize(*this,ptr); + RR->topology->addWorld(w); + } + } else { + ptr += worldLen; } } - // Handle COR if present (older versions don't send this) + // Handle certificate of representation if present if ((ptr + 2) <= size()) { if (at(ptr) > 0) { CertificateOfRepresentation cor; diff --git a/node/Peer.cpp b/node/Peer.cpp index 338bea10..d5847092 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -360,12 +360,18 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u const unsigned int startCryptedPortionAt = outp.size(); std::vector moons(RR->topology->moons()); - outp.append((uint16_t)moons.size()); + std::vector moonsWanted(RR->topology->moonsWanted()); + outp.append((uint16_t)(moons.size() + moonsWanted.size())); for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { outp.append((uint8_t)m->type()); outp.append((uint64_t)m->id()); outp.append((uint64_t)m->timestamp()); } + for(std::vector::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) { + outp.append((uint8_t)World::TYPE_MOON); + outp.append(*m); + outp.append((uint64_t)0); + } const unsigned int corSizeAt = outp.size(); outp.addSize(2); diff --git a/node/Topology.hpp b/node/Topology.hpp index 2465de64..35f98ccc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -215,6 +215,20 @@ public: return _moons; } + /** + * @return Moon IDs we are waiting for from seeds + */ + inline std::vector moonsWanted() const + { + Mutex::Lock _l(_upstreams_m); + std::vector mw; + for(std::vector< std::pair >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { + if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) + mw.push_back(s->first); + } + return mw; + } + /** * @return Current planet */ -- cgit v1.2.3 From 969e09210d89f4cecf01920d8315f984ea59245e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 13 Feb 2017 16:14:48 -0800 Subject: Fix loading of existing moons. --- node/IncomingPacket.cpp | 2 +- node/Topology.cpp | 33 +++++++++++++++++++-------------- node/Topology.hpp | 3 ++- 3 files changed, 22 insertions(+), 16 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c6cf7f36..41a06937 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -461,7 +461,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p while (ptr < endOfWorlds) { World w; ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(w); + RR->topology->addWorld(w,false); } } else { ptr += worldLen; diff --git a/node/Topology.cpp b/node/Topology.cpp index 8d0ed929..7d0b0550 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -67,7 +67,7 @@ Topology::Topology(const RuntimeEnvironment *renv) : Buffer dswtmp(buf.data(),(unsigned int)buf.length()); cachedPlanet.deserialize(dswtmp,0); } - addWorld(cachedPlanet); + addWorld(cachedPlanet,false); } catch ( ... ) {} World defaultPlanet; @@ -75,7 +75,7 @@ Topology::Topology(const RuntimeEnvironment *renv) : Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top } - addWorld(defaultPlanet); + addWorld(defaultPlanet,false); } SharedPtr Topology::addPeer(const SharedPtr &peer) @@ -273,7 +273,7 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa return false; } -bool Topology::addWorld(const World &newWorld) +bool Topology::addWorld(const World &newWorld,bool alwaysAcceptNew) { if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) return false; @@ -303,15 +303,20 @@ bool Topology::addWorld(const World &newWorld) *existing = newWorld; else return false; } else if (newWorld.type() == World::TYPE_MOON) { - for(std::vector< std::pair >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - if (m->first == newWorld.id()) { - for(std::vector::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { - if (r->identity.address() == m->second) { - _moonSeeds.erase(m); - m = _moonSeeds.end(); // cause outer loop to terminate - _moons.push_back(newWorld); - existing = &(_moons.back()); - break; + if (alwaysAcceptNew) { + _moons.push_back(newWorld); + existing = &(_moons.back()); + } else { + for(std::vector< std::pair >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { + if (m->first == newWorld.id()) { + for(std::vector::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { + if (r->identity.address() == m->second) { + _moonSeeds.erase(m); + m = _moonSeeds.end(); // cause outer loop to terminate + _moons.push_back(newWorld); + existing = &(_moons.back()); + break; + } } } } @@ -352,8 +357,8 @@ void Topology::addMoon(const uint64_t id,const Address &seed) Buffer wtmp(moonBin.data(),(unsigned int)moonBin.length()); World w; w.deserialize(wtmp); - if (w.type() == World::TYPE_MOON) { - addWorld(w); + if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { + addWorld(w,true); return; } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 35f98ccc..39367d6e 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -258,9 +258,10 @@ public: * Validate new world and update if newer and signature is okay * * @param newWorld A new or updated planet or moon to learn + * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one * @return True if it was valid and newer than current (or totally new for moons) */ - bool addWorld(const World &newWorld); + bool addWorld(const World &newWorld,bool alwaysAcceptNew); /** * Add a moon -- cgit v1.2.3 From af4e79735c3f97d4228472077bcd5d2ddfb2cb93 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 13 Feb 2017 16:38:21 -0800 Subject: Fix "orbit" semantics. Federation works. --- node/IncomingPacket.cpp | 8 ++++---- node/Topology.cpp | 15 ++++++++++++++- node/Topology.hpp | 6 ++++++ 3 files changed, 24 insertions(+), 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 41a06937..b077f7e2 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -455,16 +455,16 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p // Handle planet or moon updates if present if ((ptr + 2) <= size()) { - const unsigned int worldLen = at(ptr); ptr += 2; - if (RR->topology->isUpstream(peer->identity())) { - const unsigned int endOfWorlds = ptr + worldLen; + const unsigned int worldsLen = at(ptr); ptr += 2; + if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) { + const unsigned int endOfWorlds = ptr + worldsLen; while (ptr < endOfWorlds) { World w; ptr += w.deserialize(*this,ptr); RR->topology->addWorld(w,false); } } else { - ptr += worldLen; + ptr += worldsLen; } } diff --git a/node/Topology.cpp b/node/Topology.cpp index 7d0b0550..5abc4df0 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -225,6 +225,18 @@ bool Topology::isUpstream(const Identity &id) const return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); } +bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const +{ + Mutex::Lock _l(_upstreams_m); + if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end()) + return true; + for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { + if (s->second == addr) + return true; + } + return false; +} + ZT_PeerRole Topology::role(const Address &ztaddr) const { Mutex::Lock _l(_upstreams_m); @@ -312,12 +324,13 @@ bool Topology::addWorld(const World &newWorld,bool alwaysAcceptNew) for(std::vector::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { if (r->identity.address() == m->second) { _moonSeeds.erase(m); - m = _moonSeeds.end(); // cause outer loop to terminate _moons.push_back(newWorld); existing = &(_moons.back()); break; } } + if (existing) + break; } } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 39367d6e..37615b49 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -147,6 +147,12 @@ public: */ bool isUpstream(const Identity &id) const; + /** + * @param addr Address to check + * @return True if we should accept a world update from this address + */ + bool shouldAcceptWorldUpdateFrom(const Address &addr) const; + /** * @param ztaddr ZeroTier address * @return Peer role for this device -- cgit v1.2.3 From 10185e92faa77a4b032a27a7c01b4186727b91b9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 23 Feb 2017 11:47:36 -0800 Subject: Certificate of ownership -- used to secure against IP address spoofing, especially for IPv4 and regular IPv6. --- controller/EmbeddedNetworkController.cpp | 9 ++ include/ZeroTierOne.h | 5 + node/Capability.hpp | 1 - node/CertificateOfOwnership.cpp | 46 ++++++ node/CertificateOfOwnership.hpp | 251 +++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 19 +++ node/Membership.cpp | 164 +++++++++++++++----- node/Membership.hpp | 81 +++++----- node/Network.hpp | 11 ++ node/NetworkConfig.cpp | 25 ++- node/NetworkConfig.hpp | 21 ++- node/Packet.hpp | 2 + node/Revocation.hpp | 5 +- node/Tag.hpp | 3 +- objects.mk | 1 + 15 files changed, 550 insertions(+), 94 deletions(-) create mode 100644 node/CertificateOfOwnership.cpp create mode 100644 node/CertificateOfOwnership.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index ca548fd4..78a9b7c7 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1706,6 +1706,15 @@ void EmbeddedNetworkController::_request( } } + // Issue a certificate of ownership for all static IPs + if (nc.staticIpCount) { + nc.certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1); + for(unsigned int i=0;i(p); p += 8; _ts = b.template at(p); p += 8; _id = b.template at(p); p += 4; diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp new file mode 100644 index 00000000..8305c489 --- /dev/null +++ b/node/CertificateOfOwnership.cpp @@ -0,0 +1,46 @@ +/* + * 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 . + */ + +#include "CertificateOfOwnership.hpp" +#include "RuntimeEnvironment.hpp" +#include "Identity.hpp" +#include "Topology.hpp" +#include "Switch.hpp" +#include "Network.hpp" + +namespace ZeroTier { + +int CertificateOfOwnership::verify(const RuntimeEnvironment *RR) const +{ + if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) + return -1; + const Identity id(RR->topology->getIdentity(_signedBy)); + if (!id) { + RR->sw->requestWhois(_signedBy); + return 1; + } + try { + Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp; + this->serialize(tmp,true); + return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); + } catch ( ... ) { + return -1; + } +} + +} // namespace ZeroTier diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp new file mode 100644 index 00000000..69b26aec --- /dev/null +++ b/node/CertificateOfOwnership.hpp @@ -0,0 +1,251 @@ +/* + * 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_CERTIFICATEOFOWNERSHIP_HPP +#define ZT_CERTIFICATEOFOWNERSHIP_HPP + +#include +#include +#include +#include + +#include "Constants.hpp" +#include "C25519.hpp" +#include "Address.hpp" +#include "Identity.hpp" +#include "Buffer.hpp" +#include "InetAddress.hpp" +#include "MAC.hpp" + +// Max things per CertificateOfOwnership +#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16 + +// Maximum size of a thing's value field in bytes +#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16 + +namespace ZeroTier { + +class RuntimeEnvironment; + +/** + * Certificate indicating ownership of a network identifier + */ +class CertificateOfOwnership +{ +public: + enum Thing + { + THING_NULL = 0, + THING_MAC_ADDRESS = 1, + THING_IPV4_ADDRESS = 2, + THING_IPV6_ADDRESS = 3 + }; + + CertificateOfOwnership() : + _networkId(0), + _ts(0), + _id(0), + _thingCount(0) + { + } + + CertificateOfOwnership(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id) : + _networkId(nwid), + _ts(ts), + _flags(0), + _id(id), + _thingCount(0), + _issuedTo(issuedTo) + { + } + + inline uint64_t networkId() const { return _networkId; } + inline uint64_t timestamp() const { return _ts; } + inline uint32_t id() const { return _id; } + inline unsigned int thingCount() const { return (unsigned int)_thingCount; } + + inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } + inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } + + inline const Address &issuedTo() const { return _issuedTo; } + + inline bool owns(const Thing &t,const void *v,unsigned int l) + { + for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) + break; + ++k; + } + if (k == l) + return true; + } + } + return false; + } + + inline bool owns(const InetAddress &ip) + { + if (ip.ss_family == AF_INET) + return this->owns(THING_IPV4_ADDRESS,&(reinterpret_cast(&ip)->sin_addr.s_addr),4); + if (ip.ss_family == AF_INET6) + return this->owns(THING_IPV6_ADDRESS,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); + return false; + } + + inline bool owns(const MAC &mac) + { + uint8_t tmp[6]; + mac.copyTo(tmp,6); + return this->owns(THING_MAC_ADDRESS,tmp,6); + } + + inline void addThing(const InetAddress &ip) + { + if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; + if (ip.ss_family == AF_INET) { + _thingTypes[_thingCount] = THING_IPV4_ADDRESS; + memcpy(_thingValues[_thingCount],&(reinterpret_cast(&ip)->sin_addr.s_addr),4); + ++_thingCount; + } else if (ip.ss_family == AF_INET6) { + _thingTypes[_thingCount] = THING_IPV6_ADDRESS; + memcpy(_thingValues[_thingCount],reinterpret_cast(&ip)->sin6_addr.s6_addr,16); + ++_thingCount; + } + } + + inline void addThing(const MAC &mac) + { + if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; + _thingTypes[_thingCount] = THING_MAC_ADDRESS; + mac.copyTo(_thingValues[_thingCount],6); + ++_thingCount; + } + + /** + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + inline bool sign(const Identity &signer) + { + if (signer.hasPrivate()) { + Buffer tmp; + _signedBy = signer.address(); + this->serialize(tmp,true); + _signature = signer.sign(tmp.data(),tmp.size()); + return true; + } + return false; + } + + /** + * @param RR Runtime environment to allow identity lookup for signedBy + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature + */ + int verify(const RuntimeEnvironment *RR) const; + + template + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + b.append(_networkId); + b.append(_ts); + b.append(_flags); + b.append(_id); + b.append((uint16_t)_thingCount); + for(unsigned int i=0,j=_thingCount;i + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + unsigned int p = startAt; + + memset(this,0,sizeof(CertificateOfOwnership)); + + _networkId = b.template at(p); p += 8; + _ts = b.template at(p); p += 8; + _flags = b.template at(p); p += 8; + _id = b.template at(p); p += 4; + _thingCount = b.template at(p); p += 2; + for(unsigned int i=0,j=_thingCount;i(p) != ZT_C25519_SIGNATURE_LEN) + throw std::runtime_error("invalid signature length"); + p += 2; + memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + } else { + p += 2 + b.template at(p); + } + + p += 2 + b.template at(p); + if (p > b.size()) + throw std::runtime_error("extended field overflow"); + + return (p - startAt); + } + + // Provides natural sort order by ID + inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); } + + inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); } + inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } + +private: + uint64_t _networkId; + uint64_t _ts; + uint64_t _flags; + uint32_t _id; + uint16_t _thingCount; + uint8_t _thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS]; + uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE]; + Address _issuedTo; + Address _signedBy; + C25519::Signature _signature; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b077f7e2..b5b2bcb3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -832,6 +832,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S Capability cap; Tag tag; Revocation revocation; + CertificateOfOwnership coo; bool trustEstablished = false; unsigned int p = ZT_PACKET_IDX_PAYLOAD; @@ -909,6 +910,24 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } } + + const unsigned int numCoos = at(p); p += 2; + for(unsigned int i=0;i network(RR->node->network(coo.networkId())); + if (network) { + switch(network->addCredential(coo)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } + } } peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); diff --git a/node/Membership.cpp b/node/Membership.cpp index 8c6dab64..1eacb93d 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -37,6 +37,7 @@ Membership::Membership() : { for(unsigned int i=0;i= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) { + _localCoos[c].lastPushed = now; + _localCoos[c].id = nconf.certificatesOfOwnership[c].id(); + sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]); + } + } + unsigned int tagPtr = 0; - while ((tagPtr < sendTagCount)||(sendCom)||(sendCap)) { + unsigned int cooPtr = 0; + while ((tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)||(sendCap)) { Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); if (sendCom) { @@ -82,7 +94,7 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now const unsigned int tagCountAt = outp.size(); outp.addSize(2); unsigned int thisPacketTagCount = 0; - while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 32) < ZT_PROTO_MAX_PACKET_LENGTH)) { + while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { sendTags[tagPtr++]->serialize(outp); ++thisPacketTagCount; } @@ -91,6 +103,15 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now // No revocations, these propagate differently outp.append((uint16_t)0); + const unsigned int cooCountAt = outp.size(); + outp.addSize(2); + unsigned int thisPacketCooCount = 0; + while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { + sendCoos[cooPtr++]->serialize(outp); + ++thisPacketCooCount; + } + outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); + outp.compress(); RR->sw->send(outp,true); } @@ -98,14 +119,14 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now const Capability *Membership::getCapability(const NetworkConfig &nconf,const uint32_t id) const { - const _RemoteCapability *const *c = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)id,_RemoteCredentialSorter<_RemoteCapability>()); - return ( ((c != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*c)->id == (uint64_t)id)) ? ((((*c)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*c)->cap,**c))) ? &((*c)->cap) : (const Capability *)0) : (const Capability *)0); + const _RemoteCredential *const *c = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)id,_RemoteCredentialComp()); + return ( ((c != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*c)->id == (uint64_t)id)) ? ((((*c)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*c)->credential,**c))) ? &((*c)->credential) : (const Capability *)0) : (const Capability *)0); } const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const { - const _RemoteTag *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialSorter<_RemoteTag>()); - return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*t)->tag,**t))) ? &((*t)->tag) : (const Tag *)0) : (const Tag *)0); + const _RemoteCredential *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialComp()); + return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*t)->credential,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0); } Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com) @@ -141,14 +162,14 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag) { - _RemoteTag *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialSorter<_RemoteTag>()); - _RemoteTag *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteTag *)0; + _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp()); + _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential *)0; if (have) { - if ( (!_isCredentialTimestampValid(nconf,tag,*have)) || (have->tag.timestamp() > tag.timestamp()) ) { + if ( (!_isCredentialTimestampValid(nconf,tag,*have)) || (have->credential.timestamp() > tag.timestamp()) ) { TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId()); return ADD_REJECTED; } - if (have->tag == tag) { + if (have->credential == tag) { TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId()); return ADD_ACCEPTED_REDUNDANT; } @@ -162,7 +183,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId()); if (!have) have = _newTag(tag.id()); have->lastReceived = RR->node->now(); - have->tag = tag; + have->credential = tag; return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -171,14 +192,14 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap) { - _RemoteCapability *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialSorter<_RemoteCapability>()); - _RemoteCapability *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCapability *)0; + _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp()); + _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential *)0; if (have) { - if ( (!_isCredentialTimestampValid(nconf,cap,*have)) || (have->cap.timestamp() > cap.timestamp()) ) { + if ( (!_isCredentialTimestampValid(nconf,cap,*have)) || (have->credential.timestamp() > cap.timestamp()) ) { TRACE("addCredential(Capability) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId()); return ADD_REJECTED; } - if (have->cap == cap) { + if (have->credential == cap) { TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId()); return ADD_ACCEPTED_REDUNDANT; } @@ -192,7 +213,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId()); if (!have) have = _newCapability(cap.id()); have->lastReceived = RR->node->now(); - have->cap = cap; + have->credential = cap; return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -209,13 +230,15 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(rev.type()) { default: //case Revocation::CREDENTIAL_TYPE_ALL: - return ( (_revokeCom(rev)||_revokeCap(rev,now)||_revokeTag(rev,now)) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT ); + return ( (_revokeCom(rev)||_revokeCap(rev,now)||_revokeTag(rev,now)||_revokeCoo(rev,now)) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT ); case Revocation::CREDENTIAL_TYPE_COM: return (_revokeCom(rev) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); case Revocation::CREDENTIAL_TYPE_CAPABILITY: return (_revokeCap(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); case Revocation::CREDENTIAL_TYPE_TAG: return (_revokeTag(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); + case Revocation::CREDENTIAL_TYPE_COO: + return (_revokeCoo(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT); } } case 1: @@ -223,9 +246,40 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::_RemoteTag *Membership::_newTag(const uint64_t id) + +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo) +{ + _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp()); + _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential *)0; + if (have) { + if ( (!_isCredentialTimestampValid(nconf,coo,*have)) || (have->credential.timestamp() > coo.timestamp()) ) { + TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId()); + return ADD_REJECTED; + } + if (have->credential == coo) { + TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId()); + return ADD_ACCEPTED_REDUNDANT; + } + } + + switch(coo.verify(RR)) { + default: + TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (invalid)",cap.issuedTo().toString().c_str(),cap.networkId()); + return ADD_REJECTED; + case 0: + TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId()); + if (!have) have = _newCoo(coo.id()); + have->lastReceived = RR->node->now(); + have->credential = coo; + return ADD_ACCEPTED_NEW; + case 1: + return ADD_DEFERRED_FOR_WHOIS; + } +} + +Membership::_RemoteCredential *Membership::_newTag(const uint64_t id) { - _RemoteTag *t = NULL; + _RemoteCredential *t = NULL; uint64_t minlr = 0xffffffffffffffffULL; for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { @@ -236,21 +290,21 @@ Membership::_RemoteTag *Membership::_newTag(const uint64_t id) minlr = _remoteTags[i]->lastReceived; } } - - if (t) { - t->id = id; - t->lastReceived = 0; - t->revocationThreshold = 0; - t->tag = Tag(); - } - - std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>()); + + if (t) { + t->id = id; + t->lastReceived = 0; + t->revocationThreshold = 0; + t->credential = Tag(); + } + + std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS])); return t; } -Membership::_RemoteCapability *Membership::_newCapability(const uint64_t id) +Membership::_RemoteCredential *Membership::_newCapability(const uint64_t id) { - _RemoteCapability *c = NULL; + _RemoteCredential *c = NULL; uint64_t minlr = 0xffffffffffffffffULL; for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { @@ -266,10 +320,35 @@ Membership::_RemoteCapability *Membership::_newCapability(const uint64_t id) c->id = id; c->lastReceived = 0; c->revocationThreshold = 0; - c->cap = Capability(); + c->credential = Capability(); + } + + std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES])); + return c; +} + +Membership::_RemoteCredential *Membership::_newCoo(const uint64_t id) +{ + _RemoteCredential *c = NULL; + uint64_t minlr = 0xffffffffffffffffULL; + for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) { + c = _remoteCoos[i]; + break; + } else if (_remoteCoos[i]->lastReceived <= minlr) { + c = _remoteCoos[i]; + minlr = _remoteCoos[i]->lastReceived; + } + } + + if (c) { + c->id = id; + c->lastReceived = 0; + c->revocationThreshold = 0; + c->credential = CertificateOfOwnership(); } - std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>()); + std::sort(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP])); return c; } @@ -284,8 +363,8 @@ bool Membership::_revokeCom(const Revocation &rev) bool Membership::_revokeCap(const Revocation &rev,const uint64_t now) { - _RemoteCapability *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialSorter<_RemoteCapability>()); - _RemoteCapability *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCapability *)0; + _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialComp()); + _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential *)0; if (!have) have = _newCapability(rev.credentialId()); if (rev.threshold() > have->revocationThreshold) { have->lastReceived = now; @@ -297,8 +376,8 @@ bool Membership::_revokeCap(const Revocation &rev,const uint64_t now) bool Membership::_revokeTag(const Revocation &rev,const uint64_t now) { - _RemoteTag *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialSorter<_RemoteTag>()); - _RemoteTag *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteTag *)0; + _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialComp()); + _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential *)0; if (!have) have = _newTag(rev.credentialId()); if (rev.threshold() > have->revocationThreshold) { have->lastReceived = now; @@ -308,4 +387,17 @@ bool Membership::_revokeTag(const Revocation &rev,const uint64_t now) return false; } +bool Membership::_revokeCoo(const Revocation &rev,const uint64_t now) +{ + _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)rev.credentialId(),_RemoteCredentialComp()); + _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential *)0; + if (!have) have = _newCoo(rev.credentialId()); + if (rev.threshold() > have->revocationThreshold) { + have->lastReceived = now; + have->revocationThreshold = rev.threshold(); + return true; + } + return false; +} + } // namespace ZeroTier diff --git a/node/Membership.hpp b/node/Membership.hpp index 9814dce8..4e9d7769 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -39,49 +39,30 @@ class Network; /** * A container for certificates of membership and other network credentials * - * This is kind of analogous to a join table between Peer and Network. It is - * held by the Network object for each participating Peer. + * This is essentially a relational join between Peer and Network. * * This class is not thread safe. It must be locked externally. */ class Membership { private: - // Tags and related state - struct _RemoteTag - { - _RemoteTag() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {} - // Tag ID (last 32 bits, first 32 bits are set in unused entries to sort them to end) - uint64_t id; - // Last time we received THEIR tag (with this ID) - uint64_t lastReceived; - // Revocation blacklist threshold or 0 if none - uint64_t revocationThreshold; - // THEIR tag - Tag tag; - }; - - // Credentials and related state - struct _RemoteCapability + template + struct _RemoteCredential { - _RemoteCapability() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {} - // Capability ID (last 32 bits, first 32 bits are set in unused entries to sort them to end) + _RemoteCredential() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {} uint64_t id; - // Last time we received THEIR capability (with this ID) - uint64_t lastReceived; - // Revocation blacklist threshold or 0 if none - uint64_t revocationThreshold; - // THEIR capability - Capability cap; + uint64_t lastReceived; // last time we got this credential + uint64_t revocationThreshold; // credentials before this time are invalid + T credential; + inline bool operator<(const _RemoteCredential &c) const { return (id < c.id); } }; - // Comparison operator for remote credential entries template - struct _RemoteCredentialSorter + struct _RemoteCredentialComp { - inline bool operator()(const T *a,const T *b) const { return (a->id < b->id); } - inline bool operator()(const uint64_t a,const T *b) const { return (a < b->id); } - inline bool operator()(const T *a,const uint64_t b) const { return (a->id < b); } + inline bool operator()(const _RemoteCredential *a,const _RemoteCredential *b) const { return (a->id < b->id); } + inline bool operator()(const uint64_t a,const _RemoteCredential *b) const { return (a < b->id); } + inline bool operator()(const _RemoteCredential *a,const uint64_t b) const { return (a->id < b); } inline bool operator()(const uint64_t a,const uint64_t b) const { return (a < b); } }; @@ -89,8 +70,8 @@ private: struct _LocalCredentialPushState { _LocalCredentialPushState() : lastPushed(0),id(0) {} - uint64_t lastPushed; - uint32_t id; + uint64_t lastPushed; // last time we sent our own copy of this credential + uint64_t id; }; public: @@ -117,7 +98,7 @@ public: { for(;;) { if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { - const Capability *tmp = &((*_i)->cap); + const Capability *tmp = &((*_i)->credential); if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { ++_i; return tmp; @@ -131,7 +112,7 @@ public: private: const Membership *_m; const NetworkConfig *_c; - const _RemoteCapability *const *_i; + const _RemoteCredential *const *_i; }; friend class CapabilityIterator; @@ -150,7 +131,7 @@ public: { for(;;) { if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { - const Tag *tmp = &((*_i)->tag); + const Tag *tmp = &((*_i)->credential); if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { ++_i; return tmp; @@ -164,7 +145,7 @@ public: private: const Membership *_m; const NetworkConfig *_c; - const _RemoteTag *const *_i; + const _RemoteCredential *const *_i; }; friend class TagIterator; @@ -249,12 +230,19 @@ public: */ AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo); + private: - _RemoteTag *_newTag(const uint64_t id); - _RemoteCapability *_newCapability(const uint64_t id); + _RemoteCredential *_newTag(const uint64_t id); + _RemoteCredential *_newCapability(const uint64_t id); + _RemoteCredential *_newCoo(const uint64_t id); bool _revokeCom(const Revocation &rev); bool _revokeCap(const Revocation &rev,const uint64_t now); bool _revokeTag(const Revocation &rev,const uint64_t now); + bool _revokeCoo(const Revocation &rev,const uint64_t now); template inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred,const CS &state) const @@ -275,17 +263,20 @@ private: // Remote member's latest network COM CertificateOfMembership _com; - // Sorted (in ascending order of ID) arrays of pointers to remote tags and capabilities - _RemoteTag *_remoteTags[ZT_MAX_NETWORK_TAGS]; - _RemoteCapability *_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]; + // Sorted (in ascending order of ID) arrays of pointers to remote credentials + _RemoteCredential *_remoteTags[ZT_MAX_NETWORK_TAGS]; + _RemoteCredential *_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]; + _RemoteCredential *_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; - // This is the RAM allocated for remote tags and capabilities from which the sorted arrays are populated - _RemoteTag _tagMem[ZT_MAX_NETWORK_TAGS]; - _RemoteCapability _capMem[ZT_MAX_NETWORK_CAPABILITIES]; + // This is the RAM allocated for remote credential cache objects + _RemoteCredential _tagMem[ZT_MAX_NETWORK_TAGS]; + _RemoteCredential _capMem[ZT_MAX_NETWORK_CAPABILITIES]; + _RemoteCredential _cooMem[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; // Local credential push state tracking _LocalCredentialPushState _localTags[ZT_MAX_NETWORK_TAGS]; _LocalCredentialPushState _localCaps[ZT_MAX_NETWORK_CAPABILITIES]; + _LocalCredentialPushState _localCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; }; } // namespace ZeroTier diff --git a/node/Network.hpp b/node/Network.hpp index 85ee6e9a..56c7fc60 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -301,6 +301,17 @@ public: */ Membership::AddCredentialResult addCredential(const Address &sentFrom,const Revocation &rev); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + inline Membership::AddCredentialResult addCredential(const CertificateOfOwnership &coo) + { + if (coo.networkId() != _id) + return Membership::ADD_REJECTED; + Mutex::Lock _l(_lock); + return _membership(coo.issuedTo()).addCredential(RR,_config,coo); + } + /** * Force push credentials (COM, etc.) to a peer now * diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 2f356b15..fe7393e8 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -21,7 +21,6 @@ #include #include "NetworkConfig.hpp" -#include "Utils.hpp" namespace ZeroTier { @@ -137,6 +136,13 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false; } + tmp->clear(); + for(unsigned int i=0;icertificateOfOwnershipCount;++i) + this->certificatesOfOwnership[i].serialize(*tmp); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false; + } + tmp->clear(); for(unsigned int i=0;ispecialistCount;++i) tmp->append((uint64_t)this->specialists[i]); @@ -297,10 +303,23 @@ bool NetworkConfig::fromDictionary(const Dictionarytags[0]),&(this->tags[this->tagCount])); } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) { + unsigned int p = 0; + while (p < tmp->size()) { + if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) + p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p); + else { + CertificateOfOwnership foo; + p += foo.deserialize(*tmp,p); + } + } + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { unsigned int p = 0; - while (((p + 8) <= tmp->size())&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) { - this->specialists[this->specialistCount++] = tmp->at(p); + while ((p + 8) <= tmp->size()) { + if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) + this->specialists[this->specialistCount++] = tmp->at(p); p += 8; } } diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 39087395..85c24090 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -35,10 +35,12 @@ #include "MulticastGroup.hpp" #include "Address.hpp" #include "CertificateOfMembership.hpp" +#include "CertificateOfOwnership.hpp" #include "Capability.hpp" #include "Tag.hpp" #include "Dictionary.hpp" #include "Identity.hpp" +#include "Utils.hpp" /** * Default maximum time delta for COMs, tags, and capabilities @@ -99,7 +101,7 @@ namespace ZeroTier { // Dictionary capacity needed for max size network config -#define ZT_NETWORKCONFIG_DICT_CAPACITY (4096 + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS)) +#define ZT_NETWORKCONFIG_DICT_CAPACITY (1024 + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP)) // Dictionary capacity needed for max size network meta-data #define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024 @@ -173,6 +175,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES "CAP" // tags (binary blobs) #define ZT_NETWORKCONFIG_DICT_KEY_TAGS "TAG" +// tags (binary blobs) +#define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP "COO" // curve25519 signature #define ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE "C25519" @@ -473,11 +477,6 @@ public: */ unsigned int staticIpCount; - /** - * Number of pinned devices (devices with physical address hints) - */ - unsigned int pinnedCount; - /** * Number of rule table entries */ @@ -493,6 +492,11 @@ public: */ unsigned int tagCount; + /** + * Number of certificates of ownership + */ + unsigned int certificateOfOwnershipCount; + /** * Specialist devices * @@ -526,6 +530,11 @@ public: */ Tag tags[ZT_MAX_NETWORK_TAGS]; + /** + * Certificates of ownership for this network member + */ + CertificateOfOwnership certificatesOfOwnership[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; + /** * Network type (currently just public or private) */ diff --git a/node/Packet.hpp b/node/Packet.hpp index b736b84a..6482356a 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -730,6 +730,8 @@ public: * <[...] one or more serialized Tags> * <[2] 16-bit number of revocations> * <[...] one or more serialized Revocations> + * <[2] 16-bit number of certificates of ownership> + * <[...] one or more serialized CertificateOfOwnership> * * This can be sent by anyone at any time to push network credentials. * These will of course only be accepted if they are properly signed. diff --git a/node/Revocation.hpp b/node/Revocation.hpp index bc290e75..3903f440 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -50,9 +50,10 @@ public: enum CredentialType { CREDENTIAL_TYPE_ALL = 0, - CREDENTIAL_TYPE_COM = 1, + CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership CREDENTIAL_TYPE_CAPABILITY = 2, - CREDENTIAL_TYPE_TAG = 3 + CREDENTIAL_TYPE_TAG = 3, + CREDENTIAL_TYPE_COO = 4 // CertificateOfOwnership }; Revocation() diff --git a/node/Tag.hpp b/node/Tag.hpp index 65348200..146e8da9 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -139,7 +139,8 @@ public: { unsigned int p = startAt; - // These are the same between Tag and Capability + memset(this,0,sizeof(Tag)); + _networkId = b.template at(p); p += 8; _ts = b.template at(p); p += 8; _id = b.template at(p); p += 4; diff --git a/objects.mk b/objects.mk index 31498b72..427024eb 100644 --- a/objects.mk +++ b/objects.mk @@ -4,6 +4,7 @@ OBJS=\ node/C25519.o \ node/Capability.o \ node/CertificateOfMembership.o \ + node/CertificateOfOwnership.o \ node/Cluster.o \ node/Identity.o \ node/IncomingPacket.o \ -- cgit v1.2.3 From 2bf9145ae65385bf968542619ffcf204cf6241d8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 1 Mar 2017 10:22:57 -0800 Subject: Outgoing side of packet counter for link quality reporting. Also some cleanup and a cluster mode build fix. --- node/Buffer.hpp | 44 +- node/Cluster.cpp | 8 +- node/IncomingPacket.cpp | 26 +- node/Node.cpp | 6 +- node/Packet.cpp | 1942 +++++++++++++++++++++++------------------------ node/Packet.hpp | 25 +- node/Path.hpp | 10 + node/Peer.cpp | 24 +- node/Peer.hpp | 6 +- node/Switch.cpp | 8 +- 10 files changed, 1053 insertions(+), 1046 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 1a478894..37f39e7b 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -79,8 +79,7 @@ public: inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } - Buffer() - throw() : + Buffer() : _l(0) { } @@ -419,87 +418,70 @@ public: /** * Set buffer data length to zero */ - inline void clear() - throw() - { - _l = 0; - } + inline void clear() { _l = 0; } /** * Zero buffer up to size() */ - inline void zero() - throw() - { - memset(_b,0,_l); - } + inline void zero() { memset(_b,0,_l); } /** * Zero unused capacity area */ - inline void zeroUnused() - throw() - { - memset(_b + _l,0,C - _l); - } + inline void zeroUnused() { memset(_b + _l,0,C - _l); } /** * Unconditionally and securely zero buffer's underlying memory */ - inline void burn() - throw() - { - Utils::burn(_b,sizeof(_b)); - } + inline void burn() { Utils::burn(_b,sizeof(_b)); } /** * @return Constant pointer to data in buffer */ - inline const void *data() const throw() { return _b; } + inline const void *data() const { return _b; } + + /** + * @return Non-constant pointer to data in buffer + */ + inline void *unsafeData() { return _b; } /** * @return Size of data in buffer */ - inline unsigned int size() const throw() { return _l; } + inline unsigned int size() const { return _l; } /** * @return Capacity of buffer */ - inline unsigned int capacity() const throw() { return C; } + inline unsigned int capacity() const { return C; } template inline bool operator==(const Buffer &b) const - throw() { return ((_l == b._l)&&(!memcmp(_b,b._b,_l))); } template inline bool operator!=(const Buffer &b) const - throw() { return ((_l != b._l)||(memcmp(_b,b._b,_l))); } template inline bool operator<(const Buffer &b) const - throw() { return (memcmp(_b,b._b,std::min(_l,b._l)) < 0); } template inline bool operator>(const Buffer &b) const - throw() { return (b < *this); } template inline bool operator<=(const Buffer &b) const - throw() { return !(b < *this); } template inline bool operator>=(const Buffer &b) const - throw() { return !(*this < b); } diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 00122402..52e03ffe 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -255,7 +255,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") char polykey[ZT_POLY1305_KEY_LEN]; memset(polykey,0,sizeof(polykey)); - s20.encrypt12(polykey,polykey,sizeof(polykey)); + s20.crypt12(polykey,polykey,sizeof(polykey)); // Compute 16-byte MAC char mac[ZT_POLY1305_MAC_LEN]; @@ -267,7 +267,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) // Decrypt! dmsg.setSize(len - 24); - s20.decrypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); + s20.crypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); } if (dmsg.size() < 4) @@ -954,10 +954,10 @@ void Cluster::_flush(uint16_t memberId) // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") char polykey[ZT_POLY1305_KEY_LEN]; memset(polykey,0,sizeof(polykey)); - s20.encrypt12(polykey,polykey,sizeof(polykey)); + s20.crypt12(polykey,polykey,sizeof(polykey)); // Encrypt m.q in place - s20.encrypt12(reinterpret_cast(m.q.data()) + 24,const_cast(reinterpret_cast(m.q.data())) + 24,m.q.size() - 24); + s20.crypt12(reinterpret_cast(m.q.data()) + 24,const_cast(reinterpret_cast(m.q.data())) + 24,m.q.size() - 24); // Add MAC for authentication (encrypt-then-MAC) char mac[ZT_POLY1305_MAC_LEN]; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b5b2bcb3..85b06d50 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -243,7 +243,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true); + outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); @@ -405,7 +405,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut RR->topology->appendCertificateOfRepresentation(outp); outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -584,7 +584,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr } if (count > 0) { - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -610,7 +610,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false); + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false,0); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -732,7 +732,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -762,7 +762,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append((uint64_t)pid); if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); @@ -957,7 +957,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -984,7 +984,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared outp.append((uint64_t)packetId()); outp.append((uint64_t)network->id()); outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } @@ -1033,7 +1033,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar outp.append((uint32_t)mg.adi()); const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); if (gatheredLocally > 0) { - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -1140,7 +1140,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share outp.append((uint32_t)to.adi()); 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); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } @@ -1198,7 +1198,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now,false); + peer->attemptToContactAt(InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1217,7 +1217,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now,false); + peer->attemptToContactAt(InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1447,7 +1447,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,cons outp.append(packetId()); outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),now); } } diff --git a/node/Node.cpp b/node/Node.cpp index 6dc89387..35940d27 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -180,7 +180,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(InetAddress(),addr,_now); + p->sendHELLO(InetAddress(),addr,_now,0); contacted = true; break; } @@ -190,7 +190,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(InetAddress(),addr,_now); + p->sendHELLO(InetAddress(),addr,_now,0); contacted = true; break; } @@ -200,7 +200,7 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(up->localAddress(),up->address(),_now); + p->sendHELLO(up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); diff --git a/node/Packet.cpp b/node/Packet.cpp index 790f4b09..82a5d7ea 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -65,9 +65,9 @@ namespace { modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -85,8 +85,8 @@ namespace { OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ /* --- Dependency --- */ @@ -101,9 +101,9 @@ namespace { The LZ4 compression library provides in-memory compression and decompression functions. Compression can be done in: - - a single step (described as Simple Functions) - - a single step, reusing a context (described in Advanced Functions) - - unbounded multiple steps (described as Streaming compression) + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) lz4.h provides block compression functions. It gives full buffer control to user. Decompressing an lz4-compressed block also requires metadata (such as compressed size). @@ -164,28 +164,28 @@ namespace { * Simple Functions **************************************/ /*! LZ4_compress_default() : - Compresses 'sourceSize' bytes from buffer 'source' - into already allocated 'dest' buffer of size 'maxDestSize'. - Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). - It also runs faster, so it's a recommended setting. - If the function cannot compress 'source' into a more limited 'dest' budget, - compression stops *immediately*, and the function result is zero. - As a consequence, 'dest' content is not valid. - This function never writes outside 'dest' buffer, nor read outside 'source' buffer. - sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE - maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) - return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) - or 0 if compression fails */ + Compresses 'sourceSize' bytes from buffer 'source' + into already allocated 'dest' buffer of size 'maxDestSize'. + Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'source' into a more limited 'dest' budget, + compression stops *immediately*, and the function result is zero. + As a consequence, 'dest' content is not valid. + This function never writes outside 'dest' buffer, nor read outside 'source' buffer. + sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) + return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) + or 0 if compression fails */ //LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); /*! LZ4_decompress_safe() : - compressedSize : is the precise full size of the compressed block. - maxDecompressedSize : is the size of destination buffer, which must be already allocated. - return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) - If destination buffer is not large enough, decoding will stop and output an error code (<0). - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function is protected against buffer overflow exploits, including malicious data packets. - It never writes outside output buffer, nor reads outside input buffer. + compressedSize : is the precise full size of the compressed block. + maxDecompressedSize : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) + If destination buffer is not large enough, decoding will stop and output an error code (<0). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against buffer overflow exploits, including malicious data packets. + It never writes outside output buffer, nor reads outside input buffer. */ LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); @@ -198,33 +198,33 @@ LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compress /*! LZ4_compressBound() : - Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) - This function is primarily useful for memory allocation purposes (destination buffer size). - Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). - Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) - inputSize : max supported value is LZ4_MAX_INPUT_SIZE - return : maximum output size in a "worst case" scenario - or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) */ LZ4LIB_API int LZ4_compressBound(int inputSize); /*! LZ4_compress_fast() : - Same as LZ4_compress_default(), but allows to select an "acceleration" factor. - The larger the acceleration value, the faster the algorithm, but also the lesser the compression. - It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. - An acceleration value of "1" is the same as regular LZ4_compress_default() - Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. + Same as LZ4_compress_default(), but allows to select an "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. */ LZ4LIB_API int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); /*! LZ4_compress_fast_extState() : - Same compression function, just using an externally allocated memory space to store compression state. - Use LZ4_sizeofState() to know how much memory must be allocated, - and allocate it on 8-bytes boundaries (using malloc() typically). - Then, provide it as 'void* state' to compression function. + Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. */ //LZ4LIB_API int LZ4_sizeofState(void); LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); @@ -232,42 +232,42 @@ LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char /*! LZ4_compress_destSize() : - Reverse the logic, by compressing as much data as possible from 'source' buffer - into already allocated buffer 'dest' of size 'targetDestSize'. - This function either compresses the entire 'source' content into 'dest' if it's large enough, - or fill 'dest' buffer completely with as much data as possible from 'source'. - *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. - New value is necessarily <= old value. - return : Nb bytes written into 'dest' (necessarily <= targetDestSize) - or 0 if compression fails + Reverse the logic, by compressing as much data as possible from 'source' buffer + into already allocated buffer 'dest' of size 'targetDestSize'. + This function either compresses the entire 'source' content into 'dest' if it's large enough, + or fill 'dest' buffer completely with as much data as possible from 'source'. + *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. + New value is necessarily <= old value. + return : Nb bytes written into 'dest' (necessarily <= targetDestSize) + or 0 if compression fails */ //LZ4LIB_API int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); /*! LZ4_decompress_fast() : - originalSize : is the original and therefore uncompressed size - return : the number of bytes read from the source buffer (in other words, the compressed size) - If the source stream is detected malformed, the function will stop decoding and return a negative result. - Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. - note : This function fully respect memory boundaries for properly formed compressed data. - It is a bit faster than LZ4_decompress_safe(). - However, it does not provide any protection against intentionally modified data stream (malicious input). - Use this function in trusted environment only (data to decode comes from a trusted source). + originalSize : is the original and therefore uncompressed size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is detected malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function fully respect memory boundaries for properly formed compressed data. + It is a bit faster than LZ4_decompress_safe(). + However, it does not provide any protection against intentionally modified data stream (malicious input). + Use this function in trusted environment only (data to decode comes from a trusted source). */ //LZ4LIB_API int LZ4_decompress_fast (const char* source, char* dest, int originalSize); /*! LZ4_decompress_safe_partial() : - This function decompress a compressed block of size 'compressedSize' at position 'source' - into destination buffer 'dest' of size 'maxDecompressedSize'. - The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, - reducing decompression time. - return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) - Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. - Always control how many bytes were decoded. - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets + This function decompress a compressed block of size 'compressedSize' at position 'source' + into destination buffer 'dest' of size 'maxDecompressedSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets */ //LZ4LIB_API int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); @@ -336,20 +336,20 @@ typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defin /*! LZ4_decompress_*_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) - In the case of a ring buffers, decoding buffer must be either : - - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) - In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). - - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. - maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including small ones ( < 64 KB). - - _At least_ 64 KB + 8 bytes + maxBlockSize. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including larger than decoding buffer. - Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, - and indicate where it is saved using LZ4_setStreamDecode() + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) + In the case of a ring buffers, decoding buffer must be either : + - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including small ones ( < 64 KB). + - _At least_ 64 KB + 8 bytes + maxBlockSize. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including larger than decoding buffer. + Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + and indicate where it is saved using LZ4_setStreamDecode() */ //LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); //LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); @@ -382,37 +382,37 @@ LZ4_decompress_*_continue() : //#include typedef struct { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t* dictionary; - uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ - uint32_t dictSize; + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; } LZ4_stream_t_internal; typedef struct { - const uint8_t* externalDict; - size_t extDictSize; - const uint8_t* prefixEnd; - size_t prefixSize; + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; #else typedef struct { - unsigned int hashTable[LZ4_HASH_SIZE_U32]; - unsigned int currentOffset; - unsigned int initCheck; - const unsigned char* dictionary; - unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */ - unsigned int dictSize; + unsigned int hashTable[LZ4_HASH_SIZE_U32]; + unsigned int currentOffset; + unsigned int initCheck; + const unsigned char* dictionary; + unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */ + unsigned int dictSize; } LZ4_stream_t_internal; typedef struct { - const unsigned char* externalDict; - size_t extDictSize; - const unsigned char* prefixEnd; - size_t prefixSize; + const unsigned char* externalDict; + size_t extDictSize; + const unsigned char* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; #endif @@ -428,8 +428,8 @@ typedef struct { #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) #define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_stream_t */ @@ -444,8 +444,8 @@ union LZ4_stream_u { #define LZ4_STREAMDECODESIZE_U64 4 #define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; - LZ4_streamDecode_t_internal internal_donotuse; + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_streamDecode_t */ /* lz4.c ------------------------------------------------------------------ */ @@ -460,9 +460,9 @@ union LZ4_streamDecode_u { modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -480,8 +480,8 @@ union LZ4_streamDecode_u { OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ @@ -617,8 +617,8 @@ typedef uintptr_t reg_t; **************************************/ static unsigned LZ4_isLittleEndian(void) { - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; } #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) @@ -648,27 +648,27 @@ static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = val static U16 LZ4_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; } static U32 LZ4_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; } static reg_t LZ4_read_ARCH(const void* memPtr) { - reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; } static void LZ4_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } static void LZ4_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ @@ -676,38 +676,38 @@ static void LZ4_write32(void* memPtr, U32 value) static U16 LZ4_readLE16(const void* memPtr) { - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); - } + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } } static void LZ4_writeLE16(void* memPtr, U16 value) { - if (LZ4_isLittleEndian()) { - LZ4_write16(memPtr, value); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); - } + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } } static void LZ4_copy8(void* dst, const void* src) { - memcpy(dst,src,8); + memcpy(dst,src,8); } /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; - do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3); + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (int)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); + return (__builtin_ctzll((U64)val) >> 3); # else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; # endif - } else /* 32 bits */ { + } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); + unsigned long r; + _BitScanForward( &r, (U32)val ); + return (int)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); + return (__builtin_ctz((U32)val) >> 3); # else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; # endif - } - } else /* Big Endian CPU */ { - if (sizeof(val)==8) { + } + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { # if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); + return (__builtin_clzll((U64)val) >> 3); # else - unsigned r; - if (!(val>>32)) { r=4; } else { r=0; val>>=32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; + unsigned r; + if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; # endif - } else /* 32 bits */ { + } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); + return (__builtin_clz((U32)val) >> 3); # else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; # endif - } - } + } + } } #define STEPSIZE sizeof(reg_t) static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { - const BYTE* const pStart = pIn; - - while (likely(pIn> ((MINMATCH*8)-(LZ4_HASHLOG+1))); - else - return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); + if (tableType == byU16) + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - if (LZ4_isLittleEndian()) - return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - else - return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); - return LZ4_hash4(LZ4_read32(p), tableType); + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); } static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { - switch (tableType) - { - case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } - case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } - case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } - } + switch (tableType) + { + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } + } } FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } - if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } - { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ + if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } + if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } + { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ } FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } /** LZ4_compress_generic() : - inlined, to ensure branches are decided at compilation time */ + inlined, to ensure branches are decided at compilation time */ FORCE_INLINE int LZ4_compress_generic( - LZ4_stream_t_internal* const cctx, - const char* const source, - char* const dest, - const int inputSize, - const int maxOutputSize, - const limitedOutput_directive outputLimited, - const tableType_t tableType, - const dict_directive dict, - const dictIssue_directive dictIssue, - const U32 acceleration) + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) { - const BYTE* ip = (const BYTE*) source; - const BYTE* base; - const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - cctx->dictSize; - const BYTE* const dictionary = cctx->dictionary; - const BYTE* const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; - const BYTE* anchor = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dest; - BYTE* const olimit = op + maxOutputSize; - - U32 forwardH; - - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ - switch(dict) - { - case noDict: - default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; - break; - case withPrefix64k: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source - cctx->dictSize; - break; - case usingExtDict: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source; - break; - } - if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (inputSizehashTable, tableType, base); - ip++; forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for ( ; ; ) { - ptrdiff_t refDelta = 0; - const BYTE* match; - BYTE* token; - - /* Find a match */ - { const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - do { - U32 const h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) goto _last_literals; - - match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); - - } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); - } - - /* Catch up */ - while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } - - /* Encode Literals */ - { unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) - return 0; - if (litLength >= RUN_MASK) { - int len = (int)litLength-RUN_MASK; - *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(litLength<dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; + + U32 forwardH; + + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ + switch(dict) + { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (inputSizehashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + ptrdiff_t refDelta = 0; + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + + } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) + || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } + + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { + int len = (int)litLength-RUN_MASK; + *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchCode; - if (ip==limit) { - unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchCode += more; - ip += more; - } - } else { - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchCode; - } - - if ( outputLimited && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) - return 0; - if (matchCode >= ML_MASK) { - *token += ML_MASK; - matchCode -= ML_MASK; - LZ4_write32(op, 0xFFFFFFFF); - while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; - op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); - } else - *token += (BYTE)(matchCode); - } - - anchor = ip; - - /* Test end of chunk */ - if (ip > mflimit) break; - - /* Fill table */ - LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } } - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) - && (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + + /* Encode MatchLength */ + { unsigned matchCode; + + if ((dict==usingExtDict) && (lowLimit==dictionary)) { + const BYTE* limit; + match += refDelta; + limit = ip + (dictEnd-match); + if (limit > matchlimit) limit = matchlimit; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + } + + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) + return 0; + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); + } + + anchor = ip; + + /* Test end of chunk */ + if (ip > mflimit) break; + + /* Fill table */ + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) + && (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: - /* Encode Last Literals */ - { size_t const lastRun = (size_t)(iend - anchor); - if ( (outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) - return 0; - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRun< (U32)maxOutputSize) ) + return 0; + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRun<internal_donotuse; - LZ4_resetStream((LZ4_stream_t*)state); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } else { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + LZ4_resetStream((LZ4_stream_t*)state); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } else { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } } int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { #if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctx; - void* const ctxPtr = &ctx; + LZ4_stream_t ctx; + void* const ctxPtr = &ctx; #endif - int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) - FREEMEM(ctxPtr); + FREEMEM(ctxPtr); #endif - return result; + return result; } #if 0 int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) { - return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); + return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); } /* hidden debug function */ /* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t ctx; - LZ4_resetStream(&ctx); + LZ4_stream_t ctx; + LZ4_resetStream(&ctx); - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); } #endif @@ -1173,189 +1173,189 @@ int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int m #if 0 static int LZ4_compress_destSize_generic( - LZ4_stream_t_internal* const ctx, - const char* const src, - char* const dst, - int* const srcSizePtr, - const int targetDstSize, - const tableType_t tableType) + LZ4_stream_t_internal* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + const int targetDstSize, + const tableType_t tableType) { - const BYTE* ip = (const BYTE*) src; - const BYTE* base = (const BYTE*) src; - const BYTE* lowLimit = (const BYTE*) src; - const BYTE* anchor = ip; - const BYTE* const iend = ip + *srcSizePtr; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dst; - BYTE* const oend = op + targetDstSize; - BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; - BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); - BYTE* const oMaxSeq = oMaxLit - 1 /* token */; - - U32 forwardH; - - - /* Init conditions */ - if (targetDstSize < 1) return 0; /* Impossible to store anything */ - if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ - if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (*srcSizePtrhashTable, tableType, base); - ip++; forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for ( ; ; ) { - const BYTE* match; - BYTE* token; - - /* Find a match */ - { const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = 1 << LZ4_skipTrigger; - - do { - U32 h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) goto _last_literals; - - match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); - - } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match) != LZ4_read32(ip)) ); - } - - /* Catch up */ - while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } - - /* Encode Literal length */ - { unsigned litLength = (unsigned)(ip - anchor); - token = op++; - if (op + ((litLength+240)/255) + litLength > oMaxLit) { - /* Not enough space for a last match */ - op--; - goto _last_literals; - } - if (litLength>=RUN_MASK) { - unsigned len = litLength - RUN_MASK; - *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(litLength< (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (*srcSizePtrhashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = 1 << LZ4_skipTrigger; + + do { + U32 h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); + + } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literal length */ + { unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if (op + ((litLength+240)/255) + litLength > oMaxLit) { + /* Not enough space for a last match */ + op--; + goto _last_literals; + } + if (litLength>=RUN_MASK) { + unsigned len = litLength - RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< oMaxMatch) { - /* Match description too long : reduce it */ - matchLength = (15-1) + (oMaxMatch-op) * 255; - } - ip += MINMATCH + matchLength; - - if (matchLength>=ML_MASK) { - *token += ML_MASK; - matchLength -= ML_MASK; - while (matchLength >= 255) { matchLength-=255; *op++ = 255; } - *op++ = (BYTE)matchLength; - } - else *token += (BYTE)(matchLength); - } - - anchor = ip; - - /* Test end of block */ - if (ip > mflimit) break; - if (op > oMaxSeq) break; - - /* Fill table */ - LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); - LZ4_putPosition(ip, ctx->hashTable, tableType, base); - if ( (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + + /* Encode MatchLength */ + { size_t matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + + if (op + ((matchLength+240)/255) > oMaxMatch) { + /* Match description too long : reduce it */ + matchLength = (15-1) + (oMaxMatch-op) * 255; + } + ip += MINMATCH + matchLength; + + if (matchLength>=ML_MASK) { + *token += ML_MASK; + matchLength -= ML_MASK; + while (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of block */ + if (ip > mflimit) break; + if (op > oMaxSeq) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: - /* Encode Last Literals */ - { size_t lastRunSize = (size_t)(iend - anchor); - if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { - /* adapt lastRunSize to fill 'dst' */ - lastRunSize = (oend-op) - 1; - lastRunSize -= (lastRunSize+240)/255; - } - ip = anchor + lastRunSize; - - if (lastRunSize >= RUN_MASK) { - size_t accumulator = lastRunSize - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRunSize< oend) { + /* adapt lastRunSize to fill 'dst' */ + lastRunSize = (oend-op) - 1; + lastRunSize -= (lastRunSize+240)/255; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ - return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); - } else { - if (*srcSizePtr < LZ4_64Klimit) - return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); - else - return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr); - } + LZ4_resetStream(state); + + if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); + } else { + if (*srcSizePtr < LZ4_64Klimit) + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); + else + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr); + } } int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (HEAPMODE) - LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctxBody; - LZ4_stream_t* ctx = &ctxBody; + LZ4_stream_t ctxBody; + LZ4_stream_t* ctx = &ctxBody; #endif - int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); #if (HEAPMODE) - FREEMEM(ctx); + FREEMEM(ctx); #endif - return result; + return result; } #endif @@ -1366,23 +1366,23 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe #if 0 LZ4_stream_t* LZ4_createStream(void) { - LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ - LZ4_resetStream(lz4s); - return lz4s; + LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); + LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + LZ4_resetStream(lz4s); + return lz4s; } #endif void LZ4_resetStream (LZ4_stream_t* LZ4_stream) { - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); } #if 0 int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { - FREEMEM(LZ4_stream); - return (0); + FREEMEM(LZ4_stream); + return (0); } #endif @@ -1390,117 +1390,117 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream) #define HASH_UNIT sizeof(reg_t) int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { - LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; - const BYTE* p = (const BYTE*)dictionary; - const BYTE* const dictEnd = p + dictSize; - const BYTE* base; - - if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ - LZ4_resetStream(LZ4_dict); - - if (dictSize < (int)HASH_UNIT) { - dict->dictionary = NULL; - dict->dictSize = 0; - return 0; - } - - if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; - dict->currentOffset += 64 KB; - base = p - dict->currentOffset; - dict->dictionary = p; - dict->dictSize = (U32)(dictEnd - p); - dict->currentOffset += dict->dictSize; - - while (p <= dictEnd-HASH_UNIT) { - LZ4_putPosition(p, dict->hashTable, byU32, base); - p+=3; - } - - return dict->dictSize; + LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; + const BYTE* p = (const BYTE*)dictionary; + const BYTE* const dictEnd = p + dictSize; + const BYTE* base; + + if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ + LZ4_resetStream(LZ4_dict); + + if (dictSize < (int)HASH_UNIT) { + dict->dictionary = NULL; + dict->dictSize = 0; + return 0; + } + + if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; + dict->currentOffset += 64 KB; + base = p - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += dict->dictSize; + + while (p <= dictEnd-HASH_UNIT) { + LZ4_putPosition(p, dict->hashTable, byU32, base); + p+=3; + } + + return dict->dictSize; } static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) { - if ((LZ4_dict->currentOffset > 0x80000000) || - ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ - /* rescale hash table */ - U32 const delta = LZ4_dict->currentOffset - 64 KB; - const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; - int i; - for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; - else LZ4_dict->hashTable[i] -= delta; - } - LZ4_dict->currentOffset = 64 KB; - if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; - LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; - } + if ((LZ4_dict->currentOffset > 0x80000000) || + ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ + /* rescale hash table */ + U32 const delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } } int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - - const BYTE* smallest = (const BYTE*) source; - if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ - if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; - LZ4_renormDictT(streamPtr, smallest); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - - /* Check overlapping input/dictionary space */ - { const BYTE* sourceEnd = (const BYTE*) source + inputSize; - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { - streamPtr->dictSize = (U32)(dictEnd - sourceEnd); - if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; - if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; - streamPtr->dictionary = dictEnd - streamPtr->dictSize; - } - } - - /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE*)source) { - int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); - else - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); - streamPtr->dictSize += (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; - } - - /* external dictionary mode */ - { int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); - else - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); - streamPtr->dictionary = (const BYTE*)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; - } + LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + const BYTE* smallest = (const BYTE*) source; + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; + LZ4_renormDictT(streamPtr, smallest); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + /* Check overlapping input/dictionary space */ + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; + } + } + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) { + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); + else + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); + streamPtr->dictSize += (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } + + /* external dictionary mode */ + { int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); + else + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } } /* Hidden debug function, to force external dictionary mode */ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) { - LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; - int result; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; + int result; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - const BYTE* smallest = dictEnd; - if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; - LZ4_renormDictT(streamPtr, smallest); + const BYTE* smallest = dictEnd; + if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; + LZ4_renormDictT(streamPtr, smallest); - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); - streamPtr->dictionary = (const BYTE*)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; - return result; + return result; } /*! LZ4_saveDict() : @@ -1512,18 +1512,18 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* */ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { - LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; - if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ - if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; - memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); - dict->dictionary = (const BYTE*)safeBuffer; - dict->dictSize = (U32)dictSize; + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; - return dictSize; + return dictSize; } #endif @@ -1538,181 +1538,181 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) * in order to remove useless branches during compilation optimization. */ FORCE_INLINE int LZ4_decompress_generic( - const char* const source, - char* const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest when no prefix */ - const BYTE* const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ - ) + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ + ) { - /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; - - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; - const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; - - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - - - /* Special cases */ - if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); - - /* Main Loop : decode sequences */ - while (1) { - size_t length; - const BYTE* match; - size_t offset; - - /* get literal length */ - unsigned const token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) - { - if (partialDecoding) { - if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } else { - if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; op = cpy; - - /* get offset */ - offset = LZ4_readLE16(ip); ip+=2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ - LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ - - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - s = *ip++; - if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; - length += s; - } while (s==255); - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ - } - length += MINMATCH; - - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) { - if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ - - if (length <= (size_t)(lowPrefix-match)) { - /* match can be copied as a single segment from external dictionary */ - memmove(op, dictEnd - (lowPrefix-match), length); - op += length; - } else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix-match); - size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ - BYTE* const endOfMatch = op + restSize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) *op++ = *copyFrom++; - } else { - memcpy(op, lowPrefix, restSize); - op += restSize; - } } - continue; - } - - /* copy match within block */ - cpy = op + length; - if (unlikely(offset<8)) { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - memcpy(op+4, match, 4); - match -= dec64; - } else { LZ4_copy8(op, match); match+=8; } - op += 8; - - if (unlikely(cpy>oend-12)) { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); - if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op16) LZ4_wildCopy(op+8, match+8, cpy); - } - op=cpy; /* correction */ - } - - /* end of decoding */ - if (endOnInput) - return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ - else - return (int) (((const char*)ip)-source); /* Nb of input bytes read */ - - /* Overflow error detected */ + /* Local Variables */ + const BYTE* ip = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; + + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; + const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; + + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + + /* Special cases */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; + + /* get literal length */ + unsigned const token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) + { + if (partialDecoding) { + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ + } else { + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; op = cpy; + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + length += s; + } while (s==255); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + + if (length <= (size_t)(lowPrefix-match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + + /* copy match within block */ + cpy = op + length; + if (unlikely(offset<8)) { + const int dec64 = dec64table[offset]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[offset]; + memcpy(op+4, match, 4); + match -= dec64; + } else { LZ4_copy8(op, match); match+=8; } + op += 8; + + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op16) LZ4_wildCopy(op+8, match+8, cpy); + } + op=cpy; /* correction */ + } + + /* end of decoding */ + if (endOnInput) + return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ + else + return (int) (((const char*)ip)-source); /* Nb of input bytes read */ + + /* Overflow error detected */ _output_error: - return (int) (-(((const char*)ip)-source))-1; + return (int) (-(((const char*)ip)-source))-1; } int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); } #if 0 int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); } int LZ4_decompress_fast(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); } #endif @@ -1726,14 +1726,14 @@ int LZ4_decompress_fast(const char* source, char* dest, int originalSize) */ LZ4_streamDecode_t* LZ4_createStreamDecode(void) { - LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t)); - return lz4s; + LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t)); + return lz4s; } int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) { - FREEMEM(LZ4_stream); - return 0; + FREEMEM(LZ4_stream); + return 0; } /*! @@ -1745,107 +1745,107 @@ int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) */ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - lz4sd->prefixSize = (size_t) dictSize; - lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; - lz4sd->externalDict = NULL; - lz4sd->extDictSize = 0; - return 1; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + lz4sd->prefixSize = (size_t) dictSize; + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->externalDict = NULL; + lz4sd->extDictSize = 0; + return 1; } /* *_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks must still be available at the memory position where they were decoded. - If it's not possible, save the relevant part of decoded data into a safe buffer, - and indicate where it stands using LZ4_setStreamDecode() + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setStreamDecode() */ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - int result; - - if (lz4sd->prefixEnd == (BYTE*)dest) { - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize += result; - lz4sd->prefixEnd += result; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize = result; - lz4sd->prefixEnd = (BYTE*)dest + result; - } - - return result; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += result; + lz4sd->prefixEnd += result; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } + + return result; } int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - int result; - - if (lz4sd->prefixEnd == (BYTE*)dest) { - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize += originalSize; - lz4sd->prefixEnd += originalSize; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize = originalSize; - lz4sd->prefixEnd = (BYTE*)dest + originalSize; - } - - return result; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } + + return result; } /* Advanced decoding functions : *_usingDict() : - These decoding functions work the same as "_continue" ones, - the dictionary must be explicitly provided within parameters + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters */ FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) { - if (dictSize==0) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); - if (dictStart+dictSize == dest) { - if (dictSize >= (int)(64 KB - 1)) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); - } - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + if (dictStart+dictSize == dest) { + if (dictSize >= (int)(64 KB - 1)) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + } + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); } int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); } /* debug function */ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } #endif @@ -1878,41 +1878,41 @@ int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base) { - MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); - lz4ds->internal_donotuse.bufferStart = base; + MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); + lz4ds->internal_donotuse.bufferStart = base; } int LZ4_resetStreamState(void* state, char* inputBuffer) { - if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ - LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); - return 0; + if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ + LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); + return 0; } void* LZ4_create (char* inputBuffer) { - LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); - LZ4_init (lz4ds, (BYTE*)inputBuffer); - return lz4ds; + LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); + LZ4_init (lz4ds, (BYTE*)inputBuffer); + return lz4ds; } char* LZ4_slideInputBuffer (void* LZ4_Data) { - LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse; - int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); - return (char*)(ctx->bufferStart + dictSize); + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse; + int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); + return (char*)(ctx->bufferStart + dictSize); } /* Obsolete streaming decompression functions */ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); } int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); } #endif @@ -1928,7 +1928,6 @@ const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #ifdef ZT_TRACE const char *Packet::verbString(Verb v) - throw() { switch(v) { case VERB_NOP: return "NOP"; @@ -1955,7 +1954,6 @@ const char *Packet::verbString(Verb v) } const char *Packet::errorString(ErrorCode e) - throw() { switch(e) { case ERROR_NONE: return "NONE"; @@ -1973,54 +1971,56 @@ const char *Packet::errorString(ErrorCode e) #endif // ZT_TRACE -void Packet::armor(const void *key,bool encryptPayload) +void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) { - unsigned char mangledKey[32]; - unsigned char macKey[32]; - unsigned char mac[16]; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen); + uint8_t mangledKey[32],macKey[32],mac[16]; + uint8_t *const data = reinterpret_cast(unsafeData()); + + // Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use + data[7] = (data[7] & 0xf8) | ((uint8_t)counter & 0x07); // Set flag now, since it affects key mangle function setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/); + Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV); // MAC key is always the first 32 bytes of the Salsa20 key stream // This is the same construction DJB's NaCl library uses s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); + uint8_t *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; if (encryptPayload) s20.crypt12(payload,payload,payloadLen); - Poly1305::compute(mac,payload,payloadLen,macKey); - memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8); + memcpy(data + ZT_PACKET_IDX_MAC,mac,8); } bool Packet::dearmor(const void *key) { - unsigned char mangledKey[32]; - unsigned char macKey[32]; - unsigned char mac[16]; + uint8_t mangledKey[32],macKey[32],mac[16]; + uint8_t *const data = reinterpret_cast(unsafeData()); const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen); - unsigned int cs = cipher(); + unsigned char *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int cs = cipher(); if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); + Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV); s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); Poly1305::compute(mac,payload,payloadLen,macKey); - if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8)) - return false; + if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) + return false; // MAC failed, packet is corrupt, modified, or is not from the sender if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) s20.crypt12(payload,payload,payloadLen); return true; - } else return false; // unrecognized cipher suite + } else { + return false; // unrecognized cipher suite + } } void Packet::cryptField(const void *key,unsigned int start,unsigned int len) @@ -2028,13 +2028,13 @@ void Packet::cryptField(const void *key,unsigned int start,unsigned int len) unsigned char mangledKey[32]; unsigned char macKey[32]; _salsa20MangleKey((const unsigned char *)key,mangledKey); - mangledKey[0] ^= 0x7f; - mangledKey[1] ^= ((start >> 8) & 0xff); - mangledKey[2] ^= (start & 0xff); // slightly alter key for this use case as an added guard against key stream reuse + mangledKey[0] ^= 0x7f; + mangledKey[1] ^= ((start >> 8) & 0xff); + mangledKey[2] ^= (start & 0xff); // slightly alter key for this use case as an added guard against key stream reuse Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); // discard the first 32 bytes of key stream (the ones use for MAC in armor()) as a precaution - unsigned char *const ptr = field(start,len); - s20.crypt12(ptr,ptr,len); + unsigned char *const ptr = field(start,len); + s20.crypt12(ptr,ptr,len); } bool Packet::compress() diff --git a/node/Packet.hpp b/node/Packet.hpp index 6482356a..2017ce8e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -351,7 +351,7 @@ namespace ZeroTier { * ZeroTier packet * * Packet format: - * <[8] 64-bit random packet ID and crypto initialization vector> + * <[8] 64-bit packet ID / crypto IV / packet counter> * <[5] destination ZT address> * <[5] source ZT address> * <[1] flags/cipher/hops> @@ -362,6 +362,14 @@ namespace ZeroTier { * * Packets smaller than 28 bytes are invalid and silently discarded. * + * The 64-bit packet ID is a strongly random value used as a crypto IV. + * Its least significant 3 bits are also used as a monotonically increasing + * (and looping) counter for sending packets to a particular recipient. This + * can be used for link quality monitoring and reporting and has no crypto + * impact as it does not increase the likelihood of an IV collision. (The + * crypto we use is not sensitive to the nature of the IV, only that it does + * not repeat.) + * * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher * selection allowing up to 7 cipher suites, F is outside-envelope flags, * and H is hop count. @@ -1102,10 +1110,8 @@ public: }; #ifdef ZT_TRACE - static const char *verbString(Verb v) - throw(); - static const char *errorString(ErrorCode e) - throw(); + static const char *verbString(Verb v); + static const char *errorString(ErrorCode e); #endif template @@ -1303,6 +1309,12 @@ public: /** * Get this packet's unique ID (the IV field interpreted as uint64_t) * + * Note that the least significant 3 bits of this ID will change when armor() + * is called to armor the packet for transport. This is because armor() will + * mask the last 3 bits against the send counter for QoS monitoring use prior + * to actually using the IV to encrypt and MAC the packet. Be aware of this + * when grabbing the packetId of a new packet prior to armor/send. + * * @return Packet ID */ inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } @@ -1337,8 +1349,9 @@ public: * * @param key 32-byte key * @param encryptPayload If true, encrypt packet payload, else just MAC + * @param counter Packet send counter for destination peer -- only least significant 3 bits are used */ - void armor(const void *key,bool encryptPayload); + void armor(const void *key,bool encryptPayload,unsigned int counter); /** * Verify and (if encrypted) decrypt packet diff --git a/node/Path.hpp b/node/Path.hpp index 5993be69..626f2f4f 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -105,6 +105,7 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), + _outgoingPacketCounter(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -115,6 +116,7 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), + _outgoingPacketCounter(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -241,10 +243,18 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } + /** + * Return and increment outgoing packet counter (used with Packet::armor()) + * + * @return Next value that should be used for outgoing packet counter (only least significant 3 bits are used) + */ + inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } + private: uint64_t _lastOut; uint64_t _lastIn; uint64_t _lastTrustEstablishedPacketReceived; + unsigned int _outgoingPacketCounter; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index 25efab42..c4c8774e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -101,7 +101,7 @@ void Peer::received( outp.append(redirectTo.rawIpData(),16); } outp.append((uint16_t)redirectTo.port()); - outp.armor(_key,true); + outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } else { // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. @@ -116,7 +116,7 @@ void Peer::received( outp.append((uint8_t)16); outp.append(redirectTo.rawIpData(),16); } - outp.armor(_key,true); + outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } suboptimalPath = true; @@ -203,7 +203,7 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(path->localAddress(),path->address(),now,true); + attemptToContactAt(path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } } @@ -277,7 +277,7 @@ void Peer::received( if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true); + outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } } @@ -342,7 +342,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) } } -void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) +void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -383,22 +383,22 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u RR->node->expectReplyTo(outp.packetId()); if (atAddress) { - outp.armor(_key,false); // false == don't encrypt full payload, but add MAC + outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello) +void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,true); + outp.armor(_key,true,counter); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { - sendHELLO(localAddr,atAddress,now); + sendHELLO(localAddr,atAddress,now,counter); } } @@ -408,7 +408,7 @@ void Peer::tryMemorizedPath(uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(_id.address(),-1,mp)) - attemptToContactAt(InetAddress(),mp,now,true); + attemptToContactAt(InetAddress(),mp,now,true,0); } } @@ -430,7 +430,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false); + attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); _paths[bestp].path->sent(now); } return true; @@ -454,7 +454,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false); + attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); _paths[p].path->sent(now); _paths[p].lastReceive = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index a3ec0088..783f48b8 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -150,8 +150,9 @@ public: * @param localAddr Local address * @param atAddress Destination address * @param now Current time + * @param counter Outgoing packet counter */ - void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -162,8 +163,9 @@ public: * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO + * @param counter Outgoing packet counter */ - void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello); + void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known diff --git a/node/Switch.cpp b/node/Switch.cpp index 346091a4..bf309e36 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -88,7 +88,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses _lastBeaconResponse = now; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } } @@ -777,7 +777,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { #endif if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false); + peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } #ifdef ZT_ENABLE_CLUSTER @@ -825,14 +825,14 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if (trustedPathId) { packet.setTrusted(trustedPathId); } else { - packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt); + packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt,(viaPath) ? viaPath->nextOutgoingCounter() : 0); } #else const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); if (trustedPathId) { packet.setTrusted(trustedPathId); } else { - packet.armor(peer->key(),encrypt); + packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); } #endif -- cgit v1.2.3 From d79585d44d54256ee3ddbec264174f9b6e008bed Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 1 Mar 2017 15:12:17 -0800 Subject: Circuit tests now report link quality. Also fixed a little thing in revocation propagation. --- include/ZeroTierOne.h | 5 +++++ node/IncomingPacket.cpp | 18 +++++++++++------- node/Network.cpp | 1 + node/Packet.hpp | 3 +-- 4 files changed, 18 insertions(+), 9 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 5b478afb..98413a21 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1270,6 +1270,11 @@ typedef struct { */ struct sockaddr_storage receivedFromRemoteAddress; + /** + * Path link quality of physical path over which test was received + */ + int receivedFromLinkQuality; + /** * Next hops to which packets are being or will be sent by the reporter * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 85b06d50..9c13a283 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1342,7 +1342,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint8_t)hops()); _path->localAddress().serialize(outp); _path->address().serialize(outp); - outp.append((uint16_t)0); // no additional fields + outp.append((uint16_t)_path->linkQuality()); outp.append((uint8_t)breadth); for(unsigned int h=0;h(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58); const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen); + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; + if (report.protocolVersion >= 9) { + report.receivedFromLinkQuality = at(ptr); ptr += 2; + } else { + report.receivedFromLinkQuality = ZT_PATH_LINK_QUALITY_MAX; + ptr += at(ptr) + 2; // this field was once an 'extended field length' reserved field, which was always set to 0 + } - unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; - nhptr += at(nhptr) + 2; // add "additional field" length, which right now will be zero - - report.nextHopCount = (*this)[nhptr++]; + report.nextHopCount = (*this)[ptr++]; if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH; for(unsigned int h=0;h(&(report.nextHops[h].physicalAddress))->deserialize(*this,nhptr); + report.nextHops[h].address = Address(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); ptr += ZT_ADDRESS_LENGTH; + ptr += reinterpret_cast(&(report.nextHops[h].physicalAddress))->deserialize(*this,ptr); } RR->node->postCircuitTestReport(&report); diff --git a/node/Network.cpp b/node/Network.cpp index dc976f03..e4b91bb6 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1422,6 +1422,7 @@ Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,c outp.append((uint16_t)0); // no capabilities outp.append((uint16_t)0); // no tags outp.append((uint16_t)1); // one revocation! + outp.append((uint16_t)0); // no certificates of ownership rev.serialize(outp); RR->sw->send(outp,true); } diff --git a/node/Packet.hpp b/node/Packet.hpp index d5817708..87863b19 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1041,8 +1041,7 @@ public: * <[1] 8-bit packet hop count of received CIRCUIT_TEST> * <[...] local wire address on which packet was received> * <[...] remote wire address from which packet was received> - * <[2] 16-bit length of additional fields> - * <[...] additional fields> + * <[2] 16-bit path link quality of path over which packet was received> * <[1] 8-bit number of next hops (breadth)> * <[...] next hop information> * -- cgit v1.2.3 From d56f740dc6cf35bd4e26c17503170d0f6c8035ec Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 3 Mar 2017 13:49:21 -0800 Subject: Now with less bugs. --- node/IncomingPacket.cpp | 6 ++++++ node/Node.hpp | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9c13a283..856538b4 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -875,6 +875,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } + if (p >= size()) return true; + const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i= size()) return true; + const unsigned int numRevocations = at(p); p += 2; for(unsigned int i=0;i= size()) return true; + const unsigned int numCoos = at(p); p += 2; for(unsigned int i=0;i> 32); + const unsigned long pid2 = (unsigned long)(packetId >> 32); + const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + _expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = (uint32_t)pid2; } /** @@ -243,10 +244,10 @@ public: */ inline bool expectingReplyTo(const uint64_t packetId) const { - const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); - const uint32_t pid = (uint32_t)(packetId >> 32); + const uint32_t pid2 = (uint32_t)(packetId >> 32); + const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == pid) + if (_expectingRepliesTo[bucket][i] == pid2) return true; } return false; -- cgit v1.2.3 From 0c00b8370207c51fbc9c9901cfa0daccc9707295 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 10 Mar 2017 17:34:41 -0800 Subject: cryptField() used to obscure extended fields in HELLO cannot use mangleKey() --- node/IncomingPacket.cpp | 2 +- node/Packet.cpp | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 856538b4..f3ec7505 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -320,7 +320,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // Get moon IDs and timestamps if present if ((ptr + 2) <= size()) { - unsigned int numMoons = at(ptr); ptr += 2; + const unsigned int numMoons = at(ptr); ptr += 2; for(unsigned int i=0;i(at(ptr),at(ptr + 8))); diff --git a/node/Packet.cpp b/node/Packet.cpp index 82a5d7ea..80ea2de7 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -2025,14 +2025,9 @@ bool Packet::dearmor(const void *key) void Packet::cryptField(const void *key,unsigned int start,unsigned int len) { - unsigned char mangledKey[32]; - unsigned char macKey[32]; - _salsa20MangleKey((const unsigned char *)key,mangledKey); - mangledKey[0] ^= 0x7f; - mangledKey[1] ^= ((start >> 8) & 0xff); - mangledKey[2] ^= (start & 0xff); // slightly alter key for this use case as an added guard against key stream reuse - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); // discard the first 32 bytes of key stream (the ones use for MAC in armor()) as a precaution + unsigned char discard[32]; + Salsa20 s20(key,256,field(ZT_PACKET_IDX_IV,8)); + s20.crypt12(ZERO_KEY,discard,sizeof(discard)); // discard the first 32 bytes of key stream (the ones use for MAC in armor()) as a precaution unsigned char *const ptr = field(start,len); s20.crypt12(ptr,ptr,len); } -- cgit v1.2.3 From 0f3148bda2420c99529194ccc1422d22bd6575bd Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 10 Mar 2017 20:08:07 -0800 Subject: Roots need to respond to lots of WHOISes --- node/Constants.hpp | 2 +- node/IncomingPacket.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index c2961f12..410a245b 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -393,7 +393,7 @@ /** * WHOIS rate limit (we allow these to be pretty fast) */ -#define ZT_PEER_WHOIS_RATE_LIMIT 50 +#define ZT_PEER_WHOIS_RATE_LIMIT 100 /** * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f3ec7505..800985dc 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -552,7 +552,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - if (!peer->rateGateInboundWhoisRequest(RR->node->now())) { + if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); return true; } -- cgit v1.2.3 From c6a39ed927161736e44aeaa67c6783024c1fb86a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 17 Mar 2017 13:55:26 -0700 Subject: Fixes for possible ARM issues, cleanup, fix for spurious meaningless exceptions on NETWORK_CONFIG_REQUEST --- make-linux.mk | 14 +++++++- node/Dictionary.hpp | 25 +++++++++++---- node/IncomingPacket.cpp | 6 ++-- node/Network.cpp | 8 +++++ one.cpp | 85 +++++++++++++++++++++++++++++++------------------ service/OneService.cpp | 2 ++ 6 files changed, 99 insertions(+), 41 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/make-linux.mk b/make-linux.mk index 1bb62852..528c41c4 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -54,7 +54,7 @@ ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1) endif ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE +# DEFS+=-DZT_TRACE override CFLAGS+=-Wall -g -O -pthread $(INCLUDES) $(DEFS) override CXXFLAGS+=-Wall -g -O -std=c++11 -pthread $(INCLUDES) $(DEFS) override LDFLAGS+= @@ -96,6 +96,12 @@ endif ifeq ($(CC_MACH),arm) ZT_ARCHITECTURE=3 endif +ifeq ($(CC_MACH),armv6) + ZT_ARCHITECTURE=3 +endif +ifeq ($(CC_MACH),armv7) + ZT_ARCHITECTURE=3 +endif ifeq ($(CC_MACH),arm64) ZT_ARCHITECTURE=4 endif @@ -104,6 +110,12 @@ ifeq ($(CC_MACH),aarch64) endif DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" +# Define some conservative CPU instruction set flags for arm32 since there's a ton of variation out there +ifeq ($(ZT_ARCHITECTURE),3) + override CFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp + override CXXFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp +endif + # Define this to build a static binary, which is needed to make this runnable on a few ancient Linux distros ifeq ($(ZT_STATIC),1) override LDFLAGS+=-static diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 15ab9ce3..fa9e2883 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -61,15 +61,23 @@ public: Dictionary(const char *s) { - Utils::scopy(_d,sizeof(_d),s); + if (s) { + Utils::scopy(_d,sizeof(_d),s); + } else { + _d[0] = (char)0; + } } Dictionary(const char *s,unsigned int len) { - if (len > (C-1)) - len = C-1; - memcpy(_d,s,len); - _d[len] = (char)0; + if (s) { + if (len > (C-1)) + len = C-1; + memcpy(_d,s,len); + _d[len] = (char)0; + } else { + _d[0] = (char)0; + } } Dictionary(const Dictionary &d) @@ -91,7 +99,12 @@ public: */ inline bool load(const char *s) { - return Utils::scopy(_d,sizeof(_d),s); + if (s) { + return Utils::scopy(_d,sizeof(_d),s); + } else { + _d[0] = (char)0; + return true; + } } /** diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 800985dc..ac4ae377 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -836,7 +836,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S bool trustEstablished = false; unsigned int p = ZT_PACKET_IDX_PAYLOAD; - while ((p < size())&&((*this)[p])) { + while ((p < size())&&((*this)[p] != 0)) { p += com.deserialize(*this,p); if (com) { const SharedPtr network(RR->node->network(com.networkId())); @@ -953,8 +953,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const uint64_t requestPacketId = packetId(); if (RR->localNetworkController) { - const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); - const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); + const unsigned int metaDataLength = (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN) : 0; + const char *metaDataBytes = (metaDataLength != 0) ? (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength) : (const char *)0; const Dictionary metaData(metaDataBytes,metaDataLength); RR->localNetworkController->request(nwid,(hopCount > 0) ? InetAddress() : _path->address(),requestPacketId,peer->identity(),metaData); } else { diff --git a/node/Network.cpp b/node/Network.cpp index dd812cab..92ca67ab 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1517,6 +1517,10 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); _config.com.serialize(outp); outp.append((uint8_t)0x00); + outp.append((uint16_t)0); // no capabilities + outp.append((uint16_t)0); // no tags + outp.append((uint16_t)0); // no revocations + outp.append((uint16_t)0); // no certificates of ownership RR->sw->send(outp,true); } _announceMulticastGroupsTo(*a,groups); @@ -1529,6 +1533,10 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Packet outp(c,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); _config.com.serialize(outp); outp.append((uint8_t)0x00); + outp.append((uint16_t)0); // no capabilities + outp.append((uint16_t)0); // no tags + outp.append((uint16_t)0); // no revocations + outp.append((uint16_t)0); // no certificates of ownership RR->sw->send(outp,true); } _announceMulticastGroupsTo(c,groups); diff --git a/one.cpp b/one.cpp index 95230bf1..25a50dbb 100644 --- a/one.cpp +++ b/one.cpp @@ -72,6 +72,7 @@ #include "osdep/OSUtils.hpp" #include "osdep/Http.hpp" +#include "osdep/Thread.hpp" #include "service/OneService.hpp" @@ -1209,6 +1210,52 @@ static void printHelp(const char *cn,FILE *out) fprintf(out," -q - Query API (zerotier-cli)" ZT_EOL_S); } +class _OneServiceRunner +{ +public: + _OneServiceRunner(const char *pn,const std::string &hd,unsigned int p) : progname(pn),returnValue(0),port(p),homeDir(hd) {} + void threadMain() + throw() + { + try { + for(;;) { + zt1Service = OneService::newInstance(homeDir.c_str(),port); + switch(zt1Service->run()) { + case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done + case OneService::ONE_NORMAL_TERMINATION: + break; + case OneService::ONE_UNRECOVERABLE_ERROR: + fprintf(stderr,"%s: fatal error: %s" ZT_EOL_S,progname,zt1Service->fatalErrorMessage().c_str()); + returnValue = 1; + break; + case OneService::ONE_IDENTITY_COLLISION: { + delete zt1Service; + zt1Service = (OneService *)0; + std::string oldid; + OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); + if (oldid.length()) { + OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); + OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); + OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); + } + } continue; // restart! + } + break; // terminate loop -- normally we don't keep restarting + } + + delete zt1Service; + zt1Service = (OneService *)0; + } catch ( ... ) { + fprintf(stderr,"%s: unexpected exception starting main OneService instance" ZT_EOL_S,progname); + returnValue = 1; + } + } + const char *progname; + unsigned int returnValue; + unsigned int port; + const std::string &homeDir; +}; + #ifdef __WINDOWS__ int _tmain(int argc, _TCHAR* argv[]) #else @@ -1421,8 +1468,8 @@ int main(int argc,char **argv) } else { // Running from service manager _winPokeAHole(); - ZeroTierOneService zt1Service; - if (CServiceBase::Run(zt1Service) == TRUE) { + ZeroTierOneService zt1WindowsService; + if (CServiceBase::Run(zt1WindowsService) == TRUE) { return 0; } else { fprintf(stderr,"%s: unable to start service (try -h for help)" ZT_EOL_S,argv[0]); @@ -1448,35 +1495,11 @@ int main(int argc,char **argv) } #endif // __UNIX_LIKE__ - unsigned int returnValue = 0; - - for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port); - switch(zt1Service->run()) { - case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done - case OneService::ONE_NORMAL_TERMINATION: - break; - case OneService::ONE_UNRECOVERABLE_ERROR: - fprintf(stderr,"%s: fatal error: %s" ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str()); - returnValue = 1; - break; - case OneService::ONE_IDENTITY_COLLISION: { - delete zt1Service; - zt1Service = (OneService *)0; - std::string oldid; - OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); - if (oldid.length()) { - OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); - OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); - OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); - } - } continue; // restart! - } - break; // terminate loop -- normally we don't keep restarting - } + _OneServiceRunner thr(argv[0],homeDir,port); + thr.threadMain(); + //Thread::join(Thread::start(&thr)); - delete zt1Service; - zt1Service = (OneService *)0; + OSUtils::rm(pidPath.c_str()); - return returnValue; + return thr.returnValue; } diff --git a/service/OneService.cpp b/service/OneService.cpp index 4a2102f1..1c2fa05d 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -488,6 +488,8 @@ public: ,_updater((SoftwareUpdater *)0) ,_updateAutoApply(false) ,_primaryPort(port) + ,_v4TcpControlSocket((PhySocket *)0) + ,_v6TcpControlSocket((PhySocket *)0) ,_lastDirectReceiveFromGlobal(0) #ifdef ZT_TCP_FALLBACK_RELAY ,_lastSendToGlobalV4(0) -- cgit v1.2.3 From d1bb22a583883a86cde9c845afb3e8b884f6301d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 17 Mar 2017 14:09:30 -0700 Subject: . --- node/IncomingPacket.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ac4ae377..dc6140f5 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -938,9 +938,11 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); } catch (std::exception &exc) { + fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -969,10 +971,10 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); } catch (std::exception &exc) { - fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); + fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - fprintf(stderr,"WARNING: network config request failed with exception: unknown exception" ZT_EOL_S); + fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; -- cgit v1.2.3 From a7cb738175cde9ba85143ae7076ba6b18bcc1c5b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 17 Mar 2017 14:25:54 -0700 Subject: . --- node/IncomingPacket.cpp | 8 ++++---- node/Network.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index dc6140f5..2e4a0b8e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -938,10 +938,10 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); } catch (std::exception &exc) { - fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); + //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; @@ -971,10 +971,10 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); } catch (std::exception &exc) { - fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); + //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; diff --git a/node/Network.cpp b/node/Network.cpp index 92ca67ab..38c1b0d9 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1282,8 +1282,8 @@ void Network::requestConfiguration() } else { outp.append((unsigned char)0,16); } - RR->node->expectReplyTo(outp.packetId()); outp.compress(); + RR->node->expectReplyTo(outp.packetId()); RR->sw->send(outp,true); } -- cgit v1.2.3 From cdc0eaec3add50e1424a0bcd9d054ec140c3540b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 17 Mar 2017 22:13:34 +0000 Subject: Fix attempt to WHOIS self. --- .gitignore | 1 + make-linux.mk | 2 +- node/IncomingPacket.cpp | 6 +++++- node/Switch.cpp | 7 +++++++ node/Topology.hpp | 20 ++++++++++++-------- 5 files changed, 26 insertions(+), 10 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/.gitignore b/.gitignore index 8d404eef..437352a3 100755 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ .DS_Store .Apple* Thumbs.db +@eaDir # Windows build droppings /windows/ZeroTierOne.sdf diff --git a/make-linux.mk b/make-linux.mk index 528c41c4..17bcd158 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -54,7 +54,7 @@ ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1) endif ifeq ($(ZT_DEBUG),1) -# DEFS+=-DZT_TRACE + DEFS+=-DZT_TRACE override CFLAGS+=-Wall -g -O -pthread $(INCLUDES) $(DEFS) override CXXFLAGS+=-Wall -g -O -std=c++11 -pthread $(INCLUDES) $(DEFS) override LDFLAGS+= diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2e4a0b8e..dc2c8aaf 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -477,7 +477,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } else ptr += 2; } - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); +#ifdef ZT_TRACE + const std::string tmp1(source().toString()); + const std::string tmp2(_path->address().toString()); + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u",tmp1.c_str(),tmp2.c_str(),vMajor,vMinor,vRevision,latency); +#endif if (!hops()) peer->addDirectLatencyMeasurment((unsigned int)latency); diff --git a/node/Switch.cpp b/node/Switch.cpp index 85103aa5..aab2e7ff 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -625,6 +625,13 @@ void Switch::send(Packet &packet,bool encrypt) void Switch::requestWhois(const Address &addr) { +#ifdef ZT_TRACE + if (addr == RR->identity.address()) { + fprintf(stderr,"FATAL BUG: Switch::requestWhois() caught attempt to WHOIS self" ZT_EOL_S); + abort(); + } +#endif + bool inserted = false; { Mutex::Lock _l(_outstandingWhoisRequests_m); diff --git a/node/Topology.hpp b/node/Topology.hpp index 37615b49..e21747c8 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -184,14 +184,7 @@ public: { Mutex::Lock _l(_upstreams_m); for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { - if (std::find(ips.begin(),ips.end(),*j) == ips.end()) - ips.push_back(*j); - } - } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + if (i->identity != RR->identity) { std::vector &ips = eps[i->identity.address()]; for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { if (std::find(ips.begin(),ips.end(),*j) == ips.end()) @@ -199,6 +192,17 @@ public: } } } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + if (i->identity != RR->identity) { + std::vector &ips = eps[i->identity.address()]; + for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { + if (std::find(ips.begin(),ips.end(),*j) == ips.end()) + ips.push_back(*j); + } + } + } + } for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) eps[m->second]; } -- cgit v1.2.3 From e10325e133beb01a2e9d82687eb33fd72f1ac3ab Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 17 Mar 2017 17:15:23 -0700 Subject: GitHub issue #461 -- plus a bit of cleanup and optimization --- node/CertificateOfOwnership.hpp | 7 ++----- node/IncomingPacket.cpp | 4 +++- node/Network.hpp | 1 + node/OutboundMulticast.cpp | 4 +++- node/Packet.cpp | 30 +++++++++++++++++++----------- node/Packet.hpp | 2 +- 6 files changed, 29 insertions(+), 19 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 7e71c9b2..57fd8259 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -56,12 +56,9 @@ public: THING_IPV6_ADDRESS = 3 }; - CertificateOfOwnership() : - _networkId(0), - _ts(0), - _id(0), - _thingCount(0) + CertificateOfOwnership() { + memset(this,0,sizeof(CertificateOfOwnership)); } CertificateOfOwnership(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id) : diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index dc2c8aaf..e2275a04 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -72,13 +72,15 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { + //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); return true; } } if (!uncompress()) { - TRACE("dropped packet from %s(%s), compressed data invalid (verb may be %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),(unsigned int)verb()); + //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); + TRACE("dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); return true; } diff --git a/node/Network.hpp b/node/Network.hpp index 56c7fc60..6cf6d974 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -374,6 +374,7 @@ private: struct _IncomingConfigChunk { + _IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); } uint64_t ts; uint64_t updateId; uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 36dc41f4..d4cb87cb 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -94,7 +94,9 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA _packet.newInitializationVector(); _packet.setDestination(toAddr2); RR->node->expectReplyTo(_packet.packetId()); - RR->sw->send(_packet,true); + + Packet tmp(_packet); // make a copy of packet so as not to garble the original -- GitHub issue #461 + RR->sw->send(tmp,true); } } diff --git a/node/Packet.cpp b/node/Packet.cpp index eb866568..b07f0bed 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1066,7 +1066,7 @@ void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) uint8_t *const data = reinterpret_cast(unsafeData()); // Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use - data[7] = (data[7] & 0xf8) | ((uint8_t)counter & 0x07); + data[7] = (data[7] & 0xf8) | (uint8_t)(counter & 0x07); // Set flag now, since it affects key mangle function setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); @@ -1124,35 +1124,43 @@ void Packet::cryptField(const void *key,unsigned int start,unsigned int len) bool Packet::compress() { - unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; + char *const data = reinterpret_cast(unsafeData()); + char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; + if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD); - int cl = LZ4_compress_fast((const char *)field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)pl),(char *)buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,2); + int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,2); if ((cl > 0)&&(cl < pl)) { - (*this)[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; + data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD); - memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)cl),buf,cl); + memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,cl); return true; } } - (*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + return false; } bool Packet::uncompress() { - unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH]; + char *const data = reinterpret_cast(unsafeData()); + char buf[ZT_PROTO_MAX_PACKET_LENGTH]; + if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) { if (size() > ZT_PACKET_IDX_PAYLOAD) { unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD; - int ucl = LZ4_decompress_safe((const char *)field(ZT_PACKET_IDX_PAYLOAD,compLen),(char *)buf,compLen,sizeof(buf)); + int ucl = LZ4_decompress_safe((const char *)data + ZT_PACKET_IDX_PAYLOAD,buf,compLen,sizeof(buf)); if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) { setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD); - memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)ucl),buf,ucl); - } else return false; + memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl); + } else { + return false; + } } - (*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); } + return true; } diff --git a/node/Packet.hpp b/node/Packet.hpp index fb332b7d..8ad2c0f9 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1322,7 +1322,7 @@ public: /** * @return Value of link quality counter extracted from this packet's ID, range 0 to 7 (3 bits) */ - inline unsigned int linkQualityCounter() const { return (unsigned int)(reinterpret_cast(data())[7] & 7); } + inline unsigned int linkQualityCounter() const { return (unsigned int)(reinterpret_cast(data())[7] & 0x07); } /** * Set packet verb -- cgit v1.2.3 From e4896b257fde05a216500804d9bcef3b84b0980e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Mar 2017 17:03:17 -0700 Subject: Add thread PTR that gets passed through the entire ZT core call stack and then passed to handler functions resulting from a call. --- controller/EmbeddedNetworkController.cpp | 2 +- include/ZeroTierOne.h | 51 ++++-- node/Capability.cpp | 6 +- node/Capability.hpp | 2 +- node/CertificateOfMembership.cpp | 6 +- node/CertificateOfMembership.hpp | 3 +- node/CertificateOfOwnership.cpp | 6 +- node/CertificateOfOwnership.hpp | 3 +- node/IncomingPacket.cpp | 294 +++++++++++++++---------------- node/IncomingPacket.hpp | 43 ++--- node/Membership.cpp | 24 +-- node/Membership.hpp | 13 +- node/Multicaster.cpp | 23 +-- node/Multicaster.hpp | 13 +- node/Network.cpp | 112 ++++++------ node/Network.hpp | 59 ++++--- node/Node.cpp | 136 +++++++------- node/Node.hpp | 42 +++-- node/OutboundMulticast.cpp | 6 +- node/OutboundMulticast.hpp | 13 +- node/Path.cpp | 4 +- node/Path.hpp | 3 +- node/Peer.cpp | 37 ++-- node/Peer.hpp | 22 ++- node/Revocation.cpp | 6 +- node/Revocation.hpp | 3 +- node/SelfAwareness.cpp | 10 +- node/SelfAwareness.hpp | 2 +- node/Switch.cpp | 97 +++++----- node/Switch.hpp | 22 ++- node/Tag.cpp | 6 +- node/Tag.hpp | 3 +- node/Topology.cpp | 54 +++--- node/Topology.hpp | 26 +-- osdep/BSDEthernetTap.cpp | 5 +- osdep/BSDEthernetTap.hpp | 4 +- osdep/LinuxEthernetTap.cpp | 4 +- osdep/LinuxEthernetTap.hpp | 4 +- osdep/OSXEthernetTap.cpp | 4 +- osdep/OSXEthernetTap.hpp | 4 +- osdep/WindowsEthernetTap.cpp | 5 +- osdep/WindowsEthernetTap.hpp | 4 +- service/OneService.cpp | 58 +++--- service/SoftwareUpdater.cpp | 12 +- 44 files changed, 673 insertions(+), 583 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 51500ed7..ce56e906 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -790,7 +790,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( test->timestamp = OSUtils::now(); if (_node) { - _node->circuitTestBegin(test,&(EmbeddedNetworkController::_circuitTestCallback)); + _node->circuitTestBegin((void *)0,test,&(EmbeddedNetworkController::_circuitTestCallback)); } else { _tests.pop_back(); return 500; diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 98413a21..747e1855 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1408,6 +1408,7 @@ typedef void ZT_Node; typedef int (*ZT_VirtualNetworkConfigFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* Network ID */ void **, /* Modifiable network user PTR */ enum ZT_VirtualNetworkConfigOperation, /* Config operation */ @@ -1423,6 +1424,7 @@ typedef int (*ZT_VirtualNetworkConfigFunction)( typedef void (*ZT_VirtualNetworkFrameFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* Network ID */ void **, /* Modifiable network user PTR */ uint64_t, /* Source MAC */ @@ -1442,10 +1444,11 @@ typedef void (*ZT_VirtualNetworkFrameFunction)( * in the definition of ZT_Event. */ typedef void (*ZT_EventCallback)( - ZT_Node *, - void *, - enum ZT_Event, - const void *); + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + enum ZT_Event, /* Event type */ + const void *); /* Event payload (if applicable) */ /** * Function to get an object from the data store @@ -1468,8 +1471,9 @@ typedef void (*ZT_EventCallback)( * object. */ typedef long (*ZT_DataStoreGetFunction)( - ZT_Node *, - void *, + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ const char *, void *, unsigned long, @@ -1495,6 +1499,7 @@ typedef long (*ZT_DataStoreGetFunction)( typedef int (*ZT_DataStorePutFunction)( ZT_Node *, void *, + void *, /* Thread ptr */ const char *, const void *, unsigned long, @@ -1529,6 +1534,7 @@ typedef int (*ZT_DataStorePutFunction)( typedef int (*ZT_WirePacketSendFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ const struct sockaddr_storage *, /* Local address */ const struct sockaddr_storage *, /* Remote address */ const void *, /* Packet data */ @@ -1562,6 +1568,7 @@ typedef int (*ZT_WirePacketSendFunction)( typedef int (*ZT_PathCheckFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* ZeroTier address */ const struct sockaddr_storage *, /* Local address */ const struct sockaddr_storage *); /* Remote address */ @@ -1584,6 +1591,7 @@ typedef int (*ZT_PathCheckFunction)( typedef int (*ZT_PathLookupFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* ZeroTier address (40 bits) */ int, /* Desired ss_family or -1 for any */ struct sockaddr_storage *); /* Result buffer */ @@ -1654,11 +1662,12 @@ struct ZT_Node_Callbacks * * @param node Result: pointer is set to new node instance on success * @param uptr User pointer to pass to functions/callbacks + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param callbacks Callback function configuration * @param now Current clock in milliseconds * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); /** * Delete a node and free all resources it consumes @@ -1674,6 +1683,7 @@ void ZT_Node_delete(ZT_Node *node); * Process a packet received from the physical wire * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds * @param localAddress Local address, or point to ZT_SOCKADDR_NULL if unspecified * @param remoteAddress Origin of packet @@ -1684,6 +1694,7 @@ void ZT_Node_delete(ZT_Node *node); */ enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -1695,6 +1706,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( * Process a frame from a virtual network port (tap) * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds * @param nwid ZeroTier 64-bit virtual network ID * @param sourceMac Source MAC address (least significant 48 bits) @@ -1708,6 +1720,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( */ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -1722,11 +1735,12 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( * Perform periodic background operations * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); /** * Join a network @@ -1742,7 +1756,7 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol * @param uptr An arbitrary pointer to associate with this network (default: NULL) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr); +enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); /** * Leave a network @@ -1759,7 +1773,7 @@ enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr); * @param uptr Target pointer is set to uptr (if not NULL) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr); +enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr); /** * Subscribe to an Ethernet multicast group @@ -1781,12 +1795,13 @@ enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr); * This does not generate an update call to networkConfigCallback(). * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param nwid 64-bit network ID * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); +enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); /** * Unsubscribe from an Ethernet multicast group (or all groups) @@ -1811,21 +1826,24 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint * across invocations if the contents of moon.d are scanned and orbit is * called for each on startup. * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param moonWorldId Moon's world ID * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition * @param len Length of moonWorld in bytes * @return Error if moon was invalid or failed to be added */ -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId,uint64_t moonSeed); +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed); /** * Remove a moon (does nothing if not present) * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param moonWorldId World ID of moon to remove * @return Error if anything bad happened */ -enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId); +enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId); /** * Get this node's 40-bit ZeroTier address @@ -1919,13 +1937,15 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); * There is no delivery guarantee here. Failure can occur if the message is * too large or if dest is not a valid ZeroTier address. * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param dest Destination ZeroTier address * @param typeId VERB_USER_MESSAGE type ID * @param data Payload data to attach to user message * @param len Length of data in bytes * @return Boolean: non-zero on success, zero on failure */ -int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); +int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); /** * Set a network configuration master instance for this node @@ -1957,11 +1977,12 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); * for results forever. * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param test Test configuration * @param reportCallback Function to call each time a report is received * @return OK or error if, for example, test is too big for a packet or support isn't compiled in */ -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); +enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); /** * Stop listening for results to a given circuit test diff --git a/node/Capability.cpp b/node/Capability.cpp index 0a736ca8..c178e566 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -25,7 +25,7 @@ namespace ZeroTier { -int Capability::verify(const RuntimeEnvironment *RR) const +int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const { try { // There must be at least one entry, and sanity check for bad chain max length @@ -46,12 +46,12 @@ int Capability::verify(const RuntimeEnvironment *RR) const return -1; // otherwise if we have another entry it must be from the previous holder in the chain } - const Identity id(RR->topology->getIdentity(_custody[c].from)); + const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from)); if (id) { if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) return -1; } else { - RR->sw->requestWhois(_custody[c].from); + RR->sw->requestWhois(tPtr,_custody[c].from); return 1; } } diff --git a/node/Capability.hpp b/node/Capability.hpp index d070f2ad..5ef6c994 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -161,7 +161,7 @@ public: * @param RR Runtime environment to provide for peer lookup, etc. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 43efcd20..9bf70216 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -207,14 +207,14 @@ bool CertificateOfMembership::sign(const Identity &with) } } -int CertificateOfMembership::verify(const RuntimeEnvironment *RR) const +int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 2d7c2cb3..ae976b50 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -250,9 +250,10 @@ public: * Verify this COM and its signature * * @param RR Runtime environment for looking up peers + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; /** * @return True if signed diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 6fc59ad1..2bd181e0 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -25,13 +25,13 @@ namespace ZeroTier { -int CertificateOfOwnership::verify(const RuntimeEnvironment *RR) const +int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } try { diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 57fd8259..8c47582d 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -137,9 +137,10 @@ public: /** * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template inline void serialize(Buffer &b,const bool forSign = false) const diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e2275a04..52794fd7 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -44,7 +44,7 @@ namespace ZeroTier { -bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) +bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) { const Address sourceAddress(source()); @@ -65,10 +65,10 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { // Only HELLO is allowed in the clear, but will still have a MAC - return _doHELLO(RR,false); + return _doHELLO(RR,tPtr,false); } - const SharedPtr peer(RR->topology->getPeer(sourceAddress)); + const SharedPtr peer(RR->topology->getPeer(tPtr,sourceAddress)); if (peer) { if (!trusted) { if (!dearmor(peer->key())) { @@ -89,30 +89,30 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,true); - case Packet::VERB_ERROR: return _doERROR(RR,peer); - case Packet::VERB_OK: return _doOK(RR,peer); - case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); - case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer); - case Packet::VERB_FRAME: return _doFRAME(RR,peer); - 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_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); - case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,peer); - case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); - case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); - case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); - case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); - case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); - case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,peer); + case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true); + case Packet::VERB_ERROR: return _doERROR(RR,tPtr,peer); + case Packet::VERB_OK: return _doOK(RR,tPtr,peer); + case Packet::VERB_WHOIS: return _doWHOIS(RR,tPtr,peer); + case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,tPtr,peer); + case Packet::VERB_FRAME: return _doFRAME(RR,tPtr,peer); + case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,tPtr,peer); + case Packet::VERB_ECHO: return _doECHO(RR,tPtr,peer); + case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,tPtr,peer); + case Packet::VERB_NETWORK_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,tPtr,peer); + case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,tPtr,peer); + case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,tPtr,peer); + case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer); + case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer); + case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer); + case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,tPtr,peer); + case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,tPtr,peer); + case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer); } } else { - RR->sw->requestWhois(sourceAddress); + RR->sw->requestWhois(tPtr,sourceAddress); return false; } } catch ( ... ) { @@ -123,7 +123,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } } -bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; @@ -163,7 +163,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_IDENTITY_COLLISION: // FIXME: for federation this will need a payload with a signature or something. if (RR->topology->isUpstream(peer->identity())) - RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); + RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { @@ -171,7 +171,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) - network->pushCredentialsNow(peer->address(),now); + network->pushCredentialsNow(tPtr,peer->address(),now); } break; case Packet::ERROR_NETWORK_ACCESS_DENIED_: { @@ -185,7 +185,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->gate(peer))) { + if ((network)&&(network->gate(tPtr,peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); @@ -195,14 +195,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated) +bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) { try { const uint64_t now = RR->node->now(); @@ -226,7 +226,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } - SharedPtr peer(RR->topology->getPeer(id.address())); + SharedPtr peer(RR->topology->getPeer(tPtr,id.address())); if (peer) { // We already have an identity with this address -- check for collisions if (!alreadyAuthenticated) { @@ -246,7 +246,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.append((uint64_t)pid); outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); } @@ -292,7 +292,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } - peer = RR->topology->addPeer(newPeer); + peer = RR->topology->addPeer(tPtr,newPeer); // Continue at // VALID } @@ -304,7 +304,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut if (ptr < size()) { ptr += externalSurfaceAddress.deserialize(*this,ptr); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + RR->sa->iam(tPtr,id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); } // Get primary planet world ID and world timestamp if present @@ -408,17 +408,17 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),now); + _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; @@ -463,7 +463,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p while (ptr < endOfWorlds) { World w; ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(w,false); + RR->topology->addWorld(tPtr,w,false); } } else { ptr += worldsLen; @@ -490,20 +490,20 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + RR->sa->iam(tPtr,peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: if (RR->topology->isUpstream(peer->identity())) { const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); - RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR,RR->identity,id)))); + RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); if (network) - network->handleConfigChunk(packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); + network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; case Packet::VERB_MULTICAST_GATHER: { @@ -513,7 +513,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } } break; @@ -532,7 +532,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); if (com) - network->addCredential(com); + network->addCredential(tPtr,com); } if ((flags & 0x02) != 0) { @@ -540,7 +540,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; unsigned int totalKnown = at(offset); offset += 4; unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -548,14 +548,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { @@ -573,13 +573,13 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; - const Identity id(RR->topology->getIdentity(addr)); + const Identity id(RR->topology->getIdentity(tPtr,addr)); if (id) { id.serialize(outp,false); ++count; } else { // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(addr); + RR->sw->requestWhois(tPtr,addr); #ifdef ZT_ENABLE_CLUSTER // Distribute WHOIS queries across a cluster if we do not know the ID. // This may result in duplicate OKs to the querying peer, which is fine. @@ -591,32 +591,32 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr if (count > 0) { outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (!RR->topology->isUpstream(peer->identity())) { TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); } else { const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(with)); + const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); if (rendezvousWith) { 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))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { - RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false,0); + if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localAddress(),atAddr)) { + RR->node->putPacket(tPtr,_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(tPtr,_path->localAddress(),atAddr,RR->node->now(),false,0); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -628,46 +628,46 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); bool trustEstablished = false; if (network) { - if (network->gate(peer)) { + if (network->gate(tPtr,peer)) { trustEstablished = true; if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); const MAC sourceMac(peer->address(),nwid); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) + RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } } else { TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); @@ -680,13 +680,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

addCredential(com); + network->addCredential(tPtr,com); } - if (!network->gate(peer)) { + if (!network->gate(tPtr,peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -699,36 +699,36 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } - switch (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { + switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { case 1: if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } // fall through -- 2 means accept regardless of bridging checks or other restrictions case 2: - RR->node->putFrame(nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); break; } } @@ -739,14 +739,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -754,7 +754,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&peer) +bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (!peer->rateGateEchoRequest(RR->node->now())) { @@ -769,16 +769,16 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t now = RR->node->now(); @@ -802,9 +802,9 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (!auth) { if ((!network)||(network->id() != nwid)) network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(peer))); + const bool authOnNet = ((network)&&(network->gate(tPtr,peer))); if (!authOnNet) - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); trustEstablished |= authOnNet; if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; @@ -815,18 +815,18 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (auth) { const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); - RR->mc->add(now,nwid,group,peer->address()); + RR->mc->add(tPtr,now,nwid,group,peer->address()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (!peer->rateGateCredentialsReceived(RR->node->now())) { @@ -847,7 +847,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S if (com) { const SharedPtr network(RR->node->network(com.networkId())); if (network) { - switch (network->addCredential(com)) { + switch (network->addCredential(tPtr,com)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -857,7 +857,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S case Membership::ADD_DEFERRED_FOR_WHOIS: return false; } - } else RR->mc->addCredential(com,false); + } else RR->mc->addCredential(tPtr,com,false); } } ++p; // skip trailing 0 after COMs if present @@ -868,7 +868,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += cap.deserialize(*this,p); const SharedPtr network(RR->node->network(cap.networkId())); if (network) { - switch (network->addCredential(cap)) { + switch (network->addCredential(tPtr,cap)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -888,7 +888,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += tag.deserialize(*this,p); const SharedPtr network(RR->node->network(tag.networkId())); if (network) { - switch (network->addCredential(tag)) { + switch (network->addCredential(tPtr,tag)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -908,7 +908,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += revocation.deserialize(*this,p); const SharedPtr network(RR->node->network(revocation.networkId())); if (network) { - switch(network->addCredential(peer->address(),revocation)) { + switch(network->addCredential(tPtr,peer->address(),revocation)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -928,7 +928,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += coo.deserialize(*this,p); const SharedPtr network(RR->node->network(coo.networkId())); if (network) { - switch(network->addCredential(coo)) { + switch(network->addCredential(tPtr,coo)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -942,7 +942,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); } catch (std::exception &exc) { //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -953,7 +953,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S return true; } -bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); @@ -972,10 +972,10 @@ 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,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); } catch (std::exception &exc) { //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -986,12 +986,12 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons return true; } -bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); if (network) { - const uint64_t configUpdateId = network->handleConfigChunk(packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); + const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); if (configUpdateId) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((uint8_t)Packet::VERB_ECHO); @@ -999,17 +999,17 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared outp.append((uint64_t)network->id()); outp.append((uint64_t)configUpdateId); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); @@ -1027,17 +1027,17 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); if (com) { if (network) - network->addCredential(com); - else RR->mc->addCredential(com,false); + network->addCredential(tPtr,com); + else RR->mc->addCredential(tPtr,com,false); } } catch ( ... ) { TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); } } - const bool trustEstablished = ((network)&&(network->gate(peer))); + const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); if (!trustEstablished) - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); @@ -1048,7 +1048,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); if (gatheredLocally > 0) { outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } // If we are a member of a cluster, distribute this GATHER across it @@ -1058,14 +1058,14 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); @@ -1081,19 +1081,19 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); if (com) - network->addCredential(com); + network->addCredential(tPtr,com); } - if (!network->gate(peer)) { + if (!network->gate(tPtr,peer)) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } if (network->config().multicastLimit == 0) { TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -1120,12 +1120,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -1134,14 +1134,14 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { - RR->node->putFrame(nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { + RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } } @@ -1155,14 +1155,14 @@ 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,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1170,7 +1170,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share return true; } -bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t now = RR->node->now(); @@ -1178,7 +1178,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1209,10 +1209,10 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1228,10 +1228,10 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->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->attemptToContactAt(InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1241,20 +1241,20 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - SharedPtr originator(RR->topology->getPeer(originatorAddress)); + SharedPtr originator(RR->topology->getPeer(tPtr,originatorAddress)); if (!originator) { - RR->sw->requestWhois(originatorAddress); + RR->sw->requestWhois(tPtr,originatorAddress); return false; } @@ -1285,7 +1285,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1304,14 +1304,14 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } - if (network->gate(peer)) + if (network->gate(tPtr,peer)) reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1327,7 +1327,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt for(unsigned int h=0;h nhp(RR->topology->getPeer(nextHop[h])); + SharedPtr nhp(RR->topology->getPeer(tPtr,nextHop[h])); if (nhp) { SharedPtr nhbp(nhp->getBestPath(now,false)); if ((nhbp)&&(nhbp->alive(now))) @@ -1362,7 +1362,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt nextHop[h].appendTo(outp); nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress } - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } // If there are next hops, forward the test along through the graph @@ -1377,19 +1377,19 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid outp.newInitializationVector(); outp.setDestination(nextHop[h]); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { ZT_CircuitTestReport report; @@ -1431,14 +1431,14 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S RR->node->postCircuitTestReport(&report); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) { @@ -1447,16 +1447,16 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPt um.typeId = at(ZT_PACKET_IDX_PAYLOAD); um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); - RR->node->postEvent(ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); + RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) +void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) { const uint64_t now = RR->node->now(); if (peer->rateGateOutgoingComRequest(now)) { @@ -1466,7 +1466,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,cons outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),now); + _path->send(RR,tPtr,outp.data(),outp.size(),now); } } diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index febff28a..3d4a2e05 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -102,9 +102,10 @@ public: * may no longer be valid. * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return True if decoding and processing is complete, false if caller should try again */ - bool tryDecode(const RuntimeEnvironment *RR); + bool tryDecode(const RuntimeEnvironment *RR,void *tPtr); /** * @return Time of packet receipt / start of decode @@ -114,26 +115,26 @@ public: private: // These are called internally to handle packet contents once it has // been authenticated, decrypted, decompressed, and classified. - bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated); - bool _doOK(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); - 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_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPtr &peer); - - void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); + bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated); + bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + + void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid); uint64_t _receiveTime; SharedPtr _path; diff --git a/node/Membership.cpp b/node/Membership.cpp index 3b2e3b1c..22c13c88 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -40,7 +40,7 @@ Membership::Membership() : for(unsigned int i=0;i= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) ); @@ -113,7 +113,7 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } @@ -123,7 +123,7 @@ const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) cons return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) { const uint64_t newts = com.timestamp().first; if (newts <= _comRevocationThreshold) { @@ -141,7 +141,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_ACCEPTED_REDUNDANT; } - switch(com.verify(RR)) { + switch(com.verify(RR,tPtr)) { default: TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId()); return ADD_REJECTED; @@ -154,7 +154,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential *)0; @@ -169,7 +169,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } - switch(tag.verify(RR)) { + switch(tag.verify(RR,tPtr)) { default: TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId()); return ADD_REJECTED; @@ -184,7 +184,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential *)0; @@ -199,7 +199,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } - switch(cap.verify(RR)) { + switch(cap.verify(RR,tPtr)) { default: TRACE("addCredential(Capability) for %s on %.16llx REJECTED (invalid)",cap.issuedTo().toString().c_str(),cap.networkId()); return ADD_REJECTED; @@ -214,9 +214,9 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev) { - switch(rev.verify(RR)) { + switch(rev.verify(RR,tPtr)) { default: return ADD_REJECTED; case 0: { @@ -239,7 +239,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential *)0; @@ -254,7 +254,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } - switch(coo.verify(RR)) { + switch(coo.verify(RR,tPtr)) { default: TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (invalid)",coo.issuedTo().toString().c_str(),coo.networkId()); return ADD_REJECTED; diff --git a/node/Membership.hpp b/node/Membership.hpp index 97510b57..c28d598c 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -158,13 +158,14 @@ public: * sends VERB_NETWORK_CREDENTIALS if the recipient might need them. * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param peerAddress Address of member peer (the one that this Membership describes) * @param nconf My network config * @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none * @param force If true, send objects regardless of last push time */ - void pushCredentials(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); + void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); /** * Check whether we should push MULTICAST_LIKEs to this peer @@ -226,27 +227,27 @@ public: /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo); private: _RemoteCredential *_newTag(const uint64_t id); diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index f8d58501..8e534b5e 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -43,14 +43,14 @@ Multicaster::~Multicaster() { } -void Multicaster::addMultiple(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) +void Multicaster::addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) { const unsigned char *p = (const unsigned char *)addresses; const unsigned char *e = p + (5 * count); Mutex::Lock _l(_groups_m); MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; while (p != e) { - _add(now,nwid,mg,gs,Address(p,5)); + _add(tPtr,now,nwid,mg,gs,Address(p,5)); p += 5; } } @@ -152,6 +152,7 @@ std::vector

Multicaster::getMembers(uint64_t nwid,const MulticastGroup } void Multicaster::send( + void *tPtr, unsigned int limit, uint64_t now, uint64_t nwid, @@ -207,7 +208,7 @@ void Multicaster::send( for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { if (*ast != RR->identity.address()) { - out.sendOnly(RR,*ast); // optimization: don't use dedup log if it's a one-pass send + out.sendOnly(RR,tPtr,*ast); // optimization: don't use dedup log if it's a one-pass send if (++count >= limit) break; } @@ -217,7 +218,7 @@ void Multicaster::send( while ((count < limit)&&(idx < gs.members.size())) { Address ma(gs.members[indexes[idx++]].address); if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendOnly(RR,ma); // optimization: don't use dedup log if it's a one-pass send + out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send ++count; } } @@ -256,7 +257,7 @@ void Multicaster::send( if (com) com->serialize(outp); RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } @@ -280,7 +281,7 @@ void Multicaster::send( for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { if (*ast != RR->identity.address()) { - out.sendAndLog(RR,*ast); + out.sendAndLog(RR,tPtr,*ast); if (++count >= limit) break; } @@ -290,7 +291,7 @@ void Multicaster::send( while ((count < limit)&&(idx < gs.members.size())) { Address ma(gs.members[indexes[idx++]].address); if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendAndLog(RR,ma); + out.sendAndLog(RR,tPtr,ma); ++count; } } @@ -352,15 +353,15 @@ void Multicaster::clean(uint64_t now) } } -void Multicaster::addCredential(const CertificateOfMembership &com,bool alreadyValidated) +void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated) { - if ((alreadyValidated)||(com.verify(RR) == 0)) { + if ((alreadyValidated)||(com.verify(RR,tPtr) == 0)) { Mutex::Lock _l(_gatherAuth_m); _gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now(); } } -void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) +void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) { // assumes _groups_m is locked @@ -383,7 +384,7 @@ void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,Multi if (tx->atLimit()) gs.txQueue.erase(tx++); else { - tx->sendIfNew(RR,member); + tx->sendIfNew(RR,tPtr,member); if (tx->atLimit()) gs.txQueue.erase(tx++); else ++tx; diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 32dec9cf..f646a5be 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -90,10 +90,10 @@ public: * @param mg Multicast group * @param member New member address */ - inline void add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) + inline void add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) { Mutex::Lock _l(_groups_m); - _add(now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); + _add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); } /** @@ -101,6 +101,7 @@ public: * * It's up to the caller to check bounds on the array before calling this. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param nwid Network ID * @param mg Multicast group @@ -108,7 +109,7 @@ public: * @param count Number of addresses * @param totalKnown Total number of known addresses as reported by peer */ - void addMultiple(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); + void addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); /** * Remove a multicast group member (if present) @@ -150,6 +151,7 @@ public: /** * Send a multicast * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param limit Multicast limit * @param now Current time * @param nwid Network ID @@ -162,6 +164,7 @@ public: * @param len Length of packet data */ void send( + void *tPtr, unsigned int limit, uint64_t now, uint64_t nwid, @@ -191,7 +194,7 @@ public: * @param com Certificate of membership * @param alreadyValidated If true, COM has already been checked and found to be valid and signed */ - void addCredential(const CertificateOfMembership &com,bool alreadyValidated); + void addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated); /** * Check authorization for GATHER and LIKE for non-network-members @@ -209,7 +212,7 @@ public: } private: - void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); + void _add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); const RuntimeEnvironment *RR; diff --git a/node/Network.cpp b/node/Network.cpp index 38c1b0d9..0abfdf86 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -674,7 +674,7 @@ static _doZtFilterResult _doZtFilter( const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); -Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : +Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr) : RR(renv), _uPtr(uptr), _id(nwid), @@ -696,11 +696,11 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : Dictionary *dconf = new Dictionary(); NetworkConfig *nconf = new NetworkConfig(); try { - std::string conf(RR->node->dataStoreGet(confn)); + std::string conf(RR->node->dataStoreGet(tPtr,confn)); if (conf.length()) { dconf->load(conf.c_str()); if (nconf->fromDictionary(*dconf)) { - this->setConfiguration(*nconf,false); + this->setConfiguration(tPtr,*nconf,false); _lastConfigUpdate = 0; // we still want to re-request a new config from the network gotConf = true; } @@ -711,13 +711,13 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : if (!gotConf) { // Save a one-byte CR to persist membership while we request a real netconf - RR->node->dataStorePut(confn,"\n",1,false); + RR->node->dataStorePut(tPtr,confn,"\n",1,false); } if (!_portInitialized) { ZT_VirtualNetworkConfig ctmp; _externalConfig(&ctmp); - _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); + _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); _portInitialized = true; } } @@ -729,15 +729,16 @@ Network::~Network() char n[128]; if (_destroyed) { - RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); + RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); - RR->node->dataStoreDelete(n); + RR->node->dataStoreDelete((void *)0,n); } else { - RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); + RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); } } bool Network::filterOutgoingPacket( + void *tPtr, const bool noTee, const Address &ztSource, const Address &ztDest, @@ -781,7 +782,7 @@ bool Network::filterOutgoingPacket( if ((!noTee)&&(cc2)) { Membership &m2 = _membership(cc2); - m2.pushCredentials(RR,now,cc2,_config,localCapabilityIndex,false); + m2.pushCredentials(RR,tPtr,now,cc2,_config,localCapabilityIndex,false); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -791,7 +792,7 @@ bool Network::filterOutgoingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength2); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } break; @@ -813,11 +814,11 @@ bool Network::filterOutgoingPacket( if (accept) { if (membership) - membership->pushCredentials(RR,now,ztDest,_config,localCapabilityIndex,false); + membership->pushCredentials(RR,tPtr,now,ztDest,_config,localCapabilityIndex,false); if ((!noTee)&&(cc)) { Membership &m2 = _membership(cc); - m2.pushCredentials(RR,now,cc,_config,localCapabilityIndex,false); + m2.pushCredentials(RR,tPtr,now,cc,_config,localCapabilityIndex,false); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -827,12 +828,12 @@ bool Network::filterOutgoingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } if ((ztDest != ztFinalDest)&&(ztFinalDest)) { Membership &m2 = _membership(ztFinalDest); - m2.pushCredentials(RR,now,ztFinalDest,_config,localCapabilityIndex,false); + m2.pushCredentials(RR,tPtr,now,ztFinalDest,_config,localCapabilityIndex,false); Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -842,7 +843,7 @@ bool Network::filterOutgoingPacket( outp.append((uint16_t)etherType); outp.append(frameData,frameLen); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); return false; // DROP locally, since we redirected } else { @@ -854,6 +855,7 @@ bool Network::filterOutgoingPacket( } int Network::filterIncomingPacket( + void *tPtr, const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, @@ -898,7 +900,7 @@ int Network::filterIncomingPacket( if (accept) { if (cc2) { - _membership(cc2).pushCredentials(RR,RR->node->now(),cc2,_config,-1,false); + _membership(cc2).pushCredentials(RR,tPtr,RR->node->now(),cc2,_config,-1,false); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -908,7 +910,7 @@ int Network::filterIncomingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength2); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } break; } @@ -929,7 +931,7 @@ int Network::filterIncomingPacket( if (accept) { if (cc) { - _membership(cc).pushCredentials(RR,RR->node->now(),cc,_config,-1,false); + _membership(cc).pushCredentials(RR,tPtr,RR->node->now(),cc,_config,-1,false); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -939,11 +941,11 @@ int Network::filterIncomingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - _membership(ztFinalDest).pushCredentials(RR,RR->node->now(),ztFinalDest,_config,-1,false); + _membership(ztFinalDest).pushCredentials(RR,tPtr,RR->node->now(),ztFinalDest,_config,-1,false); Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -953,7 +955,7 @@ int Network::filterIncomingPacket( outp.append((uint16_t)etherType); outp.append(frameData,frameLen); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); return 0; // DROP locally, since we redirected } @@ -972,12 +974,12 @@ bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBr return false; } -void Network::multicastSubscribe(const MulticastGroup &mg) +void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg) { Mutex::Lock _l(_lock); if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg); - _sendUpdatesToMembers(&mg); + _sendUpdatesToMembers(tPtr,&mg); } } @@ -989,7 +991,7 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.erase(i); } -uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) +uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) { const unsigned int start = ptr; @@ -1043,7 +1045,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc } // If it's not a duplicate, check chunk signature - const Identity controllerId(RR->topology->getIdentity(controller())); + const Identity controllerId(RR->topology->getIdentity(tPtr,controller())); if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? TRACE("unable to verify chunk from %s: don't have controller identity",source.toString().c_str()); return 0; @@ -1067,7 +1069,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc if ((*a != source)&&(*a != controller())) { Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG); outp.append(reinterpret_cast(chunk.data()) + start,chunk.size() - start); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } } @@ -1126,7 +1128,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc } if (nc) { - this->setConfiguration(*nc,true); + this->setConfiguration(tPtr,*nc,true); delete nc; return configUpdateId; } else { @@ -1136,7 +1138,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc return 0; } -int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) +int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk) { // _lock is NOT locked when this is called try { @@ -1156,7 +1158,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) _portInitialized = true; _externalConfig(&ctmp); } - _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); + _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); if (saveToDisk) { Dictionary *d = new Dictionary(); @@ -1164,7 +1166,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) char n[64]; Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); if (nconf.toDictionary(*d,false)) - RR->node->dataStorePut(n,(const void *)d->data(),d->sizeBytes(),true); + RR->node->dataStorePut(tPtr,n,(const void *)d->data(),d->sizeBytes(),true); } catch ( ... ) {} delete d; } @@ -1176,7 +1178,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) return 0; } -void Network::requestConfiguration() +void Network::requestConfiguration(void *tPtr) { /* ZeroTier addresses can't begin with 0xff, so this is used to mark controllerless * network IDs. Controllerless network IDs only support unicast IPv6 using the 6plane @@ -1236,7 +1238,7 @@ void Network::requestConfiguration() nconf->type = ZT_NETWORK_TYPE_PUBLIC; Utils::snprintf(nconf->name,sizeof(nconf->name),"adhoc-%.04x-%.04x",(int)startPortRange,(int)endPortRange); - this->setConfiguration(*nconf,false); + this->setConfiguration(tPtr,*nconf,false); delete nconf; } else { this->setNotFound(); @@ -1284,10 +1286,10 @@ void Network::requestConfiguration() } outp.compress(); RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } -bool Network::gate(const SharedPtr &peer) +bool Network::gate(void *tPtr,const SharedPtr &peer) { const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -1298,8 +1300,8 @@ bool Network::gate(const SharedPtr &peer) if (!m) m = &(_membership(peer->address())); if (m->shouldLikeMulticasts(now)) { - m->pushCredentials(RR,now,peer->address(),_config,-1,false); - _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); + m->pushCredentials(RR,tPtr,now,peer->address(),_config,-1,false); + _announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups()); m->likingMulticasts(now); } return true; @@ -1377,31 +1379,31 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) } } -void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) +void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now) { Mutex::Lock _l(_lock); const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _sendUpdatesToMembers(&mg); + _sendUpdatesToMembers(tPtr,&mg); } -Membership::AddCredentialResult Network::addCredential(const CertificateOfMembership &com) +Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com) { if (com.networkId() != _id) return Membership::ADD_REJECTED; const Address a(com.issuedTo()); Mutex::Lock _l(_lock); Membership &m = _membership(a); - const Membership::AddCredentialResult result = m.addCredential(RR,_config,com); + const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,com); if ((result == Membership::ADD_ACCEPTED_NEW)||(result == Membership::ADD_ACCEPTED_REDUNDANT)) { - m.pushCredentials(RR,RR->node->now(),a,_config,-1,false); - RR->mc->addCredential(com,true); + m.pushCredentials(RR,tPtr,RR->node->now(),a,_config,-1,false); + RR->mc->addCredential(tPtr,com,true); } return result; } -Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,const Revocation &rev) +Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev) { if (rev.networkId() != _id) return Membership::ADD_REJECTED; @@ -1409,7 +1411,7 @@ Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,c Mutex::Lock _l(_lock); Membership &m = _membership(rev.target()); - const Membership::AddCredentialResult result = m.addCredential(RR,_config,rev); + const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev); if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { Address *a = (Address *)0; @@ -1424,7 +1426,7 @@ Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,c outp.append((uint16_t)1); // one revocation! rev.serialize(outp); outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } } @@ -1495,7 +1497,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } } -void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup) +void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked const uint64_t now = RR->node->now(); @@ -1521,9 +1523,9 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou outp.append((uint16_t)0); // no tags outp.append((uint16_t)0); // no revocations outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } - _announceMulticastGroupsTo(*a,groups); + _announceMulticastGroupsTo(tPtr,*a,groups); } // Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it @@ -1537,9 +1539,9 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou outp.append((uint16_t)0); // no tags outp.append((uint16_t)0); // no revocations outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } - _announceMulticastGroupsTo(c,groups); + _announceMulticastGroupsTo(tPtr,c,groups); } } @@ -1556,17 +1558,17 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - m->pushCredentials(RR,now,*a,_config,-1,false); + m->pushCredentials(RR,tPtr,now,*a,_config,-1,false); if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { if (!newMulticastGroup) m->likingMulticasts(now); - _announceMulticastGroupsTo(*a,groups); + _announceMulticastGroupsTo(tPtr,*a,groups); } } } } -void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups) +void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups) { // Assumes _lock is locked Packet outp(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); @@ -1574,7 +1576,7 @@ void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); outp.reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } @@ -1586,7 +1588,7 @@ void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector ZT_PROTO_MIN_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } diff --git a/node/Network.hpp b/node/Network.hpp index 6cf6d974..fccc267a 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -77,10 +77,11 @@ public: * constructed to actually configure the port. * * @param renv Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param nwid Network ID * @param uptr Arbitrary pointer used by externally-facing API (for user use) */ - Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr); + Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr); ~Network(); @@ -101,6 +102,7 @@ public: * such as TEE may be taken, and credentials may be pushed, so this is not * side-effect-free. It's basically step one in sending something over VL2. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) * @param ztSource Source ZeroTier address * @param ztDest Destination ZeroTier address @@ -113,6 +115,7 @@ public: * @return True if packet should be sent, false if dropped or redirected */ bool filterOutgoingPacket( + void *tPtr, const bool noTee, const Address &ztSource, const Address &ztDest, @@ -131,6 +134,7 @@ public: * a match certain actions may be taken such as sending a copy of the packet * to a TEE or REDIRECT target. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param sourcePeer Source Peer * @param ztDest Destination ZeroTier address * @param macSource Ethernet layer source address @@ -142,6 +146,7 @@ public: * @return 0 == drop, 1 == accept, 2 == accept even if bridged */ int filterIncomingPacket( + void *tPtr, const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, @@ -163,9 +168,10 @@ public: /** * Subscribe to a multicast group * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param mg New multicast group */ - void multicastSubscribe(const MulticastGroup &mg); + void multicastSubscribe(void *tPtr,const MulticastGroup &mg); /** * Unsubscribe from a multicast group @@ -181,22 +187,24 @@ public: * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies * each chunk and once assembled applies the configuration. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param packetId Packet ID or 0 if none (e.g. via cluster path) * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) * @param chunk Buffer containing chunk * @param ptr Index of chunk and related fields in packet * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - uint64_t handleConfigChunk(const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); + uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); /** * Set network configuration * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param nconf Network configuration * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new */ - int setConfiguration(const NetworkConfig &nconf,bool saveToDisk); + int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk); /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this @@ -218,13 +226,18 @@ public: /** * Causes this network to request an updated configuration from its master node now + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - void requestConfiguration(); + void requestConfiguration(void *tPtr); /** * Determine whether this peer is permitted to communicate on this network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param peer Peer to check */ - bool gate(const SharedPtr &peer); + bool gate(void *tPtr,const SharedPtr &peer); /** * Do periodic cleanup and housekeeping tasks @@ -233,11 +246,13 @@ public: /** * Push state to members such as multicast group memberships and latest COM (if needed) + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - inline void sendUpdatesToMembers() + inline void sendUpdatesToMembers(void *tPtr) { Mutex::Lock _l(_lock); - _sendUpdatesToMembers((const MulticastGroup *)0); + _sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); } /** @@ -264,64 +279,66 @@ public: /** * Learn a multicast group that is bridged to our tap device * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param mg Multicast group * @param now Current time */ - void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now); + void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now); /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(const CertificateOfMembership &com); + Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com); /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(const Capability &cap) + inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) { if (cap.networkId() != _id) return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(cap.issuedTo()).addCredential(RR,_config,cap); + return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap); } /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(const Tag &tag) + inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) { if (tag.networkId() != _id) return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(tag.issuedTo()).addCredential(RR,_config,tag); + return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag); } /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(const Address &sentFrom,const Revocation &rev); + Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(const CertificateOfOwnership &coo) + inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) { if (coo.networkId() != _id) return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(coo.issuedTo()).addCredential(RR,_config,coo); + return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo); } /** * Force push credentials (COM, etc.) to a peer now * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param to Destination peer address * @param now Current time */ - inline void pushCredentialsNow(const Address &to,const uint64_t now) + inline void pushCredentialsNow(void *tPtr,const Address &to,const uint64_t now) { Mutex::Lock _l(_lock); - _membership(to).pushCredentials(RR,now,to,_config,-1,true); + _membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true); } /** @@ -353,8 +370,8 @@ private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _gate(const SharedPtr &peer); - void _sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup); - void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); + void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); + void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; Membership &_membership(const Address &a); diff --git a/node/Node.cpp b/node/Node.cpp index 1125ca7a..4e8d6655 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,7 +46,7 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : +Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : _RR(this), RR(&_RR), _uPtr(uptr), @@ -72,26 +72,26 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : memset(_prngStream,0,sizeof(_prngStream)); _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); - std::string idtmp(dataStoreGet("identity.secret")); + std::string idtmp(dataStoreGet(tptr,"identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { TRACE("identity.secret not found, generating..."); RR->identity.generate(); idtmp = RR->identity.toString(true); - if (!dataStorePut("identity.secret",idtmp,true)) + if (!dataStorePut(tptr,"identity.secret",idtmp,true)) throw std::runtime_error("unable to write identity.secret"); } RR->publicIdentityStr = RR->identity.toString(false); RR->secretIdentityStr = RR->identity.toString(true); - idtmp = dataStoreGet("identity.public"); + idtmp = dataStoreGet(tptr,"identity.public"); if (idtmp != RR->publicIdentityStr) { - if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) + if (!dataStorePut(tptr,"identity.public",RR->publicIdentityStr,false)) throw std::runtime_error("unable to write identity.public"); } try { RR->sw = new Switch(RR); RR->mc = new Multicaster(RR); - RR->topology = new Topology(RR); + RR->topology = new Topology(RR,tptr); RR->sa = new SelfAwareness(RR); } catch ( ... ) { delete RR->sa; @@ -101,7 +101,7 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : throw; } - postEvent(ZT_EVENT_UP); + postEvent(tptr,ZT_EVENT_UP); } Node::~Node() @@ -121,6 +121,7 @@ Node::~Node() } ZT_ResultCode Node::processWirePacket( + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -129,11 +130,12 @@ ZT_ResultCode Node::processWirePacket( volatile uint64_t *nextBackgroundTaskDeadline) { _now = now; - RR->sw->onRemotePacket(*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); + RR->sw->onRemotePacket(tptr,*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); return ZT_RESULT_OK; } ZT_ResultCode Node::processVirtualNetworkFrame( + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -147,7 +149,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( _now = now; SharedPtr nw(this->network(nwid)); if (nw) { - RR->sw->onLocalEthernet(nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); + RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); return ZT_RESULT_OK; } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } @@ -156,9 +158,10 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : lastReceiveFromUpstream(0), RR(renv), + _tPtr(tPtr), _upstreamsToContact(upstreamsToContact), _now(now), _bestCurrentUpstream(RR->topology->getUpstreamPeer()) @@ -176,21 +179,21 @@ public: // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow // them to perform three way handshake introductions for both stacks. - if (!p->doPingAndKeepalive(_now,AF_INET)) { + if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); contacted = true; break; } } } else contacted = true; - if (!p->doPingAndKeepalive(_now,AF_INET6)) { + if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET6)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); contacted = true; break; } @@ -200,24 +203,25 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); + p->sendHELLO(_tPtr,up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); _upstreamsToContact.erase(p->address()); // erase from upstreams to contact so that we can WHOIS those that remain } else if (p->isActive(_now)) { - p->doPingAndKeepalive(_now,-1); + p->doPingAndKeepalive(_tPtr,_now,-1); } } private: const RuntimeEnvironment *RR; + void *_tPtr; Hashtable< Address,std::vector > &_upstreamsToContact; const uint64_t _now; const SharedPtr _bestCurrentUpstream; }; -ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) { _now = now; Mutex::Lock bl(_backgroundTasksLock); @@ -235,16 +239,16 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - n->second->sendUpdatesToMembers(); + n->second->sendUpdatesToMembers(tptr); } } for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) - (*n)->requestConfiguration(); + (*n)->requestConfiguration(tptr); // Do pings and keepalives Hashtable< Address,std::vector > upstreamsToContact; RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,upstreamsToContact,now); + _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) @@ -252,13 +256,13 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB Address *upstreamAddress = (Address *)0; std::vector *upstreamStableEndpoints = (std::vector *)0; while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(*upstreamAddress); + RR->sw->requestWhois(tptr,*upstreamAddress); // Update online status, post status change as event const bool oldOnline = _online; _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); if (oldOnline != _online) - postEvent(_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); + postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -286,7 +290,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate } else { #endif - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); + *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); #ifdef ZT_ENABLE_CLUSTER } #endif @@ -297,17 +301,17 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB return ZT_RESULT_OK; } -ZT_ResultCode Node::join(uint64_t nwid,void *uptr) +ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr) { Mutex::Lock _l(_networks_m); SharedPtr nw = _network(nwid); if(!nw) - _networks.push_back(std::pair< uint64_t,SharedPtr >(nwid,SharedPtr(new Network(RR,nwid,uptr)))); + _networks.push_back(std::pair< uint64_t,SharedPtr >(nwid,SharedPtr(new Network(RR,tptr,nwid,uptr)))); std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<> return ZT_RESULT_OK; } -ZT_ResultCode Node::leave(uint64_t nwid,void **uptr) +ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr) { std::vector< std::pair< uint64_t,SharedPtr > > newn; Mutex::Lock _l(_networks_m); @@ -324,11 +328,11 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr) return ZT_RESULT_OK; } -ZT_ResultCode Node::multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +ZT_ResultCode Node::multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) { SharedPtr nw(this->network(nwid)); if (nw) { - nw->multicastSubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); + nw->multicastSubscribe(tptr,MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); return ZT_RESULT_OK; } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } @@ -342,15 +346,15 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } -ZT_ResultCode Node::orbit(uint64_t moonWorldId,uint64_t moonSeed) +ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed) { - RR->topology->addMoon(moonWorldId,Address(moonSeed)); + RR->topology->addMoon(tptr,moonWorldId,Address(moonSeed)); return ZT_RESULT_OK; } -ZT_ResultCode Node::deorbit(uint64_t moonWorldId) +ZT_ResultCode Node::deorbit(void *tptr,uint64_t moonWorldId) { - RR->topology->removeMoon(moonWorldId); + RR->topology->removeMoon(tptr,moonWorldId); return ZT_RESULT_OK; } @@ -465,7 +469,7 @@ void Node::clearLocalInterfaceAddresses() _directPaths.clear(); } -int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) { try { if (RR->identity.address().toInt() != dest) { @@ -473,7 +477,7 @@ int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigne outp.append(typeId); outp.append(data,len); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tptr,outp,true); return 1; } } catch ( ... ) {} @@ -486,7 +490,7 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController->init(RR->identity,this); } -ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { if (test->hopCount > 0) { try { @@ -516,7 +520,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[0].breadth;++a) { outp.newInitializationVector(); outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(outp,true); + RR->sw->send(tptr,outp,true); } } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet @@ -616,13 +620,13 @@ void Node::clusterStatus(ZT_ClusterStatus *cs) /* Node methods used only within node/ */ /****************************************************************************/ -std::string Node::dataStoreGet(const char *name) +std::string Node::dataStoreGet(void *tPtr,const char *name) { char buf[1024]; std::string r; unsigned long olen = 0; do { - long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); + long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,tPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); @@ -630,7 +634,7 @@ std::string Node::dataStoreGet(const char *name) return r; } -bool Node::shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) { if (!Path::isAddressValidForPath(remoteAddress)) return false; @@ -650,7 +654,7 @@ bool Node::shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddre } } - return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); + return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); } #ifdef ZT_TRACE @@ -728,7 +732,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de if (destination == RR->identity.address()) { SharedPtr n(network(nwid)); if (!n) return; - n->setConfiguration(nc,true); + n->setConfiguration((void *)0,nc,true); } else { Dictionary *dconf = new Dictionary(); try { @@ -762,7 +766,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); chunkIndex += chunkLen; } } @@ -779,7 +783,7 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev) if (destination == RR->identity.address()) { SharedPtr n(network(rev.networkId())); if (!n) return; - n->addCredential(RR->identity.address(),rev); + n->addCredential((void *)0,RR->identity.address(),rev); } else { Packet outp(destination,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); outp.append((uint8_t)0x00); @@ -788,7 +792,7 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev) outp.append((uint16_t)1); rev.serialize(outp); outp.append((uint16_t)0); - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); } } @@ -823,7 +827,7 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des break; } outp.append(nwid); - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); } // else we can't send an ERROR() in response to nothing, so discard } @@ -835,11 +839,11 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) { *node = (ZT_Node *)0; try { - *node = reinterpret_cast(new ZeroTier::Node(uptr,callbacks,now)); + *node = reinterpret_cast(new ZeroTier::Node(uptr,tptr,callbacks,now)); return ZT_RESULT_OK; } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; @@ -859,6 +863,7 @@ void ZT_Node_delete(ZT_Node *node) enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -867,7 +872,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processWirePacket(now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processWirePacket(tptr,now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -877,6 +882,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -888,7 +894,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processVirtualNetworkFrame(now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -896,10 +902,10 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( } } -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processBackgroundTasks(now,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -907,10 +913,10 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol } } -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr) +enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr) { try { - return reinterpret_cast(node)->join(nwid,uptr); + return reinterpret_cast(node)->join(nwid,uptr,tptr); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -918,10 +924,10 @@ enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr) } } -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr) +enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr) { try { - return reinterpret_cast(node)->leave(nwid,uptr); + return reinterpret_cast(node)->leave(nwid,uptr,tptr); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -929,10 +935,10 @@ enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr) } } -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) { try { - return reinterpret_cast(node)->multicastSubscribe(nwid,multicastGroup,multicastAdi); + return reinterpret_cast(node)->multicastSubscribe(tptr,nwid,multicastGroup,multicastAdi); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -951,19 +957,19 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint } } -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId,uint64_t moonSeed) +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed) { try { - return reinterpret_cast(node)->orbit(moonWorldId,moonSeed); + return reinterpret_cast(node)->orbit(tptr,moonWorldId,moonSeed); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } } -ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId) +ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) { try { - return reinterpret_cast(node)->deorbit(moonWorldId); + return reinterpret_cast(node)->deorbit(tptr,moonWorldId); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -1031,10 +1037,10 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) } catch ( ... ) {} } -int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) { try { - return reinterpret_cast(node)->sendUserMessage(dest,typeId,data,len); + return reinterpret_cast(node)->sendUserMessage(tptr,dest,typeId,data,len); } catch ( ... ) { return 0; } @@ -1047,10 +1053,10 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { try { - return reinterpret_cast(node)->circuitTestBegin(test,reportCallback); + return reinterpret_cast(node)->circuitTestBegin(tptr,test,reportCallback); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } diff --git a/node/Node.hpp b/node/Node.hpp index 21eac617..03bd7a8c 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -65,7 +65,7 @@ class World; class Node : public NetworkController::Sender { public: - Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); + Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); virtual ~Node(); // Get rid of alignment warnings on 32-bit Windows and possibly improve performance @@ -77,6 +77,7 @@ public: // Public API Functions ---------------------------------------------------- ZT_ResultCode processWirePacket( + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -84,6 +85,7 @@ public: unsigned int packetLength, volatile uint64_t *nextBackgroundTaskDeadline); ZT_ResultCode processVirtualNetworkFrame( + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -93,13 +95,13 @@ public: const void *frameData, unsigned int frameLength, volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode join(uint64_t nwid,void *uptr); - ZT_ResultCode leave(uint64_t nwid,void **uptr); - ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); + ZT_ResultCode processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); + ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); + ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); + ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode orbit(uint64_t moonWorldId,uint64_t moonSeed); - ZT_ResultCode deorbit(uint64_t moonWorldId); + ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed); + ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId); uint64_t address() const; void status(ZT_NodeStatus *status) const; ZT_PeerList *peers() const; @@ -108,9 +110,9 @@ public: void freeQueryResult(void *qr); int addLocalInterfaceAddress(const struct sockaddr_storage *addr); void clearLocalInterfaceAddresses(); - int sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len); + int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); void setNetconfMaster(void *networkControllerInstance); - ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); + ZT_ResultCode circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); void circuitTestEnd(ZT_CircuitTest *test); ZT_ResultCode clusterInit( unsigned int myId, @@ -132,11 +134,12 @@ public: inline uint64_t now() const throw() { return _now; } - inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) + inline bool putPacket(void *tPtr,const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { return (_cb.wirePacketSendFunction( reinterpret_cast(this), _uPtr, + tPtr, reinterpret_cast(&localAddress), reinterpret_cast(&addr), data, @@ -144,11 +147,12 @@ public: ttl) == 0); } - inline void putFrame(uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) + inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { _cb.virtualNetworkFrameFunction( reinterpret_cast(this), _uPtr, + tPtr, nwid, nuptr, source.toInt(), @@ -191,14 +195,14 @@ public: return _directPaths; } - inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } - inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } - inline void dataStoreDelete(const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } - std::string dataStoreGet(const char *name); + inline bool dataStorePut(void *tPtr,const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,tPtr,name,data,len,(int)secure) == 0); } + inline bool dataStorePut(void *tPtr,const char *name,const std::string &data,bool secure) { return dataStorePut(tPtr,name,(const void *)data.data(),(unsigned int)data.length(),secure); } + inline void dataStoreDelete(void *tPtr,const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,tPtr,name,(const void *)0,0,0); } + std::string dataStoreGet(void *tPtr,const char *name); - inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,ev,md); } + inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,tPtr,ev,md); } - inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } + inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,tPtr,nwid,nuptr,op,nc); } inline bool online() const throw() { return _online; } @@ -206,8 +210,8 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif - bool shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); - inline bool externalPathLookup(const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } + bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); + inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); void postCircuitTestReport(const ZT_CircuitTestReport *report); diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index d4cb87cb..285bfa5d 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -85,18 +85,18 @@ void OutboundMulticast::init( memcpy(_frameData,payload,_frameLen); } -void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toAddr) +void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) { const SharedPtr nw(RR->node->network(_nwid)); const Address toAddr2(toAddr); - if ((nw)&&(nw->filterOutgoingPacket(true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { + if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr2); RR->node->expectReplyTo(_packet.packetId()); Packet tmp(_packet); // make a copy of packet so as not to garble the original -- GitHub issue #461 - RR->sw->send(tmp,true); + RR->sw->send(tPtr,tmp,true); } } diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 6370d0d7..0ecf113f 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -99,33 +99,36 @@ public: * Just send without checking log * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param toAddr Destination address */ - void sendOnly(const RuntimeEnvironment *RR,const Address &toAddr); + void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr); /** * Just send and log but do not check sent log * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param toAddr Destination address */ - inline void sendAndLog(const RuntimeEnvironment *RR,const Address &toAddr) + inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) { _alreadySentTo.push_back(toAddr); - sendOnly(RR,toAddr); + sendOnly(RR,tPtr,toAddr); } /** * Try to send this to a given peer if it hasn't been sent to them already * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param toAddr Destination address * @return True if address is new and packet was sent to switch, false if duplicate */ - inline bool sendIfNew(const RuntimeEnvironment *RR,const Address &toAddr) + inline bool sendIfNew(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) { if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) { - sendAndLog(RR,toAddr); + sendAndLog(RR,tPtr,toAddr); return true; } else { return false; diff --git a/node/Path.cpp b/node/Path.cpp index 5592bacc..7366b56f 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -22,9 +22,9 @@ namespace ZeroTier { -bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) +bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) { - if (RR->node->putPacket(_localAddress,address(),data,len)) { + if (RR->node->putPacket(tPtr,_localAddress,address(),data,len)) { _lastOut = now; return true; } diff --git a/node/Path.hpp b/node/Path.hpp index 62f29c22..aef628d4 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -186,12 +186,13 @@ public: * Send a packet via this path (last out time is also updated) * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @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); + bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now); /** * Manually update last sent time diff --git a/node/Peer.cpp b/node/Peer.cpp index fa3ce6c8..0cc23e33 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -68,6 +68,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident } void Peer::received( + void *tPtr, const SharedPtr &path, const unsigned int hops, const uint64_t packetId, @@ -161,7 +162,7 @@ void Peer::received( } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); @@ -206,7 +207,7 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); + attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } } @@ -281,7 +282,7 @@ void Peer::received( if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,outp.data(),outp.size(),now); + path->send(RR,tPtr,outp.data(),outp.size(),now); } } } @@ -299,7 +300,7 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const return false; } -bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) { Mutex::Lock _l(_paths_m); @@ -316,7 +317,7 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE } if (bestp >= 0) { - return _paths[bestp].path->send(RR,data,len,now); + return _paths[bestp].path->send(RR,tPtr,data,len,now); } else { return false; } @@ -345,7 +346,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) } } -void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -387,35 +388,35 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u if (atAddress) { outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); } else { - RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC + RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true,counter); - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); } else { - sendHELLO(localAddr,atAddress,now,counter); + sendHELLO(tPtr,localAddr,atAddress,now,counter); } } -void Peer::tryMemorizedPath(uint64_t now) +void Peer::tryMemorizedPath(void *tPtr,uint64_t now) { if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { _lastTriedMemorizedPath = now; InetAddress mp; - if (RR->node->externalPathLookup(_id.address(),-1,mp)) - attemptToContactAt(InetAddress(),mp,now,true,0); + if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) + attemptToContactAt(tPtr,InetAddress(),mp,now,true,0); } } -bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) +bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); @@ -433,7 +434,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); _paths[bestp].path->sent(now); } return true; @@ -452,12 +453,12 @@ bool Peer::hasActiveDirectPath(uint64_t now) const return false; } -void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) +void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); _paths[p].path->sent(now); _paths[p].lastReceive = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index 72040b1d..41836410 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -84,6 +84,7 @@ public: * This is called by the decode pipe when a packet is proven to be authentic * and appears to be valid. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param path Path over which packet was received * @param hops ZeroTier (not IP) hops * @param packetId Packet ID @@ -93,6 +94,7 @@ public: * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established */ void received( + void *tPtr, const SharedPtr &path, const unsigned int hops, const uint64_t packetId, @@ -125,13 +127,14 @@ public: /** * Send via best direct path * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param data Packet data * @param len Packet length * @param now Current time * @param forceEvenIfDead If true, send even if the path is not 'alive' * @return True if we actually sent something */ - bool sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); /** * Get the best current direct path @@ -147,41 +150,47 @@ public: * * No statistics or sent times are updated here. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localAddr Local address * @param atAddress Destination address * @param now Current time * @param counter Outgoing packet counter */ - void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address * * No statistics or sent times are updated here. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localAddr Local address * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param counter Outgoing packet counter */ - void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known * * Under the hood this is done periodically based on ZT_TRY_MEMORIZED_PATH_INTERVAL. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time */ - void tryMemorizedPath(uint64_t now); + void tryMemorizedPath(void *tPtr,uint64_t now); /** * Send pings or keepalives depending on configured timeouts * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param inetAddressFamily Keep this address family alive, or -1 for any * @return True if we have at least one direct path of the given family (or any if family is -1) */ - bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); + bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); /** * @param now Current time @@ -195,11 +204,12 @@ public: * Resetting a path involves sending an ECHO to it and then deactivating * it until or unless it responds. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param scope IP scope * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - void resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); /** * Get most recently active path addresses for IPv4 and/or IPv6 diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 420476a4..bab5653c 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -25,13 +25,13 @@ namespace ZeroTier { -int Revocation::verify(const RuntimeEnvironment *RR) const +int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } try { diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 93c55112..8b9ce6dd 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -113,9 +113,10 @@ public: * Verify this revocation's signature * * @param RR Runtime environment to provide for peer lookup, etc. + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template inline void serialize(Buffer &b,const bool forSign = false) const diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index e84b7b65..cba84cdc 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -40,15 +40,17 @@ namespace ZeroTier { class _ResetWithinScope { public: - _ResetWithinScope(uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : + _ResetWithinScope(void *tPtr,uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : _now(now), + _tPtr(tPtr), _family(inetAddressFamily), _scope(scope) {} - inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_scope,_family,_now); } + inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); } private: uint64_t _now; + void *_tPtr; int _family; InetAddress::IpScope _scope; }; @@ -59,7 +61,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) +void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -91,7 +93,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc } // Reset all paths within this scope and address family - _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); + _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); } else { // Otherwise just update DB to use to determine external surface info diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4bdafeb2..c1db0c84 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -47,7 +47,7 @@ public: * @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param now Current time */ - void iam(const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); + void iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); /** * Clean up database periodically diff --git a/node/Switch.cpp b/node/Switch.cpp index aab2e7ff..62674472 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -64,7 +64,7 @@ Switch::Switch(const RuntimeEnvironment *renv) : { } -void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) +void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) { try { const uint64_t now = RR->node->now(); @@ -81,15 +81,15 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from const Address beaconAddr(reinterpret_cast(data) + 8,5); if (beaconAddr == RR->identity.address()) return; - if (!RR->node->shouldUsePathForZeroTierTraffic(beaconAddr,localAddr,fromAddr)) + if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localAddr,fromAddr)) return; - const SharedPtr peer(RR->topology->getPeer(beaconAddr)); + const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr)); if (peer) { // we'll only respond to beacons from known peers if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses _lastBeaconResponse = now; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); outp.armor(peer->key(),true,path->nextOutgoingCounter()); - path->send(RR,outp.data(),outp.size(),now); + path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -115,8 +115,8 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. - SharedPtr relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(!relayTo->sendDirect(fragment.data(),fragment.size(),now,false))) { + SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); + if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { #ifdef ZT_ENABLE_CLUSTER if ((RR->cluster)&&(!isClusterFrontplane)) { RR->cluster->relayViaCluster(Address(),destination,fragment.data(),fragment.size(),false); @@ -127,7 +127,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Don't know peer or no direct path -- so relay via someone upstream relayTo = RR->topology->getUpstreamPeer(); if (relayTo) - relayTo->sendDirect(fragment.data(),fragment.size(),now,true); + relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -171,7 +171,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - if (rq->frag0.tryDecode(RR)) { + if (rq->frag0.tryDecode(RR,tPtr)) { rq->timestamp = 0; // packet decoded, free entry } else { rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something @@ -212,8 +212,8 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from packet.incrementHops(); #endif - SharedPtr relayTo = RR->topology->getPeer(destination); - if ((relayTo)&&(relayTo->sendDirect(packet.data(),packet.size(),now,false))) { + SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); + if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { // don't send RENDEZVOUS for cluster frontplane relays const InetAddress *hintToSource = (InetAddress *)0; const InetAddress *hintToDest = (InetAddress *)0; @@ -222,7 +222,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from InetAddress sourceV4,sourceV6; relayTo->getRendezvousAddresses(now,destV4,destV6); - const SharedPtr sourcePeer(RR->topology->getPeer(source)); + const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); if (sourcePeer) { sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6); if ((destV6)&&(sourceV6)) { @@ -249,7 +249,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from outp.append((uint8_t)4); outp.append(hintToSource->rawIpData(),4); } - send(outp,true); + send(tPtr,outp,true); } else { Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS); outp.append((uint8_t)0); @@ -262,7 +262,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from outp.append((uint8_t)4); outp.append(hintToDest->rawIpData(),4); } - send(outp,true); + send(tPtr,outp,true); } ++alt; } @@ -278,7 +278,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from #endif relayTo = RR->topology->getUpstreamPeer(&source,1,true); if (relayTo) - relayTo->sendDirect(packet.data(),packet.size(),now,true); + relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -321,7 +321,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from for(unsigned int f=1;ftotalFragments;++f) rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - if (rq->frag0.tryDecode(RR)) { + if (rq->frag0.tryDecode(RR,tPtr)) { rq->timestamp = 0; // packet decoded, free entry } else { rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something @@ -334,7 +334,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } else { // Packet is unfragmented, so just process it IncomingPacket packet(data,len,path,now); - if (!packet.tryDecode(RR)) { + if (!packet.tryDecode(RR,tPtr)) { Mutex::Lock _l(_rxQueue_m); RXQueueEntry *rq = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]); unsigned long i = ZT_RX_QUEUE_SIZE - 1; @@ -362,7 +362,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } } -void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { if (!network->hasConfig()) return; @@ -474,7 +474,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c adv[42] = (checksum >> 8) & 0xff; adv[43] = checksum & 0xff; - RR->node->putFrame(network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); + RR->node->putFrame(tPtr,network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query. } // else no NDP emulation } // else no NDP emulation @@ -491,17 +491,18 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * multicast addresses on bridge interfaces and subscribing each slave. * But in that case this does no harm, as the sets are just merged. */ if (fromBridged) - network->learnBridgedMulticastGroup(multicastGroup,RR->node->now()); + network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now()); //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. - if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } RR->mc->send( + tPtr, network->config().multicastLimit, RR->node->now(), network->id(), @@ -514,14 +515,14 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c len); } else if (to == network->mac()) { // Destination is this node, so just reinject it - RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,vlanId,data,len); + RR->node->putFrame(tPtr,network->id(),network->userPtr(),from,to,etherType,vlanId,data,len); } else if (to[0] == MAC::firstOctetForNetwork(network->id())) { // Destination is another ZeroTier peer on the same network Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this - SharedPtr toPeer(RR->topology->getPeer(toZT)); + SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); - if (!network->filterOutgoingPacket(false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } @@ -536,7 +537,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append(data,len); if (!network->config().disableCompression()) outp.compress(); - send(outp,true); + send(tPtr,outp,true); } else { Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); @@ -544,7 +545,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append(data,len); if (!network->config().disableCompression()) outp.compress(); - send(outp,true); + send(tPtr,outp,true); } //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); @@ -554,7 +555,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c // We filter with a NULL destination ZeroTier address first. Filtrations // for each ZT destination are also done below. This is the same rationale // and design as for multicast. - if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } @@ -592,7 +593,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } for(unsigned int b=0;bfilterOutgoingPacket(true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (network->filterOutgoingPacket(tPtr,true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId)) { Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); outp.append((uint8_t)0x00); @@ -602,7 +603,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append(data,len); if (!network->config().disableCompression()) outp.compress(); - send(outp,true); + send(tPtr,outp,true); } else { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); } @@ -610,20 +611,20 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } } -void Switch::send(Packet &packet,bool encrypt) +void Switch::send(void *tPtr,Packet &packet,bool encrypt) { if (packet.destination() == RR->identity.address()) { TRACE("BUG: caught attempt to send() to self, ignored"); return; } - if (!_trySend(packet,encrypt)) { + if (!_trySend(tPtr,packet,encrypt)) { Mutex::Lock _l(_txQueue_m); _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); } } -void Switch::requestWhois(const Address &addr) +void Switch::requestWhois(void *tPtr,const Address &addr) { #ifdef ZT_TRACE if (addr == RR->identity.address()) { @@ -644,10 +645,10 @@ void Switch::requestWhois(const Address &addr) } } if (inserted) - _sendWhoisRequest(addr,(const Address *)0,0); + _sendWhoisRequest(tPtr,addr,(const Address *)0,0); } -void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) +void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) { { // cancel pending WHOIS since we now know this peer Mutex::Lock _l(_outstandingWhoisRequests_m); @@ -660,7 +661,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) while (i) { RXQueueEntry *rq = &(_rxQueue[--i]); if ((rq->timestamp)&&(rq->complete)) { - if (rq->frag0.tryDecode(RR)) + if (rq->frag0.tryDecode(RR,tPtr)) rq->timestamp = 0; } } @@ -670,7 +671,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else ++txi; } else ++txi; @@ -678,7 +679,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) } } -unsigned long Switch::doTimerTasks(uint64_t now) +unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) { unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum @@ -695,7 +696,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) _outstandingWhoisRequests.erase(*a); } else { r->lastSent = now; - r->peersConsulted[r->retries] = _sendWhoisRequest(*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); + r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); TRACE("WHOIS %s (retry %u)",a->toString().c_str(),r->retries); ++r->retries; nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); @@ -709,7 +710,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); @@ -743,19 +744,19 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address return false; } -Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) +Address Switch::_sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { SharedPtr upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); if (upstream) { Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); RR->node->expectReplyTo(outp.packetId()); - send(outp,true); + send(tPtr,outp,true); } return Address(); } -bool Switch::_trySend(Packet &packet,bool encrypt) +bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; const uint64_t now = RR->node->now(); @@ -769,7 +770,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) clusterMostRecentMemberId = RR->cluster->checkSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); #endif - const SharedPtr peer(RR->topology->getPeer(destination)); + const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); if (peer) { /* First get the best path, and if it's dead (and this is not a root) * we attempt to re-activate that path but this packet will flow @@ -784,7 +785,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { #endif if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); + peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } #ifdef ZT_ENABLE_CLUSTER @@ -801,7 +802,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #else if (!viaPath) { #endif - peer->tryMemorizedPath(now); // periodically attempt memorized or statically defined paths, if any are known + peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known const SharedPtr relay(RR->topology->getUpstreamPeer()); if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { if (!(viaPath = peer->getBestPath(now,true))) @@ -816,7 +817,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #ifdef ZT_ENABLE_CLUSTER if (clusterMostRecentMemberId < 0) { #else - requestWhois(destination); + requestWhois(tPtr,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly #endif #ifdef ZT_ENABLE_CLUSTER @@ -844,9 +845,9 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #endif #ifdef ZT_ENABLE_CLUSTER - if ( ((viaPath)&&(viaPath->send(RR,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { + if ( ((viaPath)&&(viaPath->send(RR,tPtr,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { #else - if (viaPath->send(RR,packet.data(),chunkSize,now)) { + if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { #endif if (chunkSize < packet.size()) { // Too big for one packet, fragment the rest @@ -866,7 +867,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) else if (clusterMostRecentMemberId >= 0) RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,frag.data(),frag.size()); #else - viaPath->send(RR,frag.data(),frag.size(),now); + viaPath->send(RR,tPtr,frag.data(),frag.size(),now); #endif fragStart += chunkSize; remaining -= chunkSize; diff --git a/node/Switch.hpp b/node/Switch.hpp index 9245c036..ff350934 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -59,16 +59,18 @@ public: /** * Called when a packet is received from the real network * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localAddr Local interface address * @param fromAddr Internet IP address of origin * @param data Packet data * @param len Packet length */ - void onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); + void onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); /** * Called when a packet comes from a local Ethernet tap * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param network Which network's TAP did this packet come from? * @param from Originating MAC address * @param to Destination MAC address @@ -77,7 +79,7 @@ public: * @param data Ethernet payload * @param len Frame length */ - void onLocalEthernet(const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); + void onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); /** * Send a packet to a ZeroTier address (destination in packet) @@ -91,26 +93,29 @@ public: * Needless to say, the packet's source must be this node. Otherwise it * won't be encrypted right. (This is not used for relaying.) * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param packet Packet to send (buffer may be modified) * @param encrypt Encrypt packet payload? (always true except for HELLO) */ - void send(Packet &packet,bool encrypt); + void send(void *tPtr,Packet &packet,bool encrypt); /** * Request WHOIS on a given address * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param addr Address to look up */ - void requestWhois(const Address &addr); + void requestWhois(void *tPtr,const Address &addr); /** * Run any processes that are waiting for this peer's identity * * Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param peer New peer */ - void doAnythingWaitingForPeer(const SharedPtr &peer); + void doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer); /** * Perform retries and other periodic timer tasks @@ -118,15 +123,16 @@ public: * This can return a very long delay if there are no pending timer * tasks. The caller should cap this comparatively vs. other values. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @return Number of milliseconds until doTimerTasks() should be run again */ - unsigned long doTimerTasks(uint64_t now); + unsigned long doTimerTasks(void *tPtr,uint64_t now); private: bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); - Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); - bool _trySend(Packet &packet,bool encrypt); // packet is modified if return is true + Address _sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); + bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; diff --git a/node/Tag.cpp b/node/Tag.cpp index eb4026bc..3f924da1 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -25,13 +25,13 @@ namespace ZeroTier { -int Tag::verify(const RuntimeEnvironment *RR) const +int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } try { diff --git a/node/Tag.hpp b/node/Tag.hpp index 146e8da9..38085906 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -105,9 +105,10 @@ public: * Check this tag's signature * * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template inline void serialize(Buffer &b,const bool forSign = false) const diff --git a/node/Topology.cpp b/node/Topology.cpp index 21547cd2..a1d37332 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -55,19 +55,19 @@ namespace ZeroTier { #define ZT_DEFAULT_WORLD_LENGTH 634 static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x52,0x3c,0x32,0x50,0x1a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x4a,0xf7,0x86,0xa8,0x40,0xd6,0x52,0xea,0xae,0x9e,0x7a,0xbf,0x4c,0x97,0x66,0xab,0x2d,0x6f,0xaf,0xc9,0x2b,0x3a,0xff,0xed,0xd6,0x30,0x3e,0xc4,0x6a,0x65,0xf2,0xbd,0x83,0x52,0xf5,0x40,0xe9,0xcc,0x0d,0x6e,0x89,0x3f,0x9a,0xa0,0xb8,0xdf,0x42,0xd2,0x2f,0x84,0xe6,0x03,0x26,0x0f,0xa8,0xe3,0xcc,0x05,0x05,0x03,0xef,0x12,0x80,0x0d,0xce,0x3e,0xb6,0x58,0x3b,0x1f,0xa8,0xad,0xc7,0x25,0xf9,0x43,0x71,0xa7,0x5c,0x9a,0xc7,0xe1,0xa3,0xb8,0x88,0xd0,0x71,0x6c,0x94,0x99,0x73,0x41,0x0b,0x1b,0x48,0x84,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09}; -Topology::Topology(const RuntimeEnvironment *renv) : +Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : RR(renv), _trustedPathCount(0), _amRoot(false) { try { World cachedPlanet; - std::string buf(RR->node->dataStoreGet("planet")); + std::string buf(RR->node->dataStoreGet(tPtr,"planet")); if (buf.length() > 0) { Buffer dswtmp(buf.data(),(unsigned int)buf.length()); cachedPlanet.deserialize(dswtmp,0); } - addWorld(cachedPlanet,false); + addWorld(tPtr,cachedPlanet,false); } catch ( ... ) {} World defaultPlanet; @@ -75,10 +75,10 @@ Topology::Topology(const RuntimeEnvironment *renv) : Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top } - addWorld(defaultPlanet,false); + addWorld(tPtr,defaultPlanet,false); } -SharedPtr Topology::addPeer(const SharedPtr &peer) +SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { #ifdef ZT_TRACE if ((!peer)||(peer->address() == RR->identity.address())) { @@ -98,12 +98,12 @@ SharedPtr Topology::addPeer(const SharedPtr &peer) np = hp; } - saveIdentity(np->identity()); + saveIdentity(tPtr,np->identity()); return np; } -SharedPtr Topology::getPeer(const Address &zta) +SharedPtr Topology::getPeer(void *tPtr,const Address &zta) { if (zta == RR->identity.address()) { TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); @@ -118,7 +118,7 @@ SharedPtr Topology::getPeer(const Address &zta) } try { - Identity id(_getIdentity(zta)); + Identity id(_getIdentity(tPtr,zta)); if (id) { SharedPtr np(new Peer(RR,RR->identity,id)); { @@ -134,7 +134,7 @@ SharedPtr Topology::getPeer(const Address &zta) return SharedPtr(); } -Identity Topology::getIdentity(const Address &zta) +Identity Topology::getIdentity(void *tPtr,const Address &zta) { if (zta == RR->identity.address()) { return RR->identity; @@ -144,15 +144,15 @@ Identity Topology::getIdentity(const Address &zta) if (ap) return (*ap)->identity(); } - return _getIdentity(zta); + return _getIdentity(tPtr,zta); } -void Topology::saveIdentity(const Identity &id) +void Topology::saveIdentity(void *tPtr,const Identity &id) { if (id) { char p[128]; Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)id.address().toInt()); - RR->node->dataStorePut(p,id.toString(false),false); + RR->node->dataStorePut(tPtr,p,id.toString(false),false); } } @@ -264,7 +264,7 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa return false; } -bool Topology::addWorld(const World &newWorld,bool alwaysAcceptNew) +bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) { if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) return false; @@ -328,29 +328,29 @@ bool Topology::addWorld(const World &newWorld,bool alwaysAcceptNew) try { Buffer dswtmp; existing->serialize(dswtmp,false); - RR->node->dataStorePut(savePath,dswtmp.data(),dswtmp.size(),false); + RR->node->dataStorePut(tPtr,savePath,dswtmp.data(),dswtmp.size(),false); } catch ( ... ) { - RR->node->dataStoreDelete(savePath); + RR->node->dataStoreDelete(tPtr,savePath); } - _memoizeUpstreams(); + _memoizeUpstreams(tPtr); return true; } -void Topology::addMoon(const uint64_t id,const Address &seed) +void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) { char savePath[64]; Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); try { - std::string moonBin(RR->node->dataStoreGet(savePath)); + std::string moonBin(RR->node->dataStoreGet(tPtr,savePath)); if (moonBin.length() > 1) { Buffer wtmp(moonBin.data(),(unsigned int)moonBin.length()); World w; w.deserialize(wtmp); if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { - addWorld(w,true); + addWorld(tPtr,w,true); return; } } @@ -363,7 +363,7 @@ void Topology::addMoon(const uint64_t id,const Address &seed) } } -void Topology::removeMoon(const uint64_t id) +void Topology::removeMoon(void *tPtr,const uint64_t id) { Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l2(_peers_m); @@ -375,7 +375,7 @@ void Topology::removeMoon(const uint64_t id) } else { char savePath[64]; Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); - RR->node->dataStoreDelete(savePath); + RR->node->dataStoreDelete(tPtr,savePath); } } _moons.swap(nm); @@ -387,7 +387,7 @@ void Topology::removeMoon(const uint64_t id) } _moonSeeds.swap(cm); - _memoizeUpstreams(); + _memoizeUpstreams(tPtr); } void Topology::clean(uint64_t now) @@ -415,11 +415,11 @@ void Topology::clean(uint64_t now) } } -Identity Topology::_getIdentity(const Address &zta) +Identity Topology::_getIdentity(void *tPtr,const Address &zta) { char p[128]; Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)zta.toInt()); - std::string ids(RR->node->dataStoreGet(p)); + std::string ids(RR->node->dataStoreGet(tPtr,p)); if (ids.length() > 0) { try { return Identity(ids); @@ -428,7 +428,7 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } -void Topology::_memoizeUpstreams() +void Topology::_memoizeUpstreams(void *tPtr) { // assumes _upstreams_m and _peers_m are locked _upstreamAddresses.clear(); @@ -442,7 +442,7 @@ void Topology::_memoizeUpstreams() SharedPtr &hp = _peers[i->identity.address()]; if (!hp) { hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(i->identity); + saveIdentity(tPtr,i->identity); } } } @@ -456,7 +456,7 @@ void Topology::_memoizeUpstreams() SharedPtr &hp = _peers[i->identity.address()]; if (!hp) { hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(i->identity); + saveIdentity(tPtr,i->identity); } } } diff --git a/node/Topology.hpp b/node/Topology.hpp index e21747c8..4870ab5e 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -50,7 +50,7 @@ class RuntimeEnvironment; class Topology { public: - Topology(const RuntimeEnvironment *renv); + Topology(const RuntimeEnvironment *renv,void *tPtr); /** * Add a peer to database @@ -58,18 +58,20 @@ public: * This will not replace existing peers. In that case the existing peer * record is returned. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param peer Peer to add * @return New or existing peer (should replace 'peer') */ - SharedPtr addPeer(const SharedPtr &peer); + SharedPtr addPeer(void *tPtr,const SharedPtr &peer); /** * Get a peer from its address * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param zta ZeroTier address of peer * @return Peer or NULL if not found */ - SharedPtr getPeer(const Address &zta); + SharedPtr getPeer(void *tPtr,const Address &zta); /** * Get a peer only if it is presently in memory (no disk cache) @@ -109,10 +111,11 @@ public: /** * Get the identity of a peer * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param zta ZeroTier address of peer * @return Identity or NULL Identity if not found */ - Identity getIdentity(const Address &zta); + Identity getIdentity(void *tPtr,const Address &zta); /** * Cache an identity @@ -120,9 +123,10 @@ public: * This is done automatically on addPeer(), and so is only useful for * cluster identity replication. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param id Identity to cache */ - void saveIdentity(const Identity &id); + void saveIdentity(void *tPtr,const Identity &id); /** * Get the current best upstream peer @@ -267,11 +271,12 @@ public: /** * Validate new world and update if newer and signature is okay * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param newWorld A new or updated planet or moon to learn * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one * @return True if it was valid and newer than current (or totally new for moons) */ - bool addWorld(const World &newWorld,bool alwaysAcceptNew); + bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew); /** * Add a moon @@ -282,14 +287,15 @@ public: * @param id Moon ID * @param seed If non-NULL, an address of any member of the moon to contact */ - void addMoon(const uint64_t id,const Address &seed); + void addMoon(void *tPtr,const uint64_t id,const Address &seed); /** * Remove a moon * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param id Moon's world ID */ - void removeMoon(const uint64_t id); + void removeMoon(void *tPtr,const uint64_t id); /** * Clean and flush database @@ -420,8 +426,8 @@ public: } private: - Identity _getIdentity(const Address &zta); - void _memoizeUpstreams(); + Identity _getIdentity(void *tPtr,const Address &zta); + void _memoizeUpstreams(void *tPtr); const RuntimeEnvironment *const RR; diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index 0e1ada6b..62fabc48 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -71,7 +71,7 @@ BSDEthernetTap::BSDEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : _handler(handler), _arg(arg), @@ -460,8 +460,7 @@ void BSDEthernetTap::threadMain() to.setTo(getBuf,6); from.setTo(getBuf + 6,6); unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); } r = 0; diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index 1bb48d31..8c6314db 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -43,7 +43,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~BSDEthernetTap(); @@ -62,7 +62,7 @@ public: throw(); private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; Thread _thread; diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index e7fe657f..c4b978e7 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -62,7 +62,7 @@ LinuxEthernetTap::LinuxEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : _handler(handler), _arg(arg), @@ -470,7 +470,7 @@ void LinuxEthernetTap::threadMain() from.setTo(getBuf + 6,6); unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); } r = 0; diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index 7dd7e01d..a2a00a79 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -44,7 +44,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~LinuxEthernetTap(); @@ -66,7 +66,7 @@ public: throw(); private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; Thread _thread; diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp index b3580929..35eac05a 100644 --- a/osdep/OSXEthernetTap.cpp +++ b/osdep/OSXEthernetTap.cpp @@ -314,7 +314,7 @@ OSXEthernetTap::OSXEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), void *arg) : _handler(handler), _arg(arg), @@ -646,7 +646,7 @@ void OSXEthernetTap::threadMain() from.setTo(getBuf + 6,6); unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); } r = 0; diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp index de48f9a4..5a96c210 100644 --- a/osdep/OSXEthernetTap.hpp +++ b/osdep/OSXEthernetTap.hpp @@ -48,7 +48,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~OSXEthernetTap(); @@ -67,7 +67,7 @@ public: throw(); private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; Thread _thread; diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 8ee088bb..79b9d35e 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -456,7 +456,7 @@ WindowsEthernetTap::WindowsEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : _handler(handler), _arg(arg), @@ -1058,8 +1058,7 @@ void WindowsEthernetTap::threadMain() MAC from(tapReadBuf + 6,6); unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); try { - // TODO: decode vlans - _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); } catch ( ... ) {} // handlers should not throw } } diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 53bba3e9..f2cf73f3 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -87,7 +87,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~WindowsEthernetTap(); @@ -118,7 +118,7 @@ private: void _setRegistryIPv4Value(const char *regKey,const std::vector &value); void _syncIps(); - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; MAC _mac; uint64_t _nwid; diff --git a/service/OneService.cpp b/service/OneService.cpp index 22eefbb9..c07b3ba4 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -291,21 +291,21 @@ static void _moonToJson(nlohmann::json &mj,const World &world) class OneServiceImpl; -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); -static void SnodeEventCallback(ZT_Node *node,void *uptr,enum ZT_Event event,const void *metaData); -static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize); -static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure); -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); +static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); +static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); +static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize); +static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,const void *data,unsigned long len,int secure); +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); +static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); #ifdef ZT_ENABLE_CLUSTER static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len); static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr,int *x,int *y,int *z); #endif -static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); +static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); static int ShttpOnMessageBegin(http_parser *parser); static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); @@ -573,7 +573,7 @@ public: cb.eventCallback = SnodeEventCallback; cb.pathCheckFunction = SnodePathCheckFunction; cb.pathLookupFunction = SnodePathLookupFunction; - _node = new Node(this,&cb,OSUtils::now()); + _node = new Node(this,(void *)0,&cb,OSUtils::now()); } // Read local configuration @@ -804,7 +804,7 @@ public: for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".conf")) - _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0); + _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0,(void *)0); } } { // Load existing moons @@ -812,7 +812,7 @@ public: for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".moon")) - _node->orbit(Utils::hexStrToU64(f->substr(0,dot).c_str()),0); + _node->orbit((void *)0,Utils::hexStrToU64(f->substr(0,dot).c_str()),0); } } @@ -877,7 +877,7 @@ public: uint64_t dl = _nextBackgroundTaskDeadline; if (dl <= now) { - _node->processBackgroundTasks(now,&_nextBackgroundTaskDeadline); + _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); dl = _nextBackgroundTaskDeadline; } @@ -892,7 +892,7 @@ public: std::vector added,removed; n->second.tap->scanMulticastGroups(added,removed); for(std::vector::iterator m(added.begin());m!=added.end();++m) - _node->multicastSubscribe(n->first,m->mac().toInt(),m->adi()); + _node->multicastSubscribe((void *)0,n->first,m->mac().toInt(),m->adi()); for(std::vector::iterator m(removed.begin());m!=removed.end();++m) _node->multicastUnsubscribe(n->first,m->mac().toInt(),m->adi()); } @@ -1306,7 +1306,7 @@ public: res["signature"] = json(); res["updatesMustBeSignedBy"] = json(); res["waiting"] = true; - _node->orbit(id,seed); + _node->orbit((void *)0,id,seed); scode = 200; } @@ -1315,7 +1315,7 @@ public: if (ps.size() == 2) { uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); - _node->join(wantnw,(void *)0); // does nothing if we are a member + _node->join(wantnw,(void *)0,(void *)0); // does nothing if we are a member ZT_VirtualNetworkList *nws = _node->networks(); if (nws) { for(unsigned long i=0;inetworkCount;++i) { @@ -1360,7 +1360,7 @@ public: if (ps[0] == "moon") { if (ps.size() == 2) { - _node->deorbit(Utils::hexStrToU64(ps[1].c_str())); + _node->deorbit((void *)0,Utils::hexStrToU64(ps[1].c_str())); res["result"] = true; scode = 200; } // else 404 @@ -1371,7 +1371,7 @@ public: uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); for(unsigned long i=0;inetworkCount;++i) { if (nws->networks[i].nwid == wantnw) { - _node->leave(wantnw,(void **)0); + _node->leave(wantnw,(void **)0,(void *)0); res["result"] = true; scode = 200; break; @@ -1693,6 +1693,7 @@ public: _lastDirectReceiveFromGlobal = OSUtils::now(); const ZT_ResultCode rc = _node->processWirePacket( + (void *)0, OSUtils::now(), reinterpret_cast(localAddr), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big @@ -1845,6 +1846,7 @@ public: if (from) { InetAddress fakeTcpLocalInterfaceAddress((uint32_t)0xffffffff,0xffff); const ZT_ResultCode rc = _node->processWirePacket( + (void *)0, OSUtils::now(), reinterpret_cast(&fakeTcpLocalInterfaceAddress), reinterpret_cast(&from), @@ -2255,7 +2257,7 @@ public: inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { - _node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); + _node->processVirtualNetworkFrame((void *)0,OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); } inline void onHttpRequestToServer(TcpConnection *tc) @@ -2426,21 +2428,21 @@ public: } }; -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) +static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) { return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } -static void SnodeEventCallback(ZT_Node *node,void *uptr,enum ZT_Event event,const void *metaData) +static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) { reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } -static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize) +static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize) { return reinterpret_cast(uptr)->nodeDataStoreGetFunction(name,buf,bufSize,readIndex,totalSize); } -static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure) +static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,const void *data,unsigned long len,int secure) { return reinterpret_cast(uptr)->nodeDataStorePutFunction(name,data,len,secure); } -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) { return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) { return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } #ifdef ZT_ENABLE_CLUSTER @@ -2458,7 +2460,7 @@ static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr, } #endif -static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } static int ShttpOnMessageBegin(http_parser *parser) diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 7ecd42b1..7ec377cc 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -175,7 +175,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void std::string lj; lj.push_back((char)VERB_LATEST); lj.append(OSUtils::jsonDump(*latest)); - _node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length()); + _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length()); if (_distLog) { fprintf(_distLog,"%.10llx GET_LATEST %u.%u.%u_%u platform %u arch %u vendor %u channel %s -> LATEST %u.%u.%u_%u" ZT_EOL_S,(unsigned long long)origin,rvMaj,rvMin,rvRev,rvBld,rvPlatform,rvArch,rvVendor,rvChannel.c_str(),bestVMaj,bestVMin,bestVRev,bestVBld); fflush(_distLog); @@ -205,7 +205,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append((uint8_t)VERB_GET_DATA); gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -229,7 +229,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void buf.append(reinterpret_cast(data) + 1,16); buf.append((uint32_t)idx); buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx))); - _node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); + _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); //printf(">> DATA @%u\n",(unsigned int)idx); } } @@ -249,7 +249,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append((uint8_t)VERB_GET_DATA); gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -296,7 +296,7 @@ bool SoftwareUpdater::check(const uint64_t now) ZT_BUILD_ARCHITECTURE, (int)ZT_VENDOR_ZEROTIER, _channel.c_str()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); //printf(">> GET_LATEST\n"); } @@ -343,7 +343,7 @@ bool SoftwareUpdater::check(const uint64_t now) gd.append((uint8_t)VERB_GET_DATA); gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } -- cgit v1.2.3 From 139c4b56337c0cfe7458ecf5df4e12e38c2d4f8a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 14 Apr 2017 17:53:32 -0700 Subject: Significant simplification to path logic. --- node/Constants.hpp | 2 +- node/IncomingPacket.cpp | 32 +++--- node/Node.cpp | 18 ++-- node/Peer.cpp | 273 +++++++++++++++++++----------------------------- node/Peer.hpp | 119 +++++++++------------ node/Topology.hpp | 4 +- 6 files changed, 182 insertions(+), 266 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 410a245b..93184efa 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -289,7 +289,7 @@ #define ZT_PEER_PING_PERIOD 60000 /** - * Paths are considered expired if they have not produced a real packet in this long + * Paths are considered expired if they have not sent us a real packet in this long */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 52794fd7..a0f5ee1d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1200,16 +1200,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt switch(addrType) { case 4: { - InetAddress a(field(ptr,4),4,at(ptr + 4)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { + const InetAddress a(field(ptr,4),4,at(ptr + 4)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + { 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(tPtr,InetAddress(),a,now,false,0); @@ -1219,16 +1215,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt } } break; case 6: { - InetAddress a(field(ptr,16),16,at(ptr + 16)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { + const InetAddress a(field(ptr,16),16,at(ptr + 16)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + { 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(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Node.cpp b/node/Node.cpp index 9844b09e..1bc96cca 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -407,17 +407,17 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->role(pi->second->identity().address()); - std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); + std::vector< SharedPtr > paths(pi->second->paths(_now)); SharedPtr bestp(pi->second->getBestPath(_now,false)); p->pathCount = 0; - for(std::vector< std::pair< SharedPtr,bool > >::iterator path(paths.begin());path!=paths.end();++path) { - memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].lastSend = path->first->lastOut(); - p->paths[p->pathCount].lastReceive = path->first->lastIn(); - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); - p->paths[p->pathCount].linkQuality = (int)path->first->linkQuality(); - p->paths[p->pathCount].expired = path->second; - p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; + for(std::vector< SharedPtr >::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)->lastOut(); + p->paths[p->pathCount].lastReceive = (*path)->lastIn(); + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); + p->paths[p->pathCount].linkQuality = (int)(*path)->linkQuality(); + p->paths[p->pathCount].expired = 0; + p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; ++p->pathCount; } } diff --git a/node/Peer.cpp b/node/Peer.cpp index 0795a6ea..2711dd19 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,14 +27,6 @@ #include "Cluster.hpp" #include "Packet.hpp" -#ifndef AF_MAX -#if AF_INET > AF_INET6 -#define AF_MAX AF_INET -#else -#define AF_MAX AF_INET6 -#endif -#endif - namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : @@ -51,18 +43,15 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), - _remoteClusterOptimal4(0), _vProto(0), _vMajor(0), _vMinor(0), _vRevision(0), _id(peerIdentity), - _numPaths(0), _latency(0), _directPathPushCutoffCount(0), _credentialsCutoffCount(0) { - memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); } @@ -80,7 +69,7 @@ void Peer::received( const uint64_t now = RR->node->now(); #ifdef ZT_ENABLE_CLUSTER - bool suboptimalPath = false; + bool isClusterSuboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { // Note: findBetterEndpoint() is first since we still want to check // for a better endpoint even if we don't actually send a redirect. @@ -146,65 +135,60 @@ void Peer::received( path->updateLinkQuality((unsigned int)(packetId & 7)); if (hops == 0) { - bool pathIsConfirmed = false; + bool pathAlreadyKnown = false; { Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address() == path->address()) { - _paths[p].lastReceive = now; - _paths[p].path = path; // local address may have changed! + if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { + const struct sockaddr_in *const r = reinterpret_cast(&(path->address())); + const struct sockaddr_in *const l = reinterpret_cast(&(_v4Path.p->address())); + const struct sockaddr_in *const rl = reinterpret_cast(&(path->localAddress())); + const struct sockaddr_in *const ll = reinterpret_cast(&(_v4Path.p->localAddress())); + if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { + _v4Path.lr = now; #ifdef ZT_ENABLE_CLUSTER - _paths[p].localClusterSuboptimal = suboptimalPath; + _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; #endif - pathIsConfirmed = true; - break; + pathAlreadyKnown = true; + } + } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { + const struct sockaddr_in6 *const r = reinterpret_cast(&(path->address())); + const struct sockaddr_in6 *const l = reinterpret_cast(&(_v6Path.p->address())); + const struct sockaddr_in6 *const rl = reinterpret_cast(&(path->localAddress())); + const struct sockaddr_in6 *const ll = reinterpret_cast(&(_v6Path.p->localAddress())); + if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { + _v6Path.lr = now; +#ifdef ZT_ENABLE_CLUSTER + _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; +#endif + pathAlreadyKnown = true; } } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); - - // Since this is a new path, figure out where to put it (possibly replacing an old/dead one) - unsigned int slot; - if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { - slot = _numPaths++; - } else { - // First try to replace the worst within the same address family, if possible - int worstSlot = -1; - uint64_t worstScore = 0xffffffffffffffffULL; - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == path->address().ss_family) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - worstSlot = (int)p; - } - } - } - if (worstSlot >= 0) { - slot = (unsigned int)worstSlot; - } else { - // If we can't find one with the same family, replace the worst of any family - slot = ZT_MAX_PEER_NETWORK_PATHS - 1; - for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - slot = p; - } - } + if (path->address().ss_family == AF_INET) { + if ((!_v4Path.p)||(!_v4Path.p->alive(now))||(path->preferenceRank() >= _v4Path.p->preferenceRank())) { + _v4Path.lr = now; + _v4Path.p = path; +#ifdef ZT_ENABLE_CLUSTER + _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); +#endif } - } - - _paths[slot].lastReceive = now; - _paths[slot].path = path; + } else if (path->address().ss_family == AF_INET6) { + if ((!_v6Path.p)||(!_v6Path.p->alive(now))||(path->preferenceRank() >= _v6Path.p->preferenceRank())) { + _v6Path.lr = now; + _v6Path.p = path; #ifdef ZT_ENABLE_CLUSTER - _paths[slot].localClusterSuboptimal = suboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); + _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); #endif + } + } } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -214,10 +198,10 @@ void Peer::received( } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) #ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - const bool haveCluster = (RR->cluster); + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + const bool haveCluster = (RR->cluster); #else - const bool haveCluster = false; + const bool haveCluster = false; #endif if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { _lastDirectPathPushSent = now; @@ -290,60 +274,50 @@ void Peer::received( } } -bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) - return true; - } - return false; -} - -bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } + uint64_t v6lr = 0; + if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if ( (v6lr > v4lr) && ((now - v6lr) < ZT_PATH_ALIVE_TIMEOUT) ) { + return _v6Path.p->send(RR,tPtr,data,len,now); + } else if ((now - v4lr) < ZT_PATH_ALIVE_TIMEOUT) { + return _v4Path.p->send(RR,tPtr,data,len,now); + } else if (force) { + if (v6lr > v4lr) { + return _v6Path.p->send(RR,tPtr,data,len,now); + } else if (v4lr) { + return _v4Path.p->send(RR,tPtr,data,len,now); } } - if (bestp >= 0) { - return _paths[bestp].path->send(RR,tPtr,data,len,now); - } else { - return false; - } + return false; } SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } - } + uint64_t v6lr = 0; + if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if (v6lr > v4lr) { + return _v6Path.p; + } else if (v4lr) { + return _v4Path.p; } - if (bestp >= 0) { - return _paths[bestp].path; - } else { - return SharedPtr(); - } + return SharedPtr(); } void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) @@ -420,79 +394,44 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; + if (inetAddressFamily < 0) { + uint64_t v6lr = 0; + if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if (v6lr > v4lr) { + if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + return true; + } + } else if (v4lr) { + if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + return true; } } - } - - if (bestp >= 0) { - if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); - _paths[bestp].path->sent(now); - } - return true; } else { - return false; - } -} - -bool Peer::hasActiveDirectPath(uint64_t now) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now))) - return true; - } - return false; -} - -void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); - _paths[p].path->sent(now); - _paths[p].lastReceive = 0; // path will not be used unless it speaks again - } - } -} - -void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const -{ - Mutex::Lock _l(_paths_m); - - int bestp4 = -1,bestp6 = -1; - uint64_t best4 = 0ULL,best6 = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) { - if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _pathScore(p,now); - if (s >= best4) { - best4 = s; - bestp4 = (int)p; - } - } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _pathScore(p,now); - if (s >= best6) { - best6 = s; - bestp6 = (int)p; - } + if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { + if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + return true; + } + } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { + if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + return true; } } } - if (bestp4 >= 0) - v4 = _paths[bestp4].path->address(); - if (bestp6 >= 0) - v6 = _paths[bestp6].path->address(); + return false; } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 41836410..f225eb85 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -108,20 +108,10 @@ public: * @param addr Remote address * @return True if we have an active path to this destination */ - bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; - - /** - * Set which known path for an address family is optimal - * - * @param addr Address to make exclusive - */ - inline void setClusterOptimal(const InetAddress &addr) + inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const { - if (addr.ss_family == AF_INET) { - _remoteClusterOptimal4 = (uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr; - } else if (addr.ss_family == AF_INET6) { - memcpy(_remoteClusterOptimal6,reinterpret_cast(&addr)->sin6_addr.s6_addr,16); - } + Mutex::Lock _l(_paths_m); + return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); } /** @@ -131,14 +121,17 @@ public: * @param data Packet data * @param len Packet length * @param now Current time - * @param forceEvenIfDead If true, send even if the path is not 'alive' + * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force); /** * Get the best current direct path * + * This does not check Path::alive(), but does return the most recently + * active path and does check expiration (which is a longer timeout). + * * @param now Current time * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none @@ -192,12 +185,6 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); - /** - * @param now Current time - * @return True if this peer has at least one active and alive direct path - */ - bool hasActiveDirectPath(uint64_t now) const; - /** * Reset paths within a given IP scope and address family * @@ -209,30 +196,48 @@ public: * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) + { + Mutex::Lock _l(_paths_m); + if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + _v4Path.lr = 0; // path will not be used unless it speaks again + } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + _v6Path.lr = 0; // path will not be used unless it speaks again + } + } /** - * Get most recently active path addresses for IPv4 and/or IPv6 - * - * Note that v4 and v6 are not modified if they are not found, so - * initialize these to a NULL address to be able to check. + * Fill parameters with V4 and V6 addresses if known and alive * * @param now Current time * @param v4 Result parameter to receive active IPv4 address, if any * @param v6 Result parameter to receive active IPv6 address, if any */ - void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const + { + Mutex::Lock _l(_paths_m); + if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) + v4 = _v4Path.p->address(); + if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) + v6 = _v6Path.p->address(); + } /** * @param now Current time - * @return All known direct paths to this peer and whether they are expired (true == expired) + * @return All known paths to this peer */ - inline std::vector< std::pair< SharedPtr,bool > > paths(const uint64_t now) const + inline std::vector< SharedPtr > paths(const uint64_t now) const { - std::vector< std::pair< SharedPtr,bool > > pp; + std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); - for(unsigned int p=0,np=_numPaths;p,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION)); + if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) + pp.push_back(_v4Path.p); + if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) + pp.push_back(_v6Path.p); return pp; } @@ -424,32 +429,19 @@ public: } private: - inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const + struct _PeerPath { - uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); - - if (_paths[p].path->address().ss_family == AF_INET) { - s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); - } else if (_paths[p].path->address().ss_family == AF_INET6) { - uint64_t clusterWeight = ZT_PEER_PING_PERIOD; - const uint8_t *a = reinterpret_cast(reinterpret_cast(&(_paths[p].path->address()))->sin6_addr.s6_addr); - for(long i=0;i<16;++i) { - if (a[i] != _remoteClusterOptimal6[i]) { - clusterWeight = 0; - break; - } - } - s += clusterWeight; - } - - s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now); - #ifdef ZT_ENABLE_CLUSTER - s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; + _PeerPath() : lr(0),p(),localClusterSuboptimal(false) {} +#else + _PeerPath() : lr(0),p() {} #endif - - return s; - } + uint64_t lr; // time of last valid ZeroTier packet + SharedPtr p; +#ifdef ZT_ENABLE_CLUSTER + bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer +#endif + }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -468,26 +460,17 @@ private: uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; - uint8_t _remoteClusterOptimal6[16]; - uint32_t _remoteClusterOptimal4; - uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; - Identity _id; - - struct { - uint64_t lastReceive; - SharedPtr path; -#ifdef ZT_ENABLE_CLUSTER - bool localClusterSuboptimal; -#endif - } _paths[ZT_MAX_PEER_NETWORK_PATHS]; + _PeerPath _v4Path; // IPv4 direct path + _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; - unsigned int _numPaths; + Identity _id; + unsigned int _latency; unsigned int _directPathPushCutoffCount; unsigned int _credentialsCutoffCount; diff --git a/node/Topology.hpp b/node/Topology.hpp index 4870ab5e..d29c424e 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -314,7 +314,9 @@ public: Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - cnt += (unsigned long)((*p)->hasActiveDirectPath(now)); + const SharedPtr pp((*p)->getBestPath(now,false)); + if ((pp)&&(pp->alive(now))) + ++cnt; } return cnt; } -- cgit v1.2.3 From f1c0563c40dc9e3ec5e975d3e1e8d6057ed6bd83 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 14 Apr 2017 18:02:04 -0700 Subject: Fix for cluster handoff. --- node/IncomingPacket.cpp | 4 ++++ node/Peer.cpp | 4 ++-- node/Peer.hpp | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a0f5ee1d..303160ec 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1206,6 +1206,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + peer->setClusterPreferred(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->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); @@ -1221,6 +1223,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + peer->setClusterPreferred(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->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Peer.cpp b/node/Peer.cpp index 2711dd19..7ffe8926 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -169,7 +169,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); if (path->address().ss_family == AF_INET) { - if ((!_v4Path.p)||(!_v4Path.p->alive(now))||(path->preferenceRank() >= _v4Path.p->preferenceRank())) { + if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) { _v4Path.lr = now; _v4Path.p = path; #ifdef ZT_ENABLE_CLUSTER @@ -179,7 +179,7 @@ void Peer::received( #endif } } else if (path->address().ss_family == AF_INET6) { - if ((!_v6Path.p)||(!_v6Path.p->alive(now))||(path->preferenceRank() >= _v6Path.p->preferenceRank())) { + if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) { _v6Path.lr = now; _v6Path.p = path; #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Peer.hpp b/node/Peer.hpp index f225eb85..6cf30feb 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -210,6 +210,19 @@ public: } } + /** + * Indicate that the given address was provided by a cluster as a preferred destination + * + * @param addr Address cluster prefers that we use + */ + inline void setClusterPreferred(const InetAddress &addr) + { + if (addr.ss_family == AF_INET) + _v4ClusterPreferred = addr; + else if (addr.ss_family == AF_INET6) + _v6ClusterPreferred = addr; + } + /** * Fill parameters with V4 and V6 addresses if known and alive * @@ -465,6 +478,9 @@ private: uint16_t _vMinor; uint16_t _vRevision; + InetAddress _v4ClusterPreferred; + InetAddress _v6ClusterPreferred; + _PeerPath _v4Path; // IPv4 direct path _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; -- cgit v1.2.3 From 1b68d6dbdc5540e1b26b4ea35d019dde746af79e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 27 Apr 2017 20:47:25 -0700 Subject: License header update. --- include/ZeroTierOne.h | 10 +++++++++- node/Address.hpp | 10 +++++++++- node/Array.hpp | 10 +++++++++- node/AtomicCounter.hpp | 10 +++++++++- node/Buffer.hpp | 10 +++++++++- node/C25519.cpp | 4 +--- node/C25519.hpp | 10 +++++++++- node/Capability.cpp | 10 +++++++++- node/Capability.hpp | 10 +++++++++- node/CertificateOfMembership.cpp | 10 +++++++++- node/CertificateOfMembership.hpp | 10 +++++++++- node/CertificateOfOwnership.cpp | 10 +++++++++- node/CertificateOfOwnership.hpp | 10 +++++++++- node/CertificateOfRepresentation.hpp | 10 +++++++++- node/Cluster.cpp | 10 +++++++++- node/Cluster.hpp | 10 +++++++++- node/Constants.hpp | 10 +++++++++- node/Credential.hpp | 10 +++++++++- node/Dictionary.hpp | 10 +++++++++- node/Hashtable.hpp | 10 +++++++++- node/Identity.cpp | 10 +++++++++- node/Identity.hpp | 10 +++++++++- node/IncomingPacket.cpp | 10 +++++++++- node/IncomingPacket.hpp | 10 +++++++++- node/InetAddress.cpp | 10 +++++++++- node/InetAddress.hpp | 10 +++++++++- node/MAC.hpp | 10 +++++++++- node/Membership.cpp | 10 +++++++++- node/Membership.hpp | 10 +++++++++- node/MulticastGroup.hpp | 10 +++++++++- node/Multicaster.cpp | 10 +++++++++- node/Multicaster.hpp | 10 +++++++++- node/Mutex.hpp | 10 +++++++++- node/Network.cpp | 10 +++++++++- node/Network.hpp | 10 +++++++++- node/NetworkConfig.cpp | 10 +++++++++- node/NetworkConfig.hpp | 10 +++++++++- node/NetworkController.hpp | 10 +++++++++- node/Node.cpp | 10 +++++++++- node/Node.hpp | 10 +++++++++- node/NonCopyable.hpp | 10 +++++++++- node/OutboundMulticast.cpp | 10 +++++++++- node/OutboundMulticast.hpp | 10 +++++++++- node/Packet.cpp | 10 +++++++++- node/Packet.hpp | 10 +++++++++- node/Path.cpp | 10 +++++++++- node/Path.hpp | 10 +++++++++- node/Peer.cpp | 10 +++++++++- node/Peer.hpp | 10 +++++++++- node/Poly1305.hpp | 10 +++++++++- node/Revocation.cpp | 10 +++++++++- node/Revocation.hpp | 10 +++++++++- node/RuntimeEnvironment.hpp | 10 +++++++++- node/SHA512.cpp | 35 +++++++---------------------------- node/SHA512.hpp | 10 +++++++++- node/SelfAwareness.cpp | 10 +++++++++- node/SelfAwareness.hpp | 10 +++++++++- node/SharedPtr.hpp | 10 +++++++++- node/Switch.cpp | 10 +++++++++- node/Switch.hpp | 10 +++++++++- node/Tag.cpp | 10 +++++++++- node/Tag.hpp | 10 +++++++++- node/Topology.cpp | 10 +++++++++- node/Topology.hpp | 10 +++++++++- node/Utils.cpp | 10 +++++++++- node/Utils.hpp | 10 +++++++++- node/World.hpp | 10 +++++++++- one.cpp | 10 +++++++++- osdep/Arp.cpp | 10 +++++++++- osdep/Arp.hpp | 10 +++++++++- osdep/BSDEthernetTap.cpp | 10 +++++++++- osdep/BSDEthernetTap.hpp | 10 +++++++++- osdep/Binder.hpp | 10 +++++++++- osdep/BlockingQueue.hpp | 10 +++++++++- osdep/Http.cpp | 10 +++++++++- osdep/Http.hpp | 10 +++++++++- osdep/LinuxEthernetTap.cpp | 10 +++++++++- osdep/LinuxEthernetTap.hpp | 10 +++++++++- osdep/ManagedRoute.cpp | 10 +++++++++- osdep/ManagedRoute.hpp | 26 ++++++++++++++++++++++++++ osdep/NeighborDiscovery.cpp | 10 +++++++++- osdep/NeighborDiscovery.hpp | 10 +++++++++- osdep/OSUtils.cpp | 10 +++++++++- osdep/OSUtils.hpp | 10 +++++++++- osdep/OSXEthernetTap.cpp | 10 +++++++++- osdep/OSXEthernetTap.hpp | 10 +++++++++- osdep/Phy.hpp | 10 +++++++++- osdep/PortMapper.cpp | 10 +++++++++- osdep/PortMapper.hpp | 10 +++++++++- osdep/TestEthernetTap.hpp | 10 +++++++++- osdep/Thread.hpp | 10 +++++++++- osdep/WindowsEthernetTap.cpp | 10 +++++++++- osdep/WindowsEthernetTap.hpp | 10 +++++++++- selftest.cpp | 10 +++++++++- service/ClusterDefinition.hpp | 10 +++++++++- service/ClusterGeoIpService.cpp | 10 +++++++++- service/ClusterGeoIpService.hpp | 10 +++++++++- service/OneService.cpp | 10 +++++++++- service/OneService.hpp | 10 +++++++++- service/SoftwareUpdater.cpp | 10 +++++++++- service/SoftwareUpdater.hpp | 10 +++++++++- version.h | 10 +++++++++- 102 files changed, 925 insertions(+), 130 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 747e1855..20707a1d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ /* diff --git a/node/Address.hpp b/node/Address.hpp index 4a5883b0..9d2d1734 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ADDRESS_HPP diff --git a/node/Array.hpp b/node/Array.hpp index 19b29eb3..5c616475 100644 --- a/node/Array.hpp +++ b/node/Array.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ARRAY_HPP diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index a0f29baa..e1864db8 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ATOMICCOUNTER_HPP diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 37f39e7b..ae242c73 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BUFFER_HPP diff --git a/node/C25519.cpp b/node/C25519.cpp index e9ffecc1..a78e0466 100644 --- a/node/C25519.cpp +++ b/node/C25519.cpp @@ -1,5 +1,3 @@ -// Code taken from NaCl by D. J. Bernstein and others - /* Matthew Dempsky Public domain. @@ -7,7 +5,7 @@ Derived from public domain code by D. J. Bernstein. */ // Modified very slightly for ZeroTier One by Adam Ierymenko -// (no functional changes) +// This code remains in the public domain. #include #include diff --git a/node/C25519.hpp b/node/C25519.hpp index b19d9693..da9ba665 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_C25519_HPP diff --git a/node/Capability.cpp b/node/Capability.cpp index c178e566..0e02025a 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Capability.hpp" diff --git a/node/Capability.hpp b/node/Capability.hpp index 454723ac..8d4b9085 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CAPABILITY_HPP diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 9bf70216..a5445e42 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "CertificateOfMembership.hpp" diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index dfccb138..739d5390 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 2bd181e0..31d0ae18 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "CertificateOfOwnership.hpp" diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index f01da38e..95039a2d 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp index 710ee577..92a71bc0 100644 --- a/node/CertificateOfRepresentation.hpp +++ b/node/CertificateOfRepresentation.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 54206f99..4d2dea76 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 08e32a99..74b091f5 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CLUSTER_HPP diff --git a/node/Constants.hpp b/node/Constants.hpp index 93184efa..d3c87491 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CONSTANTS_HPP diff --git a/node/Credential.hpp b/node/Credential.hpp index 0ae2a0a8..bc81919b 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CREDENTIAL_HPP diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 0db13b63..e212e453 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_DICTIONARY_HPP diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 66f2990a..c46ed68f 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_HASHTABLE_HPP diff --git a/node/Identity.cpp b/node/Identity.cpp index d1b21e9c..ba77aa47 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Identity.hpp b/node/Identity.hpp index e4522732..b1c7d6f4 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_IDENTITY_HPP diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 303160ec..126da53c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 3d4a2e05..43a1ea10 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_INCOMINGPACKET_HPP diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 7d22eeae..62bb8145 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index c37fa621..0975a9cf 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_INETADDRESS_HPP diff --git a/node/MAC.hpp b/node/MAC.hpp index 95623f12..e7717d99 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MAC_HPP diff --git a/node/Membership.cpp b/node/Membership.cpp index 2d0471f1..466f9021 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Membership.hpp b/node/Membership.hpp index 0bc8f335..5e4475da 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MEMBERSHIP_HPP diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index be4e8084..4240db67 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MULTICASTGROUP_HPP diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 8e534b5e..52213364 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index f646a5be..2186e9c3 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MULTICASTER_HPP diff --git a/node/Mutex.hpp b/node/Mutex.hpp index d451ede0..6f1d3471 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MUTEX_HPP diff --git a/node/Network.cpp b/node/Network.cpp index b7f25f7f..ee0f8611 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Network.hpp b/node/Network.hpp index faef0fed..cce6c41f 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORK_HPP diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index fe7393e8..9effe529 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 85c24090..7bae6a91 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORKCONFIG_HPP diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index 0634f435..63d44a46 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORKCONFIGMASTER_HPP diff --git a/node/Node.cpp b/node/Node.cpp index ccbe9411..5848d953 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Node.hpp b/node/Node.hpp index d25a619b..95587161 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NODE_HPP diff --git a/node/NonCopyable.hpp b/node/NonCopyable.hpp index 6d4daa86..25c71b1c 100644 --- a/node/NonCopyable.hpp +++ b/node/NonCopyable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NONCOPYABLE_HPP__ diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 285bfa5d..a2341ffd 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Constants.hpp" diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 0ecf113f..0c988804 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_OUTBOUNDMULTICAST_HPP diff --git a/node/Packet.cpp b/node/Packet.cpp index 8a57dd55..d60a3a34 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Packet.hpp b/node/Packet.hpp index 8ad2c0f9..1de679e7 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_N_PACKET_HPP diff --git a/node/Path.cpp b/node/Path.cpp index 7366b56f..a5fe1aa7 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Path.hpp" diff --git a/node/Path.hpp b/node/Path.hpp index aef628d4..32bceae0 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_PATH_HPP diff --git a/node/Peer.cpp b/node/Peer.cpp index 2e9f6a2b..01905833 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "../version.h" diff --git a/node/Peer.hpp b/node/Peer.hpp index b9d85404..9b57f23e 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_PEER_HPP diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 62d57546..ff709983 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_POLY1305_HPP diff --git a/node/Revocation.cpp b/node/Revocation.cpp index bab5653c..026058da 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Revocation.hpp" diff --git a/node/Revocation.hpp b/node/Revocation.hpp index e5e013bd..e8f5d00d 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_REVOCATION_HPP diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 7ba1c989..d8e1d699 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_RUNTIMEENVIRONMENT_HPP diff --git a/node/SHA512.cpp b/node/SHA512.cpp index 76737d37..c8d81dd1 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -1,20 +1,11 @@ +// Code taken from NaCl by D. J. Bernstein and others +// Public domain + /* - * 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 . - */ +20080913 +D. J. Bernstein +Public domain. +*/ #include #include @@ -25,18 +16,6 @@ namespace ZeroTier { -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Code taken from NaCl by D. J. Bernstein and others -// Public domain - -/* -20080913 -D. J. Bernstein -Public domain. -*/ - #define uint64 uint64_t #ifdef ZT_NO_TYPE_PUNNING diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 639a7dfd..584f8e11 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SHA512_HPP diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index cba84cdc..c5daddc3 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index c1db0c84..63c416bf 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SELFAWARENESS_HPP diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index 1dd3b43d..09010f67 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SHAREDPTR_HPP diff --git a/node/Switch.cpp b/node/Switch.cpp index 56299a9a..211b706a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Switch.hpp b/node/Switch.hpp index ff350934..9793dd45 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_N_SWITCH_HPP diff --git a/node/Tag.cpp b/node/Tag.cpp index 3f924da1..39b17f2a 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Tag.hpp" diff --git a/node/Tag.hpp b/node/Tag.hpp index 1f7f6835..746ade26 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_TAG_HPP diff --git a/node/Topology.cpp b/node/Topology.cpp index a1d37332..80f4ed4e 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Constants.hpp" diff --git a/node/Topology.hpp b/node/Topology.hpp index d29c424e..d06ba94b 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_TOPOLOGY_HPP diff --git a/node/Utils.cpp b/node/Utils.cpp index 9ce1bf05..d69e5335 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Utils.hpp b/node/Utils.hpp index ceb29d7e..25a90055 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_UTILS_HPP diff --git a/node/World.hpp b/node/World.hpp index 6e835bec..003d70e3 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_WORLD_HPP diff --git a/one.cpp b/one.cpp index b40e28fc..1f38361f 100644 --- a/one.cpp +++ b/one.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index fcc122f0..c06f459b 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp index 5f0d199a..e26fcdb3 100644 --- a/osdep/Arp.hpp +++ b/osdep/Arp.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ARP_HPP diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index 62fabc48..87a9aece 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index 8c6314db..3cb9c10e 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BSDETHERNETTAP_HPP diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index 9829f170..ee832825 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BINDER_HPP diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp index 6172f4da..34abcb67 100644 --- a/osdep/BlockingQueue.hpp +++ b/osdep/BlockingQueue.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BLOCKINGQUEUE_HPP diff --git a/osdep/Http.cpp b/osdep/Http.cpp index 064ccd0c..d2540071 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/Http.hpp b/osdep/Http.hpp index e7d4d03e..3f98d760 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_HTTP_HPP diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index f74efc0a..2d3891e3 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index a2a00a79..ab9d2370 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_LINUXETHERNETTAP_HPP diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 3a020d61..fca1c290 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "../node/Constants.hpp" diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index fd77a79a..849bddf5 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -1,3 +1,29 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + #ifndef ZT_MANAGEDROUTE_HPP #define ZT_MANAGEDROUTE_HPP diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp index 4f636310..cd8b9b91 100644 --- a/osdep/NeighborDiscovery.cpp +++ b/osdep/NeighborDiscovery.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "NeighborDiscovery.hpp" diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp index 47831bda..2e7a68ba 100644 --- a/osdep/NeighborDiscovery.hpp +++ b/osdep/NeighborDiscovery.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NEIGHBORDISCOVERY_HPP diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index fd5efed0..b7fce982 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index b84d5d2d..4b9ee893 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_OSUTILS_HPP diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp index f70908b8..53c9ba98 100644 --- a/osdep/OSXEthernetTap.cpp +++ b/osdep/OSXEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp index 5a96c210..ed7f39c3 100644 --- a/osdep/OSXEthernetTap.hpp +++ b/osdep/OSXEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_OSXETHERNETTAP_HPP diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index eab8a317..01a339e9 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_PHY_HPP diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index d3a19384..99286172 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_USE_MINIUPNPC diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp index 0b8d15fc..61015a09 100644 --- a/osdep/PortMapper.hpp +++ b/osdep/PortMapper.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_USE_MINIUPNPC diff --git a/osdep/TestEthernetTap.hpp b/osdep/TestEthernetTap.hpp index 6c044a94..afd89541 100644 --- a/osdep/TestEthernetTap.hpp +++ b/osdep/TestEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_TESTETHERNETTAP_HPP diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index 5423a8ab..a2f0919f 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_THREAD_HPP diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 79b9d35e..c37c7410 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index f2cf73f3..a3c1c0c3 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_WINDOWSETHERNETTAP_HPP diff --git a/selftest.cpp b/selftest.cpp index e23afd6e..209fe203 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/service/ClusterDefinition.hpp b/service/ClusterDefinition.hpp index dda1a8c8..9947e46b 100644 --- a/service/ClusterDefinition.hpp +++ b/service/ClusterDefinition.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CLUSTERDEFINITION_HPP diff --git a/service/ClusterGeoIpService.cpp b/service/ClusterGeoIpService.cpp index 89015c51..2dcc9179 100644 --- a/service/ClusterGeoIpService.cpp +++ b/service/ClusterGeoIpService.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_ENABLE_CLUSTER diff --git a/service/ClusterGeoIpService.hpp b/service/ClusterGeoIpService.hpp index ff2fcdb8..380f944f 100644 --- a/service/ClusterGeoIpService.hpp +++ b/service/ClusterGeoIpService.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CLUSTERGEOIPSERVICE_HPP diff --git a/service/OneService.cpp b/service/OneService.cpp index 988e723d..9f9cec0a 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/service/OneService.hpp b/service/OneService.hpp index 3390f2ac..f52cd40e 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ONESERVICE_HPP diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 7ec377cc..d94beab5 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index 4bb0ef51..ff3e36df 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SOFTWAREUPDATER_HPP diff --git a/version.h b/version.h index c51bfee2..b3b2fc81 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef _ZT_VERSION_H -- cgit v1.2.3 From 107e3e41065a816354c3f383736c5abbb156b0d3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 May 2017 17:12:02 -0700 Subject: First pass of configurable MTU and max MTU increase. --- include/ZeroTierOne.h | 22 +--------------------- node/Constants.hpp | 9 +++------ node/IncomingPacket.cpp | 2 +- node/Network.cpp | 4 +++- node/NetworkConfig.cpp | 7 +++++++ node/NetworkConfig.hpp | 7 +++++++ 6 files changed, 22 insertions(+), 29 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 20707a1d..21adbe02 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -61,28 +61,8 @@ extern "C" { /** * Maximum MTU for ZeroTier virtual networks - * - * This is pretty much an unchangeable global constant. To make it change - * across nodes would require logic to send ICMP packet too big messages, - * which would complicate things. 1500 has been good enough on most LANs - * for ages, so a larger MTU should be fine for the forseeable future. This - * typically results in two UDP packets per single large frame. Experimental - * results seem to show that this is good. Larger MTUs resulting in more - * fragments seemed too brittle on slow/crummy links for no benefit. - * - * If this does change, also change it in tap.h in the tuntaposx code under - * mac-tap. - * - * Overhead for a normal frame split into two packets: - * - * 1414 = 1444 (typical UDP MTU) - 28 (packet header) - 2 (ethertype) - * 1428 = 1444 (typical UDP MTU) - 16 (fragment header) - * SUM: 2842 - * - * We use 2800, which leaves some room for other payload in other types of - * messages such as multicast propagation or future support for bridging. */ -#define ZT_MAX_MTU 2800 +#define ZT_MAX_MTU 10000 /** * Maximum length of network short name diff --git a/node/Constants.hpp b/node/Constants.hpp index d3c87491..8aeaef02 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -159,15 +159,12 @@ /** * Default MTU used for Ethernet tap device */ -#define ZT_IF_MTU ZT_MAX_MTU +#define ZT_DEFAULT_MTU 2800 /** - * Maximum number of packet fragments we'll support - * - * The actual spec allows 16, but this is the most we'll support right - * now. Packets with more than this many fragments are dropped. + * Maximum number of packet fragments we'll support (protocol max: 16) */ -#define ZT_MAX_PACKET_FRAGMENTS 4 +#define ZT_MAX_PACKET_FRAGMENTS 7 /** * Size of RX queue diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 126da53c..7ef2054b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1125,7 +1125,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, //TRACE("<address().toString().c_str(),flags,frameLen); - if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { + if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay diff --git a/node/Network.cpp b/node/Network.cpp index ee0f8611..de2ea7d7 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1225,6 +1225,8 @@ void Network::requestConfiguration(void *tPtr) nconf->revision = 1; nconf->issuedTo = RR->identity.address(); nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + nconf->mtu = ZT_DEFAULT_MTU; + nconf->multicastLimit = 0; nconf->staticIpCount = 1; nconf->ruleCount = 14; nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt()); @@ -1495,7 +1497,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const else ec->name[0] = (char)0; ec->status = _status(); ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; - ec->mtu = ZT_IF_MTU; + ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16); ec->dhcp = 0; std::vector
ab(_config.activeBridges()); diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 9effe529..c39f6cab 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -51,6 +51,7 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) return false; #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF if (includeLegacy) { @@ -217,6 +218,12 @@ bool NetworkConfig::fromDictionary(const DictionarymulticastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); + this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU); + if (this->mtu < 1280) + this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others + else if (this->mtu > ZT_MAX_MTU) + this->mtu = ZT_MAX_MTU; + if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF char tmp2[1024]; diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 7bae6a91..fdd078d5 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -167,6 +167,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t" // text #define ZT_NETWORKCONFIG_DICT_KEY_NAME "n" +// network MTU +#define ZT_NETWORKCONFIG_DICT_KEY_MTU "mtu" // credential time max delta in ms #define ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA "ctmd" // binary serialized certificate of membership @@ -465,6 +467,11 @@ public: */ uint64_t flags; + /** + * Network MTU + */ + unsigned int mtu; + /** * Maximum number of recipients per multicast (not including active bridges) */ -- cgit v1.2.3 From b9c1407013eba0f26f311ab97937048eaa0ce9df Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 May 2017 09:36:37 -0700 Subject: Adjust PUSH_DIRECT_PATH circuit breaker, and comment out traces to reduce noise. --- node/Constants.hpp | 6 +++--- node/IncomingPacket.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 8aeaef02..494ebace 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -369,7 +369,7 @@ /** * Time horizon for push direct paths cutoff */ -#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 +#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 30000 /** * Maximum number of direct path pushes within cutoff time @@ -378,12 +378,12 @@ * per CUTOFF_TIME milliseconds per peer to prevent this from being * useful for DOS amplification attacks. */ -#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 +#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 8 /** * 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 4 +#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 8 /** * Time horizon for VERB_NETWORK_CREDENTIALS cutoff diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7ef2054b..131659f9 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1185,7 +1185,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + //TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1220,7 +1220,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { - TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); + //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; @@ -1237,7 +1237,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { - TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); + //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; -- cgit v1.2.3 From 2ec88e800877cfbc7f007d21f10429bc1b493006 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 30 May 2017 10:19:45 -0700 Subject: Remove old circuit test code. Rules engine will let us do this much better and more simply. --- controller/EmbeddedNetworkController.cpp | 125 ----------------- controller/EmbeddedNetworkController.hpp | 7 - include/ZeroTierOne.h | 226 ------------------------------- node/IncomingPacket.cpp | 196 +-------------------------- node/IncomingPacket.hpp | 2 - node/Node.cpp | 88 ------------ node/Node.hpp | 6 - node/Packet.cpp | 2 - node/Packet.hpp | 116 +--------------- 9 files changed, 4 insertions(+), 764 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 3e9a28b8..e2eaa788 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -726,59 +726,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( responseContentType = "application/json"; return 200; - } else if ((path.size() == 3)&&(path[2] == "test")) { - - Mutex::Lock _l(_tests_m); - - _tests.push_back(ZT_CircuitTest()); - ZT_CircuitTest *const test = &(_tests.back()); - memset(test,0,sizeof(ZT_CircuitTest)); - - Utils::getSecureRandom(&(test->testId),sizeof(test->testId)); - test->credentialNetworkId = nwid; - test->ptr = (void *)this; - json hops = b["hops"]; - if (hops.is_array()) { - for(unsigned long i=0;ihops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL; - } - ++test->hopCount; - } else if (hops2.is_string()) { - std::string s = hops2; - test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL; - ++test->hopCount; - } - } - } - test->reportAtEveryHop = (OSUtils::jsonBool(b["reportAtEveryHop"],true) ? 1 : 0); - - if (!test->hopCount) { - _tests.pop_back(); - responseBody = "{ \"message\": \"a test must contain at least one hop\" }"; - responseContentType = "application/json"; - return 400; - } - - test->timestamp = OSUtils::now(); - - if (_node) { - _node->circuitTestBegin((void *)0,test,&(EmbeddedNetworkController::_circuitTestCallback)); - } else { - _tests.pop_back(); - return 500; - } - - char json[512]; - Utils::snprintf(json,sizeof(json),"{\"testId\":\"%.16llx\",\"timestamp\":%llu}",test->testId,test->timestamp); - responseBody = json; - responseContentType = "application/json"; - - return 200; - } // else 404 } else { @@ -1118,7 +1065,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( void EmbeddedNetworkController::threadMain() throw() { - uint64_t lastCircuitTestCheck = 0; _RQEntry *qe = (_RQEntry *)0; while ((_running)&&(_queue.get(qe))) { try { @@ -1153,80 +1099,9 @@ void EmbeddedNetworkController::threadMain() } } catch ( ... ) {} delete qe; - - if (_running) { - uint64_t now = OSUtils::now(); - if ((now - lastCircuitTestCheck) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { - lastCircuitTestCheck = now; - Mutex::Lock _l(_tests_m); - for(std::list< ZT_CircuitTest >::iterator i(_tests.begin());i!=_tests.end();) { - if ((now - i->timestamp) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { - _node->circuitTestEnd(&(*i)); - _tests.erase(i++); - } else ++i; - } - } - } } } -void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) -{ - char tmp[2048],id[128]; - EmbeddedNetworkController *const self = reinterpret_cast(test->ptr); - - if ((!test)||(!report)||(!test->credentialNetworkId)) return; // sanity check - - const uint64_t now = OSUtils::now(); - Utils::snprintf(id,sizeof(id),"network/%.16llx/test/%.16llx-%.16llx-%.10llx-%.10llx",test->credentialNetworkId,test->testId,now,report->upstream,report->current); - Utils::snprintf(tmp,sizeof(tmp), - "{\"id\": \"%s\"," - "\"objtype\": \"circuit_test\"," - "\"timestamp\": %llu," - "\"networkId\": \"%.16llx\"," - "\"testId\": \"%.16llx\"," - "\"upstream\": \"%.10llx\"," - "\"current\": \"%.10llx\"," - "\"receivedTimestamp\": %llu," - "\"sourcePacketId\": \"%.16llx\"," - "\"flags\": %llu," - "\"sourcePacketHopCount\": %u," - "\"errorCode\": %u," - "\"vendor\": %d," - "\"protocolVersion\": %u," - "\"majorVersion\": %u," - "\"minorVersion\": %u," - "\"revision\": %u," - "\"platform\": %d," - "\"architecture\": %d," - "\"receivedOnLocalAddress\": \"%s\"," - "\"receivedFromRemoteAddress\": \"%s\"," - "\"receivedFromLinkQuality\": %f}", - id + 30, // last bit only, not leading path - (unsigned long long)test->timestamp, - (unsigned long long)test->credentialNetworkId, - (unsigned long long)test->testId, - (unsigned long long)report->upstream, - (unsigned long long)report->current, - (unsigned long long)now, - (unsigned long long)report->sourcePacketId, - (unsigned long long)report->flags, - report->sourcePacketHopCount, - report->errorCode, - (int)report->vendor, - report->protocolVersion, - report->majorVersion, - report->minorVersion, - report->revision, - (int)report->platform, - (int)report->architecture, - reinterpret_cast(&(report->receivedOnLocalAddress))->toString().c_str(), - reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str(), - ((double)report->receivedFromLinkQuality / (double)ZT_PATH_LINK_QUALITY_MAX)); - - self->_db.writeRaw(id,std::string(tmp)); -} - void EmbeddedNetworkController::_request( uint64_t nwid, const InetAddress &fromAddr, diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 4f4660f8..1589ea71 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -45,9 +45,6 @@ #include "JSONDB.hpp" -// TTL for circuit tests -#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000 - namespace ZeroTier { class Node; @@ -110,7 +107,6 @@ private: } type; }; - static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); inline void _startThreads() @@ -219,9 +215,6 @@ private: NetworkController::Sender *_sender; Identity _signingId; - std::list< ZT_CircuitTest > _tests; - Mutex _tests_m; - struct _MemberStatusKey { _MemberStatusKey() : networkId(0),nodeId(0) {} diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 17d6d67e..5126c5a2 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -760,7 +760,6 @@ typedef struct */ uint64_t expiration; - struct { uint64_t from; uint64_t to; @@ -1105,197 +1104,6 @@ typedef struct unsigned long peerCount; } ZT_PeerList; -/** - * ZeroTier circuit test configuration and path - */ -typedef struct { - /** - * Test ID -- an arbitrary 64-bit identifier - */ - uint64_t testId; - - /** - * Timestamp -- sent with test and echoed back by each reporter - */ - uint64_t timestamp; - - /** - * Originator credential: network ID - * - * If this is nonzero, a network ID will be set for this test and - * the originator must be its primary network controller. This is - * currently the only authorization method available, so it must - * be set to run a test. - */ - uint64_t credentialNetworkId; - - /** - * Hops in circuit test (a.k.a. FIFO for graph traversal) - */ - struct { - /** - * Hop flags (currently unused, must be zero) - */ - unsigned int flags; - - /** - * Number of addresses in this hop (max: ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) - */ - unsigned int breadth; - - /** - * 40-bit ZeroTier addresses (most significant 24 bits ignored) - */ - uint64_t addresses[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH]; - } hops[ZT_CIRCUIT_TEST_MAX_HOPS]; - - /** - * Number of hops (max: ZT_CIRCUIT_TEST_MAX_HOPS) - */ - unsigned int hopCount; - - /** - * If non-zero, circuit test will report back at every hop - */ - int reportAtEveryHop; - - /** - * An arbitrary user-settable pointer - */ - void *ptr; - - /** - * Pointer for internal use -- initialize to zero and do not modify - */ - void *_internalPtr; -} ZT_CircuitTest; - -/** - * Circuit test result report - */ -typedef struct { - /** - * Sender of report (current hop) - */ - uint64_t current; - - /** - * Previous hop - */ - uint64_t upstream; - - /** - * 64-bit test ID - */ - uint64_t testId; - - /** - * Timestamp from original test (echoed back at each hop) - */ - uint64_t timestamp; - - /** - * 64-bit packet ID of packet received by the reporting device - */ - uint64_t sourcePacketId; - - /** - * Flags - */ - uint64_t flags; - - /** - * ZeroTier protocol-level hop count of packet received by reporting device (>0 indicates relayed) - */ - unsigned int sourcePacketHopCount; - - /** - * Error code (currently unused, will be zero) - */ - unsigned int errorCode; - - /** - * Remote device vendor ID - */ - enum ZT_Vendor vendor; - - /** - * Remote device protocol compliance version - */ - unsigned int protocolVersion; - - /** - * Software major version - */ - unsigned int majorVersion; - - /** - * Software minor version - */ - unsigned int minorVersion; - - /** - * Software revision - */ - unsigned int revision; - - /** - * Platform / OS - */ - enum ZT_Platform platform; - - /** - * System architecture - */ - enum ZT_Architecture architecture; - - /** - * Local device address on which packet was received by reporting device - * - * This may have ss_family equal to zero (null address) if unspecified. - */ - struct sockaddr_storage receivedOnLocalAddress; - - /** - * Remote address from which reporter received the test packet - * - * This may have ss_family set to zero (null address) if unspecified. - */ - struct sockaddr_storage receivedFromRemoteAddress; - - /** - * Path link quality of physical path over which test was received - */ - int receivedFromLinkQuality; - - /** - * Next hops to which packets are being or will be sent by the reporter - * - * In addition to reporting back, the reporter may send the test on if - * there are more recipients in the FIFO. If it does this, it can report - * back the address(es) that make up the next hop and the physical address - * for each if it has one. The physical address being null/unspecified - * typically indicates that no direct path exists and the next packet - * will be relayed. - */ - struct { - /** - * 40-bit ZeroTier address - */ - uint64_t address; - - /** - * Physical address or null address (ss_family == 0) if unspecified or unknown - */ - struct sockaddr_storage physicalAddress; - } nextHops[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH]; - - /** - * Number of next hops reported in nextHops[] - */ - unsigned int nextHopCount; -} ZT_CircuitTestReport; - /** * A cluster member's status */ @@ -1957,40 +1765,6 @@ int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t type */ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); -/** - * Initiate a VL1 circuit test - * - * This sends an initial VERB_CIRCUIT_TEST and reports results back to the - * supplied callback until circuitTestEnd() is called. The supplied - * ZT_CircuitTest structure should be initially zeroed and then filled - * in with settings and hops. - * - * It is the caller's responsibility to call circuitTestEnd() and then - * to dispose of the test structure. Otherwise this node will listen - * for results forever. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param test Test configuration - * @param reportCallback Function to call each time a report is received - * @return OK or error if, for example, test is too big for a packet or support isn't compiled in - */ -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); - -/** - * Stop listening for results to a given circuit test - * - * This does not free the 'test' structure. The caller may do that - * after calling this method to unregister it. - * - * Any reports that are received for a given test ID after it is - * terminated are ignored. - * - * @param node Node instance - * @param test Test configuration to unregister - */ -void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test); - /** * Initialize cluster operation * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 131659f9..9140c502 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -115,8 +115,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer); - case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,tPtr,peer); - case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,tPtr,peer); case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer); } } else { @@ -1252,196 +1250,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt return true; } -bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - SharedPtr originator(RR->topology->getPeer(tPtr,originatorAddress)); - if (!originator) { - RR->sw->requestWhois(tPtr,originatorAddress); - return false; - } - - const unsigned int flags = at(ZT_PACKET_IDX_PAYLOAD + 5); - const uint64_t timestamp = at(ZT_PACKET_IDX_PAYLOAD + 7); - const uint64_t testId = at(ZT_PACKET_IDX_PAYLOAD + 15); - - // Tracks total length of variable length fields, initialized to originator credential length below - unsigned int vlf; - - // Originator credentials -- right now only a network ID for which the originator is controller or is authorized by controller is allowed - const unsigned int originatorCredentialLength = vlf = at(ZT_PACKET_IDX_PAYLOAD + 23); - uint64_t originatorCredentialNetworkId = 0; - if (originatorCredentialLength >= 1) { - switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) { - case 0x01: { // 64-bit network ID, originator must be controller - if (originatorCredentialLength >= 9) - originatorCredentialNetworkId = at(ZT_PACKET_IDX_PAYLOAD + 26); - } break; - default: break; - } - } - - // Add length of "additional fields," which are currently unused - vlf += at(ZT_PACKET_IDX_PAYLOAD + 25 + vlf); - - // Verify signature -- only tests signed by their originators are allowed - const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); - if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { - TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - return true; - } - vlf += signatureLength; - - // Save this length so we can copy the immutable parts of this test - // into the one we send along to next hops. - const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf; - - // Add length of second "additional fields" section. - vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); - - uint64_t reportFlags = 0; - - // Check credentials (signature already verified) - if (originatorCredentialNetworkId) { - SharedPtr network(RR->node->network(originatorCredentialNetworkId)); - if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - return true; - } - if (network->gate(tPtr,peer)) - reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - return true; - } - - const uint64_t now = RR->node->now(); - - unsigned int breadth = 0; - Address nextHop[256]; // breadth is a uin8_t, so this is the max - InetAddress nextHopBestPathAddress[256]; - unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf; - if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) { - // unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf] - breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf]; - for(unsigned int h=0;h nhp(RR->topology->getPeer(tPtr,nextHop[h])); - if (nhp) { - SharedPtr nhbp(nhp->getBestPath(now,false)); - if ((nhbp)&&(nhbp->alive(now))) - nextHopBestPathAddress[h] = nhbp->address(); - } - } - } - - // Report back to originator, depending on flags and whether we are last hop - if ( ((flags & 0x01) != 0) || ((breadth == 0)&&((flags & 0x02) != 0)) ) { - Packet outp(originatorAddress,RR->identity.address(),Packet::VERB_CIRCUIT_TEST_REPORT); - outp.append((uint64_t)timestamp); - outp.append((uint64_t)testId); - outp.append((uint64_t)0); // field reserved for future use - outp.append((uint8_t)ZT_VENDOR_ZEROTIER); - outp.append((uint8_t)ZT_PROTO_VERSION); - outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED); - outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED); - outp.append((uint16_t)0); // error code, currently unused - outp.append((uint64_t)reportFlags); - outp.append((uint64_t)packetId()); - peer->address().appendTo(outp); - outp.append((uint8_t)hops()); - _path->localAddress().serialize(outp); - _path->address().serialize(outp); - outp.append((uint16_t)_path->linkQuality()); - outp.append((uint8_t)breadth); - for(unsigned int h=0;hsw->send(tPtr,outp,true); - } - - // If there are next hops, forward the test along through the graph - if (breadth > 0) { - Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); - outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature); - outp.append((uint16_t)0); // no additional fields - if (remainingHopsPtr < size()) - outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr); - - for(unsigned int h=0;hidentity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid - outp.newInitializationVector(); - outp.setDestination(nextHop[h]); - RR->sw->send(tPtr,outp,true); - } - } - } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - -bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) -{ - try { - ZT_CircuitTestReport report; - memset(&report,0,sizeof(report)); - - report.current = peer->address().toInt(); - report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); - report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); - report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); - report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); - report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); - report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58 - report.errorCode = at(ZT_PACKET_IDX_PAYLOAD + 34); - report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]); - report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25]; - report.majorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 26]; - report.minorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 27]; - report.revision = at(ZT_PACKET_IDX_PAYLOAD + 28); - report.platform = (enum ZT_Platform)at(ZT_PACKET_IDX_PAYLOAD + 30); - report.architecture = (enum ZT_Architecture)at(ZT_PACKET_IDX_PAYLOAD + 32); - - const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58); - const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen); - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; - if (report.protocolVersion >= 9) { - report.receivedFromLinkQuality = at(ptr); ptr += 2; - } else { - report.receivedFromLinkQuality = ZT_PATH_LINK_QUALITY_MAX; - ptr += at(ptr) + 2; // this field was once an 'extended field length' reserved field, which was always set to 0 - } - - report.nextHopCount = (*this)[ptr++]; - if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible - report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH; - for(unsigned int h=0;h(&(report.nextHops[h].physicalAddress))->deserialize(*this,ptr); - } - - RR->node->postCircuitTestReport(&report); - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); - } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); - } - return true; -} - bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { @@ -1453,9 +1261,9 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + TRACE("dropped USER_MESSAGE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 43a1ea10..11b60712 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -138,8 +138,6 @@ private: bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid); diff --git a/node/Node.cpp b/node/Node.cpp index 6d7eea43..911c9c4b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -503,64 +503,6 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController->init(RR->identity,this); } -ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) -{ - if (test->hopCount > 0) { - try { - Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); - RR->identity.address().appendTo(outp); - outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02)); - outp.append((uint64_t)test->timestamp); - outp.append((uint64_t)test->testId); - outp.append((uint16_t)0); // originator credential length, updated later - if (test->credentialNetworkId) { - outp.append((uint8_t)0x01); - outp.append((uint64_t)test->credentialNetworkId); - outp.setAt(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9); - } - outp.append((uint16_t)0); - C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD)); - outp.append((uint16_t)sig.size()); - outp.append(sig.data,(unsigned int)sig.size()); - outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator - for(unsigned int h=1;hhopCount;++h) { - outp.append((uint8_t)0); - outp.append((uint8_t)(test->hops[h].breadth & 0xff)); - for(unsigned int a=0;ahops[h].breadth;++a) - Address(test->hops[h].addresses[a]).appendTo(outp); - } - - for(unsigned int a=0;ahops[0].breadth;++a) { - outp.newInitializationVector(); - outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(tptr,outp,true); - } - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet - } - } - - { - test->_internalPtr = reinterpret_cast(reportCallback); - Mutex::Lock _l(_circuitTests_m); - if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end()) - _circuitTests.push_back(test); - } - - return ZT_RESULT_OK; -} - -void Node::circuitTestEnd(ZT_CircuitTest *test) -{ - Mutex::Lock _l(_circuitTests_m); - for(;;) { - std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test)); - if (ct == _circuitTests.end()) - break; - else _circuitTests.erase(ct); - } -} - ZT_ResultCode Node::clusterInit( unsigned int myId, const struct sockaddr_storage *zeroTierPhysicalEndpoints, @@ -715,20 +657,6 @@ uint64_t Node::prng() return z + y; } -void Node::postCircuitTestReport(const ZT_CircuitTestReport *report) -{ - std::vector< ZT_CircuitTest * > toNotify; - { - Mutex::Lock _l(_circuitTests_m); - for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) { - if ((*i)->testId == report->testId) - toNotify.push_back(*i); - } - } - for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i) - (reinterpret_cast((*i)->_internalPtr))(reinterpret_cast(this),*i,report); -} - void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) { RR->topology->setTrustedPaths(reinterpret_cast(networks),ids,count); @@ -1070,22 +998,6 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) -{ - try { - return reinterpret_cast(node)->circuitTestBegin(tptr,test,reportCallback); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - -void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) -{ - try { - reinterpret_cast(node)->circuitTestEnd(test); - } catch ( ... ) {} -} - enum ZT_ResultCode ZT_Node_clusterInit( ZT_Node *node, unsigned int myId, diff --git a/node/Node.hpp b/node/Node.hpp index 95587161..57b5489e 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -117,8 +117,6 @@ public: void clearLocalInterfaceAddresses(); int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); void setNetconfMaster(void *networkControllerInstance); - ZT_ResultCode circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); - void circuitTestEnd(ZT_CircuitTest *test); ZT_ResultCode clusterInit( unsigned int myId, const struct sockaddr_storage *zeroTierPhysicalEndpoints, @@ -219,7 +217,6 @@ public: inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); - void postCircuitTestReport(const ZT_CircuitTestReport *report); void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); World planet() const; @@ -309,9 +306,6 @@ private: std::vector< std::pair< uint64_t, SharedPtr > > _networks; Mutex _networks_m; - std::vector< ZT_CircuitTest * > _circuitTests; - Mutex _circuitTests_m; - std::vector _directPaths; Mutex _directPaths_m; diff --git a/node/Packet.cpp b/node/Packet.cpp index e778e3bb..6e1b36ac 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1082,8 +1082,6 @@ const char *Packet::verbString(Verb v) case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; - case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST"; - case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT"; case VERB_USER_MESSAGE: return "USER_MESSAGE"; } return "(unknown)"; diff --git a/node/Packet.hpp b/node/Packet.hpp index 1de679e7..a76d4180 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -61,7 +61,7 @@ * 4 - 0.6.0 ... 1.0.6 * + BREAKING CHANGE: New identity format based on hashcash design * 5 - 1.1.0 ... 1.1.5 - * + Supports circuit test, proof of work, and echo + * + Supports echo * + Supports in-band world (root server definition) updates * + Clustering! (Though this will work with protocol v4 clients.) * + Otherwise backward compatible with protocol v4 @@ -954,119 +954,7 @@ public: */ VERB_PUSH_DIRECT_PATHS = 0x10, - /** - * Source-routed circuit test message: - * <[5] address of originator of circuit test> - * <[2] 16-bit flags> - * <[8] 64-bit timestamp> - * <[8] 64-bit test ID (arbitrary, set by tester)> - * <[2] 16-bit originator credential length (includes type)> - * [[1] originator credential type (for authorizing test)] - * [[...] originator credential] - * <[2] 16-bit length of additional fields> - * [[...] additional fields] - * [ ... end of signed portion of request ... ] - * <[2] 16-bit length of signature of request> - * <[...] signature of request by originator> - * <[2] 16-bit length of additional fields> - * [[...] additional fields] - * <[...] next hop(s) in path> - * - * Flags: - * 0x01 - Report back to originator at all hops - * 0x02 - Report back to originator at last hop - * - * Originator credential types: - * 0x01 - 64-bit network ID for which originator is controller - * - * Path record format: - * <[1] 8-bit flags (unused, must be zero)> - * <[1] 8-bit breadth (number of next hops)> - * <[...] one or more ZeroTier addresses of next hops> - * - * The circuit test allows a device to send a message that will traverse - * the network along a specified path, with each hop optionally reporting - * back to the tester via VERB_CIRCUIT_TEST_REPORT. - * - * Each circuit test packet includes a digital signature by the originator - * of the request, as well as a credential by which that originator claims - * authorization to perform the test. Currently this signature is ed25519, - * but in the future flags might be used to indicate an alternative - * algorithm. For example, the originator might be a network controller. - * In this case the test might be authorized if the recipient is a member - * of a network controlled by it, and if the previous hop(s) are also - * members. Each hop may include its certificate of network membership. - * - * Circuit test paths consist of a series of records. When a node receives - * an authorized circuit test, it: - * - * (1) Reports back to circuit tester as flags indicate - * (2) Reads and removes the next hop from the packet's path - * (3) Sends the packet along to next hop(s), if any. - * - * It is perfectly legal for a path to contain the same hop more than - * once. In fact, this can be a very useful test to determine if a hop - * can be reached bidirectionally and if so what that connectivity looks - * like. - * - * The breadth field in source-routed path records allows a hop to forward - * to more than one recipient, allowing the tester to specify different - * forms of graph traversal in a test. - * - * There is no hard limit to the number of hops in a test, but it is - * practically limited by the maximum size of a (possibly fragmented) - * ZeroTier packet. - * - * Support for circuit tests is optional. If they are not supported, the - * node should respond with an UNSUPPORTED_OPERATION error. If a circuit - * test request is not authorized, it may be ignored or reported as - * an INVALID_REQUEST. No OK messages are generated, but TEST_REPORT - * messages may be sent (see below). - * - * ERROR packet format: - * <[8] 64-bit timestamp (echoed from original> - * <[8] 64-bit test ID (echoed from original)> - */ - VERB_CIRCUIT_TEST = 0x11, - - /** - * Circuit test hop report: - * <[8] 64-bit timestamp (echoed from original test)> - * <[8] 64-bit test ID (echoed from original test)> - * <[8] 64-bit reserved field (set to 0, currently unused)> - * <[1] 8-bit vendor ID (set to 0, currently unused)> - * <[1] 8-bit reporter protocol version> - * <[1] 8-bit reporter software major version> - * <[1] 8-bit reporter software minor version> - * <[2] 16-bit reporter software revision> - * <[2] 16-bit reporter OS/platform or 0 if not specified> - * <[2] 16-bit reporter architecture or 0 if not specified> - * <[2] 16-bit error code (set to 0, currently unused)> - * <[8] 64-bit report flags> - * <[8] 64-bit packet ID of received CIRCUIT_TEST packet> - * <[5] upstream ZeroTier address from which CIRCUIT_TEST was received> - * <[1] 8-bit packet hop count of received CIRCUIT_TEST> - * <[...] local wire address on which packet was received> - * <[...] remote wire address from which packet was received> - * <[2] 16-bit path link quality of path over which packet was received> - * <[1] 8-bit number of next hops (breadth)> - * <[...] next hop information> - * - * Next hop information record format: - * <[5] ZeroTier address of next hop> - * <[...] current best direct path address, if any, 0 if none> - * - * Report flags: - * 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid) - * - * Circuit test reports can be sent by hops in a circuit test to report - * back results. They should include information about the sender as well - * as about the paths to which next hops are being sent. - * - * 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 = 0x12, + // 0x11, 0x12 -- deprecated /** * A message with arbitrary user-definable content: -- cgit v1.2.3 From 02d18af57d7d05d26e44ff2015f5bcf55ebce7a2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 23 Jun 2017 16:10:26 -0700 Subject: Remove Cluster.hpp --- node/IncomingPacket.cpp | 1 - node/Network.cpp | 1 - node/Node.cpp | 1 - node/Peer.cpp | 1 - node/Switch.cpp | 1 - 5 files changed, 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9140c502..1d55c9f3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,7 +42,6 @@ #include "Salsa20.hpp" #include "SHA512.hpp" #include "World.hpp" -#include "Cluster.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" #include "CertificateOfRepresentation.hpp" diff --git a/node/Network.cpp b/node/Network.cpp index 74d81941..12deeeb7 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -42,7 +42,6 @@ #include "NetworkController.hpp" #include "Node.hpp" #include "Peer.hpp" -#include "Cluster.hpp" // Uncomment to make the rules engine dump trace info to stdout //#define ZT_RULES_ENGINE_DEBUGGING 1 diff --git a/node/Node.cpp b/node/Node.cpp index 37586834..39325b65 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -45,7 +45,6 @@ #include "Address.hpp" #include "Identity.hpp" #include "SelfAwareness.hpp" -#include "Cluster.hpp" #include "Network.hpp" const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; diff --git a/node/Peer.cpp b/node/Peer.cpp index 01905833..84086048 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -32,7 +32,6 @@ #include "Switch.hpp" #include "Network.hpp" #include "SelfAwareness.hpp" -#include "Cluster.hpp" #include "Packet.hpp" namespace ZeroTier { diff --git a/node/Switch.cpp b/node/Switch.cpp index 211b706a..2be54b37 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -43,7 +43,6 @@ #include "Peer.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" -#include "Cluster.hpp" namespace ZeroTier { -- cgit v1.2.3 From baa10c2995b7e0e49b49fe63a264a20982b817cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 30 Jun 2017 17:32:07 -0700 Subject: . --- include/ZeroTierOne.h | 8 +-- node/Constants.hpp | 2 +- node/IncomingPacket.cpp | 8 +-- node/Network.cpp | 14 +++-- node/Node.cpp | 24 ++++--- node/Node.hpp | 6 +- node/Path.hpp | 30 +++++++++ node/Peer.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++------ node/Peer.hpp | 54 ++++++---------- node/Topology.cpp | 32 +++++++--- node/Topology.hpp | 2 +- service/OneService.cpp | 130 +++++++++++++++++++++----------------- 12 files changed, 326 insertions(+), 148 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 9c295cee..40cae3b4 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1115,14 +1115,14 @@ enum ZT_StateObjectType * Canonical path: /peers.d/
(10-digit hex address) * Persistence: optional, can be purged at any time */ - ZT_STATE_OBJECT_PEER = 3, + ZT_STATE_OBJECT_PEER_STATE = 3, /** * The identity of a known peer * * Object ID: peer address * Canonical path: /iddb.d/
(10-digit hex address) - * Persistence: optional, can be purged at any time, recommended ttl 30-60 days + * Persistence: recommended, can be purged at any time, recommended ttl 30-60 days */ ZT_STATE_OBJECT_PEER_IDENTITY = 4, @@ -1248,7 +1248,7 @@ typedef void (*ZT_StatePutFunction)( void *, /* User ptr */ void *, /* Thread ptr */ enum ZT_StateObjectType, /* State object type */ - uint64_t, /* State object ID (if applicable) */ + const uint64_t [2], /* State object ID (if applicable) */ const void *, /* State object data */ int); /* Length of data or -1 to delete */ @@ -1264,7 +1264,7 @@ typedef int (*ZT_StateGetFunction)( void *, /* User ptr */ void *, /* Thread ptr */ enum ZT_StateObjectType, /* State object type */ - uint64_t, /* State object ID (if applicable) */ + const uint64_t [2], /* State object ID (if applicable) */ void *, /* Buffer to store state object data */ unsigned int); /* Length of data buffer in bytes */ diff --git a/node/Constants.hpp b/node/Constants.hpp index fbbba76e..88549937 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -216,7 +216,7 @@ /** * How often Topology::clean() and Network::clean() and similar are called, in ms */ -#define ZT_HOUSEKEEPING_PERIOD 120000 +#define ZT_HOUSEKEEPING_PERIOD 10000 /** * How long to remember peer records in RAM if they haven't been used diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1d55c9f3..4d99e87d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1211,8 +1211,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - peer->setClusterPreferred(a); + //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + // peer->setClusterPreferred(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->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); @@ -1228,8 +1228,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - peer->setClusterPreferred(a); + //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + // peer->setClusterPreferred(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->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Network.cpp b/node/Network.cpp index 8c6f2ce8..0a16ded8 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -700,10 +700,13 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u this->setConfiguration(tPtr,*nconf,false); _lastConfigUpdate = 0; // still want to re-request since it's likely outdated } else { + uint64_t tmp[2]; + tmp[0] = nwid; tmp[1] = 0; + bool got = false; Dictionary *dict = new Dictionary(); try { - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,nwid,dict->unsafeData(),ZT_NETWORKCONFIG_DICT_CAPACITY - 1); + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,dict->unsafeData(),ZT_NETWORKCONFIG_DICT_CAPACITY - 1); if (n > 1) { NetworkConfig *nconf = new NetworkConfig(); try { @@ -719,7 +722,7 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u delete dict; if (!got) - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,nwid,"\n",1); + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1); } if (!_portInitialized) { @@ -1185,8 +1188,11 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD if (saveToDisk) { Dictionary *d = new Dictionary(); try { - if (nconf.toDictionary(*d,false)) - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,_id,d->data(),d->sizeBytes()); + if (nconf.toDictionary(*d,false)) { + uint64_t tmp[2]; + tmp[0] = _id; tmp[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d->data(),d->sizeBytes()); + } } catch ( ... ) {} delete d; } diff --git a/node/Node.cpp b/node/Node.cpp index ab49e63b..1112c0f2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -76,22 +76,26 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); + uint64_t idtmp[2]; + idtmp[0] = 0; idtmp[1] = 0; char tmp[512]; std::string tmp2; - int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,0,tmp,sizeof(tmp) - 1); + int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; if (!RR->identity.fromString(tmp)) n = -1; } + + idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; if (n <= 0) { RR->identity.generate(); tmp2 = RR->identity.toString(true); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,RR->identity.address().toInt(),tmp2.data(),(unsigned int)tmp2.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp2.data(),(unsigned int)tmp2.length()); tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,RR->identity.address().toInt(),tmp2.data(),(unsigned int)tmp2.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); } else { - n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,RR->identity.address().toInt(),tmp,sizeof(tmp) - 1); + n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; if (RR->identity.toString(false) != tmp) @@ -99,7 +103,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } if (n <= 0) { tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,RR->identity.address().toInt(),tmp2.data(),(unsigned int)tmp2.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); } } @@ -145,7 +149,7 @@ ZT_ResultCode Node::processStateUpdate( ZT_ResultCode r = ZT_RESULT_OK_IGNORED; switch(type) { - case ZT_STATE_OBJECT_PEER: + case ZT_STATE_OBJECT_PEER_STATE: if (len) { } break; @@ -380,9 +384,9 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { + _lastHousekeepingRun = now; try { - _lastHousekeepingRun = now; - RR->topology->clean(now); + RR->topology->doPeriodicTasks(tptr,now); RR->sa->clean(now); RR->mc->clean(now); } catch ( ... ) { @@ -443,7 +447,9 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr) _networks.erase(nwid); } - RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,nwid); + uint64_t tmp[2]; + tmp[0] = nwid; tmp[1] = 0; + RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp); return ZT_RESULT_OK; } diff --git a/node/Node.hpp b/node/Node.hpp index f407c60c..f1209d00 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -197,9 +197,9 @@ public: inline bool online() const throw() { return _online; } - inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id,void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,maxlen); } - inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id,const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,(int)len); } - inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,(const void *)0,-1); } + inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,maxlen); } + inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,(int)len); } + inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,(const void *)0,-1); } #ifdef ZT_TRACE void postTrace(const char *module,unsigned int line,const char *fmt,...); diff --git a/node/Path.hpp b/node/Path.hpp index 32bceae0..74b31d8d 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -46,6 +46,11 @@ */ #define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1) +/** + * Maximum distance for a path + */ +#define ZT_PATH_DISTANCE_MAX 0xffff + namespace ZeroTier { class RuntimeEnvironment; @@ -120,6 +125,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _distance(ZT_PATH_DISTANCE_MAX), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -137,6 +143,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _distance(ZT_PATH_DISTANCE_MAX), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -299,6 +306,28 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } + /** + * @return Time last trust-established packet was received + */ + inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } + + /** + * @return Distance (higher is further) + */ + inline unsigned int distance() const { return _distance; } + + /** + * @param lo Last out send + * @param li Last in send + * @param lt Last trust established packet received + */ + inline void updateFromRemoteState(const uint64_t lo,const uint64_t li,const uint64_t lt) + { + _lastOut = lo; + _lastIn = li; + _lastTrustEstablishedPacketReceived = lt; + } + /** * Return and increment outgoing packet counter (used with Packet::armor()) * @@ -315,6 +344,7 @@ private: volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; + volatile unsigned int _distance; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index 84086048..a7466296 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -38,6 +38,8 @@ namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : RR(renv), + _lastWroteState(0), + _lastReceivedStateTimestamp(0), _lastReceive(0), _lastNontrivialReceive(0), _lastTriedMemorizedPath(0), @@ -75,6 +77,7 @@ void Peer::received( { const uint64_t now = RR->node->now(); +/* #ifdef ZT_ENABLE_CLUSTER bool isClusterSuboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { @@ -120,6 +123,7 @@ void Peer::received( } } #endif +*/ _lastReceive = now; switch (verb) { @@ -143,6 +147,8 @@ void Peer::received( if (hops == 0) { bool pathAlreadyKnown = false; + bool newPathLearned = false; + { Mutex::Lock _l(_paths_m); if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { @@ -152,9 +158,6 @@ void Peer::received( const struct sockaddr_in *const ll = reinterpret_cast(&(_v4Path.p->localAddress())); if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { _v4Path.lr = now; -#ifdef ZT_ENABLE_CLUSTER - _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; -#endif pathAlreadyKnown = true; } } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { @@ -164,9 +167,6 @@ void Peer::received( const struct sockaddr_in6 *const ll = reinterpret_cast(&(_v6Path.p->localAddress())); if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { _v6Path.lr = now; -#ifdef ZT_ENABLE_CLUSTER - _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; -#endif pathAlreadyKnown = true; } } @@ -176,11 +176,11 @@ void Peer::received( Mutex::Lock _l(_paths_m); _PeerPath *potentialNewPeerPath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { - if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) { + if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) { potentialNewPeerPath = &_v4Path; } } else if (path->address().ss_family == AF_INET6) { - if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) { + if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) { potentialNewPeerPath = &_v6Path; } } @@ -188,11 +188,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { potentialNewPeerPath->lr = now; potentialNewPeerPath->p = path; -#ifdef ZT_ENABLE_CLUSTER - potentialNewPeerPath->localClusterSuboptimal = isClusterSuboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); -#endif + newPathLearned = true; } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -200,15 +196,12 @@ void Peer::received( } } } + + if (newPathLearned) + writeState(tPtr,now); } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - const bool haveCluster = (RR->cluster); -#else - const bool haveCluster = false; -#endif - if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { + if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; std::vector pathsToPush; @@ -439,4 +432,135 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } +void Peer::writeState(void *tPtr,const uint64_t now) +{ + try { + Buffer b; + + b.append((uint8_t)1); // version + b.append(now); + + _id.serialize(b); + + { + Mutex::Lock _l(_paths_m); + unsigned int count = 0; + if (_v4Path.lr) + ++count; + if (_v6Path.lr) + ++count; + b.append((uint8_t)count); + if (_v4Path.lr) { + b.append(_v4Path.lr); + b.append(_v4Path.p->lastOut()); + b.append(_v4Path.p->lastIn()); + b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); + b.append((uint16_t)_v4Path.p->distance()); + _v4Path.p->address().serialize(b); + _v4Path.p->localAddress().serialize(b); + } + if (_v6Path.lr) { + b.append(_v6Path.lr); + b.append(_v6Path.p->lastOut()); + b.append(_v6Path.p->lastIn()); + b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); + b.append((uint16_t)_v6Path.p->distance()); + _v6Path.p->address().serialize(b); + _v6Path.p->localAddress().serialize(b); + } + } + + b.append(_lastReceive); + b.append(_lastNontrivialReceive); + b.append(_lastTriedMemorizedPath); + b.append(_lastDirectPathPushSent); + b.append(_lastDirectPathPushReceive); + b.append(_lastCredentialRequestSent); + b.append(_lastWhoisRequestReceived); + b.append(_lastEchoRequestReceived); + b.append(_lastComRequestReceived); + b.append(_lastComRequestSent); + b.append(_lastCredentialsReceived); + b.append(_lastTrustEstablishedPacketReceived); + + b.append(_vProto); + b.append(_vMajor); + b.append(_vMinor); + b.append(_vRevision); + + b.append((uint16_t)0); // length of additional fields + + uint64_t tmp[2]; + tmp[0] = _id.address().toInt(); tmp[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); + + _lastWroteState = now; + } catch ( ... ) {} // sanity check, should not be possible +} + +bool Peer::applyStateUpdate(const void *data,unsigned int len) +{ + try { + Buffer b(data,len); + unsigned int ptr = 0; + + if (b[ptr++] != 1) + return false; + const uint64_t ts = b.at(ptr); ptr += 8; + if (ts <= _lastReceivedStateTimestamp) + return false; + + const unsigned int pathCount = (unsigned int)b[ptr++]; + { + Mutex::Lock _l(_paths_m); + for(unsigned int i=0;i(ptr); ptr += 8; + const uint64_t lastOut = b.at(ptr); ptr += 8; + const uint64_t lastIn = b.at(ptr); ptr += 8; + const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; + const unsigned int distance = b.at(ptr); ptr += 2; + InetAddress addr,localAddr; + ptr += addr.deserialize(b,ptr); + ptr += localAddr.deserialize(b,ptr); + if (addr.ss_family == localAddr.ss_family) { + _PeerPath *p = (_PeerPath *)0; + switch(addr.ss_family) { + case AF_INET: p = &_v4Path; break; + case AF_INET6: p = &_v6Path; break; + } + if (p) { + if ( ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) && (p->p->distance() > distance) ) + p->p = RR->topology->getPath(localAddr,addr); + p->lr = lr; + p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); + } + } + } + } + + _lastReceive = std::max(_lastReceive,b.at(ptr)); ptr += 8; + _lastNontrivialReceive = std::max(_lastNontrivialReceive,b.at(ptr)); ptr += 8; + _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,b.at(ptr)); ptr += 8; + _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,b.at(ptr)); ptr += 8; + _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,b.at(ptr)); ptr += 8; + _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,b.at(ptr)); ptr += 8; + _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,b.at(ptr)); ptr += 8; + _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,b.at(ptr)); ptr += 8; + _lastComRequestReceived = std::max(_lastComRequestReceived,b.at(ptr)); ptr += 8; + _lastComRequestSent = std::max(_lastComRequestSent,b.at(ptr)); ptr += 8; + _lastCredentialsReceived = std::max(_lastCredentialsReceived,b.at(ptr)); ptr += 8; + _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,b.at(ptr)); ptr += 8; + + _vProto = b.at(ptr); ptr += 2; + _vMajor = b.at(ptr); ptr += 2; + _vMinor = b.at(ptr); ptr += 2; + _vRevision = b.at(ptr); ptr += 2; + + _lastReceivedStateTimestamp = ts; + + return true; + } catch ( ... ) {} // ignore invalid state updates + return false; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 9b57f23e..d6b7dad9 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -193,6 +193,22 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); + /** + * Write current peer state to external storage / cluster network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + void writeState(void *tPtr,const uint64_t now); + + /** + * Apply a state update received from e.g. a remote cluster member + * + * @param data State update data + * @param len Length of state update + * @return True if state update was applied, false if ignored or invalid + */ + bool applyStateUpdate(const void *data,unsigned int len); + /** * Reset paths within a given IP scope and address family * @@ -218,19 +234,6 @@ public: } } - /** - * Indicate that the given address was provided by a cluster as a preferred destination - * - * @param addr Address cluster prefers that we use - */ - inline void setClusterPreferred(const InetAddress &addr) - { - if (addr.ss_family == AF_INET) - _v4ClusterPreferred = addr; - else if (addr.ss_family == AF_INET6) - _v6ClusterPreferred = addr; - } - /** * Fill parameters with V4 and V6 addresses if known and alive * @@ -317,18 +320,6 @@ public: else _latency = std::min(l,(unsigned int)65535); } -#ifdef ZT_ENABLE_CLUSTER - /** - * @param now Current time - * @return True if this peer has at least one active direct path that is not cluster-suboptimal - */ - inline bool hasLocalClusterOptimalPath(uint64_t now) const - { - Mutex::Lock _l(_paths_m); - return ( ((_v4Path.p)&&(_v4Path.p->alive(now))&&(!_v4Path.localClusterSuboptimal)) || ((_v6Path.p)&&(_v6Path.p->alive(now))&&(!_v6Path.localClusterSuboptimal)) ); - } -#endif - /** * @return 256-bit secret symmetric encryption key */ @@ -449,22 +440,18 @@ public: private: struct _PeerPath { -#ifdef ZT_ENABLE_CLUSTER - _PeerPath() : lr(0),p(),localClusterSuboptimal(false) {} -#else _PeerPath() : lr(0),p() {} -#endif uint64_t lr; // time of last valid ZeroTier packet SharedPtr p; -#ifdef ZT_ENABLE_CLUSTER - bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer -#endif }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; const RuntimeEnvironment *RR; + uint64_t _lastWroteState; + uint64_t _lastReceivedStateTimestamp; + uint64_t _lastReceive; // direct or indirect uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. uint64_t _lastTriedMemorizedPath; @@ -483,9 +470,6 @@ private: uint16_t _vMinor; uint16_t _vRevision; - InetAddress _v4ClusterPreferred; - InetAddress _v6ClusterPreferred; - _PeerPath _v4Path; // IPv4 direct path _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; diff --git a/node/Topology.cpp b/node/Topology.cpp index d4b424ff..be116b28 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -69,7 +69,9 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : _amRoot(false) { uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,0,tmp,sizeof(tmp)); + uint64_t idtmp[2]; + idtmp[0] = 0; idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp)); if (n > 0) { try { World cachedPlanet; @@ -159,7 +161,9 @@ void Topology::saveIdentity(void *tPtr,const Identity &id) { if (id) { const std::string tmp(id.toString(false)); - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,id.address().toInt(),tmp.data(),(unsigned int)tmp.length()); + uint64_t idtmp[2]; + idtmp[0] = id.address().toInt(); idtmp[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp.data(),(unsigned int)tmp.length()); } } @@ -329,7 +333,9 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) try { Buffer sbuf; existing->serialize(sbuf,false); - RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,existing->id(),sbuf.data(),sbuf.size()); + uint64_t idtmp[2]; + idtmp[0] = existing->id(); idtmp[1] = 0; + RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size()); } catch ( ... ) {} _memoizeUpstreams(tPtr); @@ -340,7 +346,9 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) { char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,id,tmp,sizeof(tmp)); + uint64_t idtmp[2]; + idtmp[0] = id; idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp)); if (n > 0) { try { World w; @@ -369,7 +377,9 @@ void Topology::removeMoon(void *tPtr,const uint64_t id) if (m->id() != id) { nm.push_back(*m); } else { - RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,id); + uint64_t idtmp[2]; + idtmp[0] = id; idtmp[1] = 0; + RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp); } } _moons.swap(nm); @@ -384,7 +394,7 @@ void Topology::removeMoon(void *tPtr,const uint64_t id) _memoizeUpstreams(tPtr); } -void Topology::clean(uint64_t now) +void Topology::doPeriodicTasks(void *tPtr,uint64_t now) { { Mutex::Lock _l1(_peers_m); @@ -393,10 +403,14 @@ void Topology::clean(uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { _peers.erase(*a); + } else { + (*p)->writeState(tPtr,now); + } } } + { Mutex::Lock _l(_paths_m); Hashtable< Path::HashKey,SharedPtr >::Iterator i(_paths); @@ -412,7 +426,9 @@ void Topology::clean(uint64_t now) Identity Topology::_getIdentity(void *tPtr,const Address &zta) { char tmp[512]; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,zta.toInt(),tmp,sizeof(tmp) - 1); + uint64_t idtmp[2]; + idtmp[0] = zta.toInt(); idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; try { diff --git a/node/Topology.hpp b/node/Topology.hpp index d06ba94b..9bc7c0d8 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -308,7 +308,7 @@ public: /** * Clean and flush database */ - void clean(uint64_t now); + void doPeriodicTasks(void *tPtr,uint64_t now); /** * @param now Current time diff --git a/service/OneService.cpp b/service/OneService.cpp index 993fb116..f949f348 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -312,8 +312,8 @@ class OneServiceImpl; static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); -static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,const void *data,int len); -static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,void *data,unsigned int maxlen); +static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len); +static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen); static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); @@ -1220,34 +1220,20 @@ public: res["planetWorldId"] = planet.id(); res["planetWorldTimestamp"] = planet.timestamp(); -/* -#ifdef ZT_ENABLE_CLUSTER - json cj; - ZT_ClusterStatus cs; - _node->clusterStatus(&cs); - if (cs.clusterSize >= 1) { - json cja = json::array(); - for(unsigned int i=0;i::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) { + uint64_t up = 0; + for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { + if (((*c)->remoteAddr == *ca)&&((*c)->clusterMemberId)&&((*c)->lastReceive > up)) + up = (*c)->lastReceive; + } + cj[ca->toString()] = up; } - cj["members"] = cja; - cj["myId"] = (int)cs.myId; - cj["clusterSize"] = cs.clusterSize; + res["cluster"] = cj; } - res["cluster"] = cj; -#else - res["cluster"] = json(); -#endif -*/ scode = 200; } else if (ps[0] == "moon") { @@ -1877,16 +1863,15 @@ public: return false; } - void replicateStateObject(const ZT_StateObjectType type,const uint64_t id,const void *const data,const unsigned int len,TcpConnection *tc) + void replicateStateObject(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,TcpConnection *tc) { - char buf[34]; - + char buf[42]; Mutex::Lock _l2(tc->writeq_m); if (tc->writeq.length() == 0) _phy.setNotifyWritable(tc->sock,true); - const unsigned int mlen = len + 34; + const unsigned int mlen = len + 42; tc->writeq.push_back((char)((mlen >> 16) & 0xff)); tc->writeq.push_back((char)((mlen >> 8) & 0xff)); @@ -1895,24 +1880,32 @@ public: Utils::getSecureRandom(buf,16); buf[24] = (char)CLUSTER_MESSAGE_STATE_OBJECT; buf[25] = (char)type; - buf[26] = (char)((id >> 56) & 0xff); - buf[27] = (char)((id >> 48) & 0xff); - buf[28] = (char)((id >> 40) & 0xff); - buf[29] = (char)((id >> 32) & 0xff); - buf[30] = (char)((id >> 24) & 0xff); - buf[31] = (char)((id >> 16) & 0xff); - buf[32] = (char)((id >> 8) & 0xff); - buf[33] = (char)(id & 0xff); + buf[26] = (char)((id[0] >> 56) & 0xff); + buf[27] = (char)((id[0] >> 48) & 0xff); + buf[28] = (char)((id[0] >> 40) & 0xff); + buf[29] = (char)((id[0] >> 32) & 0xff); + buf[30] = (char)((id[0] >> 24) & 0xff); + buf[31] = (char)((id[0] >> 16) & 0xff); + buf[32] = (char)((id[0] >> 8) & 0xff); + buf[33] = (char)(id[0] & 0xff); + buf[34] = (char)((id[1] >> 56) & 0xff); + buf[35] = (char)((id[1] >> 48) & 0xff); + buf[36] = (char)((id[1] >> 40) & 0xff); + buf[37] = (char)((id[1] >> 32) & 0xff); + buf[38] = (char)((id[1] >> 24) & 0xff); + buf[39] = (char)((id[1] >> 16) & 0xff); + buf[40] = (char)((id[1] >> 8) & 0xff); + buf[41] = (char)(id[1] & 0xff); const unsigned long startpos = (unsigned long)tc->writeq.length(); - tc->writeq.append(buf,34); + tc->writeq.append(buf,42); tc->writeq.append(reinterpret_cast(data),len); char *const outdata = const_cast(tc->writeq.data()) + startpos; encryptClusterMessage(outdata,mlen); } - void replicateStateObjectToCluster(const ZT_StateObjectType type,const uint64_t id,const void *const data,const unsigned int len,const uint64_t everyoneBut) + void replicateStateObjectToCluster(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,const uint64_t everyoneBut) { std::vector sentTo; if (everyoneBut) @@ -1927,7 +1920,7 @@ public: } } - void writeStateObject(enum ZT_StateObjectType type,uint64_t id,const void *data,int len) + void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { char p[4096]; bool secure = false; @@ -1940,17 +1933,17 @@ public: secure = true; break; case ZT_STATE_OBJECT_PEER_IDENTITY: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id); + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id[0]); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); secure = true; break; case ZT_STATE_OBJECT_PLANET: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id); + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); break; default: p[0] = (char)0; @@ -1985,8 +1978,12 @@ public: if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { if (f->length() == 21) { const uint64_t nwid = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (nwid) - replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,nwid,buf.data(),(int)buf.length(),tc); + if (nwid) { + uint64_t tmp[2]; + tmp[0] = nwid; + tmp[1] = 0; + replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,buf.data(),(int)buf.length(),tc); + } } } } @@ -1996,8 +1993,12 @@ public: if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { if (f->length() == 21) { const uint64_t moonId = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (moonId) - replicateStateObject(ZT_STATE_OBJECT_MOON,moonId,buf.data(),(int)buf.length(),tc); + if (moonId) { + uint64_t tmp[2]; + tmp[0] = moonId; + tmp[1] = 0; + replicateStateObject(ZT_STATE_OBJECT_MOON,tmp,buf.data(),(int)buf.length(),tc); + } } } } @@ -2313,8 +2314,9 @@ public: break; case CLUSTER_MESSAGE_STATE_OBJECT: - if (mlen >= (25 + 9)) { // type + object ID + [data] - const uint64_t objId = ( + if (mlen >= 42) { // type + object ID + [data] + uint64_t objId[2]; + objId[0] = ( ((uint64_t)data[26] << 56) | ((uint64_t)data[27] << 48) | ((uint64_t)data[28] << 40) | @@ -2324,9 +2326,19 @@ public: ((uint64_t)data[32] << 8) | (uint64_t)data[33] ); - if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 34,(unsigned int)(mlen - 34)) == ZT_RESULT_OK) { - writeStateObject((ZT_StateObjectType)data[25],objId,data + 34,(unsigned int)(mlen - 34)); - replicateStateObjectToCluster((ZT_StateObjectType)data[25],objId,data + 34,(unsigned int)(mlen - 34),tc->clusterMemberId); + objId[1] = ( + ((uint64_t)data[34] << 56) | + ((uint64_t)data[35] << 48) | + ((uint64_t)data[36] << 40) | + ((uint64_t)data[37] << 32) | + ((uint64_t)data[38] << 24) | + ((uint64_t)data[39] << 16) | + ((uint64_t)data[40] << 8) | + (uint64_t)data[41] + ); + if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId[0],data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) { + writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)); + replicateStateObjectToCluster((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42),tc->clusterMemberId); } } break; @@ -2543,13 +2555,13 @@ public: } } - inline void nodeStatePutFunction(enum ZT_StateObjectType type,uint64_t id,const void *data,int len) + inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { writeStateObject(type,id,data,len); replicateStateObjectToCluster(type,id,data,len,0); } - inline int nodeStateGetFunction(enum ZT_StateObjectType type,uint64_t id,void *data,unsigned int maxlen) + inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { char p[4096]; switch(type) { @@ -2866,9 +2878,9 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr { return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) { reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } -static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,const void *data,int len) +static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { reinterpret_cast(uptr)->nodeStatePutFunction(type,id,data,len); } -static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,void *data,unsigned int maxlen) +static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { return reinterpret_cast(uptr)->nodeStateGetFunction(type,id,data,maxlen); } static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } -- cgit v1.2.3 From 2f20258807f8665bc3f9c527106e61761e01ecc3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 10:25:36 -0700 Subject: . --- include/ZeroTierOne.h | 34 +++++----- node/Constants.hpp | 12 ++-- node/Identity.hpp | 5 +- node/IncomingPacket.cpp | 12 ---- node/Network.cpp | 10 --- node/Node.cpp | 151 +++++++++++--------------------------------- node/Node.hpp | 2 +- node/Path.hpp | 13 ---- node/Peer.cpp | 113 ++++++++++++++++++++------------- node/Peer.hpp | 16 ++++- node/RuntimeEnvironment.hpp | 19 ++++-- node/Switch.cpp | 93 ++------------------------- node/Topology.cpp | 59 +++++------------ node/Topology.hpp | 27 ++------ osdep/Binder.hpp | 4 +- service/OneService.cpp | 94 +++++++++++++-------------- 16 files changed, 240 insertions(+), 424 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 40cae3b4..133ae340 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1072,9 +1072,9 @@ typedef struct * identity of a node and its address, the identity (public and secret) * must be saved at a minimum. * - * The reference service implementation currently persists identity, - * peer identities (for a period of time), planet, moons, and network - * configurations. Other state is treated as ephemeral. + * State objects actually have two IDs (uint64_t[2]). If only one is + * listed the second ([1]) should be zero and is ignored in storage + * and replication. * * All state objects should be replicated in cluster mode. The reference * clustering implementation uses a rumor mill algorithm in which state @@ -1118,22 +1118,25 @@ enum ZT_StateObjectType ZT_STATE_OBJECT_PEER_STATE = 3, /** - * The identity of a known peer + * Network configuration * * Object ID: peer address - * Canonical path: /iddb.d/
(10-digit hex address) - * Persistence: recommended, can be purged at any time, recommended ttl 30-60 days + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist */ - ZT_STATE_OBJECT_PEER_IDENTITY = 4, + ZT_STATE_OBJECT_NETWORK_CONFIG = 4, /** - * Network configuration + * Network membership (network X peer intersection) * - * Object ID: peer address - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist + * If these are persisted they must be restored after peer states and + * network configs. Otherwise they are ignored. + * + * Object ID: [0] network ID, [1] peer address + * Canonical path: /networks.d//members.d/
+ * Persistence: optional (not usually needed) */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 5, + ZT_STATE_OBJECT_NETWORK_MEMBERSHIP = 5, /** * The planet (there is only one per... well... planet!) @@ -1450,7 +1453,8 @@ void ZT_Node_delete(ZT_Node *node); * * Unless clustering is being implemented this function doesn't need to be * used after startup. It could be called in response to filesystem changes - * to allow some degree of live configurability by filesystem observation. + * to allow some degree of live configurability by filesystem observation + * but this kind of thing is entirely optional. * * The return value of this function indicates whether the update was accepted * as new. A return value of ZT_RESULT_OK indicates that the node gleaned new @@ -1468,7 +1472,7 @@ void ZT_Node_delete(ZT_Node *node); * @param node Node instance * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param type State object type - * @param id State object ID + * @param id State object ID (if object type has only one ID, second should be zero) * @param data State object data * @param len Length of state object data in bytes * @return ZT_RESULT_OK if object was accepted or ZT_RESULT_OK_IGNORED if non-informative, error if object was invalid @@ -1477,7 +1481,7 @@ enum ZT_ResultCode ZT_Node_processStateUpdate( ZT_Node *node, void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len); diff --git a/node/Constants.hpp b/node/Constants.hpp index 88549937..274b9564 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -216,7 +216,12 @@ /** * How often Topology::clean() and Network::clean() and similar are called, in ms */ -#define ZT_HOUSEKEEPING_PERIOD 10000 +#define ZT_HOUSEKEEPING_PERIOD 60000 + +/** + * How often in ms to write peer state to storage and/or cluster (approximate) + */ +#define ZT_PEER_STATE_WRITE_PERIOD 10000 /** * How long to remember peer records in RAM if they haven't been used @@ -322,11 +327,6 @@ */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) -/** - * Send a full HELLO every this often (ms) - */ -#define ZT_PEER_SEND_FULL_HELLO_EVERY (ZT_PEER_PING_PERIOD * 2) - /** * How often to retry expired paths that we're still remembering */ diff --git a/node/Identity.hpp b/node/Identity.hpp index b1c7d6f4..79e17f4d 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -91,7 +91,10 @@ public: ~Identity() { - delete _privateKey; + if (_privateKey) { + Utils::burn(_privateKey,sizeof(C25519::Private)); + delete _privateKey; + } } inline Identity &operator=(const Identity &id) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 4d99e87d..0548387b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -585,12 +585,6 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar } else { // Request unknown WHOIS from upstream from us (if we have one) RR->sw->requestWhois(tPtr,addr); -#ifdef ZT_ENABLE_CLUSTER - // Distribute WHOIS queries across a cluster if we do not know the ID. - // This may result in duplicate OKs to the querying peer, which is fine. - if (RR->cluster) - RR->cluster->sendDistributedQuery(*this); -#endif } } @@ -1055,12 +1049,6 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - - // If we are a member of a cluster, distribute this GATHER across it -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(gatheredLocally < gatherLimit)) - RR->cluster->sendDistributedQuery(*this); -#endif } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); diff --git a/node/Network.cpp b/node/Network.cpp index 0a16ded8..bccc0397 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1067,11 +1067,6 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add return 0; } -#ifdef ZT_ENABLE_CLUSTER - if ((source)&&(RR->cluster)) - RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); -#endif - // New properly verified chunks can be flooded "virally" through the network if (fastPropagate) { Address *a = (Address *)0; @@ -1099,11 +1094,6 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) c = &(_incomingConfigChunks[i]); } - -#ifdef ZT_ENABLE_CLUSTER - if ((source)&&(RR->cluster)) - RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); -#endif } else { TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); return 0; diff --git a/node/Node.cpp b/node/Node.cpp index 1112c0f2..4ffe496c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -68,6 +68,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 throw std::runtime_error("callbacks struct version mismatch"); memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); + // Initialize non-cryptographic PRNG from a good random source Utils::getSecureRandom((void *)_prngState,sizeof(_prngState)); _online = false; @@ -78,33 +79,34 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0; - char tmp[512]; - std::string tmp2; + char tmp[1024]; int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; - if (!RR->identity.fromString(tmp)) + if (RR->identity.fromString(tmp)) { + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + } else { n = -1; + } } idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; if (n <= 0) { RR->identity.generate(); - tmp2 = RR->identity.toString(true); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp2.data(),(unsigned int)tmp2.length()); - tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr.data(),(unsigned int)RR->secretIdentityStr.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr.data(),(unsigned int)RR->publicIdentityStr.length()); } else { n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; - if (RR->identity.toString(false) != tmp) + if (RR->publicIdentityStr != tmp) n = -1; } - if (n <= 0) { - tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); - } + if (n <= 0) + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr.data(),(unsigned int)RR->publicIdentityStr.length()); } try { @@ -125,24 +127,20 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 Node::~Node() { - Mutex::Lock _l(_networks_m); - - _networks.clear(); // destroy all networks before shutdown - + { + Mutex::Lock _l(_networks_m); + _networks.clear(); // destroy all networks before shutdown + } delete RR->sa; delete RR->topology; delete RR->mc; delete RR->sw; - -#ifdef ZT_ENABLE_CLUSTER - delete RR->cluster; -#endif } ZT_ResultCode Node::processStateUpdate( void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len) { @@ -151,11 +149,12 @@ ZT_ResultCode Node::processStateUpdate( case ZT_STATE_OBJECT_PEER_STATE: if (len) { - } - break; - - case ZT_STATE_OBJECT_PEER_IDENTITY: - if (len) { + const SharedPtr p(RR->topology->getPeer(tptr,Address(id[0]))); + if (p) { + r = (p->applyStateUpdate(data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; + } else { + r = (Peer::createFromStateUpdate(RR,tptr,data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; + } } break; @@ -163,9 +162,9 @@ ZT_ResultCode Node::processStateUpdate( if (len <= (ZT_NETWORKCONFIG_DICT_CAPACITY - 1)) { if (len < 2) { Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id]; + SharedPtr &nw = _networks[id[0]]; if (!nw) { - nw = SharedPtr(new Network(RR,tptr,id,(void *)0,(const NetworkConfig *)0)); + nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,(const NetworkConfig *)0)); r = ZT_RESULT_OK; } } else { @@ -175,7 +174,7 @@ ZT_ResultCode Node::processStateUpdate( try { if (nconf->fromDictionary(*dict)) { Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id]; + SharedPtr &nw = _networks[id[0]]; if (nw) { switch (nw->setConfiguration(tptr,*nconf,false)) { default: @@ -189,7 +188,7 @@ ZT_ResultCode Node::processStateUpdate( break; } } else { - nw = SharedPtr(new Network(RR,tptr,id,(void *)0,nconf)); + nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,nconf)); } } else { r = ZT_RESULT_ERROR_BAD_PARAMETER; @@ -208,9 +207,14 @@ ZT_ResultCode Node::processStateUpdate( } break; + case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: + if (len) { + } + break; + case ZT_STATE_OBJECT_PLANET: case ZT_STATE_OBJECT_MOON: - if (len <= ZT_WORLD_MAX_SERIALIZED_LENGTH) { + if ((len)&&(len <= ZT_WORLD_MAX_SERIALIZED_LENGTH)) { World w; try { w.deserialize(Buffer(data,len)); @@ -395,18 +399,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } try { -#ifdef ZT_ENABLE_CLUSTER - // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior - if (RR->cluster) { - RR->sw->doTimerTasks(tptr,now); - RR->cluster->doPeriodicTasks(); - *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate - } else { -#endif - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); -#ifdef ZT_ENABLE_CLUSTER - } -#endif + *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -620,76 +613,6 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController->init(RR->identity,this); } -/* -ZT_ResultCode Node::clusterInit( - unsigned int myId, - const struct sockaddr_storage *zeroTierPhysicalEndpoints, - unsigned int numZeroTierPhysicalEndpoints, - int x, - int y, - int z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - return ZT_RESULT_ERROR_BAD_PARAMETER; - - std::vector eps; - for(unsigned int i=0;icluster = new Cluster(RR,myId,eps,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg); - - return ZT_RESULT_OK; -#else - return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; -#endif -} - -ZT_ResultCode Node::clusterAddMember(unsigned int memberId) -{ -#ifdef ZT_ENABLE_CLUSTER - if (!RR->cluster) - return ZT_RESULT_ERROR_BAD_PARAMETER; - RR->cluster->addMember((uint16_t)memberId); - return ZT_RESULT_OK; -#else - return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; -#endif -} - -void Node::clusterRemoveMember(unsigned int memberId) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->removeMember((uint16_t)memberId); -#endif -} - -void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->handleIncomingStateMessage(msg,len); -#endif -} - -void Node::clusterStatus(ZT_ClusterStatus *cs) -{ - if (!cs) - return; -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->status(*cs); - else -#endif - memset(cs,0,sizeof(ZT_ClusterStatus)); -} -*/ - /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -918,7 +841,7 @@ enum ZT_ResultCode ZT_Node_processStateUpdate( ZT_Node *node, void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len) { diff --git a/node/Node.hpp b/node/Node.hpp index f1209d00..17050d24 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -85,7 +85,7 @@ public: ZT_ResultCode processStateUpdate( void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len); ZT_ResultCode processWirePacket( diff --git a/node/Path.hpp b/node/Path.hpp index 74b31d8d..a6f56d31 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -46,11 +46,6 @@ */ #define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1) -/** - * Maximum distance for a path - */ -#define ZT_PATH_DISTANCE_MAX 0xffff - namespace ZeroTier { class RuntimeEnvironment; @@ -125,7 +120,6 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), - _distance(ZT_PATH_DISTANCE_MAX), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -143,7 +137,6 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), - _distance(ZT_PATH_DISTANCE_MAX), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -311,11 +304,6 @@ public: */ inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } - /** - * @return Distance (higher is further) - */ - inline unsigned int distance() const { return _distance; } - /** * @param lo Last out send * @param li Last in send @@ -344,7 +332,6 @@ private: volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; - volatile unsigned int _distance; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index a7466296..18d05875 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -146,8 +146,8 @@ void Peer::received( path->updateLinkQuality((unsigned int)(packetId & 7)); if (hops == 0) { + // If this is a direct packet (no hops), update existing paths or learn new ones bool pathAlreadyKnown = false; - bool newPathLearned = false; { Mutex::Lock _l(_paths_m); @@ -188,7 +188,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { potentialNewPeerPath->lr = now; potentialNewPeerPath->p = path; - newPathLearned = true; + _lastWroteState = 0; // force state write now } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -196,9 +196,6 @@ void Peer::received( } } } - - if (newPathLearned) - writeState(tPtr,now); } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { @@ -270,6 +267,9 @@ void Peer::received( } } } + + if ((now - _lastWroteState) > ZT_PEER_STATE_WRITE_PERIOD) + writeState(tPtr,now); } bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) @@ -435,7 +435,7 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) void Peer::writeState(void *tPtr,const uint64_t now) { try { - Buffer b; + Buffer b; b.append((uint8_t)1); // version b.append(now); @@ -455,7 +455,6 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v4Path.p->lastOut()); b.append(_v4Path.p->lastIn()); b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); - b.append((uint16_t)_v4Path.p->distance()); _v4Path.p->address().serialize(b); _v4Path.p->localAddress().serialize(b); } @@ -464,29 +463,29 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v6Path.p->lastOut()); b.append(_v6Path.p->lastIn()); b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); - b.append((uint16_t)_v6Path.p->distance()); _v6Path.p->address().serialize(b); _v6Path.p->localAddress().serialize(b); } } - b.append(_lastReceive); - b.append(_lastNontrivialReceive); - b.append(_lastTriedMemorizedPath); - b.append(_lastDirectPathPushSent); - b.append(_lastDirectPathPushReceive); - b.append(_lastCredentialRequestSent); - b.append(_lastWhoisRequestReceived); - b.append(_lastEchoRequestReceived); - b.append(_lastComRequestReceived); - b.append(_lastComRequestSent); - b.append(_lastCredentialsReceived); - b.append(_lastTrustEstablishedPacketReceived); - - b.append(_vProto); - b.append(_vMajor); - b.append(_vMinor); - b.append(_vRevision); + // Save space by sending these as time since now at 100ms resolution + b.append((uint16_t)(std::max(now - _lastReceive,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastNontrivialReceive,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastTriedMemorizedPath,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastDirectPathPushSent,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastDirectPathPushReceive,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastCredentialRequestSent,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastWhoisRequestReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastEchoRequestReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastComRequestReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastComRequestSent,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastCredentialsReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastTrustEstablishedPacketReceived,(uint64_t)6553500) / 100)); + + b.append((uint8_t)_vProto); + b.append((uint8_t)_vMajor); + b.append((uint8_t)_vMinor); + b.append((uint16_t)_vRevision); b.append((uint16_t)0); // length of additional fields @@ -501,7 +500,7 @@ void Peer::writeState(void *tPtr,const uint64_t now) bool Peer::applyStateUpdate(const void *data,unsigned int len) { try { - Buffer b(data,len); + Buffer b(data,len); unsigned int ptr = 0; if (b[ptr++] != 1) @@ -510,6 +509,11 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) if (ts <= _lastReceivedStateTimestamp) return false; + Identity id; + ptr += id.deserialize(b,ptr); + if (id != _id) // sanity check + return false; + const unsigned int pathCount = (unsigned int)b[ptr++]; { Mutex::Lock _l(_paths_m); @@ -518,7 +522,6 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) const uint64_t lastOut = b.at(ptr); ptr += 8; const uint64_t lastIn = b.at(ptr); ptr += 8; const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; - const unsigned int distance = b.at(ptr); ptr += 2; InetAddress addr,localAddr; ptr += addr.deserialize(b,ptr); ptr += localAddr.deserialize(b,ptr); @@ -529,8 +532,9 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) case AF_INET6: p = &_v6Path; break; } if (p) { - if ( ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) && (p->p->distance() > distance) ) + if ( (!p->p) || ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) ) { p->p = RR->topology->getPath(localAddr,addr); + } p->lr = lr; p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); } @@ -538,22 +542,22 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) } } - _lastReceive = std::max(_lastReceive,b.at(ptr)); ptr += 8; - _lastNontrivialReceive = std::max(_lastNontrivialReceive,b.at(ptr)); ptr += 8; - _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,b.at(ptr)); ptr += 8; - _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,b.at(ptr)); ptr += 8; - _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,b.at(ptr)); ptr += 8; - _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,b.at(ptr)); ptr += 8; - _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,b.at(ptr)); ptr += 8; - _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,b.at(ptr)); ptr += 8; - _lastComRequestReceived = std::max(_lastComRequestReceived,b.at(ptr)); ptr += 8; - _lastComRequestSent = std::max(_lastComRequestSent,b.at(ptr)); ptr += 8; - _lastCredentialsReceived = std::max(_lastCredentialsReceived,b.at(ptr)); ptr += 8; - _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,b.at(ptr)); ptr += 8; - - _vProto = b.at(ptr); ptr += 2; - _vMajor = b.at(ptr); ptr += 2; - _vMinor = b.at(ptr); ptr += 2; + _lastReceive = std::max(_lastReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastNontrivialReceive = std::max(_lastNontrivialReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastComRequestReceived = std::max(_lastComRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastComRequestSent = std::max(_lastComRequestSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastCredentialsReceived = std::max(_lastCredentialsReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + + _vProto = (uint16_t)b[ptr++]; + _vMajor = (uint16_t)b[ptr++]; + _vMinor = (uint16_t)b[ptr++]; _vRevision = b.at(ptr); ptr += 2; _lastReceivedStateTimestamp = ts; @@ -563,4 +567,25 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) return false; } +SharedPtr Peer::createFromStateUpdate(const RuntimeEnvironment *renv,void *tPtr,const void *data,unsigned int len) +{ + try { + Identity id; + { + Buffer b(data,len); + unsigned int ptr = 0; + if (b[ptr++] != 1) + return SharedPtr(); + ptr += 8; // skip TS, don't care + id.deserialize(b,ptr); + } + if (id) { + const SharedPtr p(new Peer(renv,renv->identity,id)); + if (p->applyStateUpdate(data,len)) + return renv->topology->addPeer(tPtr,p); + } + } catch ( ... ) {} + return SharedPtr(); +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index d6b7dad9..f0eb3ee8 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -51,6 +51,8 @@ #include "Mutex.hpp" #include "NonCopyable.hpp" +#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) + namespace ZeroTier { /** @@ -194,9 +196,10 @@ public: bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); /** - * Write current peer state to external storage / cluster network + * Write object state to external storage and/or cluster network * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time */ void writeState(void *tPtr,const uint64_t now); @@ -437,6 +440,17 @@ public: return false; } + /** + * Create a peer from a remote state update + * + * @param renv Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param data State update data + * @param len State update length + * @return Peer or NULL if data was invalid + */ + static SharedPtr createFromStateUpdate(const RuntimeEnvironment *renv,void *tPtr,const void *data,unsigned int len); + private: struct _PeerPath { diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index d8e1d699..ee0c8c24 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -30,8 +30,8 @@ #include #include "Constants.hpp" +#include "Utils.hpp" #include "Identity.hpp" -#include "Mutex.hpp" namespace ZeroTier { @@ -58,10 +58,13 @@ public: ,mc((Multicaster *)0) ,topology((Topology *)0) ,sa((SelfAwareness *)0) -#ifdef ZT_ENABLE_CLUSTER - ,cluster((Cluster *)0) -#endif { + Utils::getSecureRandom(&instanceId,sizeof(instanceId)); + } + + ~RuntimeEnvironment() + { + Utils::burn(reinterpret_cast(const_cast(secretIdentityStr.data())),(unsigned int)secretIdentityStr.length()); } // Node instance that owns this RuntimeEnvironment @@ -87,9 +90,11 @@ public: Multicaster *mc; Topology *topology; SelfAwareness *sa; -#ifdef ZT_ENABLE_CLUSTER - Cluster *cluster; -#endif + + /** + * A random integer identifying this run of ZeroTier + */ + uint32_t instanceId; }; } // namespace ZeroTier diff --git a/node/Switch.cpp b/node/Switch.cpp index 2be54b37..cbd73a83 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -108,13 +108,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd const Address destination(fragment.destination()); if (destination != RR->identity.address()) { -#ifdef ZT_ENABLE_CLUSTER - const bool isClusterFrontplane = ((RR->cluster)&&(RR->cluster->isClusterPeerFrontplane(fromAddr))); -#else - const bool isClusterFrontplane = false; -#endif - - if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (!isClusterFrontplane) ) + if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) ) return; if (fragment.hops() < ZT_RELAY_MAX_HOPS) { @@ -124,13 +118,6 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(!isClusterFrontplane)) { - RR->cluster->relayViaCluster(Address(),destination,fragment.data(),fragment.size(),false); - return; - } -#endif - // Don't know peer or no direct path -- so relay via someone upstream relayTo = RR->topology->getUpstreamPeer(); if (relayTo) @@ -197,13 +184,8 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); -#ifdef ZT_ENABLE_CLUSTER - if ( (source == RR->identity.address()) && ((!RR->cluster)||(!RR->cluster->isClusterPeerFrontplane(fromAddr))) ) - return; -#else if (source == RR->identity.address()) return; -#endif if (destination != RR->identity.address()) { if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) @@ -212,12 +194,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd Packet packet(data,len); if (packet.hops() < ZT_RELAY_MAX_HOPS) { -#ifdef ZT_ENABLE_CLUSTER - if (source != RR->identity.address()) // don't increment hops for cluster frontplane relays - packet.incrementHops(); -#else packet.incrementHops(); -#endif SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { @@ -277,12 +254,6 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd } } } else { -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(source != RR->identity.address())) { - RR->cluster->relayViaCluster(source,destination,packet.data(),packet.size(),_shouldUnite(now,source,destination)); - return; - } -#endif relayTo = RR->topology->getUpstreamPeer(&source,1,true); if (relayTo) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); @@ -769,14 +740,6 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) const uint64_t now = RR->node->now(); const Address destination(packet.destination()); -#ifdef ZT_ENABLE_CLUSTER - uint64_t clusterMostRecentTs = 0; - int clusterMostRecentMemberId = -1; - uint8_t clusterPeerSecret[ZT_PEER_SECRET_KEY_LENGTH]; - if (RR->cluster) - clusterMostRecentMemberId = RR->cluster->checkSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); -#endif - const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); if (peer) { /* First get the best path, and if it's dead (and this is not a root) @@ -788,74 +751,37 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) viaPath = peer->getBestPath(now,false); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { -#ifdef ZT_ENABLE_CLUSTER - if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { -#endif - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); - viaPath->sent(now); - } -#ifdef ZT_ENABLE_CLUSTER + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { + peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); + viaPath->sent(now); } -#endif viaPath.zero(); } -#ifdef ZT_ENABLE_CLUSTER - if (clusterMostRecentMemberId >= 0) { - if ((viaPath)&&(viaPath->lastIn() < clusterMostRecentTs)) - viaPath.zero(); - } else if (!viaPath) { -#else if (!viaPath) { -#endif peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known const SharedPtr relay(RR->topology->getUpstreamPeer()); if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { if (!(viaPath = peer->getBestPath(now,true))) return false; } -#ifdef ZT_ENABLE_CLUSTER } -#else - } -#endif } else { -#ifdef ZT_ENABLE_CLUSTER - if (clusterMostRecentMemberId < 0) { -#else - requestWhois(tPtr,destination); - return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly -#endif -#ifdef ZT_ENABLE_CLUSTER - } -#endif + requestWhois(tPtr,destination); + return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); packet.setFragmented(chunkSize < packet.size()); -#ifdef ZT_ENABLE_CLUSTER - const uint64_t trustedPathId = (viaPath) ? RR->topology->getOutboundPathTrust(viaPath->address()) : 0; - if (trustedPathId) { - packet.setTrusted(trustedPathId); - } else { - packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt,(viaPath) ? viaPath->nextOutgoingCounter() : 0); - } -#else const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); if (trustedPathId) { packet.setTrusted(trustedPathId); } else { packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); } -#endif -#ifdef ZT_ENABLE_CLUSTER - if ( ((viaPath)&&(viaPath->send(RR,tPtr,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { -#else if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { -#endif if (chunkSize < packet.size()) { // Too big for one packet, fragment the rest unsigned int fragStart = chunkSize; @@ -868,14 +794,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) for(unsigned int fno=1;fnosend(RR,tPtr,frag.data(),frag.size(),now); - else if (clusterMostRecentMemberId >= 0) - RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,frag.data(),frag.size()); -#else viaPath->send(RR,tPtr,frag.data(),frag.size(),now); -#endif fragStart += chunkSize; remaining -= chunkSize; } diff --git a/node/Topology.cpp b/node/Topology.cpp index be116b28..09a1a895 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -108,8 +108,6 @@ SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) np = hp; } - saveIdentity(tPtr,np->identity()); - return np; } @@ -128,18 +126,20 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) } try { - Identity id(_getIdentity(tPtr,zta)); - if (id) { - SharedPtr np(new Peer(RR,RR->identity,id)); - { - Mutex::Lock _l(_peers_m); - SharedPtr &ap = _peers[zta]; - if (!ap) - ap.swap(np); + char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; + uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_STATE,idbuf,buf,(unsigned int)sizeof(buf)); + if (len > 0) { + Mutex::Lock _l(_peers_m); + SharedPtr &ap = _peers[zta]; + if (ap) return ap; - } + ap = Peer::createFromStateUpdate(RR,tPtr,buf,len); + if (!ap) + _peers.erase(zta); + return ap; } - } catch ( ... ) {} // invalid identity on disk? + } catch ( ... ) {} // ignore invalid identities or other strage failures return SharedPtr(); } @@ -154,17 +154,7 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) if (ap) return (*ap)->identity(); } - return _getIdentity(tPtr,zta); -} - -void Topology::saveIdentity(void *tPtr,const Identity &id) -{ - if (id) { - const std::string tmp(id.toString(false)); - uint64_t idtmp[2]; - idtmp[0] = id.address().toInt(); idtmp[1] = 0; - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp.data(),(unsigned int)tmp.length()); - } + return Identity(); } SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) @@ -423,21 +413,6 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now) } } -Identity Topology::_getIdentity(void *tPtr,const Address &zta) -{ - char tmp[512]; - uint64_t idtmp[2]; - idtmp[0] = zta.toInt(); idtmp[1] = 0; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp,sizeof(tmp) - 1); - if (n > 0) { - tmp[n] = (char)0; - try { - return Identity(tmp); - } catch ( ... ) {} // ignore invalid IDs - } - return Identity(); -} - void Topology::_memoizeUpstreams(void *tPtr) { // assumes _upstreams_m and _peers_m are locked @@ -450,10 +425,8 @@ void Topology::_memoizeUpstreams(void *tPtr) } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { _upstreamAddresses.push_back(i->identity.address()); SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { + if (!hp) hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(tPtr,i->identity); - } } } @@ -464,10 +437,8 @@ void Topology::_memoizeUpstreams(void *tPtr) } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { _upstreamAddresses.push_back(i->identity.address()); SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { + if (!hp) hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(tPtr,i->identity); - } } } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 9bc7c0d8..32e38dd3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -81,6 +81,13 @@ public: */ SharedPtr getPeer(void *tPtr,const Address &zta); + /** + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param zta ZeroTier address of peer + * @return Identity or NULL identity if not found + */ + Identity getIdentity(void *tPtr,const Address &zta); + /** * Get a peer only if it is presently in memory (no disk cache) * @@ -116,26 +123,6 @@ public: return p; } - /** - * Get the identity of a peer - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param zta ZeroTier address of peer - * @return Identity or NULL Identity if not found - */ - Identity getIdentity(void *tPtr,const Address &zta); - - /** - * Cache an identity - * - * This is done automatically on addPeer(), and so is only useful for - * cluster identity replication. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param id Identity to cache - */ - void saveIdentity(void *tPtr,const Identity &id); - /** * Get the current best upstream peer * diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index a0b47367..b1fe5921 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -180,7 +180,7 @@ public: const unsigned long pid = (unsigned long)getpid(); // Get all device names - Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid); + Utils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid); FILE *procf = fopen(fn,"r"); if (procf) { while (fgets(tmp,sizeof(tmp),procf)) { @@ -196,7 +196,7 @@ public: } // Get IPv6 addresses (and any device names we don't already know) - Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); + Utils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); procf = fopen(fn,"r"); if (procf) { while (fgets(tmp,sizeof(tmp),procf)) { diff --git a/service/OneService.cpp b/service/OneService.cpp index f949f348..b5b11111 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -154,9 +154,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } // How often to check for local interface addresses #define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 -// Clean files from iddb.d that are older than this (60 days) -#define ZT_IDDB_CLEANUP_AGE 5184000000ULL - // Maximum write buffer size for outgoing TCP connections (sanity limit) #define ZT_TCP_MAX_WRITEQ_SIZE 33554432 @@ -414,7 +411,6 @@ public: const std::string _homePath; std::string _authToken; std::string _controllerDbPath; - const std::string _iddbPath; const std::string _networksPath; const std::string _moonsPath; @@ -513,7 +509,6 @@ public: OneServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : ".") ,_controllerDbPath(_homePath + ZT_PATH_SEPARATOR_S "controller.d") - ,_iddbPath(_homePath + ZT_PATH_SEPARATOR_S "iddb.d") ,_networksPath(_homePath + ZT_PATH_SEPARATOR_S "networks.d") ,_moonsPath(_homePath + ZT_PATH_SEPARATOR_S "moons.d") ,_controller((EmbeddedNetworkController *)0) @@ -732,6 +727,9 @@ public: } #endif + // Delete legacy iddb.d if present (cleanup) + OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str()); + // Network controller is now enabled by default for desktop and server _controller = new EmbeddedNetworkController(_node,_controllerDbPath.c_str()); _node->setNetconfMaster((void *)_controller); @@ -781,7 +779,6 @@ public: uint64_t lastBindRefresh = 0; uint64_t lastUpdateCheck = clockShouldBe; uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle - uint64_t lastCleanedIddb = 0; uint64_t lastTcpCheck = 0; for(;;) { _run_m.lock(); @@ -797,12 +794,6 @@ public: const uint64_t now = OSUtils::now(); - // Clean iddb.d on start and every 24 hours - if ((now - lastCleanedIddb) > 86400000) { - lastCleanedIddb = now; - OSUtils::cleanDirectory(_iddbPath.c_str(),now - ZT_IDDB_CLEANUP_AGE); - } - // Attempt to detect sleep/wake events by detecting delay overruns bool restarted = false; if ((now > clockShouldBe)&&((now - clockShouldBe) > 10000)) { @@ -1027,7 +1018,7 @@ public: return NULL; } - virtual Node * getNode() + virtual Node *getNode() { return _node; } @@ -1903,27 +1894,16 @@ public: char *const outdata = const_cast(tc->writeq.data()) + startpos; encryptClusterMessage(outdata,mlen); - } - - void replicateStateObjectToCluster(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,const uint64_t everyoneBut) - { - std::vector sentTo; - if (everyoneBut) - sentTo.push_back(everyoneBut); - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) { - TcpConnection *const c = *ci; - if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) { - sentTo.push_back(c->clusterMemberId); - replicateStateObject(type,id,data,len,c); - } - } + tc->writeq.append(outdata,mlen); } void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { - char p[4096]; + char buf[65535]; + char p[1024]; + FILE *f; bool secure = false; + switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); @@ -1932,13 +1912,14 @@ public: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); secure = true; break; - case ZT_STATE_OBJECT_PEER_IDENTITY: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id[0]); - break; + //case ZT_STATE_OBJECT_PEER_STATE: + // break; case ZT_STATE_OBJECT_NETWORK_CONFIG: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); secure = true; break; + //case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: + // break; case ZT_STATE_OBJECT_PLANET: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; @@ -1949,17 +1930,30 @@ public: p[0] = (char)0; break; } + if (p[0]) { if (len >= 0) { - FILE *f = fopen(p,"w"); + // Check to see if we've already written this first. This reduces + // redundant writes and I/O overhead on most platforms and has + // little effect on others. + f = fopen(p,"r"); + bool redundant = false; if (f) { - if (fwrite(data,len,1,f) != 1) - fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + long l = (long)fread(buf,1,sizeof(buf),f); fclose(f); - if (secure) - OSUtils::lockDownFile(p,false); - } else { - fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + redundant = ((l == (long)len)&&(memcmp(data,buf,l) == 0)); + } + if (!redundant) { + f = fopen(p,"w"); + if (f) { + if (fwrite(data,len,1,f) != 1) + fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + fclose(f); + if (secure) + OSUtils::lockDownFile(p,false); + } else { + fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + } } } else { OSUtils::rm(p); @@ -2314,7 +2308,7 @@ public: break; case CLUSTER_MESSAGE_STATE_OBJECT: - if (mlen >= 42) { // type + object ID + [data] + if (mlen > 42) { // type + object ID + [data] uint64_t objId[2]; objId[0] = ( ((uint64_t)data[26] << 56) | @@ -2336,10 +2330,8 @@ public: ((uint64_t)data[40] << 8) | (uint64_t)data[41] ); - if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId[0],data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) { + if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)); - replicateStateObjectToCluster((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42),tc->clusterMemberId); - } } break; @@ -2558,7 +2550,18 @@ public: inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { writeStateObject(type,id,data,len); - replicateStateObjectToCluster(type,id,data,len,0); + + std::vector sentTo; + { + Mutex::Lock _l(_tcpConnections_m); + for(std::vector::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) { + TcpConnection *const c = *ci; + if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) { + sentTo.push_back(c->clusterMemberId); + replicateStateObject(type,id,data,len,c); + } + } + } } inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) @@ -2571,9 +2574,6 @@ public: case ZT_STATE_OBJECT_IDENTITY_SECRET: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); break; - case ZT_STATE_OBJECT_PEER_IDENTITY: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id); - break; case ZT_STATE_OBJECT_NETWORK_CONFIG: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); break; -- cgit v1.2.3 From f18158a52d28c14352018a68d328f41fcdb7966f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 11:45:22 -0700 Subject: . --- include/ZeroTierOne.h | 135 ++-------- node/IncomingPacket.cpp | 14 +- node/Node.cpp | 130 +--------- node/Node.hpp | 14 +- node/Path.cpp | 2 +- node/Path.hpp | 51 ++-- node/Peer.cpp | 59 ++--- node/Peer.hpp | 12 +- node/RuntimeEnvironment.hpp | 10 +- node/SelfAwareness.cpp | 4 +- node/SelfAwareness.hpp | 10 +- node/Switch.cpp | 8 +- node/Switch.hpp | 4 +- node/Topology.cpp | 4 +- node/Topology.hpp | 4 +- osdep/Binder.hpp | 109 ++------ service/OneService.cpp | 609 +++++--------------------------------------- 17 files changed, 198 insertions(+), 981 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 133ae340..180e5cd2 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -229,11 +229,6 @@ extern "C" { */ #define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL -/** - * A null/empty sockaddr (all zero) to signify an unspecified socket address - */ -extern const struct sockaddr_storage ZT_SOCKADDR_NULL; - /****************************************************************************/ /* Structures and other types */ /****************************************************************************/ @@ -1067,21 +1062,6 @@ typedef struct /** * ZeroTier core state objects - * - * All of these objects can be persisted if desired. To preserve the - * identity of a node and its address, the identity (public and secret) - * must be saved at a minimum. - * - * State objects actually have two IDs (uint64_t[2]). If only one is - * listed the second ([1]) should be zero and is ignored in storage - * and replication. - * - * All state objects should be replicated in cluster mode. The reference - * clustering implementation uses a rumor mill algorithm in which state - * updates that are accepted with RESULT_OK (but not RESULT_OK_IGNORED) - * are flooded to all connected cluster peers. This results in updates - * being flooded across the cluster until all cluster members have the - * latest. */ enum ZT_StateObjectType { @@ -1108,36 +1088,6 @@ enum ZT_StateObjectType */ ZT_STATE_OBJECT_IDENTITY_SECRET = 2, - /** - * A peer to which this node is communicating - * - * Object ID: peer address - * Canonical path: /peers.d/
(10-digit hex address) - * Persistence: optional, can be purged at any time - */ - ZT_STATE_OBJECT_PEER_STATE = 3, - - /** - * Network configuration - * - * Object ID: peer address - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist - */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 4, - - /** - * Network membership (network X peer intersection) - * - * If these are persisted they must be restored after peer states and - * network configs. Otherwise they are ignored. - * - * Object ID: [0] network ID, [1] peer address - * Canonical path: /networks.d//members.d/
- * Persistence: optional (not usually needed) - */ - ZT_STATE_OBJECT_NETWORK_MEMBERSHIP = 5, - /** * The planet (there is only one per... well... planet!) * @@ -1145,7 +1095,7 @@ enum ZT_StateObjectType * Canonical path: /planet * Persistence: recommended */ - ZT_STATE_OBJECT_PLANET = 6, + ZT_STATE_OBJECT_PLANET = 3, /** * A moon (federated root set) @@ -1154,12 +1104,25 @@ enum ZT_StateObjectType * Canonical path: /moons.d/.moon (16-digit hex ID) * Persistence: required if moon memberships should persist */ - ZT_STATE_OBJECT_MOON = 7, + ZT_STATE_OBJECT_MOON = 4, /** - * IDs above this value will not be used by the core (and could be used as implementation-specific IDs) + * Peer and related state + * + * Object ID: peer address + * Canonical path: /peers.d/ (10-digit address + * Persistence: optional, can be cleared at any time + */ + ZT_STATE_OBJECT_PEER = 5, + + /** + * Network configuration + * + * Object ID: peer address + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist */ - ZT_STATE_OBJECT__MAX_ID = 255 + ZT_STATE_OBJECT_NETWORK_CONFIG = 6 }; /** @@ -1277,17 +1240,15 @@ typedef int (*ZT_StateGetFunction)( * Parameters: * (1) Node * (2) User pointer - * (3) Local interface address + * (3) Local socket or -1 for "all" or "any" * (4) Remote address * (5) Packet data * (6) Packet length * (7) Desired IP TTL or 0 to use default * - * If there is only one local interface it is safe to ignore the local - * interface address. Otherwise if running with multiple interfaces, the - * correct local interface should be chosen by address unless NULL. If - * the ss_family field is zero (NULL address), a random or preferred - * default interface should be used. + * If there is only one local socket, the local socket can be ignored. + * If the local socket is -1, the packet should be sent out from all + * bound local sockets or a random bound local socket. * * If TTL is nonzero, packets should have their IP TTL value set to this * value if possible. If this is not possible it is acceptable to ignore @@ -1301,7 +1262,7 @@ typedef int (*ZT_WirePacketSendFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ void *, /* Thread ptr */ - const struct sockaddr_storage *, /* Local address */ + int64_t, /* Local socket */ const struct sockaddr_storage *, /* Remote address */ const void *, /* Packet data */ unsigned int, /* Packet length */ @@ -1314,7 +1275,7 @@ typedef int (*ZT_WirePacketSendFunction)( * (1) Node * (2) User pointer * (3) ZeroTier address or 0 for none/any - * (4) Local interface address + * (4) Local socket or -1 if unknown * (5) Remote address * * This function must return nonzero (true) if the path should be used. @@ -1333,7 +1294,7 @@ typedef int (*ZT_PathCheckFunction)( void *, /* User ptr */ void *, /* Thread ptr */ uint64_t, /* ZeroTier address */ - const struct sockaddr_storage *, /* Local address */ + int64_t, /* Local socket or -1 if unknown */ const struct sockaddr_storage *); /* Remote address */ /** @@ -1441,57 +1402,13 @@ enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct */ void ZT_Node_delete(ZT_Node *node); -/** - * Notify node of an update to a state object - * - * This can be called after node startup to restore cached state objects such - * as network configurations for joined networks, planet, moons, etc. See - * the documentation of ZT_StateObjectType for more information. It's okay - * to call this for everything in the object store, but note that the node - * will automatically query for some core objects like identities so supplying - * these via this function is not necessary. - * - * Unless clustering is being implemented this function doesn't need to be - * used after startup. It could be called in response to filesystem changes - * to allow some degree of live configurability by filesystem observation - * but this kind of thing is entirely optional. - * - * The return value of this function indicates whether the update was accepted - * as new. A return value of ZT_RESULT_OK indicates that the node gleaned new - * information from this update and that therefore (in cluster rumor mill mode) - * this update should be distributed to other members of a cluster. A return - * value of ZT_RESULT_OK_IGNORED indicates that the object did not provide any - * new information and therefore should not be propagated in a cluster. - * - * If clustering isn't being implemented the return value of this function can - * generally be ignored. - * - * ZT_RESULT_ERROR_BAD_PARAMETER can be returned if the parameter was invalid - * or not applicable. Object stores may delete the object in this case. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param type State object type - * @param id State object ID (if object type has only one ID, second should be zero) - * @param data State object data - * @param len Length of state object data in bytes - * @return ZT_RESULT_OK if object was accepted or ZT_RESULT_OK_IGNORED if non-informative, error if object was invalid - */ -enum ZT_ResultCode ZT_Node_processStateUpdate( - ZT_Node *node, - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len); - /** * Process a packet received from the physical wire * * @param node Node instance * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds - * @param localAddress Local address, or point to ZT_SOCKADDR_NULL if unspecified + * @param localSocket Local socket (you can use 0 if only one local socket is bound and ignore this) * @param remoteAddress Origin of packet * @param packetData Packet data * @param packetLength Packet length @@ -1502,7 +1419,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0548387b..f0be96f9 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -309,7 +309,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool if (ptr < size()) { ptr += externalSurfaceAddress.deserialize(*this,ptr); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); } // Get primary planet world ID and world timestamp if present @@ -495,7 +495,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: @@ -613,9 +613,9 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localAddress(),atAddr)) { - RR->node->putPacket(tPtr,_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localAddress(),atAddr,RR->node->now(),false,0); + if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { + RR->node->putPacket(tPtr,_path->localSocket(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1197,7 +1197,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) // peer->setClusterPreferred(a); @@ -1214,7 +1214,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) // peer->setClusterPreferred(a); diff --git a/node/Node.cpp b/node/Node.cpp index 4ffe496c..4b598f61 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -47,8 +47,6 @@ #include "SelfAwareness.hpp" #include "Network.hpp" -const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; - namespace ZeroTier { /****************************************************************************/ @@ -137,114 +135,17 @@ Node::~Node() delete RR->sw; } -ZT_ResultCode Node::processStateUpdate( - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len) -{ - ZT_ResultCode r = ZT_RESULT_OK_IGNORED; - switch(type) { - - case ZT_STATE_OBJECT_PEER_STATE: - if (len) { - const SharedPtr p(RR->topology->getPeer(tptr,Address(id[0]))); - if (p) { - r = (p->applyStateUpdate(data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; - } else { - r = (Peer::createFromStateUpdate(RR,tptr,data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; - } - } - break; - - case ZT_STATE_OBJECT_NETWORK_CONFIG: - if (len <= (ZT_NETWORKCONFIG_DICT_CAPACITY - 1)) { - if (len < 2) { - Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id[0]]; - if (!nw) { - nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,(const NetworkConfig *)0)); - r = ZT_RESULT_OK; - } - } else { - Dictionary *dict = new Dictionary(reinterpret_cast(data),len); - try { - NetworkConfig *nconf = new NetworkConfig(); - try { - if (nconf->fromDictionary(*dict)) { - Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id[0]]; - if (nw) { - switch (nw->setConfiguration(tptr,*nconf,false)) { - default: - r = ZT_RESULT_ERROR_BAD_PARAMETER; - break; - case 1: - r = ZT_RESULT_OK_IGNORED; - break; - case 2: - r = ZT_RESULT_OK; - break; - } - } else { - nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,nconf)); - } - } else { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - } catch ( ... ) { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - delete nconf; - } catch ( ... ) { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - delete dict; - } - } else { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - break; - - case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: - if (len) { - } - break; - - case ZT_STATE_OBJECT_PLANET: - case ZT_STATE_OBJECT_MOON: - if ((len)&&(len <= ZT_WORLD_MAX_SERIALIZED_LENGTH)) { - World w; - try { - w.deserialize(Buffer(data,len)); - if (( (w.type() == World::TYPE_MOON)&&(type == ZT_STATE_OBJECT_MOON) )||( (w.type() == World::TYPE_PLANET)&&(type == ZT_STATE_OBJECT_PLANET) )) { - r = (RR->topology->addWorld(tptr,w,false)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; - } - } catch ( ... ) { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - } else { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - break; - - default: break; - } - return r; -} - ZT_ResultCode Node::processWirePacket( void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, volatile uint64_t *nextBackgroundTaskDeadline) { _now = now; - RR->sw->onRemotePacket(tptr,*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); + RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast(remoteAddress)),packetData,packetLength); return ZT_RESULT_OK; } @@ -317,7 +218,7 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(_tPtr,up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); + p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now,up->nextOutgoingCounter()); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); @@ -617,7 +518,7 @@ void Node::setNetconfMaster(void *networkControllerInstance) /* Node methods used only within node/ */ /****************************************************************************/ -bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress) { if (!Path::isAddressValidForPath(remoteAddress)) return false; @@ -640,7 +541,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons } } - return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); + return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),localSocket,reinterpret_cast(&remoteAddress)) != 0) : true); } #ifdef ZT_TRACE @@ -837,35 +738,18 @@ void ZT_Node_delete(ZT_Node *node) } catch ( ... ) {} } -enum ZT_ResultCode ZT_Node_processStateUpdate( - ZT_Node *node, - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len) -{ - try { - return reinterpret_cast(node)->processStateUpdate(tptr,type,id,data,len); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processWirePacket(tptr,now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { diff --git a/node/Node.hpp b/node/Node.hpp index 17050d24..55491b06 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -82,16 +82,10 @@ public: // Public API Functions ---------------------------------------------------- - ZT_ResultCode processStateUpdate( - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len); ZT_ResultCode processWirePacket( void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, @@ -129,13 +123,13 @@ public: inline uint64_t now() const throw() { return _now; } - inline bool putPacket(void *tPtr,const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) + inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { return (_cb.wirePacketSendFunction( reinterpret_cast(this), _uPtr, tPtr, - reinterpret_cast(&localAddress), + localSocket, reinterpret_cast(&addr), data, len, @@ -205,7 +199,7 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif - bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); + bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress); inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); diff --git a/node/Path.cpp b/node/Path.cpp index a5fe1aa7..9dc9aba5 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -32,7 +32,7 @@ namespace ZeroTier { bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) { - if (RR->node->putPacket(tPtr,_localAddress,address(),data,len)) { + if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { _lastOut = now; return true; } diff --git a/node/Path.hpp b/node/Path.hpp index a6f56d31..854b28e2 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -66,49 +66,28 @@ public: public: HashKey() {} - HashKey(const InetAddress &l,const InetAddress &r) + HashKey(const int64_t l,const InetAddress &r) { - // This is an ad-hoc bit packing algorithm to yield unique keys for - // remote addresses and their local-side counterparts if defined. - // Portability across runtimes is not needed. if (r.ss_family == AF_INET) { _k[0] = (uint64_t)reinterpret_cast(&r)->sin_addr.s_addr; _k[1] = (uint64_t)reinterpret_cast(&r)->sin_port; - if (l.ss_family == AF_INET) { - _k[2] = (uint64_t)reinterpret_cast(&l)->sin_addr.s_addr; - _k[3] = (uint64_t)reinterpret_cast(&r)->sin_port; - } else { - _k[2] = 0; - _k[3] = 0; - } + _k[2] = (uint64_t)l; } else if (r.ss_family == AF_INET6) { - const uint8_t *a = reinterpret_cast(reinterpret_cast(&r)->sin6_addr.s6_addr); - uint8_t *b = reinterpret_cast(_k); - for(unsigned int i=0;i<16;++i) b[i] = a[i]; - _k[2] = ~((uint64_t)reinterpret_cast(&r)->sin6_port); - if (l.ss_family == AF_INET6) { - _k[2] ^= ((uint64_t)reinterpret_cast(&r)->sin6_port) << 32; - a = reinterpret_cast(reinterpret_cast(&l)->sin6_addr.s6_addr); - b += 24; - for(unsigned int i=0;i<8;++i) b[i] = a[i]; - a += 8; - for(unsigned int i=0;i<8;++i) b[i] ^= a[i]; - } + memcpy(_k,reinterpret_cast(&r)->sin6_addr.s6_addr,16); + _k[2] = ((uint64_t)reinterpret_cast(&r)->sin6_port << 32) ^ (uint64_t)l; } else { - _k[0] = 0; - _k[1] = 0; - _k[2] = 0; - _k[3] = 0; + memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress))); + _k[2] += (uint64_t)l; } } - inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2] + _k[3]); } + inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); } - inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) && (_k[3] == k._k[3]) ); } + inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); } inline bool operator!=(const HashKey &k) const { return (!(*this == k)); } private: - uint64_t _k[4]; + uint64_t _k[3]; }; Path() : @@ -116,29 +95,29 @@ public: _lastIn(0), _lastTrustEstablishedPacketReceived(0), _incomingLinkQualityFastLog(0xffffffffffffffffULL), + _localSocket(-1), _incomingLinkQualitySlowLogPtr(0), _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), _addr(), - _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) { for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } - Path(const InetAddress &localAddress,const InetAddress &addr) : + Path(const int64_t localSocket,const InetAddress &addr) : _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), _incomingLinkQualityFastLog(0xffffffffffffffffULL), + _localSocket(localSocket), _incomingLinkQualitySlowLogPtr(0), _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), _addr(addr), - _localAddress(localAddress), _ipScope(addr.ipScope()) { for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) @@ -210,9 +189,9 @@ public: inline void sent(const uint64_t t) { _lastOut = t; } /** - * @return Address of local side of this path or NULL if unspecified + * @return Local socket as specified by external code */ - inline const InetAddress &localAddress() const { return _localAddress; } + inline const int64_t localSocket() const { return _localSocket; } /** * @return Physical address @@ -328,12 +307,12 @@ private: volatile uint64_t _lastIn; volatile uint64_t _lastTrustEstablishedPacketReceived; volatile uint64_t _incomingLinkQualityFastLog; + int64_t _localSocket; volatile unsigned long _incomingLinkQualitySlowLogPtr; volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; InetAddress _addr; - InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often volatile uint8_t _incomingLinkQualitySlowLog[32]; AtomicCounter __refCount; diff --git a/node/Peer.cpp b/node/Peer.cpp index 18d05875..875d651e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -154,25 +154,21 @@ void Peer::received( if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { const struct sockaddr_in *const r = reinterpret_cast(&(path->address())); const struct sockaddr_in *const l = reinterpret_cast(&(_v4Path.p->address())); - const struct sockaddr_in *const rl = reinterpret_cast(&(path->localAddress())); - const struct sockaddr_in *const ll = reinterpret_cast(&(_v4Path.p->localAddress())); - if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { + if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(path->localSocket() == _v4Path.p->localSocket())) { _v4Path.lr = now; pathAlreadyKnown = true; } } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { const struct sockaddr_in6 *const r = reinterpret_cast(&(path->address())); const struct sockaddr_in6 *const l = reinterpret_cast(&(_v6Path.p->address())); - const struct sockaddr_in6 *const rl = reinterpret_cast(&(path->localAddress())); - const struct sockaddr_in6 *const ll = reinterpret_cast(&(_v6Path.p->localAddress())); - if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { + if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(path->localSocket() == _v6Path.p->localSocket())) { _v6Path.lr = now; pathAlreadyKnown = true; } } } - if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) { Mutex::Lock _l(_paths_m); _PeerPath *potentialNewPeerPath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { @@ -191,7 +187,7 @@ void Peer::received( _lastWroteState = 0; // force state write now } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } } @@ -318,7 +314,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) return SharedPtr(); } -void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -360,21 +356,21 @@ void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress & if (atAddress) { outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC - RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true,counter); - RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { - sendHELLO(tPtr,localAddr,atAddress,now,counter); + sendHELLO(tPtr,localSocket,atAddress,now,counter); } } @@ -402,13 +398,13 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) if (v6lr > v4lr) { if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); _v6Path.p->sent(now); return true; } } else if (v4lr) { if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); _v4Path.p->sent(now); return true; } @@ -416,13 +412,13 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) } else { if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); _v4Path.p->sent(now); return true; } } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); _v6Path.p->sent(now); return true; } @@ -456,7 +452,6 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v4Path.p->lastIn()); b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); _v4Path.p->address().serialize(b); - _v4Path.p->localAddress().serialize(b); } if (_v6Path.lr) { b.append(_v6Path.lr); @@ -464,7 +459,6 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v6Path.p->lastIn()); b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); _v6Path.p->address().serialize(b); - _v6Path.p->localAddress().serialize(b); } } @@ -491,7 +485,7 @@ void Peer::writeState(void *tPtr,const uint64_t now) uint64_t tmp[2]; tmp[0] = _id.address().toInt(); tmp[1] = 0; - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); + //RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); _lastWroteState = now; } catch ( ... ) {} // sanity check, should not be possible @@ -522,22 +516,19 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) const uint64_t lastOut = b.at(ptr); ptr += 8; const uint64_t lastIn = b.at(ptr); ptr += 8; const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; - InetAddress addr,localAddr; + InetAddress addr; ptr += addr.deserialize(b,ptr); - ptr += localAddr.deserialize(b,ptr); - if (addr.ss_family == localAddr.ss_family) { - _PeerPath *p = (_PeerPath *)0; - switch(addr.ss_family) { - case AF_INET: p = &_v4Path; break; - case AF_INET6: p = &_v6Path; break; - } - if (p) { - if ( (!p->p) || ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) ) { - p->p = RR->topology->getPath(localAddr,addr); - } - p->lr = lr; - p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); + _PeerPath *p = (_PeerPath *)0; + switch(addr.ss_family) { + case AF_INET: p = &_v4Path; break; + case AF_INET6: p = &_v6Path; break; + } + if (p) { + if ( (!p->p) || (p->p->address() != addr) ) { + p->p = RR->topology->getPath(-1,addr); } + p->lr = lr; + p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); } } } diff --git a/node/Peer.hpp b/node/Peer.hpp index f0eb3ee8..478c7232 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -154,12 +154,12 @@ public: * No statistics or sent times are updated here. * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local address + * @param localSocket Local source socket * @param atAddress Destination address * @param now Current time * @param counter Outgoing packet counter */ - void sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -167,13 +167,13 @@ public: * No statistics or sent times are updated here. * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local address + * @param localSocket Local source socket * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param counter Outgoing packet counter */ - void attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known @@ -227,11 +227,11 @@ public: { Mutex::Lock _l(_paths_m); if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); _v4Path.p->sent(now); _v4Path.lr = 0; // path will not be used unless it speaks again } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); _v6Path.p->sent(now); _v6Path.lr = 0; // path will not be used unless it speaks again } diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index ee0c8c24..99afe25d 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -67,6 +67,11 @@ public: Utils::burn(reinterpret_cast(const_cast(secretIdentityStr.data())),(unsigned int)secretIdentityStr.length()); } + /** + * A random integer identifying this running instance in a cluster + */ + uint64_t instanceId; + // Node instance that owns this RuntimeEnvironment Node *const node; @@ -90,11 +95,6 @@ public: Multicaster *mc; Topology *topology; SelfAwareness *sa; - - /** - * A random integer identifying this run of ZeroTier - */ - uint32_t instanceId; }; } // namespace ZeroTier diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index c5daddc3..3e3397f5 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -69,7 +69,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) +void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -77,7 +77,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &re return; Mutex::Lock _l(_phy_m); - PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalAddress,reporterPhysicalAddress,scope)]; + PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)]; if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 63c416bf..35e0ad39 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -55,7 +55,7 @@ public: * @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param now Current time */ - void iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); + void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); /** * Clean up database periodically @@ -75,15 +75,15 @@ private: struct PhySurfaceKey { Address reporter; - InetAddress receivedOnLocalAddress; + int64_t receivedOnLocalSocket; InetAddress reporterPhysicalAddress; InetAddress::IpScope scope; PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {} - PhySurfaceKey(const Address &r,const InetAddress &rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalAddress(rol),reporterPhysicalAddress(ra),scope(s) {} + PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {} - inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); } - inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(receivedOnLocalAddress == k.receivedOnLocalAddress)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } + inline unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)scope); } + inline bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } }; struct PhySurfaceEntry { diff --git a/node/Switch.cpp b/node/Switch.cpp index cbd73a83..a77ca89e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -71,12 +71,12 @@ Switch::Switch(const RuntimeEnvironment *renv) : { } -void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) +void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len) { try { const uint64_t now = RR->node->now(); - SharedPtr path(RR->topology->getPath(localAddr,fromAddr)); + SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); if (len == 13) { @@ -88,7 +88,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd const Address beaconAddr(reinterpret_cast(data) + 8,5); if (beaconAddr == RR->identity.address()) return; - if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localAddr,fromAddr)) + if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr)) return; const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr)); if (peer) { // we'll only respond to beacons from known peers @@ -752,7 +752,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) viaPath = peer->getBestPath(now,false); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); + peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } viaPath.zero(); diff --git a/node/Switch.hpp b/node/Switch.hpp index 9793dd45..cebe9e67 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -68,12 +68,12 @@ public: * Called when a packet is received from the real network * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local interface address + * @param localSocket Local I/O socket as supplied by external code * @param fromAddr Internet IP address of origin * @param data Packet data * @param len Packet length */ - void onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); + void onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len); /** * Called when a packet comes from a local Ethernet tap diff --git a/node/Topology.cpp b/node/Topology.cpp index 09a1a895..d4632f43 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -125,10 +125,11 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return *ap; } + /* try { char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; - int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_STATE,idbuf,buf,(unsigned int)sizeof(buf)); + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf)); if (len > 0) { Mutex::Lock _l(_peers_m); SharedPtr &ap = _peers[zta]; @@ -140,6 +141,7 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return ap; } } catch ( ... ) {} // ignore invalid identities or other strage failures + */ return SharedPtr(); } diff --git a/node/Topology.hpp b/node/Topology.hpp index 32e38dd3..5f3e2da1 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -110,11 +110,11 @@ public: /** * Get a Path object for a given local and remote physical address, creating if needed * - * @param l Local address or NULL for 'any' or 'wildcard' + * @param l Local socket * @param r Remote address * @return Pointer to canonicalized Path object */ - inline SharedPtr getPath(const InetAddress &l,const InetAddress &r) + inline SharedPtr getPath(const int64_t l,const InetAddress &r) { Mutex::Lock _l(_paths_m); SharedPtr &p = _paths[Path::HashKey(l,r)]; diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index b1fe5921..040f3e46 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -88,11 +88,7 @@ class Binder : NonCopyable private: struct _Binding { - _Binding() : - udpSock((PhySocket *)0), - tcpListenSock((PhySocket *)0), - address() {} - + _Binding() : udpSock((PhySocket *)0),tcpListenSock((PhySocket *)0) {} PhySocket *udpSock; PhySocket *tcpListenSock; InetAddress address; @@ -373,93 +369,6 @@ public: _bindings.swap(newBindings); } - /** - * Send a UDP packet from the specified local interface, or all - * - * Unfortunately even by examining the routing table there is no ultimately - * robust way to tell where we might reach another host that works in all - * environments. As a result, we send packets with null (wildcard) local - * addresses from *every* bound interface. - * - * These are typically initial HELLOs, path probes, etc., since normal - * conversations will have a local endpoint address. So the cost is low and - * if the peer is not reachable via that route then the packet will go - * nowhere and nothing will happen. - * - * It will of course only send via interface bindings of the same socket - * family. No point in sending V4 via V6 or vice versa. - * - * In any case on most hosts there's only one or two interfaces that we - * will use, so none of this is particularly costly. - * - * @param local Local interface address or null address for 'all' - * @param remote Remote address - * @param data Data to send - * @param len Length of data - * @param v4ttl If non-zero, send this packet with the specified IP TTL (IPv4 only) - * @return -1 == local doesn't match any bound address, 0 == send failure, 1 == send successful - */ - template - inline int udpSend(Phy &phy,const InetAddress &local,const InetAddress &remote,const void *data,unsigned int len,unsigned int v4ttl = 0) const - { - PhySocket *s; - typename std::vector<_Binding>::const_iterator i; - int result; - Mutex::Lock _l(_lock); - - if (remote.ss_family == AF_INET) { - if (local) { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if ( - (i->address.ss_family == AF_INET) && - (reinterpret_cast(&(i->address))->sin_port == reinterpret_cast(&local)->sin_port) && - (reinterpret_cast(&(i->address))->sin_addr.s_addr == reinterpret_cast(&local)->sin_addr.s_addr) - ) - { - s = i->udpSock; - goto Binder_send_packet; - } - } - } else { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if (i->address.ss_family == AF_INET) { - s = i->udpSock; - goto Binder_send_packet; - } - } - } - } else { - if (local) { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if ( - (i->address.ss_family == AF_INET6) && - (reinterpret_cast(&(i->address))->sin6_port == reinterpret_cast(&local)->sin6_port) && - (!memcmp(reinterpret_cast(&(i->address))->sin6_addr.s6_addr,reinterpret_cast(&local)->sin6_addr.s6_addr,16)) - ) - { - s = i->udpSock; - goto Binder_send_packet; - } - } - } else { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if (i->address.ss_family == AF_INET6) { - s = i->udpSock; - goto Binder_send_packet; - } - } - } - } - - return -1; - -Binder_send_packet: - if (v4ttl) phy.setIp4UdpTtl(s,v4ttl); - result = (int)phy.udpSend(s,reinterpret_cast(&remote),data,len); - if (v4ttl) phy.setIp4UdpTtl(s,255); - return result; - } - /** * @return All currently bound local interface addresses */ @@ -472,6 +381,22 @@ Binder_send_packet: return aa; } + /** + * Send from all bound UDP sockets + */ + template + inline bool udpSendAll(Phy &phy,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) + { + bool r = false; + Mutex::Lock _l(_lock); + for(std::vector<_Binding>::const_iterator b(_bindings.begin());b!=_bindings.end();++b) { + if (ttl) phy.setIp4UdpTtl(b->udpSock,ttl); + if (phy.udpSend(b->udpSock,(const struct sockaddr *)addr,data,len)) r = true; + if (ttl) phy.setIp4UdpTtl(b->udpSock,255); + } + return r; + } + /** * @param addr Address to check * @return True if this is a bound local interface address diff --git a/service/OneService.cpp b/service/OneService.cpp index b5b11111..6497ae20 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -59,8 +59,6 @@ #include "../osdep/ManagedRoute.hpp" #include "OneService.hpp" -#include "ClusterGeoIpService.hpp" -#include "ClusterDefinition.hpp" #include "SoftwareUpdater.hpp" #ifdef __WINDOWS__ @@ -157,9 +155,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } // Maximum write buffer size for outgoing TCP connections (sanity limit) #define ZT_TCP_MAX_WRITEQ_SIZE 33554432 -// How often to check TCP connections and cluster links and send status to cluster peers -#define ZT_TCP_CHECK_PERIOD 15000 - // TCP activity timeout #define ZT_TCP_ACTIVITY_TIMEOUT 60000 @@ -311,9 +306,9 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len); static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen); -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr); static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); @@ -362,8 +357,7 @@ struct TcpConnection TCP_UNCATEGORIZED_INCOMING, // uncategorized incoming connection TCP_HTTP_INCOMING, TCP_HTTP_OUTGOING, - TCP_TUNNEL_OUTGOING, // TUNNELED mode proxy outbound connection - TCP_CLUSTER_BACKPLANE + TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection } type; OneServiceImpl *parent; @@ -380,29 +374,11 @@ struct TcpConnection std::string status; std::map< std::string,std::string > headers; - // Used for cluster backplane connections - uint64_t clusterMemberId; - unsigned int clusterMemberVersionMajor; - unsigned int clusterMemberVersionMinor; - unsigned int clusterMemberVersionRev; - std::vector< InetAddress > clusterMemberLocalAddresses; - Mutex clusterMemberLocalAddresses_m; - std::string readq; std::string writeq; Mutex writeq_m; }; -/** - * Message types for cluster backplane communication - */ -enum ClusterMessageType -{ - CLUSTER_MESSAGE_STATUS = 0, - CLUSTER_MESSAGE_STATE_OBJECT = 1, - CLUSTER_MESSAGE_PROXY_SEND = 2 -}; - class OneServiceImpl : public OneService { public: @@ -421,8 +397,6 @@ public: bool _updateAutoApply; unsigned int _primaryPort; volatile unsigned int _udpPortPickerCounter; - uint64_t _clusterMemberId; - uint8_t _clusterKey[32]; // secret key for cluster backplane config // Local configuration and memo-ized information from it json _localConfig; @@ -434,7 +408,6 @@ public: std::vector< InetAddress > _globalV6Blacklist; std::vector< InetAddress > _allowManagementFrom; std::vector< std::string > _interfacePrefixBlacklist; - std::vector< InetAddress > _clusterBackplaneAddresses; Mutex _localConfig_m; /* @@ -518,7 +491,6 @@ public: ,_updateAutoApply(false) ,_primaryPort(port) ,_udpPortPickerCounter(0) - ,_clusterMemberId(0) ,_lastDirectReceiveFromGlobal(0) #ifdef ZT_TCP_FALLBACK_RELAY ,_lastSendToGlobalV4(0) @@ -754,23 +726,6 @@ public: } } - // Derive the cluster's shared secret backplane encryption key by hashing its shared secret identity - { - uint8_t tmp[64]; - uint8_t sk[ZT_C25519_PRIVATE_KEY_LEN + 4]; - memcpy(sk,_node->identity().privateKeyPair().priv.data,ZT_C25519_PRIVATE_KEY_LEN); - sk[ZT_C25519_PRIVATE_KEY_LEN] = 0xab; - sk[ZT_C25519_PRIVATE_KEY_LEN + 1] = 0xcd; - sk[ZT_C25519_PRIVATE_KEY_LEN + 2] = 0xef; - sk[ZT_C25519_PRIVATE_KEY_LEN + 3] = 0xab; // add an arbitrary nonce, just because - SHA512::hash(tmp,sk,ZT_C25519_PRIVATE_KEY_LEN + 4); - memcpy(_clusterKey,tmp,32); - } - - // Assign a random non-zero cluster member ID to identify vs. other cluster members - Utils::getSecureRandom(&_clusterMemberId,sizeof(_clusterMemberId)); - if (!_clusterMemberId) _clusterMemberId = 1; - // Main I/O loop _nextBackgroundTaskDeadline = 0; uint64_t clockShouldBe = OSUtils::now(); @@ -779,7 +734,6 @@ public: uint64_t lastBindRefresh = 0; uint64_t lastUpdateCheck = clockShouldBe; uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle - uint64_t lastTcpCheck = 0; for(;;) { _run_m.lock(); if (!_run) { @@ -873,58 +827,6 @@ public: _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); } - // Check TCP connections and cluster links - if ((now - lastTcpCheck) >= ZT_TCP_CHECK_PERIOD) { - lastTcpCheck = now; - - // Send status to active cluster links and close overflowed and dead ones - std::vector toClose; - std::vector clusterLinksUp; - { - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { - TcpConnection *const tc = *c; - tc->writeq_m.lock(); - const unsigned long wql = (unsigned long)tc->writeq.length(); - tc->writeq_m.unlock(); - if ((tc->sock)&&((wql > ZT_TCP_MAX_WRITEQ_SIZE)||((now - tc->lastReceive) > ZT_TCP_ACTIVITY_TIMEOUT))) { - toClose.push_back(tc->sock); - } else if ((tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(tc->clusterMemberId)) { - clusterLinksUp.push_back(tc->remoteAddr); - sendMyCurrentClusterState(tc); - } - } - } - for(std::vector::iterator s(toClose.begin());s!=toClose.end();++s) - _phy.close(*s,true); - - // Attempt to connect to cluster links we don't have an active connection to - { - Mutex::Lock _l(_localConfig_m); - for(std::vector::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) { - if ( (std::find(clusterLinksUp.begin(),clusterLinksUp.end(),*ca) == clusterLinksUp.end()) && (!_binder.isBoundLocalInterfaceAddress(*ca)) ) { - TcpConnection *tc = new TcpConnection(); - { - Mutex::Lock _l(_tcpConnections_m); - _tcpConnections.push_back(tc); - } - - tc->type = TcpConnection::TCP_CLUSTER_BACKPLANE; - tc->remoteAddr = *ca; - tc->lastReceive = OSUtils::now(); - tc->parent = this; - tc->sock = (PhySocket *)0; // set in connect handler - tc->messageSize = 0; - - tc->clusterMemberId = 0; // not known yet - - bool connected = false; - _phy.tcpConnect(reinterpret_cast(&(*ca)),connected,(void *)tc,true); - } - } - } - } - const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100; clockShouldBe = now + (uint64_t)delay; _phy.poll(delay); @@ -1211,21 +1113,6 @@ public: res["planetWorldId"] = planet.id(); res["planetWorldTimestamp"] = planet.timestamp(); - { - json cj(json::object()); - Mutex::Lock _l(_tcpConnections_m); - Mutex::Lock _l2(_localConfig_m); - for(std::vector::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) { - uint64_t up = 0; - for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { - if (((*c)->remoteAddr == *ca)&&((*c)->clusterMemberId)&&((*c)->lastReceive > up)) - up = (*c)->lastReceive; - } - cj[ca->toString()] = up; - } - res["cluster"] = cj; - } - scode = 200; } else if (ps[0] == "moon") { std::vector moons(_node->moons()); @@ -1576,16 +1463,6 @@ public: } } - json &cl = settings["cluster"]; - _clusterBackplaneAddresses.clear(); - if (cl.is_array()) { - for(unsigned long i=0;i buf; - - buf.appendRandom(16); - buf.addSize(8); // space for MAC - buf.append((uint8_t)CLUSTER_MESSAGE_STATUS); - buf.append(_clusterMemberId); - buf.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR); - buf.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR); - buf.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - - std::vector lif(_binder.allBoundLocalInterfaceAddresses()); - buf.append((uint16_t)lif.size()); - for(std::vector::const_iterator i(lif.begin());i!=lif.end();++i) - i->serialize(buf); - - Mutex::Lock _l(tc->writeq_m); - - if (tc->writeq.length() == 0) - _phy.setNotifyWritable(tc->sock,true); - - const unsigned int mlen = buf.size(); - tc->writeq.push_back((char)((mlen >> 16) & 0xff)); - tc->writeq.push_back((char)((mlen >> 8) & 0xff)); - tc->writeq.push_back((char)(mlen & 0xff)); - - char *const data = reinterpret_cast(buf.unsafeData()); - encryptClusterMessage(data,mlen); - tc->writeq.append(data,mlen); - } catch ( ... ) { - fprintf(stderr,"WARNING: unexpected exception announcing status to cluster members" ZT_EOL_S); - } - } - - bool proxySendViaCluster(const InetAddress &fromAddress,const InetAddress &dest,const void *data,unsigned int len,unsigned int ttl) - { - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { - TcpConnection *const tc = *c; - if ((tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(tc->clusterMemberId)) { - Mutex::Lock _l2(tc->clusterMemberLocalAddresses_m); - for(std::vector::const_iterator i(tc->clusterMemberLocalAddresses.begin());i!=tc->clusterMemberLocalAddresses.end();++i) { - if (*i == fromAddress) { - Buffer<1024> buf; - - buf.appendRandom(16); - buf.addSize(8); // space for MAC - buf.append((uint8_t)CLUSTER_MESSAGE_PROXY_SEND); - buf.append((uint8_t)ttl); - dest.serialize(buf); - fromAddress.serialize(buf); - - Mutex::Lock _l3(tc->writeq_m); - - if (tc->writeq.length() == 0) - _phy.setNotifyWritable(tc->sock,true); - - const unsigned int mlen = buf.size() + len; - tc->writeq.push_back((char)((mlen >> 16) & 0xff)); - tc->writeq.push_back((char)((mlen >> 8) & 0xff)); - tc->writeq.push_back((char)(mlen & 0xff)); - - const unsigned long startpos = (unsigned long)tc->writeq.length(); - tc->writeq.append(reinterpret_cast(buf.data()),buf.size()); - tc->writeq.append(reinterpret_cast(data),len); - - char *const outdata = const_cast(tc->writeq.data()) + startpos; - encryptClusterMessage(outdata,mlen); - - return true; - } - } - } - } - return false; - } - - void replicateStateObject(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,TcpConnection *tc) - { - char buf[42]; - Mutex::Lock _l2(tc->writeq_m); - - if (tc->writeq.length() == 0) - _phy.setNotifyWritable(tc->sock,true); - - const unsigned int mlen = len + 42; - - tc->writeq.push_back((char)((mlen >> 16) & 0xff)); - tc->writeq.push_back((char)((mlen >> 8) & 0xff)); - tc->writeq.push_back((char)(mlen & 0xff)); - - Utils::getSecureRandom(buf,16); - buf[24] = (char)CLUSTER_MESSAGE_STATE_OBJECT; - buf[25] = (char)type; - buf[26] = (char)((id[0] >> 56) & 0xff); - buf[27] = (char)((id[0] >> 48) & 0xff); - buf[28] = (char)((id[0] >> 40) & 0xff); - buf[29] = (char)((id[0] >> 32) & 0xff); - buf[30] = (char)((id[0] >> 24) & 0xff); - buf[31] = (char)((id[0] >> 16) & 0xff); - buf[32] = (char)((id[0] >> 8) & 0xff); - buf[33] = (char)(id[0] & 0xff); - buf[34] = (char)((id[1] >> 56) & 0xff); - buf[35] = (char)((id[1] >> 48) & 0xff); - buf[36] = (char)((id[1] >> 40) & 0xff); - buf[37] = (char)((id[1] >> 32) & 0xff); - buf[38] = (char)((id[1] >> 24) & 0xff); - buf[39] = (char)((id[1] >> 16) & 0xff); - buf[40] = (char)((id[1] >> 8) & 0xff); - buf[41] = (char)(id[1] & 0xff); - - const unsigned long startpos = (unsigned long)tc->writeq.length(); - tc->writeq.append(buf,42); - tc->writeq.append(reinterpret_cast(data),len); - - char *const outdata = const_cast(tc->writeq.data()) + startpos; - encryptClusterMessage(outdata,mlen); - tc->writeq.append(outdata,mlen); - } - - void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) - { - char buf[65535]; - char p[1024]; - FILE *f; - bool secure = false; - - switch(type) { - case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_IDENTITY_SECRET: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); - secure = true; - break; - //case ZT_STATE_OBJECT_PEER_STATE: - // break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); - secure = true; - break; - //case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: - // break; - case ZT_STATE_OBJECT_PLANET: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_MOON: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); - break; - default: - p[0] = (char)0; - break; - } - - if (p[0]) { - if (len >= 0) { - // Check to see if we've already written this first. This reduces - // redundant writes and I/O overhead on most platforms and has - // little effect on others. - f = fopen(p,"r"); - bool redundant = false; - if (f) { - long l = (long)fread(buf,1,sizeof(buf),f); - fclose(f); - redundant = ((l == (long)len)&&(memcmp(data,buf,l) == 0)); - } - if (!redundant) { - f = fopen(p,"w"); - if (f) { - if (fwrite(data,len,1,f) != 1) - fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); - fclose(f); - if (secure) - OSUtils::lockDownFile(p,false); - } else { - fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); - } - } - } else { - OSUtils::rm(p); - } - } - } - - void sendMyCurrentClusterState(TcpConnection *tc) - { - // We currently don't need to dump everything. Networks and moons are most important. - // The rest will get caught up rapidly due to constant peer updates, etc. - std::string buf; - std::vector l(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str(),false)); - for(std::vector::const_iterator f(l.begin());f!=l.end();++f) { - buf.clear(); - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { - if (f->length() == 21) { - const uint64_t nwid = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (nwid) { - uint64_t tmp[2]; - tmp[0] = nwid; - tmp[1] = 0; - replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,buf.data(),(int)buf.length(),tc); - } - } - } - } - l = OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "moons.d").c_str(),false); - for(std::vector::const_iterator f(l.begin());f!=l.end();++f) { - buf.clear(); - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { - if (f->length() == 21) { - const uint64_t moonId = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (moonId) { - uint64_t tmp[2]; - tmp[0] = moonId; - tmp[1] = 0; - replicateStateObject(ZT_STATE_OBJECT_MOON,tmp,buf.data(),(int)buf.length(),tc); - } - } - } - } - } - // ========================================================================= // Handlers for Node and Phy<> callbacks // ========================================================================= @@ -2010,7 +1643,7 @@ public: const ZT_ResultCode rc = _node->processWirePacket( (void *)0, OSUtils::now(), - reinterpret_cast(localAddr), + (int64_t)((uintptr_t)sock), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big data, len, @@ -2044,13 +1677,6 @@ public: _phy.close(_tcpFallbackTunnel->sock); _tcpFallbackTunnel = tc; _phy.streamSend(sock,ZT_TCP_TUNNEL_HELLO,sizeof(ZT_TCP_TUNNEL_HELLO)); - } else if (tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE) { - { - Mutex::Lock _l(tc->writeq_m); - tc->writeq.push_back((char)0x93); // identifies type of connection as cluster backplane - } - announceStatusToClusterMember(tc); - _phy.setNotifyWritable(sock,true); } else { _phy.close(sock,true); } @@ -2106,31 +1732,6 @@ public: case TcpConnection::TCP_UNCATEGORIZED_INCOMING: switch(reinterpret_cast(data)[0]) { - // 0x93 is first byte of cluster backplane connections - case 0x93: { - // We only allow this from cluster backplane IPs. We also authenticate - // each packet cryptographically, so this is just a first line of defense. - bool allow = false; - { - Mutex::Lock _l(_localConfig_m); - for(std::vector< InetAddress >::const_iterator i(_clusterBackplaneAddresses.begin());i!=_clusterBackplaneAddresses.end();++i) { - if (tc->remoteAddr.ipsEqual(*i)) { - allow = true; - break; - } - } - } - if (allow) { - tc->type = TcpConnection::TCP_CLUSTER_BACKPLANE; - tc->clusterMemberId = 0; // unknown, waiting for first status message - announceStatusToClusterMember(tc); - if (len > 1) - phyOnTcpData(sock,uptr,reinterpret_cast(data) + 1,len - 1); - } else { - _phy.close(sock); - } - } break; - // HTTP: GET, PUT, POST, HEAD case 'G': case 'P': @@ -2223,7 +1824,7 @@ public: const ZT_ResultCode rc = _node->processWirePacket( (void *)0, OSUtils::now(), - reinterpret_cast(&fakeTcpLocalInterfaceAddress), + -1, reinterpret_cast(&from), data, plen, @@ -2248,114 +1849,6 @@ public: } return; - case TcpConnection::TCP_CLUSTER_BACKPLANE: - tc->readq.append((const char *)data,len); - if (tc->readq.length() >= 28) { // got 3-byte message size + 16-byte IV + 8-byte MAC + 1-byte type (encrypted) - uint8_t *data = reinterpret_cast(const_cast(tc->readq.data())); - unsigned long mlen = ( ((unsigned long)data[0] << 16) | ((unsigned long)data[1] << 8) | (unsigned long)data[2] ); - if ((mlen < 25)||(mlen > ZT_TCP_MAX_WRITEQ_SIZE)) { - _phy.close(sock); - return; - } else if (tc->readq.length() >= (mlen + 3)) { // got entire message - data += 3; - - uint8_t key[32]; - memcpy(key,_clusterKey,32); - for(int i=0;i<8;++i) key[i] ^= data[i]; // first 8 bytes of IV get XORed with key - Salsa20 s20(key,data + 8); // last 8 bytes of IV are fed into Salsa20 directly as its 64-bit IV - - uint8_t macKey[32]; - uint8_t mac[16]; - memset(macKey,0,32); - s20.crypt12(macKey,macKey,32); - Poly1305::compute(mac,data + 24,mlen - 24,macKey); - if (!Utils::secureEq(mac,data + 16,8)) { - _phy.close(sock); - return; - } - s20.crypt12(data + 24,data + 24,mlen - 24); - - switch((ClusterMessageType)data[24]) { - case CLUSTER_MESSAGE_STATUS: - if (mlen > (25 + 16)) { - Buffer<4096> tmp(data + 25,mlen - 25); - try { - const uint64_t cmid = tmp.at(0); - if (cmid == _clusterMemberId) { // shouldn't happen, but don't allow self-to-self - _phy.close(sock); - return; - } - if (!tc->clusterMemberId) { - tc->clusterMemberId = cmid; - sendMyCurrentClusterState(tc); - } - tc->clusterMemberVersionMajor = tmp.at(8); - tc->clusterMemberVersionMinor = tmp.at(10); - tc->clusterMemberVersionRev = tmp.at(12); - const unsigned int clusterMemberLocalAddressCount = tmp.at(14); - std::vector la; - unsigned int ptr = 16; - for(unsigned int k=0;kclusterMemberLocalAddresses_m); - tc->clusterMemberLocalAddresses.swap(la); - } - } catch ( ... ) {} - } - break; - - case CLUSTER_MESSAGE_STATE_OBJECT: - if (mlen > 42) { // type + object ID + [data] - uint64_t objId[2]; - objId[0] = ( - ((uint64_t)data[26] << 56) | - ((uint64_t)data[27] << 48) | - ((uint64_t)data[28] << 40) | - ((uint64_t)data[29] << 32) | - ((uint64_t)data[30] << 24) | - ((uint64_t)data[31] << 16) | - ((uint64_t)data[32] << 8) | - (uint64_t)data[33] - ); - objId[1] = ( - ((uint64_t)data[34] << 56) | - ((uint64_t)data[35] << 48) | - ((uint64_t)data[36] << 40) | - ((uint64_t)data[37] << 32) | - ((uint64_t)data[38] << 24) | - ((uint64_t)data[39] << 16) | - ((uint64_t)data[40] << 8) | - (uint64_t)data[41] - ); - if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) - writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)); - } - break; - - case CLUSTER_MESSAGE_PROXY_SEND: - if (mlen > 25) { - Buffer<4096> tmp(data + 25,mlen - 25); - try { - InetAddress dest,src; - const unsigned int ttl = (unsigned int)tmp[0]; - unsigned int ptr = 1; - ptr += dest.deserialize(tmp); - ptr += src.deserialize(tmp,ptr); - if (ptr < tmp.size()) - _binder.udpSend(_phy,src,dest,reinterpret_cast(tmp.data()) + ptr,tmp.size() - ptr,ttl); - } catch ( ... ) {} - } - break; - } - - tc->readq.erase(tc->readq.begin(),tc->readq.begin() + mlen); - } - } - return; - } } catch ( ... ) { _phy.close(sock); @@ -2549,18 +2042,57 @@ public: inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { - writeStateObject(type,id,data,len); + char p[1024]; + FILE *f; + bool secure = false; - std::vector sentTo; - { - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) { - TcpConnection *const c = *ci; - if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) { - sentTo.push_back(c->clusterMemberId); - replicateStateObject(type,id,data,len,c); - } + switch(type) { + case ZT_STATE_OBJECT_IDENTITY_PUBLIC: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_IDENTITY_SECRET: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + secure = true; + break; + case ZT_STATE_OBJECT_PLANET: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_MOON: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + secure = true; + break; + default: + return; + } + + if (len >= 0) { + // Check to see if we've already written this first. This reduces + // redundant writes and I/O overhead on most platforms and has + // little effect on others. + f = fopen(p,"r"); + if (f) { + char buf[65535]; + long l = (long)fread(buf,1,sizeof(buf),f); + fclose(f); + if ((l == (long)len)&&(memcmp(data,buf,l) == 0)) + return; } + + f = fopen(p,"w"); + if (f) { + if (fwrite(data,len,1,f) != 1) + fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + fclose(f); + if (secure) + OSUtils::lockDownFile(p,false); + } else { + fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + } + } else { + OSUtils::rm(p); } } @@ -2596,7 +2128,7 @@ public: return -1; } - inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) + inline int nodeWirePacketSendFunction(const int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { #ifdef ZT_TCP_FALLBACK_RELAY if (addr->ss_family == AF_INET) { @@ -2646,20 +2178,13 @@ public: // proxy fallback, which is slow. #endif // ZT_TCP_FALLBACK_RELAY - switch (_binder.udpSend(_phy,*(reinterpret_cast(localAddr)),*(reinterpret_cast(addr)),data,len,ttl)) { - case -1: // local bound address not found, so see if a cluster peer owns it - if (localAddr->ss_family != 0) { - return (proxySendViaCluster(*(reinterpret_cast(localAddr)),*(reinterpret_cast(addr)),data,len,ttl)) ? 0 : -1; - } else { - return -1; // failure - } - break; - - case 0: // failure - return -1; - - default: // success - return 0; + if ((localSocket != 0)&&(localSocket != -1)) { + if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),ttl); + const bool r = _phy.udpSend((PhySocket *)((uintptr_t)localSocket),(const struct sockaddr *)addr,data,len); + if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),255); + return ((r) ? 0 : -1); + } else { + return ((_binder.udpSendAll(_phy,addr,data,len,ttl)) ? 0 : -1); } } @@ -2671,7 +2196,7 @@ public: n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); } - inline int nodePathCheckFunction(uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) + inline int nodePathCheckFunction(uint64_t ztaddr,const int64_t localSocket,const struct sockaddr_storage *remoteAddr) { // Make sure we're not trying to do ZeroTier-over-ZeroTier { @@ -2882,12 +2407,12 @@ static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_St { reinterpret_cast(uptr)->nodeStatePutFunction(type,id,data,len); } static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { return reinterpret_cast(uptr)->nodeStateGetFunction(type,id,data,maxlen); } -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) -{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) +{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); } static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr) +{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); } static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) { return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -- cgit v1.2.3 From dff8c02cfee9eaafae0974f3b070ff849a94c4ac Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 12:33:00 -0700 Subject: Pull out and deprecate old cluster code. New cluster code will not be merged yet. --- node/IncomingPacket.cpp | 12 ++++++------ node/Peer.cpp | 18 ++++++++++++++++-- node/Peer.hpp | 17 ++++++++++++++++- service/OneService.cpp | 20 ++++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f0be96f9..ac8514c6 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1199,9 +1199,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { - //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - // peer->setClusterPreferred(a); - if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->redirect(tPtr,_path->localSocket(),a,now); + } else 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(tPtr,InetAddress(),a,now,false,0); } else { @@ -1216,9 +1216,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { - //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - // peer->setClusterPreferred(a); - if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->redirect(tPtr,_path->localSocket(),a,now); + } else 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(tPtr,InetAddress(),a,now,false,0); } else { diff --git a/node/Peer.cpp b/node/Peer.cpp index fb9a72b1..e16540b3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -170,11 +170,11 @@ void Peer::received( Mutex::Lock _l(_paths_m); _PeerPath *potentialNewPeerPath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { - if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) { + if ( ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) && ( (now - _v4Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { potentialNewPeerPath = &_v4Path; } } else if (path->address().ss_family == AF_INET6) { - if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) { + if ( ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) && ( (now - _v6Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { potentialNewPeerPath = &_v6Path; } } @@ -422,4 +422,18 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } +void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now) +{ + Mutex::Lock _l(_paths_m); + SharedPtr p(RR->topology->getPath(localSocket,remoteAddress)); + attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,p->nextOutgoingCounter()); + if (remoteAddress.ss_family == AF_INET) { + _v4Path.p = p; + _v4Path.sticky = now; + } else if (remoteAddress.ss_family == AF_INET6) { + _v6Path.p = p; + _v6Path.sticky = now; + } +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index ad2d0ddc..b24318ec 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -195,6 +195,20 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); + /** + * Specify remote path for this peer and forget others + * + * This overrides normal path learning and tells this peer to be found + * at this address, at least within the address's family. Other address + * families are not modified. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param localSocket Local socket as supplied by external code + * @param remoteAddress Remote address + * @param now Current time + */ + void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now); + /** * Reset paths within a given IP scope and address family * @@ -426,8 +440,9 @@ public: private: struct _PeerPath { - _PeerPath() : lr(0),p() {} + _PeerPath() : lr(0),sticky(0),p() {} uint64_t lr; // time of last valid ZeroTier packet + uint64_t sticky; // time last set as sticky SharedPtr p; }; diff --git a/service/OneService.cpp b/service/OneService.cpp index 6497ae20..6c2c9a8b 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -394,6 +394,8 @@ public: Phy _phy; Node *_node; SoftwareUpdater *_updater; + PhySocket *_localControlSocket4; + PhySocket *_localControlSocket6; bool _updateAutoApply; unsigned int _primaryPort; volatile unsigned int _udpPortPickerCounter; @@ -488,6 +490,8 @@ public: ,_phy(this,false,true) ,_node((Node *)0) ,_updater((SoftwareUpdater *)0) + ,_localControlSocket4((PhySocket *)0) + ,_localControlSocket6((PhySocket *)0) ,_updateAutoApply(false) ,_primaryPort(port) ,_udpPortPickerCounter(0) @@ -513,6 +517,8 @@ public: virtual ~OneServiceImpl() { _binder.closeAll(_phy); + _phy.close(_localControlSocket4); + _phy.close(_localControlSocket6); #ifdef ZT_USE_MINIUPNPC delete _portMapper; #endif @@ -652,6 +658,20 @@ public: return _termReason; } + // Bind local control socket + { + struct sockaddr_in lo4; + memset(&lo4,0,sizeof(lo4)); + lo4.sin_family = AF_INET; + lo4.sin_port = Utils::hton((uint16_t)_ports[0]); + _localControlSocket4 = _phy.tcpListen((const struct sockaddr *)&lo4); + struct sockaddr_in6 lo6; + memset(&lo6,0,sizeof(lo6)); + lo6.sin6_family = AF_INET6; + lo6.sin6_port = lo4.sin_port; + _localControlSocket6 = _phy.tcpListen((const struct sockaddr *)&lo6); + } + // Save primary port to a file so CLIs and GUIs can learn it easily char portstr[64]; Utils::ztsnprintf(portstr,sizeof(portstr),"%u",_ports[0]); -- cgit v1.2.3 From dab0fb9e05677bdc6294f196fcf8234892c582c1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 7 Jul 2017 16:58:05 -0700 Subject: Remote trace: plumbing, replace old TRACE with calls to Trace object. --- include/ZeroTierOne.h | 9 +- node/IncomingPacket.cpp | 180 ++++++++++------------------- node/Membership.cpp | 29 ++--- node/Multicaster.cpp | 4 - node/Network.cpp | 274 +++++++++----------------------------------- node/NetworkConfig.cpp | 2 + node/NetworkConfig.hpp | 7 ++ node/Node.cpp | 3 + node/Node.hpp | 7 -- node/OutboundMulticast.cpp | 13 --- node/Packet.cpp | 44 ------- node/Packet.hpp | 33 ++++-- node/Peer.cpp | 57 ++++----- node/RuntimeEnvironment.hpp | 3 +- node/SelfAwareness.cpp | 3 +- node/Switch.cpp | 71 +++--------- node/Topology.cpp | 10 +- node/Topology.hpp | 6 - node/Trace.cpp | 197 +++++++++++++++++++++++++++++++ node/Trace.hpp | 157 +++++++++++++++++++++++++ objects.mk | 1 + 21 files changed, 577 insertions(+), 533 deletions(-) create mode 100644 node/Trace.cpp create mode 100644 node/Trace.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 1365a9a0..f7681768 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -29,8 +29,8 @@ * engine. */ -#ifndef ZT_ZEROTIERONE_H -#define ZT_ZEROTIERONE_H +#ifndef ZT_ZEROTIER_API_H +#define ZT_ZEROTIER_API_H #include @@ -92,6 +92,11 @@ extern "C" { */ #define ZT_MAX_MTU 10000 +/** + * Maximum size of a remote trace message's serialized Dictionary + */ +#define ZT_MAX_REMOTE_TRACE_SIZE 10000 + /** * Maximum length of network short name */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ac8514c6..e1fb180c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -48,6 +48,7 @@ #include "Capability.hpp" #include "Tag.hpp" #include "Revocation.hpp" +#include "Trace.hpp" namespace ZeroTier { @@ -63,11 +64,12 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // If this is marked as a packet via a trusted path, check source address and path ID. // Obviously if no trusted paths are configured this always returns false and such // packets are dropped on the floor. - if (RR->topology->shouldInboundPathBeTrusted(_path->address(),trustedPathId())) { + const uint64_t tpid = trustedPathId(); + if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { + RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,true); trusted = true; - TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId()); } else { - TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId(),_path->address().toString().c_str()); + RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,false); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -80,19 +82,18 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (!trusted) { if (!dearmor(peer->key())) { //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); - TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,packetId(),sourceAddress); return true; } } if (!uncompress()) { //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); - TRACE("dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); + RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"LZ4 decompression failed"); return true; } const Packet::Verb v = verb(); - //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_path->address().toString().c_str()); switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" @@ -121,9 +122,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) return false; } } catch ( ... ) { - // Exceptions are more informatively caught in _do...() handlers but - // this outer try/catch will catch anything else odd. - TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"unexpected exception in tryDecode() (outer)"); return true; } } @@ -135,8 +134,6 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); - /* Security note: we do not gate doERROR() with expectingReplyTo() to * avoid having to log every outgoing packet ID. Instead we put the * logic to determine whether we should consider an ERROR in each @@ -192,7 +189,6 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->gate(tPtr,peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); } } break; @@ -202,7 +198,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ERROR,"unexpected exception"); } return true; } @@ -223,11 +219,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"protocol version too old"); return true; } if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"identity/address mismatch"); return true; } @@ -245,7 +241,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"address collision"); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); @@ -253,10 +249,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); } } else { - TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); } return true; @@ -264,7 +260,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); return true; } @@ -276,24 +272,26 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Sanity check: this basically can't happen if (alreadyAuthenticated) { - TRACE("dropped HELLO from %s(%s): somehow already authenticated with unknown peer?",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"illegal alreadyAuthenticated state"); return true; } // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) + if (!RR->node->rateGateIdentityVerification(now,_path->address())) { + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"rate limit exceeded"); return true; + } // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); return true; } // Check that identity's address is valid as per the derivation function if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"invalid identity"); return true; } @@ -418,7 +416,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_HELLO,"unexpected exception"); } return true; } @@ -429,12 +427,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - if (!RR->node->expectingReplyTo(inRePacketId)) { - TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); + if (!RR->node->expectingReplyTo(inRePacketId)) return true; - } - - //TRACE("%s(%s): OK(%s)",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { @@ -447,11 +441,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; 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(),_path->address().toString().c_str()); + if (vProto < ZT_PROTO_VERSION_MIN) return true; - } InetAddress externalSurfaceAddress; unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; @@ -484,12 +475,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } else ptr += 2; } -#ifdef ZT_TRACE - const std::string tmp1(source().toString()); - const std::string tmp2(_path->address().toString()); - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u",tmp1.c_str(),tmp2.c_str(),vMajor,vMinor,vRevision,latency); -#endif - if (!hops()) peer->addDirectLatencyMeasurment((unsigned int)latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); @@ -516,7 +501,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const SharedPtr network(RR->node->network(nwid)); if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } @@ -527,8 +511,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); - const SharedPtr network(RR->node->network(nwid)); if (network) { unsigned int offset = 0; @@ -555,7 +537,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_OK,"unexpected exception"); } return true; } @@ -563,10 +545,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { - TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) return true; - } Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); @@ -595,7 +575,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_WHOIS,"unexpected exception"); } return true; } @@ -603,9 +583,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (!RR->topology->isUpstream(peer->identity())) { - TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); - } else { + if (RR->topology->isUpstream(peer->identity())) { const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); if (rendezvousWith) { @@ -614,22 +592,16 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { - RR->node->putPacket(tPtr,_path->localSocket(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + const uint64_t junk = RR->node->prng(); + RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); - TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } - } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); } - } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_RENDEZVOUS,"unexpected exception"); } return true; } @@ -652,16 +624,15 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } } else { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); } } else { - TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { - TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_FRAME,"unexpected exception"); } return true; } @@ -683,7 +654,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const } if (!network->gate(tPtr,peer)) { - TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; @@ -696,8 +667,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); + if ((!from)||(from == network->mac())) { peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -708,19 +678,19 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -743,12 +713,10 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { - TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { - TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_EXT_FRAME,"unexpected exception"); } return true; } @@ -756,10 +724,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (!peer->rateGateEchoRequest(RR->node->now())) { - TRACE("dropped ECHO from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + if (!peer->rateGateEchoRequest(RR->node->now())) return true; - } const uint64_t pid = packetId(); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); @@ -772,7 +738,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ECHO,"unexpected exception"); } return true; } @@ -820,7 +786,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { - TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); } return true; } @@ -828,10 +794,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (!peer->rateGateCredentialsReceived(RR->node->now())) { - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + if (!peer->rateGateCredentialsReceived(RR->node->now())) return true; - } CertificateOfMembership com; Capability cap; @@ -942,12 +906,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); - } catch (std::exception &exc) { - //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); } return true; } @@ -975,12 +935,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void } peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); - } catch (std::exception &exc) { - //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); } return true; } @@ -1003,7 +959,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); } return true; } @@ -1016,8 +972,6 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); - const SharedPtr network(RR->node->network(nwid)); if ((flags & 0x01) != 0) { @@ -1029,9 +983,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr network->addCredential(tPtr,com); else RR->mc->addCredential(tPtr,com,false); } - } catch ( ... ) { - TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); - } + } catch ( ... ) {} // discard invalid COMs } const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); @@ -1053,7 +1005,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { - TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); } return true; } @@ -1078,18 +1030,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } if (!network->gate(tPtr,peer)) { - TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } - if (network->config().multicastLimit == 0) { - TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); - return true; - } - unsigned int gatherLimit = 0; if ((flags & 0x02) != 0) { gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); @@ -1108,16 +1054,20 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); - //TRACE("<address().toString().c_str(),flags,frameLen); + if (network->config().multicastLimit == 0) { + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + return true; + } if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { if (!to.mac().isMulticast()) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -1126,16 +1076,15 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); - } } if (gatherLimit) { @@ -1158,7 +1107,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { - TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); } return true; } @@ -1170,7 +1119,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { - //TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1202,10 +1150,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->redirect(tPtr,_path->localSocket(),a,now); } else 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(tPtr,InetAddress(),a,now,false,0); - } else { - //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; @@ -1219,10 +1164,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->redirect(tPtr,_path->localSocket(),a,now); } else 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(tPtr,InetAddress(),a,now,false,0); - } else { - //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; @@ -1232,7 +1174,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); } return true; } @@ -1250,7 +1192,7 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped USER_MESSAGE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_USER_MESSAGE,"unexpected exception"); } return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index 466f9021..be6ea6a5 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -33,6 +33,7 @@ #include "Switch.hpp" #include "Packet.hpp" #include "Node.hpp" +#include "Trace.hpp" #define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3) @@ -128,27 +129,25 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme { const uint64_t newts = com.timestamp(); if (newts <= _comRevocationThreshold) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId()); + RR->t->credentialRejected(com,"revoked"); return ADD_REJECTED; } const uint64_t oldts = _com.timestamp(); if (newts < oldts) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId()); + RR->t->credentialRejected(com,"old"); return ADD_REJECTED; } - if ((newts == oldts)&&(_com == com)) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); + if ((newts == oldts)&&(_com == com)) return ADD_ACCEPTED_REDUNDANT; - } switch(com.verify(RR,tPtr)) { default: - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId()); + RR->t->credentialRejected(com,"invalid"); return ADD_REJECTED; case 0: - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); _com = com; + RR->t->credentialAccepted(com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -162,27 +161,25 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot C *rc = remoteCreds.get(cred.id()); if (rc) { if (rc->timestamp() > cred.timestamp()) { - TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (older than credential we have)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialRejected(cred,"old"); return Membership::ADD_REJECTED; } - if (*rc == cred) { - //TRACE("addCredential(type==%d) for %s on %.16llx ACCEPTED (redundant)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + if (*rc == cred) return Membership::ADD_ACCEPTED_REDUNDANT; - } } const uint64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); if ((rt)&&(*rt >= cred.timestamp())) { - TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (timestamp below revocation threshold)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialRejected(cred,"revoked"); return Membership::ADD_REJECTED; } switch(cred.verify(RR,tPtr)) { default: - TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (invalid)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialRejected(cred,"invalid"); return Membership::ADD_REJECTED; case 0: - TRACE("addCredential(type==%d) for %s on %.16llx ACCEPTED (new)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialAccepted(cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -201,12 +198,14 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme uint64_t *rt; switch(rev.verify(RR,tPtr)) { default: + RR->t->credentialRejected(rev,"invalid"); return ADD_REJECTED; case 0: { const Credential::Type ct = rev.type(); switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { + RR->t->credentialAccepted(rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } @@ -217,10 +216,12 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme rt = &(_revocations[credentialKey(ct,rev.credentialId())]); if (*rt < rev.threshold()) { *rt = rev.threshold(); + _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } return ADD_ACCEPTED_REDUNDANT; default: + RR->t->credentialRejected(rev,"invalid"); return ADD_REJECTED; } } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 52213364..fb7b068f 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -139,8 +139,6 @@ restart_member_scan: appendTo.setAt(totalAt,(uint32_t)totalKnown); appendTo.setAt(addedAt,(uint16_t)added); - //TRACE("..MC Multicaster::gather() attached %u of %u peers for %.16llx/%s (2)",n,(unsigned int)(gs->second.members.size() - skipped),nwid,mg.toString().c_str()); - return added; } @@ -386,8 +384,6 @@ void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGrou gs.members.push_back(MulticastGroupMember(member,now)); - //TRACE("..MC %s joined multicast group %.16llx/%s via %s",member.toString().c_str(),nwid,mg.toString().c_str(),((learnedFrom) ? learnedFrom.toString().c_str() : "(direct)")); - for(std::list::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) { if (tx->atLimit()) gs.txQueue.erase(tx++); diff --git a/node/Network.cpp b/node/Network.cpp index f2b6771b..575b0170 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -42,89 +42,12 @@ #include "NetworkController.hpp" #include "Node.hpp" #include "Peer.hpp" - -// Uncomment to make the rules engine dump trace info to stdout -//#define ZT_RULES_ENGINE_DEBUGGING 1 +#include "Trace.hpp" namespace ZeroTier { namespace { -#ifdef ZT_RULES_ENGINE_DEBUGGING -#define FILTER_TRACE(f,...) { snprintf(dpbuf,sizeof(dpbuf),f,##__VA_ARGS__); dlog.push_back(std::string(dpbuf)); } -static const char *_rtn(const ZT_VirtualNetworkRuleType rt) -{ - switch(rt) { - case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP"; - case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT"; - case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE"; - case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH"; - case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT"; - case ZT_NETWORK_RULE_ACTION_BREAK: return "ACTION_BREAK"; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS"; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: return "MATCH_DEST_ZEROTIER_ADDRESS"; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: return "MATCH_VLAN_ID"; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: return "MATCH_VLAN_PCP"; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: return "MATCH_VLAN_DEI"; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: return "MATCH_MAC_SOURCE"; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: return "MATCH_MAC_DEST"; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: return "MATCH_IPV4_SOURCE"; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: return "MATCH_IPV4_DEST"; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: return "MATCH_IPV6_SOURCE"; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: return "MATCH_IPV6_DEST"; - case ZT_NETWORK_RULE_MATCH_IP_TOS: return "MATCH_IP_TOS"; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: return "MATCH_IP_PROTOCOL"; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: return "MATCH_ETHERTYPE"; - case ZT_NETWORK_RULE_MATCH_ICMP: return "MATCH_ICMP"; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: return "MATCH_IP_SOURCE_PORT_RANGE"; - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: return "MATCH_IP_DEST_PORT_RANGE"; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: return "MATCH_CHARACTERISTICS"; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: return "MATCH_FRAME_SIZE_RANGE"; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: return "MATCH_TAGS_DIFFERENCE"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: return "MATCH_TAGS_BITWISE_AND"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: return "MATCH_TAGS_BITWISE_OR"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: return "MATCH_TAGS_BITWISE_XOR"; - default: return "???"; - } -} -static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,bool inbound,const Address &ztSource,const Address &ztDest,const MAC &macSource,const MAC &macDest,const std::vector &dlog,unsigned int frameLen,unsigned int etherType,const char *msg) -{ - static volatile unsigned long cnt = 0; - printf("%.6lu %c %s %s frameLen=%u etherType=%u" ZT_EOL_S, - cnt++, - ((thisSetMatches) ? 'Y' : '.'), - ruleName, - ((inbound) ? "INBOUND" : "OUTBOUND"), - frameLen, - etherType - ); - for(std::vector::const_iterator m(dlog.begin());m!=dlog.end();++m) - printf(" | %s" ZT_EOL_S,m->c_str()); - printf(" + %c %s->%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x->%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" ZT_EOL_S, - ((thisSetMatches) ? 'Y' : '.'), - ztSource.toString().c_str(), - ztDest.toString().c_str(), - (unsigned int)macSource[0], - (unsigned int)macSource[1], - (unsigned int)macSource[2], - (unsigned int)macSource[3], - (unsigned int)macSource[4], - (unsigned int)macSource[5], - (unsigned int)macDest[0], - (unsigned int)macDest[1], - (unsigned int)macDest[2], - (unsigned int)macDest[3], - (unsigned int)macDest[4], - (unsigned int)macDest[5] - ); - if (msg) - printf(" + (%s)" ZT_EOL_S,msg); - fflush(stdout); -} -#else -#define FILTER_TRACE(f,...) {} -#endif // ZT_RULES_ENGINE_DEBUGGING - // 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) { @@ -162,8 +85,10 @@ enum _doZtFilterResult DOZTFILTER_ACCEPT, DOZTFILTER_SUPER_ACCEPT }; + static _doZtFilterResult _doZtFilter( const RuntimeEnvironment *RR, + Trace::RuleResultLog &rrl, const NetworkConfig &nconf, const Membership *membership, // can be NULL const bool inbound, @@ -181,11 +106,6 @@ static _doZtFilterResult _doZtFilter( unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE bool &ccWatch) // MUTABLE -- set to true for WATCH target as opposed to normal TEE { -#ifdef ZT_RULES_ENGINE_DEBUGGING - char dpbuf[1024]; // used by FILTER_TRACE macro - std::vector dlog; -#endif // ZT_RULES_ENGINE_DEBUGGING - // Set to true if we are a TEE/REDIRECT/WATCH target bool superAccept = false; @@ -193,6 +113,8 @@ static _doZtFilterResult _doZtFilter( // ACTION with no MATCH entries preceding it is always taken. uint8_t thisSetMatches = 1; + rrl.clear(); + for(unsigned int rn=0;rnidentity.address()) { if (inbound) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"interpreted as super-ACCEPT on inbound since we are target"); -#endif // ZT_RULES_ENGINE_DEBUGGING return DOZTFILTER_SUPER_ACCEPT; } else { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"skipped as no-op on outbound since we are target"); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING } } else if (fwdAddr == ztDest) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"skipped as no-op because destination is already target"); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING } else { if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_REDIRECT",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); -#endif // ZT_RULES_ENGINE_DEBUGGING ztDest = fwdAddr; return DOZTFILTER_REDIRECT; } else { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING cc = fwdAddr; ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); @@ -259,18 +154,10 @@ static _doZtFilterResult _doZtFilter( } continue; case ZT_NETWORK_RULE_ACTION_BREAK: -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_BREAK",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING return DOZTFILTER_NO_MATCH; // Unrecognized ACTIONs are ignored as no-ops default: -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING continue; } } else { @@ -290,10 +177,6 @@ static _doZtFilterResult _doZtFilter( } } -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING thisSetMatches = 1; // reset to default true for next batch of entries continue; } @@ -301,8 +184,10 @@ static _doZtFilterResult _doZtFilter( // Circuit breaker: no need to evaluate an AND if the set's match state // is currently false since anything AND false is false. - if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) + if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) { + rrl.logSkipped(rn,thisSetMatches); continue; + } // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) uint8_t thisRuleMatches = 0; @@ -310,106 +195,82 @@ static _doZtFilterResult _doZtFilter( switch(rt) { case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); - FILTER_TRACE("%u %s %c %.10llx==%.10llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.zt,ztSource.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); - FILTER_TRACE("%u %s %c %.10llx==%.10llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.zt,ztDest.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_VLAN_ID: thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanId,(unsigned int)vlanId,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_VLAN_PCP: // NOT SUPPORTED YET thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanPcp,0,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_VLAN_DEI: // NOT SUPPORTED YET thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanDei,0,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macSource); - FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macSource.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_MAC_DEST: thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macDest); - FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macDest.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).toString().c_str(),InetAddress((const void *)(frameData + 12),4,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv4] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IPV4_DEST: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).toString().c_str(),InetAddress((const void *)(frameData + 16),4,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv4] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).toString().c_str(),InetAddress((const void *)(frameData + 8),16,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IPV6_DEST: if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).toString().c_str(),InetAddress((const void *)(frameData + 24),16,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IP_TOS: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - //thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((frameData[1] & 0xfc) >> 2)); const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); - FILTER_TRACE("%u %s %c (IPv4) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipProtocol,(unsigned int)frameData[9],(unsigned int)thisRuleMatches); } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); - FILTER_TRACE("%u %s %c (IPv6) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipProtocol,proto,(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_ETHERTYPE: thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.etherType,etherType,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_ICMP: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { @@ -425,14 +286,11 @@ static _doZtFilterResult _doZtFilter( } else { thisRuleMatches = 0; } - FILTER_TRACE("%u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[ihl],(int)rules[rn].v.icmp.type,(int)frameData[ihl+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [IPv4 frame invalid] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not ICMP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; @@ -447,21 +305,16 @@ static _doZtFilterResult _doZtFilter( } else { thisRuleMatches = 0; } - FILTER_TRACE("%u %s %c (IPv6) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[pos],(int)rules[rn].v.icmp.type,(int)frameData[pos+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not ICMPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; - break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { @@ -482,7 +335,6 @@ static _doZtFilterResult _doZtFilter( } thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - FILTER_TRACE("%u %s %c (IPv4) %d in %d-%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),p,(int)rules[rn].v.port[0],(int)rules[rn].v.port[1],(unsigned int)thisRuleMatches); } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { @@ -501,14 +353,11 @@ static _doZtFilterResult _doZtFilter( break; } thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - FILTER_TRACE("%u %s %c (IPv6) %d in %d-%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),p,(int)rules[rn].v.port[0],(int)rules[rn].v.port[1],(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { @@ -570,15 +419,12 @@ static _doZtFilterResult _doZtFilter( } } thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); - FILTER_TRACE("%u %s %c (%.16llx | %.16llx)!=0 -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),cf,rules[rn].v.characteristics,(unsigned int)thisRuleMatches); } break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); - FILTER_TRACE("%u %s %c %u in %u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),frameLen,(unsigned int)rules[rn].v.frameSize[0],(unsigned int)rules[rn].v.frameSize[1],(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_RANDOM: thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability); - FILTER_TRACE("%u %s %c -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: @@ -594,26 +440,20 @@ static _doZtFilterResult _doZtFilter( if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value)); - FILTER_TRACE("%u %s %c TAG %u local:%.8x and remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { // sanity check, can't really happen thisRuleMatches = 0; } } else { if ((inbound)&&(!superAccept)) { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } else { // Outbound side is not strict since if we have to match both tags and // we are sending a first packet to a recipient, we probably do not know @@ -621,43 +461,35 @@ static _doZtFilterResult _doZtFilter( // once we get their tag. If we are a tee/redirect target we are also // not strict since we likely do not have these tags. thisRuleMatches = 1; - FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side and TEE/REDIRECT targets are not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } break; case ZT_NETWORK_RULE_MATCH_TAG_SENDER: case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { if (superAccept) { thisRuleMatches = 1; - FILTER_TRACE("%u %s %c we are a TEE/REDIRECT target -> 1",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) { const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); if (remoteTag) { thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,remoteTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { // If we are checking the receiver and this is an outbound packet, we // can't be strict since we may not yet know the receiver's tag. thisRuleMatches = 1; - FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 1 (outbound receiver match is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } } else { // sender and outbound or receiver and inbound const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,localTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } } break; @@ -669,6 +501,8 @@ static _doZtFilterResult _doZtFilter( break; } + rrl.log(rn,thisRuleMatches,thisSetMatches); + if ((rules[rn].t & 0x40)) thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); @@ -761,33 +595,34 @@ bool Network::filterOutgoingPacket( const uint64_t now = RR->node->now(); Address ztFinalDest(ztDest); int localCapabilityIndex = -1; - bool accept = false; + int accept = 0; + Trace::RuleResultLog rrl,crrl; + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; Mutex::Lock _l(_lock); Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0; - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - switch(_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { + switch(_doZtFilter(RR,rrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { - case DOZTFILTER_NO_MATCH: + case DOZTFILTER_NO_MATCH: { for(unsigned int c=0;c<_config.capabilityCount;++c) { ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match Address cc2; unsigned int ccLength2 = 0; bool ccWatch2 = false; - switch (_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) { + switch (_doZtFilter(RR,crrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side + case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side in capabilities localCapabilityIndex = (int)c; - accept = true; + accept = 1; if ((!noTee)&&(cc2)) { Membership &m2 = _membership(cc2); @@ -809,15 +644,20 @@ bool Network::filterOutgoingPacket( if (accept) break; } - break; + } break; case DOZTFILTER_DROP: + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side - accept = true; + accept = 1; + break; + + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; break; } @@ -854,11 +694,17 @@ bool Network::filterOutgoingPacket( outp.compress(); RR->sw->send(tPtr,outp,true); + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; // DROP locally, since we redirected } else { + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); return true; } } else { + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; } } @@ -875,26 +721,27 @@ int Network::filterIncomingPacket( const unsigned int vlanId) { Address ztFinalDest(ztDest); + Trace::RuleResultLog rrl,crrl; int accept = 0; + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; + const Capability *c = (Capability *)0; Mutex::Lock _l(_lock); Membership &membership = _membership(sourcePeer->address()); - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - switch (_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { + switch (_doZtFilter(RR,rrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { case DOZTFILTER_NO_MATCH: { Membership::CapabilityIterator mci(membership,_config); - const Capability *c; while ((c = mci.next())) { ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match Address cc2; unsigned int ccLength2 = 0; bool ccWatch2 = false; - switch(_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) { + switch(_doZtFilter(RR,crrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; @@ -927,6 +774,8 @@ int Network::filterIncomingPacket( } break; case DOZTFILTER_DROP: + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -966,10 +815,14 @@ int Network::filterIncomingPacket( outp.compress(); RR->sw->send(tPtr,outp,true); + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP locally, since we redirected } } + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); return accept; } @@ -1025,15 +878,10 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add totalLength = chunk.at(ptr); ptr += 4; chunkIndex = chunk.at(ptr); ptr += 4; - if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end - TRACE("discarded chunk from %s: invalid length or length overflow",source.toString().c_str()); + if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) // >= since we need room for a null at the end return 0; - } - - if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: unrecognized signature type",source.toString().c_str()); + if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) return 0; - } const uint8_t *sig = reinterpret_cast(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN)); // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use @@ -1058,14 +906,10 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add // If it's not a duplicate, check chunk signature const Identity controllerId(RR->topology->getIdentity(tPtr,controller())); - if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? - TRACE("unable to verify chunk from %s: don't have controller identity",source.toString().c_str()); + if (!controllerId) // we should always have the controller identity by now, otherwise how would we have queried it the first time? return 0; - } - if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: signature check failed",source.toString().c_str()); + if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) return 0; - } // New properly verified chunks can be flooded "virally" through the network if (fastPropagate) { @@ -1095,7 +939,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add c = &(_incomingConfigChunks[i]); } } else { - TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); + // Single-chunk unsigned legacy configs are only allowed from the controller itself return 0; } @@ -1188,9 +1032,7 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD } return 2; // OK and configuration has changed - } catch ( ... ) { - TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); - } + } catch ( ... ) {} // ignore invalid configs return 0; } @@ -1293,6 +1135,8 @@ void Network::requestConfiguration(void *tPtr) rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); + RR->t->networkConfigRequestSent(*this,ctrl); + if (ctrl == RR->identity.address()) { if (RR->localNetworkController) { RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd); @@ -1302,8 +1146,6 @@ void Network::requestConfiguration(void *tPtr) return; } - TRACE("requesting netconf for network %.16llx from controller %s",(unsigned long long)_id,ctrl.toString().c_str()); - Packet outp(ctrl,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append((uint64_t)_id); const unsigned int rmdSize = rmd.sizeBytes(); @@ -1337,9 +1179,7 @@ bool Network::gate(void *tPtr,const SharedPtr &peer) return true; } } - } catch ( ... ) { - TRACE("gate() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); - } + } catch ( ... ) {} return false; } diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index e5929923..0bf4bc19 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -47,6 +47,7 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; @@ -217,6 +218,7 @@ bool NetworkConfig::fromDictionary(const DictionaryremoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET); this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index fdd078d5..8b3b3619 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -159,6 +159,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_REVISION "r" // address of member #define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id" +// remote trace target +#define ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET "tt" // flags(hex) #define ZT_NETWORKCONFIG_DICT_KEY_FLAGS "f" // integer(hex) @@ -462,6 +464,11 @@ public: */ Address issuedTo; + /** + * If non-NULL, remote traces related to this network are sent here + */ + Address remoteTraceTarget; + /** * Flags (64-bit) */ diff --git a/node/Node.cpp b/node/Node.cpp index e28accee..c54ca450 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,6 +46,7 @@ #include "Identity.hpp" #include "SelfAwareness.hpp" #include "Network.hpp" +#include "Trace.hpp" namespace ZeroTier { @@ -108,6 +109,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } try { + RR->t = new Trace(RR); RR->sw = new Switch(RR); RR->mc = new Multicaster(RR); RR->topology = new Topology(RR,tptr); @@ -133,6 +135,7 @@ Node::~Node() delete RR->topology; delete RR->mc; delete RR->sw; + delete RR->t; } ZT_ResultCode Node::processWirePacket( diff --git a/node/Node.hpp b/node/Node.hpp index 40903f7c..57b99fe9 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -48,13 +48,6 @@ #include "NetworkController.hpp" #include "Hashtable.hpp" -#undef TRACE -#ifdef ZT_TRACE -#define TRACE(f,...) RR->node->postTrace(__FILE__,__LINE__,f,##__VA_ARGS__) -#else -#define TRACE(f,...) {} -#endif - // Bit mask for "expecting reply" hash #define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 #define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index a2341ffd..04ba2c2a 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -65,18 +65,6 @@ void OutboundMulticast::init( if (gatherLimit) flags |= 0x02; - /* - TRACE(">>MC %.16llx INIT %.16llx/%s limit %u gatherLimit %u from %s to %s length %u", - (unsigned long long)this, - nwid, - dest.toString().c_str(), - limit, - gatherLimit, - (src) ? src.toString().c_str() : MAC(RR->identity.address(),nwid).toString().c_str(), - dest.toString().c_str(), - len); - */ - _packet.setSource(RR->identity.address()); _packet.setVerb(Packet::VERB_MULTICAST_FRAME); _packet.append((uint64_t)nwid); @@ -98,7 +86,6 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const A const SharedPtr nw(RR->node->network(_nwid)); const Address toAddr2(toAddr); if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { - //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr2); RR->node->expectReplyTo(_packet.packetId()); diff --git a/node/Packet.cpp b/node/Packet.cpp index 6e1b36ac..d3f7dfd6 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1061,50 +1061,6 @@ static inline int LZ4_decompress_safe(const char* source, char* dest, int compre const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -#ifdef ZT_TRACE - -const char *Packet::verbString(Verb v) -{ - switch(v) { - case VERB_NOP: return "NOP"; - case VERB_HELLO: return "HELLO"; - case VERB_ERROR: return "ERROR"; - case VERB_OK: return "OK"; - case VERB_WHOIS: return "WHOIS"; - case VERB_RENDEZVOUS: return "RENDEZVOUS"; - case VERB_FRAME: return "FRAME"; - case VERB_EXT_FRAME: return "EXT_FRAME"; - case VERB_ECHO: return "ECHO"; - case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; - case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; - case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; - case VERB_NETWORK_CONFIG: return "NETWORK_CONFIG"; - case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; - case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; - case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; - case VERB_USER_MESSAGE: return "USER_MESSAGE"; - } - return "(unknown)"; -} - -const char *Packet::errorString(ErrorCode e) -{ - switch(e) { - case ERROR_NONE: return "NONE"; - case ERROR_INVALID_REQUEST: return "INVALID_REQUEST"; - case ERROR_BAD_PROTOCOL_VERSION: return "BAD_PROTOCOL_VERSION"; - case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; - case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; - case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; - case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; - case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; - case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; - } - return "(unknown)"; -} - -#endif // ZT_TRACE - void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) { uint8_t mangledKey[32]; diff --git a/node/Packet.hpp b/node/Packet.hpp index a76d4180..4941e96a 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -42,12 +42,6 @@ #include "Utils.hpp" #include "Buffer.hpp" -//#ifdef ZT_USE_SYSTEM_LZ4 -//#include -//#else -//#include "../ext/lz4/lz4.h" -//#endif - /** * Protocol version -- incremented only for major changes * @@ -969,7 +963,27 @@ public: * ZeroTier, Inc. itself. We recommend making up random ones for your own * implementations. */ - VERB_USER_MESSAGE = 0x14 + VERB_USER_MESSAGE = 0x14, + + /** + * A trace for remote debugging or diagnostics: + * <[8] 64-bit instance ID> + * <[2] 16-bit length of Dictionary> + * <[...] dictionary containing trace information> + * + * This message contains a remote trace event. Remote trace events can + * be sent to observers configured at the network level for those that + * pertain directly to actiity on a network, or to global observers if + * locally configured. + * + * The instance ID is a random 64-bit value generated by each ZeroTier + * node on startup. This is helpful in identifying traces from different + * members of a cluster. + * + * The Dictionary serialization format is the same as used for network + * configurations. The maximum size of a trace is 10000 bytes. + */ + VERB_REMOTE_TRACE = 0x15 }; /** @@ -1005,11 +1019,6 @@ public: ERROR_UNWANTED_MULTICAST = 0x08 }; -#ifdef ZT_TRACE - static const char *verbString(Verb v); - static const char *errorString(ErrorCode e); -#endif - template Packet(const Buffer &b) : Buffer(b) diff --git a/node/Peer.cpp b/node/Peer.cpp index e16540b3..79a4bc90 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -33,6 +33,7 @@ #include "Network.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" +#include "Trace.hpp" namespace ZeroTier { @@ -168,22 +169,25 @@ void Peer::received( if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) { Mutex::Lock _l(_paths_m); - _PeerPath *potentialNewPeerPath = (_PeerPath *)0; + + _PeerPath *replacablePath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { if ( ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) && ( (now - _v4Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - potentialNewPeerPath = &_v4Path; + replacablePath = &_v4Path; } } else if (path->address().ss_family == AF_INET6) { if ( ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) && ( (now - _v6Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - potentialNewPeerPath = &_v6Path; + replacablePath = &_v6Path; } } - if (potentialNewPeerPath) { + + if (replacablePath) { if (verb == Packet::VERB_OK) { - potentialNewPeerPath->lr = now; - potentialNewPeerPath->p = path; + RR->t->peerLearnedNewPath(*this,replacablePath->p,path,packetId); + replacablePath->lr = now; + replacablePath->p = path; } else { - TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); + RR->t->peerConfirmingUnknownPath(*this,path,packetId,verb); attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } @@ -211,16 +215,6 @@ void Peer::received( } if (pathsToPush.size() > 0) { -#ifdef ZT_TRACE - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); -#endif - std::vector::const_iterator p(pathsToPush.begin()); while (p != pathsToPush.end()) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); @@ -424,16 +418,27 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now) { - Mutex::Lock _l(_paths_m); - SharedPtr p(RR->topology->getPath(localSocket,remoteAddress)); - attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,p->nextOutgoingCounter()); - if (remoteAddress.ss_family == AF_INET) { - _v4Path.p = p; - _v4Path.sticky = now; - } else if (remoteAddress.ss_family == AF_INET6) { - _v6Path.p = p; - _v6Path.sticky = now; + if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check + return; + + SharedPtr op; + SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); + + { + Mutex::Lock _l(_paths_m); + if (remoteAddress.ss_family == AF_INET) { + op = _v4Path.p; + _v4Path.p = np; + _v4Path.sticky = now; + } else if (remoteAddress.ss_family == AF_INET6) { + op = _v6Path.p; + _v6Path.p = np; + _v6Path.sticky = now; + } } + + RR->t->peerRedirected(*this,op,np); } } // namespace ZeroTier diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 94b96d34..0bb78599 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -42,7 +42,7 @@ class Node; class Multicaster; class NetworkController; class SelfAwareness; -class Cluster; +class Trace; /** * Holds global state for an instance of ZeroTier::Node @@ -93,6 +93,7 @@ public: * These are constant and never null after startup unless indicated. */ + Trace *t; Switch *sw; Multicaster *mc; Topology *topology; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 3e3397f5..173230fb 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -39,6 +39,7 @@ #include "Packet.hpp" #include "Peer.hpp" #include "Switch.hpp" +#include "Trace.hpp" // Entry timeout -- make it fairly long since this is just to prevent stale buildup #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 @@ -81,7 +82,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope - TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str()); + RR->t->resettingPathsInScope(reporter,reporterPhysicalAddress,myPhysicalAddress,scope); entry.mySurface = myPhysicalAddress; entry.ts = now; diff --git a/node/Switch.cpp b/node/Switch.cpp index a77ca89e..2fbd243b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -43,26 +43,10 @@ #include "Peer.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" +#include "Trace.hpp" namespace ZeroTier { -#ifdef ZT_TRACE -static const char *etherTypeName(const unsigned int etherType) -{ - switch(etherType) { - case ZT_ETHERTYPE_IPV4: return "IPV4"; - case ZT_ETHERTYPE_ARP: return "ARP"; - case ZT_ETHERTYPE_RARP: return "RARP"; - case ZT_ETHERTYPE_ATALK: return "ATALK"; - case ZT_ETHERTYPE_AARP: return "AARP"; - case ZT_ETHERTYPE_IPX_A: return "IPX_A"; - case ZT_ETHERTYPE_IPX_B: return "IPX_B"; - case ZT_ETHERTYPE_IPV6: return "IPV6"; - } - return "UNKNOWN"; -} -#endif // ZT_TRACE - Switch::Switch(const RuntimeEnvironment *renv) : RR(renv), _lastBeaconResponse(0), @@ -123,8 +107,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if (relayTo) relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); } - } else { - TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); } } else { // Fragment looks like ours @@ -143,7 +125,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((!rq->timestamp)||(rq->packetId != fragmentPacketId)) { // No packet found, so we received a fragment without its head. - //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str()); rq->timestamp = now; rq->packetId = fragmentPacketId; @@ -153,14 +134,12 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre rq->complete = false; } else if (!(rq->haveFragments & (1 << fragmentNumber))) { // We have other fragments and maybe the head, so add this one and check - //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str()); rq->frags[fragmentNumber - 1] = fragment; rq->totalFragments = totalFragments; if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) { // We have all fragments -- assemble and process full Packet - //TRACE("packet %.16llx is complete, assembling and processing...",fragmentPacketId); for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); @@ -182,8 +161,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre const Address destination(reinterpret_cast(data) + 8,ZT_ADDRESS_LENGTH); const Address source(reinterpret_cast(data) + 13,ZT_ADDRESS_LENGTH); - //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); - if (source == RR->identity.address()) return; @@ -258,8 +235,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if (relayTo) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } - } else { - TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); } } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { // Packet is the head of a fragmented packet series @@ -280,7 +255,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((!rq->timestamp)||(rq->packetId != packetId)) { // If we have no other fragments yet, create an entry and save the head - //TRACE("fragment (0/?) of %.16llx from %s",pid,fromAddr.toString().c_str()); rq->timestamp = now; rq->packetId = packetId; @@ -293,7 +267,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) { // We have all fragments -- assemble and process full Packet - //TRACE("packet %.16llx is complete, assembling and processing...",pid); rq->frag0.init(data,len,path,now); for(unsigned int f=1;ftotalFragments;++f) @@ -333,11 +306,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre // -------------------------------------------------------------------- } } - } catch (std::exception &ex) { - TRACE("dropped packet from %s: unexpected exception: %s",fromAddr.toString().c_str(),ex.what()); - } catch ( ... ) { - TRACE("dropped packet from %s: unexpected exception: (unknown)",fromAddr.toString().c_str()); - } + } catch ( ... ) {} // sanity check, should be caught elsewhere } void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) @@ -349,7 +318,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const bool fromBridged; if ((fromBridged = (from != network->mac()))) { if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("%.16llx: %s -> %s %s not forwarded, bridging disabled or this peer not a bridge",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"not a bridge"); return; } } @@ -371,7 +340,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them - TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"broadcast disabled"); return; } } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { @@ -424,7 +393,6 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const if ((v6EmbeddedAddress)&&(v6EmbeddedAddress != RR->identity.address())) { const MAC peerMac(v6EmbeddedAddress,network->id()); - TRACE("IPv6 NDP emulation: %.16llx: forging response for %s/%s",network->id(),v6EmbeddedAddress.toString().c_str(),peerMac.toString().c_str()); uint8_t adv[72]; adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00; @@ -460,7 +428,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // Check this after NDP emulation, since that has to be allowed in exactly this case if (network->config().multicastLimit == 0) { - TRACE("%.16llx: dropped multicast: not allowed on network",network->id()); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"multicast disabled"); return; } @@ -471,11 +439,9 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const if (fromBridged) network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now()); - //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); - // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -501,7 +467,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -526,7 +492,6 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const send(tPtr,outp,true); } - //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); } else { // Destination is bridged behind a remote peer @@ -534,7 +499,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // for each ZT destination are also done below. This is the same rationale // and design as for multicast. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -583,7 +548,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const outp.compress(); send(tPtr,outp,true); } else { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); } } } @@ -591,11 +556,8 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const void Switch::send(void *tPtr,Packet &packet,bool encrypt) { - if (packet.destination() == RR->identity.address()) { - TRACE("BUG: caught attempt to send() to self, ignored"); + if (packet.destination() == RR->identity.address()) return; - } - if (!_trySend(tPtr,packet,encrypt)) { Mutex::Lock _l(_txQueue_m); _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); @@ -604,13 +566,8 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) void Switch::requestWhois(void *tPtr,const Address &addr) { -#ifdef ZT_TRACE - if (addr == RR->identity.address()) { - fprintf(stderr,"FATAL BUG: Switch::requestWhois() caught attempt to WHOIS self" ZT_EOL_S); - abort(); - } -#endif - + if (addr == RR->identity.address()) + return; bool inserted = false; { Mutex::Lock _l(_outstandingWhoisRequests_m); @@ -670,12 +627,10 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) const unsigned long since = (unsigned long)(now - r->lastSent); if (since >= ZT_WHOIS_RETRY_DELAY) { if (r->retries >= ZT_MAX_WHOIS_RETRIES) { - TRACE("WHOIS %s timed out",a->toString().c_str()); _outstandingWhoisRequests.erase(*a); } else { r->lastSent = now; r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); - TRACE("WHOIS %s (retry %u)",a->toString().c_str(),r->retries); ++r->retries; nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); } @@ -691,7 +646,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); + RR->t->txTimedOut(txi->dest); _txQueue.erase(txi++); } else ++txi; } diff --git a/node/Topology.cpp b/node/Topology.cpp index e7bbdfae..edca0180 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -90,11 +90,6 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { -#ifdef ZT_TRACE - if ((!peer)||(peer->address() == RR->identity.address())) - return SharedPtr(); -#endif - SharedPtr np; { Mutex::Lock _l(_peers_m); @@ -103,16 +98,13 @@ SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) hp = peer; np = hp; } - return np; } SharedPtr Topology::getPeer(void *tPtr,const Address &zta) { - if (zta == RR->identity.address()) { - TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); + if (zta == RR->identity.address()) return SharedPtr(); - } { Mutex::Lock _l(_peers_m); diff --git a/node/Topology.hpp b/node/Topology.hpp index 5f3e2da1..30e58abc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -330,12 +330,6 @@ public: Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { -#ifdef ZT_TRACE - if (!(*p)) { - fprintf(stderr,"FATAL BUG: eachPeer() caught NULL peer for %s -- peer pointers in Topology should NEVER be NULL" ZT_EOL_S,a->toString().c_str()); - abort(); - } -#endif f(*this,*((const SharedPtr *)p)); } } diff --git a/node/Trace.cpp b/node/Trace.cpp new file mode 100644 index 00000000..6b68cfe7 --- /dev/null +++ b/node/Trace.cpp @@ -0,0 +1,197 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "Trace.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Node.hpp" +#include "Utils.hpp" + +namespace ZeroTier { + +#ifdef ZT_TRACE +static const char *packetVerbString(Packet::Verb v) +{ + switch(v) { + case Packet::VERB_NOP: return "NOP"; + case Packet::VERB_HELLO: return "HELLO"; + case Packet::Packet::VERB_ERROR: return "ERROR"; + case Packet::VERB_OK: return "OK"; + case Packet::VERB_WHOIS: return "WHOIS"; + case Packet::VERB_RENDEZVOUS: return "RENDEZVOUS"; + case Packet::VERB_FRAME: return "FRAME"; + case Packet::VERB_EXT_FRAME: return "EXT_FRAME"; + case Packet::VERB_ECHO: return "ECHO"; + case Packet::VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; + case Packet::VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; + case Packet::VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; + case Packet::VERB_NETWORK_CONFIG: return "NETWORK_CONFIG"; + case Packet::VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; + case Packet::VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; + case Packet::VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; + case Packet::VERB_USER_MESSAGE: return "USER_MESSAGE"; + case Packet::VERB_REMOTE_TRACE: return "REMOTE_TRACE"; + } + return "(unknown)"; +} + +static const char *packetErrorString(Packet::ErrorCode e) +{ + switch(e) { + case Packet::ERROR_NONE: return "NONE"; + case Packet::ERROR_INVALID_REQUEST: return "INVALID_REQUEST"; + case Packet::ERROR_BAD_PROTOCOL_VERSION: return "BAD_PROTOCOL_VERSION"; + case Packet::ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; + case Packet::ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; + case Packet::ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; + case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; + case Packet::ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; + case Packet::ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; + } + return "(unknown)"; +} +#endif + +void Trace::resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) +{ +} + +void Trace::txTimedOut(const Address &destination) +{ +} + +void Trace::peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) +{ +} + +void Trace::peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) +{ +} + +void Trace::peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) +{ +} + +void Trace::outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) +{ +} + +void Trace::incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) +{ +} + +void Trace::incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source) +{ +} + +void Trace::incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason) +{ +} + +void Trace::incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) +{ +} + +void Trace::networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) +{ +} + +void Trace::networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) +{ +} + +void Trace::networkConfigRequestSent(const Network &network,const Address &controller) +{ +} + +void Trace::networkFilter( + const Network &network, + const RuleResultLog &primaryRuleSetLog, + const RuleResultLog *const matchingCapabilityRuleSetLog, + const Capability *const matchingCapability, + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const bool noTee, + const bool inbound, + const int accept) +{ +} + +void Trace::credentialRejected(const CertificateOfMembership &c,const char *reason) +{ +} + +void Trace::credentialRejected(const CertificateOfOwnership &c,const char *reason) +{ +} + +void Trace::credentialRejected(const CertificateOfRepresentation &c,const char *reason) +{ +} + +void Trace::credentialRejected(const Capability &c,const char *reason) +{ +} + +void Trace::credentialRejected(const Tag &c,const char *reason) +{ +} + +void Trace::credentialRejected(const Revocation &c,const char *reason) +{ +} + +void Trace::credentialAccepted(const CertificateOfMembership &c) +{ +} + +void Trace::credentialAccepted(const CertificateOfOwnership &c) +{ +} + +void Trace::credentialAccepted(const CertificateOfRepresentation &c) +{ +} + +void Trace::credentialAccepted(const Capability &c) +{ +} + +void Trace::credentialAccepted(const Tag &c) +{ +} + +void Trace::credentialAccepted(const Revocation &c) +{ +} + +} // namespace ZeroTier diff --git a/node/Trace.hpp b/node/Trace.hpp new file mode 100644 index 00000000..65d1acf1 --- /dev/null +++ b/node/Trace.hpp @@ -0,0 +1,157 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_TRACE_HPP +#define ZT_TRACE_HPP + +#include +#include +#include +#include + +#include "../include/ZeroTierOne.h" + +#include "Constants.hpp" +#include "SharedPtr.hpp" +#include "Packet.hpp" +#include "Credential.hpp" +#include "InetAddress.hpp" + +namespace ZeroTier { + +class RuntimeEnvironment; +class Address; +class Identity; +class Peer; +class Path; +class Network; +class NetworkConfig; +class MAC; +class CertificateOfMembership; +class CertificateOfOwnership; +class CertificateOfRepresentation; +class Revocation; +class Tag; +class Capability; + +/** + * Remote tracing and trace logging handler + */ +class Trace +{ +public: + /** + * Filter rule evaluation result log + * + * Each rule in a rule set gets a four-bit log entry. A log entry + * of zero means not evaluated. Otherwise each four-bit log entry + * contains two two-bit values of 01 for 'false' and 10 for 'true'. + * As with four-bit rules an 00 value here means this was not + * evaluated or was not relevant. + */ + class RuleResultLog + { + public: + RuleResultLog() {} + + inline void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches) + { + _l[rn >> 1] |= ( ((thisRuleMatches + 1) << 2) | (thisSetMatches + 1) ) << ((rn & 1) << 2); + } + inline void logSkipped(const unsigned int rn,const uint8_t thisSetMatches) + { + _l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2); + } + + inline void clear() + { + memset(_l,0,sizeof(_l)); + } + + inline const uint8_t *data() const { return _l; } + inline unsigned int sizeBytes() const { return (unsigned int)sizeof(_l); } + + private: + uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; + }; + + Trace(const RuntimeEnvironment *renv) : RR(renv) {} + + void resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); + void txTimedOut(const Address &destination); + + void peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); + void peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); + void peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); + + void outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); + + void incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); + void incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source); + void incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason); + void incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); + + void networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); + void networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); + + void networkConfigRequestSent(const Network &network,const Address &controller); + void networkFilter( + const Network &network, + const RuleResultLog &primaryRuleSetLog, + const RuleResultLog *const matchingCapabilityRuleSetLog, + const Capability *const matchingCapability, + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const bool noTee, + const bool inbound, + const int accept); + + void credentialRejected(const CertificateOfMembership &c,const char *reason); + void credentialRejected(const CertificateOfOwnership &c,const char *reason); + void credentialRejected(const CertificateOfRepresentation &c,const char *reason); + void credentialRejected(const Capability &c,const char *reason); + void credentialRejected(const Tag &c,const char *reason); + void credentialRejected(const Revocation &c,const char *reason); + void credentialAccepted(const CertificateOfMembership &c); + void credentialAccepted(const CertificateOfOwnership &c); + void credentialAccepted(const CertificateOfRepresentation &c); + void credentialAccepted(const Capability &c); + void credentialAccepted(const Tag &c); + void credentialAccepted(const Revocation &c); + +private: + const RuntimeEnvironment *const RR; +}; + +} // namespace ZeroTier + +#endif diff --git a/objects.mk b/objects.mk index 3a8bd645..ed396378 100644 --- a/objects.mk +++ b/objects.mk @@ -23,6 +23,7 @@ CORE_OBJS=\ node/Switch.o \ node/Tag.o \ node/Topology.o \ + node/Trace.o \ node/Utils.o ONE_OBJS=\ -- cgit v1.2.3 From 495c5ce81ddb245e21f21325927236d0f666f6cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 13 Jul 2017 10:51:05 -0700 Subject: Bunch of remote tracing work. --- node/Dictionary.hpp | 29 ++++ node/Identity.cpp | 2 +- node/IncomingPacket.cpp | 180 ++++++++++++------------ node/Membership.cpp | 22 +-- node/Membership.hpp | 5 + node/Network.cpp | 23 ++-- node/Network.hpp | 13 ++ node/Node.cpp | 7 +- node/Node.hpp | 3 + node/Packet.hpp | 5 +- node/Peer.cpp | 9 +- node/Peer.hpp | 4 +- node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 16 +-- node/Trace.cpp | 353 ++++++++++++++++++++++++++++++++++++++++++++---- node/Trace.hpp | 57 ++++---- 16 files changed, 552 insertions(+), 178 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 6cbbfc0e..061dcac1 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -288,6 +288,21 @@ public: return dfl; } + /** + * Get an unsigned int64 stored as hex in the dictionary + * + * @param key Key to look up + * @param dfl Default value or 0 if unspecified + * @return Decoded hex UInt value or 'dfl' if not found + */ + inline int64_t getI(const char *key,int64_t dfl = 0) const + { + char tmp[128]; + if (this->get(key,tmp,sizeof(tmp)) >= 1) + return Utils::hexStrTo64(tmp); + return dfl; + } + /** * Add a new key=value pair * @@ -394,6 +409,20 @@ public: return this->add(key,Utils::hex(value,tmp),-1); } + /** + * Add a 64-bit integer (unsigned) as a hex value + */ + inline bool add(const char *key,int64_t value) + { + char tmp[32]; + if (value >= 0) { + return this->add(key,Utils::hex((uint64_t)value,tmp),-1); + } else { + tmp[0] = '-'; + return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1); + } + } + /** * Add a 64-bit integer (unsigned) as a hex value */ diff --git a/node/Identity.cpp b/node/Identity.cpp index 3b00b4c0..dba27d1c 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -151,7 +151,7 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_ Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p); p += ZT_C25519_PRIVATE_KEY_LEN * 2; } - *(p++) = (char)0; + *p = (char)0; return buf; } diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e1fb180c..a5875d1e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -66,10 +66,10 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // packets are dropped on the floor. const uint64_t tpid = trustedPathId(); if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { - RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,true); + RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,true); trusted = true; } else { - RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,false); + RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,false); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -82,14 +82,14 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (!trusted) { if (!dearmor(peer->key())) { //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); - RR->t->incomingPacketMessageAuthenticationFailure(_path,packetId(),sourceAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops()); return true; } } if (!uncompress()) { //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); - RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"LZ4 decompression failed"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),Packet::VERB_NOP,"LZ4 decompression failed"); return true; } @@ -97,7 +97,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,0); return true; case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true); @@ -122,7 +122,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) return false; } } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"unexpected exception in tryDecode() (outer)"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode() (outer)"); return true; } } @@ -133,6 +133,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; + uint64_t networkId = 0; /* Security note: we do not gate doERROR() with expectingReplyTo() to * avoid having to log every outgoing packet ID. Instead we put the @@ -170,7 +171,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { // Peers can send this in response to frames if they do not have a recent enough COM from us - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); const uint64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(tPtr,peer->address(),now); @@ -186,7 +188,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar case Packet::ERROR_UNWANTED_MULTICAST: { // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); if ((network)&&(network->gate(tPtr,peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); RR->mc->remove(network->id(),mg,peer->address()); @@ -196,9 +199,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar default: break; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ERROR,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_ERROR,"unexpected exception"); } return true; } @@ -219,11 +222,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); if (protoVersion < ZT_PROTO_VERSION_MIN) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"protocol version too old"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"protocol version too old"); return true; } if (fromAddress != id.address()) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"identity/address mismatch"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"identity/address mismatch"); return true; } @@ -241,7 +244,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"address collision"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"address collision"); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); @@ -249,10 +252,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); } } else { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); } return true; @@ -260,7 +263,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); return true; } @@ -272,26 +275,26 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Sanity check: this basically can't happen if (alreadyAuthenticated) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"illegal alreadyAuthenticated state"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"illegal alreadyAuthenticated state"); return true; } // Check rate limits if (!RR->node->rateGateIdentityVerification(now,_path->address())) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"rate limit exceeded"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"rate limit exceeded"); return true; } // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); return true; } // Check that identity's address is valid as per the derivation function if (!id.locallyValidate()) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"invalid identity"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"invalid identity"); return true; } @@ -414,9 +417,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_HELLO,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_HELLO,"unexpected exception"); } return true; } @@ -426,6 +429,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + uint64_t networkId = 0; if (!RR->node->expectingReplyTo(inRePacketId)) return true; @@ -491,27 +495,28 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); + networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); if (network) network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; case Packet::VERB_MULTICAST_GATHER: { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); + networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(networkId)); if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } } break; case Packet::VERB_MULTICAST_FRAME: { const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); + networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - const SharedPtr network(RR->node->network(nwid)); + const SharedPtr network(RR->node->network(networkId)); if (network) { unsigned int offset = 0; @@ -527,7 +532,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; unsigned int totalKnown = at(offset); offset += 4; unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -535,9 +540,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP default: break; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_OK,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_OK,"unexpected exception"); } return true; } @@ -573,9 +578,9 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_WHOIS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_WHOIS,"unexpected exception"); } return true; } @@ -599,9 +604,9 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const } } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_RENDEZVOUS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_RENDEZVOUS,"unexpected exception"); } return true; } @@ -625,14 +630,14 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar } } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); } } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_FRAME,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_FRAME,"unexpected exception"); } return true; } @@ -654,9 +659,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const } if (!network->gate(tPtr,peer)) { - RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } @@ -668,7 +673,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); if ((!from)||(from == network->mac())) { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } @@ -678,20 +683,20 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } @@ -711,12 +716,12 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); } else { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); } } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_EXT_FRAME,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_EXT_FRAME,"unexpected exception"); } return true; } @@ -736,9 +741,9 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ECHO,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_ECHO,"unexpected exception"); } return true; } @@ -784,9 +789,9 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); } return true; } @@ -803,12 +808,13 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t Revocation revocation; CertificateOfOwnership coo; bool trustEstablished = false; + SharedPtr network; unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p] != 0)) { p += com.deserialize(*this,p); if (com) { - const SharedPtr network(RR->node->network(com.networkId())); + network = RR->node->network(com.networkId()); if (network) { switch (network->addCredential(tPtr,com)) { case Membership::ADD_REJECTED: @@ -829,7 +835,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(cap.networkId())); + if ((!network)||(network->id() != cap.networkId())) + network = RR->node->network(cap.networkId()); if (network) { switch (network->addCredential(tPtr,cap)) { case Membership::ADD_REJECTED: @@ -849,7 +856,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(tag.networkId())); + if ((!network)||(network->id() != tag.networkId())) + network = RR->node->network(tag.networkId()); if (network) { switch (network->addCredential(tPtr,tag)) { case Membership::ADD_REJECTED: @@ -869,7 +877,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numRevocations = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(revocation.networkId())); + if ((!network)||(network->id() != revocation.networkId())) + network = RR->node->network(revocation.networkId()); if (network) { switch(network->addCredential(tPtr,peer->address(),revocation)) { case Membership::ADD_REJECTED: @@ -889,7 +898,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numCoos = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(coo.networkId())); + if ((!network)||(network->id() != coo.networkId())) + network = RR->node->network(coo.networkId()); if (network) { switch(network->addCredential(tPtr,coo)) { case Membership::ADD_REJECTED: @@ -905,9 +915,9 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); } return true; } @@ -934,9 +944,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); } return true; } @@ -957,9 +967,9 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); } return true; } @@ -1003,9 +1013,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); } return true; } @@ -1030,9 +1040,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } if (!network->gate(tPtr,peer)) { - RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } @@ -1055,20 +1065,20 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); if (network->config().multicastLimit == 0) { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { if (!to.mac().isMulticast()) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } @@ -1076,8 +1086,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } @@ -1101,13 +1111,13 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); } } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); } return true; } @@ -1119,7 +1129,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); return true; } @@ -1172,9 +1182,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt ptr += addrLen; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); } return true; } @@ -1190,9 +1200,9 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_USER_MESSAGE,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_USER_MESSAGE,"unexpected exception"); } return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index be6ea6a5..a1453307 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -129,13 +129,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme { const uint64_t newts = com.timestamp(); if (newts <= _comRevocationThreshold) { - RR->t->credentialRejected(com,"revoked"); + RR->t->credentialRejected(tPtr,com,"revoked"); return ADD_REJECTED; } const uint64_t oldts = _com.timestamp(); if (newts < oldts) { - RR->t->credentialRejected(com,"old"); + RR->t->credentialRejected(tPtr,com,"old"); return ADD_REJECTED; } if ((newts == oldts)&&(_com == com)) @@ -143,11 +143,11 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(com.verify(RR,tPtr)) { default: - RR->t->credentialRejected(com,"invalid"); + RR->t->credentialRejected(tPtr,com,"invalid"); return ADD_REJECTED; case 0: _com = com; - RR->t->credentialAccepted(com); + RR->t->credentialAccepted(tPtr,com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -161,7 +161,7 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot C *rc = remoteCreds.get(cred.id()); if (rc) { if (rc->timestamp() > cred.timestamp()) { - RR->t->credentialRejected(cred,"old"); + RR->t->credentialRejected(tPtr,cred,"old"); return Membership::ADD_REJECTED; } if (*rc == cred) @@ -170,16 +170,16 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot const uint64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); if ((rt)&&(*rt >= cred.timestamp())) { - RR->t->credentialRejected(cred,"revoked"); + RR->t->credentialRejected(tPtr,cred,"revoked"); return Membership::ADD_REJECTED; } switch(cred.verify(RR,tPtr)) { default: - RR->t->credentialRejected(cred,"invalid"); + RR->t->credentialRejected(tPtr,cred,"invalid"); return Membership::ADD_REJECTED; case 0: - RR->t->credentialAccepted(cred); + RR->t->credentialAccepted(tPtr,cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -198,14 +198,14 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme uint64_t *rt; switch(rev.verify(RR,tPtr)) { default: - RR->t->credentialRejected(rev,"invalid"); + RR->t->credentialRejected(tPtr,rev,"invalid"); return ADD_REJECTED; case 0: { const Credential::Type ct = rev.type(); switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { - RR->t->credentialAccepted(rev); + RR->t->credentialAccepted(tPtr,rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } @@ -221,7 +221,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } return ADD_ACCEPTED_REDUNDANT; default: - RR->t->credentialRejected(rev,"invalid"); + RR->t->credentialRejected(tPtr,rev,"invalid"); return ADD_REJECTED; } } diff --git a/node/Membership.hpp b/node/Membership.hpp index 5e4475da..c6e2b803 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -110,6 +110,11 @@ public: return nconf.com.agreesWith(_com); } + inline bool recentlyAssociated(const uint64_t now) const + { + return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); + } + /** * Check whether the peer represented by this Membership owns a given resource * diff --git a/node/Network.cpp b/node/Network.cpp index 575b0170..f7b144e3 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -648,7 +648,7 @@ bool Network::filterOutgoingPacket( case DOZTFILTER_DROP: if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -695,16 +695,16 @@ bool Network::filterOutgoingPacket( RR->sw->send(tPtr,outp,true); if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; // DROP locally, since we redirected } else { if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); + RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); return true; } } else { if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; } } @@ -775,7 +775,7 @@ int Network::filterIncomingPacket( case DOZTFILTER_DROP: if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); + RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -816,13 +816,13 @@ int Network::filterIncomingPacket( RR->sw->send(tPtr,outp,true); if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); + RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP locally, since we redirected } } if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); + RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); return accept; } @@ -1135,7 +1135,7 @@ void Network::requestConfiguration(void *tPtr) rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); - RR->t->networkConfigRequestSent(*this,ctrl); + RR->t->networkConfigRequestSent(tPtr,*this,ctrl); if (ctrl == RR->identity.address()) { if (RR->localNetworkController) { @@ -1183,6 +1183,13 @@ bool Network::gate(void *tPtr,const SharedPtr &peer) return false; } +bool Network::recentlyAssociatedWith(const Address &addr) +{ + Mutex::Lock _l(_lock); + const Membership *m = _memberships.get(addr); + return ((m)&&(m->recentlyAssociated(RR->node->now()))); +} + void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index 454a3f20..be5f1a12 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -248,6 +248,19 @@ public: */ bool gate(void *tPtr,const SharedPtr &peer); + /** + * Check whether a given peer has recently had an association with this network + * + * This checks whether a peer has communicated with us recently about this + * network and has possessed a valid certificate of membership. This may return + * true even if the peer has been offline for a while or no longer has a valid + * certificate of membership but had one recently. + * + * @param addr Peer address + * @return True if peer has recently associated + */ + bool recentlyAssociatedWith(const Address &addr); + /** * Do periodic cleanup and housekeeping tasks */ diff --git a/node/Node.cpp b/node/Node.cpp index c54ca450..073af4bd 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -90,14 +90,15 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } } - idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; if (n <= 0) { RR->identity.generate(); + idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; RR->identity.toString(false,RR->publicIdentityStr); RR->identity.toString(true,RR->secretIdentityStr); stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr)); stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr)); } else { + idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; @@ -201,7 +202,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now,0); contacted = true; break; } @@ -211,7 +212,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now,0); contacted = true; break; } diff --git a/node/Node.hpp b/node/Node.hpp index 57b99fe9..e60da1ad 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -257,6 +257,8 @@ public: virtual void ncSendRevocation(const Address &destination,const Revocation &rev); virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); + inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; } + private: RuntimeEnvironment _RR; RuntimeEnvironment *RR; @@ -278,6 +280,7 @@ private: Mutex _backgroundTasksLock; + Address _remoteTraceTarget; uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; diff --git a/node/Packet.hpp b/node/Packet.hpp index 4941e96a..a1ea73e1 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -967,9 +967,8 @@ public: /** * A trace for remote debugging or diagnostics: - * <[8] 64-bit instance ID> - * <[2] 16-bit length of Dictionary> - * <[...] dictionary containing trace information> + * <[...] null-terminated dictionary containing trace information> + * [<[...] additional null-terminated dictionaries>] * * This message contains a remote trace event. Remote trace events can * be sent to observers configured at the network level for those that diff --git a/node/Peer.cpp b/node/Peer.cpp index 79a4bc90..d362be9f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -72,7 +72,8 @@ void Peer::received( const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished) + const bool trustEstablished, + const uint64_t networkId) { const uint64_t now = RR->node->now(); @@ -183,11 +184,11 @@ void Peer::received( if (replacablePath) { if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(*this,replacablePath->p,path,packetId); + RR->t->peerLearnedNewPath(tPtr,networkId,*this,replacablePath->p,path,packetId); replacablePath->lr = now; replacablePath->p = path; } else { - RR->t->peerConfirmingUnknownPath(*this,path,packetId,verb); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } @@ -438,7 +439,7 @@ void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remo } } - RR->t->peerRedirected(*this,op,np); + RR->t->peerRedirected(tPtr,0,*this,op,np); } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index b24318ec..6d00e3e6 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -102,6 +102,7 @@ public: * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established + * @param networkId Network ID if this pertains to a network, or 0 otherwise */ void received( void *tPtr, @@ -111,7 +112,8 @@ public: const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished); + const bool trustEstablished, + const uint64_t networkId); /** * @param now Current time diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 173230fb..cdbb6303 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -82,7 +82,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope - RR->t->resettingPathsInScope(reporter,reporterPhysicalAddress,myPhysicalAddress,scope); + RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope); entry.mySurface = myPhysicalAddress; entry.ts = now; diff --git a/node/Switch.cpp b/node/Switch.cpp index 2fbd243b..eee49775 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -318,7 +318,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const bool fromBridged; if ((fromBridged = (from != network->mac()))) { if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"not a bridge"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"not a bridge"); return; } } @@ -340,7 +340,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"broadcast disabled"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"broadcast disabled"); return; } } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { @@ -428,7 +428,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // Check this after NDP emulation, since that has to be allowed in exactly this case if (network->config().multicastLimit == 0) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"multicast disabled"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"multicast disabled"); return; } @@ -441,7 +441,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -467,7 +467,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -499,7 +499,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // for each ZT destination are also done below. This is the same rationale // and design as for multicast. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -548,7 +548,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const outp.compress(); send(tPtr,outp,true); } else { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); } } } @@ -646,7 +646,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - RR->t->txTimedOut(txi->dest); + RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); } else ++txi; } diff --git a/node/Trace.cpp b/node/Trace.cpp index 6b68cfe7..dc5ecf19 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -29,16 +29,25 @@ #include "Switch.hpp" #include "Node.hpp" #include "Utils.hpp" +#include "Dictionary.hpp" +#include "CertificateOfMembership.hpp" +#include "CertificateOfOwnership.hpp" +#include "CertificateOfRepresentation.hpp" +#include "Tag.hpp" +#include "Capability.hpp" +#include "Revocation.hpp" namespace ZeroTier { +// Defining ZT_TRACE causes debug tracing messages to be dumped to stderr #ifdef ZT_TRACE + static const char *packetVerbString(Packet::Verb v) { switch(v) { case Packet::VERB_NOP: return "NOP"; case Packet::VERB_HELLO: return "HELLO"; - case Packet::Packet::VERB_ERROR: return "ERROR"; + case Packet::VERB_ERROR: return "ERROR"; case Packet::VERB_OK: return "OK"; case Packet::VERB_WHOIS: return "WHOIS"; case Packet::VERB_RENDEZVOUS: return "RENDEZVOUS"; @@ -73,61 +82,220 @@ static const char *packetErrorString(Packet::ErrorCode e) } return "(unknown)"; } -#endif -void Trace::resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) +#define TRprintf(f,...) { fprintf(stderr,(f),__VA_ARGS__); fflush(stderr); } + +#else + +#define TRprintf(f,...) + +#endif // ZT_TRACE + +#define ZT_REMOTE_TRACE_FIELD__EVENT "E" +#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "pid" +#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "pv" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "ptpid" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "ptpok" +#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "phops" +#define ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR "oldrphy" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "rzt" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "rphy" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "lzt" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "lphy" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "ls" +#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "ipsc" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "nwid" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "seth" +#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "deth" +#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "et" +#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlan" +#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "fl" +#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "fd" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credtype" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credid" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credts" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credinfo" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "crediss" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRt" +#define ZT_REMOTE_TRACE_FIELD__REASON "reason" + +#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" +#define ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT_S "1001" +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1002" +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1003" +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1004" +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1005" +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1006" +#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" + +#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" + +void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,reporter); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,reporterPhysicalAddress.toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope); + _send(tPtr,d,0); } -void Trace::txTimedOut(const Address &destination) +void Trace::txTimedOut(void *const tPtr,const Address &destination) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT_S); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,destination); + _send(tPtr,d,0); } -void Trace::peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) +void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + _send(tPtr,d,networkId); } -void Trace::peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) +void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (oldPath) { + d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); + } + if (newPath) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + } + _send(tPtr,d,networkId); } -void Trace::peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) +void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (oldPath) { + d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); + } + if (newPath) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + } + _send(tPtr,d,networkId); } -void Trace::outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) +void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) { + if (!network) return; // sanity check + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,network); } -void Trace::incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) +void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) { + if (!network) return; // sanity check + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } } -void Trace::incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source) +void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) { + //Dictionary d; + //d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); } -void Trace::incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason) +void Trace::incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) { + // TODO } -void Trace::incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) +void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + _send(tPtr,d,0); } -void Trace::networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) +void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,0); } -void Trace::networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) +void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,0); } -void Trace::networkConfigRequestSent(const Network &network,const Address &controller) +void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller) { } void Trace::networkFilter( + void *const tPtr, const Network &network, const RuleResultLog &primaryRuleSetLog, const RuleResultLog *const matchingCapabilityRuleSetLog, @@ -144,54 +312,185 @@ void Trace::networkFilter( const bool inbound, const int accept) { + //char tmp[128]; + //Dictionary d; + //_send(tPtr,d,network.id()); +} + +void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) +{ + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const CertificateOfMembership &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const CertificateOfOwnership &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const CertificateOfRepresentation &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const Capability &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const Tag &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const Revocation &c,const char *reason) +void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); } -void Trace::credentialAccepted(const CertificateOfMembership &c) +void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); } -void Trace::credentialAccepted(const CertificateOfOwnership &c) +void Trace::credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); } -void Trace::credentialAccepted(const CertificateOfRepresentation &c) +void Trace::credentialAccepted(void *const tPtr,const Capability &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); } -void Trace::credentialAccepted(const Capability &c) +void Trace::credentialAccepted(void *const tPtr,const Tag &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); } -void Trace::credentialAccepted(const Tag &c) +void Trace::credentialAccepted(void *const tPtr,const Revocation &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); } -void Trace::credentialAccepted(const Revocation &c) +void Trace::_send(void *const tPtr,const Dictionary &d) { + const Address rtt(RR->node->remoteTraceTarget()); + if (rtt) { + Packet outp(rtt,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); + } +} + +void Trace::_send(void *const tPtr,const Dictionary &d,const uint64_t networkId) +{ + _send(tPtr,d); + if (networkId) { + const SharedPtr network(RR->node->network(networkId)); + if ((network)&&(network->config().remoteTraceTarget)) { + Packet outp(network->config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); + } + } +} + +void Trace::_send(void *const tPtr,const Dictionary &d,const SharedPtr &network) +{ + _send(tPtr,d); + if ((network)&&(network->config().remoteTraceTarget)) { + Packet outp(network->config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); + } } } // namespace ZeroTier diff --git a/node/Trace.hpp b/node/Trace.hpp index 65d1acf1..eefd5359 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -39,6 +39,7 @@ #include "Packet.hpp" #include "Credential.hpp" #include "InetAddress.hpp" +#include "Dictionary.hpp" namespace ZeroTier { @@ -100,25 +101,25 @@ public: Trace(const RuntimeEnvironment *renv) : RR(renv) {} - void resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); - void txTimedOut(const Address &destination); + void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); + void txTimedOut(void *const tPtr,const Address &destination); - void peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); - void peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); - void peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); + void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); + void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); + void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); - void outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); + void incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); + void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops); + void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); + void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); - void incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); - void incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source); - void incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason); - void incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); + void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); + void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); + void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); - void networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); - void networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); - - void networkConfigRequestSent(const Network &network,const Address &controller); + void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller); void networkFilter( + void *const tPtr, const Network &network, const RuleResultLog &primaryRuleSetLog, const RuleResultLog *const matchingCapabilityRuleSetLog, @@ -135,21 +136,25 @@ public: const bool inbound, const int accept); - void credentialRejected(const CertificateOfMembership &c,const char *reason); - void credentialRejected(const CertificateOfOwnership &c,const char *reason); - void credentialRejected(const CertificateOfRepresentation &c,const char *reason); - void credentialRejected(const Capability &c,const char *reason); - void credentialRejected(const Tag &c,const char *reason); - void credentialRejected(const Revocation &c,const char *reason); - void credentialAccepted(const CertificateOfMembership &c); - void credentialAccepted(const CertificateOfOwnership &c); - void credentialAccepted(const CertificateOfRepresentation &c); - void credentialAccepted(const Capability &c); - void credentialAccepted(const Tag &c); - void credentialAccepted(const Revocation &c); + void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason); + void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason); + void credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason); + void credentialRejected(void *const tPtr,const Capability &c,const char *reason); + void credentialRejected(void *const tPtr,const Tag &c,const char *reason); + void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); + void credentialAccepted(void *const tPtr,const CertificateOfMembership &c); + void credentialAccepted(void *const tPtr,const CertificateOfOwnership &c); + void credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c); + void credentialAccepted(void *const tPtr,const Capability &c); + void credentialAccepted(void *const tPtr,const Tag &c); + void credentialAccepted(void *const tPtr,const Revocation &c); private: const RuntimeEnvironment *const RR; + + void _send(void *const tPtr,const Dictionary &d); + void _send(void *const tPtr,const Dictionary &d,const uint64_t networkId); + void _send(void *const tPtr,const Dictionary &d,const SharedPtr &network); }; } // namespace ZeroTier -- cgit v1.2.3 From 4ecc0c59cafac54ff2d32e97b130f83b7481da2e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 14 Jul 2017 13:03:16 -0700 Subject: Plumbing through of remote trace into controller code. --- controller/EmbeddedNetworkController.cpp | 67 ++++++++++++++++++++++++++++++++ controller/EmbeddedNetworkController.hpp | 4 ++ include/ZeroTierOne.h | 45 ++++++++++++++++++++- node/IncomingPacket.cpp | 27 ++++++++++++- node/IncomingPacket.hpp | 1 + node/Packet.hpp | 3 -- service/OneService.cpp | 6 +++ 7 files changed, 148 insertions(+), 5 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index b57a37e8..8b8a93bd 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -621,6 +621,15 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false); if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"],false); + if (b.count("remoteTraceTarget")) { + const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + member["remoteTraceTarget"] = rtt; + } else { + member["remoteTraceTarget"] = json(); + } + } + if (b.count("authorized")) { const bool newAuth = OSUtils::jsonBool(b["authorized"],false); if (newAuth != OSUtils::jsonBool(member["authorized"],false)) { @@ -764,6 +773,15 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); + if (b.count("remoteTraceTarget")) { + const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + network["remoteTraceTarget"] = rtt; + } else { + network["remoteTraceTarget"] = json(); + } + } + if (b.count("v4AssignMode")) { json nv4m; json &v4m = b["v4AssignMode"]; @@ -1065,6 +1083,55 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( return 404; } +void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) +{ + // Convert Dictionary into JSON object + json d; + char *saveptr = (char *)0; + for(char *l=Utils::stok(rt.data,"\n",&saveptr);(l);l=Utils::stok((char *)0,"\n",&saveptr)) { + char *eq = strchr(l,'='); + if (eq > l) { + std::string k(l,(unsigned long)(eq - l)); + std::string v; + ++eq; + while (*eq) { + if (*eq == '\\') { + ++eq; + if (*eq) { + switch(*eq) { + case 'r': + v.push_back('\r'); + break; + case 'n': + v.push_back('\n'); + break; + case '0': + v.push_back((char)0); + break; + case 'e': + v.push_back('='); + break; + default: + v.push_back(*eq); + break; + } + ++eq; + } + } else { + v.push_back(*(eq++)); + } + } + if (v.length() > 0) + d[k] = v; + } + } + + char p[128]; + OSUtils::ztsnprintf(p,sizeof(p),"trace/%.10llx_%.16llx.json",rt.origin,OSUtils::now()); + _db.writeRaw(p,OSUtils::jsonDump(d)); + //fprintf(stdout,"%s\n",OSUtils::jsonDump(d).c_str()); fflush(stdout); +} + void EmbeddedNetworkController::threadMain() throw() { diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 1589ea71..03ba0b95 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -90,6 +90,8 @@ public: std::string &responseBody, std::string &responseContentType); + void handleRemoteTrace(const ZT_RemoteTrace &rt); + void threadMain() throw(); @@ -142,6 +144,7 @@ private: if (!member.count("vRev")) member["vRev"] = -1; if (!member.count("vProto")) member["vProto"] = -1; if (!member.count("physicalAddr")) member["physicalAddr"] = nlohmann::json(); + if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json(); member["objtype"] = "member"; } inline void _initNetwork(nlohmann::json &network) @@ -159,6 +162,7 @@ private: if (!network.count("routes")) network["routes"] = nlohmann::json::array(); if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array(); if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU; + if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json(); if (!network.count("rules")) { // If unspecified, rules are set to allow anything and behave like a flat L2 segment network["rules"] = {{ diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index e4c39fbc..14ddc7fe 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -470,9 +470,52 @@ enum ZT_Event * * Meta-data: ZT_UserMessage structure */ - ZT_EVENT_USER_MESSAGE = 6 + ZT_EVENT_USER_MESSAGE = 6, + + /** + * Remote trace received + * + * These are generated when a VERB_REMOTE_TRACE is received. Note + * that any node can fling one of these at us. It is your responsibility + * to filter and determine if it's worth paying attention to. If it's + * not just drop it. Most nodes that are not active controllers ignore + * these, and controllers only save them if they pertain to networks + * with remote tracing enabled. + * + * Meta-data: ZT_RemoteTrace structure + */ + ZT_EVENT_REMOTE_TRACE = 7 }; +/** + * Payload of REMOTE_TRACE event + */ +typedef struct +{ + /** + * ZeroTier address of sender + */ + uint64_t origin; + + /** + * Null-terminated Dictionary containing key/value pairs sent by origin + * + * This *should* be a dictionary, but the implementation only checks + * that it is a valid non-empty C-style null-terminated string. Be very + * careful to use a well-tested parser to parse this as it represents + * data received from a potentially un-trusted peer on the network. + * Invalid payloads should be dropped. + * + * The contents of data[] may be modified. + */ + char *data; + + /** + * Length of dict[] in bytes, including terminating null + */ + unsigned int len; +} ZT_RemoteTrace; + /** * User message used with ZT_EVENT_USER_MESSAGE * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a5875d1e..5e5d1d72 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1192,7 +1192,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) { + if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { ZT_UserMessage um; um.origin = peer->address().toInt(); um.typeId = at(ZT_PACKET_IDX_PAYLOAD); @@ -1207,6 +1207,31 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con return true; } +bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +{ + ZT_RemoteTrace rt; + try { + const char *ptr = reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD; + const char *const eof = reinterpret_cast(data()) + size(); + rt.origin = peer->address().toInt(); + rt.data = const_cast(ptr); // start of first string + while (ptr < eof) { + if (!*ptr) { // end of string + rt.len = (unsigned int)(ptr - rt.data); + if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) + RR->node->postEvent(tPtr,ZT_EVENT_REMOTE_TRACE,&rt); + rt.data = const_cast(++ptr); // start of next string, if any + } else { + ++ptr; + } + } + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0); + } catch ( ... ) { + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_REMOTE_TRACE,"unexpected exception"); + } + return true; +} + void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) { const uint64_t now = RR->node->now(); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 11b60712..692c63df 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -139,6 +139,7 @@ private: bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid); diff --git a/node/Packet.hpp b/node/Packet.hpp index a1ea73e1..b8e69fa9 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -978,9 +978,6 @@ public: * The instance ID is a random 64-bit value generated by each ZeroTier * node on startup. This is helpful in identifying traces from different * members of a cluster. - * - * The Dictionary serialization format is the same as used for network - * configurations. The maximum size of a trace is 10000 bytes. */ VERB_REMOTE_TRACE = 0x15 }; diff --git a/service/OneService.cpp b/service/OneService.cpp index 1b07eb79..115830e5 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2058,6 +2058,12 @@ public: } } break; + case ZT_EVENT_REMOTE_TRACE: { + const ZT_RemoteTrace *rt = reinterpret_cast(metaData); + if ((rt)&&(rt->len > 0)&&(rt->len <= ZT_MAX_REMOTE_TRACE_SIZE)&&(rt->data)) + _controller->handleRemoteTrace(*rt); + } + default: break; } -- cgit v1.2.3 From d939d8d21d79c23a5af82bcc60214b4e19dc5f74 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 14 Jul 2017 14:57:40 -0700 Subject: A bit more remote tracing stuff. --- include/ZeroTierOne.h | 13 ++++++++++++ node/IncomingPacket.cpp | 10 ++++----- node/Trace.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++------- node/Trace.hpp | 4 ++-- 4 files changed, 68 insertions(+), 15 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 14ddc7fe..b123e8e3 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -272,12 +272,20 @@ extern "C" { #define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "ls" #define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "ipsc" #define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "nwid" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "szt" +#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "dzt" #define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "seth" #define ZT_REMOTE_TRACE_FIELD__DEST_MAC "deth" #define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "et" #define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlan" #define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "fl" #define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "fd" +#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "ffnotee" +#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "ffdir" +#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "fresult" +#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "frlog" +#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "fclog" +#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "fcid" #define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "crtype" #define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "crid" #define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "crts" @@ -285,6 +293,7 @@ extern "C" { #define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "criss" #define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "crrevt" #define ZT_REMOTE_TRACE_FIELD__REASON "reason" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "nwctrl" // Event types in remote traces #define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 @@ -300,6 +309,8 @@ extern "C" { #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED 0x2002 #define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003 #define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004 +#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005 +#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006 // Event types in remote traces in hex string form #define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" @@ -315,6 +326,8 @@ extern "C" { #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" #define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" #define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" +#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005" +#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006" /****************************************************************************/ /* Structures and other types */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5e5d1d72..94c73f81 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -683,19 +683,19 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } @@ -1065,7 +1065,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); if (network->config().multicastLimit == 0) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"multicast disabled"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } @@ -1086,7 +1086,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"bridging not allowed (remote)"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } diff --git a/node/Trace.cpp b/node/Trace.cpp index 21d06228..2b1c69dd 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -120,8 +120,9 @@ void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtrid()); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); if (path) { d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); } + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + _send(tPtr,d,network); } -void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) +void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason) { - //Dictionary d; - //d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); + if (!network) return; // sanity check + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,network); } void Trace::incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) @@ -197,6 +214,11 @@ void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &p void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller); + _send(tPtr,d,0); } void Trace::networkFilter( @@ -217,9 +239,27 @@ void Trace::networkFilter( const bool inbound, const int accept) { - //char tmp[128]; - //Dictionary d; - //_send(tPtr,d,network.id()); + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR,ztSource); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR,ztDest); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,macSource.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,macDest.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE,noTee ? "1" : "0"); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND,inbound ? "1" : "0"); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT,(int64_t)accept); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG,(const char *)primaryRuleSetLog.data(),(int)primaryRuleSetLog.sizeBytes()); + if (matchingCapabilityRuleSetLog) + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG,(const char *)matchingCapabilityRuleSetLog->data(),(int)matchingCapabilityRuleSetLog->sizeBytes()); + if (matchingCapability) + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID,(uint64_t)matchingCapability->id()); + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); + if (frameLen > 0) + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen); + _send(tPtr,d,network.id()); } void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) diff --git a/node/Trace.hpp b/node/Trace.hpp index dae67e28..7fe48cdd 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -93,7 +93,7 @@ public: } inline const uint8_t *data() const { return _l; } - inline unsigned int sizeBytes() const { return (unsigned int)sizeof(_l); } + inline unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); } private: uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; @@ -115,7 +115,7 @@ public: void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); - void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); + void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason); void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller); void networkFilter( -- cgit v1.2.3 From 3a1ec07db0d30415a21ab05be9898210d7cc70ef Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Jul 2017 10:43:28 -0700 Subject: Remove some exception copypasta. --- node/IncomingPacket.cpp | 1706 +++++++++++++++++++++++------------------------ 1 file changed, 830 insertions(+), 876 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 94c73f81..9489b16e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -129,1106 +129,1060 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; - const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); - const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - uint64_t networkId = 0; - - /* Security note: we do not gate doERROR() with expectingReplyTo() to - * avoid having to log every outgoing packet ID. Instead we put the - * logic to determine whether we should consider an ERROR in each - * error handler. In most cases these are only trusted in specific - * circumstances. */ - - switch(errorCode) { - - case Packet::ERROR_OBJ_NOT_FOUND: - // Object not found, currently only meaningful from network controllers. - if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) - network->setNotFound(); - } - break; - - case Packet::ERROR_UNSUPPORTED_OPERATION: - // This can be sent in response to any operation, though right now we only - // consider it meaningful from network controllers. This would indicate - // that the queried node does not support acting as a controller. - if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) - network->setNotFound(); - } - break; - - case Packet::ERROR_IDENTITY_COLLISION: - // FIXME: for federation this will need a payload with a signature or something. - if (RR->topology->isUpstream(peer->identity())) - RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); - break; - - case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - // Peers can send this in response to frames if they do not have a recent enough COM from us - networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); - const SharedPtr network(RR->node->network(networkId)); - const uint64_t now = RR->node->now(); - if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) - network->pushCredentialsNow(tPtr,peer->address(),now); - } break; + const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; + const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); + const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; + uint64_t networkId = 0; + + /* Security note: we do not gate doERROR() with expectingReplyTo() to + * avoid having to log every outgoing packet ID. Instead we put the + * logic to determine whether we should consider an ERROR in each + * error handler. In most cases these are only trusted in specific + * circumstances. */ + + switch(errorCode) { + + case Packet::ERROR_OBJ_NOT_FOUND: + // Object not found, currently only meaningful from network controllers. + if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->controller() == peer->address())) + network->setNotFound(); + } + break; - case Packet::ERROR_NETWORK_ACCESS_DENIED_: { - // Network controller: network access denied. + case Packet::ERROR_UNSUPPORTED_OPERATION: + // This can be sent in response to any operation, though right now we only + // consider it meaningful from network controllers. This would indicate + // that the queried node does not support acting as a controller. + if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) - network->setAccessDenied(); - } break; + network->setNotFound(); + } + break; + + case Packet::ERROR_IDENTITY_COLLISION: + // FIXME: for federation this will need a payload with a signature or something. + if (RR->topology->isUpstream(peer->identity())) + RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); + break; + + case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + // Peers can send this in response to frames if they do not have a recent enough COM from us + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); + const uint64_t now = RR->node->now(); + if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) + network->pushCredentialsNow(tPtr,peer->address(),now); + } break; + + case Packet::ERROR_NETWORK_ACCESS_DENIED_: { + // Network controller: network access denied. + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->controller() == peer->address())) + network->setAccessDenied(); + } break; + + case Packet::ERROR_UNWANTED_MULTICAST: { + // Members of networks can use this error to indicate that they no longer + // want to receive multicasts on a given channel. + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); + if ((network)&&(network->gate(tPtr,peer))) { + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); + RR->mc->remove(network->id(),mg,peer->address()); + } + } break; - case Packet::ERROR_UNWANTED_MULTICAST: { - // Members of networks can use this error to indicate that they no longer - // want to receive multicasts on a given channel. - networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); - const SharedPtr network(RR->node->network(networkId)); - if ((network)&&(network->gate(tPtr,peer))) { - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - RR->mc->remove(network->id(),mg,peer->address()); - } - } break; + default: break; + } - default: break; - } + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_ERROR,"unexpected exception"); - } return true; } bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) { - try { - const uint64_t now = RR->node->now(); - - const uint64_t pid = packetId(); - const Address fromAddress(source()); - const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; - const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; - 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); - Identity id; - unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - - if (protoVersion < ZT_PROTO_VERSION_MIN) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"protocol version too old"); - return true; - } - if (fromAddress != id.address()) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"identity/address mismatch"); - return true; - } + const uint64_t now = RR->node->now(); - SharedPtr peer(RR->topology->getPeer(tPtr,id.address())); - if (peer) { - // We already have an identity with this address -- check for collisions - if (!alreadyAuthenticated) { - if (peer->identity() != id) { - // Identity is different from the one we already have -- address collision - - // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) - return true; - - uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; - if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { - if (dearmor(key)) { // ensure packet is authentic, otherwise drop - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"address collision"); - Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)Packet::VERB_HELLO); - outp.append((uint64_t)pid); - outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); - } - } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); - } + const uint64_t pid = packetId(); + const Address fromAddress(source()); + const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; + 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); + Identity id; + unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + + if (protoVersion < ZT_PROTO_VERSION_MIN) { + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"protocol version too old"); + return true; + } + if (fromAddress != id.address()) { + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"identity/address mismatch"); + return true; + } + + SharedPtr peer(RR->topology->getPeer(tPtr,id.address())); + if (peer) { + // We already have an identity with this address -- check for collisions + if (!alreadyAuthenticated) { + if (peer->identity() != id) { + // Identity is different from the one we already have -- address collision + // Check rate limits + if (!RR->node->rateGateIdentityVerification(now,_path->address())) return true; - } else { - // Identity is the same as the one we already have -- check packet integrity - if (!dearmor(peer->key())) { + uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; + if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { + if (dearmor(key)) { // ensure packet is authentic, otherwise drop + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"address collision"); + Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)Packet::VERB_HELLO); + outp.append((uint64_t)pid); + outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); + outp.armor(key,true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + } else { RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); - return true; } - - // Continue at // VALID + } else { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); } - } // else if alreadyAuthenticated then continue at // VALID - } else { - // We don't already have an identity with this address -- validate and learn it - - // Sanity check: this basically can't happen - if (alreadyAuthenticated) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"illegal alreadyAuthenticated state"); - return true; - } - // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"rate limit exceeded"); return true; - } + } else { + // Identity is the same as the one we already have -- check packet integrity - // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) - SharedPtr newPeer(new Peer(RR,RR->identity,id)); - if (!dearmor(newPeer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); - return true; - } + if (!dearmor(peer->key())) { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + return true; + } - // Check that identity's address is valid as per the derivation function - if (!id.locallyValidate()) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"invalid identity"); - return true; + // Continue at // VALID } + } // else if alreadyAuthenticated then continue at // VALID + } else { + // We don't already have an identity with this address -- validate and learn it - peer = RR->topology->addPeer(tPtr,newPeer); - - // Continue at // VALID + // Sanity check: this basically can't happen + if (alreadyAuthenticated) { + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"illegal alreadyAuthenticated state"); + return true; } - // VALID -- if we made it here, packet passed identity and authenticity checks! + // Check rate limits + if (!RR->node->rateGateIdentityVerification(now,_path->address())) { + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"rate limit exceeded"); + return true; + } - // Get external surface address if present (was not in old versions) - InetAddress externalSurfaceAddress; - if (ptr < size()) { - ptr += externalSurfaceAddress.deserialize(*this,ptr); - if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) + SharedPtr newPeer(new Peer(RR,RR->identity,id)); + if (!dearmor(newPeer->key())) { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + return true; } - // Get primary planet world ID and world timestamp if present - uint64_t planetWorldId = 0; - uint64_t planetWorldTimestamp = 0; - if ((ptr + 16) <= size()) { - planetWorldId = at(ptr); ptr += 8; - planetWorldTimestamp = at(ptr); ptr += 8; + // Check that identity's address is valid as per the derivation function + if (!id.locallyValidate()) { + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"invalid identity"); + return true; } - std::vector< std::pair > moonIdsAndTimestamps; - if (ptr < size()) { - // Remainder of packet, if present, is encrypted - cryptField(peer->key(),ptr,size() - ptr); + peer = RR->topology->addPeer(tPtr,newPeer); - // Get moon IDs and timestamps if present - if ((ptr + 2) <= size()) { - const unsigned int numMoons = at(ptr); ptr += 2; - for(unsigned int i=0;i(at(ptr),at(ptr + 8))); - ptr += 16; - } - } + // Continue at // VALID + } - // Handle COR if present (older versions don't send this) - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } - } + // VALID -- if we made it here, packet passed identity and authenticity checks! - // Send OK(HELLO) with an echo of the packet's timestamp and some of the same - // information about us: version, sent-to address, etc. + // Get external surface address if present (was not in old versions) + InetAddress externalSurfaceAddress; + if (ptr < size()) { + ptr += externalSurfaceAddress.deserialize(*this,ptr); + if ((externalSurfaceAddress)&&(hops() == 0)) + RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + } - Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append((uint64_t)pid); - outp.append((uint64_t)timestamp); - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + // Get primary planet world ID and world timestamp if present + uint64_t planetWorldId = 0; + uint64_t planetWorldTimestamp = 0; + if ((ptr + 16) <= size()) { + planetWorldId = at(ptr); ptr += 8; + planetWorldTimestamp = at(ptr); ptr += 8; + } - if (protoVersion >= 5) { - _path->address().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(_path->address()); - tmpa.setPort(0); - tmpa.serialize(outp); + std::vector< std::pair > moonIdsAndTimestamps; + if (ptr < size()) { + // Remainder of packet, if present, is encrypted + cryptField(peer->key(),ptr,size() - ptr); + + // Get moon IDs and timestamps if present + if ((ptr + 2) <= size()) { + const unsigned int numMoons = at(ptr); ptr += 2; + for(unsigned int i=0;i(at(ptr),at(ptr + 8))); + ptr += 16; + } } - const unsigned int worldUpdateSizeAt = outp.size(); - outp.addSize(2); // make room for 16-bit size field - if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { - RR->topology->planet().serialize(outp,false); + // Handle COR if present (older versions don't send this) + if ((ptr + 2) <= size()) { + if (at(ptr) > 0) { + CertificateOfRepresentation cor; + ptr += 2; + ptr += cor.deserialize(*this,ptr); + } else ptr += 2; } - if (moonIdsAndTimestamps.size() > 0) { - std::vector moons(RR->topology->moons()); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - for(std::vector< std::pair >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) { - if (i->first == m->id()) { - if (m->timestamp() > i->second) - m->serialize(outp,false); - break; - } + } + + // Send OK(HELLO) with an echo of the packet's timestamp and some of the same + // information about us: version, sent-to address, etc. + + Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_HELLO); + outp.append((uint64_t)pid); + outp.append((uint64_t)timestamp); + outp.append((unsigned char)ZT_PROTO_VERSION); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); + outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + + if (protoVersion >= 5) { + _path->address().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(_path->address()); + tmpa.setPort(0); + tmpa.serialize(outp); + } + + const unsigned int worldUpdateSizeAt = outp.size(); + outp.addSize(2); // make room for 16-bit size field + if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { + RR->topology->planet().serialize(outp,false); + } + if (moonIdsAndTimestamps.size() > 0) { + std::vector moons(RR->topology->moons()); + for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { + for(std::vector< std::pair >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) { + if (i->first == m->id()) { + if (m->timestamp() > i->second) + m->serialize(outp,false); + break; } } } - outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); + } + outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); + const unsigned int corSizeAt = outp.size(); + outp.addSize(2); + RR->topology->appendCertificateOfRepresentation(outp); + outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),now); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),now); + + peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version + peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0); - peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_HELLO,"unexpected exception"); - } return true; } bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; - const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - uint64_t networkId = 0; - - if (!RR->node->expectingReplyTo(inRePacketId)) - return true; - - switch(inReVerb) { + const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; + const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + uint64_t networkId = 0; - case Packet::VERB_HELLO: { - const uint64_t latency = RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP); - if (latency > ZT_HELLO_MAX_ALLOWABLE_LATENCY) - return true; + if (!RR->node->expectingReplyTo(inRePacketId)) + return true; - const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; - const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; - 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) - return true; + switch(inReVerb) { - InetAddress externalSurfaceAddress; - unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; - - // Get reported external surface address if present - if (ptr < size()) - ptr += externalSurfaceAddress.deserialize(*this,ptr); - - // Handle planet or moon updates if present - if ((ptr + 2) <= size()) { - const unsigned int worldsLen = at(ptr); ptr += 2; - if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) { - const unsigned int endOfWorlds = ptr + worldsLen; - while (ptr < endOfWorlds) { - World w; - ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(tPtr,w,false); - } - } else { - ptr += worldsLen; - } - } + case Packet::VERB_HELLO: { + const uint64_t latency = RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP); + if (latency > ZT_HELLO_MAX_ALLOWABLE_LATENCY) + return true; - // Handle certificate of representation if present - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } + const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; + 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) + return true; - if (!hops()) - peer->addDirectLatencyMeasurment((unsigned int)latency); - peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); + InetAddress externalSurfaceAddress; + unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; - if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); - } break; + // Get reported external surface address if present + if (ptr < size()) + ptr += externalSurfaceAddress.deserialize(*this,ptr); - case Packet::VERB_WHOIS: - if (RR->topology->isUpstream(peer->identity())) { - const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); - RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); + // Handle planet or moon updates if present + if ((ptr + 2) <= size()) { + const unsigned int worldsLen = at(ptr); ptr += 2; + if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) { + const unsigned int endOfWorlds = ptr + worldsLen; + while (ptr < endOfWorlds) { + World w; + ptr += w.deserialize(*this,ptr); + RR->topology->addWorld(tPtr,w,false); + } + } else { + ptr += worldsLen; } - break; + } - case Packet::VERB_NETWORK_CONFIG_REQUEST: { - networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); - const SharedPtr network(RR->node->network(networkId)); - if (network) - network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); - } break; + // Handle certificate of representation if present + if ((ptr + 2) <= size()) { + if (at(ptr) > 0) { + CertificateOfRepresentation cor; + ptr += 2; + ptr += cor.deserialize(*this,ptr); + } else ptr += 2; + } - case Packet::VERB_MULTICAST_GATHER: { - networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(networkId)); - if (network) { - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); - } - } break; + if (!hops()) + peer->addDirectLatencyMeasurment((unsigned int)latency); + peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - case Packet::VERB_MULTICAST_FRAME: { - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; - networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); + if ((externalSurfaceAddress)&&(hops() == 0)) + RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + } break; - const SharedPtr network(RR->node->network(networkId)); - if (network) { - unsigned int offset = 0; + case Packet::VERB_WHOIS: + if (RR->topology->isUpstream(peer->identity())) { + const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); + RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); + } + break; + + case Packet::VERB_NETWORK_CONFIG_REQUEST: { + networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); + if (network) + network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); + } break; + + case Packet::VERB_MULTICAST_GATHER: { + networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(networkId)); + if (network) { + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); + const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + } + } break; - if ((flags & 0x01) != 0) { // deprecated but still used by older peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - if (com) - network->addCredential(tPtr,com); - } + case Packet::VERB_MULTICAST_FRAME: { + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; + networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(offset,count * 5),count,totalKnown); - } + const SharedPtr network(RR->node->network(networkId)); + if (network) { + unsigned int offset = 0; + + if ((flags & 0x01) != 0) { // deprecated but still used by older peers + CertificateOfMembership com; + offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); + if (com) + network->addCredential(tPtr,com); } - } break; - default: break; - } + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); offset += 4; + unsigned int count = at(offset); offset += 2; + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(offset,count * 5),count,totalKnown); + } + } + } break; - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_OK,"unexpected exception"); + default: break; } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId); + return true; } bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) - return true; - - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_WHOIS); - outp.append(packetId()); + if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) + return true; - unsigned int count = 0; - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; - while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { - const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - ptr += ZT_ADDRESS_LENGTH; + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_WHOIS); + outp.append(packetId()); - const Identity id(RR->topology->getIdentity(tPtr,addr)); - if (id) { - id.serialize(outp,false); - ++count; - } else { - // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(tPtr,addr); - } - } + unsigned int count = 0; + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; + while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { + const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + ptr += ZT_ADDRESS_LENGTH; - if (count > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + const Identity id(RR->topology->getIdentity(tPtr,addr)); + if (id) { + id.serialize(outp,false); + ++count; + } else { + // Request unknown WHOIS from upstream from us (if we have one) + RR->sw->requestWhois(tPtr,addr); } + } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_WHOIS,"unexpected exception"); + if (count > 0) { + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0); + return true; } bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - if (RR->topology->isUpstream(peer->identity())) { - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); - if (rendezvousWith) { - 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))) { - const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { - const uint64_t junk = RR->node->prng(); - RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); - } + if (RR->topology->isUpstream(peer->identity())) { + const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); + if (rendezvousWith) { + 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))) { + const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); + if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { + const uint64_t junk = RR->node->prng(); + RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); } } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_RENDEZVOUS,"unexpected exception"); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0); + return true; } bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - bool trustEstablished = false; - if (network) { - if (network->gate(tPtr,peer)) { - trustEstablished = true; - if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),nwid); - const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - } - } else { - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); + const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + bool trustEstablished = false; + if (network) { + if (network->gate(tPtr,peer)) { + trustEstablished = true; + if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { + const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + const MAC sourceMac(peer->address(),nwid); + const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) + RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_FRAME,"unexpected exception"); + } else { + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid); + return true; } bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - if (network) { - const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; - - unsigned int comLen = 0; - if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers - CertificateOfMembership com; - comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); - if (com) - network->addCredential(tPtr,com); - } + const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + if (network) { + const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; + + unsigned int comLen = 0; + if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers + CertificateOfMembership com; + comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); + if (com) + network->addCredential(tPtr,com); + } - if (!network->gate(tPtr,peer)) { - RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); - return true; - } + if (!network->gate(tPtr,peer)) { + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); + return true; + } - if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); - const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); - const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); - const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); - const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); + if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { + const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); + const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); + const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); + const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); + const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - if ((!from)||(from == network->mac())) { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay - return true; - } + if ((!from)||(from == network->mac())) { + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay + return true; + } - switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { - case 1: - if (from != MAC(peer->address(),nwid)) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay - return true; - } - } else if (to != network->mac()) { - if (to.isMulticast()) { - if (network->config().multicastLimit == 0) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay - return true; - } - } else if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)"); + switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { + case 1: + if (from != MAC(peer->address(),nwid)) { + if (network->config().permitsBridging(peer->address())) { + network->learnBridgeRoute(from,peer->address()); + } else { + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay + return true; + } + } else if (to != network->mac()) { + if (to.isMulticast()) { + if (network->config().multicastLimit == 0) { + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } + } else if (!network->config().permitsBridging(RR->identity.address())) { + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay + return true; } - // fall through -- 2 means accept regardless of bridging checks or other restrictions - case 2: - RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); - break; - } - } - - if ((flags & 0x10) != 0) { // ACK requested - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_EXT_FRAME); - outp.append((uint64_t)packetId()); - outp.append((uint64_t)nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + } + // fall through -- 2 means accept regardless of bridging checks or other restrictions + case 2: + RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + break; } + } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); - } else { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); + if ((flags & 0x10) != 0) { // ACK requested + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((uint8_t)Packet::VERB_EXT_FRAME); + outp.append((uint64_t)packetId()); + outp.append((uint64_t)nwid); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_EXT_FRAME,"unexpected exception"); + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); + } else { + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); } + return true; } bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - if (!peer->rateGateEchoRequest(RR->node->now())) - return true; + if (!peer->rateGateEchoRequest(RR->node->now())) + return true; - const uint64_t pid = packetId(); - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_ECHO); - outp.append((uint64_t)pid); - if (size() > ZT_PACKET_IDX_PAYLOAD) - outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + const uint64_t pid = packetId(); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_ECHO); + outp.append((uint64_t)pid); + if (size() > ZT_PACKET_IDX_PAYLOAD) + outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + + peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0); - peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_ECHO,"unexpected exception"); - } return true; } bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t now = RR->node->now(); + const uint64_t now = RR->node->now(); - uint64_t authOnNetwork[256]; // cache for approved network IDs - unsigned int authOnNetworkCount = 0; - SharedPtr network; - bool trustEstablished = false; + uint64_t authOnNetwork[256]; // cache for approved network IDs + unsigned int authOnNetworkCount = 0; + SharedPtr network; + bool trustEstablished = false; - // Iterate through 18-byte network,MAC,ADI tuples - for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); + // Iterate through 18-byte network,MAC,ADI tuples + for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); - bool auth = false; - for(unsigned int i=0;iid() != nwid)) - network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(tPtr,peer))); - if (!authOnNet) - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - trustEstablished |= authOnNet; - if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { - auth = true; - if (authOnNetworkCount < 256) // sanity check, packets can't really be this big - authOnNetwork[authOnNetworkCount++] = nwid; - } + bool auth = false; + for(unsigned int i=0;i(ptr + 14)); - RR->mc->add(tPtr,now,nwid,group,peer->address()); + } + if (!auth) { + if ((!network)||(network->id() != nwid)) + network = RR->node->network(nwid); + const bool authOnNet = ((network)&&(network->gate(tPtr,peer))); + if (!authOnNet) + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + trustEstablished |= authOnNet; + if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { + auth = true; + if (authOnNetworkCount < 256) // sanity check, packets can't really be this big + authOnNetwork[authOnNetworkCount++] = nwid; } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); + if (auth) { + const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); + RR->mc->add(tPtr,now,nwid,group,peer->address()); + } } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); + return true; } bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - if (!peer->rateGateCredentialsReceived(RR->node->now())) - return true; + if (!peer->rateGateCredentialsReceived(RR->node->now())) + return true; - CertificateOfMembership com; - Capability cap; - Tag tag; - Revocation revocation; - CertificateOfOwnership coo; - bool trustEstablished = false; - SharedPtr network; - - unsigned int p = ZT_PACKET_IDX_PAYLOAD; - while ((p < size())&&((*this)[p] != 0)) { - p += com.deserialize(*this,p); - if (com) { - network = RR->node->network(com.networkId()); - if (network) { - switch (network->addCredential(tPtr,com)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } else RR->mc->addCredential(tPtr,com,false); - } + CertificateOfMembership com; + Capability cap; + Tag tag; + Revocation revocation; + CertificateOfOwnership coo; + bool trustEstablished = false; + SharedPtr network; + + unsigned int p = ZT_PACKET_IDX_PAYLOAD; + while ((p < size())&&((*this)[p] != 0)) { + p += com.deserialize(*this,p); + if (com) { + network = RR->node->network(com.networkId()); + if (network) { + switch (network->addCredential(tPtr,com)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } else RR->mc->addCredential(tPtr,com,false); } - ++p; // skip trailing 0 after COMs if present - - if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations - const unsigned int numCapabilities = at(p); p += 2; - for(unsigned int i=0;iid() != cap.networkId())) - network = RR->node->network(cap.networkId()); - if (network) { - switch (network->addCredential(tPtr,cap)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } + } + ++p; // skip trailing 0 after COMs if present + + if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations + const unsigned int numCapabilities = at(p); p += 2; + for(unsigned int i=0;iid() != cap.networkId())) + network = RR->node->network(cap.networkId()); + if (network) { + switch (network->addCredential(tPtr,cap)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } + } - if (p >= size()) return true; - - const unsigned int numTags = at(p); p += 2; - for(unsigned int i=0;iid() != tag.networkId())) - network = RR->node->network(tag.networkId()); - if (network) { - switch (network->addCredential(tPtr,tag)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } + if (p >= size()) return true; + + const unsigned int numTags = at(p); p += 2; + for(unsigned int i=0;iid() != tag.networkId())) + network = RR->node->network(tag.networkId()); + if (network) { + switch (network->addCredential(tPtr,tag)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } + } - if (p >= size()) return true; - - const unsigned int numRevocations = at(p); p += 2; - for(unsigned int i=0;iid() != revocation.networkId())) - network = RR->node->network(revocation.networkId()); - if (network) { - switch(network->addCredential(tPtr,peer->address(),revocation)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } + if (p >= size()) return true; + + const unsigned int numRevocations = at(p); p += 2; + for(unsigned int i=0;iid() != revocation.networkId())) + network = RR->node->network(revocation.networkId()); + if (network) { + switch(network->addCredential(tPtr,peer->address(),revocation)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } + } - if (p >= size()) return true; - - const unsigned int numCoos = at(p); p += 2; - for(unsigned int i=0;iid() != coo.networkId())) - network = RR->node->network(coo.networkId()); - if (network) { - switch(network->addCredential(tPtr,coo)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } + if (p >= size()) return true; + + const unsigned int numCoos = at(p); p += 2; + for(unsigned int i=0;iid() != coo.networkId())) + network = RR->node->network(coo.networkId()); + if (network) { + switch(network->addCredential(tPtr,coo)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; } } } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); + return true; } bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); - const unsigned int hopCount = hops(); - const uint64_t requestPacketId = packetId(); - - if (RR->localNetworkController) { - const unsigned int metaDataLength = (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN) : 0; - const char *metaDataBytes = (metaDataLength != 0) ? (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength) : (const char *)0; - const Dictionary metaData(metaDataBytes,metaDataLength); - RR->localNetworkController->request(nwid,(hopCount > 0) ? InetAddress() : _path->address(),requestPacketId,peer->identity(),metaData); - } else { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); - outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - - peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); + const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); + const unsigned int hopCount = hops(); + const uint64_t requestPacketId = packetId(); + + if (RR->localNetworkController) { + const unsigned int metaDataLength = (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN) : 0; + const char *metaDataBytes = (metaDataLength != 0) ? (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength) : (const char *)0; + const Dictionary metaData(metaDataBytes,metaDataLength); + RR->localNetworkController->request(nwid,(hopCount > 0) ? InetAddress() : _path->address(),requestPacketId,peer->identity(),metaData); + } else { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); + outp.append(nwid); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } + + peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid); + return true; } bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); - if (network) { - const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); - if (configUpdateId) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_ECHO); - outp.append((uint64_t)packetId()); - outp.append((uint64_t)network->id()); - outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } + const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); + if (network) { + const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); + if (configUpdateId) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((uint8_t)Packet::VERB_ECHO); + outp.append((uint64_t)packetId()); + outp.append((uint64_t)network->id()); + outp.append((uint64_t)configUpdateId); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0); + return true; } bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); - const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - - const SharedPtr network(RR->node->network(nwid)); + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); + const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - if ((flags & 0x01) != 0) { - try { - CertificateOfMembership com; - com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); - if (com) { - if (network) - network->addCredential(tPtr,com); - else RR->mc->addCredential(tPtr,com,false); - } - } catch ( ... ) {} // discard invalid COMs - } + const SharedPtr network(RR->node->network(nwid)); - const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); - if (!trustEstablished) - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); - outp.append(packetId()); - outp.append(nwid); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); - if (gatheredLocally > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + if ((flags & 0x01) != 0) { + try { + CertificateOfMembership com; + com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); + if (com) { + if (network) + network->addCredential(tPtr,com); + else RR->mc->addCredential(tPtr,com,false); } - } + } catch ( ... ) {} // discard invalid COMs + } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); + const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); + if (!trustEstablished) + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); + outp.append(packetId()); + outp.append(nwid); + mg.mac().appendTo(outp); + outp.append((uint32_t)mg.adi()); + const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); + if (gatheredLocally > 0) { + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + } } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid); + return true; } bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; - - const SharedPtr network(RR->node->network(nwid)); - if (network) { - // Offset -- size of optional fields added to position of later fields - unsigned int offset = 0; - - if ((flags & 0x01) != 0) { - // This is deprecated but may still be sent by old peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - if (com) - network->addCredential(tPtr,com); - } + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; - if (!network->gate(tPtr,peer)) { - RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); - return true; - } + const SharedPtr network(RR->node->network(nwid)); + if (network) { + // Offset -- size of optional fields added to position of later fields + unsigned int offset = 0; - unsigned int gatherLimit = 0; - if ((flags & 0x02) != 0) { - gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); - offset += 4; - } + if ((flags & 0x01) != 0) { + // This is deprecated but may still be sent by old peers + CertificateOfMembership com; + offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); + if (com) + network->addCredential(tPtr,com); + } - MAC from; - if ((flags & 0x04) != 0) { - from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6),6); - offset += 6; - } else { - from.fromAddress(peer->address(),nwid); - } + if (!network->gate(tPtr,peer)) { + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); + return true; + } + + unsigned int gatherLimit = 0; + if ((flags & 0x02) != 0) { + gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); + offset += 4; + } + + MAC from; + if ((flags & 0x04) != 0) { + from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6),6); + offset += 6; + } else { + from.fromAddress(peer->address(),nwid); + } - const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); - const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); - const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); + const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); + const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); + const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); - if (network->config().multicastLimit == 0) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"multicast disabled"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); + if (network->config().multicastLimit == 0) { + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"multicast disabled"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); + return true; + } + + if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { + if (!to.mac().isMulticast()) { + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay + return true; + } + if ((!from)||(from.isMulticast())||(from == network->mac())) { + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } - if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { - if (!to.mac().isMulticast()) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay - return true; - } - if ((!from)||(from.isMulticast())||(from == network->mac())) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); + if (from != MAC(peer->address(),nwid)) { + if (network->config().permitsBridging(peer->address())) { + network->learnBridgeRoute(from,peer->address()); + } else { + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"bridging not allowed (remote)"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } - - if (from != MAC(peer->address(),nwid)) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"bridging not allowed (remote)"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay - return true; - } - } - - const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } - if (gatherLimit) { - Packet outp(source(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); - outp.append(packetId()); - outp.append(nwid); - to.mac().appendTo(outp); - outp.append((uint32_t)to.adi()); - 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,_path->nextOutgoingCounter()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - } + const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) + RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); + } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); - } else { - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); + if (gatherLimit) { + Packet outp(source(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); + outp.append(packetId()); + outp.append(nwid); + to.mac().appendTo(outp); + outp.append((uint32_t)to.adi()); + 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,_path->nextOutgoingCounter()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + } } - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); + } else { + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); } + return true; } bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - const uint64_t now = RR->node->now(); + const uint64_t now = RR->node->now(); - // First, subject this to a rate limit - if (!peer->rateGatePushDirectPaths(now)) { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); - return true; - } + // First, subject this to a rate limit + if (!peer->rateGatePushDirectPaths(now)) { + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); + return true; + } - // 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; - - while (count--) { // if ptr overflows Buffer will throw - // TODO: some flags are not yet implemented - - unsigned int flags = (*this)[ptr++]; - unsigned int extLen = at(ptr); ptr += 2; - ptr += extLen; // unused right now - unsigned int addrType = (*this)[ptr++]; - unsigned int addrLen = (*this)[ptr++]; - - switch(addrType) { - case 4: { - const InetAddress a(field(ptr,4),4,at(ptr + 4)); - if ( - ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget - (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path - { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->redirect(tPtr,_path->localSocket(),a,now); - } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); - } + // 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; + + while (count--) { // if ptr overflows Buffer will throw + // TODO: some flags are not yet implemented + + unsigned int flags = (*this)[ptr++]; + unsigned int extLen = at(ptr); ptr += 2; + ptr += extLen; // unused right now + unsigned int addrType = (*this)[ptr++]; + unsigned int addrLen = (*this)[ptr++]; + + switch(addrType) { + case 4: { + const InetAddress a(field(ptr,4),4,at(ptr + 4)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path + { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->redirect(tPtr,_path->localSocket(),a,now); + } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } - } break; - case 6: { - const InetAddress a(field(ptr,16),16,at(ptr + 16)); - if ( - ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget - (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path - { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->redirect(tPtr,_path->localSocket(),a,now); - } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); - } + } + } break; + case 6: { + const InetAddress a(field(ptr,16),16,at(ptr + 16)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path + { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->redirect(tPtr,_path->localSocket(),a,now); + } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } - } break; - } - ptr += addrLen; + } + } break; } - - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); + ptr += addrLen; } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); + return true; } bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - try { - if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { - ZT_UserMessage um; - um.origin = peer->address().toInt(); - um.typeId = at(ZT_PACKET_IDX_PAYLOAD); - um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); - um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); - RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); - } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_USER_MESSAGE,"unexpected exception"); + if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { + ZT_UserMessage um; + um.origin = peer->address().toInt(); + um.typeId = at(ZT_PACKET_IDX_PAYLOAD); + um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); + um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); + RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0); + return true; } bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { ZT_RemoteTrace rt; - try { - const char *ptr = reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD; - const char *const eof = reinterpret_cast(data()) + size(); - rt.origin = peer->address().toInt(); - rt.data = const_cast(ptr); // start of first string - while (ptr < eof) { - if (!*ptr) { // end of string - rt.len = (unsigned int)(ptr - rt.data); - if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) - RR->node->postEvent(tPtr,ZT_EVENT_REMOTE_TRACE,&rt); - rt.data = const_cast(++ptr); // start of next string, if any - } else { - ++ptr; - } + const char *ptr = reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD; + const char *const eof = reinterpret_cast(data()) + size(); + rt.origin = peer->address().toInt(); + rt.data = const_cast(ptr); // start of first string + while (ptr < eof) { + if (!*ptr) { // end of string + rt.len = (unsigned int)(ptr - rt.data); + if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) + RR->node->postEvent(tPtr,ZT_EVENT_REMOTE_TRACE,&rt); + rt.data = const_cast(++ptr); // start of next string, if any + } else { + ++ptr; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0); - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_REMOTE_TRACE,"unexpected exception"); } + + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0); + return true; } -- cgit v1.2.3 From ab0806a036485979d60015a22a8e8831b68643a2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Jul 2017 13:48:39 -0700 Subject: Cleanup. --- node/IncomingPacket.cpp | 5 ++--- node/Packet.hpp | 6 ------ node/Switch.cpp | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9489b16e..be3d082b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -99,7 +99,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) default: // ignore unknown verbs, but if they pass auth check they are "received" peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,0); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true); case Packet::VERB_ERROR: return _doERROR(RR,tPtr,peer); case Packet::VERB_OK: return _doOK(RR,tPtr,peer); @@ -122,7 +121,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) return false; } } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode() (outer)"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); return true; } } @@ -332,7 +331,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool } } - // Handle COR if present (older versions don't send this) + // Certificates of representation (if present) if ((ptr + 2) <= size()) { if (at(ptr) > 0) { CertificateOfRepresentation cor; diff --git a/node/Packet.hpp b/node/Packet.hpp index b8e69fa9..4192b4e3 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1274,12 +1274,6 @@ public: /** * Encrypt/decrypt a separately armored portion of a packet * - * This currently uses Salsa20/12, but any message that uses this should - * incorporate a cipher selector to permit this to be changed later. To - * ensure that key stream is not reused, the key is slightly altered for - * this use case and the same initial 32 keystream bytes that are taken - * for MAC in ordinary armor() are also skipped here. - * * This is currently only used to mask portions of HELLO as an extra * security precation since most of that message is sent in the clear. * diff --git a/node/Switch.cpp b/node/Switch.cpp index eee49775..9c9daac9 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -60,7 +60,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre try { const uint64_t now = RR->node->now(); - SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); + const SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); if (len == 13) { -- cgit v1.2.3 From 1685659e37f568c727580634e412674cc266ff31 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Jul 2017 17:02:50 -0700 Subject: Remote tracing works. --- controller/EmbeddedNetworkController.cpp | 12 ++++++++--- node/IncomingPacket.cpp | 4 +++- node/NetworkConfig.hpp | 29 -------------------------- node/Packet.hpp | 4 ---- node/Trace.cpp | 35 ++++++++++++++++---------------- node/Trace.hpp | 2 +- 6 files changed, 30 insertions(+), 56 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index c2024962..07ab5168 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1089,7 +1089,9 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) { try { std::vector nw4m(_db.networksForMember(rt.origin)); - if (nw4m.empty()) // ignore these for unknown members + + // Ignore remote traces from members we don't know about + if (nw4m.empty()) return; // Convert Dictionary into JSON object @@ -1133,7 +1135,8 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) } } - bool accept = false; + bool accept = true; + /* for(std::vector::const_iterator nwid(nw4m.begin());nwid!=nw4m.end();++nwid) { json nconf; if (_db.getNetwork(*nwid,nconf)) { @@ -1153,9 +1156,10 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) } catch ( ... ) {} // ignore missing fields or other errors, drop trace message } } + */ if (accept) { char p[128]; - OSUtils::ztsnprintf(p,sizeof(p),"trace/%.10llx_%.16llx.json",rt.origin,OSUtils::now()); + OSUtils::ztsnprintf(p,sizeof(p),"trace/%.10llx-%.10llx-%.16llx",_signingId.address().toInt(),rt.origin,OSUtils::now()); _db.writeRaw(p,OSUtils::jsonDump(d)); } } catch ( ... ) { @@ -1419,6 +1423,8 @@ void EmbeddedNetworkController::_request( rtt = OSUtils::jsonString(network["remoteTraceTarget"],""); if (rtt.length() == 10) { nc->remoteTraceTarget = Address(Utils::hexStrToU64(rtt.c_str())); + } else { + nc->remoteTraceTarget = _signingId.address(); } } diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index be3d082b..51955bf3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -115,6 +115,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer); case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer); + case Packet::VERB_REMOTE_TRACE: return _doREMOTE_TRACE(RR,tPtr,peer); } } else { RR->sw->requestWhois(tPtr,sourceAddress); @@ -1172,8 +1173,9 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con while (ptr < eof) { if (!*ptr) { // end of string rt.len = (unsigned int)(ptr - rt.data); - if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) + if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) { RR->node->postEvent(tPtr,ZT_EVENT_REMOTE_TRACE,&rt); + } rt.data = const_cast(++ptr); // start of next string, if any } else { ++ptr; diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index fb48edc9..3fd5ddac 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -410,35 +410,6 @@ public: return (Tag *)0; } - /* - inline void dump() const - { - printf("networkId==%.16llx\n",networkId); - printf("timestamp==%llu\n",timestamp); - printf("credentialTimeMaxDelta==%llu\n",credentialTimeMaxDelta); - printf("revision==%llu\n",revision); - printf("issuedTo==%.10llx\n",issuedTo.toInt()); - printf("multicastLimit==%u\n",multicastLimit); - printf("flags=%.8lx\n",(unsigned long)flags); - printf("specialistCount==%u\n",specialistCount); - for(unsigned int i=0;i(&(routes[i].target))->toString().c_str()); - printf(" routes[i].via==%s\n",reinterpret_cast(&(routes[i].via))->toIpString().c_str()); - printf(" routes[i].flags==%.4x\n",(unsigned int)routes[i].flags); - printf(" routes[i].metric==%u\n",(unsigned int)routes[i].metric); - } - printf("staticIpCount==%u\n",staticIpCount); - for(unsigned int i=0;ilocalSocket()); } d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); - _send(tPtr,d,network); + _send(tPtr,d,*network); } void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason) @@ -161,7 +161,7 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) @@ -218,7 +218,7 @@ void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,con d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller); - _send(tPtr,d,0); + _send(tPtr,d,network); } void Trace::networkFilter( @@ -259,7 +259,7 @@ void Trace::networkFilter( d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); if (frameLen > 0) d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen); - _send(tPtr,d,network.id()); + _send(tPtr,d,network); } void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) @@ -273,7 +273,7 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); if (reason) d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason) @@ -287,7 +287,7 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c, d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); if (reason) d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason) @@ -313,7 +313,7 @@ void Trace::credentialRejected(void *const tPtr,const Capability &c,const char * d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); if (reason) d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason) @@ -328,7 +328,7 @@ void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason) d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); if (reason) d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason) @@ -341,7 +341,7 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char * d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); if (reason) d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c) @@ -353,7 +353,7 @@ void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) @@ -365,7 +365,7 @@ void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c) @@ -387,7 +387,7 @@ void Trace::credentialAccepted(void *const tPtr,const Capability &c) d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialAccepted(void *const tPtr,const Tag &c) @@ -400,7 +400,7 @@ void Trace::credentialAccepted(void *const tPtr,const Tag &c) d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::credentialAccepted(void *const tPtr,const Revocation &c) @@ -411,7 +411,7 @@ void Trace::credentialAccepted(void *const tPtr,const Revocation &c) d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); - _send(tPtr,d,0); + _send(tPtr,d,c.networkId()); } void Trace::_send(void *const tPtr,const Dictionary &d) @@ -434,7 +434,6 @@ void Trace::_send(void *const tPtr,const Dictionary &d } } _traceMsgBuf[i] = (char)0; - //printf("%s\n",_traceMsgBuf); RR->node->postEvent(tPtr,ZT_EVENT_TRACE,_traceMsgBuf); #endif @@ -461,11 +460,11 @@ void Trace::_send(void *const tPtr,const Dictionary &d } } -void Trace::_send(void *const tPtr,const Dictionary &d,const SharedPtr &network) +void Trace::_send(void *const tPtr,const Dictionary &d,const Network &network) { _send(tPtr,d); - if ((network)&&(network->config().remoteTraceTarget)) { - Packet outp(network->config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + if (network.config().remoteTraceTarget) { + Packet outp(network.config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); outp.appendCString(d.data()); outp.compress(); RR->sw->send(tPtr,outp,true); diff --git a/node/Trace.hpp b/node/Trace.hpp index 7fe48cdd..d66d0871 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -154,7 +154,7 @@ private: void _send(void *const tPtr,const Dictionary &d); void _send(void *const tPtr,const Dictionary &d,const uint64_t networkId); - void _send(void *const tPtr,const Dictionary &d,const SharedPtr &network); + void _send(void *const tPtr,const Dictionary &d,const Network &network); #ifdef ZT_TRACE char _traceMsgBuf[4096]; -- cgit v1.2.3 From 727ccb112543f3c44da3d094fa755e3a5d25cc3e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 18 Jul 2017 13:57:37 -0700 Subject: Cleanup and stdin/stdout harness mode for controller. --- controller/JSONDB.cpp | 185 +++++++++++++++++++++++++++++++------------- controller/JSONDB.hpp | 3 + node/IncomingPacket.cpp | 2 - service/SoftwareUpdater.cpp | 9 --- 4 files changed, 133 insertions(+), 66 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index 0c061266..7f92d6ee 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -16,6 +16,18 @@ * along with this program. If not, see . */ +#include +#include +#include +#ifndef __WINDOWS__ +#include +#include +#include +#include +#include +#include +#endif + #include "JSONDB.hpp" #define ZT_JSONDB_HTTP_TIMEOUT 60000 @@ -27,9 +39,12 @@ static const std::map _ZT_JSONDB_GET_HEADERS; JSONDB::JSONDB(const std::string &basePath) : _basePath(basePath), + _rawInput(-1), + _rawOutput(-1), _summaryThreadRun(true) { if ((_basePath.length() > 7)&&(_basePath.substr(0,7) == "http://")) { + // If base path is http:// we run in HTTP mode // TODO: this doesn't yet support IPv6 since bracketed address notiation isn't supported. // Typically it's just used with 127.0.0.1 anyway. std::string hn = _basePath.substr(7); @@ -46,16 +61,27 @@ JSONDB::JSONDB(const std::string &basePath) : _basePath = "/"; if (_basePath[0] != '/') _basePath = std::string("/") + _basePath; +#ifndef __WINDOWS__ + } else if (_basePath == "-") { + // If base path is "-" we run in stdin/stdout mode and expect our database to be populated on startup via stdin + // Not supported on Windows + _rawInput = STDIN_FILENO; + _rawOutput = STDOUT_FILENO; + fcntl(_rawInput,F_SETFL,O_NONBLOCK); +#endif } else { + // Default mode of operation is to store files in the filesystem OSUtils::mkdir(_basePath.c_str()); OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions } - unsigned int cnt = 0; - while (!_load(_basePath)) { - if ((++cnt & 7) == 0) - fprintf(stderr,"WARNING: controller still waiting to read '%s'..." ZT_EOL_S,_basePath.c_str()); - Thread::sleep(250); + if (_rawInput < 0) { + unsigned int cnt = 0; + while (!_load(_basePath)) { + if ((++cnt & 7) == 0) + fprintf(stderr,"WARNING: controller still waiting to read '%s'..." ZT_EOL_S,_basePath.c_str()); + Thread::sleep(250); + } } for(std::unordered_map::iterator n(_networks.begin());n!=_networks.end();++n) @@ -89,7 +115,18 @@ JSONDB::~JSONDB() bool JSONDB::writeRaw(const std::string &n,const std::string &obj) { - if (_httpAddr) { + if (_rawOutput >= 0) { +#ifndef __WINDOWS__ + if (obj.length() > 0) { + Mutex::Lock _l(_rawLock); + if (write(_rawOutput,obj.c_str(),obj.length() + 1) > 0) + return true; + } else { + return true; + } +#endif + return false; + } else if (_httpAddr) { std::map headers; std::string body; std::map reqHeaders; @@ -205,11 +242,13 @@ nlohmann::json JSONDB::eraseNetwork(const uint64_t networkId) char n[256]; OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId); - if (_httpAddr) { - // Deletion is currently done by Central in harnessed mode - //std::map headers; - //std::string body; - //Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); + if (_rawOutput >= 0) { + // In harnessed mode, deletes occur in Central or other management + // software and do not need to be executed this way. + } else if (_httpAddr) { + std::map headers; + std::string body; + Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); } else { const std::string path(_genPath(n,false)); if (path.length()) @@ -232,11 +271,13 @@ nlohmann::json JSONDB::eraseNetworkMember(const uint64_t networkId,const uint64_ char n[256]; OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId); - if (_httpAddr) { - // Deletion is currently done by the caller in Central harnessed mode - //std::map headers; - //std::string body; - //Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); + if (_rawOutput >= 0) { + // In harnessed mode, deletes occur in Central or other management + // software and do not need to be executed this way. + } else if (_httpAddr) { + std::map headers; + std::string body; + Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); } else { const std::string path(_genPath(n,false)); if (path.length()) @@ -263,9 +304,41 @@ nlohmann::json JSONDB::eraseNetworkMember(const uint64_t networkId,const uint64_ void JSONDB::threadMain() throw() { +#ifndef __WINDOWS__ + fd_set readfds,nullfds; + char *const readbuf = (_rawInput >= 0) ? (new char[1048576]) : (char *)0; + std::string rawInputBuf; + FD_ZERO(&readfds); + FD_ZERO(&nullfds); +#endif + std::vector todo; + while (_summaryThreadRun) { - Thread::sleep(10); +#ifndef __WINDOWS__ + if (_rawInput < 0) { + Thread::sleep(25); + } else { + FD_SET(_rawInput,&readfds); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 25000; + select(_rawInput+1,&readfds,&nullfds,&nullfds,&tv); + if (FD_ISSET(_rawInput,&readfds)) { + const long rn = (long)read(_rawInput,readbuf,1048576); + for(long i=0;i 0) { + _add(OSUtils::jsonParse(rawInputBuf)); + rawInputBuf.clear(); + } + } + } + } +#else + Thread::sleep(25); +#endif { Mutex::Lock _l(_summaryThread_m); @@ -273,7 +346,6 @@ void JSONDB::threadMain() continue; else _summaryThreadToDo.swap(todo); } - const uint64_t now = OSUtils::now(); for(std::vector::iterator ii(todo.begin());ii!=todo.end();++ii) { const uint64_t networkId = *ii; @@ -340,10 +412,46 @@ void JSONDB::threadMain() todo.clear(); } + +#ifndef __WINDOWS__ + delete [] readbuf; +#endif +} + +bool JSONDB::_add(const nlohmann::json &j) +{ + try { + if (j.is_object()) { + std::string id(OSUtils::jsonString(j["id"],"0")); + std::string objtype(OSUtils::jsonString(j["objtype"],"")); + + if ((id.length() == 16)&&(objtype == "network")) { + const uint64_t nwid = Utils::hexStrToU64(id.c_str()); + if (nwid) { + Mutex::Lock _l(_networks_m); + _networks[nwid].config = nlohmann::json::to_msgpack(j); + return true; + } + } else if ((id.length() == 10)&&(objtype == "member")) { + const uint64_t mid = Utils::hexStrToU64(id.c_str()); + const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str()); + if ((mid)&&(nwid)) { + Mutex::Lock _l(_networks_m); + _networks[nwid].members[mid] = nlohmann::json::to_msgpack(j); + _members[mid].insert(nwid); + return true; + } + } + } + } catch ( ... ) {} + return false; } bool JSONDB::_load(const std::string &p) { + // This is not used in stdin/stdout mode. Instead data is populated by + // sending it all to stdin. + if (_httpAddr) { // In HTTP harnessed mode we download our entire working data set on startup. @@ -357,24 +465,9 @@ bool JSONDB::_load(const std::string &p) if (dbImg.is_object()) { Mutex::Lock _l(_networks_m); for(nlohmann::json::iterator i(dbImg.begin());i!=dbImg.end();++i) { - nlohmann::json &j = i.value(); - if (j.is_object()) { - std::string id(OSUtils::jsonString(j["id"],"0")); - std::string objtype(OSUtils::jsonString(j["objtype"],"")); - - if ((id.length() == 16)&&(objtype == "network")) { - const uint64_t nwid = Utils::hexStrToU64(id.c_str()); - if (nwid) - _networks[nwid].config = nlohmann::json::to_msgpack(j); - } else if ((id.length() == 10)&&(objtype == "member")) { - const uint64_t mid = Utils::hexStrToU64(id.c_str()); - const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str()); - if ((mid)&&(nwid)) { - _networks[nwid].members[mid] = nlohmann::json::to_msgpack(j); - _members[mid].insert(nwid); - } - } - } + try { + _add(i.value()); + } catch ( ... ) {} } return true; } @@ -391,25 +484,7 @@ bool JSONDB::_load(const std::string &p) std::string buf; if (OSUtils::readFile((p + ZT_PATH_SEPARATOR_S + *di).c_str(),buf)) { try { - nlohmann::json j(OSUtils::jsonParse(buf)); - std::string id(OSUtils::jsonString(j["id"],"0")); - std::string objtype(OSUtils::jsonString(j["objtype"],"")); - - if ((id.length() == 16)&&(objtype == "network")) { - const uint64_t nwid = Utils::hexStrToU64(id.c_str()); - if (nwid) { - Mutex::Lock _l(_networks_m); - _networks[nwid].config = nlohmann::json::to_msgpack(j); - } - } else if ((id.length() == 10)&&(objtype == "member")) { - const uint64_t mid = Utils::hexStrToU64(id.c_str()); - const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str()); - if ((mid)&&(nwid)) { - Mutex::Lock _l(_networks_m); - _networks[nwid].members[mid] = nlohmann::json::to_msgpack(j); - _members[mid].insert(nwid); - } - } + _add(OSUtils::jsonParse(buf)); } catch ( ... ) {} } } else { diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index 99b69ba2..23d00a51 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -145,12 +145,15 @@ public: throw(); private: + bool _add(const nlohmann::json &j); bool _load(const std::string &p); void _recomputeSummaryInfo(const uint64_t networkId); std::string _genPath(const std::string &n,bool create); std::string _basePath; InetAddress _httpAddr; + int _rawInput,_rawOutput; + Mutex _rawLock; Thread _summaryThread; std::vector _summaryThreadToDo; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 51955bf3..e5e10476 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -81,14 +81,12 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { - //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops()); return true; } } if (!uncompress()) { - //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),Packet::VERB_NOP,"LZ4 decompression failed"); return true; } diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 57ecce78..11005945 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -243,7 +243,6 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } } @@ -258,7 +257,6 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; idx |= (unsigned long)*(reinterpret_cast(data) + 20); - //printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast(data) + 1,16).c_str()); std::map< Array,_D >::iterator d(_dist.find(Array(reinterpret_cast(data) + 1))); if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) { Buffer buf; @@ -267,7 +265,6 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void buf.append((uint32_t)idx); buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx))); _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); - //printf(">> DATA @%u\n",(unsigned int)idx); } } break; @@ -278,7 +275,6 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; idx |= (unsigned long)*(reinterpret_cast(data) + 20); - //printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length()); if (idx == (unsigned long)_download.length()) { _download.append(reinterpret_cast(data) + 21,len - 21); if (_download.length() < _downloadLength) { @@ -287,7 +283,6 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } } @@ -334,7 +329,6 @@ bool SoftwareUpdater::check(const uint64_t now) (int)ZT_VENDOR_ZEROTIER, _channel.c_str()); _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); - //printf(">> GET_LATEST\n"); } if (_latestValid) @@ -360,7 +354,6 @@ bool SoftwareUpdater::check(const uint64_t now) if (OSUtils::writeFile(binPath.c_str(),_download)) { OSUtils::lockDownFile(binPath.c_str(),false); _latestValid = true; - //printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); _download = std::string(); _downloadLength = 0; return true; @@ -370,7 +363,6 @@ bool SoftwareUpdater::check(const uint64_t now) } catch ( ... ) {} // any exception equals verification failure // If we get here, checks failed. - //printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); OSUtils::rm(binPath.c_str()); _latestMeta = nlohmann::json(); _latestValid = false; @@ -382,7 +374,6 @@ bool SoftwareUpdater::check(const uint64_t now) gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } -- cgit v1.2.3 From fcaf1d89c260943d3c9c4021b9ab6fe89c1c4de8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 13:59:22 -0700 Subject: Get rid of some noisy remote traces that should not be needed. --- node/IncomingPacket.cpp | 13 ++++---- node/Membership.cpp | 3 -- node/Trace.cpp | 79 ++----------------------------------------------- node/Trace.hpp | 9 +----- 4 files changed, 10 insertions(+), 94 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e5e10476..3788708d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -66,10 +66,9 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // packets are dropped on the floor. const uint64_t tpid = trustedPathId(); if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { - RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,true); trusted = true; } else { - RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,false); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted"); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -81,7 +80,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); return true; } } @@ -246,10 +245,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); } } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid identity"); } return true; @@ -257,7 +256,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); return true; } @@ -282,7 +281,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index a1453307..17de6554 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -147,7 +147,6 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_REJECTED; case 0: _com = com; - RR->t->credentialAccepted(tPtr,com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -179,7 +178,6 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot RR->t->credentialRejected(tPtr,cred,"invalid"); return Membership::ADD_REJECTED; case 0: - RR->t->credentialAccepted(tPtr,cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -205,7 +203,6 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { - RR->t->credentialAccepted(tPtr,rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } diff --git a/node/Trace.cpp b/node/Trace.cpp index 98a4adcb..8e78b676 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -164,12 +164,7 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) -{ - // TODO -} - -void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops) +void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) { char tmp[128]; Dictionary d; @@ -179,6 +174,8 @@ void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const Sh d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); _send(tPtr,d,0); } @@ -344,76 +341,6 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char * _send(tPtr,d,c.networkId()); } -void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - _send(tPtr,d,0); -} - -void Trace::credentialAccepted(void *const tPtr,const Capability &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const Tag &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const Revocation &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); - _send(tPtr,d,c.networkId()); -} - void Trace::_send(void *const tPtr,const Dictionary &d) { #ifdef ZT_TRACE diff --git a/node/Trace.hpp b/node/Trace.hpp index d66d0871..a7b2b194 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -108,8 +108,7 @@ public: void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); - void incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); - void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops); + void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); @@ -142,12 +141,6 @@ public: void credentialRejected(void *const tPtr,const Capability &c,const char *reason); void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); - void credentialAccepted(void *const tPtr,const CertificateOfMembership &c); - void credentialAccepted(void *const tPtr,const CertificateOfOwnership &c); - void credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c); - void credentialAccepted(void *const tPtr,const Capability &c); - void credentialAccepted(void *const tPtr,const Tag &c); - void credentialAccepted(void *const tPtr,const Revocation &c); private: const RuntimeEnvironment *const RR; -- cgit v1.2.3 From 6ee201865b12f5b0f16208f6d696b1bf00197eaf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:42:17 -0700 Subject: Clean up WHOIS code. --- node/Capability.cpp | 3 +- node/CertificateOfMembership.cpp | 3 +- node/CertificateOfOwnership.cpp | 3 +- node/Constants.hpp | 9 +-- node/IncomingPacket.cpp | 4 +- node/Node.cpp | 26 ++++---- node/Revocation.cpp | 3 +- node/Switch.cpp | 132 ++++++++++++++++++++------------------- node/Switch.hpp | 24 +++---- node/Tag.cpp | 3 +- node/Topology.cpp | 35 +++-------- node/Topology.hpp | 14 +---- 12 files changed, 115 insertions(+), 144 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Capability.cpp b/node/Capability.cpp index 0e02025a..47dca1fc 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -59,7 +60,7 @@ int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) return -1; } else { - RR->sw->requestWhois(tPtr,_custody[c].from); + RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from); return 1; } } diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 100253e1..dedcccff 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -29,6 +29,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -223,7 +224,7 @@ int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) con const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 31d0ae18..eeb0d99c 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) cons return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Constants.hpp b/node/Constants.hpp index 27dce075..cda1af3b 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -228,20 +228,15 @@ */ #define ZT_WHOIS_RETRY_DELAY 500 -/** - * Maximum identity WHOIS retries (each attempt tries consulting a different peer) - */ -#define ZT_MAX_WHOIS_RETRIES 5 - /** * Transmit queue entry timeout */ -#define ZT_TRANSMIT_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +#define ZT_TRANSMIT_QUEUE_TIMEOUT 5000 /** * Receive queue entry timeout */ -#define ZT_RECEIVE_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +#define ZT_RECEIVE_QUEUE_TIMEOUT 5000 /** * Maximum latency to allow for OK(HELLO) before packet is discarded diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3788708d..685f2f09 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -115,7 +115,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) case Packet::VERB_REMOTE_TRACE: return _doREMOTE_TRACE(RR,tPtr,peer); } } else { - RR->sw->requestWhois(tPtr,sourceAddress); + RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); return false; } } catch ( ... ) { @@ -556,7 +556,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar ++count; } else { // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(tPtr,addr); + RR->sw->requestWhois(tPtr,RR->node->now(),addr); } } diff --git a/node/Node.cpp b/node/Node.cpp index 366ddbf0..09260172 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -249,6 +249,19 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint try { _lastPingCheck = now; + // Do pings and keepalives + Hashtable< Address,std::vector > upstreamsToContact; + RR->topology->getUpstreamsToContact(upstreamsToContact); + _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); + RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); + + // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) + Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); + Address *upstreamAddress = (Address *)0; + std::vector *upstreamStableEndpoints = (std::vector *)0; + while (i.next(upstreamAddress,upstreamStableEndpoints)) + RR->sw->requestWhois(tptr,now,*upstreamAddress); + // Get networks that need config without leaving mutex locked { std::vector< std::pair< SharedPtr,bool > > nwl; @@ -268,19 +281,6 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } } - // Do pings and keepalives - Hashtable< Address,std::vector > upstreamsToContact; - RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); - RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); - - // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) - Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(tptr,*upstreamAddress); - // Update online status, post status change as event const bool oldOnline = _online; _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 026058da..89a2db95 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Switch.cpp b/node/Switch.cpp index 0d39bee9..8446602c 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -50,7 +50,6 @@ namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : RR(renv), _lastBeaconResponse(0), - _outstandingWhoisRequests(32), _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine { } @@ -229,8 +228,8 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } } } else { - relayTo = RR->topology->getUpstreamPeer(&source,1,true); - if (relayTo) + relayTo = RR->topology->getUpstreamPeer(); + if ((relayTo)&&(relayTo->address() != source)) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } } @@ -553,33 +552,35 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) } } -void Switch::requestWhois(void *tPtr,const Address &addr) +void Switch::requestWhois(void *tPtr,const uint64_t now,const Address &addr) { if (addr == RR->identity.address()) return; - bool inserted = false; + { - Mutex::Lock _l(_outstandingWhoisRequests_m); - WhoisRequest &r = _outstandingWhoisRequests[addr]; - if (r.lastSent) { - r.retries = 0; // reset retry count if entry already existed, but keep waiting and retry again after normal timeout - } else { - r.lastSent = RR->node->now(); - inserted = true; - } + Mutex::Lock _l(_lastSentWhoisRequest_m); + uint64_t &last = _lastSentWhoisRequest[addr]; + if ((now - last) < ZT_WHOIS_RETRY_DELAY) + return; + else last = now; + } + + const SharedPtr upstream(RR->topology->getUpstreamPeer()); + if (upstream) { + Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); + addr.appendTo(outp); + RR->node->expectReplyTo(outp.packetId()); + send(tPtr,outp,true); } - if (inserted) - _sendWhoisRequest(tPtr,addr,(const Address *)0,0); } void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) { - { // cancel pending WHOIS since we now know this peer - Mutex::Lock _l(_outstandingWhoisRequests_m); - _outstandingWhoisRequests.erase(peer->address()); + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + _lastSentWhoisRequest.erase(peer->address()); } - // finish processing any packets waiting on peer's public key / identity const uint64_t now = RR->node->now(); for(unsigned int ptr=0;ptr &peer) } } - { // finish sending any packets waiting on peer's public key / identity + { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); - else ++txi; - } else ++txi; - } - } -} - -unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) -{ - unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - - { // Retry outstanding WHOIS requests - Mutex::Lock _l(_outstandingWhoisRequests_m); - Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests); - Address *a = (Address *)0; - WhoisRequest *r = (WhoisRequest *)0; - while (i.next(a,r)) { - const unsigned long since = (unsigned long)(now - r->lastSent); - if (since >= ZT_WHOIS_RETRY_DELAY) { - if (r->retries >= ZT_MAX_WHOIS_RETRIES) { - _outstandingWhoisRequests.erase(*a); } else { - r->lastSent = now; - r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); - ++r->retries; - nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); + ++txi; } } else { - nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since); + ++txi; } } } +} - { // Time out TX queue packets that never got WHOIS lookups or other info. +unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) +{ + const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; + if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) + return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); + _lastCheckedQueues = now; + + { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); - _txQueue.erase(txi++); - } else ++txi; + _txQueue.erase(txi); + ++txi; + } else if (!RR->topology->getPeer(tPtr,txi->dest)) { + requestWhois(tPtr,now,txi->dest); + ++txi; + } else { + ++txi; + } + } + } + + for(unsigned int ptr=0;ptrtimestamp)&&(rq->complete)) { + if ((rq->frag0.tryDecode(RR,tPtr))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { + rq->timestamp = 0; + } else { + const Address src(rq->frag0.source()); + if (!RR->topology->getPeer(tPtr,src)) + requestWhois(tPtr,now,src); + } } } - { // Remove really old last unite attempt entries to keep table size controlled + { Mutex::Lock _l(_lastUniteAttempt_m); Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt); _LastUniteKey *k = (_LastUniteKey *)0; @@ -650,7 +655,18 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) } } - return nextDelay; + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + Hashtable< Address,uint64_t >::Iterator i(_lastSentWhoisRequest); + Address *a = (Address *)0; + uint64_t *ts = (uint64_t *)0; + while (i.next(a,ts)) { + if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) + _lastSentWhoisRequest.erase(*a); + } + } + + return ZT_WHOIS_RETRY_DELAY; } bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination) @@ -664,18 +680,6 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address return false; } -Address Switch::_sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) -{ - SharedPtr upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); - if (upstream) { - Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); - addr.appendTo(outp); - RR->node->expectReplyTo(outp.packetId()); - send(tPtr,outp,true); - } - return Address(); -} - bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; @@ -709,7 +713,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - requestWhois(tPtr,destination); + requestWhois(tPtr,now,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } diff --git a/node/Switch.hpp b/node/Switch.hpp index 88415541..2420607d 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -111,9 +111,10 @@ public: * Request WHOIS on a given address * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time * @param addr Address to look up */ - void requestWhois(void *tPtr,const Address &addr); + void requestWhois(void *tPtr,const uint64_t now,const Address &addr); /** * Run any processes that are waiting for this peer's identity @@ -139,34 +140,27 @@ public: private: bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); - Address _sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; + uint64_t _lastCheckedQueues; - // Outstanding WHOIS requests and how many retries they've undergone - struct WhoisRequest - { - WhoisRequest() : lastSent(0),retries(0) {} - uint64_t lastSent; - Address peersConsulted[ZT_MAX_WHOIS_RETRIES]; // by retry - unsigned int retries; // 0..ZT_MAX_WHOIS_RETRIES - }; - Hashtable< Address,WhoisRequest > _outstandingWhoisRequests; - Mutex _outstandingWhoisRequests_m; + // Time we last sent a WHOIS request for each address + Hashtable< Address,uint64_t > _lastSentWhoisRequest; + Mutex _lastSentWhoisRequest_m; // Packets waiting for WHOIS replies or other decode info or missing fragments struct RXQueueEntry { RXQueueEntry() : timestamp(0) {} - uint64_t timestamp; // 0 if entry is not in use - uint64_t packetId; + volatile uint64_t timestamp; // 0 if entry is not in use + volatile uint64_t packetId; IncomingPacket frag0; // head of packet Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) unsigned int totalFragments; // 0 if only frag0 received, waiting for frags uint32_t haveFragments; // bit mask, LSB to MSB - bool complete; // if true, packet is complete + volatile bool complete; // if true, packet is complete }; RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE]; AtomicCounter _rxQueuePtr; diff --git a/node/Tag.cpp b/node/Tag.cpp index 39b17f2a..bde41a70 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Topology.cpp b/node/Topology.cpp index aeca59a7..ee5d969d 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -154,13 +154,11 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) return Identity(); } -SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) +SharedPtr Topology::getUpstreamPeer() { const uint64_t now = RR->node->now(); - unsigned int bestQualityOverall = ~((unsigned int)0); - unsigned int bestQualityNotAvoid = ~((unsigned int)0); - const SharedPtr *bestOverall = (const SharedPtr *)0; - const SharedPtr *bestNotAvoid = (const SharedPtr *)0; + unsigned int bestq = ~((unsigned int)0); + const SharedPtr *best = (const SharedPtr *)0; Mutex::Lock _l1(_peers_m); Mutex::Lock _l2(_upstreams_m); @@ -168,32 +166,17 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { const SharedPtr *p = _peers.get(*a); if (p) { - bool avoiding = false; - for(unsigned int i=0;iaddress()) { - avoiding = true; - break; - } - } const unsigned int q = (*p)->relayQuality(now); - if (q <= bestQualityOverall) { - bestQualityOverall = q; - bestOverall = &(*p); - } - if ((!avoiding)&&(q <= bestQualityNotAvoid)) { - bestQualityNotAvoid = q; - bestNotAvoid = &(*p); + if (q <= bestq) { + bestq = q; + best = p; } } } - if (bestNotAvoid) { - return *bestNotAvoid; - } else if ((!strictAvoid)&&(bestOverall)) { - return *bestOverall; - } - - return SharedPtr(); + if (!best) + return SharedPtr(); + return *best; } bool Topology::isUpstream(const Identity &id) const diff --git a/node/Topology.hpp b/node/Topology.hpp index 04dfb1cc..43921896 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -127,19 +127,9 @@ public: /** * Get the current best upstream peer * - * @return Root server with lowest latency or NULL if none + * @return Upstream or NULL if none available */ - inline SharedPtr getUpstreamPeer() { return getUpstreamPeer((const Address *)0,0,false); } - - /** - * Get the current best upstream peer, avoiding those in the supplied avoid list - * - * @param avoid Nodes to avoid - * @param avoidCount Number of nodes to avoid - * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available - * @return Root server or NULL if none available - */ - SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); + SharedPtr getUpstreamPeer(); /** * @param id Identity to check -- cgit v1.2.3 From b1d60df44cb24589bc5718da932ef4bb54168fa3 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Mon, 2 Oct 2017 15:52:57 -0700 Subject: timestamps changed from uint64_t to int64_t There were cases in the code where time calculations and comparisons were overflowing and causing connection instability. This will keep time calculations within expected ranges. --- controller/EmbeddedNetworkController.cpp | 14 +++--- controller/EmbeddedNetworkController.hpp | 8 ++-- controller/JSONDB.cpp | 4 +- controller/JSONDB.hpp | 2 +- include/ZeroTierOne.h | 12 ++--- node/CertificateOfMembership.hpp | 2 +- node/IncomingPacket.cpp | 12 ++--- node/IncomingPacket.hpp | 4 +- node/Membership.cpp | 8 ++-- node/Membership.hpp | 14 +++--- node/Multicaster.cpp | 8 ++-- node/Multicaster.hpp | 12 ++--- node/Network.cpp | 10 ++--- node/Network.hpp | 4 +- node/Node.cpp | 34 +++++++------- node/Node.hpp | 26 +++++------ node/OutboundMulticast.hpp | 2 +- node/Path.cpp | 2 +- node/Path.hpp | 22 ++++----- node/Peer.cpp | 35 ++++++++------- node/Peer.hpp | 76 ++++++++++++++++---------------- node/Revocation.hpp | 4 +- node/SelfAwareness.cpp | 6 +-- node/SelfAwareness.hpp | 4 +- node/Switch.cpp | 20 ++++----- node/Switch.hpp | 14 +++--- node/Topology.cpp | 7 +-- node/Topology.hpp | 4 +- one.cpp | 6 +-- osdep/OSUtils.hpp | 6 +-- osdep/PortMapper.cpp | 2 +- service/OneService.cpp | 22 +++++---- service/SoftwareUpdater.cpp | 2 +- service/SoftwareUpdater.hpp | 2 +- 34 files changed, 209 insertions(+), 201 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 1d46d5e6..20f81966 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -535,7 +535,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( } else { // Get network - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); JSONDB::NetworkSummaryInfo ns; _db.getNetworkSummaryInfo(nwid,ns); _addNetworkNonPersistedFields(network,now,ns); @@ -602,7 +602,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( responseContentType = "application/json"; return 400; } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (path[0] == "network") { @@ -1087,7 +1087,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) } } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); OSUtils::ztsnprintf(id,sizeof(id),"%.10llx-%.10llx-%.16llx-%.8lx",_signingId.address().toInt(),rt.origin,now,++idCounter); d["id"] = id; d["objtype"] = "trace"; @@ -1129,7 +1129,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) void EmbeddedNetworkController::onNetworkUpdate(const uint64_t networkId) { // Send an update to all members of the network that are online - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); Mutex::Lock _l(_memberStatus_m); for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData)) @@ -1150,7 +1150,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const uint64_t networkId,c void EmbeddedNetworkController::onNetworkMemberDeauthorize(const uint64_t networkId,const uint64_t memberId) { - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); Revocation rev((uint32_t)_node->prng(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM); rev.sign(_signingId); { @@ -1224,7 +1224,7 @@ void EmbeddedNetworkController::_request( if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (requestPacketId) { Mutex::Lock _l(_memberStatus_m); @@ -1360,7 +1360,7 @@ void EmbeddedNetworkController::_request( // If we made it this far, they are authorized. // ------------------------------------------------------------------------- - uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; if (now > ns.mostRecentDeauthTime) { // If we recently de-authorized a member, shrink credential TTL/max delta to // be below the threshold required to exclude it. Cap this to a min/max to diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 19469164..fce56065 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -166,7 +166,7 @@ private: } network["objtype"] = "network"; } - inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const JSONDB::NetworkSummaryInfo &ns) + inline void _addNetworkNonPersistedFields(nlohmann::json &network,int64_t now,const JSONDB::NetworkSummaryInfo &ns) { network["clock"] = now; network["authorizedMemberCount"] = ns.authorizedMemberCount; @@ -182,7 +182,7 @@ private: // legacy fields network.erase("lastModified"); } - inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,uint64_t now) + inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,int64_t now) { member["clock"] = now; Mutex::Lock _l(_memberStatus_m); @@ -197,7 +197,7 @@ private: member.erase("lastRequestMetaData"); } - const uint64_t _startTime; + const int64_t _startTime; volatile bool _running; BlockingQueue<_RQEntry *> _queue; @@ -230,7 +230,7 @@ private: Dictionary lastRequestMetaData; Identity identity; InetAddress physicalAddr; // last known physical address - inline bool online(const uint64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } + inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } }; struct _MemberStatusHash { diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index f362acf3..67b13393 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -323,7 +323,7 @@ void JSONDB::threadMain() _networks_m.unlock(); } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); try { Mutex::Lock _l(_networks_m); for(std::vector::iterator ii(todo.begin());ii!=todo.end();++ii) { @@ -373,7 +373,7 @@ void JSONDB::threadMain() } catch ( ... ) {} } else { try { - ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,OSUtils::jsonInt(member["lastDeauthorizedTime"],0ULL)); + ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,(int64_t)OSUtils::jsonInt(member["lastDeauthorizedTime"],0LL)); } catch ( ... ) {} } ++ns.totalMemberCount; diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index 44f4d7f5..db909cb0 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -57,7 +57,7 @@ public: unsigned long authorizedMemberCount; unsigned long activeMemberCount; unsigned long totalMemberCount; - uint64_t mostRecentDeauthTime; + int64_t mostRecentDeauthTime; }; JSONDB(const std::string &basePath,EmbeddedNetworkController *parent); diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index cf6b21fd..8adbc4d1 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1587,7 +1587,7 @@ struct ZT_Node_Callbacks * @param now Current clock in milliseconds * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); +ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); /** * Delete a node and free all resources it consumes @@ -1615,12 +1615,12 @@ ZT_SDK_API void ZT_Node_delete(ZT_Node *node); ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); /** * Process a frame from a virtual network port (tap) @@ -1641,7 +1641,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -1649,7 +1649,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); /** * Perform periodic background operations @@ -1660,7 +1660,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); +ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); /** * Join a network diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 3ffa814f..0105fade 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -176,7 +176,7 @@ public: /** * @return Timestamp for this cert and maximum delta for timestamp */ - inline uint64_t timestamp() const + inline int64_t timestamp() const { for(unsigned int i=0;i<_qualifierCount;++i) { if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 685f2f09..c0409c91 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -169,7 +169,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar // Peers can send this in response to frames if they do not have a recent enough COM from us networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); const SharedPtr network(RR->node->network(networkId)); - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(tPtr,peer->address(),now); } break; @@ -202,7 +202,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); const uint64_t pid = packetId(); const Address fromAddress(source()); @@ -210,7 +210,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; 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 int64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id; unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); @@ -725,7 +725,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); uint64_t authOnNetwork[256]; // cache for approved network IDs unsigned int authOnNetworkCount = 0; @@ -1082,7 +1082,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { @@ -1186,7 +1186,7 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); if (peer->rateGateOutgoingComRequest(now)) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)verb()); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 45a0166d..c8f52721 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -77,7 +77,7 @@ public: * @param now Current time * @throws std::out_of_range Range error processing packet */ - IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) : + IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,int64_t now) : Packet(data,len), _receiveTime(now), _path(path) @@ -93,7 +93,7 @@ public: * @param now Current time * @throws std::out_of_range Range error processing packet */ - inline void init(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) + inline void init(const void *data,unsigned int len,const SharedPtr &path,int64_t now) { copyFrom(data,len); _receiveTime = now; diff --git a/node/Membership.cpp b/node/Membership.cpp index 17de6554..740f4e68 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -51,7 +51,7 @@ Membership::Membership() : resetPushState(); } -void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force) +void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force) { bool sendCom = ( (nconf.com) && ( ((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) ); @@ -127,13 +127,13 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const u Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) { - const uint64_t newts = com.timestamp(); + const int64_t newts = com.timestamp(); if (newts <= _comRevocationThreshold) { RR->t->credentialRejected(tPtr,com,"revoked"); return ADD_REJECTED; } - const uint64_t oldts = _com.timestamp(); + const int64_t oldts = _com.timestamp(); if (newts < oldts) { RR->t->credentialRejected(tPtr,com,"old"); return ADD_REJECTED; @@ -227,7 +227,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -void Membership::clean(const uint64_t now,const NetworkConfig &nconf) +void Membership::clean(const int64_t now,const NetworkConfig &nconf) { _cleanCredImpl(nconf,_remoteTags); _cleanCredImpl(nconf,_remoteCaps); diff --git a/node/Membership.hpp b/node/Membership.hpp index c6e2b803..5612858a 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -80,7 +80,7 @@ public: * @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none * @param force If true, send objects regardless of last push time */ - void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); + void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); /** * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true @@ -88,7 +88,7 @@ public: * @param now Current time * @return True if we should update multicasts */ - inline bool multicastLikeGate(const uint64_t now) + inline bool multicastLikeGate(const int64_t now) { if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) { _lastUpdatedMulticast = now; @@ -110,7 +110,7 @@ public: return nconf.com.agreesWith(_com); } - inline bool recentlyAssociated(const uint64_t now) const + inline bool recentlyAssociated(const int64_t now) const { return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); } @@ -180,7 +180,7 @@ public: * @param now Current time * @param nconf Current network configuration */ - void clean(const uint64_t now,const NetworkConfig &nconf); + void clean(const int64_t now,const NetworkConfig &nconf); /** * Reset last pushed time for local credentials @@ -223,13 +223,13 @@ private: } // Last time we pushed MULTICAST_LIKE(s) - uint64_t _lastUpdatedMulticast; + int64_t _lastUpdatedMulticast; // Last time we pushed our COM to this peer - uint64_t _lastPushedCom; + int64_t _lastPushedCom; // Revocation threshold for COM or 0 if none - uint64_t _comRevocationThreshold; + int64_t _comRevocationThreshold; // Remote member's latest network COM CertificateOfMembership _com; diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index e8c8613a..fa6f7bd1 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -51,7 +51,7 @@ Multicaster::~Multicaster() { } -void Multicaster::addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) +void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) { const unsigned char *p = (const unsigned char *)addresses; const unsigned char *e = p + (5 * count); @@ -160,7 +160,7 @@ std::vector
Multicaster::getMembers(uint64_t nwid,const MulticastGroup void Multicaster::send( void *tPtr, unsigned int limit, - uint64_t now, + int64_t now, uint64_t nwid, bool disableCompression, const std::vector
&alwaysSendTo, @@ -309,7 +309,7 @@ void Multicaster::send( delete [] indexes; } -void Multicaster::clean(uint64_t now) +void Multicaster::clean(int64_t now) { { Mutex::Lock _l(_groups_m); @@ -367,7 +367,7 @@ void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bo } } -void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) +void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) { // assumes _groups_m is locked diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 69a6645d..08c96485 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -98,7 +98,7 @@ public: * @param mg Multicast group * @param member New member address */ - inline void add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) + inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) { Mutex::Lock _l(_groups_m); _add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); @@ -117,7 +117,7 @@ public: * @param count Number of addresses * @param totalKnown Total number of known addresses as reported by peer */ - void addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); + void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); /** * Remove a multicast group member (if present) @@ -174,7 +174,7 @@ public: void send( void *tPtr, unsigned int limit, - uint64_t now, + int64_t now, uint64_t nwid, bool disableCompression, const std::vector
&alwaysSendTo, @@ -190,7 +190,7 @@ public: * @param RR Runtime environment * @param now Current time */ - void clean(uint64_t now); + void clean(int64_t now); /** * Add an authorization credential @@ -212,7 +212,7 @@ public: * @param now Current time * @return True if GATHER and LIKE should be allowed */ - bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const + bool cacheAuthorized(const Address &a,const uint64_t nwid,const int64_t now) const { Mutex::Lock _l(_gatherAuth_m); const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a)); @@ -220,7 +220,7 @@ public: } private: - void _add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); + void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); const RuntimeEnvironment *RR; diff --git a/node/Network.cpp b/node/Network.cpp index 16155c33..111e4736 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -592,7 +592,7 @@ bool Network::filterOutgoingPacket( const unsigned int etherType, const unsigned int vlanId) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); Address ztFinalDest(ztDest); int localCapabilityIndex = -1; int accept = 0; @@ -1164,7 +1164,7 @@ void Network::requestConfiguration(void *tPtr) bool Network::gate(void *tPtr,const SharedPtr &peer) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); Mutex::Lock _l(_lock); try { if (_config) { @@ -1192,7 +1192,7 @@ bool Network::recentlyAssociatedWith(const Address &addr) void Network::clean() { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); Mutex::Lock _l(_lock); if (_destroyed) @@ -1257,7 +1257,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) } } -void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now) +void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now) { Mutex::Lock _l(_lock); const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); @@ -1377,7 +1377,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); std::vector groups; if (newMulticastGroup) diff --git a/node/Network.hpp b/node/Network.hpp index d4d217f2..1b4da7d2 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -305,7 +305,7 @@ public: * @param mg Multicast group * @param now Current time */ - void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now); + void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now); /** * Validate a credential and learn it if it passes certificate and other checks @@ -357,7 +357,7 @@ public: * @param to Destination peer address * @param now Current time */ - inline void pushCredentialsNow(void *tPtr,const Address &to,const uint64_t now) + inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now) { Mutex::Lock _l(_lock); _membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true); diff --git a/node/Node.cpp b/node/Node.cpp index cc076e4d..31ee8f19 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -54,7 +54,7 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : +Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) : _RR(this), RR(&_RR), _uPtr(uptr), @@ -139,12 +139,12 @@ Node::~Node() ZT_ResultCode Node::processWirePacket( void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { _now = now; RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast(remoteAddress)),packetData,packetLength); @@ -153,7 +153,7 @@ ZT_ResultCode Node::processWirePacket( ZT_ResultCode Node::processVirtualNetworkFrame( void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -161,7 +161,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { _now = now; SharedPtr nw(this->network(nwid)); @@ -175,7 +175,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,int64_t now) : lastReceiveFromUpstream(0), RR(renv), _tPtr(tPtr), @@ -185,7 +185,7 @@ public: { } - uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay + int64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay inline void operator()(Topology &t,const SharedPtr &p) { @@ -234,17 +234,17 @@ private: const RuntimeEnvironment *RR; void *_tPtr; Hashtable< Address,std::vector > &_upstreamsToContact; - const uint64_t _now; + const int64_t _now; const SharedPtr _bestCurrentUpstream; }; -ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) { _now = now; Mutex::Lock bl(_backgroundTasksLock); unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL; - const uint64_t timeSinceLastPingCheck = now - _lastPingCheck; + const int64_t timeSinceLastPingCheck = now - _lastPingCheck; if (timeSinceLastPingCheck >= ZT_PING_CHECK_INVERVAL) { try { _lastPingCheck = now; @@ -305,7 +305,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } try { - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); + *nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -689,7 +689,7 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) { *node = (ZT_Node *)0; try { @@ -714,12 +714,12 @@ void ZT_Node_delete(ZT_Node *node) enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { try { return reinterpret_cast(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); @@ -733,7 +733,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -741,7 +741,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { try { return reinterpret_cast(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); @@ -752,7 +752,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( } } -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) { try { return reinterpret_cast(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline); diff --git a/node/Node.hpp b/node/Node.hpp index 1aa01c9a..ae7976d4 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -64,7 +64,7 @@ class World; class Node : public NetworkController::Sender { public: - Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); + Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); virtual ~Node(); // Get rid of alignment warnings on 32-bit Windows and possibly improve performance @@ -77,15 +77,15 @@ public: ZT_ResultCode processWirePacket( void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); ZT_ResultCode processVirtualNetworkFrame( void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -93,8 +93,8 @@ public: unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); + ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); @@ -114,7 +114,7 @@ public: // Internal functions ------------------------------------------------------ - inline uint64_t now() const { return _now; } + inline int64_t now() const { return _now; } inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { @@ -243,7 +243,7 @@ public: * @param from Source address of packet * @return True if within rate limits */ - inline bool rateGateIdentityVerification(const uint64_t now,const InetAddress &from) + inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from) { unsigned long iph = from.rateGateHash(); if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { @@ -270,7 +270,7 @@ private: uint32_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; // Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification() - uint64_t _lastIdentityVerification[16384]; + int64_t _lastIdentityVerification[16384]; Hashtable< uint64_t,SharedPtr > _networks; Mutex _networks_m; @@ -281,10 +281,10 @@ private: Mutex _backgroundTasksLock; Address _remoteTraceTarget; - uint64_t _now; - uint64_t _lastPingCheck; - uint64_t _lastHousekeepingRun; - volatile uint64_t _prngState[2]; + int64_t _now; + int64_t _lastPingCheck; + int64_t _lastHousekeepingRun; + volatile int64_t _prngState[2]; bool _online; }; diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 486b66ff..2f6d8338 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -96,7 +96,7 @@ public: * @param now Current time * @return True if this multicast is expired (has exceeded transmit timeout) */ - inline bool expired(uint64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } + inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } /** * @return True if this outbound multicast has been sent to enough peers diff --git a/node/Path.cpp b/node/Path.cpp index 9dc9aba5..ca366e39 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -30,7 +30,7 @@ namespace ZeroTier { -bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) +bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now) { if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { _lastOut = now; diff --git a/node/Path.hpp b/node/Path.hpp index ac8e4c0e..050fb6e2 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -179,14 +179,14 @@ public: * @param now Current time * @return True if transport reported success */ - bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now); + bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now); /** * Manually update last sent time * * @param t Time of send */ - inline void sent(const uint64_t t) { _lastOut = t; } + inline void sent(const int64_t t) { _lastOut = t; } /** * @return Local socket as specified by external code @@ -206,7 +206,7 @@ public: /** * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms */ - inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } /** * @return Preference rank, higher == better @@ -261,27 +261,27 @@ public: /** * @return True if path appears alive */ - inline bool alive(const uint64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } + inline bool alive(const int64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } /** * @return True if this path needs a heartbeat */ - inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } + inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } /** * @return Last time we sent something */ - inline uint64_t lastOut() const { return _lastOut; } + inline int64_t lastOut() const { return _lastOut; } /** * @return Last time we received anything */ - inline uint64_t lastIn() const { return _lastIn; } + inline int64_t lastIn() const { return _lastIn; } /** * @return Time last trust-established packet was received */ - inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } + inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } /** * Return and increment outgoing packet counter (used with Packet::armor()) @@ -291,9 +291,9 @@ public: inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } private: - volatile uint64_t _lastOut; - volatile uint64_t _lastIn; - volatile uint64_t _lastTrustEstablishedPacketReceived; + volatile int64_t _lastOut; + volatile int64_t _lastIn; + volatile int64_t _lastTrustEstablishedPacketReceived; volatile uint64_t _incomingLinkQualityFastLog; int64_t _localSocket; volatile unsigned long _incomingLinkQualitySlowLogPtr; diff --git a/node/Peer.cpp b/node/Peer.cpp index a954b716..60661592 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -34,6 +34,7 @@ #include "SelfAwareness.hpp" #include "Packet.hpp" #include "Trace.hpp" +#include "InetAddress.hpp" namespace ZeroTier { @@ -75,7 +76,7 @@ void Peer::received( const bool trustEstablished, const uint64_t networkId) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); /* #ifdef ZT_ENABLE_CLUSTER @@ -263,14 +264,14 @@ void Peer::received( } } -bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force) { Mutex::Lock _l(_paths_m); - uint64_t v6lr = 0; + int64_t v6lr = 0; if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) v6lr = _v6Path.p->lastIn(); - uint64_t v4lr = 0; + int64_t v4lr = 0; if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) v4lr = _v4Path.p->lastIn(); @@ -289,16 +290,18 @@ bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now, return false; } -SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) +SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); - uint64_t v6lr = 0; - if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) ) + int64_t v6lr = 0; + if ((includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v6Path.p)) { v6lr = _v6Path.p->lastIn(); - uint64_t v4lr = 0; - if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) ) + } + int64_t v4lr = 0; + if ((includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v4Path.p)) { v4lr = _v4Path.p->lastIn(); + } if (v6lr > v4lr) { return _v6Path.p; @@ -309,7 +312,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) return SharedPtr(); } -void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -357,7 +360,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA } } -void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); @@ -369,7 +372,7 @@ void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAdd } } -void Peer::tryMemorizedPath(void *tPtr,uint64_t now) +void Peer::tryMemorizedPath(void *tPtr,int64_t now) { if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { _lastTriedMemorizedPath = now; @@ -379,15 +382,15 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now) } } -bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) +bool Peer::doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); if (inetAddressFamily < 0) { - uint64_t v6lr = 0; + int64_t v6lr = 0; if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) v6lr = _v6Path.p->lastIn(); - uint64_t v4lr = 0; + int64_t v4lr = 0; if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) v4lr = _v4Path.p->lastIn(); @@ -423,7 +426,7 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } -void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now) +void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) { if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check return; diff --git a/node/Peer.hpp b/node/Peer.hpp index af9163a5..e08f7d36 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -120,7 +120,7 @@ public: * @param addr Remote address * @return True if we have an active path to this destination */ - inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const + inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); @@ -136,7 +136,7 @@ public: * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force); + bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force); /** * Get the best current direct path @@ -148,7 +148,7 @@ public: * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none */ - SharedPtr getBestPath(uint64_t now,bool includeExpired); + SharedPtr getBestPath(int64_t now,bool includeExpired); /** * Send a HELLO to this peer at a specified physical address @@ -161,7 +161,7 @@ public: * @param now Current time * @param counter Outgoing packet counter */ - void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -175,7 +175,7 @@ public: * @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param counter Outgoing packet counter */ - void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known @@ -185,7 +185,7 @@ public: * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time */ - void tryMemorizedPath(void *tPtr,uint64_t now); + void tryMemorizedPath(void *tPtr,int64_t now); /** * Send pings or keepalives depending on configured timeouts @@ -195,7 +195,7 @@ public: * @param inetAddressFamily Keep this address family alive, or -1 for any * @return True if we have at least one direct path of the given family (or any if family is -1) */ - bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); + bool doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily); /** * Specify remote path for this peer and forget others @@ -209,7 +209,7 @@ public: * @param remoteAddress Remote address * @param now Current time */ - void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now); + void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); /** * Reset paths within a given IP scope and address family @@ -222,7 +222,7 @@ public: * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) + inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) { Mutex::Lock _l(_paths_m); if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { @@ -243,7 +243,7 @@ public: * @param v4 Result parameter to receive active IPv4 address, if any * @param v6 Result parameter to receive active IPv6 address, if any */ - inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const + inline void getRendezvousAddresses(int64_t now,InetAddress &v4,InetAddress &v6) const { Mutex::Lock _l(_paths_m); if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) @@ -256,7 +256,7 @@ public: * @param now Current time * @return All known paths to this peer */ - inline std::vector< SharedPtr > paths(const uint64_t now) const + inline std::vector< SharedPtr > paths(const int64_t now) const { std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); @@ -270,17 +270,17 @@ public: /** * @return Time of last receive of anything, whether direct or relayed */ - inline uint64_t lastReceive() const { return _lastReceive; } + inline int64_t lastReceive() const { return _lastReceive; } /** * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT */ - inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return True if this peer has sent us real network traffic recently */ - inline uint64_t isActive(uint64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Latency in milliseconds or 0 if unknown @@ -298,7 +298,7 @@ public: * * @return Relay quality score computed from latency and other factors, lower is better */ - inline unsigned int relayQuality(const uint64_t now) const + inline unsigned int relayQuality(const int64_t now) const { const uint64_t tsr = now - _lastReceive; if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) @@ -353,12 +353,12 @@ public: /** * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms */ - inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } /** * Rate limit gate for VERB_PUSH_DIRECT_PATHS */ - inline bool rateGatePushDirectPaths(const uint64_t now) + inline bool rateGatePushDirectPaths(const int64_t now) { if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) ++_directPathPushCutoffCount; @@ -370,7 +370,7 @@ public: /** * Rate limit gate for VERB_NETWORK_CREDENTIALS */ - inline bool rateGateCredentialsReceived(const uint64_t now) + inline bool rateGateCredentialsReceived(const int64_t now) { if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME) ++_credentialsCutoffCount; @@ -382,7 +382,7 @@ public: /** * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE */ - inline bool rateGateRequestCredentials(const uint64_t now) + inline bool rateGateRequestCredentials(const int64_t now) { if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastCredentialRequestSent = now; @@ -394,7 +394,7 @@ public: /** * Rate limit gate for inbound WHOIS requests */ - inline bool rateGateInboundWhoisRequest(const uint64_t now) + inline bool rateGateInboundWhoisRequest(const int64_t now) { if ((now - _lastWhoisRequestReceived) >= ZT_PEER_WHOIS_RATE_LIMIT) { _lastWhoisRequestReceived = now; @@ -406,7 +406,7 @@ public: /** * Rate limit gate for inbound ECHO requests */ - inline bool rateGateEchoRequest(const uint64_t now) + inline bool rateGateEchoRequest(const int64_t now) { if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastEchoRequestReceived = now; @@ -418,7 +418,7 @@ public: /** * Rate gate incoming requests for network COM */ - inline bool rateGateIncomingComRequest(const uint64_t now) + inline bool rateGateIncomingComRequest(const int64_t now) { if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestReceived = now; @@ -430,7 +430,7 @@ public: /** * Rate gate outgoing requests for network COM */ - inline bool rateGateOutgoingComRequest(const uint64_t now) + inline bool rateGateOutgoingComRequest(const int64_t now) { if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestSent = now; @@ -484,7 +484,7 @@ public: } template - inline static SharedPtr deserializeFromCache(uint64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) + inline static SharedPtr deserializeFromCache(int64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) { try { unsigned int ptr = 0; @@ -527,8 +527,8 @@ private: struct _PeerPath { _PeerPath() : lr(0),sticky(0),p() {} - uint64_t lr; // time of last valid ZeroTier packet - uint64_t sticky; // time last set as sticky + int64_t lr; // time of last valid ZeroTier packet + int64_t sticky; // time last set as sticky SharedPtr p; }; @@ -536,18 +536,18 @@ private: const RuntimeEnvironment *RR; - uint64_t _lastReceive; // direct or indirect - uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. - uint64_t _lastTriedMemorizedPath; - uint64_t _lastDirectPathPushSent; - uint64_t _lastDirectPathPushReceive; - uint64_t _lastCredentialRequestSent; - uint64_t _lastWhoisRequestReceived; - uint64_t _lastEchoRequestReceived; - uint64_t _lastComRequestReceived; - uint64_t _lastComRequestSent; - uint64_t _lastCredentialsReceived; - uint64_t _lastTrustEstablishedPacketReceived; + int64_t _lastReceive; // direct or indirect + int64_t _lastNontrivialReceive; // frames, things like netconf, etc. + int64_t _lastTriedMemorizedPath; + int64_t _lastDirectPathPushSent; + int64_t _lastDirectPathPushReceive; + int64_t _lastCredentialRequestSent; + int64_t _lastWhoisRequestReceived; + int64_t _lastEchoRequestReceived; + int64_t _lastComRequestReceived; + int64_t _lastComRequestSent; + int64_t _lastCredentialsReceived; + int64_t _lastTrustEstablishedPacketReceived; uint16_t _vProto; uint16_t _vMajor; diff --git a/node/Revocation.hpp b/node/Revocation.hpp index a28da0ab..7f7498bb 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -85,7 +85,7 @@ public: inline uint32_t id() const { return _id; } inline uint32_t credentialId() const { return _credentialId; } inline uint64_t networkId() const { return _networkId; } - inline uint64_t threshold() const { return _threshold; } + inline int64_t threshold() const { return _threshold; } inline const Address &target() const { return _target; } inline const Address &signer() const { return _signedBy; } inline Credential::Type type() const { return _type; } @@ -184,7 +184,7 @@ private: uint32_t _id; uint32_t _credentialId; uint64_t _networkId; - uint64_t _threshold; + int64_t _threshold; uint64_t _flags; Address _target; Address _signedBy; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 0af0d691..83cd89c9 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -49,7 +49,7 @@ namespace ZeroTier { class _ResetWithinScope { public: - _ResetWithinScope(void *tPtr,uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : + _ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), @@ -70,7 +70,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) +void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -112,7 +112,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive } } -void SelfAwareness::clean(uint64_t now) +void SelfAwareness::clean(int64_t now) { Mutex::Lock _l(_phy_m); Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 35e0ad39..7ddba465 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -55,14 +55,14 @@ public: * @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param now Current time */ - void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); + void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now); /** * Clean up database periodically * * @param now Current time */ - void clean(uint64_t now); + void clean(int64_t now); /** * If we appear to be behind a symmetric NAT, get predictions for possible external endpoints diff --git a/node/Switch.cpp b/node/Switch.cpp index f46b3e73..cc022b6b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -57,7 +57,7 @@ Switch::Switch(const RuntimeEnvironment *renv) : void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len) { try { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); const SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); @@ -557,14 +557,14 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) } } -void Switch::requestWhois(void *tPtr,const uint64_t now,const Address &addr) +void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr) { if (addr == RR->identity.address()) return; { Mutex::Lock _l(_lastSentWhoisRequest_m); - uint64_t &last = _lastSentWhoisRequest[addr]; + int64_t &last = _lastSentWhoisRequest[addr]; if ((now - last) < ZT_WHOIS_RETRY_DELAY) return; else last = now; @@ -586,7 +586,7 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) _lastSentWhoisRequest.erase(peer->address()); } - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); for(unsigned int ptr=0;ptrtimestamp)&&(rq->complete)) { @@ -611,7 +611,7 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) } } -unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) +unsigned long Switch::doTimerTasks(void *tPtr,int64_t now) { const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) @@ -663,9 +663,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) { Mutex::Lock _l(_lastSentWhoisRequest_m); - Hashtable< Address,uint64_t >::Iterator i(_lastSentWhoisRequest); + Hashtable< Address,int64_t >::Iterator i(_lastSentWhoisRequest); Address *a = (Address *)0; - uint64_t *ts = (uint64_t *)0; + int64_t *ts = (int64_t *)0; while (i.next(a,ts)) { if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) _lastSentWhoisRequest.erase(*a); @@ -675,7 +675,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) return ZT_WHOIS_RETRY_DELAY; } -bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination) +bool Switch::_shouldUnite(const int64_t now,const Address &source,const Address &destination) { Mutex::Lock _l(_lastUniteAttempt_m); uint64_t &ts = _lastUniteAttempt[_LastUniteKey(source,destination)]; @@ -689,7 +689,7 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); const Address destination(packet.destination()); const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); @@ -703,7 +703,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) viaPath = peer->getBestPath(now,false); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(int64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } diff --git a/node/Switch.hpp b/node/Switch.hpp index c258a255..b42389fc 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -114,7 +114,7 @@ public: * @param now Current time * @param addr Address to look up */ - void requestWhois(void *tPtr,const uint64_t now,const Address &addr); + void requestWhois(void *tPtr,const int64_t now,const Address &addr); /** * Run any processes that are waiting for this peer's identity @@ -136,25 +136,25 @@ public: * @param now Current time * @return Number of milliseconds until doTimerTasks() should be run again */ - unsigned long doTimerTasks(void *tPtr,uint64_t now); + unsigned long doTimerTasks(void *tPtr,int64_t now); private: - bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); + bool _shouldUnite(const int64_t now,const Address &source,const Address &destination); bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; - uint64_t _lastBeaconResponse; - volatile uint64_t _lastCheckedQueues; + int64_t _lastBeaconResponse; + volatile int64_t _lastCheckedQueues; // Time we last sent a WHOIS request for each address - Hashtable< Address,uint64_t > _lastSentWhoisRequest; + Hashtable< Address,int64_t > _lastSentWhoisRequest; Mutex _lastSentWhoisRequest_m; // Packets waiting for WHOIS replies or other decode info or missing fragments struct RXQueueEntry { RXQueueEntry() : timestamp(0) {} - volatile uint64_t timestamp; // 0 if entry is not in use + volatile int64_t timestamp; // 0 if entry is not in use volatile uint64_t packetId; IncomingPacket frag0; // head of packet Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) diff --git a/node/Topology.cpp b/node/Topology.cpp index 8a830b93..f884e9c3 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -133,8 +133,9 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) if (ap) return ap; ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); - if (!ap) + if (!ap) { _peers.erase(zta); + } return SharedPtr(); } } catch ( ... ) {} // ignore invalid identities or other strage failures @@ -157,7 +158,7 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) SharedPtr Topology::getUpstreamPeer() { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); unsigned int bestq = ~((unsigned int)0); const SharedPtr *best = (const SharedPtr *)0; @@ -365,7 +366,7 @@ void Topology::removeMoon(void *tPtr,const uint64_t id) _memoizeUpstreams(tPtr); } -void Topology::doPeriodicTasks(void *tPtr,uint64_t now) +void Topology::doPeriodicTasks(void *tPtr,int64_t now) { { Mutex::Lock _l1(_peers_m); diff --git a/node/Topology.hpp b/node/Topology.hpp index 34df28a1..c3a218e3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -286,13 +286,13 @@ public: /** * Clean and flush database */ - void doPeriodicTasks(void *tPtr,uint64_t now); + void doPeriodicTasks(void *tPtr,int64_t now); /** * @param now Current time * @return Number of peers with active direct paths */ - inline unsigned long countActive(uint64_t now) const + inline unsigned long countActive(int64_t now) const { unsigned long cnt = 0; Mutex::Lock _l(_peers_m); diff --git a/one.cpp b/one.cpp index b1a19e8c..de16cc2d 100644 --- a/one.cpp +++ b/one.cpp @@ -364,9 +364,9 @@ static int cli(int argc,char **argv) if (path["preferred"]) { char tmp[256]; std::string addr = path["address"]; - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); const double lq = (path.count("linkQuality")) ? (double)path["linkQuality"] : -1.0; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%llu;%llu;%1.2f",addr.c_str(),now - (uint64_t)path["lastSend"],now - (uint64_t)path["lastReceive"],lq); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld;%1.2f",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"],lq); bestPath = tmp; break; } @@ -864,7 +864,7 @@ static int idtool(int argc,char **argv) } std::sort(roots.begin(),roots.end()); - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey)); Buffer wbuf; w.serialize(wbuf); diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 8683ba25..8f66f850 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -200,7 +200,7 @@ public: /** * @return Current time in milliseconds since epoch */ - static inline uint64_t now() + static inline int64_t now() { #ifdef __WINDOWS__ FILETIME ft; @@ -210,7 +210,7 @@ public: SystemTimeToFileTime(&st,&ft); tmp.LowPart = ft.dwLowDateTime; tmp.HighPart = ft.dwHighDateTime; - return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds ); + return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds ); #else struct timeval tv; #ifdef __LINUX__ @@ -218,7 +218,7 @@ public: #else gettimeofday(&tv,(struct timezone *)0); #endif - return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) ); + return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) ); #endif }; diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index 0da00653..825972b0 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -131,7 +131,7 @@ public: InetAddress publicAddress; sendpublicaddressrequest(&natpmp); - uint64_t myTimeout = OSUtils::now() + 5000; + int64_t myTimeout = OSUtils::now() + 5000; do { fd_set fds; struct timeval timeout; diff --git a/service/OneService.cpp b/service/OneService.cpp index 66e9a9c8..fb185ee7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -276,6 +276,10 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) pa.push_back(j); } pj["paths"] = pa; + + if (peer->address == 0xda6c71a1ad) { + fprintf(stdout, "%s\n", pj.dump(2).c_str()); + } } static void _moonToJson(nlohmann::json &mj,const World &world) @@ -436,7 +440,7 @@ public: uint64_t _lastRestart; // Deadline for the next background task service function - volatile uint64_t _nextBackgroundTaskDeadline; + volatile int64_t _nextBackgroundTaskDeadline; // Configured networks struct NetworkState @@ -755,12 +759,12 @@ public: // Main I/O loop _nextBackgroundTaskDeadline = 0; - uint64_t clockShouldBe = OSUtils::now(); + int64_t clockShouldBe = OSUtils::now(); _lastRestart = clockShouldBe; - uint64_t lastTapMulticastGroupCheck = 0; - uint64_t lastBindRefresh = 0; - uint64_t lastUpdateCheck = clockShouldBe; - uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle + int64_t lastTapMulticastGroupCheck = 0; + int64_t lastBindRefresh = 0; + int64_t lastUpdateCheck = clockShouldBe; + int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle for(;;) { _run_m.lock(); if (!_run) { @@ -773,7 +777,7 @@ public: _run_m.unlock(); } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); // Attempt to detect sleep/wake events by detecting delay overruns bool restarted = false; @@ -809,7 +813,7 @@ public: } // Run background task processor in core if it's time to do so - uint64_t dl = _nextBackgroundTaskDeadline; + int64_t dl = _nextBackgroundTaskDeadline; if (dl <= now) { _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); dl = _nextBackgroundTaskDeadline; @@ -2152,7 +2156,7 @@ public: // Engage TCP tunnel fallback if we haven't received anything valid from a global // IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting // valid direct traffic we'll stop using it and close the socket after a while. - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { if (_tcpFallbackTunnel) { bool flushNow = false; diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 11005945..39833c90 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -303,7 +303,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void } } -bool SoftwareUpdater::check(const uint64_t now) +bool SoftwareUpdater::check(const int64_t now) { if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) { _lastCheckTime = now; diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index ff3e36df..f16c99a0 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -167,7 +167,7 @@ public: * * @return True if we've downloaded and verified an update */ - bool check(const uint64_t now); + bool check(const int64_t now); /** * @return Meta-data for downloaded update or NULL if none -- cgit v1.2.3 From c7d370c17fc8b44f4d83868de9c6958347b75ca2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 24 Oct 2017 14:49:38 -0700 Subject: Delete something that turns out not to be useful. This will be handled differently. --- node/CertificateOfRepresentation.hpp | 188 ----------------------------------- node/Credential.hpp | 1 - node/IncomingPacket.cpp | 24 ----- node/Peer.cpp | 5 - node/Topology.cpp | 7 -- node/Topology.hpp | 21 ---- node/Trace.cpp | 13 --- node/Trace.hpp | 2 - 8 files changed, 261 deletions(-) delete mode 100644 node/CertificateOfRepresentation.hpp (limited to 'node/IncomingPacket.cpp') diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp deleted file mode 100644 index 3007f1dc..00000000 --- a/node/CertificateOfRepresentation.hpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 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 . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. - */ - -#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP -#define ZT_CERTIFICATEOFREPRESENTATION_HPP - -#include "Constants.hpp" -#include "Credential.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" - -/** - * Maximum number of addresses allowed in a COR - */ -#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS - -namespace ZeroTier { - -/** - * A signed enumeration of a node's roots (planet and moons) - * - * This is sent as part of HELLO and attests to which roots a node trusts - * to represent it on the network. Federated roots (moons) can send these - * further upstream to tell global roots which nodes they represent, making - * them reachable via federated roots if they are not reachable directly. - * - * As of 1.2.0 this is sent but not used. Right now nodes still always - * announce to planetary roots no matter what. In the future this can be - * used to implement even better fault tolerance for federation for the - * no roots are reachable case as well as a "privacy mode" where federated - * roots can shield nodes entirely and p2p connectivity behind them can - * be disabled. This will be desirable for a number of use cases. - */ -class CertificateOfRepresentation : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COR; } - - CertificateOfRepresentation() - { - memset(this,0,sizeof(CertificateOfRepresentation)); - } - - inline uint32_t id() const { return 0; } - inline uint64_t timestamp() const { return _timestamp; } - inline const Address &representative(const unsigned int i) const { return _reps[i]; } - inline unsigned int repCount() const { return _repCount; } - - inline void clear() - { - memset(this,0,sizeof(CertificateOfRepresentation)); - } - - /** - * Add a representative if space remains - * - * @param r Representative to add - * @return True if representative was added - */ - inline bool addRepresentative(const Address &r) - { - if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) { - _reps[_repCount++] = r; - return true; - } - return false; - } - - /** - * Sign this COR with my identity - * - * @param myIdentity This node's identity - * @param ts COR timestamp for establishing new vs. old - */ - inline void sign(const Identity &myIdentity,const uint64_t ts) - { - _timestamp = ts; - Buffer tmp; - this->serialize(tmp,true); - _signature = myIdentity.sign(tmp.data(),tmp.size()); - } - - /** - * Verify this COR's signature - * - * @param senderIdentity Identity of sender of COR - * @return True if COR is valid - */ - inline bool verify(const Identity &senderIdentity) - { - try { - Buffer tmp; - this->serialize(tmp,true); - return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN); - } catch ( ... ) { - return false; - } - } - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append((uint64_t)_timestamp); - b.append((uint16_t)_repCount); - for(unsigned int i=0;i<_repCount;++i) - _reps[i].appendTo(b); - - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - - b.append((uint16_t)0); // size of any additional fields, currently 0 - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - clear(); - - unsigned int p = startAt; - - _timestamp = b.template at(p); p += 8; - const unsigned int rc = b.template at(p); p += 2; - for(unsigned int i=0;i ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc; - - if (b[p++] == 1) { - if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - - return (p - startAt); - } - -private: - uint64_t _timestamp; - Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES]; - unsigned int _repCount; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Credential.hpp b/node/Credential.hpp index bc81919b..e8767e22 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -56,7 +56,6 @@ public: CREDENTIAL_TYPE_CAPABILITY = 2, CREDENTIAL_TYPE_TAG = 3, CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership - CREDENTIAL_TYPE_COR = 5, // CertificateOfRepresentation CREDENTIAL_TYPE_REVOCATION = 6 }; }; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c0409c91..9b614e37 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -44,7 +44,6 @@ #include "World.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" -#include "CertificateOfRepresentation.hpp" #include "Capability.hpp" #include "Tag.hpp" #include "Revocation.hpp" @@ -328,15 +327,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool ptr += 16; } } - - // Certificates of representation (if present) - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } } // Send OK(HELLO) with an echo of the packet's timestamp and some of the same @@ -401,11 +391,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool } outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),now); @@ -460,15 +445,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } } - // Handle certificate of representation if present - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } - if (!hops()) peer->addDirectLatencyMeasurment((unsigned int)latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); diff --git a/node/Peer.cpp b/node/Peer.cpp index 60661592..255d4004 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -343,11 +343,6 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA outp.append((uint64_t)0); } - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); RR->node->expectReplyTo(outp.packetId()); diff --git a/node/Topology.cpp b/node/Topology.cpp index f884e9c3..d5fea569 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -425,13 +425,6 @@ void Topology::_memoizeUpstreams(void *tPtr) } std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); - - _cor.clear(); - for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - if (!_cor.addRepresentative(*a)) - break; - } - _cor.sign(RR->identity,RR->node->now()); } void Topology::_savePeer(void *tPtr,const SharedPtr &peer) diff --git a/node/Topology.hpp b/node/Topology.hpp index c3a218e3..650e5363 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -46,7 +46,6 @@ #include "InetAddress.hpp" #include "Hashtable.hpp" #include "World.hpp" -#include "CertificateOfRepresentation.hpp" namespace ZeroTier { @@ -441,25 +440,6 @@ public: } } - /** - * @return Current certificate of representation (copy) - */ - inline CertificateOfRepresentation certificateOfRepresentation() const - { - Mutex::Lock _l(_upstreams_m); - return _cor; - } - - /** - * @param buf Buffer to receive COR - */ - template - void appendCertificateOfRepresentation(Buffer &buf) - { - Mutex::Lock _l(_upstreams_m); - _cor.serialize(buf); - } - private: Identity _getIdentity(void *tPtr,const Address &zta); void _memoizeUpstreams(void *tPtr); @@ -480,7 +460,6 @@ private: std::vector _moons; std::vector< std::pair > _moonSeeds; std::vector
_upstreamAddresses; - CertificateOfRepresentation _cor; bool _amRoot; Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; diff --git a/node/Trace.cpp b/node/Trace.cpp index 8e78b676..d90c3143 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -32,7 +32,6 @@ #include "Dictionary.hpp" #include "CertificateOfMembership.hpp" #include "CertificateOfOwnership.hpp" -#include "CertificateOfRepresentation.hpp" #include "Tag.hpp" #include "Capability.hpp" #include "Revocation.hpp" @@ -287,18 +286,6 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c, _send(tPtr,d,c.networkId()); } -void Trace::credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); -} - void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason) { Dictionary d; diff --git a/node/Trace.hpp b/node/Trace.hpp index a7b2b194..5ee5b520 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -53,7 +53,6 @@ class NetworkConfig; class MAC; class CertificateOfMembership; class CertificateOfOwnership; -class CertificateOfRepresentation; class Revocation; class Tag; class Capability; @@ -137,7 +136,6 @@ public: void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason); void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason); - void credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason); void credentialRejected(void *const tPtr,const Capability &c,const char *reason); void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); -- cgit v1.2.3 From 459f1e7bfb50eb7b491940b7106d8788a7a5e11f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 25 Oct 2017 12:42:14 -0700 Subject: Refactor path stability stuff and add basic multipath support. --- node/Constants.hpp | 10 -- node/Hashtable.hpp | 5 - node/IncomingPacket.cpp | 7 +- node/InetAddress.cpp | 36 +++-- node/InetAddress.hpp | 4 +- node/Node.cpp | 24 ++-- node/Path.hpp | 30 ++++- node/Peer.cpp | 352 ++++++++++++++++++++++++++++++------------------ node/Peer.hpp | 173 ++++++++++-------------- node/Switch.cpp | 81 ++--------- node/Topology.cpp | 2 +- node/Topology.hpp | 2 +- node/Trace.cpp | 5 +- node/Trace.hpp | 2 +- 14 files changed, 375 insertions(+), 358 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 30cd1575..6360a693 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -268,16 +268,6 @@ */ #define ZT_PATH_HEARTBEAT_PERIOD 14000 -/** - * Paths are considered inactive if they have not received traffic in this long - */ -#define ZT_PATH_ALIVE_TIMEOUT 45000 - -/** - * Minimum time between attempts to check dead paths to see if they can be re-awakened - */ -#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 - /** * Do not accept HELLOs over a given path more often than this */ diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 95a8e74f..e5496592 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -42,11 +42,6 @@ namespace ZeroTier { /** * A minimal hash table implementation for the ZeroTier core - * - * This is not a drop-in replacement for STL containers, and has several - * limitations. Keys can be uint64_t or an object, and if the latter they - * must implement a method called hashCode() that returns an unsigned long - * value that is evenly distributed. */ template class Hashtable diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9b614e37..dfa0a161 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -446,7 +446,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } if (!hops()) - peer->addDirectLatencyMeasurment((unsigned int)latency); + _path->updateLatency((unsigned int)latency); + peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) @@ -1091,7 +1092,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->redirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path->localSocket(),a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } @@ -1105,7 +1106,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->redirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path->localSocket(),a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index f7585bdb..d3efc089 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -273,29 +273,27 @@ InetAddress InetAddress::network() const return r; } -#ifdef ZT_SDK - bool InetAddress::isEqualPrefix(const InetAddress &addr) const - { - if (addr.ss_family == ss_family) { - switch(ss_family) { - case AF_INET6: { - const InetAddress mask(netmask()); - InetAddress addr_mask(addr.netmask()); - const uint8_t *n = reinterpret_cast(reinterpret_cast(&addr_mask)->sin6_addr.s6_addr); - 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] & n[i])) - return false; - } - return true; +bool InetAddress::isEqualPrefix(const InetAddress &addr) const +{ + if (addr.ss_family == ss_family) { + switch(ss_family) { + case AF_INET6: { + const InetAddress mask(netmask()); + InetAddress addr_mask(addr.netmask()); + const uint8_t *n = reinterpret_cast(reinterpret_cast(&addr_mask)->sin6_addr.s6_addr); + 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] & n[i])) + return false; } + return true; } } - return false; } -#endif + return false; +} bool InetAddress::containsAddress(const InetAddress &addr) const { diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 61cdb05e..79bf76ad 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -330,7 +330,6 @@ struct InetAddress : public sockaddr_storage */ InetAddress network() const; -#ifdef ZT_SDK /** * Test whether this IPv6 prefix matches the prefix of a given IPv6 address * @@ -338,8 +337,7 @@ struct InetAddress : public sockaddr_storage * @return True if this IPv6 prefix matches the prefix of a given IPv6 address */ bool isEqualPrefix(const InetAddress &addr) const; -#endif - + /** * Test whether this IP/netmask contains this address * diff --git a/node/Node.cpp b/node/Node.cpp index 31ee8f19..b7dbffc3 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -191,12 +191,13 @@ public: { const std::vector *const upstreamStableEndpoints = _upstreamsToContact.get(p->address()); if (upstreamStableEndpoints) { - bool contacted = false; - // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow // them to perform three way handshake introductions for both stacks. - if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET)) { + const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now); + bool contacted = (sent != 0); + + if ((sent & 0x1) == 0) { // bit 0x1 == IPv4 sent for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { @@ -205,8 +206,9 @@ public: break; } } - } else contacted = true; - if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET6)) { + } + + if ((sent & 0x2) == 0) { // bit 0x2 == IPv6 sent for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { @@ -215,8 +217,10 @@ public: break; } } - } else contacted = true; + } + // If we have no memoized addresses for this upstream peer, attempt to contact + // it indirectly so we will be introduced. if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) @@ -224,9 +228,11 @@ public: } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - _upstreamsToContact.erase(p->address()); // erase from upstreams to contact so that we can WHOIS those that remain + + _upstreamsToContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain } else if (p->isActive(_now)) { - p->doPingAndKeepalive(_tPtr,_now,-1); + // Regular non-upstream nodes get pinged if they appear active. + p->doPingAndKeepalive(_tPtr,_now); } } @@ -420,7 +426,7 @@ ZT_PeerList *Node::peers() const p->versionMinor = -1; p->versionRev = -1; } - p->latency = pi->second->latency(); + p->latency = pi->second->latency(_now); p->role = RR->topology->role(pi->second->identity().address()); std::vector< SharedPtr > paths(pi->second->paths(_now)); diff --git a/node/Path.hpp b/node/Path.hpp index 050fb6e2..80132c13 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -100,6 +100,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _latency(0xffff), _addr(), _ipScope(InetAddress::IP_SCOPE_NONE) { @@ -117,6 +118,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _latency(0xffff), _addr(addr), _ipScope(addr.ipScope()) { @@ -188,6 +190,19 @@ public: */ inline void sent(const int64_t t) { _lastOut = t; } + /** + * Update path latency with a new measurement + * + * @param l Measured latency + */ + inline void updateLatency(const unsigned int l) + { + unsigned int pl = _latency; + if (pl < 0xffff) + _latency = (pl + l) / 2; + else _latency = l; + } + /** * @return Local socket as specified by external code */ @@ -259,9 +274,19 @@ public: } /** - * @return True if path appears alive + * @return Latency or 0xffff if unknown */ - inline bool alive(const int64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } + inline unsigned int latency() const { return _latency; } + + /** + * @return Path quality -- lower is better + */ + inline int quality(const int64_t now) const + { + const int l = (int)_latency; + const int age = (int)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow + return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (int)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); + } /** * @return True if this path needs a heartbeat @@ -300,6 +325,7 @@ private: volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; + volatile unsigned int _latency; InetAddress _addr; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often volatile uint8_t _incomingLinkQualitySlowLog[32]; diff --git a/node/Peer.cpp b/node/Peer.cpp index 255d4004..61d8e990 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -52,12 +52,12 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), + _lastSentFullHello(0), _vProto(0), _vMajor(0), _vMinor(0), _vRevision(0), _id(peerIdentity), - _latency(0), _directPathPushCutoffCount(0), _credentialsCutoffCount(0) { @@ -148,59 +148,47 @@ void Peer::received( if (hops == 0) { // If this is a direct packet (no hops), update existing paths or learn new ones - bool pathAlreadyKnown = false; - - { - Mutex::Lock _l(_paths_m); - if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { - const struct sockaddr_in *const r = reinterpret_cast(&(path->address())); - const struct sockaddr_in *const l = reinterpret_cast(&(_v4Path.p->address())); - if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(path->localSocket() == _v4Path.p->localSocket())) { - _v4Path.lr = now; - pathAlreadyKnown = true; - } - } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { - const struct sockaddr_in6 *const r = reinterpret_cast(&(path->address())); - const struct sockaddr_in6 *const l = reinterpret_cast(&(_v6Path.p->address())); - if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(path->localSocket() == _v6Path.p->localSocket())) { - _v6Path.lr = now; - pathAlreadyKnown = true; - } - } - } - - if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) { - Mutex::Lock _l(_paths_m); + Mutex::Lock _l(_paths_m); - _PeerPath *replacablePath = (_PeerPath *)0; - if (path->address().ss_family == AF_INET) { - if ( ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) && ( (now - _v4Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - replacablePath = &_v4Path; + unsigned int worstQualityPath = 0; + int worstQuality = 0; + bool havePath = false; + for(unsigned int p=0;paddress().ss_family == AF_INET6) { - if ( ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) && ( (now - _v6Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - replacablePath = &_v6Path; + const int q = _paths[p].p->quality(now) / _paths[p].priority; + if (q >= worstQuality) { + worstQuality = q; + worstQualityPath = p; } + } else { + worstQualityPath = p; + break; } + } - if (replacablePath) { - if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(tPtr,networkId,*this,replacablePath->p,path,packetId); - replacablePath->lr = now; - replacablePath->p = path; - } else { - RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); - } + if ((!havePath)&&(RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()))) { + if (verb == Packet::VERB_OK) { + RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[worstQualityPath].p,path,packetId); + _paths[worstQualityPath].lr = now; + _paths[worstQualityPath].p = path; + _paths[worstQualityPath].priority = 1; + } else { + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + path->sent(now); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); } } } - // If we are being relayed or if we're using a global address, send PUSH_DIRECT_PATHS. - // In the global address case we push only configured direct paths to accomplish - // fall-forward to local backplane networks over e.g. LAN or Amazon VPC. - if ( ((hops > 0)||(path->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) && (this->trustEstablished(now)) ) { + // If we have a trust relationship periodically push a message enumerating + // all known external addresses for ourselves. We now do this even if we + // have a current path since we'll want to use new ones too. + if (this->trustEstablished(now)) { if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; @@ -210,6 +198,7 @@ void Peer::received( for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) pathsToPush.push_back(*i); + // Do symmetric NAT prediction if we are communicating indirectly. if (hops > 0) { std::vector sym(RR->sa->getSymmetricNatPredictions()); for(unsigned long i=0,added=0;i Peer::getBestPath(int64_t now,bool includeExpired) const { Mutex::Lock _l(_paths_m); - int64_t v6lr = 0; - if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) - v6lr = _v6Path.p->lastIn(); - int64_t v4lr = 0; - if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) - v4lr = _v4Path.p->lastIn(); - - if ( (v6lr > v4lr) && ((now - v6lr) < ZT_PATH_ALIVE_TIMEOUT) ) { - return _v6Path.p->send(RR,tPtr,data,len,now); - } else if ((now - v4lr) < ZT_PATH_ALIVE_TIMEOUT) { - return _v4Path.p->send(RR,tPtr,data,len,now); - } else if (force) { - if (v6lr > v4lr) { - return _v6Path.p->send(RR,tPtr,data,len,now); - } else if (v4lr) { - return _v4Path.p->send(RR,tPtr,data,len,now); - } + unsigned int bestPath = ZT_PEER_MAX_PATHS; + int bestPathQuality = 2147483647; // INT_MAX + for(unsigned int i=0;iquality(now) / _paths[i].priority; + if (q < bestPathQuality) { + bestPathQuality = q; + bestPath = i; + } + } + } else break; } - return false; + if (bestPath != ZT_PEER_MAX_PATHS) + return _paths[bestPath].p; + return SharedPtr(); } -SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) +void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &other) const { - Mutex::Lock _l(_paths_m); + unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { + myBestV4ByScope[i] = ZT_PEER_MAX_PATHS; + myBestV6ByScope[i] = ZT_PEER_MAX_PATHS; + myBestV4QualityByScope[i] = 2147483647; + myBestV6QualityByScope[i] = 2147483647; + theirBestV4ByScope[i] = ZT_PEER_MAX_PATHS; + theirBestV6ByScope[i] = ZT_PEER_MAX_PATHS; + theirBestV4QualityByScope[i] = 2147483647; + theirBestV6QualityByScope[i] = 2147483647; + } - int64_t v6lr = 0; - if ((includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v6Path.p)) { - v6lr = _v6Path.p->lastIn(); + Mutex::Lock _l1(_paths_m); + + for(unsigned int i=0;iquality(now) / _paths[i].priority; + const unsigned int s = (unsigned int)_paths[i].p->ipScope(); + switch(_paths[i].p->address().ss_family) { + case AF_INET: + if (q < myBestV4QualityByScope[s]) { + myBestV4QualityByScope[s] = q; + myBestV4ByScope[s] = i; + } + break; + case AF_INET6: + if (q < myBestV6QualityByScope[s]) { + myBestV6QualityByScope[s] = q; + myBestV6ByScope[s] = i; + } + break; + } + } else break; } - int64_t v4lr = 0; - if ((includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v4Path.p)) { - v4lr = _v4Path.p->lastIn(); + + Mutex::Lock _l2(other->_paths_m); + + for(unsigned int i=0;i_paths[i].p) { + const int q = other->_paths[i].p->quality(now) / other->_paths[i].priority; + const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); + switch(other->_paths[i].p->address().ss_family) { + case AF_INET: + if (q < theirBestV4QualityByScope[s]) { + theirBestV4QualityByScope[s] = q; + theirBestV4ByScope[s] = i; + } + break; + case AF_INET6: + if (q < theirBestV6QualityByScope[s]) { + theirBestV6QualityByScope[s] = q; + theirBestV6ByScope[s] = i; + } + break; + } + } else break; } - if (v6lr > v4lr) { - return _v6Path.p; - } else if (v4lr) { - return _v4Path.p; + unsigned int mine = ZT_PEER_MAX_PATHS; + unsigned int theirs = ZT_PEER_MAX_PATHS; + + for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) { + if ((myBestV6ByScope[s] != ZT_PEER_MAX_PATHS)&&(theirBestV6ByScope[s] != ZT_PEER_MAX_PATHS)) { + mine = myBestV6ByScope[s]; + theirs = theirBestV6ByScope[s]; + break; + } + if ((myBestV4ByScope[s] != ZT_PEER_MAX_PATHS)&&(theirBestV4ByScope[s] != ZT_PEER_MAX_PATHS)) { + mine = myBestV4ByScope[s]; + theirs = theirBestV4ByScope[s]; + break; + } } - return SharedPtr(); + if (mine != ZT_PEER_MAX_PATHS) { + unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons + const unsigned int completed = alt + 2; + while (alt != completed) { + if ((alt & 1) == 0) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + other->_id.address().appendTo(outp); + outp.append((uint16_t)other->_paths[theirs].p->address().port()); + if (other->_paths[theirs].p->address().ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(other->_paths[theirs].p->address().rawIpData(),16); + } else { + outp.append((uint8_t)4); + outp.append(other->_paths[theirs].p->address().rawIpData(),4); + } + outp.armor(_key,true,_paths[mine].p->nextOutgoingCounter()); + _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); + } else { + Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + _id.address().appendTo(outp); + outp.append((uint16_t)_paths[mine].p->address().port()); + if (_paths[mine].p->address().ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(_paths[mine].p->address().rawIpData(),16); + } else { + outp.append((uint8_t)4); + outp.append(_paths[mine].p->address().rawIpData(),4); + } + outp.armor(other->_key,true,other->_paths[theirs].p->nextOutgoingCounter()); + other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); + } + ++alt; + } + } } void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter) @@ -377,76 +462,83 @@ void Peer::tryMemorizedPath(void *tPtr,int64_t now) } } -bool Peer::doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily) +unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) { + unsigned int sent = 0; + Mutex::Lock _l(_paths_m); - if (inetAddressFamily < 0) { - int64_t v6lr = 0; - if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) - v6lr = _v6Path.p->lastIn(); - int64_t v4lr = 0; - if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) - v4lr = _v4Path.p->lastIn(); - - if (v6lr > v4lr) { - if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); - _v6Path.p->sent(now); - return true; - } - } else if (v4lr) { - if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); - _v4Path.p->sent(now); - return true; - } - } - } else { - if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { - if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); - _v4Path.p->sent(now); - return true; - } - } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { - if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); - _v6Path.p->sent(now); - return true; + const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD); + _lastSentFullHello = now; + + unsigned int j = 0; + for(unsigned int i=0;ineedsHeartbeat(now))) { + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); + _paths[i].p->sent(now); + sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; } + if (i != j) + _paths[j] = _paths[i]; + ++j; } } + while(j < ZT_PEER_MAX_PATHS) { + _paths[j].lr = 0; + _paths[j].p.zero(); + _paths[j].priority = 1; + ++j; + } - return false; + return sent; } -void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) +void Peer::clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) { - if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check - return; - - SharedPtr op; SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); - np->received(now); + RR->t->peerRedirected(tPtr,0,*this,np); attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); - { Mutex::Lock _l(_paths_m); - if (remoteAddress.ss_family == AF_INET) { - op = _v4Path.p; - _v4Path.lr = now; - _v4Path.sticky = now; - _v4Path.p = np; - } else if (remoteAddress.ss_family == AF_INET6) { - op = _v6Path.p; - _v6Path.lr = now; - _v6Path.sticky = now; - _v6Path.p = np; + int worstQuality = 0; + unsigned int worstQualityPath = 0; + for(unsigned int i=0;iquality(now) / _paths[i].priority; + if (q >= worstQuality) { + worstQuality = q; + worstQualityPath = i; + } + } else { + worstQualityPath = i; + break; + } } + _paths[worstQualityPath].lr = now; + _paths[worstQualityPath].p = np; + _paths[worstQualityPath].priority = 6; // 1 + 5 } +} - RR->t->peerRedirected(tPtr,0,*this,op,np); +void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) +{ + Mutex::Lock _l(_paths_m); + for(unsigned int i=0;iaddress().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false,_paths[i].p->nextOutgoingCounter()); + _paths[i].p->sent(now); + _paths[i].lr = 0; // path will not be used unless it speaks again + } + } else break; + } } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index e08f7d36..c236a2cd 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -53,6 +53,15 @@ #define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) +/** + * Maximum number of direct paths to a peer + * + * This can be increased. You'll want about 2X the number of physical links + * you are ever likely to want to bundle/trunk since there is likely to be + * a path for every protocol (IPv4, IPv6, etc.). + */ +#define ZT_PEER_MAX_PATHS 16 + namespace ZeroTier { /** @@ -116,6 +125,8 @@ public: const uint64_t networkId); /** + * Check whether we have an active path to this peer via the given address + * * @param now Current time * @param addr Remote address * @return True if we have an active path to this destination @@ -123,7 +134,13 @@ public: inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); - return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); + for(unsigned int i=0;iaddress() == addr)) + return true; + } else break; + } + return false; } /** @@ -136,19 +153,27 @@ public: * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force); + inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force) + { + SharedPtr bp(getBestPath(now,force)); + if (bp) + return bp->send(RR,tPtr,data,len,now); + return false; + } /** * Get the best current direct path * - * This does not check Path::alive(), but does return the most recently - * active path and does check expiration (which is a longer timeout). - * * @param now Current time * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none */ - SharedPtr getBestPath(int64_t now,bool includeExpired); + SharedPtr getBestPath(int64_t now,bool includeExpired) const; + + /** + * Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path + */ + void introduce(void *const tPtr,const int64_t now,const SharedPtr &other) const; /** * Send a HELLO to this peer at a specified physical address @@ -190,67 +215,39 @@ public: /** * Send pings or keepalives depending on configured timeouts * + * This also cleans up some internal data structures. It's called periodically from Node. + * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param inetAddressFamily Keep this address family alive, or -1 for any - * @return True if we have at least one direct path of the given family (or any if family is -1) + * @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent) */ - bool doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily); + unsigned int doPingAndKeepalive(void *tPtr,int64_t now); /** - * Specify remote path for this peer and forget others - * - * This overrides normal path learning and tells this peer to be found - * at this address, at least within the address's family. Other address - * families are not modified. + * Process a cluster redirect sent by this peer * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localSocket Local socket as supplied by external code * @param remoteAddress Remote address * @param now Current time */ - void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); + void clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); /** * Reset paths within a given IP scope and address family * * Resetting a path involves sending an ECHO to it and then deactivating - * it until or unless it responds. + * it until or unless it responds. This is done when we detect a change + * to our external IP or another system change that might invalidate + * many or all current paths. * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param scope IP scope * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) - { - Mutex::Lock _l(_paths_m); - if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); - _v4Path.p->sent(now); - _v4Path.lr = 0; // path will not be used unless it speaks again - } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); - _v6Path.p->sent(now); - _v6Path.lr = 0; // path will not be used unless it speaks again - } - } - - /** - * Fill parameters with V4 and V6 addresses if known and alive - * - * @param now Current time - * @param v4 Result parameter to receive active IPv4 address, if any - * @param v6 Result parameter to receive active IPv6 address, if any - */ - inline void getRendezvousAddresses(int64_t now,InetAddress &v4,InetAddress &v6) const - { - Mutex::Lock _l(_paths_m); - if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) - v4 = _v4Path.p->address(); - if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) - v6 = _v6Path.p->address(); - } + void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now); /** * @param now Current time @@ -260,10 +257,10 @@ public: { std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); - if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) - pp.push_back(_v4Path.p); - if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) - pp.push_back(_v6Path.p); + for(unsigned int i=0;i bp(getBestPath(now,false)); + return ((bp) ? bp->latency() : 0xffff); + } /** * This computes a quality score for relays and root servers @@ -303,25 +304,12 @@ public: const uint64_t tsr = now - _lastReceive; if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) return (~(unsigned int)0); - unsigned int l = _latency; + unsigned int l = latency(now); if (!l) l = 0xffff; return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1)); } - /** - * Update latency with a new direct measurment - * - * @param l Direct latency measurment in ms - */ - inline void addDirectLatencyMeasurment(unsigned int l) - { - unsigned int ol = _latency; - if ((ol > 0)&&(ol < 10000)) - _latency = (ol + std::min(l,(unsigned int)65535)) / 2; - else _latency = std::min(l,(unsigned int)65535); - } - /** * @return 256-bit secret symmetric encryption key */ @@ -442,29 +430,15 @@ public: /** * Serialize a peer for storage in local cache * - * This does not serialize everything, just identity and addresses where the peer - * may be reached. + * This does not serialize everything, just non-ephemeral information. */ template - inline void serialize(Buffer &b) const + inline void serializeForCache(Buffer &b) const { - b.append((uint8_t)0); + b.append((uint8_t)1); _id.serialize(b); - b.append(_lastReceive); - b.append(_lastNontrivialReceive); - b.append(_lastTriedMemorizedPath); - b.append(_lastDirectPathPushSent); - b.append(_lastDirectPathPushReceive); - b.append(_lastCredentialRequestSent); - b.append(_lastWhoisRequestReceived); - b.append(_lastEchoRequestReceived); - b.append(_lastComRequestReceived); - b.append(_lastComRequestSent); - b.append(_lastCredentialsReceived); - b.append(_lastTrustEstablishedPacketReceived); - b.append((uint16_t)_vProto); b.append((uint16_t)_vMajor); b.append((uint16_t)_vMinor); @@ -472,15 +446,16 @@ public: { Mutex::Lock _l(_paths_m); - unsigned int pcount = 0; - if (_v4Path.p) ++pcount; - if (_v6Path.p) ++pcount; - b.append((uint8_t)pcount); - if (_v4Path.p) _v4Path.p->address().serialize(b); - if (_v6Path.p) _v6Path.p->address().serialize(b); + unsigned int pc = 0; + for(unsigned int i=0;iaddress().serialize(b); } - - b.append((uint16_t)0); } template @@ -488,7 +463,7 @@ public: { try { unsigned int ptr = 0; - if (b[ptr++] != 0) + if (b[ptr++] != 1) return SharedPtr(); Identity id; @@ -498,15 +473,16 @@ public: SharedPtr p(new Peer(renv,renv->identity,id)); - ptr += 12 * 8; // skip deserializing ephemeral state in this case - p->_vProto = b.template at(ptr); ptr += 2; p->_vMajor = b.template at(ptr); ptr += 2; p->_vMinor = b.template at(ptr); ptr += 2; p->_vRevision = b.template at(ptr); ptr += 2; - const unsigned int pcount = (unsigned int)b[ptr++]; - for(unsigned int i=0;i(ptr); ptr += 2; + for(unsigned int i=0;i p; + int priority; // >= 1, higher is better }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -548,19 +524,18 @@ private: int64_t _lastComRequestSent; int64_t _lastCredentialsReceived; int64_t _lastTrustEstablishedPacketReceived; + int64_t _lastSentFullHello; uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; - _PeerPath _v4Path; // IPv4 direct path - _PeerPath _v6Path; // IPv6 direct path + _PeerPath _paths[ZT_PEER_MAX_PATHS]; Mutex _paths_m; Identity _id; - unsigned int _latency; unsigned int _directPathPushCutoffCount; unsigned int _credentialsCutoffCount; diff --git a/node/Switch.cpp b/node/Switch.cpp index cc022b6b..a8cf0ce6 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -169,68 +169,22 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if (packet.hops() < ZT_RELAY_MAX_HOPS) { packet.incrementHops(); - SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { - if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { // don't send RENDEZVOUS for cluster frontplane relays - const InetAddress *hintToSource = (InetAddress *)0; - const InetAddress *hintToDest = (InetAddress *)0; - - InetAddress destV4,destV6; - InetAddress sourceV4,sourceV6; - relayTo->getRendezvousAddresses(now,destV4,destV6); - + if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); - if (sourcePeer) { - sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6); - if ((destV6)&&(sourceV6)) { - hintToSource = &destV6; - hintToDest = &sourceV6; - } else if ((destV4)&&(sourceV4)) { - hintToSource = &destV4; - hintToDest = &sourceV4; - } - - if ((hintToSource)&&(hintToDest)) { - unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for obscure NAT-t reasons - const unsigned int completed = alt + 2; - while (alt != completed) { - if ((alt & 1) == 0) { - Packet outp(source,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - destination.appendTo(outp); - outp.append((uint16_t)hintToSource->port()); - if (hintToSource->ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(hintToSource->rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(hintToSource->rawIpData(),4); - } - send(tPtr,outp,true); - } else { - Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - source.appendTo(outp); - outp.append((uint16_t)hintToDest->port()); - if (hintToDest->ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(hintToDest->rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(hintToDest->rawIpData(),4); - } - send(tPtr,outp,true); - } - ++alt; - } - } - } + if (sourcePeer) + relayTo->introduce(tPtr,now,sourcePeer); } } else { relayTo = RR->topology->getUpstreamPeer(); - if ((relayTo)&&(relayTo->address() != source)) - relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); + if ((relayTo)&&(relayTo->address() != source)) { + if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) { + const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); + if (sourcePeer) + relayTo->introduce(tPtr,now,sourcePeer); + } + } } } } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { @@ -694,22 +648,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); if (peer) { - /* First get the best path, and if it's dead (and this is not a root) - * we attempt to re-activate that path but this packet will flow - * upstream. If the path comes back alive, it will be used in the future. - * For roots we don't do the alive check since roots are not required - * to send heartbeats "down" and because we have to at least try to - * go somewhere. */ - viaPath = peer->getBestPath(now,false); - if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(int64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); - viaPath->sent(now); - } - viaPath.zero(); - } - if (!viaPath) { peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known const SharedPtr relay(RR->topology->getUpstreamPeer()); diff --git a/node/Topology.cpp b/node/Topology.cpp index d5fea569..d1b389df 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -431,7 +431,7 @@ void Topology::_savePeer(void *tPtr,const SharedPtr &peer) { try { Buffer buf; - peer->serialize(buf); + peer->serializeForCache(buf); uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0; RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); } catch ( ... ) {} // sanity check, discard invalid entries diff --git a/node/Topology.hpp b/node/Topology.hpp index 650e5363..b09f95cf 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -300,7 +300,7 @@ public: SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { const SharedPtr pp((*p)->getBestPath(now,false)); - if ((pp)&&(pp->alive(now))) + if (pp) ++cnt; } return cnt; diff --git a/node/Trace.cpp b/node/Trace.cpp index d90c3143..6d85942d 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -92,16 +92,13 @@ void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &p _send(tPtr,d,networkId); } -void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) +void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath) { char tmp[128]; Dictionary d; d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - if (oldPath) { - d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); - } if (newPath) { d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); diff --git a/node/Trace.hpp b/node/Trace.hpp index 5ee5b520..4192d1c2 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -105,7 +105,7 @@ public: void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); - void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); + void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath); void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); -- cgit v1.2.3 From 508fa6a7fed894fd616239c04aeb0c2e8f6b9022 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 25 Oct 2017 15:44:10 -0700 Subject: A few fixes for cluster mode. --- node/IncomingPacket.cpp | 4 +- node/Path.hpp | 13 ++-- node/Peer.cpp | 183 +++++++++++++++++++++++++++++++----------------- node/Peer.hpp | 6 +- 4 files changed, 133 insertions(+), 73 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index dfa0a161..d44e3b54 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1092,7 +1092,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->clusterRedirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } @@ -1106,7 +1106,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->clusterRedirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } diff --git a/node/Path.hpp b/node/Path.hpp index 80132c13..ab52ced6 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -281,13 +281,18 @@ public: /** * @return Path quality -- lower is better */ - inline int quality(const int64_t now) const + inline long quality(const int64_t now) const { - const int l = (int)_latency; - const int age = (int)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow - return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (int)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); + const int l = (long)_latency; + const int age = (long)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow + return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); } + /** + * @return True if this path is alive (receiving heartbeats) + */ + inline bool alive(const int64_t now) const { return ((now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000)); } + /** * @return True if this path needs a heartbeat */ diff --git a/node/Peer.cpp b/node/Peer.cpp index d2692011..d68e0df3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -148,39 +148,64 @@ void Peer::received( if (hops == 0) { // If this is a direct packet (no hops), update existing paths or learn new ones - Mutex::Lock _l(_paths_m); - unsigned int worstQualityPath = 0; - int worstQuality = 0; bool havePath = false; - for(unsigned int p=0;pquality(now) / _paths[p].priority; - if (q >= worstQuality) { - worstQuality = q; - worstQualityPath = p; - } - } else { - worstQualityPath = p; - break; + { + Mutex::Lock _l(_paths_m); + for(unsigned int i=0;inode->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()))) { - if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[worstQualityPath].p,path,packetId); - _paths[worstQualityPath].lr = now; - _paths[worstQualityPath].p = path; - _paths[worstQualityPath].priority = 1; - } else { - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); - RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); + Mutex::Lock _l(_paths_m); + + // Paths are redunant if they duplicate an alive path to the same IP or + // with the same local socket and address family. + bool redundant = false; + for(unsigned int i=0;ialive(now)) && ( ((_paths[i].p->localSocket() == path->localSocket())&&(_paths[i].p->address().ss_family == path->address().ss_family)) || (_paths[i].p->address().ipsEqual(path->address())) ) ) { + redundant = true; + break; + } + } else break; + } + + if (!redundant) { + unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS; + int replacePathQuality = 0; + for(unsigned int i=0;iquality(now); + if (q > replacePathQuality) { + replacePathQuality = q; + replacePath = i; + } + } else { + replacePath = i; + break; + } + } + + if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) { + if (verb == Packet::VERB_OK) { + RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[replacePath].p,path,packetId); + _paths[replacePath].lr = now; + _paths[replacePath].p = path; + _paths[replacePath].priority = 1; + } else { + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + path->sent(now); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); + } + } } } } @@ -258,11 +283,11 @@ SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) const Mutex::Lock _l(_paths_m); unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; - int bestPathQuality = 2147483647; // INT_MAX + long bestPathQuality = 2147483647; for(unsigned int i=0;iquality(now) / _paths[i].priority; + const long q = _paths[i].p->quality(now) / _paths[i].priority; if (q <= bestPathQuality) { bestPathQuality = q; bestPath = i; @@ -280,12 +305,12 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o { unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; @@ -301,7 +326,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o for(unsigned int i=0;iquality(now) / _paths[i].priority; + const long q = _paths[i].p->quality(now) / _paths[i].priority; const unsigned int s = (unsigned int)_paths[i].p->ipScope(); switch(_paths[i].p->address().ss_family) { case AF_INET: @@ -324,7 +349,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o for(unsigned int i=0;i_paths[i].p) { - const int q = other->_paths[i].p->quality(now) / other->_paths[i].priority; + const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority; const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); switch(other->_paths[i].p->address().ss_family) { case AF_INET: @@ -471,19 +496,32 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD); _lastSentFullHello = now; + // Right now we only keep pinging links that have the maximum priority. The + // priority is used to track cluster redirections, meaning that when a cluster + // redirects us its redirect target links override all other links and we + // let those old links expire. + long maxPriority = 0; + for(unsigned int i=0;ineedsHeartbeat(now))) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); - _paths[i].p->sent(now); - sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; + if (_paths[i].p) { + // Clean expired and reduced priority paths + if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) { + if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) { + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); + _paths[i].p->sent(now); + sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; + } + if (i != j) + _paths[j] = _paths[i]; + ++j; } - if (i != j) - _paths[j] = _paths[i]; - ++j; - } + } else break; } while(j < ZT_MAX_PEER_NETWORK_PATHS) { _paths[j].lr = 0; @@ -495,35 +533,52 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) return sent; } -void Peer::clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) +void Peer::clusterRedirect(void *tPtr,const SharedPtr &originatingPath,const InetAddress &remoteAddress,const int64_t now) { - SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + SharedPtr np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress)); RR->t->peerRedirected(tPtr,0,*this,np); - attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); + + attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true,np->nextOutgoingCounter()); + { Mutex::Lock _l(_paths_m); - int worstQuality = 0; - unsigned int worstQualityPath = 0; + + // New priority is higher than the priority of the originating path (if known) + long newPriority = 1; for(unsigned int i=0;iquality(now) / _paths[i].priority; - if (q >= worstQuality) { - worstQuality = q; - worstQualityPath = i; + } else break; + } + newPriority += 2; + + // Erase any paths with lower priority than this one or that are duplicate + // IPs and add this path. + unsigned int j = 0; + for(unsigned int i=0;i= newPriority)&&(!_paths[i].p->address().ipsEqual(remoteAddress))) { + if (i != j) + _paths[j] = _paths[i]; + ++j; } - } else { - worstQualityPath = i; - break; } } - _paths[worstQualityPath].lr = now; - _paths[worstQualityPath].p = np; - _paths[worstQualityPath].priority = 6; // 1 + 5 + if (j < ZT_MAX_PEER_NETWORK_PATHS) { + _paths[j].lr = now; + _paths[j].p = np; + _paths[j].priority = newPriority; + ++j; + while (j < ZT_MAX_PEER_NETWORK_PATHS) { + _paths[j].lr = 0; + _paths[j].p.zero(); + _paths[j].priority = 1; + ++j; + } + } } } diff --git a/node/Peer.hpp b/node/Peer.hpp index 997c44f5..53b916ab 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -219,11 +219,11 @@ public: * Process a cluster redirect sent by this peer * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localSocket Local socket as supplied by external code + * @param originatingPath Path from which redirect originated * @param remoteAddress Remote address * @param now Current time */ - void clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); + void clusterRedirect(void *tPtr,const SharedPtr &originatingPath,const InetAddress &remoteAddress,const int64_t now); /** * Reset paths within a given IP scope and address family @@ -498,7 +498,7 @@ private: _PeerPath() : lr(0),p(),priority(1) {} int64_t lr; // time of last valid ZeroTier packet SharedPtr p; - int priority; // >= 1, higher is better + long priority; // >= 1, higher is better }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; -- cgit v1.2.3 From 9c7ee5a21e2875baf3b1643101f660f41c903124 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 Jan 2018 13:06:24 -0800 Subject: Tear out old "link quality" stuff since it is not currently used and will be done differently. --- include/ZeroTierOne.h | 5 ----- node/IncomingPacket.cpp | 26 ++++++++++----------- node/Node.cpp | 7 +++--- node/Packet.cpp | 6 ++--- node/Packet.hpp | 9 +------- node/Path.hpp | 60 ------------------------------------------------- node/Peer.cpp | 29 +++++++++++------------- node/Peer.hpp | 8 +++---- node/Switch.cpp | 4 ++-- one.cpp | 3 +-- service/OneService.cpp | 1 - 11 files changed, 38 insertions(+), 120 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 04c4b83b..93a91933 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1183,11 +1183,6 @@ typedef struct */ uint64_t trustedPathId; - /** - * Path link quality from 0 to 255 (always 255 if peer does not support) - */ - int linkQuality; - /** * Is path expired? */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index d44e3b54..38fd3aa0 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -241,7 +241,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true,_path->nextOutgoingCounter()); + outp.armor(key,true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); @@ -391,7 +391,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool } outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -538,7 +538,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar } if (count > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -560,7 +560,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { const uint64_t junk = RR->node->prng(); RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); + rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false); } } } @@ -669,7 +669,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const outp.append((uint8_t)Packet::VERB_EXT_FRAME); outp.append((uint64_t)packetId()); outp.append((uint64_t)nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -692,7 +692,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share outp.append((uint64_t)pid); if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0); @@ -885,7 +885,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -905,7 +905,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c outp.append((uint64_t)packetId()); outp.append((uint64_t)network->id()); outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -948,7 +948,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr outp.append((uint32_t)mg.adi()); const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); if (gatheredLocally > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1043,7 +1043,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, outp.append((uint32_t)to.adi()); 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,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1094,7 +1094,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false); } } } break; @@ -1108,7 +1108,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false); } } } break; @@ -1170,7 +1170,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void outp.append(packetId()); outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),now); } } diff --git a/node/Node.cpp b/node/Node.cpp index 8d8f5ca0..d4b69689 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -202,7 +202,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(_tPtr,-1,addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now); contacted = true; break; } @@ -213,7 +213,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(_tPtr,-1,addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now); contacted = true; break; } @@ -225,7 +225,7 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now,up->nextOutgoingCounter()); + p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); @@ -445,7 +445,6 @@ ZT_PeerList *Node::peers() const p->paths[p->pathCount].lastSend = (*path)->lastOut(); p->paths[p->pathCount].lastReceive = (*path)->lastIn(); p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); - p->paths[p->pathCount].linkQuality = (int)(*path)->linkQuality(); p->paths[p->pathCount].expired = 0; p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; ++p->pathCount; diff --git a/node/Packet.cpp b/node/Packet.cpp index af42cda5..cb9e1e0f 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1061,18 +1061,16 @@ static inline int LZ4_decompress_safe(const char* source, char* dest, int compre const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) +void Packet::armor(const void *key,bool encryptPayload) { uint8_t mangledKey[32]; uint8_t *const data = reinterpret_cast(unsafeData()); - // Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use - data[7] = (data[7] & 0xf8) | (uint8_t)(counter & 0x07); - // Set flag now, since it affects key mangle function setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); _salsa20MangleKey((const unsigned char *)key,mangledKey); + if (ZT_HAS_FAST_CRYPTO()) { const unsigned int encryptLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0; uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; diff --git a/node/Packet.hpp b/node/Packet.hpp index cc055347..8cfb5492 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -68,7 +68,6 @@ * + Tags and Capabilities * + Inline push of CertificateOfMembership deprecated * 9 - 1.2.0 ... CURRENT - * + In-band encoding of packet counter for link quality measurement */ #define ZT_PROTO_VERSION 9 @@ -1202,11 +1201,6 @@ public: */ inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } - /** - * @return Value of link quality counter extracted from this packet's ID, range 0 to 7 (3 bits) - */ - inline unsigned int linkQualityCounter() const { return (unsigned int)(reinterpret_cast(data())[7] & 0x07); } - /** * Set packet verb * @@ -1237,9 +1231,8 @@ public: * * @param key 32-byte key * @param encryptPayload If true, encrypt packet payload, else just MAC - * @param counter Packet send counter for destination peer -- only least significant 3 bits are used */ - void armor(const void *key,bool encryptPayload,unsigned int counter); + void armor(const void *key,bool encryptPayload); /** * Verify and (if encrypted) decrypt packet diff --git a/node/Path.hpp b/node/Path.hpp index 008b05c5..6b4b9915 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -94,36 +94,22 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), - _incomingLinkQualityFastLog(0xffffffffffffffffULL), _localSocket(-1), - _incomingLinkQualitySlowLogPtr(0), - _incomingLinkQualitySlowLogCounter(-64), // discard first fast log - _incomingLinkQualityPreviousPacketCounter(0), - _outgoingPacketCounter(0), _latency(0xffff), _addr(), _ipScope(InetAddress::IP_SCOPE_NONE) { - for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) - _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } Path(const int64_t localSocket,const InetAddress &addr) : _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), - _incomingLinkQualityFastLog(0xffffffffffffffffULL), _localSocket(localSocket), - _incomingLinkQualitySlowLogPtr(0), - _incomingLinkQualitySlowLogCounter(-64), // discard first fast log - _incomingLinkQualityPreviousPacketCounter(0), - _outgoingPacketCounter(0), _latency(0xffff), _addr(addr), _ipScope(addr.ipScope()) { - for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) - _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } /** @@ -133,39 +119,6 @@ public: */ inline void received(const uint64_t t) { _lastIn = t; } - /** - * Update link quality using a counter from an incoming packet (or packet head in fragmented case) - * - * @param counter Packet link quality counter (range 0 to 7, must not have other bits set) - */ - inline void updateLinkQuality(const unsigned int counter) - { - const unsigned int prev = _incomingLinkQualityPreviousPacketCounter; - _incomingLinkQualityPreviousPacketCounter = counter; - const uint64_t fl = (_incomingLinkQualityFastLog = ((_incomingLinkQualityFastLog << 1) | (uint64_t)(prev == ((counter - 1) & 0x7)))); - if (++_incomingLinkQualitySlowLogCounter >= 64) { - _incomingLinkQualitySlowLogCounter = 0; - _incomingLinkQualitySlowLog[_incomingLinkQualitySlowLogPtr++ % sizeof(_incomingLinkQualitySlowLog)] = (uint8_t)Utils::countBits(fl); - } - } - - /** - * @return Link quality from 0 (min) to 255 (max) - */ - inline unsigned int linkQuality() const - { - unsigned long slsize = _incomingLinkQualitySlowLogPtr; - if (slsize > (unsigned long)sizeof(_incomingLinkQualitySlowLog)) - slsize = (unsigned long)sizeof(_incomingLinkQualitySlowLog); - else if (!slsize) - return 255; // ZT_PATH_LINK_QUALITY_MAX - unsigned long lq = 0; - for(unsigned long i=0;i= 255) ? 255 : lq); - } - /** * Set time last trusted packet was received (done in Peer::received()) */ @@ -313,27 +266,14 @@ public: */ inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } - /** - * Return and increment outgoing packet counter (used with Packet::armor()) - * - * @return Next value that should be used for outgoing packet counter (only least significant 3 bits are used) - */ - inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } - private: volatile int64_t _lastOut; volatile int64_t _lastIn; volatile int64_t _lastTrustEstablishedPacketReceived; - volatile uint64_t _incomingLinkQualityFastLog; int64_t _localSocket; - volatile unsigned long _incomingLinkQualitySlowLogPtr; - volatile signed int _incomingLinkQualitySlowLogCounter; - volatile unsigned int _incomingLinkQualityPreviousPacketCounter; - volatile unsigned int _outgoingPacketCounter; volatile unsigned int _latency; InetAddress _addr; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often - volatile uint8_t _incomingLinkQualitySlowLog[32]; AtomicCounter __refCount; }; diff --git a/node/Peer.cpp b/node/Peer.cpp index fceef94f..6e46089f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -95,9 +95,6 @@ void Peer::received( path->trustedPacketReceived(now); } - if (_vProto >= 9) - path->updateLinkQuality((unsigned int)(packetId & 7)); - if (hops == 0) { // If this is a direct packet (no hops), update existing paths or learn new ones @@ -161,7 +158,7 @@ void Peer::received( } if (attemptToContact) { - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true); path->sent(now); RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); } @@ -226,7 +223,7 @@ void Peer::received( if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true,path->nextOutgoingCounter()); + outp.armor(_key,true); path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -357,7 +354,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o outp.append((uint8_t)4); outp.append(other->_paths[theirs].p->address().rawIpData(),4); } - outp.armor(_key,true,_paths[mine].p->nextOutgoingCounter()); + outp.armor(_key,true); _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); } else { Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -371,7 +368,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o outp.append((uint8_t)4); outp.append(_paths[mine].p->address().rawIpData(),4); } - outp.armor(other->_key,true,other->_paths[theirs].p->nextOutgoingCounter()); + outp.armor(other->_key,true); other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); } ++alt; @@ -379,7 +376,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } } -void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -415,22 +412,22 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA RR->node->expectReplyTo(outp.packetId()); if (atAddress) { - outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC + outp.armor(_key,false); // false == don't encrypt full payload, but add MAC RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,true,counter); + outp.armor(_key,true); RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { - sendHELLO(tPtr,localSocket,atAddress,now,counter); + sendHELLO(tPtr,localSocket,atAddress,now); } } @@ -440,7 +437,7 @@ void Peer::tryMemorizedPath(void *tPtr,int64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) - attemptToContactAt(tPtr,-1,mp,now,true,0); + attemptToContactAt(tPtr,-1,mp,now,true); } } @@ -470,7 +467,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) // Clean expired and reduced priority paths if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) { if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello); _paths[i].p->sent(now); sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; } @@ -495,7 +492,7 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr &originatingPath,con SharedPtr np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress)); RR->t->peerRedirected(tPtr,0,*this,np); - attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true,np->nextOutgoingCounter()); + attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true); { Mutex::Lock _l(_paths_m); @@ -545,7 +542,7 @@ void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddres for(unsigned int i=0;iaddress().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false,_paths[i].p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false); _paths[i].p->sent(now); _paths[i].lr = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index 53b916ab..99728736 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -175,9 +175,8 @@ public: * @param localSocket Local source socket * @param atAddress Destination address * @param now Current time - * @param counter Outgoing packet counter */ - void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -189,9 +188,8 @@ public: * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO - * @param counter Outgoing packet counter */ - void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello); /** * Try a memorized or statically defined path if any are known @@ -480,7 +478,7 @@ public: try { ptr += inaddr.deserialize(b,ptr); if (inaddr) - p->attemptToContactAt(tPtr,-1,inaddr,now,true,0); + p->attemptToContactAt(tPtr,-1,inaddr,now,true); } catch ( ... ) { break; } diff --git a/node/Switch.cpp b/node/Switch.cpp index 1958c43e..b2cab1d0 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -78,7 +78,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses _lastBeaconResponse = now; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),true,path->nextOutgoingCounter()); + outp.armor(peer->key(),true); path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -670,7 +670,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) if (trustedPathId) { packet.setTrusted(trustedPathId); } else { - packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); + packet.armor(peer->key(),encrypt); } if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { diff --git a/one.cpp b/one.cpp index 48b5d9a2..a1238bb8 100644 --- a/one.cpp +++ b/one.cpp @@ -365,8 +365,7 @@ static int cli(int argc,char **argv) char tmp[256]; std::string addr = path["address"]; const int64_t now = OSUtils::now(); - const double lq = (path.count("linkQuality")) ? (double)path["linkQuality"] : -1.0; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld;%1.2f",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"],lq); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"]); bestPath = tmp; break; } diff --git a/service/OneService.cpp b/service/OneService.cpp index 3ca75362..686806b3 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -271,7 +271,6 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) j["lastSend"] = (lastSend < 0) ? 0 : lastSend; j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive; j["trustedPathId"] = peer->paths[i].trustedPathId; - j["linkQuality"] = (double)peer->paths[i].linkQuality / (double)ZT_PATH_LINK_QUALITY_MAX; j["active"] = (bool)(peer->paths[i].expired == 0); j["expired"] = (bool)(peer->paths[i].expired != 0); j["preferred"] = (bool)(peer->paths[i].preferred != 0); -- cgit v1.2.3 From 65c07afe055e6d33a07ea6adf87aedcf564806a2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 Jan 2018 14:33:28 -0800 Subject: Copyright updates for 2018. --- COPYING | 2 +- include/ZeroTierOne.h | 2 +- node/Address.hpp | 2 +- node/Array.hpp | 2 +- node/AtomicCounter.hpp | 2 +- node/Buffer.hpp | 2 +- node/C25519.hpp | 2 +- node/Capability.cpp | 2 +- node/Capability.hpp | 2 +- node/CertificateOfMembership.cpp | 2 +- node/CertificateOfMembership.hpp | 2 +- node/CertificateOfOwnership.cpp | 2 +- node/CertificateOfOwnership.hpp | 2 +- node/Constants.hpp | 2 +- node/Credential.hpp | 2 +- node/Dictionary.hpp | 2 +- node/Hashtable.hpp | 2 +- node/Identity.cpp | 2 +- node/Identity.hpp | 2 +- node/IncomingPacket.cpp | 2 +- node/IncomingPacket.hpp | 2 +- node/InetAddress.cpp | 2 +- node/InetAddress.hpp | 2 +- node/MAC.hpp | 2 +- node/Membership.cpp | 2 +- node/Membership.hpp | 2 +- node/MulticastGroup.hpp | 2 +- node/Multicaster.cpp | 2 +- node/Multicaster.hpp | 2 +- node/Mutex.hpp | 2 +- node/Network.cpp | 2 +- node/Network.hpp | 2 +- node/NetworkConfig.cpp | 2 +- node/NetworkConfig.hpp | 2 +- node/NetworkController.hpp | 2 +- node/Node.cpp | 2 +- node/Node.hpp | 2 +- node/NonCopyable.hpp | 2 +- node/OutboundMulticast.cpp | 2 +- node/OutboundMulticast.hpp | 2 +- node/Packet.cpp | 2 +- node/Packet.hpp | 2 +- node/Path.cpp | 2 +- node/Path.hpp | 2 +- node/Peer.cpp | 2 +- node/Peer.hpp | 2 +- node/Poly1305.hpp | 2 +- node/Revocation.cpp | 2 +- node/Revocation.hpp | 2 +- node/RuntimeEnvironment.hpp | 2 +- node/SHA512.hpp | 2 +- node/SelfAwareness.cpp | 2 +- node/SelfAwareness.hpp | 2 +- node/SharedPtr.hpp | 2 +- node/Switch.cpp | 2 +- node/Switch.hpp | 2 +- node/Tag.cpp | 2 +- node/Tag.hpp | 2 +- node/Topology.cpp | 2 +- node/Topology.hpp | 2 +- node/Trace.cpp | 2 +- node/Trace.hpp | 2 +- node/Utils.cpp | 2 +- node/Utils.hpp | 2 +- node/World.hpp | 2 +- one.cpp | 4 ++-- osdep/Arp.cpp | 2 +- osdep/Arp.hpp | 2 +- osdep/BSDEthernetTap.cpp | 2 +- osdep/BSDEthernetTap.hpp | 2 +- osdep/Binder.hpp | 2 +- osdep/BlockingQueue.hpp | 2 +- osdep/Http.cpp | 2 +- osdep/Http.hpp | 2 +- osdep/LinuxEthernetTap.cpp | 2 +- osdep/LinuxEthernetTap.hpp | 2 +- osdep/ManagedRoute.cpp | 2 +- osdep/ManagedRoute.hpp | 2 +- osdep/NeighborDiscovery.cpp | 2 +- osdep/NeighborDiscovery.hpp | 2 +- osdep/OSUtils.cpp | 2 +- osdep/OSUtils.hpp | 2 +- osdep/OSXEthernetTap.cpp | 2 +- osdep/OSXEthernetTap.hpp | 2 +- osdep/Phy.hpp | 2 +- osdep/PortMapper.cpp | 2 +- osdep/PortMapper.hpp | 2 +- osdep/TestEthernetTap.hpp | 2 +- osdep/Thread.hpp | 2 +- osdep/WindowsEthernetTap.cpp | 2 +- osdep/WindowsEthernetTap.hpp | 2 +- selftest.cpp | 2 +- service/OneService.cpp | 2 +- service/OneService.hpp | 2 +- service/SoftwareUpdater.cpp | 2 +- service/SoftwareUpdater.hpp | 2 +- version.h | 2 +- 97 files changed, 98 insertions(+), 98 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/COPYING b/COPYING index 23d42dfa..8008d3e0 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ ZeroTier One, an endpoint server for the ZeroTier virtual network layer. -Copyright © 2011–2016 ZeroTier, Inc. +Copyright © 2011–2018 ZeroTier, Inc. ZeroTier One is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 93a91933..f07650b5 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Address.hpp b/node/Address.hpp index 12c52a3f..41977af2 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Array.hpp b/node/Array.hpp index ef2611e4..de827c08 100644 --- a/node/Array.hpp +++ b/node/Array.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index 34b58e91..d58c4b56 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Buffer.hpp b/node/Buffer.hpp index f84b3774..bbf4ee37 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/C25519.hpp b/node/C25519.hpp index 950c7fed..3f22b445 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Capability.cpp b/node/Capability.cpp index 47dca1fc..fb52be8a 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Capability.hpp b/node/Capability.hpp index bec1f47f..91a46566 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index dedcccff..a849a44c 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 2eff1083..19fe5367 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index eeb0d99c..8ee67865 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index e397fd63..278ae863 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Constants.hpp b/node/Constants.hpp index 6360a693..23bebafd 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Credential.hpp b/node/Credential.hpp index e8767e22..34e94162 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index a1b0f9cb..59afb7c6 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 5aa045b9..58dc8fca 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Identity.cpp b/node/Identity.cpp index 72bea75d..9cc507f7 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Identity.hpp b/node/Identity.hpp index ab2886ad..cd24757e 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 38fd3aa0..341f3281 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index c8f52721..88f4f066 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index ee32ce72..ecfc81ab 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index fd430099..e6dfabf9 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/MAC.hpp b/node/MAC.hpp index 18fe2032..c08323a4 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Membership.cpp b/node/Membership.cpp index de5fb99d..affe7a71 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Membership.hpp b/node/Membership.hpp index 95ec2180..ad0bb73e 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index 6039d3c4..0f4a621e 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index fa6f7bd1..d5bdfdf6 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 08c96485..59959328 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 53ae05c4..cbd80524 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Network.cpp b/node/Network.cpp index e8e91174..e8a52e33 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Network.hpp b/node/Network.hpp index 1b4da7d2..db285108 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 2e07ac82..f9b16cc5 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 19823e24..4121a241 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index 63d44a46..393bcc91 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Node.cpp b/node/Node.cpp index d4b69689..af03669c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Node.hpp b/node/Node.hpp index f8236db8..82f35c56 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NonCopyable.hpp b/node/NonCopyable.hpp index 5e8c753d..31107a50 100644 --- a/node/NonCopyable.hpp +++ b/node/NonCopyable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 9aa44736..d7a7b4d8 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 2f6d8338..836b840b 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Packet.cpp b/node/Packet.cpp index cb9e1e0f..de059054 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Packet.hpp b/node/Packet.hpp index 8cfb5492..b96ab375 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Path.cpp b/node/Path.cpp index ca366e39..b1b3dd06 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Path.hpp b/node/Path.hpp index 6b4b9915..62d750b7 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Peer.cpp b/node/Peer.cpp index 6e46089f..71afd852 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Peer.hpp b/node/Peer.hpp index 99728736..99216bab 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 0bdfa74f..adcc2410 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 89a2db95..78098f8c 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 4a18914f..eaf01915 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 0bb78599..9ecdc400 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 584f8e11..eedc284a 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 83cd89c9..c4f107fb 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 7ddba465..ce6e8c76 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index af66545f..aa03cf0b 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Switch.cpp b/node/Switch.cpp index b2cab1d0..c3626f9f 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Switch.hpp b/node/Switch.hpp index b42389fc..4fc5453d 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Tag.cpp b/node/Tag.cpp index bde41a70..62d9cb2e 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Tag.hpp b/node/Tag.hpp index 394c7be6..d2e932c2 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Topology.cpp b/node/Topology.cpp index d1b389df..fa9868e9 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Topology.hpp b/node/Topology.hpp index b09f95cf..0bcdfb0a 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Trace.cpp b/node/Trace.cpp index 4303946b..a60a0194 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Trace.hpp b/node/Trace.hpp index 08241d37..05d5b66a 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Utils.cpp b/node/Utils.cpp index 4ac18366..a69a575e 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Utils.hpp b/node/Utils.hpp index 54af3aec..5565fad6 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/World.hpp b/node/World.hpp index 26d94fcd..459470ca 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/one.cpp b/one.cpp index a1238bb8..8d4b8fc5 100644 --- a/one.cpp +++ b/one.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 @@ -93,7 +93,7 @@ using namespace ZeroTier; static OneService *volatile zt1Service = (OneService *)0; #define PROGRAM_NAME "ZeroTier One" -#define COPYRIGHT_NOTICE "Copyright (c) 2011-2017 ZeroTier, Inc." +#define COPYRIGHT_NOTICE "Copyright (c) 2011-2018 ZeroTier, Inc." #define LICENSE_GRANT \ "This is free software: you may copy, modify, and/or distribute this" ZT_EOL_S \ "work under the terms of the GNU General Public License, version 3 or" ZT_EOL_S \ diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index c06f459b..cc4e920a 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp index e26fcdb3..27e92fdb 100644 --- a/osdep/Arp.hpp +++ b/osdep/Arp.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index c0fdad9c..053df21d 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index fd2685f3..3d91dbbb 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index e3c2dc02..399ce04a 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp index 5e1a24ef..351a095a 100644 --- a/osdep/BlockingQueue.hpp +++ b/osdep/BlockingQueue.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Http.cpp b/osdep/Http.cpp index d6d0238c..16785c96 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Http.hpp b/osdep/Http.hpp index 3f98d760..b717c5c9 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index 848f3638..6ef42744 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index e05dee8c..5142eec1 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 2289b23a..8ffbed2a 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 849bddf5..873d0cfb 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp index ac95748b..d9862f3d 100644 --- a/osdep/NeighborDiscovery.cpp +++ b/osdep/NeighborDiscovery.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp index 2e7a68ba..59186289 100644 --- a/osdep/NeighborDiscovery.hpp +++ b/osdep/NeighborDiscovery.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 3325c621..aa531243 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 274b48df..324b7923 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp index b43d34c0..dbff6200 100644 --- a/osdep/OSXEthernetTap.cpp +++ b/osdep/OSXEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp index d0a8a99d..fe402901 100644 --- a/osdep/OSXEthernetTap.hpp +++ b/osdep/OSXEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index f71bd56c..8e683f10 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index 9aeeb8d6..a7dd3046 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp index 61015a09..fa3cdc31 100644 --- a/osdep/PortMapper.hpp +++ b/osdep/PortMapper.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/TestEthernetTap.hpp b/osdep/TestEthernetTap.hpp index 047a19b1..2f73258a 100644 --- a/osdep/TestEthernetTap.hpp +++ b/osdep/TestEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index b3011f32..35ea5035 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 93da8ad6..22b81454 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 70789e75..856c3be7 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/selftest.cpp b/selftest.cpp index 86894564..9edb4928 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/OneService.cpp b/service/OneService.cpp index 71bb6983..e65ad0e2 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/OneService.hpp b/service/OneService.hpp index 23e572d0..3b670e4a 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 39833c90..6a25dbec 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index f16c99a0..ed329b1f 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/version.h b/version.h index b3b2fc81..d80bec80 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 -- cgit v1.2.3 From 4419734a7db21cd6a9ee8aba911f220cbecba085 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 25 Jan 2018 07:11:59 -0500 Subject: Implement continuous contacting of designated anchors and multicast replicators - GitHub issue #666 --- node/IncomingPacket.cpp | 2 +- node/NetworkConfig.hpp | 17 ++++++-- node/Node.cpp | 104 ++++++++++++++++++++++++-------------------- node/RuntimeEnvironment.hpp | 27 ++++-------- node/Switch.cpp | 4 +- node/Topology.cpp | 8 ++-- node/Topology.hpp | 4 +- 7 files changed, 87 insertions(+), 79 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 341f3281..8a6f4bc5 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -514,7 +514,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) + if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) return true; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 3a2664a2..ebe0d70e 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -47,6 +47,7 @@ #include "Capability.hpp" #include "Tag.hpp" #include "Dictionary.hpp" +#include "Hashtable.hpp" #include "Identity.hpp" #include "Utils.hpp" #include "Trace.hpp" @@ -317,6 +318,18 @@ public: return r; } + /** + * Add addresses that we should attempt to stay connected to to a set + */ + inline void getAlwaysContactAddresses(Hashtable< Address,std::vector > &a) const + { + for(unsigned int i=0;i > &upstreamsToContact,int64_t now) : - lastReceiveFromUpstream(0), + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &alwaysContact,int64_t now) : RR(renv), _tPtr(tPtr), - _upstreamsToContact(upstreamsToContact), + _alwaysContact(alwaysContact), _now(now), _bestCurrentUpstream(RR->topology->getUpstreamPeer()) { } - int64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay - inline void operator()(Topology &t,const SharedPtr &p) { - const std::vector *const upstreamStableEndpoints = _upstreamsToContact.get(p->address()); - if (upstreamStableEndpoints) { - // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow - // them to perform three way handshake introductions for both stacks. - + const std::vector *const alwaysContactEndpoints = _alwaysContact.get(p->address()); + if (alwaysContactEndpoints) { const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now); bool contacted = (sent != 0); if ((sent & 0x1) == 0) { // bit 0x1 == IPv4 sent - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { - const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; + for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)alwaysContactEndpoints->size();++k) { + const InetAddress &addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()]; if (addr.ss_family == AF_INET) { p->sendHELLO(_tPtr,-1,addr,_now); contacted = true; @@ -210,8 +204,8 @@ public: } if ((sent & 0x2) == 0) { // bit 0x2 == IPv6 sent - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { - const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; + for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)alwaysContactEndpoints->size();++k) { + const InetAddress &addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()]; if (addr.ss_family == AF_INET6) { p->sendHELLO(_tPtr,-1,addr,_now); contacted = true; @@ -220,19 +214,14 @@ public: } } - // If we have no memoized addresses for this upstream peer, attempt to contact - // it indirectly so we will be introduced. if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now); } - lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - - _upstreamsToContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain + _alwaysContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain } else if (p->isActive(_now)) { - // Regular non-upstream nodes get pinged if they appear active. p->doPingAndKeepalive(_tPtr,_now); } } @@ -240,7 +229,7 @@ public: private: const RuntimeEnvironment *RR; void *_tPtr; - Hashtable< Address,std::vector > &_upstreamsToContact; + Hashtable< Address,std::vector > &_alwaysContact; const int64_t _now; const SharedPtr _bestCurrentUpstream; }; @@ -256,41 +245,60 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 try { _lastPingCheck = now; - // Do pings and keepalives - Hashtable< Address,std::vector > upstreamsToContact; - RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); - RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); - - // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) - Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(tptr,now,*upstreamAddress); + // Get designated VL1 upstreams + Hashtable< Address,std::vector > alwaysContact; + RR->topology->getUpstreamsToContact(alwaysContact); - // Get networks that need config without leaving mutex locked + // Check last receive time on designated upstreams to see if we seem to be online + int64_t lastReceivedFromUpstream = 0; { - std::vector< std::pair< SharedPtr,bool > > nwl; - { - Mutex::Lock _l(_networks_m); - nwl.reserve(_networks.size()+1); - Hashtable< uint64_t,SharedPtr >::Iterator i(_networks); - uint64_t *k = (uint64_t *)0; - SharedPtr *v = (SharedPtr *)0; - while (i.next(k,v)) - nwl.push_back( std::pair< SharedPtr,bool >(*v,(((now - (*v)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!(*v)->hasConfig()))) ); + Hashtable< Address,std::vector >::Iterator i(alwaysContact); + Address *upstreamAddress = (Address *)0; + std::vector *upstreamStableEndpoints = (std::vector *)0; + while (i.next(upstreamAddress,upstreamStableEndpoints)) { + SharedPtr p(RR->topology->getPeerNoCache(*upstreamAddress)); + if (p) + lastReceivedFromUpstream = std::max(p->lastReceive(),lastReceivedFromUpstream); } - for(std::vector< std::pair< SharedPtr,bool > >::const_iterator n(nwl.begin());n!=nwl.end();++n) { - if (n->second) - n->first->requestConfiguration(tptr); - n->first->sendUpdatesToMembers(tptr); + } + + // Get peers we should stay connected to according to network configs + // Also get networks and whether they need config + std::vector< std::pair< SharedPtr,bool > > networkConfigNeeded; + { + Mutex::Lock l(_networks_m); + Hashtable< uint64_t,SharedPtr >::Iterator i(_networks); + uint64_t *nwid = (uint64_t *)0; + SharedPtr *network = (SharedPtr *)0; + while (i.next(nwid,network)) { + (*network)->config().getAlwaysContactAddresses(alwaysContact); + networkConfigNeeded.push_back( std::pair< SharedPtr,bool >(*network,(((now - (*network)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!(*network)->hasConfig()))) ); } } + // Ping active peers, upstreams, and others that we should always contact + _PingPeersThatNeedPing pfunc(RR,tptr,alwaysContact,now); + RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); + + // Run WHOIS to create Peer for alwaysContact addresses that could not be contacted + { + Hashtable< Address,std::vector >::Iterator i(alwaysContact); + Address *upstreamAddress = (Address *)0; + std::vector *upstreamStableEndpoints = (std::vector *)0; + while (i.next(upstreamAddress,upstreamStableEndpoints)) + RR->sw->requestWhois(tptr,now,*upstreamAddress); + } + + // Refresh network config or broadcast network updates to members as needed + for(std::vector< std::pair< SharedPtr,bool > >::const_iterator n(networkConfigNeeded.begin());n!=networkConfigNeeded.end();++n) { + if (n->second) + n->first->requestConfiguration(tptr); + n->first->sendUpdatesToMembers(tptr); + } + // Update online status, post status change as event const bool oldOnline = _online; - _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); + _online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amUpstream())); if (oldOnline != _online) postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); } catch ( ... ) { diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 9ecdc400..17170718 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -52,16 +52,14 @@ class RuntimeEnvironment public: RuntimeEnvironment(Node *n) : node(n) - ,identity() ,localNetworkController((NetworkController *)0) ,sw((Switch *)0) ,mc((Multicaster *)0) ,topology((Topology *)0) ,sa((SelfAwareness *)0) { - Utils::getSecureRandom(&instanceId,sizeof(instanceId)); - memset(publicIdentityStr,0,sizeof(publicIdentityStr)); - memset(secretIdentityStr,0,sizeof(secretIdentityStr)); + publicIdentityStr[0] = (char)0; + secretIdentityStr[0] = (char)0; } ~RuntimeEnvironment() @@ -69,35 +67,28 @@ public: Utils::burn(secretIdentityStr,sizeof(secretIdentityStr)); } - /** - * A random integer identifying this running instance in a cluster - */ - uint64_t instanceId; - // Node instance that owns this RuntimeEnvironment Node *const node; - // This node's identity - Identity identity; - char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - // This is set externally to an instance of this base class NetworkController *localNetworkController; - /* - * Order matters a bit here. These are constructed in this order + /* Order matters a bit here. These are constructed in this order * and then deleted in the opposite order on Node exit. The order ensures * that things that are needed are there before they're needed. * - * These are constant and never null after startup unless indicated. - */ + * These are constant and never null after startup unless indicated. */ Trace *t; Switch *sw; Multicaster *mc; Topology *topology; SelfAwareness *sa; + + // This node's identity and string representations thereof + Identity identity; + char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; }; } // namespace ZeroTier diff --git a/node/Switch.cpp b/node/Switch.cpp index c3626f9f..6ffeced4 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -91,7 +91,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre const Address destination(fragment.destination()); if (destination != RR->identity.address()) { - if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) ) + if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) ) return; if (fragment.hops() < ZT_RELAY_MAX_HOPS) { @@ -162,7 +162,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre return; if (destination != RR->identity.address()) { - if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) + if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) return; Packet packet(data,len); diff --git a/node/Topology.cpp b/node/Topology.cpp index 17a0eee4..2c440d92 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -66,7 +66,7 @@ static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x0 Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : RR(renv), _numConfiguredPhysicalPaths(0), - _amRoot(false) + _amUpstream(false) { uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; uint64_t idtmp[2]; @@ -398,11 +398,11 @@ void Topology::_memoizeUpstreams(void *tPtr) { // assumes _upstreams_m and _peers_m are locked _upstreamAddresses.clear(); - _amRoot = false; + _amUpstream = false; for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { if (i->identity == RR->identity) { - _amRoot = true; + _amUpstream = true; } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { _upstreamAddresses.push_back(i->identity.address()); SharedPtr &hp = _peers[i->identity.address()]; @@ -414,7 +414,7 @@ void Topology::_memoizeUpstreams(void *tPtr) for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { if (i->identity == RR->identity) { - _amRoot = true; + _amUpstream = true; } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { _upstreamAddresses.push_back(i->identity.address()); SharedPtr &hp = _peers[i->identity.address()]; diff --git a/node/Topology.hpp b/node/Topology.hpp index 0bcdfb0a..7f33e92b 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -336,7 +336,7 @@ public: /** * @return True if I am a root server in a planet or moon */ - inline bool amRoot() const { return _amRoot; } + inline bool amUpstream() const { return _amUpstream; } /** * Get info about a path @@ -460,7 +460,7 @@ private: std::vector _moons; std::vector< std::pair > _moonSeeds; std::vector
_upstreamAddresses; - bool _amRoot; + bool _amUpstream; Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; -- cgit v1.2.3 From f7019d9e80efa81e31ee7fa303be4f0e0a85c0fc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 26 Jan 2018 22:14:10 -0500 Subject: Tie up the rest of hub and spoke designated replicator multicast mode. --- RELEASE-NOTES.md | 1 + controller/EmbeddedNetworkController.cpp | 2 -- controller/README.md | 1 - node/IncomingPacket.cpp | 6 +++++- node/Multicaster.cpp | 10 +++++++--- node/Network.cpp | 2 +- node/NetworkConfig.cpp | 3 --- node/NetworkConfig.hpp | 32 ++++++++++++++++++-------------- node/Packet.hpp | 1 + 9 files changed, 33 insertions(+), 25 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 243ccde4..c7185792 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -6,6 +6,7 @@ ZeroTier Release Notes * Features and Core Improvements * Path selection has been overhauled to improve path stability, simplify code, and prepare for multi-path and trunking in the next major release. * This version introduces remote tracing for remote diagnostics. Network controllers can set a node (usually the controller itself) to receive remote tracing events from all members of the network or from select members. Events are only sent if they pertain to a given network for security reasons. These can be used to help remotely diagnose problems. In the future we'll be refining and enhancing this feature. + * Multicast replication can now be done by designated multicast replicators on a network (flagged as such at the controller) rather than by the sender. This offers a hub-and-spoke multicast replication topology that may be faster or more bandwidth efficient in certain cases. It's also attractive for use on networks with low powered devices that need to send multicast or where there are very large numbers of multicast recipients. * Documentation fixes in network controller. * Performance improvements in crypto and memory operations. * Multithreaded performance improvements throughout the code base, including the use of an inline lightweight spinlock for low-contention resources. diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 3945c8c7..f88f8cff 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -782,7 +782,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); - if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = OSUtils::jsonBool(b["allowPassiveBridging"],false); if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); @@ -1338,7 +1337,6 @@ void EmbeddedNetworkController::_request( nc->revision = OSUtils::jsonInt(network["revision"],0ULL); nc->issuedTo = identity.address(); if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - if (OSUtils::jsonBool(network["allowPassiveBridging"],false)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str()); nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); diff --git a/controller/README.md b/controller/README.md index 09eab834..23bd931d 100644 --- a/controller/README.md +++ b/controller/README.md @@ -88,7 +88,6 @@ Example: | creationTime | integer | Time network record was created (ms since epoch) | no | | private | boolean | Is access control enabled? | YES | | enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES | -| allowPassiveBridging | boolean | Allow any member to bridge (very experimental) | YES | | v4AssignMode | object | IPv4 management and assign options (see below) | YES | | v6AssignMode | object | IPv6 management and assign options (see below) | YES | | mtu | integer | Network MTU (default: 2800) | YES | diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 8a6f4bc5..ff4fc94b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1019,6 +1019,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, return true; } + const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); + + if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address()))) + RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen); + if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); @@ -1029,7 +1034,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } } - const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 9845c6cd..753e4ee0 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -174,8 +174,12 @@ void Multicaster::send( // If we're in hub-and-spoke designated multicast replication mode, see if we // have a multicast replicator active. If so, pick the best and send it // there. If we are a multicast replicator or if none are alive, fall back - // to sender replication. - { + // to sender replication. Note that bridges do not do this since this would + // break bridge route learning. This is sort of an edge case limitation of + // the current protocol and could be fixed, but fixing it would add more + // complexity than the fix is probably worth. Bridges are generally high + // bandwidth nodes. + if (!network->config().isActiveBridge(RR->identity.address())) { Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS]; const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators); if (multicastReplicatorCount) { @@ -197,7 +201,7 @@ void Multicaster::send( if (bestMulticastReplicator) { Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME); outp.append((uint64_t)network->id()); - outp.append((uint8_t)0x04); // includes source MAC + outp.append((uint8_t)0x0c); // includes source MAC | please replicate ((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp); mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); diff --git a/node/Network.cpp b/node/Network.cpp index 6a96b3fc..c12df6c1 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1379,7 +1379,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; ec->dhcp = 0; std::vector
ab(_config.activeBridges()); - ec->bridge = ((_config.allowPassiveBridging())||(std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end())) ? 1 : 0; + ec->bridge = (std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end()) ? 1 : 0; ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0; ec->portError = _portError; ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0; diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index f9b16cc5..db051699 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -58,7 +58,6 @@ bool NetworkConfig::toDictionary(Dictionary &d,b #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF if (includeLegacy) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD,this->allowPassiveBridging())) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) return false; @@ -236,8 +235,6 @@ bool NetworkConfig::fromDictionary(const Dictionaryflags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 30b8d0f3..44066c86 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -68,11 +68,6 @@ */ #define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA 185000ULL -/** - * Flag: allow passive bridging (experimental) - */ -#define ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING 0x0000000000000001ULL - /** * Flag: enable broadcast */ @@ -196,8 +191,6 @@ namespace ZeroTier { // Legacy fields -- these are obsoleted but are included when older clients query -// boolean (now a flag) -#define ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD "pb" // boolean (now a flag) #define ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD "eb" // IP/bits[,IP/bits,...] @@ -249,11 +242,6 @@ public: */ bool fromDictionary(const Dictionary &d); - /** - * @return True if passive bridging is allowed (experimental) - */ - inline bool allowPassiveBridging() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0); } - /** * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network */ @@ -302,6 +290,15 @@ public: return c; } + inline bool isActiveBridge(const Address &a) const + { + for(unsigned int i=0;i anchors() const { std::vector
r; @@ -332,6 +329,15 @@ public: return c; } + inline bool isMulticastReplicator(const Address &a) const + { + for(unsigned int i=0;i alwaysContactAddresses() const { std::vector
r; @@ -367,8 +373,6 @@ public: */ inline bool permitsBridging(const Address &fromPeer) const { - if ((flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0) - return true; for(unsigned int i=0;i