diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 3500276d0..d1a6a6761 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -522,7 +522,7 @@ void EmbeddedNetworkController::request( const InetAddress &fromAddr, uint64_t requestPacketId, const Identity &identity, - const Dictionary &metaData) + const Dictionary &metaData) { if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; @@ -1104,7 +1104,7 @@ void EmbeddedNetworkController::onNetworkUpdate(const void *db,uint64_t networkI const int64_t now = OSUtils::now(); std::lock_guard l(_memberStatus_l); for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { - if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData)) + if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData.size() > 0)) request(networkId,InetAddress(),0,i->second.identity,i->second.lastRequestMetaData); } } @@ -1115,7 +1115,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const void *db,uint64_t ne try { std::lock_guard l(_memberStatus_l); _MemberStatus &ms = _memberStatus[_MemberStatusKey(networkId,memberId)]; - if ((ms.online(OSUtils::now()))&&(ms.lastRequestMetaData)) + if ((ms.online(OSUtils::now()))&&(ms.lastRequestMetaData.size() > 0)) request(networkId,InetAddress(),0,ms.identity,ms.lastRequestMetaData); } catch ( ... ) {} } @@ -1139,7 +1139,7 @@ void EmbeddedNetworkController::_request( const InetAddress &fromAddr, uint64_t requestPacketId, const Identity &identity, - const Dictionary &metaData) + const Dictionary &metaData) { char nwids[24]; DB::NetworkSummaryInfo ns; @@ -1212,19 +1212,18 @@ void EmbeddedNetworkController::_request( autoAuthCredentialType = "public"; } else { char presentedAuth[512]; - if (metaData.get(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth)) > 0) { - presentedAuth[511] = (char)0; // sanity check - if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) { - const char *const presentedToken = presentedAuth + 6; - json authTokens(network["authTokens"]); - json &tokenExpires = authTokens[presentedToken]; - if (tokenExpires.is_number()) { - if ((tokenExpires == 0)||(tokenExpires > now)) { - authorized = true; - autoAuthorized = true; - autoAuthCredentialType = "token"; - autoAuthCredential = presentedToken; - } + metaData.getS(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth)); + presentedAuth[511] = 0; // sanity check, make sure always terminated + if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) { + const char *const presentedToken = presentedAuth + 6; + json authTokens(network["authTokens"]); + json &tokenExpires = authTokens[presentedToken]; + if (tokenExpires.is_number()) { + if ((tokenExpires == 0)||(tokenExpires > now)) { + authorized = true; + autoAuthorized = true; + autoAuthCredentialType = "token"; + autoAuthCredential = presentedToken; } } } @@ -1296,6 +1295,7 @@ void EmbeddedNetworkController::_request( nc->credentialTimeMaxDelta = credentialtmd; nc->revision = OSUtils::jsonInt(network["revision"],0ULL); nc->issuedTo = identity.address(); + memcpy(nc->issuedToIdentityHash,identity.hash(),sizeof(nc->issuedToIdentityHash)); if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; 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); diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 66622d2ce..0772c036f 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -64,7 +64,7 @@ public: const InetAddress &fromAddr, uint64_t requestPacketId, const Identity &identity, - const Dictionary &metaData); + const Dictionary &metaData); unsigned int handleControlPlaneHttpGET( const std::vector &path, @@ -87,7 +87,7 @@ public: virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId); private: - void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); + void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); void _startThreads(); struct _RQEntry @@ -96,31 +96,34 @@ private: uint64_t requestPacketId; InetAddress fromAddr; Identity identity; - Dictionary metaData; + Dictionary metaData; enum { RQENTRY_TYPE_REQUEST = 0 } type; }; + struct _MemberStatusKey { - _MemberStatusKey() : networkId(0),nodeId(0) {} - _MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {} + ZT_ALWAYS_INLINE _MemberStatusKey() : networkId(0),nodeId(0) {} + ZT_ALWAYS_INLINE _MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {} uint64_t networkId; uint64_t nodeId; inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); } }; + struct _MemberStatus { - _MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} + ZT_ALWAYS_INLINE _MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} uint64_t lastRequestTime; int vMajor,vMinor,vRev,vProto; - Dictionary lastRequestMetaData; + Dictionary lastRequestMetaData; Identity identity; inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } }; + struct _MemberStatusHash { - inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const + ZT_ALWAYS_INLINE std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const { return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId); } diff --git a/go/native/CoreTests.cpp b/go/native/CoreTests.cpp index 4acbb3903..fb40d9a41 100644 --- a/go/native/CoreTests.cpp +++ b/go/native/CoreTests.cpp @@ -26,11 +26,7 @@ #include "../../node/InetAddress.hpp" #include "../../node/Utils.hpp" #include "../../node/Identity.hpp" -#include "../../node/Buffer.hpp" #include "../../node/Salsa20.hpp" -#include "../../node/AES.hpp" -#include "../../node/Locator.hpp" -#include "../../node/NetworkConfig.hpp" #include "../../node/Dictionary.hpp" #include "../../node/SHA512.hpp" #include "../../node/C25519.hpp" @@ -126,6 +122,7 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = {{0x25,0x87,0x1e,0x6f,0xe8,0xd0,0xde,0x1d,0xd5,0xf2,0xd3,0x5b,0xff,0x9e,0x67,0x99,0x60,0xb4,0x0e,0xb7,0x98,0x1b,0x2a,0x3a,0x9c,0xec,0xc1,0xe1,0x2e,0x2b,0xc0,0x3e,0x3c,0xfb,0x64,0x91,0x72,0xc6,0x7e,0x57,0x47,0x00,0x97,0xbf,0x8e,0x0e,0xbf,0xad,0xd9,0x28,0x86,0x7c,0xfd,0x41,0x91,0xae,0x2d,0xee,0xc0,0xb2,0x32,0x7d,0x99,0x7d},{0x63,0xc1,0xf9,0x61,0x9c,0x9e,0x1a,0xd7,0xca,0xa3,0x71,0xd6,0x34,0x3d,0xa7,0x08,0x36,0x0c,0xec,0x37,0x35,0x94,0x1a,0x45,0xa9,0xfa,0xf2,0xb5,0x25,0x92,0xbf,0xd1,0x1e,0xca,0xdd,0x5a,0x23,0xad,0x9e,0x45,0xc3,0x66,0xcb,0x8f,0xda,0xa3,0xd1,0xe6,0x27,0x38,0x11,0x54,0x67,0x31,0x03,0x64,0x35,0xe0,0x68,0x0b,0x93,0xee,0x81,0x17},{0x8b,0x01,0xe9,0x99,0x54,0x54,0x73,0x15,0x0b,0xac,0x38,0x7b,0xe9,0xe3,0x17,0x4f,0x02,0x3e,0xe3,0x8e,0xda,0x41,0xa0,0x9d,0x10,0xe0,0xda,0x11,0xfe,0xec,0x2f,0x42,0xe7,0xc8,0xb3,0xde,0x2f,0x7b,0xfd,0xdf,0x7c,0x34,0x3b,0x5e,0xac,0x22,0x8c,0x99,0x3d,0xa1,0xa9,0xd9,0x81,0xb6,0x51,0xc8,0xaf,0x3e,0x75,0xed,0x45,0xcf,0xf7,0xb9},{0xaf,0xe9,0x9c,0x16,0x4a,0x8f,0x3b,0x0f,0xef,0x71,0x2f,0xaa,0x8d,0x7d,0xce,0xed,0xea,0x31,0x93,0xaf,0x2c,0x75,0xc6,0xfa,0xda,0x3e,0xa6,0xea,0x2a,0x3e,0x7b,0x72,0xb6,0xf8,0xd7,0x9a,0x88,0xcb,0x0b,0x81,0x97,0x24,0x29,0x3b,0x11,0x23,0x69,0xc2,0xff,0x98,0x39,0x25,0x99,0xae,0xe1,0x07,0x3e,0x97,0xde,0x10,0x21,0x23,0x7a,0x2d},{0xbe,0x2f,0xb9,0x4c,0x41,0x5a,0x9a,0xf6,0xfb,0xf8,0x26,0x9d,0x81,0x7f,0x39,0x91,0xaf,0x5b,0xf1,0xd7,0x93,0x0a,0xdf,0x18,0x19,0x4a,0x80,0x74,0x14,0x98,0x2b,0xf2,0x3b,0x25,0xc5,0xe8,0xfc,0x07,0x3f,0x5d,0xa1,0x39,0x27,0x4e,0x1c,0xd2,0x7a,0xfe,0x3e,0x7b,0x03,0x35,0x15,0x9e,0x35,0x2b,0xd0,0xbe,0x67,0x48,0x42,0xdd,0xa4,0xdd},{0xbd,0xcd,0xd7,0xbf,0xb1,0x0a,0xdb,0x9f,0x85,0x42,0xba,0xf4,0xc8,0xff,0xb0,0xe1,0x9a,0x18,0x6d,0x1a,0xe0,0x37,0xc1,0xa2,0xe1,0x1c,0x38,0x55,0x14,0xbf,0x64,0x67,0x84,0x47,0xb6,0x0a,0xf6,0x93,0xf1,0x10,0xab,0x09,0xf0,0x60,0x84,0xe2,0x4e,0x4b,0x5e,0xa2,0xd2,0xd1,0x19,0x22,0xd7,0xc4,0x85,0x13,0x23,0xa3,0x6a,0xb6,0x75,0x0f,0x43,0xe6,0xde,0x7b,0x67,0x2a,0x73,0x77,0x9e,0xb4,0x94,0x6c,0xc3,0x9a,0x67,0x51,0xcf,0xe9,0x47,0x46,0x0e,0x3a,0x12,0x7d,0x7c,0x66,0x73,0x6c,0xd5,0x4a,0x21,0x4d},{0x89,0x7e,0xd0,0xbf,0x2e,0x9f,0x0c,0xff,0x6e,0x56,0x25,0x9b,0x79,0x99,0x52,0x27,0xc2,0x3a,0xaa,0xf0,0x47,0x6d,0xed,0x05,0xa1,0xeb,0x9c,0x92,0x28,0x7f,0x1b,0xc8,0x1c,0x57,0x76,0xab,0x05,0xe3,0xd3,0xb7,0xa3,0xf5,0xac,0xa8,0x21,0x33,0x7c,0xb7,0xe7,0xc2,0xd0,0x25,0x6f,0xdf,0x34,0xd1,0xb0,0x34,0x41,0x46,0x30,0x9c,0x76,0x07,0x43,0xe6,0xde,0x7b,0x67,0x2a,0x73,0x77,0x9e,0xb4,0x94,0x6c,0xc3,0x9a,0x67,0x51,0xcf,0xe9,0x47,0x46,0x0e,0x3a,0x12,0x7d,0x7c,0x66,0x73,0x6c,0xd5,0x4a,0x21,0x4d}} }; +/* static const uint8_t AES_TEST_VECTOR_0_KEY[32] = { 0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4 }; static const uint8_t AES_TEST_VECTOR_0_IN[16] = { 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a }; static const uint8_t AES_TEST_VECTOR_0_OUT[16] = { 0xf3,0xee,0xd1,0xbd,0xb5,0xd2,0xa0,0x3c,0x06,0x4b,0x5a,0x7e,0x3d,0xb1,0x81,0xf8 }; @@ -144,6 +141,7 @@ static const uint8_t AES_GMAC_VECTOR_2_KEY[32] = { 0x63,0x2f,0xd9,0x48,0xcf,0x70 static const uint8_t AES_GMAC_VECTOR_2_IV[12] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b }; static const uint8_t AES_GMAC_VECTOR_2_IN[541] = { 0xc8,0x36,0x38,0xe8,0x53,0xc8,0x86,0xa3,0xe3,0xad,0x9e,0x2a,0x91,0x47,0xb9,0x51,0xad,0xf7,0x78,0x89,0x9a,0xeb,0x80,0x41,0x67,0xa9,0x16,0xc4,0x93,0xcc,0x77,0x3d,0x8c,0xcf,0x4d,0xb5,0x0b,0xda,0xfd,0xc2,0x8c,0x83,0x5d,0x66,0x43,0x74,0x21,0xbd,0xc4,0xab,0x41,0xd8,0x40,0x53,0x34,0xe8,0x05,0xcb,0x89,0x45,0x09,0xb0,0xa4,0xa6,0x04,0x95,0x19,0x2c,0xab,0x94,0xe1,0x8d,0x7b,0x59,0x8b,0xb9,0x31,0xae,0x3c,0x25,0xd3,0x23,0xab,0x8f,0x95,0xa3,0x8b,0xa5,0xc1,0x66,0x8b,0x57,0xe4,0x88,0x70,0xc9,0xe0,0xa1,0x16,0x39,0xf8,0x12,0xb3,0xe5,0x95,0x38,0x3a,0x01,0x1d,0xcc,0xc0,0xc3,0xa9,0x1c,0x72,0xa7,0x46,0x79,0x51,0x05,0xb2,0x85,0x5a,0x97,0x16,0x97,0xa6,0x85,0xa4,0xf2,0x0b,0x3c,0x90,0x52,0xa3,0xe0,0xbe,0xad,0x06,0x1b,0x8e,0x04,0x22,0xeb,0x3a,0x48,0xb9,0x84,0x24,0x0b,0x24,0x42,0xd9,0xed,0x6b,0x5c,0xc1,0xb6,0x2e,0xa5,0xc0,0x07,0xfe,0x3e,0xbc,0x9a,0x92,0x26,0xb5,0xa6,0x5f,0x09,0x13,0x85,0x5a,0xcf,0x61,0x56,0x65,0x0f,0x4c,0x64,0x79,0xfa,0x0a,0xcf,0xc0,0x95,0x8d,0x4d,0xc6,0xbe,0xee,0xb3,0x67,0xd8,0xa7,0x40,0x90,0x61,0xe3,0xba,0xcb,0x18,0xe0,0x61,0x7b,0x33,0x86,0xf7,0xef,0x64,0xe5,0x36,0xf0,0x9c,0xb6,0x34,0xb1,0xe1,0x2a,0xd8,0xd8,0x5e,0x6b,0x61,0x92,0xa0,0x8e,0x04,0x7b,0xbf,0xa5,0x84,0x39,0x3a,0xe0,0x27,0xc7,0xb0,0x83,0x88,0x4f,0x3e,0x49,0x14,0xaa,0x34,0xde,0xb4,0xbb,0x4c,0xe4,0xbf,0xae,0x9a,0xf9,0x88,0x7a,0x1f,0x18,0xa0,0x8c,0x60,0xc0,0x5c,0x46,0xa1,0xd1,0x36,0x99,0x60,0x9b,0x73,0xa2,0x9a,0x0b,0x8d,0x6e,0x2f,0xe1,0x58,0x7a,0x39,0x71,0xed,0xfc,0x34,0xe4,0x98,0x57,0x7e,0x86,0xf1,0xe5,0x00,0x7d,0x1b,0x6a,0xfa,0xf8,0x6e,0x7b,0x12,0x44,0x04,0x60,0x02,0x81,0x12,0x09,0x00,0xb4,0x35,0x9e,0x03,0x73,0x79,0x9b,0x13,0xc5,0xd7,0x0e,0xce,0x49,0x87,0x48,0x1a,0x67,0x89,0x93,0xef,0xd1,0xdf,0x2d,0x48,0x6d,0x30,0xd5,0xec,0x49,0xfe,0x15,0x1b,0xa6,0x2b,0x6c,0x08,0x8e,0x39,0x73,0x68,0x87,0xa7,0x43,0x28,0x16,0x77,0x86,0xd1,0xcb,0x13,0xe4,0xd3,0xda,0x63,0xcd,0x3a,0x2a,0x35,0xd5,0xfa,0x36,0x67,0xc8,0x4c,0x6b,0xa1,0x8a,0xaf,0x7b,0x4c,0x43,0xb0,0x2f,0x4a,0xcc,0xc0,0x11,0xc6,0x30,0x8e,0xa3,0xd2,0x4a,0x1b,0x2a,0x4f,0xec,0x97,0x83,0xa6,0x4c,0xee,0x51,0xaf,0x06,0x0a,0x1d,0x80,0xd9,0xcf,0xb7,0x69,0x23,0x15,0x3a,0x26,0x04,0x34,0x33,0x76,0x30,0x9f,0xfb,0x56,0xb4,0x26,0xee,0xfa,0x54,0x6c,0x18,0xf9,0xd5,0x32,0x5d,0x03,0xcb,0x2c,0x20,0x30,0x0c,0xa0,0xbb,0xde,0x01,0x77,0x65,0xb0,0x18,0x30,0xd2,0x55,0x9f,0x9b,0xcf,0xb8,0x9b,0xb4,0xbc,0x0b,0x49,0x52,0x53,0x30,0x48,0xa5,0x12,0xe5,0x3b,0x47,0x84,0xff,0xf1,0x53,0x5d,0x5c,0x04,0x70,0x63,0x91,0xc3,0xc0,0xf0,0xea,0xcb,0x44,0x4f,0x8c,0x85,0x42,0x6a,0xc7,0xfa,0xc7,0xb5,0x30,0x03,0x12,0x65,0xca,0xba,0x4f,0x67,0xbb,0xef,0xb6,0xc6,0x3f,0x19,0xe2,0xb5,0x4b,0x8c,0xfc,0x9e,0x18,0xb0,0x33,0x89,0x6e,0xde,0x61,0x0a,0xe3,0x5e,0xa3,0x5d,0x2e,0x80,0x3e,0x53,0x67,0xfb,0x7b,0x7a,0xbf,0xd5,0xf4,0x47 }; static const uint8_t AES_GMAC_VECTOR_2_OUT[16] = { 0x67,0x39,0x4f,0x00,0x04,0x28,0xaf,0xe9,0xb4,0x2e,0xb5,0x3c,0x42,0x24,0x86,0xa3 }; +*/ extern "C" int ZT_TestCrypto() { @@ -443,7 +441,6 @@ extern "C" int ZT_TestCrypto() extern "C" int ZT_TestIdentity() { Identity id; - Buffer<512> buf; char buf2[1024]; std::cout << "[identity] Validate known-good identity... "; std::cout.flush(); @@ -490,6 +487,7 @@ extern "C" int ZT_TestIdentity() } } + /* { Identity id2; buf.clear(); @@ -517,6 +515,7 @@ extern "C" int ZT_TestIdentity() return -1; } } + */ { Identity id2; @@ -634,60 +633,6 @@ extern "C" int ZT_TestOther() std::cout << " " << InetAddress("").toString(buf); std::cout << ZT_EOL_S; - { - std::cout << "[other] Testing/fuzzing Dictionary... "; std::cout.flush(); - for(int k=0;k<250;++k) { - Dictionary<8194> *test = new Dictionary<8194>(); - char key[32][16]; - char value[32][64]; - memset(key, 0, sizeof(key)); - memset(value, 0, sizeof(value)); - for(unsigned int q=0;q<32;++q) { - Utils::hex((uint32_t)((Utils::random() % 1000) + (q * 1000)),key[q]); - int r = (int)(Utils::random() % 64); - for(int x=0;xadd(key[q],value[q],r); - } - for(unsigned int q=0;q<1024;++q) { - int r = (int)(Utils::random() % 32); - char tmp[128]; - if (test->get(key[r],tmp,sizeof(tmp)) >= 0) { - if (strcmp(value[r],tmp)) { - std::cout << "FAILED (invalid value '" << value[r] << "' != '" << tmp << "')!" ZT_EOL_S; - return -1; - } - } else { - std::cout << "FAILED (can't find key '" << key[r] << "')!" ZT_EOL_S; - return -1; - } - } - delete test; - } - int foo = 0; - volatile int *volatile bar = &foo; // force compiler not to optimize out test.get() below - for(int k=0;k<200;++k) { - int r = rand() % 8194; - unsigned char *tmp = new unsigned char[8194]; - for(int q=0;q *test = new Dictionary<8194>((const char *)tmp); - for(unsigned int q=0;q<100;++q) { - char tmp[128]; - for(unsigned int x=0;x<128;++x) - tmp[x] = (char)(rand() & 0xff); - tmp[127] = (char)0; - char value[8194]; - *bar += test->get(tmp,value,sizeof(value)); - } - delete test; - delete[] tmp; - } - std::cout << "PASS (junk value to prevent optimization-out of test: " << foo << ")" ZT_EOL_S; - } - std::cout.flush(); return 0; } diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index 6778cf89d..03b2b90fb 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -15,23 +15,25 @@ #define ZT_ATOMICCOUNTER_HPP #include "Constants.hpp" +#include "TriviallyCopyable.hpp" #ifndef __GNUC__ -#include +#include #endif namespace ZeroTier { /** - * Simple atomic counter + * Simple atomic integer used for reference and other counters * * @tparam T Type of underlying integer (default: int) */ template -class AtomicCounter +class AtomicCounter : public TriviallyCopyable { public: - explicit ZT_ALWAYS_INLINE AtomicCounter(T iv = T(0)) : _v(iv) {} + ZT_ALWAYS_INLINE AtomicCounter() : _v(0) {} + explicit ZT_ALWAYS_INLINE AtomicCounter(T iv) : _v(iv) {} ZT_ALWAYS_INLINE T load() const { @@ -42,10 +44,7 @@ public: #endif } - ZT_ALWAYS_INLINE void zero() - { - _v = T(0); - } + ZT_ALWAYS_INLINE void zero() { _v = 0; } ZT_ALWAYS_INLINE T operator++() { diff --git a/node/Buf.hpp b/node/Buf.hpp index 563a55b60..6c5c3225c 100644 --- a/node/Buf.hpp +++ b/node/Buf.hpp @@ -19,6 +19,7 @@ #include "Utils.hpp" #include "SharedPtr.hpp" #include "Mutex.hpp" +#include "TriviallyCopyable.hpp" #include #include @@ -113,7 +114,7 @@ public: /** * Slice is almost exactly like the built-in slice data structure in Go */ - struct Slice + struct Slice : TriviallyCopyable { ZT_ALWAYS_INLINE Slice(const SharedPtr &b_,const unsigned int s_,const unsigned int e_) : b(b_),s(s_),e(e_) {} ZT_ALWAYS_INLINE Slice() : b(),s(0),e(0) {} diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index d4aa5bc0d..d53ab11b2 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -33,7 +33,7 @@ void CertificateOfOwnership::addThing(const MAC &mac) { if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; _thingTypes[_thingCount] = THING_MAC_ADDRESS; - mac.copyTo(_thingValues[_thingCount],6); + mac.copyTo(_thingValues[_thingCount]); ++_thingCount; } diff --git a/node/Defragmenter.hpp b/node/Defragmenter.hpp index 6908150a4..7dea7187f 100644 --- a/node/Defragmenter.hpp +++ b/node/Defragmenter.hpp @@ -88,6 +88,7 @@ public: struct Result { ZT_ALWAYS_INLINE Result() : message(),messageFragmentCount(0),error(Defragmenter::ERR_NONE) {} + explicit ZT_ALWAYS_INLINE Result(const Defragmenter::ErrorCode e) : message(),messageFragmentCount(0),error(e) {} /** * Fully assembled message as a series of slices of fragments @@ -186,25 +187,21 @@ public: const unsigned long messageQueueSizeTarget, const unsigned long messageQueueSizeGCTrigger) { - Result r; - // Sanity checks for malformed fragments or invalid input parameters. - if ((fragmentNo >= totalFragmentsExpected)||(totalFragmentsExpected > MF)||(totalFragmentsExpected == 0)) { - r.error = ERR_INVALID_FRAGMENT; - return r; - } + if ((fragmentNo >= totalFragmentsExpected)||(totalFragmentsExpected > MF)||(totalFragmentsExpected == 0)) + return Result(ERR_INVALID_FRAGMENT); // If there is only one fragment just return that fragment and we are done. if (totalFragmentsExpected < 2) { if (fragmentNo == 0) { + Result r; r.message[0].b.move(fragment); r.message[0].s = fragmentDataIndex; r.message[0].e = fragmentDataSize; r.messageFragmentCount = 1; return r; } else { - r.error = ERR_INVALID_FRAGMENT; - return r; + return Result(ERR_INVALID_FRAGMENT); } } @@ -246,8 +243,7 @@ public: _messages_l.lock(); _messages.clear(); _messages_l.unlock(); - r.error = ERR_OUT_OF_MEMORY; - return r; + return Result(ERR_OUT_OF_MEMORY); } } } @@ -260,8 +256,7 @@ public: RWMutex::Lock ml(_messages_l); e = &(_messages[messageId]); } catch ( ... ) { - r.error = ERR_OUT_OF_MEMORY; - return r; + return Result(ERR_OUT_OF_MEMORY); } e->id = messageId; } @@ -292,8 +287,7 @@ public: } via->_inboundFragmentedMessages_l.unlock(); if (tooManyPerPath) { - r.error = ERR_TOO_MANY_FRAGMENTS_FOR_PATH; - return r; + return Result(ERR_TOO_MANY_FRAGMENTS_FOR_PATH); } } @@ -305,11 +299,9 @@ public: // data would just mean the transfer is corrupt and would be detected // later e.g. by packet MAC check. Other use cases of this code like // network configs check each fragment so this basically can't happen. - Buf<>::Slice &s = e->fragment[fragmentNo]; - if (s.b) { - r.error = ERR_DUPLICATE_FRAGMENT; - return r; - } + Buf<>::Slice &s = e->result.message[fragmentNo]; + if (s.b) + return Result(ERR_DUPLICATE_FRAGMENT); // Take ownership of fragment, setting 'fragment' pointer to NULL. The simple // transfer of the pointer avoids a synchronized increment/decrement of the object's @@ -319,7 +311,7 @@ public: s.e = fragmentDataIndex + fragmentDataSize; // If we now have all fragments then assemble them. - if (++e->fragmentCount >= totalFragmentsExpected) { + if (++e->result.messageFragmentCount >= totalFragmentsExpected) { // This message is done so de-register it with its path if one is associated. if (e->via) { e->via->_inboundFragmentedMessages_l.lock(); @@ -328,18 +320,10 @@ public: e->via.zero(); } - // PERFORMANCE HACK: SharedPtr<> is introspective and only holds a pointer, so we - // can 'move' the pointers it holds very quickly by bulk copying the source - // slices and then zeroing the originals. This is only okay if the destination - // currently holds no pointers, which should always be the case. Don't try this - // at home kids. - unsigned int msize = e->fragmentCount * sizeof(Buf<>::Slice); - memcpy(reinterpret_cast(r.message),reinterpret_cast(e->fragment),msize); - memset(reinterpret_cast(e->fragment),0,msize); - r.messageFragmentCount = e->fragmentCount; + return e->result; } - return r; + return Result(ERR_NONE); } /** @@ -354,7 +338,7 @@ public: private: struct _E { - ZT_ALWAYS_INLINE _E() : id(0),lastUsed(0),via(),fragmentCount(0) {} + ZT_ALWAYS_INLINE _E() : id(0),lastUsed(0),via() {} ZT_ALWAYS_INLINE ~_E() { // Ensure that this entry is not in use while it is being deleted! @@ -369,8 +353,7 @@ private: uint64_t id; volatile int64_t lastUsed; SharedPtr via; - Buf<>::Slice fragment[MF]; - unsigned int fragmentCount; + Result result; Mutex lock; }; diff --git a/node/Endpoint.hpp b/node/Endpoint.hpp index 21921a4b8..eb537ab2b 100644 --- a/node/Endpoint.hpp +++ b/node/Endpoint.hpp @@ -53,10 +53,7 @@ public: ZT_ALWAYS_INLINE Endpoint() { memoryZero(this); } - explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) - { - *this = sa; - } + explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) { *this = sa; } ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) : _t(ZEROTIER) @@ -74,9 +71,7 @@ public: explicit ZT_ALWAYS_INLINE Endpoint(const char *url) : _t(URL) - { - Utils::scopy(_v.url,sizeof(_v.url),url); - } + { Utils::scopy(_v.url,sizeof(_v.url),url); } ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa) { diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 972cf2505..2428bc031 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -358,7 +358,7 @@ private: static ZT_ALWAYS_INLINE unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); } static ZT_ALWAYS_INLINE unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); } static ZT_ALWAYS_INLINE unsigned long _hc(const uint8_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); } - static ZT_ALWAYS_INLINE unsigned long _hc(const int64_t i) { return (unsigned long)(i ^ (i >> 32U)); } + static ZT_ALWAYS_INLINE unsigned long _hc(const int64_t i) { return (unsigned long)((unsigned long long)i ^ ((unsigned long long)i >> 32U)); } static ZT_ALWAYS_INLINE unsigned long _hc(const int32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); } static ZT_ALWAYS_INLINE unsigned long _hc(const int16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); } static ZT_ALWAYS_INLINE unsigned long _hc(const int8_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); } diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 420502b7a..dc6b0d433 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -336,7 +336,7 @@ ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &p,const RuntimeEnvironment *const RR networkId = pkt.rI64(ptr); const SharedPtr network(RR->node->network(networkId)); if (network) - network->handleConfigChunk(tPtr,p.idBE,peer->address(),pkt,sizeof(Protocol::OK::Header),(int)p.size); + network->handleConfigChunk(tPtr,p.idBE,peer,pkt,sizeof(Protocol::OK::Header),(int)p.size); } break; case Protocol::VERB_MULTICAST_GATHER: { @@ -782,33 +782,34 @@ ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &p,const RuntimeE ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer) { int ptr = sizeof(Protocol::Header); - const uint64_t nwid = p.pkt->rI64(ptr); - if (Buf<>::readOverflow(ptr,p.size)) { - RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG_REQUEST,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + if (ptr >= (int)p.size) { + RR->t->incomingPacketDropped(tPtr,p.idBE,0,peer->identity(),p.path->address(),p.hops,Protocol::VERB_NETWORK_CONFIG,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return true; } const SharedPtr network(RR->node->network(nwid)); if (network) { - } + const uint64_t configUpdateId = network->handleConfigChunk(tPtr,p.idBE,peer,*p.pkt,ptr,(int)p.size - ptr); + if (configUpdateId != 0) { + ZT_GET_NEW_BUF(outp,Protocol::OK::NETWORK_CONFIG); - /* - const SharedPtr network(RR->node->network(pkt.at(ZT_PACKET_IDX_PAYLOAD))); - if (network) { - const uint64_t configUpdateId = network->handleConfigChunk(tPtr,pkt.packetId(),pkt.source(),pkt,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)pkt.packetId()); - outp.append((uint64_t)network->id()); - outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true); - path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + 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; + + outp->data.fields.oh.inReVerb = Protocol::VERB_NETWORK_CONFIG; + outp->data.fields.oh.inRePacketId = p.idBE; + + outp->data.fields.networkId = Utils::hton(nwid); + outp->data.fields.configUpdateId = Utils::hton(configUpdateId); + + Protocol::armor(*outp,sizeof(Protocol::OK::NETWORK_CONFIG),peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + p.path->send(RR,tPtr,outp->data.bytes,sizeof(Protocol::OK::NETWORK_CONFIG),RR->node->now()); } } - peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,(network) ? network->id() : 0); - */ peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_NETWORK_CONFIG,0,Protocol::VERB_NOP,nwid); return true; @@ -873,17 +874,17 @@ ZT_ALWAYS_INLINE bool _doPUSH_DIRECT_PATHS(IncomingPacket &p,const RuntimeEnviro ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &p,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer) { - /* - if (likely(pkt.size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { - ZT_UserMessage um; - um.id = (const ZT_Identity *)(&(peer->identity())); - um.typeId = pkt.at(ZT_PACKET_IDX_PAYLOAD); - um.data = reinterpret_cast(reinterpret_cast(pkt.data()) + ZT_PACKET_IDX_PAYLOAD + 8); - um.length = pkt.size() - (ZT_PACKET_IDX_PAYLOAD + 8); + ZT_UserMessage um; + int ptr = sizeof(Protocol::Header); + um.id = reinterpret_cast(&(peer->identity())); + um.typeId = p.pkt->rI64(ptr); + int ds = (int)p.size - ptr; + if (ds > 0) { + um.data = p.pkt->data.bytes + ptr; + um.length = (unsigned int)ds; RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } - peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,0); - */ + peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_USER_MESSAGE,0,Protocol::VERB_NOP,0); return true; } diff --git a/node/Network.cpp b/node/Network.cpp index b4acdffea..876f4c3e7 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -849,7 +849,7 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.erase(i); } -uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const Address &source,const Buf<> &chunk,int ptr,int size) +uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr &source,const Buf<> &chunk,int ptr,int size) { if (_destroyed) return 0; @@ -907,7 +907,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const Address & Membership *m = nullptr; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ((*a != source)&&(*a != controller())) { + if ((*a != source->address())&&(*a != controller())) { ZT_GET_NEW_BUF(outp,Protocol::Header); outp->data.fields.packetId = Protocol::getPacketId(); @@ -926,7 +926,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const Address & } } } - } else if ((source == controller())||(!source)) { + } else if ((!source)||(source->address() != this->controller())) { // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers that don't sign chunks and don't // support multiple chunks. Since old controllers don't sign chunks we only accept the message if it comes // directly from the controller. @@ -990,6 +990,9 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD try { if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) return 0; // invalid config that is not for us or not for this network + if ((!Utils::allZero(nconf.issuedToIdentityHash,ZT_IDENTITY_HASH_SIZE))&&(memcmp(nconf.issuedToIdentityHash,RR->identity.hash(),ZT_IDENTITY_HASH_SIZE) != 0)) + return 0; // full identity hash is present and does not match + if (_config == nconf) return 1; // OK config, but duplicate of what we already have diff --git a/node/Network.hpp b/node/Network.hpp index 1e89accd0..47e88fa6b 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -77,7 +77,7 @@ public: ~Network(); ZT_ALWAYS_INLINE uint64_t id() const { return _id; } - ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24); } + ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24U); } ZT_ALWAYS_INLINE bool multicastEnabled() const { return (_config.multicastLimit > 0); } ZT_ALWAYS_INLINE bool hasConfig() const { return (_config); } ZT_ALWAYS_INLINE uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } @@ -190,13 +190,13 @@ public: * * @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 source Peer that actually sent this chunk (probably controller) * @param chunk Buffer containing chunk * @param ptr Index of chunk and related fields in packet (starting with network ID) * @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 Address &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 @@ -403,7 +403,7 @@ private: Mutex _config_l; Mutex _memberships_l; - AtomicCounter __refCount; + AtomicCounter __refCount; }; } // namespace ZeroTier diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index ad4865e36..16ece9d62 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -275,7 +275,8 @@ struct NetworkConfig : TriviallyCopyable /** * Hash of identity public key(s) of node to whom this is issued * - * TODO + * If this field is all zero it is treated as undefined since old controllers + * do not set it. */ uint8_t issuedToIdentityHash[ZT_IDENTITY_HASH_SIZE]; diff --git a/node/Node.hpp b/node/Node.hpp index 01dc5858d..e6d32f60a 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -18,7 +18,6 @@ #include #include -#include #include #include "Constants.hpp" diff --git a/node/Path.hpp b/node/Path.hpp index 851a23991..ffc0f6769 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -47,37 +47,6 @@ class Path friend class Defragmenter; public: - /** - * Efficient unique key for paths in a Hashtable - */ - class HashKey - { - public: - ZT_ALWAYS_INLINE HashKey() {} - ZT_ALWAYS_INLINE HashKey(const int64_t l,const InetAddress &r) - { - 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; - _k[2] = (uint64_t)l; - } else if (r.ss_family == AF_INET6) { - memcpy(_k,reinterpret_cast(&r)->sin6_addr.s6_addr,16); - _k[2] = ((uint64_t)reinterpret_cast(&r)->sin6_port << 32) ^ (uint64_t)l; - } else { - memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress))); - _k[2] += (uint64_t)l; - } - } - - ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); } - - ZT_ALWAYS_INLINE bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); } - ZT_ALWAYS_INLINE bool operator!=(const HashKey &k) const { return (!(*this == k)); } - - private: - uint64_t _k[3]; - }; - ZT_ALWAYS_INLINE Path(const int64_t l,const InetAddress &r) : _localSocket(l), _lastIn(0), diff --git a/node/Protocol.hpp b/node/Protocol.hpp index 3583f2117..32c3f5859 100644 --- a/node/Protocol.hpp +++ b/node/Protocol.hpp @@ -855,6 +855,14 @@ ZT_PACKED_STRUCT(struct EXT_FRAME uint16_t etherType; }); +ZT_PACKED_STRUCT(struct NETWORK_CONFIG +{ + Protocol::Header h; + OK::Header oh; + uint64_t networkId; + uint64_t configUpdateId; +}); + } // namespace OK namespace ERROR { diff --git a/node/SHA512.cpp b/node/SHA512.cpp index 3190cf843..ab5e06532 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -250,9 +250,9 @@ void KBKDFHMACSHA384(const uint8_t key[32],const char label,const char context,c { uint8_t kbkdfMsg[13]; uint8_t kbuf[48]; - kbkdfMsg[0] = (uint8_t)(iter >> 24); - kbkdfMsg[1] = (uint8_t)(iter >> 16); - kbkdfMsg[2] = (uint8_t)(iter >> 8); + kbkdfMsg[0] = (uint8_t)(iter >> 24U); + kbkdfMsg[1] = (uint8_t)(iter >> 16U); + kbkdfMsg[2] = (uint8_t)(iter >> 8U); kbkdfMsg[3] = (uint8_t)iter; kbkdfMsg[4] = (uint8_t)'Z'; kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index f4aeff521..bc372c766 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -80,6 +80,7 @@ private: ZT_ALWAYS_INLINE bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } ZT_ALWAYS_INLINE bool operator!=(const PhySurfaceKey &k) const { return (!(*this == k)); } }; + struct PhySurfaceEntry { InetAddress mySurface; diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index 39f324ee8..db5adbf6d 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -15,6 +15,7 @@ #define ZT_SHAREDPTR_HPP #include "AtomicCounter.hpp" +#include "TriviallyCopyable.hpp" namespace ZeroTier { @@ -26,7 +27,7 @@ namespace ZeroTier { * AtomicCounter called __refCount. */ template -class SharedPtr +class SharedPtr : public TriviallyCopyable { public: ZT_ALWAYS_INLINE SharedPtr() : _ptr((T *)0) {} diff --git a/node/Topology.cpp b/node/Topology.cpp index b69fea236..16aa534be 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -15,6 +15,8 @@ namespace ZeroTier { +const uint64_t Topology::s_pathHashSalt = Utils::getSecureRandomU64(); + // Sorts roots so as to put the lowest latency alive root first. struct _RootSortComparisonOperator { @@ -89,8 +91,8 @@ void Topology::getAllPeers(std::vector< SharedPtr > &allPeers) const allPeers.clear(); allPeers.reserve(_peers.size()); Hashtable< Address,SharedPtr >::Iterator i(*(const_cast > *>(&_peers))); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; + Address *a = nullptr; + SharedPtr *p = nullptr; while (i.next(a,p)) allPeers.push_back(*p); } @@ -189,8 +191,8 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now) { RWMutex::Lock l1(_peers_l); Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; + Address *a = nullptr; + SharedPtr *p = nullptr; while (i.next(a,p)) { if ( (!(*p)->alive(now)) && (_roots.count((*p)->identity()) == 0) ) { (*p)->save(tPtr); @@ -200,9 +202,9 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now) } { RWMutex::Lock l1(_paths_l); - Hashtable< Path::HashKey,SharedPtr >::Iterator i(_paths); - Path::HashKey *k = (Path::HashKey *)0; - SharedPtr *p = (SharedPtr *)0; + Hashtable< uint64_t,SharedPtr >::Iterator i(_paths); + uint64_t *k = nullptr; + SharedPtr *p = nullptr; while (i.next(k,p)) { if (p->references() <= 1) _paths.erase(*k); @@ -214,8 +216,8 @@ void Topology::saveAll(void *tPtr) { RWMutex::RLock l(_peers_l); Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; + Address *a = nullptr; + SharedPtr *p = nullptr; while (i.next(a,p)) { if ( (!(*p)->alive(RR->node->now())) && (_roots.count((*p)->identity()) == 0) ) { (*p)->save((void *)0); diff --git a/node/Topology.hpp b/node/Topology.hpp index 70ffe8519..381f278e8 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -92,7 +92,7 @@ public: */ ZT_ALWAYS_INLINE SharedPtr getPath(const int64_t l,const InetAddress &r) { - const Path::HashKey k(l,r); + const uint64_t k = _pathHash(l,r); _paths_l.rlock(); SharedPtr p(_paths[k]); @@ -205,8 +205,8 @@ public: ZT_ALWAYS_INLINE void eachPath(F f) const { RWMutex::RLock l(_paths_l); - Hashtable< Path::HashKey,SharedPtr >::Iterator i(const_cast(this)->_paths); - Path::HashKey *k = nullptr; + Hashtable< uint64_t,SharedPtr >::Iterator i(const_cast(this)->_paths); + uint64_t *k = nullptr; SharedPtr *p = nullptr; while (i.next(k,p)) { f(*((const SharedPtr *)p)); @@ -310,6 +310,31 @@ public: private: void _loadCached(void *tPtr,const Address &zta,SharedPtr &peer); + // This is a secure random integer created at startup to salt the calculation of path hash map keys + static const uint64_t s_pathHashSalt; + + // Get a hash key for looking up paths by their local port and destination address + ZT_ALWAYS_INLINE uint64_t _pathHash(int64_t l,const InetAddress &r) const + { + if (r.ss_family == AF_INET) { + return Utils::hash64(s_pathHashSalt ^ (uint64_t)(reinterpret_cast(&r)->sin_addr.s_addr)) + (uint64_t)Utils::ntoh(reinterpret_cast(&r)->sin_port) + (uint64_t)l; + } else if (r.ss_family == AF_INET6) { +#ifdef ZT_NO_UNALIGNED_ACCESS + uint64_t h = s_pathHashSalt; + for(int i=0;i<16;++i) { + h += (uint64_t)((reinterpret_cast(&r)->sin6_addr.s6_addr)[i]); + h += (h << 10U); + h ^= (h >> 6U); + } +#else + uint64_t h = Utils::hash64(s_pathHashSalt ^ (reinterpret_cast(reinterpret_cast(&r)->sin6_addr.s6_addr)[0] + reinterpret_cast(reinterpret_cast(&r)->sin6_addr.s6_addr)[1])); +#endif + return h + (uint64_t)Utils::ntoh(reinterpret_cast(&r)->sin6_port) + (uint64_t)l; + } else { + return Utils::hashString(reinterpret_cast(&r),sizeof(InetAddress)) + (uint64_t)l; + } + } + const RuntimeEnvironment *const RR; const Identity _myIdentity; @@ -320,7 +345,7 @@ private: unsigned int _numConfiguredPhysicalPaths; Hashtable< Address,SharedPtr > _peers; - Hashtable< Path::HashKey,SharedPtr > _paths; + Hashtable< uint64_t,SharedPtr > _paths; std::set< Identity > _roots; // locked by _peers_l std::vector< SharedPtr > _rootPeers; // locked by _peers_l }; diff --git a/node/Utils.cpp b/node/Utils.cpp index 92ca9836f..0dcf59f46 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -321,6 +321,13 @@ void getSecureRandom(void *buf,unsigned int bytes) } } +uint64_t getSecureRandomU64() +{ + uint64_t tmp = 0; + getSecureRandom(&tmp,sizeof(tmp)); + return tmp; +} + int b32e(const uint8_t *data,int length,char *result,int bufSize) { if (length < 0 || length > (1 << 28)) { @@ -397,22 +404,15 @@ int b32d(const char *encoded,uint8_t *result,int bufSize) return count; } -static uint64_t _secureRandom64() -{ - uint64_t tmp = 0; - getSecureRandom(&tmp,sizeof(tmp)); - return tmp; -} - #define ROL64(x,k) (((x) << (k)) | ((x) >> (64 - (k)))) uint64_t random() { // https://en.wikipedia.org/wiki/Xorshift#xoshiro256** static Mutex l; - static uint64_t s0 = _secureRandom64(); - static uint64_t s1 = _secureRandom64(); - static uint64_t s2 = _secureRandom64(); - static uint64_t s3 = _secureRandom64(); + static uint64_t s0 = getSecureRandomU64(); + static uint64_t s1 = getSecureRandomU64(); + static uint64_t s2 = getSecureRandomU64(); + static uint64_t s3 = getSecureRandomU64(); l.lock(); const uint64_t result = ROL64(s1 * 5,7) * 9; diff --git a/node/Utils.hpp b/node/Utils.hpp index 5b5a141ef..95ef573cd 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -139,6 +139,11 @@ unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen */ void getSecureRandom(void *buf,unsigned int bytes); +/** + * @return Secure random 64-bit integer + */ +uint64_t getSecureRandomU64(); + /** * Encode string to base32 * @@ -178,6 +183,41 @@ uint64_t random(); */ bool scopy(char *dest,unsigned int len,const char *src); +/** + * Mix bits in a 64-bit integer + * + * https://nullprogram.com/blog/2018/07/31/ + * + * @param x Integer to mix + * @return Hashed value + */ +static ZT_ALWAYS_INLINE uint64_t hash64(uint64_t x) +{ + x ^= x >> 30U; + x *= 0xbf58476d1ce4e5b9ULL; + x ^= x >> 27U; + x *= 0x94d049bb133111ebULL; + x ^= x >> 31U; + return x; +} + +/** + * @param b Buffer to check + * @param l Length of buffer + * @return True if buffer is all zero + */ +static ZT_ALWAYS_INLINE bool allZero(const void *const b,const unsigned int l) +{ + const uint8_t *x = reinterpret_cast(b); + const uint8_t *const y = x + l; + while (x != y) { + if (*x != 0) + return false; + ++x; + } + return true; +} + /** * Wrapper around reentrant strtok functions, which differ in name by platform * diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index 474f6d3b4..6930b68ee 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -57,11 +57,11 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response _ArpEntry *targetEntry = _cache.get(reinterpret_cast(arp)[6]); if ((targetEntry)&&(targetEntry->local)) { memcpy(response,ARP_RESPONSE_HEADER,8); - targetEntry->mac.copyTo(reinterpret_cast(response) + 8,6); + targetEntry->mac.copyTo(reinterpret_cast(response) + 8); memcpy(reinterpret_cast(response) + 14,reinterpret_cast(arp) + 24,4); memcpy(reinterpret_cast(response) + 18,reinterpret_cast(arp) + 8,10); responseLen = 28; - responseDest.setTo(reinterpret_cast(arp) + 8,6); + responseDest.setTo(reinterpret_cast(arp) + 8); } } else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) { // Learn cache entries for remote IPs from relevant ARP replies @@ -70,7 +70,7 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response _ArpEntry *queryEntry = _cache.get(responseIp); if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) { queryEntry->lastResponseReceived = now; - queryEntry->mac.setTo(reinterpret_cast(arp) + 8,6); + queryEntry->mac.setTo(reinterpret_cast(arp) + 8); ip = responseIp; } } @@ -102,7 +102,7 @@ MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *quer uint8_t *q = reinterpret_cast(query); memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same - localMac.copyTo(q,6); q += 6; // sending host MAC address + localMac.copyTo(q); q += 6; // sending host MAC address memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order) memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order) diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 833110ffe..2df7d8ff3 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -14,9 +14,6 @@ #ifndef ZT_MANAGEDROUTE_HPP #define ZT_MANAGEDROUTE_HPP -#include -#include - #include "../node/InetAddress.hpp" #include "../node/Utils.hpp" #include "../node/SharedPtr.hpp" @@ -25,6 +22,8 @@ #include #include #include +#include +#include namespace ZeroTier { @@ -84,7 +83,7 @@ private: char _device[128]; char _systemDevice[128]; // for route overrides - AtomicCounter __refCount; + AtomicCounter __refCount; }; } // namespace ZeroTier