From 60de5ed3dd798dee0a61c2eb4170453ca42871cc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 7 Feb 2020 13:54:17 -0800 Subject: [PATCH] It almost compiles again --- include/ZeroTierCore.h | 18 ++- node/Buf.cpp | 2 +- node/Credential.cpp | 2 +- node/Endpoint.hpp | 10 +- node/Identity.cpp | 2 + node/Identity.hpp | 5 + node/InetAddress.hpp | 32 ++--- node/MulticastGroup.hpp | 6 +- node/Network.hpp | 2 +- node/Node.hpp | 4 +- node/Peer.cpp | 35 +++-- node/Protocol.cpp | 9 +- node/Protocol.hpp | 44 +++--- node/RuntimeEnvironment.hpp | 28 ++-- node/SHA512.cpp | 7 +- node/SelfAwareness.cpp | 3 +- node/SharedPtr.hpp | 1 + node/Trace.cpp | 158 ++++++++++++-------- node/Trace.hpp | 46 ++++-- node/Utils.cpp | 23 +-- node/VL1.cpp | 277 ++++++++++++++++++++++-------------- node/VL1.hpp | 3 +- node/VL2.cpp | 7 + node/VL2.hpp | 16 +++ 24 files changed, 456 insertions(+), 284 deletions(-) diff --git a/include/ZeroTierCore.h b/include/ZeroTierCore.h index 002e52391..e828fe596 100644 --- a/include/ZeroTierCore.h +++ b/include/ZeroTierCore.h @@ -328,6 +328,9 @@ enum ZT_CredentialType */ enum ZT_TraceEventType { + /* An unexpected error is an internal assertion / sanity check failure, out of memory, etc. */ + ZT_TRACE_UNEXPECTED_ERROR = 0, + /* VL1 events related to the peer-to-peer layer */ ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE = 1, ZT_TRACE_VL1_TRYING_NEW_PATH = 2, @@ -433,16 +436,25 @@ ZT_PACKED_STRUCT(struct ZT_TraceEventPathAddress */ ZT_PACKED_STRUCT(struct ZT_TraceEvent { - uint16_t evSize; /* sizeof(ZT_TraceEvent_XX structure) (inclusive size in bytes) */ - uint16_t evType; /* ZT_TraceEventType */ + uint16_t evSize; /* sizeof(ZT_TraceEvent_XX structure) (inclusive) */ + uint16_t evType; /* ZT_TraceEventType */ + uint32_t codeLocation; /* arbitrary identifier of location in source code */ }); /* Temporary macros to make it easier to declare all ZT_TraceEvent's sub-types */ #define _ZT_TRACE_EVENT_STRUCT_START(e) ZT_PACKED_STRUCT_START struct ZT_TraceEvent_##e { \ uint16_t evSize; \ - uint16_t evType; + uint16_t evType; \ + uint32_t codeLocation; #define _ZT_TRACE_EVENT_STRUCT_END() } ZT_PACKED_STRUCT_END; +/** + * An unexpected or internal error occurred + */ +_ZT_TRACE_EVENT_STRUCT_START(UNEXPECTED_ERROR) + char message[256]; /* arbitrary human-readable message */ +_ZT_TRACE_EVENT_STRUCT_END() + /** * Node is resetting all paths in a given address scope * diff --git a/node/Buf.cpp b/node/Buf.cpp index e36f1d5de..7c36e46eb 100644 --- a/node/Buf.cpp +++ b/node/Buf.cpp @@ -66,7 +66,7 @@ void *_Buf_get() #else s_pool.store(bb); #endif - b = (Buf *)malloc(sizeof(Buf<>)); + b = (Buf *)malloc(sizeof(Buf)); if (!b) throw std::bad_alloc(); } else { diff --git a/node/Credential.cpp b/node/Credential.cpp index 256b0a1cf..3dc37cadb 100644 --- a/node/Credential.cpp +++ b/node/Credential.cpp @@ -19,8 +19,8 @@ #include "CertificateOfMembership.hpp" #include "CertificateOfOwnership.hpp" #include "Revocation.hpp" -#include "Switch.hpp" #include "Network.hpp" +#include "Topology.hpp" // These are compile-time asserts to make sure temporary marshal buffers here and // also in NtworkConfig.cpp are always large enough to marshal all credential types. diff --git a/node/Endpoint.hpp b/node/Endpoint.hpp index eb537ab2b..501d75de4 100644 --- a/node/Endpoint.hpp +++ b/node/Endpoint.hpp @@ -14,17 +14,17 @@ #ifndef ZT_ENDPOINT_HPP #define ZT_ENDPOINT_HPP -#include -#include -#include -#include - #include "Constants.hpp" #include "InetAddress.hpp" #include "Address.hpp" #include "Utils.hpp" #include "TriviallyCopyable.hpp" +#include +#include +#include +#include + // max name size + type byte + port (for DNS name/port) + 3x 16-bit coordinate for location #define ZT_ENDPOINT_MARSHAL_SIZE_MAX (ZT_ENDPOINT_MAX_NAME_SIZE+1+2+2+2+2) diff --git a/node/Identity.cpp b/node/Identity.cpp index c7b7cb1f0..63e738702 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -83,6 +83,8 @@ struct _Identity_generate_cond } // anonymous namespace +const Identity Identity::NIL; + void Identity::generate(const Type t) { uint8_t digest[64]; diff --git a/node/Identity.hpp b/node/Identity.hpp index 0edccc40f..aba19399e 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -56,6 +56,11 @@ public: P384 = ZT_CRYPTO_ALG_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+) }; + /** + * A nil/empty identity instance + */ + static const Identity NIL; + ZT_ALWAYS_INLINE Identity() { memoryZero(this); } ZT_ALWAYS_INLINE ~Identity() { Utils::burn(reinterpret_cast(&this->_priv),sizeof(this->_priv)); } diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index d048d6bbf..043684fd5 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -87,57 +87,57 @@ public: ZT_ALWAYS_INLINE InetAddress() { memoryZero(this); } ZT_ALWAYS_INLINE InetAddress(const InetAddress &a) { memoryCopy(this,&a); } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; } - explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 *sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr_storage &ss) { *this = ss; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr_storage *ss) { *this = ss; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr &sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr *sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr_in &sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr_in *sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr_in6 &sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const sockaddr_in6 *sa) { *this = sa; } ZT_ALWAYS_INLINE InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); } ZT_ALWAYS_INLINE InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); } explicit ZT_ALWAYS_INLINE InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); } ZT_ALWAYS_INLINE void clear() { memoryZero(this); } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage &ss) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr_storage &ss) { memoryCopyUnsafe(this,&ss); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage *ss) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr_storage *ss) { if (ss) memoryCopyUnsafe(this,ss); else memoryZero(this); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in &sa) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr_in &sa) { copySockaddrToThis(&sa); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in *sa) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr_in *sa) { if (sa) copySockaddrToThis(sa); else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 &sa) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr_in6 &sa) { copySockaddrToThis(&sa); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 *sa) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr_in6 *sa) { if (sa) copySockaddrToThis(sa); else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr &sa) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr &sa) { if (sa.sa_family == AF_INET) copySockaddrToThis(reinterpret_cast(&sa)); @@ -146,7 +146,7 @@ public: else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } - ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr *sa) + ZT_ALWAYS_INLINE InetAddress &operator=(const sockaddr *sa) { if (sa) { if (sa->sa_family == AF_INET) diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index 2456e180c..0f405a442 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -14,14 +14,14 @@ #ifndef ZT_MULTICASTGROUP_HPP #define ZT_MULTICASTGROUP_HPP -#include - #include "Constants.hpp" #include "MAC.hpp" #include "InetAddress.hpp" #include "Utils.hpp" #include "TriviallyCopyable.hpp" +#include + namespace ZeroTier { /** @@ -64,7 +64,7 @@ public: // multicast address directly from the IP address, and it gives us // 24 bits of uniqueness. Collisions aren't likely to be common enough // to care about. - const uint8_t *a = (const uint8_t *)ip.rawIpData(); + const uint8_t *const a = reinterpret_cast(ip.rawIpData()); return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0); } return MulticastGroup(); diff --git a/node/Network.hpp b/node/Network.hpp index 47e88fa6b..7bf48b99d 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -196,7 +196,7 @@ public: * @param size Size of data in chunk buffer (total, not relative to ptr) * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr &source,const Buf<> &chunk,int ptr,int size); + uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr &source,const Buf &chunk,int ptr,int size); /** * Set network configuration diff --git a/node/Node.hpp b/node/Node.hpp index e6d32f60a..71ecc13e0 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -65,7 +65,7 @@ public: void operator delete(void* p) { _mm_free(p); } #endif - // Public API Functions ---------------------------------------------------- + // Public API Functions --------------------------------------------------------------------------------------------- ZT_ResultCode processWirePacket( void *tptr, @@ -104,7 +104,7 @@ public: int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); void setController(void *networkControllerInstance); - // Internal functions ------------------------------------------------------ + // Internal functions ----------------------------------------------------------------------------------------------- /** * @return Most recent time value supplied to core via API diff --git a/node/Peer.cpp b/node/Peer.cpp index 2058dacb0..c52cafa73 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -12,14 +12,15 @@ /****/ #include "Constants.hpp" +#include "RuntimeEnvironment.hpp" +#include "Trace.hpp" #include "Peer.hpp" +#include "Topology.hpp" #include "Node.hpp" -#include "Switch.hpp" #include "Network.hpp" #include "SelfAwareness.hpp" -#include "Packet.hpp" -#include "Trace.hpp" #include "InetAddress.hpp" +#include "Protocol.hpp" #include @@ -43,7 +44,11 @@ Peer::Peer(const RuntimeEnvironment *renv) : _lastTriedStaticPath(0), _lastPrioritizedPaths(0), _latency(0xffff), - _alivePathCount(0) + _alivePathCount(0), + _vProto(0), + _vMajor(0), + _vMinor(0), + _vRevision(0) { } @@ -52,10 +57,6 @@ bool Peer::init(const Identity &myIdentity,const Identity &peerIdentity) if (_id == peerIdentity) return true; _id = peerIdentity; - _vProto = 0; - _vMajor = 0; - _vMinor = 0; - _vRevision = 0; return myIdentity.agree(peerIdentity,_key); } @@ -65,9 +66,9 @@ void Peer::received( const unsigned int hops, const uint64_t packetId, const unsigned int payloadLength, - const Packet::Verb verb, + const Protocol::Verb verb, const uint64_t inRePacketId, - const Packet::Verb inReVerb, + const Protocol::Verb inReVerb, const uint64_t networkId) { const int64_t now = RR->node->now(); @@ -83,7 +84,7 @@ void Peer::received( } _lock.runlock(); - if (verb == Packet::VERB_OK) { + if (verb == Protocol::VERB_OK) { RWMutex::Lock l(_lock); int64_t lastReceiveTimeMax = 0; @@ -115,10 +116,10 @@ void Peer::received( _paths[lastReceiveTimeMaxAt] = path; _bootstrap = path->address(); _prioritizePaths(now); - RR->t->learnedNewPath(tPtr,packetId,_id,path->address(),old); + RR->t->learnedNewPath(tPtr,0x582fabdd,packetId,_id,path->address(),old); } else { if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,path->localSocket(),path->address())) { - RR->t->tryingNewPath(tPtr,_id,path->address(),path->address(),packetId,(uint8_t)verb,_id.address(),_id.hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH); + RR->t->tryingNewPath(tPtr,0xb7747ddd,_id,path->address(),path->address(),packetId,(uint8_t)verb,_id.address(),_id.hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH); sendHELLO(tPtr,path->localSocket(),path->address(),now); path->sent(now); } @@ -131,11 +132,11 @@ path_check_done: InetAddress addr; if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6)) { - RR->t->tryingNewPath(tPtr,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,0,nullptr,ZT_TRACE_TRYING_NEW_PATH_REASON_BOOTSTRAP_ADDRESS); + RR->t->tryingNewPath(tPtr,0x0a009444,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,0,nullptr,ZT_TRACE_TRYING_NEW_PATH_REASON_BOOTSTRAP_ADDRESS); sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now); } if (RR->node->externalPathLookup(tPtr,_id,-1,addr)) { if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,-1,addr)) { - RR->t->tryingNewPath(tPtr,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,0,nullptr,ZT_TRACE_TRYING_NEW_PATH_REASON_EXPLICITLY_SUGGESTED_ADDRESS); + RR->t->tryingNewPath(tPtr,0x84a10000,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,0,nullptr,ZT_TRACE_TRYING_NEW_PATH_REASON_EXPLICITLY_SUGGESTED_ADDRESS); sendHELLO(tPtr,-1,addr,now); } } @@ -155,6 +156,7 @@ path_check_done: } if (!addrs.empty()) { +#if 0 ScopedPtr outp(new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS)); outp->addSize(2); // leave room for count unsigned int count = 0; @@ -197,6 +199,7 @@ path_check_done: outp->armor(_key,true); path->send(RR,tPtr,outp->data(),outp->size(),now); } +#endif } } } @@ -222,6 +225,7 @@ bool Peer::shouldTryPath(void *tPtr,int64_t now,const SharedPtr &suggested void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now) { +#if 0 Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); outp.append((unsigned char)ZT_PROTO_VERSION); @@ -240,6 +244,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA } else { RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } +#endif } void Peer::ping(void *tPtr,int64_t now,const bool pingAllAddressTypes) diff --git a/node/Protocol.cpp b/node/Protocol.cpp index e4606267c..7bf8d1bea 100644 --- a/node/Protocol.cpp +++ b/node/Protocol.cpp @@ -44,8 +44,12 @@ unsigned long long _packetIdCtr = _initPacketID(); static std::atomic _packetIdCtr(_initPacketID()); #endif -uintptr_t _checkStructureSizing() +uintptr_t _checkSizes() { + // These are compiled time checked assertions that make sure our platform/compiler is sane + // and that packed structures are working properly. + if (ZT_PROTO_MAX_PACKET_LENGTH > ZT_BUF_MEM_SIZE) + throw std::runtime_error("ZT_PROTO_MAX_PACKET_LENGTH > ZT_BUF_MEM_SIZE"); if (sizeof(Header) != ZT_PROTO_MIN_PACKET_LENGTH) throw std::runtime_error("sizeof(Header) != ZT_PROTO_MIN_PACKET_LENGTH"); if (sizeof(FragmentHeader) != ZT_PROTO_MIN_FRAGMENT_LENGTH) @@ -55,7 +59,8 @@ uintptr_t _checkStructureSizing() } // anonymous namespace -volatile uintptr_t _compileTimeStructCheckHappened = _checkStructureSizing(); +// Make compiler compile and "run" _checkSizes() +volatile uintptr_t _checkSizesIMeanIt = _checkSizes(); uint64_t getPacketId() { diff --git a/node/Protocol.hpp b/node/Protocol.hpp index 4405ea4e3..d65189583 100644 --- a/node/Protocol.hpp +++ b/node/Protocol.hpp @@ -50,6 +50,7 @@ * 10 - 1.4.0 ... 1.4.6 * 11 - 2.0.0 ... CURRENT * + Peer-to-peer multicast replication + * + HELLO and OK(HELLO) include an extra HMAC to further harden auth * + Old planet/moon stuff is DEAD! * + AES encryption support * + NIST P-384 (type 1) identities @@ -152,7 +153,10 @@ #define ZT_PROTO_VERB_MASK 0x1fU /** - * Key derivation function label for the key used with HMAC-384 in HELLO + * Key derivation function label for the keys used with HMAC-384 in HELLO + * + * With the KDF the 'iter' parameter is 0 for the key used for + * HMAC in HELLO and 1 for the one used in OK(HELLO). */ #define ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC 'H' @@ -284,6 +288,7 @@ enum Verb * ordinary packet authentication. * * OK payload: + * [... HMAC-384 starts here ...] * <[8] HELLO timestamp field echo> * <[1] protocol version> * <[1] software major version> @@ -293,6 +298,7 @@ enum Verb * <[2] 16-bit reserved (legacy) field, always 0> * <[2] 16-bit length of meta-data dictionary> * <[...] meta-data dictionary> + * <[2] 16-bit length of any additional fields> * <[48] HMAC-SHA384 of all fields to this point (as plaintext)> * * With the exception of the timestamp, the other fields pertain to the @@ -824,26 +830,24 @@ namespace OK { */ ZT_PACKED_STRUCT(struct Header { + Protocol::Header h; uint8_t inReVerb; uint64_t inRePacketId; }); ZT_PACKED_STRUCT(struct WHOIS { - Protocol::Header h; - OK::Header oh; + OK::Header h; }); ZT_PACKED_STRUCT(struct ECHO { - Protocol::Header h; - OK::Header oh; + OK::Header h; }); ZT_PACKED_STRUCT(struct HELLO { - Protocol::Header h; - OK::Header oh; + OK::Header h; uint64_t timestampEcho; uint8_t versionProtocol; uint8_t versionMajor; @@ -853,8 +857,7 @@ ZT_PACKED_STRUCT(struct HELLO ZT_PACKED_STRUCT(struct EXT_FRAME { - Protocol::Header h; - OK::Header oh; + OK::Header h; uint64_t networkId; uint8_t flags; uint8_t destMac[6]; @@ -864,8 +867,7 @@ ZT_PACKED_STRUCT(struct EXT_FRAME ZT_PACKED_STRUCT(struct NETWORK_CONFIG { - Protocol::Header h; - OK::Header oh; + OK::Header h; uint64_t networkId; uint64_t configUpdateId; }); @@ -883,6 +885,7 @@ namespace ERROR { */ ZT_PACKED_STRUCT(struct Header { + Protocol::Header h; int8_t inReVerb; uint64_t inRePacketId; uint8_t error; @@ -890,15 +893,13 @@ ZT_PACKED_STRUCT(struct Header ZT_PACKED_STRUCT(struct NEED_MEMBERSHIP_CERTIFICATE { - Protocol::Header h; - ERROR::Header eh; + ERROR::Header h; uint64_t networkId; }); ZT_PACKED_STRUCT(struct UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST { - Protocol::Header h; - ERROR::Header eh; + ERROR::Header h; uint64_t networkId; }); @@ -906,19 +907,6 @@ ZT_PACKED_STRUCT(struct UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST /****************************************************************************/ -/** - * Increment the 3-bit hops field embedded in the packet flags field - */ -ZT_ALWAYS_INLINE unsigned int incrementPacketHops(Header &h) -{ - uint8_t flags = h.flags; - uint8_t hops = flags; - flags &= 0xf8U; - ++hops; - h.flags = flags | (hops & 0x07U); - return (unsigned int)hops; -} - /** * @return 3-bit hops field embedded in packet flags field */ diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index a4b5bd880..f0c0026d4 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -22,8 +22,8 @@ namespace ZeroTier { -class NodeConfig; -class Switch; +class VL1; +class VL2; class Topology; class Node; class NetworkController; @@ -36,19 +36,24 @@ class Trace; class RuntimeEnvironment { public: - inline RuntimeEnvironment(Node *n) : - node(n) - ,localNetworkController((NetworkController *)0) - ,rtmem((void *)0) - ,sw((Switch *)0) - ,topology((Topology *)0) - ,sa((SelfAwareness *)0) + ZT_ALWAYS_INLINE RuntimeEnvironment(Node *n) : + node(n), + localNetworkController(nullptr), + rtmem(nullptr), + t(nullptr), + vl2(nullptr), + vl1(nullptr), + topology(nullptr), + sa(nullptr) { publicIdentityStr[0] = (char)0; secretIdentityStr[0] = (char)0; } - inline ~RuntimeEnvironment() { Utils::burn(secretIdentityStr,sizeof(secretIdentityStr)); } + ZT_ALWAYS_INLINE ~RuntimeEnvironment() + { + Utils::burn(secretIdentityStr,sizeof(secretIdentityStr)); + } // Node instance that owns this RuntimeEnvironment Node *const node; @@ -66,7 +71,8 @@ public: * These are constant and never null after startup unless indicated. */ Trace *t; - Switch *sw; + VL2 *vl2; + VL1 *vl1; Topology *topology; SelfAwareness *sa; diff --git a/node/SHA512.cpp b/node/SHA512.cpp index ab5e06532..d60f9af5f 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -1,14 +1,13 @@ // This code is public domain, taken from a PD crypto source file on GitHub. -#include -#include -#include - #include "SHA512.hpp" #include "Utils.hpp" #include #include +#include +#include +#include namespace ZeroTier { diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 18f3fd1fa..53d43cd22 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -21,7 +21,6 @@ #include "RuntimeEnvironment.hpp" #include "Topology.hpp" #include "Peer.hpp" -#include "Switch.hpp" #include "Trace.hpp" // Entry timeout -- make it fairly long since this is just to prevent stale buildup @@ -86,7 +85,7 @@ void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receiv _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); - RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,entry.mySurface,myPhysicalAddress,scope); + RR->t->resettingPathsInScope(tPtr,0x9afff100,reporter,reporterPhysicalAddress,entry.mySurface,myPhysicalAddress,scope); } else { // Otherwise just update DB to use to determine external surface info entry.mySurface = myPhysicalAddress; diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index db5adbf6d..530e68f34 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -14,6 +14,7 @@ #ifndef ZT_SHAREDPTR_HPP #define ZT_SHAREDPTR_HPP +#include "Constants.hpp" #include "AtomicCounter.hpp" #include "TriviallyCopyable.hpp" diff --git a/node/Trace.cpp b/node/Trace.cpp index 8ae385a3d..01e1c104b 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -16,6 +16,10 @@ #include "Node.hpp" #include "Peer.hpp" +#include +#include +#include + // NOTE: packet IDs are always handled in network byte order, so no need to convert them. namespace ZeroTier { @@ -25,13 +29,31 @@ Trace::Trace(const RuntimeEnvironment *renv) : _vl1(false), _vl2(false), _vl2Filter(false), - _vl2Multicast(false), - _eventBufSize(0) + _vl2Multicast(false) { } +void Trace::unexpectedError( + void *tPtr, + uint32_t codeLocation, + const char *message, + ...) +{ + va_list ap; + ZT_TraceEvent_UNEXPECTED_ERROR ev; + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_UNEXPECTED_ERROR); + ev.codeLocation = codeLocation; + memset(ev.message,0,sizeof(ev.message)); + va_start(ap,message); + vsnprintf(ev.message,sizeof(ev.message),message,ap); + va_end(ap); + RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev); +} + void Trace::_resettingPathsInScope( void *const tPtr, + const uint32_t codeLocation, const Identity &reporter, const InetAddress &from, const InetAddress &oldExternal, @@ -39,30 +61,32 @@ void Trace::_resettingPathsInScope( const InetAddress::IpScope scope) { ZT_TraceEvent_VL1_RESETTING_PATHS_IN_SCOPE ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE); + ev.codeLocation = Utils::hton(codeLocation); from.forTrace(ev.from); oldExternal.forTrace(ev.oldExternal); newExternal.forTrace(ev.newExternal); ev.scope = (uint8_t)scope; - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev); } void Trace::_tryingNewPath( void *const tPtr, + const uint32_t codeLocation, const Identity &trying, const InetAddress &physicalAddress, const InetAddress &triggerAddress, - uint64_t triggeringPacketId, - uint8_t triggeringPacketVerb, - uint64_t triggeredByAddress, + const uint64_t triggeringPacketId, + const uint8_t triggeringPacketVerb, + const uint64_t triggeredByAddress, const uint8_t *triggeredByIdentityHash, - ZT_TraceTryingNewPathReason reason) + const ZT_TraceTryingNewPathReason reason) { ZT_TraceEvent_VL1_TRYING_NEW_PATH ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH); + ev.codeLocation = Utils::hton(codeLocation); ev.address = Utils::hton(trying.address().toInt()); memcpy(ev.identityHash,trying.hash(),48); physicalAddress.forTrace(ev.physicalAddress); @@ -74,21 +98,22 @@ void Trace::_tryingNewPath( memcpy(ev.triggeredByIdentityHash,triggeredByIdentityHash,48); else memset(ev.triggeredByIdentityHash,0,48); ev.reason = (uint8_t)reason; - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev); } void Trace::_learnedNewPath( void *const tPtr, - uint64_t packetId, + const uint32_t codeLocation, + const uint64_t packetId, const Identity &peerIdentity, const InetAddress &physicalAddress, const InetAddress &replaced) { ZT_TraceEvent_VL1_LEARNED_NEW_PATH ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH); - ev.packetId = packetId; + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH); + ev.codeLocation = Utils::hton(codeLocation); + ev.packetId = packetId; // packet IDs are kept in big-endian ev.address = Utils::hton(peerIdentity.address().toInt()); memcpy(ev.identityHash,peerIdentity.hash(),48); physicalAddress.forTrace(ev.physicalAddress); @@ -99,18 +124,20 @@ void Trace::_learnedNewPath( void Trace::_incomingPacketDropped( void *const tPtr, - uint64_t packetId, - uint64_t networkId, + const uint32_t codeLocation, + const uint64_t packetId, + const uint64_t networkId, const Identity &peerIdentity, const InetAddress &physicalAddress, - uint8_t hops, - uint8_t verb, - ZT_TracePacketDropReason reason) + const uint8_t hops, + const uint8_t verb, + const ZT_TracePacketDropReason reason) { ZT_TraceEvent_VL1_INCOMING_PACKET_DROPPED ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); - ev.packetId = packetId; + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); + ev.codeLocation = Utils::hton(codeLocation); + ev.packetId = packetId; // packet IDs are kept in big-endian ev.networkId = Utils::hton(networkId); if (peerIdentity) { ev.address = Utils::hton(peerIdentity.address().toInt()); @@ -129,17 +156,19 @@ void Trace::_incomingPacketDropped( void Trace::_outgoingNetworkFrameDropped( void *const tPtr, - uint64_t networkId, + const uint32_t codeLocation, + const uint64_t networkId, const MAC &sourceMac, const MAC &destMac, - uint16_t etherType, - uint16_t frameLength, + const uint16_t etherType, + const uint16_t frameLength, const uint8_t *frameData, - ZT_TraceFrameDropReason reason) + const ZT_TraceFrameDropReason reason) { ZT_TraceEvent_VL2_OUTGOING_FRAME_DROPPED ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED); + ev.codeLocation = Utils::hton(codeLocation); ev.networkId = Utils::hton(networkId); ev.sourceMac = Utils::hton(sourceMac.toInt()); ev.destMac = Utils::hton(destMac.toInt()); @@ -159,21 +188,23 @@ void Trace::_outgoingNetworkFrameDropped( void Trace::_incomingNetworkFrameDropped( void *const tPtr, - uint64_t networkId, + const uint32_t codeLocation, + const uint64_t networkId, const MAC &sourceMac, const MAC &destMac, const Identity &peerIdentity, const InetAddress &physicalAddress, - uint8_t hops, - uint16_t frameLength, + const uint8_t hops, + const uint16_t frameLength, const uint8_t *frameData, - uint8_t verb, - bool credentialRequestSent, - ZT_TraceFrameDropReason reason) + const uint8_t verb, + const bool credentialRequestSent, + const ZT_TraceFrameDropReason reason) { ZT_TraceEvent_VL2_INCOMING_FRAME_DROPPED ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_INCOMING_FRAME_DROPPED); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_INCOMING_FRAME_DROPPED); + ev.codeLocation = Utils::hton(codeLocation); ev.networkId = Utils::hton(networkId); ev.sourceMac = Utils::hton(sourceMac.toInt()); ev.destMac = Utils::hton(destMac.toInt()); @@ -197,38 +228,41 @@ void Trace::_incomingNetworkFrameDropped( void Trace::_networkConfigRequestSent( void *const tPtr, - uint64_t networkId) + const uint32_t codeLocation, + const uint64_t networkId) { ZT_TraceEvent_VL2_NETWORK_CONFIG_REQUESTED ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED); + ev.codeLocation = Utils::hton(codeLocation); ev.networkId = Utils::hton(networkId); - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev); } void Trace::_networkFilter( void *const tPtr, - uint64_t networkId, + const uint32_t codeLocation, + const uint64_t networkId, const uint8_t primaryRuleSetLog[512], const uint8_t matchingCapabilityRuleSetLog[512], - uint32_t matchingCapabilityId, - int64_t matchingCapabilityTimestamp, + const uint32_t matchingCapabilityId, + const int64_t matchingCapabilityTimestamp, const Address &source, const Address &dest, const MAC &sourceMac, const MAC &destMac, - uint16_t frameLength, + const uint16_t frameLength, const uint8_t *frameData, - uint16_t etherType, - uint16_t vlanId, - bool noTee, - bool inbound, - int accept) + const uint16_t etherType, + const uint16_t vlanId, + const bool noTee, + const bool inbound, + const int accept) { ZT_TraceEvent_VL2_NETWORK_FILTER ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER); + ev.codeLocation = Utils::hton(codeLocation); ev.networkId = Utils::hton(networkId); memcpy(ev.primaryRuleSetLog,primaryRuleSetLog,sizeof(ev.primaryRuleSetLog)); if (matchingCapabilityRuleSetLog) @@ -253,29 +287,29 @@ void Trace::_networkFilter( ev.noTee = (uint8_t)noTee; ev.inbound = (uint8_t)inbound; ev.accept = (int8_t)accept; - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev); } void Trace::_credentialRejected( void *const tPtr, - uint64_t networkId, + const uint32_t codeLocation, + const uint64_t networkId, const Address &address, - uint32_t credentialId, - int64_t credentialTimestamp, - uint8_t credentialType, - ZT_TraceCredentialRejectionReason reason) + const uint32_t credentialId, + const int64_t credentialTimestamp, + const uint8_t credentialType, + const ZT_TraceCredentialRejectionReason reason) { ZT_TraceEvent_VL2_CREDENTIAL_REJECTED ev; - ev.evSize = CONST_TO_BE_UINT16(sizeof(ev)); - ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER); + ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev)); + ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER); + ev.codeLocation = Utils::hton(codeLocation); ev.networkId = Utils::hton(networkId); ev.address = Utils::hton(address.toInt()); ev.credentialId = Utils::hton(credentialId); ev.credentialTimestamp = Utils::hton(credentialTimestamp); ev.credentialType = credentialType; ev.reason = (uint8_t)reason; - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev); } diff --git a/node/Trace.hpp b/node/Trace.hpp index d337b98df..40a062b20 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -66,19 +66,27 @@ public: explicit Trace(const RuntimeEnvironment *renv); + void unexpectedError( + void *tPtr, + uint32_t codeLocation, + const char *message, + ...); + ZT_ALWAYS_INLINE void resettingPathsInScope( void *const tPtr, + const uint32_t codeLocation, const Identity &reporter, const InetAddress &from, const InetAddress &oldExternal, const InetAddress &newExternal, const InetAddress::IpScope scope) { - if (_vl1) _resettingPathsInScope(tPtr,reporter,from,oldExternal,newExternal,scope); + if (_vl1) _resettingPathsInScope(tPtr,codeLocation,reporter,from,oldExternal,newExternal,scope); } ZT_ALWAYS_INLINE void tryingNewPath( void *const tPtr, + const uint32_t codeLocation, const Identity &trying, const InetAddress &physicalAddress, const InetAddress &triggerAddress, @@ -88,21 +96,23 @@ public: const uint8_t *triggeredByIdentityHash, ZT_TraceTryingNewPathReason reason) { - if (_vl1) _tryingNewPath(tPtr,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeredByAddress,triggeredByIdentityHash,reason); + if (_vl1) _tryingNewPath(tPtr,codeLocation,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeredByAddress,triggeredByIdentityHash,reason); } ZT_ALWAYS_INLINE void learnedNewPath( void *const tPtr, + const uint32_t codeLocation, uint64_t packetId, const Identity &peerIdentity, const InetAddress &physicalAddress, const InetAddress &replaced) { - if (_vl1) _learnedNewPath(tPtr,packetId,peerIdentity,physicalAddress,replaced); + if (_vl1) _learnedNewPath(tPtr,codeLocation,packetId,peerIdentity,physicalAddress,replaced); } ZT_ALWAYS_INLINE void incomingPacketDropped( void *const tPtr, + const uint32_t codeLocation, uint64_t packetId, uint64_t networkId, const Identity &peerIdentity, @@ -111,11 +121,12 @@ public: uint8_t verb, const ZT_TracePacketDropReason reason) { - if (_vl1) _incomingPacketDropped(tPtr,packetId,networkId,peerIdentity,physicalAddress,hops,verb,reason); + if (_vl1) _incomingPacketDropped(tPtr,codeLocation,packetId,networkId,peerIdentity,physicalAddress,hops,verb,reason); } ZT_ALWAYS_INLINE void outgoingNetworkFrameDropped( void *const tPtr, + const uint32_t codeLocation, uint64_t networkId, const MAC &sourceMac, const MAC &destMac, @@ -124,11 +135,12 @@ public: const uint8_t *frameData, ZT_TraceFrameDropReason reason) { - if (_vl2) _outgoingNetworkFrameDropped(tPtr,networkId,sourceMac,destMac,etherType,frameLength,frameData,reason); + if (_vl2) _outgoingNetworkFrameDropped(tPtr,codeLocation,networkId,sourceMac,destMac,etherType,frameLength,frameData,reason); } ZT_ALWAYS_INLINE void incomingNetworkFrameDropped( void *const tPtr, + const uint32_t codeLocation, uint64_t networkId, const MAC &sourceMac, const MAC &destMac, @@ -141,18 +153,20 @@ public: bool credentialRequestSent, ZT_TraceFrameDropReason reason) { - if (_vl2) _incomingNetworkFrameDropped(tPtr,networkId,sourceMac,destMac,peerIdentity,physicalAddress,hops,frameLength,frameData,verb,credentialRequestSent,reason); + if (_vl2) _incomingNetworkFrameDropped(tPtr,codeLocation,networkId,sourceMac,destMac,peerIdentity,physicalAddress,hops,frameLength,frameData,verb,credentialRequestSent,reason); } ZT_ALWAYS_INLINE void networkConfigRequestSent( void *const tPtr, + const uint32_t codeLocation, uint64_t networkId) { - if (_vl2) _networkConfigRequestSent(tPtr,networkId); + if (_vl2) _networkConfigRequestSent(tPtr,codeLocation,networkId); } ZT_ALWAYS_INLINE void networkFilter( void *const tPtr, + const uint32_t codeLocation, uint64_t networkId, const uint8_t primaryRuleSetLog[512], const uint8_t matchingCapabilityRuleSetLog[512], @@ -173,6 +187,7 @@ public: if (_vl2Filter) { _networkFilter( tPtr, + codeLocation, networkId, primaryRuleSetLog, matchingCapabilityRuleSetLog, @@ -194,6 +209,7 @@ public: ZT_ALWAYS_INLINE void credentialRejected( void *const tPtr, + const uint32_t codeLocation, uint64_t networkId, const Address &address, uint32_t credentialId, @@ -201,12 +217,13 @@ public: uint8_t credentialType, ZT_TraceCredentialRejectionReason reason) { - if (_vl2) _credentialRejected(tPtr,networkId,address,credentialId,credentialTimestamp,credentialType,reason); + if (_vl2) _credentialRejected(tPtr,codeLocation,networkId,address,credentialId,credentialTimestamp,credentialType,reason); } private: void _resettingPathsInScope( void *tPtr, + uint32_t codeLocation, const Identity &reporter, const InetAddress &from, const InetAddress &oldExternal, @@ -214,6 +231,7 @@ private: InetAddress::IpScope scope); void _tryingNewPath( void *tPtr, + uint32_t codeLocation, const Identity &trying, const InetAddress &physicalAddress, const InetAddress &triggerAddress, @@ -224,12 +242,14 @@ private: ZT_TraceTryingNewPathReason reason); void _learnedNewPath( void *tPtr, + uint32_t codeLocation, uint64_t packetId, const Identity &peerIdentity, const InetAddress &physicalAddress, const InetAddress &replaced); void _incomingPacketDropped( void *tPtr, + uint32_t codeLocation, uint64_t packetId, uint64_t networkId, const Identity &peerIdentity, @@ -239,6 +259,7 @@ private: ZT_TracePacketDropReason reason); void _outgoingNetworkFrameDropped( void *tPtr, + uint32_t codeLocation, uint64_t networkId, const MAC &sourceMac, const MAC &destMac, @@ -247,7 +268,8 @@ private: const uint8_t *frameData, ZT_TraceFrameDropReason reason); void _incomingNetworkFrameDropped( - void *const tPtr, + void *tPtr, + uint32_t codeLocation, uint64_t networkId, const MAC &sourceMac, const MAC &destMac, @@ -261,9 +283,11 @@ private: ZT_TraceFrameDropReason reason); void _networkConfigRequestSent( void *tPtr, + uint32_t codeLocation, uint64_t networkId); void _networkFilter( void *tPtr, + uint32_t codeLocation, uint64_t networkId, const uint8_t primaryRuleSetLog[512], const uint8_t matchingCapabilityRuleSetLog[512], @@ -282,6 +306,7 @@ private: int accept); void _credentialRejected( void *tPtr, + uint32_t codeLocation, uint64_t networkId, const Address &address, uint32_t credentialId, @@ -300,9 +325,6 @@ private: Mutex lock; }; - uint8_t _eventBuf[8192]; // must be less than ZT_PROTO_MAX_PACKET_LENGTH - unsigned int _eventBufSize; - std::vector<_MonitoringPeer> _monitoringPeers; RWMutex _monitoringPeers_l; }; diff --git a/node/Utils.cpp b/node/Utils.cpp index c7e0c8bf1..374cc507a 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -409,22 +409,27 @@ int b32d(const char *encoded,uint8_t *result,int bufSize) uint64_t random() { // https://en.wikipedia.org/wiki/Xorshift#xoshiro256** - static Mutex l; - static uint64_t s0 = getSecureRandomU64(); - static uint64_t s1 = getSecureRandomU64(); - static uint64_t s2 = getSecureRandomU64(); - static uint64_t s3 = getSecureRandomU64(); + static volatile uint64_t s_s0 = getSecureRandomU64(); + static volatile uint64_t s_s1 = getSecureRandomU64(); + static volatile uint64_t s_s2 = getSecureRandomU64(); + static volatile uint64_t s_s3 = getSecureRandomU64(); - l.lock(); - const uint64_t result = ROL64(s1 * 5,7) * 9; + uint64_t s0 = s_s0; + uint64_t s1 = s_s1; + uint64_t s2 = s_s2; + uint64_t s3 = s_s3; + const uint64_t result = ROL64(s1 * 5,7U) * 9; const uint64_t t = s1 << 17U; s2 ^= s0; s3 ^= s1; s1 ^= s2; s0 ^= s3; s2 ^= t; - s3 = ROL64(s3,45); - l.unlock(); + s3 = ROL64(s3,45U); + s_s0 = s0; + s_s1 = s1; + s_s2 = s2; + s_s3 = s3; return result; } diff --git a/node/VL1.cpp b/node/VL1.cpp index 0b2b03bb5..96dae9b2c 100644 --- a/node/VL1.cpp +++ b/node/VL1.cpp @@ -13,6 +13,7 @@ #include "VL1.hpp" #include "RuntimeEnvironment.hpp" +#include "Node.hpp" #include "Topology.hpp" #include "VL2.hpp" #include "Salsa20.hpp" @@ -21,12 +22,24 @@ #include "Identity.hpp" #include "SelfAwareness.hpp" #include "SHA512.hpp" +#include "Peer.hpp" +#include "Path.hpp" namespace ZeroTier { +namespace { + +ZT_ALWAYS_INLINE const Identity &ifPeerNonNull(const SharedPtr &p) +{ + if (p) + return p->identity(); + return Identity::NIL; +} + +} // anonymous namespace + VL1::VL1(const RuntimeEnvironment *renv) : - RR(renv), - _vl2(nullptr) + RR(renv) { } @@ -40,6 +53,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd const SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); + // Really short packets are keepalives and other junk. if (len < ZT_PROTO_MIN_FRAGMENT_LENGTH) return; @@ -131,8 +145,10 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd // Subject pktv to a few sanity checks just to make sure Defragmenter worked correctly and // there is enough room in each slice to shift their contents to sizes that are multiples // of 64 if needed for crypto. - if ((pktv.empty()) || (((int)pktv[0].e - (int)pktv[0].s) < sizeof(Protocol::Header))) + if ((pktv.empty()) || (((int)pktv[0].e - (int)pktv[0].s) < sizeof(Protocol::Header))) { + RR->t->unexpectedError(tPtr,0x3df19990,"empty or undersized packet vector"); return; + } for(FCV::const_iterator s(pktv.begin());s!=pktv.end();++s) { if ((s->e > (ZT_BUF_MEM_SIZE - 64))||(s->s > s->e)) return; @@ -155,7 +171,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd for(FCV::const_iterator s(pktv.begin()+1);s!=pktv.end();++s) packetSize += s->e - s->s; if (packetSize > ZT_PROTO_MAX_PACKET_LENGTH) { - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0x010348da,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return; } @@ -163,18 +179,15 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd if ((!peer)&&(!(((cipher == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)||(cipher == ZT_PROTO_CIPHER_SUITE__NONE))&&((ph->verb & 0x1fU) == Protocol::VERB_HELLO)))) { pkt = Buf::assembleSliceVector(pktv); if (pkt.e < ZT_PROTO_MIN_PACKET_LENGTH) { - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0xbada9366,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return; } { Mutex::Lock wl(_whoisQueue_l); _WhoisQueueItem &wq = _whoisQueue[source]; wq.inboundPackets.push_back(pkt); - if (wq.retries == 0) { - wq.retries = 1; - _sendPendingWhois(); - } } + _sendPendingWhois(tPtr,now); return; } @@ -182,8 +195,10 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd case ZT_PROTO_CIPHER_SUITE__POLY1305_NONE: if (peer) { pkt = Buf::assembleSliceVector(pktv); - if (pkt.e < ZT_PROTO_MIN_PACKET_LENGTH) - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + if (pkt.e < ZT_PROTO_MIN_PACKET_LENGTH) { + RR->t->incomingPacketDropped(tPtr,0x432aa9da,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + return; + } ph = &(pkt.b->as()); // Generate one-time-use MAC key using Salsa20. @@ -196,7 +211,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd uint64_t mac[2]; poly1305(mac,pkt.b->b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey); if (ph->mac != mac[0]) { - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + RR->t->incomingPacketDropped(tPtr,0xcc89c812,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } authenticated = true; @@ -216,8 +231,10 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd // Get a buffer to store the decrypted and fully contiguous packet. pkt.b = Buf::get(); - if (!pkt.b) // only possible on out of memory condition + if (!pkt.b) { + RR->t->unexpectedError(tPtr,0x1de16991,"Buf::get() failed (out of memory?)"); return; + } // Salsa20 is a stream cipher but it's only seekable to multiples of 64 bytes. // This moves data in slices around so that all slices have sizes that are @@ -237,6 +254,8 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd } // Simultaneously decrypt and assemble packet into a contiguous buffer. + // Since we moved data around above all slices will have sizes that are + // multiples of 64. memcpy(pkt.b->b,ph,sizeof(Protocol::Header)); pkt.e = sizeof(Protocol::Header); for(FCV::iterator s(pktv.begin());s!=pktv.end();++s) { @@ -250,12 +269,12 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd uint64_t mac[2]; poly1305(mac,pkt.b->b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey); if (ph->mac != mac[0]) { - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + RR->t->incomingPacketDropped(tPtr,0xbc881231,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } authenticated = true; } else { - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + RR->t->incomingPacketDropped(tPtr,0xb0b01999,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } break; @@ -267,14 +286,13 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd pkt = Buf::assembleSliceVector(pktv); if (pkt.e < ZT_PROTO_MIN_PACKET_LENGTH) - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0x3d3337df,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); ph = &(pkt.b->as()); if (RR->topology->shouldInboundPathBeTrusted(path->address(),Utils::ntoh(ph->mac))) { authenticated = true; } else { - if (peer) - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_NOT_TRUSTED_PATH); + RR->t->incomingPacketDropped(tPtr,0x2dfa910b,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_NOT_TRUSTED_PATH); return; } } break; @@ -285,8 +303,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd // break; default: - if (peer) - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + RR->t->incomingPacketDropped(tPtr,0x5b001099,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return; } @@ -295,16 +312,20 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd // Return any still held buffers in pktv to the buffer pool. pktv.clear(); + const Protocol::Verb verb = (Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK); + // Decompress packet payload if compressed. if ((ph->verb & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) { if (!authenticated) { - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0x390bcd0a,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return; } SharedPtr nb(Buf::get()); - if (!nb) // can only happen if we're out of memory + if (!nb) { + RR->t->unexpectedError(tPtr,0xffe169fa,"Buf::get() failed (out of memory?)"); return; + } const int uncompressedLen = LZ4_decompress_safe( reinterpret_cast(pkt.b->b + ZT_PROTO_PACKET_PAYLOAD_START), @@ -316,13 +337,14 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd pkt.b.swap(nb); pkt.e = packetSize = (unsigned int)uncompressedLen; } else { - if (peer) - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,(Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK),ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA); + RR->t->incomingPacketDropped(tPtr,0xee9e4392,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA); return; } } - const Protocol::Verb verb = (Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK); + // VL1 and VL2 are conceptually and (mostly) logically separate layers. + // Verbs that relate to VL1 (P2P transport) are handled in this class. + // VL2 (virtual Ethernet / SDN) verbs are handled in the VL2 class. switch(verb) { case Protocol::VERB_NOP: peer->received(tPtr,path,hops,ph->packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,Protocol::VERB_NOP,0,Protocol::VERB_NOP,0); @@ -333,32 +355,26 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd case Protocol::VERB_OK: _OK(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; case Protocol::VERB_WHOIS: _WHOIS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; case Protocol::VERB_RENDEZVOUS: _RENDEZVOUS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_FRAME: _vl2->_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_EXT_FRAME: _vl2->_EXT_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_FRAME: RR->vl2->_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_EXT_FRAME: RR->vl2->_EXT_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; case Protocol::VERB_ECHO: _ECHO(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); - case Protocol::VERB_MULTICAST_LIKE: _vl2->_MULTICAST_LIKE(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_NETWORK_CREDENTIALS: _vl2->_NETWORK_CREDENTIALS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_NETWORK_CONFIG_REQUEST: _vl2->_NETWORK_CONFIG_REQUEST(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_NETWORK_CONFIG: _vl2->_NETWORK_CONFIG(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_MULTICAST_GATHER: _vl2->_MULTICAST_GATHER(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_MULTICAST_FRAME_deprecated: _vl2->_MULTICAST_FRAME_deprecated(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_MULTICAST_LIKE: RR->vl2->_MULTICAST_LIKE(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_NETWORK_CREDENTIALS: RR->vl2->_NETWORK_CREDENTIALS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_NETWORK_CONFIG_REQUEST: RR->vl2->_NETWORK_CONFIG_REQUEST(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_NETWORK_CONFIG: RR->vl2->_NETWORK_CONFIG(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_MULTICAST_GATHER: RR->vl2->_MULTICAST_GATHER(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_MULTICAST_FRAME_deprecated: RR->vl2->_MULTICAST_FRAME_deprecated(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; case Protocol::VERB_PUSH_DIRECT_PATHS: _PUSH_DIRECT_PATHS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; case Protocol::VERB_USER_MESSAGE: _USER_MESSAGE(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_MULTICAST: _vl2->_MULTICAST(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; + case Protocol::VERB_MULTICAST: RR->vl2->_MULTICAST(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; case Protocol::VERB_ENCAP: _ENCAP(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; default: - if (peer) - RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB); + RR->t->incomingPacketDropped(tPtr,0xdeadeff0,ph->packetId,0,ifPeerNonNull(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB); break; } } catch ( ... ) { - uint64_t packetId = 0; - if (len >= 8) { - for(int i=0;i<8;++i) - reinterpret_cast(&packetId)[i] = data->b[i]; - } - RR->t->incomingPacketDropped(tPtr,packetId,0,Identity(),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->unexpectedError(tPtr,0xea1b6dea,"unexpected exception in onRemotePacket()"); } } @@ -366,15 +382,59 @@ void VL1::_relay(void *tPtr,const SharedPtr &path,const Address &destinati { } -void VL1::_sendPendingWhois() +void VL1::_sendPendingWhois(void *const tPtr,const int64_t now) { - // assume _whoisQueue_l locked + SharedPtr root(RR->topology->root()); + if (!root) + return; + SharedPtr rootPath(root->path(now)); + if (!rootPath) + return; + + std::vector
toSend; + { + Mutex::Lock wl(_whoisQueue_l); + Hashtable::Iterator wi(_whoisQueue); + Address *a = nullptr; + _WhoisQueueItem *wq = nullptr; + while (wi.next(a,wq)) { + if ((now - wq->lastRetry) >= ZT_WHOIS_RETRY_DELAY) { + wq->lastRetry = now; + ++wq->retries; + toSend.push_back(*a); + } + } + } + + Buf outp; + Protocol::Header &ph = outp.as(); + + std::vector
::iterator a(toSend.begin()); + while (a != toSend.end()) { + ph.packetId = Protocol::getPacketId(); + root->address().copyTo(ph.destination); + RR->identity.address().copyTo(ph.source); + ph.flags = 0; + ph.verb = Protocol::VERB_OK; + + int ptr = sizeof(Protocol::Header); + while ((a != toSend.end())&&(ptr < (ZT_PROTO_MAX_PACKET_LENGTH - 1))) { + a->copyTo(outp.b + ptr); + ++a; + ptr += ZT_ADDRESS_LENGTH; + } + + if (ptr > sizeof(Protocol::Header)) { + Protocol::armor(outp,ptr,root->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + rootPath->send(RR,tPtr,outp.b,ptr,now); + } + } } void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated) { if (packetSize < sizeof(Protocol::HELLO)) { - RR->t->incomingPacketDropped(tPtr,0,0,Identity(),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0x2bdb0001,0,0,ifPeerNonNull(peer),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return; } @@ -383,20 +443,22 @@ void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu int ptr = sizeof(Protocol::HELLO); if (p.versionProtocol < ZT_PROTO_VERSION_MIN) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,Identity(),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD); + RR->t->incomingPacketDropped(tPtr,0xe8d12bad,p.h.packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD); return; } Identity id; if (pkt.rO(ptr,id) < 0) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,Identity(),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + RR->t->incomingPacketDropped(tPtr,0x707a9810,p.h.packetId,0,ifPeerNonNull(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return; } if (Address(p.h.source) != id.address()) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + RR->t->incomingPacketDropped(tPtr,0x06aa9ff1,p.h.packetId,0,Identity::NIL,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } + // Packet is basically valid and identity unmarshaled --------------------------------------------------------------- + // Get long-term static key for this node. uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if ((peer)&&(id == peer->identity())) { @@ -404,12 +466,12 @@ void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu } else { peer.zero(); if (!RR->identity.agree(id,key)) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + RR->t->incomingPacketDropped(tPtr,0x46db8010,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } } - // Verify packet using Poly1305. For v2.x+ HELLOs this will be the first of two MACs for HELLO. + // Verify packet using Poly1305, which for v2.x { uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t macKey[ZT_POLY1305_KEY_LEN]; @@ -418,31 +480,31 @@ void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu uint64_t mac[2]; poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey); if (p.h.mac != mac[0]) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + RR->t->incomingPacketDropped(tPtr,0x11bfff81,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } } + // Packet has passed Poly1305 verification -------------------------------------------------------------------------- + InetAddress externalSurfaceAddress; Dictionary nodeMetaData; + uint8_t hmacKey[ZT_PEER_SECRET_KEY_LENGTH],hmac[ZT_HMACSHA384_LEN]; + bool hmacAuthenticated = false; // Get external surface address if present. if (ptr < packetSize) { if (pkt.rO(ptr,externalSurfaceAddress) < 0) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + RR->t->incomingPacketDropped(tPtr,0xf1000023,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return; } } if (ptr < packetSize) { - // NOTE to auditors: - // Anything after the external surface address is encrypted using Salsa20/12. - // The key for this is un-mangled static peer key. This is a bit of a legacy - // thing and isn't absolutely necessary, but does help conceal information - // that does not need to be in plaintext. This should not be considered - // a required part of the security/authentication model since leakage of - // this information would have no impact on either authentication or actual - // payload encryption. + // Everything after this point is encrypted with Salsa20/12. This is only a privacy measure + // since there's nothing truly secret in a HELLO packet. It also means that an observer + // can't even get ephemeral public keys without first knowing the long term secret key, + // adding a little defense in depth. uint8_t iv[8]; for(int i=0;i<8;++i) iv[i] = pkt.b[i]; iv[7] &= 0xf8U; @@ -454,44 +516,52 @@ void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu const unsigned int dictionarySize = pkt.rI16(ptr); const void *const dictionaryBytes = pkt.b + ptr; if ((ptr += (int)dictionarySize) > packetSize) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + RR->t->incomingPacketDropped(tPtr,0x0d0f0112,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return; } ptr += pkt.rI16(ptr); // skip any additional fields, currently always 0 if (ptr > packetSize) { - RR->t->incomingPacketDropped(tPtr,0,0,Identity(),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0x451f2341,0,p.h.packetId,id,path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return; } if ((ptr + ZT_SHA384_DIGEST_LEN) <= packetSize) { - uint8_t hmacKey[ZT_PEER_SECRET_KEY_LENGTH],mac[ZT_HMACSHA384_LEN]; - KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,0,hmacKey); - HMACSHA384(hmacKey,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,mac); - if (!Utils::secureEq(pkt.b + ptr,mac,ZT_HMACSHA384_LEN)) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,0,hmacKey); // iter == 0 for HELLO + HMACSHA384(hmacKey,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,hmac); + if (!Utils::secureEq(pkt.b + ptr,hmac,ZT_HMACSHA384_LEN)) { + RR->t->incomingPacketDropped(tPtr,0x1000662a,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; } + hmacAuthenticated = true; } if (dictionarySize) { if (!nodeMetaData.decode(dictionaryBytes,dictionarySize)) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + RR->t->incomingPacketDropped(tPtr,0x67192344,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return; } } } } + // v2.x+ peers must include HMAC, older peers don't + if ((!hmacAuthenticated)&&(p.versionProtocol >= 11)) { + RR->t->incomingPacketDropped(tPtr,0x571feeea,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return; + } + + // Packet is fully decoded and has passed full HMAC (if present) ---------------------------------------------------- + const int64_t now = RR->node->now(); if (!peer) { if (!RR->node->rateGateIdentityVerification(now,path->address())) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED); + RR->t->incomingPacketDropped(tPtr,0xaffa9ff7,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED); return; } if (!id.locallyValidate()) { - RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + RR->t->incomingPacketDropped(tPtr,0x2ff7a909,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return; } peer.set(new Peer(RR)); @@ -501,24 +571,30 @@ void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu peer = RR->topology->add(tPtr,peer); } + // All validation steps complete, peer learned if not yet known ----------------------------------------------------- + if ((hops == 0)&&(externalSurfaceAddress)) RR->sa->iam(tPtr,id,path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(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. + std::vector myNodeMetaDataBin; + { + Dictionary myNodeMetaData; + myNodeMetaData.encode(myNodeMetaDataBin); + } + if (myNodeMetaDataBin.size() > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check + return; - SharedPtr outp(Buf::get()); - if (!outp) return; - Protocol::OK::HELLO &ok = outp->as(); + Buf outp; + Protocol::OK::HELLO &ok = outp.as(); - ok.h.packetId = Protocol::getPacketId(); - id.address().copyTo(ok.h.destination); - RR->identity.address().copyTo(ok.h.source); - ok.h.flags = 0; - ok.h.verb = Protocol::VERB_OK; + ok.h.h.packetId = Protocol::getPacketId(); + id.address().copyTo(ok.h.h.destination); + RR->identity.address().copyTo(ok.h.h.source); + ok.h.h.flags = 0; + ok.h.h.verb = Protocol::VERB_OK; - ok.oh.inReVerb = Protocol::VERB_HELLO; - ok.oh.inRePacketId = p.h.packetId; + ok.h.inReVerb = Protocol::VERB_HELLO; + ok.h.inRePacketId = p.h.packetId; ok.timestampEcho = p.timestamp; ok.versionProtocol = ZT_PROTO_VERSION; @@ -527,33 +603,24 @@ void VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu ok.versionRev = ZT_CONST_TO_BE_UINT16(ZEROTIER_ONE_VERSION_REVISION); int outl = sizeof(Protocol::OK::HELLO); - outp->wO(outl,path->address()); + outp.wO(outl,path->address()); -#if 0 - ZT_GET_NEW_BUF(outp,Protocol::OK::HELLO); + if (p.versionProtocol >= 11) { + outp.wI(outl,(uint16_t)0); // legacy field, always 0 + outp.wI(outl,(uint16_t)myNodeMetaDataBin.size()); + outp.wB(outl,myNodeMetaDataBin.data(),(unsigned int)myNodeMetaDataBin.size()); + outp.wI(outl,(uint16_t)0); // length of additional fields, currently 0 - outp->data.fields.h.packetId = Protocol::getPacketId(); - peer->address().copyTo(outp->data.fields.h.destination); - RR->identity.address().copyTo(outp->data.fields.h.source); - outp->data.fields.h.flags = 0; - outp->data.fields.h.verb = Protocol::VERB_OK; + if ((outl + ZT_HMACSHA384_LEN) > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check, shouldn't be possible + return; - outp->data.fields.oh.inReVerb = Protocol::VERB_HELLO; - outp->data.fields.oh.inRePacketId = p.idBE; - - outp->data.fields.timestampEcho = pkt.data.fields.timestamp; - outp->data.fields.versionProtocol = ZT_PROTO_VERSION; - outp->data.fields.versionMajor = ZEROTIER_ONE_VERSION_MAJOR; - outp->data.fields.versionMinor = ZEROTIER_ONE_VERSION_MINOR; - outp->data.fields.versionRev = CONST_TO_BE_UINT16(ZEROTIER_ONE_VERSION_REVISION); - - int outl = sizeof(Protocol::OK::HELLO); - outp->wO(outl,p.path->address()); - if (!Buf<>::writeOverflow(outl)) { - Protocol::armor(*outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); - p.path->send(RR,tPtr,outp->data.bytes,outl,RR->node->now()); + KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,1,hmacKey); // iter == 1 for OK + HMACSHA384(hmacKey,outp.b + sizeof(ok.h),outl - sizeof(ok.h),outp.b + outl); + outl += ZT_HMACSHA384_LEN; } -#endif + + Protocol::armor(outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + path->send(RR,tPtr,outp.b,outl,now); peer->setRemoteVersion(p.versionProtocol,p.versionMajor,p.versionMinor,Utils::ntoh(p.versionRev)); peer->received(tPtr,path,hops,p.h.packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,Protocol::VERB_HELLO,0,Protocol::VERB_NOP,0); diff --git a/node/VL1.hpp b/node/VL1.hpp index 464997a37..d597d9a60 100644 --- a/node/VL1.hpp +++ b/node/VL1.hpp @@ -53,7 +53,7 @@ public: private: void _relay(void *tPtr,const SharedPtr &path,const Address &destination,SharedPtr &data,unsigned int len); - void _sendPendingWhois(); + void _sendPendingWhois(void *tPtr,int64_t now); // Handlers for VL1 verbs void _HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated); @@ -67,7 +67,6 @@ private: void _ENCAP(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated); const RuntimeEnvironment *RR; - VL2 *const _vl2; struct _WhoisQueueItem { diff --git a/node/VL2.cpp b/node/VL2.cpp index 86d35225e..707d1ebce 100644 --- a/node/VL2.cpp +++ b/node/VL2.cpp @@ -13,10 +13,13 @@ #include "VL2.hpp" #include "RuntimeEnvironment.hpp" +#include "Node.hpp" #include "VL1.hpp" #include "Topology.hpp" #include "Peer.hpp" #include "Path.hpp" +#include "Network.hpp" +#include "MAC.hpp" namespace ZeroTier { @@ -28,6 +31,10 @@ VL2::~VL2() { } +void VL2::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +{ +} + void VL2::_FRAME(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated) { } diff --git a/node/VL2.hpp b/node/VL2.hpp index 360b1b8be..a2c2c9270 100644 --- a/node/VL2.hpp +++ b/node/VL2.hpp @@ -28,6 +28,8 @@ class Path; class Peer; class RuntimeEnvironment; class VL1; +class Network; +class MAC; class VL2 { @@ -37,6 +39,20 @@ public: VL2(const RuntimeEnvironment *renv); ~VL2(); + /** + * 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 + * @param etherType Ethernet packet type + * @param vlanId VLAN ID or 0 if none + * @param data Ethernet payload + * @param len Frame length + */ + 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); + protected: void _FRAME(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated); void _EXT_FRAME(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated);