From 5bfa29ddedaa918fb0d5912537391f1ca4b0ba07 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 30 Oct 2015 11:09:40 -0700 Subject: Make antirec tail len slightly shorter, better performance and still plenty long enough. --- node/AntiRecursion.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/AntiRecursion.hpp') diff --git a/node/AntiRecursion.hpp b/node/AntiRecursion.hpp index c5aa92d8..4bb24bf3 100644 --- a/node/AntiRecursion.hpp +++ b/node/AntiRecursion.hpp @@ -35,7 +35,7 @@ namespace ZeroTier { -#define ZT_ANTIRECURSION_TAIL_LEN 256 +#define ZT_ANTIRECURSION_TAIL_LEN 128 /** * Filter to prevent recursion (ZeroTier-over-ZeroTier) -- cgit v1.2.3 From b6725c44150af306130d38a2875ab31a640607c8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 30 Oct 2015 11:48:33 -0700 Subject: Optimize AntiRecursion. --- node/AntiRecursion.hpp | 66 ++++++++++++++++++++++++++++++++------------------ node/Constants.hpp | 5 ---- 2 files changed, 42 insertions(+), 29 deletions(-) (limited to 'node/AntiRecursion.hpp') diff --git a/node/AntiRecursion.hpp b/node/AntiRecursion.hpp index 4bb24bf3..8629d19a 100644 --- a/node/AntiRecursion.hpp +++ b/node/AntiRecursion.hpp @@ -35,28 +35,28 @@ namespace ZeroTier { -#define ZT_ANTIRECURSION_TAIL_LEN 128 +/** + * Size of anti-recursion history + */ +#define ZT_ANTIRECURSION_HISTORY_SIZE 16 /** * Filter to prevent recursion (ZeroTier-over-ZeroTier) * * This works by logging ZeroTier packets that we send. It's then invoked - * again against packets read from local Ethernet taps. If the last N + * again against packets read from local Ethernet taps. If the last 32 * bytes representing the ZeroTier packet match in the tap frame, then * the frame is a re-injection of a frame that we sent and is rejected. * * This means that ZeroTier packets simply will not traverse ZeroTier * networks, which would cause all sorts of weird problems. * - * NOTE: this is applied to low-level packets before they are sent to - * SocketManager and/or sockets, not to fully assembled packets before - * (possible) fragmentation. + * This is highly optimized code since it's checked for every packet. */ class AntiRecursion { public: AntiRecursion() - throw() { memset(_history,0,sizeof(_history)); _ptr = 0; @@ -68,13 +68,20 @@ public: * @param data ZT packet data * @param len Length of packet */ - inline void logOutgoingZT(const void *data,unsigned int len) - throw() + inline void logOutgoingZT(const void *const data,const unsigned int len) { - ArItem *i = &(_history[_ptr++ % ZT_ANTIRECURSION_HISTORY_SIZE]); - const unsigned int tl = (len > ZT_ANTIRECURSION_TAIL_LEN) ? ZT_ANTIRECURSION_TAIL_LEN : len; - memcpy(i->tail,((const unsigned char *)data) + (len - tl),tl); - i->len = tl; + if (len < 32) + return; +#ifdef ZT_NO_TYPE_PUNNING + memcpy(_history[++_ptr % ZT_ANTIRECURSION_HISTORY_SIZE].tail,reinterpret_cast(data) + (len - 32),32); +#else + uint64_t *t = _history[++_ptr % ZT_ANTIRECURSION_HISTORY_SIZE].tail; + const uint64_t *p = reinterpret_cast(reinterpret_cast(data) + (len - 32)); + *(t++) = *(p++); + *(t++) = *(p++); + *(t++) = *(p++); + *t = *p; +#endif } /** @@ -84,25 +91,36 @@ public: * @param len Length of frame * @return True if frame is OK to be passed, false if it's a ZT frame that we sent */ - inline bool checkEthernetFrame(const void *data,unsigned int len) - throw() + inline bool checkEthernetFrame(const void *const data,const unsigned int len) const { - for(unsigned int h=0;hlen > 0)&&(len >= i->len)&&(!memcmp(((const unsigned char *)data) + (len - i->len),i->tail,i->len))) + if (len < 32) + return true; + const uint8_t *const pp = reinterpret_cast(data) + (len - 32); + const _ArItem *i = _history; + const _ArItem *const end = i + ZT_ANTIRECURSION_HISTORY_SIZE; + while (i != end) { +#ifdef ZT_NO_TYPE_PUNNING + if (!memcmp(pp,i->tail,32)) return false; +#else + const uint64_t *t = i->tail; + const uint64_t *p = reinterpret_cast(pp); + uint64_t bits = *(t++) ^ *(p++); + bits |= *(t++) ^ *(p++); + bits |= *(t++) ^ *(p++); + bits |= *t ^ *p; + if (!bits) + return false; +#endif + ++i; } return true; } private: - struct ArItem - { - unsigned char tail[ZT_ANTIRECURSION_TAIL_LEN]; - unsigned int len; - }; - ArItem _history[ZT_ANTIRECURSION_HISTORY_SIZE]; - volatile unsigned int _ptr; + struct _ArItem { uint64_t tail[4]; }; + _ArItem _history[ZT_ANTIRECURSION_HISTORY_SIZE]; + volatile unsigned long _ptr; }; } // namespace ZeroTier diff --git a/node/Constants.hpp b/node/Constants.hpp index 5a4d4a4d..1d5fa6f4 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -309,11 +309,6 @@ */ #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000 -/** - * Size of anti-recursion history (see AntiRecursion.hpp) - */ -#define ZT_ANTIRECURSION_HISTORY_SIZE 16 - /** * Minimum delay between attempts to confirm new paths to peers (to avoid HELLO flooding) */ -- cgit v1.2.3 From 0d9f33dc4f14b7339d1893e79772a8e49b4821eb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 13 Nov 2015 12:14:28 -0800 Subject: Fix: (1) Windows stack overflow due to buffer too large in peer deserialize, (2) clean up some other stuff seen during debugging and reduce the sizes of some buffers due to Windows small stack size, (3) remove a redundant try/catch. --- node/AntiRecursion.hpp | 7 ++- node/Cluster.cpp | 4 +- node/Identity.cpp | 2 +- node/Node.cpp | 33 +++++++------- node/Topology.cpp | 31 +++++-------- node/Topology.hpp | 16 ++++++- one.cpp | 60 +++++++++++-------------- osdep/OSUtils.cpp | 2 +- osdep/WindowsEthernetTap.cpp | 20 ++++----- selftest.cpp | 3 +- windows/ZeroTierOne/ZeroTierOne.vcxproj | 13 +++--- windows/ZeroTierOne/ZeroTierOne.vcxproj.filters | 9 ++-- 12 files changed, 103 insertions(+), 97 deletions(-) (limited to 'node/AntiRecursion.hpp') diff --git a/node/AntiRecursion.hpp b/node/AntiRecursion.hpp index 8629d19a..4d9df465 100644 --- a/node/AntiRecursion.hpp +++ b/node/AntiRecursion.hpp @@ -58,7 +58,12 @@ class AntiRecursion public: AntiRecursion() { - memset(_history,0,sizeof(_history)); + for(int i=0;itopology->countActive()); + alive.append((uint64_t)RR->topology->countActive(now)); alive.append((uint64_t)0); // unused/reserved flags alive.append((uint8_t)_zeroTierPhysicalEndpoints.size()); for(std::vector::const_iterator pe(_zeroTierPhysicalEndpoints.begin());pe!=_zeroTierPhysicalEndpoints.end();++pe) @@ -769,7 +769,7 @@ void Cluster::status(ZT_ClusterStatus &status) const s->y = _y; s->z = _z; s->load = 0; // TODO - s->peers = RR->topology->countActive(); + s->peers = RR->topology->countActive(now); for(std::vector::const_iterator ep(_zeroTierPhysicalEndpoints.begin());ep!=_zeroTierPhysicalEndpoints.end();++ep) { if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check break; diff --git a/node/Identity.cpp b/node/Identity.cpp index e5aaf13d..4611f6a5 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -158,7 +158,7 @@ bool Identity::fromString(const char *str) return false; char *saveptr = (char *)0; - char tmp[4096]; + char tmp[1024]; if (!Utils::scopy(tmp,sizeof(tmp),str)) return false; diff --git a/node/Node.cpp b/node/Node.cpp index 4b449401..f077424b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -93,21 +93,22 @@ Node::Node( _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); } - std::string idtmp(dataStoreGet("identity.secret")); - if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { - TRACE("identity.secret not found, generating..."); - RR->identity.generate(); - idtmp = RR->identity.toString(true); - if (!dataStorePut("identity.secret",idtmp,true)) - throw std::runtime_error("unable to write identity.secret"); - } - RR->publicIdentityStr = RR->identity.toString(false); - RR->secretIdentityStr = RR->identity.toString(true); - - idtmp = dataStoreGet("identity.public"); - if (idtmp != RR->publicIdentityStr) { - if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) - throw std::runtime_error("unable to write identity.public"); + { + std::string idtmp(dataStoreGet("identity.secret")); + if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { + TRACE("identity.secret not found, generating..."); + RR->identity.generate(); + idtmp = RR->identity.toString(true); + if (!dataStorePut("identity.secret",idtmp,true)) + throw std::runtime_error("unable to write identity.secret"); + } + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + idtmp = dataStoreGet("identity.public"); + if (idtmp != RR->publicIdentityStr) { + if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) + throw std::runtime_error("unable to write identity.public"); + } } try { @@ -662,7 +663,7 @@ void Node::backgroundThreadMain() std::string Node::dataStoreGet(const char *name) { - char buf[16384]; + char buf[1024]; std::string r; unsigned long olen = 0; do { diff --git a/node/Topology.cpp b/node/Topology.cpp index 5379ac1f..1617dd94 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -50,6 +50,7 @@ Topology::Topology(const RuntimeEnvironment *renv) : const uint8_t *all = reinterpret_cast(alls.data()); RR->node->dataStoreDelete("peers.save"); + Buffer *deserializeBuf = new Buffer(); unsigned int ptr = 0; while ((ptr + 4) < alls.size()) { try { @@ -60,7 +61,8 @@ Topology::Topology(const RuntimeEnvironment *renv) : (((unsigned int)all[ptr + 3]) & 0xff) ); unsigned int pos = 0; - SharedPtr p(Peer::deserializeNew(RR->identity,Buffer(all + ptr,reclen + 4),pos)); + deserializeBuf->copyFrom(all + ptr,reclen + 4); + SharedPtr p(Peer::deserializeNew(RR->identity,*deserializeBuf,pos)); ptr += pos; if (!p) break; // stop if invalid records @@ -70,16 +72,19 @@ Topology::Topology(const RuntimeEnvironment *renv) : break; // stop if invalid records } } + delete deserializeBuf; clean(RR->node->now()); std::string dsWorld(RR->node->dataStoreGet("world")); World cachedWorld; - try { - Buffer dswtmp(dsWorld.data(),(unsigned int)dsWorld.length()); - cachedWorld.deserialize(dswtmp,0); - } catch ( ... ) { - cachedWorld = World(); // clear if cached world is invalid + if (dsWorld.length() > 0) { + try { + Buffer dswtmp(dsWorld.data(),(unsigned int)dsWorld.length()); + cachedWorld.deserialize(dswtmp,0); + } catch ( ... ) { + cachedWorld = World(); // clear if cached world is invalid + } } World defaultWorld; { @@ -315,20 +320,6 @@ void Topology::clean(uint64_t now) } } -unsigned long Topology::countActive() const -{ - const uint64_t now = RR->node->now(); - unsigned long cnt = 0; - Mutex::Lock _l(_lock); - Hashtable< Address,SharedPtr >::Iterator i(const_cast(this)->_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - cnt += (unsigned long)((*p)->hasActiveDirectPath(now)); - } - return cnt; -} - Identity Topology::_getIdentity(const Address &zta) { char p[128]; diff --git a/node/Topology.hpp b/node/Topology.hpp index 68ad273f..a9a5f2f9 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -200,9 +200,21 @@ public: void clean(uint64_t now); /** + * @param now Current time * @return Number of peers with active direct paths */ - unsigned long countActive() const; + inline unsigned long countActive(uint64_t now) const + { + unsigned long cnt = 0; + Mutex::Lock _l(_lock); + Hashtable< Address,SharedPtr >::Iterator i(const_cast(this)->_peers); + Address *a = (Address *)0; + SharedPtr *p = (SharedPtr *)0; + while (i.next(a,p)) { + cnt += (unsigned long)((*p)->hasActiveDirectPath(now)); + } + return cnt; + } /** * Apply a function or function object to all peers @@ -253,7 +265,7 @@ private: Identity _getIdentity(const Address &zta); void _setWorld(const World &newWorld); - const RuntimeEnvironment *RR; + const RuntimeEnvironment *const RR; World _world; Hashtable< Address,SharedPtr > _peers; diff --git a/one.cpp b/one.cpp index c8661fda..11bcc11e 100644 --- a/one.cpp +++ b/one.cpp @@ -958,13 +958,15 @@ int main(int argc,char **argv) #endif // __UNIX_LIKE__ #ifdef __WINDOWS__ - WSADATA wsaData; - WSAStartup(MAKEWORD(2,2),&wsaData); + { + WSADATA wsaData; + WSAStartup(MAKEWORD(2,2),&wsaData); + } #ifdef ZT_WIN_RUN_IN_CONSOLE bool winRunFromCommandLine = true; #else - bool winRunFromCommandLine = false; + bool winRunFromCommandLine = true; #endif #endif // __WINDOWS__ @@ -1153,37 +1155,29 @@ int main(int argc,char **argv) unsigned int returnValue = 0; - try { - for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port); - switch(zt1Service->run()) { - case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done - case OneService::ONE_NORMAL_TERMINATION: - break; - case OneService::ONE_UNRECOVERABLE_ERROR: - fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str()); - returnValue = 1; - break; - case OneService::ONE_IDENTITY_COLLISION: { - delete zt1Service; - zt1Service = (OneService *)0; - std::string oldid; - OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); - if (oldid.length()) { - OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); - OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); - OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); - } - } continue; // restart! - } - break; // terminate loop -- normally we don't keep restarting + for(;;) { + zt1Service = OneService::newInstance(homeDir.c_str(),port); + switch(zt1Service->run()) { + case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done + case OneService::ONE_NORMAL_TERMINATION: + break; + case OneService::ONE_UNRECOVERABLE_ERROR: + fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str()); + returnValue = 1; + break; + case OneService::ONE_IDENTITY_COLLISION: { + delete zt1Service; + zt1Service = (OneService *)0; + std::string oldid; + OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); + if (oldid.length()) { + OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); + OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); + OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); + } + } continue; // restart! } - } catch (std::exception &exc) { - fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],exc.what()); - returnValue = 1; - } catch ( ... ) { - fprintf(stderr,"%s: fatal error: unknown exception"ZT_EOL_S,argv[0]); - returnValue = 1; + break; // terminate loop -- normally we don't keep restarting } delete zt1Service; diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 45fbf100..728704e5 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -206,7 +206,7 @@ skip_add_inetaddr: bool OSUtils::readFile(const char *path,std::string &buf) { - char tmp[4096]; + char tmp[1024]; FILE *f = fopen(path,"rb"); if (f) { for(;;) { diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index f327009d..5b2bc154 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -213,7 +213,7 @@ std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf, Mutex::Lock _l(_systemDeviceManagementLock); GUID classGuid; - char className[4096]; + char className[1024]; if (!WINENV.SetupDiGetINFClassA(pathToInf,&classGuid,className,sizeof(className),(PDWORD)0)) { return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file"); } @@ -269,9 +269,9 @@ std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf, std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices() { - char subkeyName[4096]; - char subkeyClass[4096]; - char data[4096]; + char subkeyName[1024]; + char subkeyClass[1024]; + char data[1024]; std::set instanceIdPathsToRemove; { @@ -321,9 +321,9 @@ std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices() std::string WindowsEthernetTap::destroyAllPersistentTapDevices() { - char subkeyName[4096]; - char subkeyClass[4096]; - char data[4096]; + char subkeyName[1024]; + char subkeyClass[1024]; + char data[1024]; std::set instanceIdPathsToRemove; { @@ -479,9 +479,9 @@ WindowsEthernetTap::WindowsEthernetTap( _initialized(false), _enabled(true) { - char subkeyName[4096]; - char subkeyClass[4096]; - char data[4096]; + char subkeyName[1024]; + char subkeyClass[1024]; + char data[1024]; char tag[24]; std::string mySubkeyName; diff --git a/selftest.cpp b/selftest.cpp index fa8df48b..87043ddd 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -860,8 +860,9 @@ struct TestPhyHandlers inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} - inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} #endif // __UNIX_LIKE__ + + inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} }; static int testPhy() { diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index c3163608..82b70400 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -24,6 +24,7 @@ + @@ -44,18 +45,14 @@ - + + false + - - true - true - true - true - @@ -123,6 +120,7 @@ + @@ -232,6 +230,7 @@ NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions) + false true diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index b9e00b37..5a2767e4 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -96,9 +96,6 @@ Source Files\osdep - - Source Files - Source Files\node @@ -192,6 +189,9 @@ Source Files\node + + Source Files\node + @@ -419,6 +419,9 @@ Header Files\node + + Header Files\node + -- cgit v1.2.3