diff --git a/node/Node.cpp b/node/Node.cpp index 8d041a4b0..496f49ec2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -447,7 +447,7 @@ Node::ReasonForTermination Node::run() _r->sw = new Switch(_r); _r->demarc = new Demarc(_r); _r->topology = new Topology(_r,Utils::fileExists((_r->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str())); - _r->sysEnv = new SysEnv(_r); + _r->sysEnv = new SysEnv(); try { _r->nc = new NodeConfig(_r,configAuthToken.c_str(),impl->controlPort); } catch (std::exception &exc) { @@ -513,7 +513,7 @@ Node::ReasonForTermination Node::run() uint64_t lastPingCheck = 0; uint64_t lastClean = Utils::now(); // don't need to do this immediately uint64_t lastNetworkFingerprintCheck = 0; - uint64_t networkConfigurationFingerprint = _r->sysEnv->getNetworkConfigurationFingerprint(); + uint64_t networkConfigurationFingerprint = _r->sysEnv->getNetworkConfigurationFingerprint(_r->nc->networkTapDeviceNames()); uint64_t lastMulticastCheck = 0; long lastDelayDelta = 0; @@ -538,7 +538,7 @@ Node::ReasonForTermination Node::run() // If our network environment looks like it changed, also set resynchronize flag. if ((resynchronize)||((now - lastNetworkFingerprintCheck) >= ZT_NETWORK_FINGERPRINT_CHECK_DELAY)) { lastNetworkFingerprintCheck = now; - uint64_t fp = _r->sysEnv->getNetworkConfigurationFingerprint(); + uint64_t fp = _r->sysEnv->getNetworkConfigurationFingerprint(_r->nc->networkTapDeviceNames()); if (fp != networkConfigurationFingerprint) { LOG("netconf fingerprint change: %.16llx != %.16llx, resyncing with network",networkConfigurationFingerprint,fp); networkConfigurationFingerprint = fp; diff --git a/node/SysEnv.cpp b/node/SysEnv.cpp index 3fb2c8722..e88e2bbb5 100644 --- a/node/SysEnv.cpp +++ b/node/SysEnv.cpp @@ -62,8 +62,7 @@ namespace ZeroTier { -SysEnv::SysEnv(const RuntimeEnvironment *renv) : - _r(renv) +SysEnv::SysEnv() { } @@ -73,7 +72,7 @@ SysEnv::~SysEnv() #ifdef __APPLE__ -uint64_t SysEnv::getNetworkConfigurationFingerprint() +uint64_t SysEnv::getNetworkConfigurationFingerprint(const std::set &ignoreDevices) { int mib[6]; size_t needed; @@ -82,7 +81,8 @@ uint64_t SysEnv::getNetworkConfigurationFingerprint() // Right now this just scans for changes in default routes. This is not // totally robust -- it will miss cases where we switch from one 10.0.0.0/24 // network with gateway .1 to another -- but most of the time it'll pick - // up shifts in connectivity. + // up shifts in connectivity. Combined with sleep/wake detection this seems + // pretty solid so far on Mac for detecting when you change locations. mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -139,15 +139,13 @@ uint64_t SysEnv::getNetworkConfigurationFingerprint() #if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) -uint64_t SysEnv::getNetworkConfigurationFingerprint() +uint64_t SysEnv::getNetworkConfigurationFingerprint(const std::set &ignoreDevices) { char buf[16384]; uint64_t fingerprint = 5381; // djb2 hash algorithm is used below char *t1,*t2; try { - std::set tapDevs(_r->nc->networkTapDeviceNames()); - // Include default IPv4 route if available int fd = open("/proc/net/route",O_RDONLY); if (fd > 0) { @@ -159,7 +157,7 @@ uint64_t SysEnv::getNetworkConfigurationFingerprint() int fno = 0; for(char *field=strtok_r(line," \t",&t2);(field);field=strtok_r((char *)0," \t",&t2)) { if (fno == 0) { // device name - if ((tapDevs.count(std::string(field)))||(!strcmp(field,"lo"))) + if ((ignoreDevices.count(std::string(field)))||(!strcmp(field,"lo"))) break; } else if ((fno == 1)||(fno == 2)) { // destination, gateway if (strlen(field) == 8) { // ignore header junk, use only hex route info @@ -198,7 +196,7 @@ uint64_t SysEnv::getNetworkConfigurationFingerprint() } if ((v6ip)&&(devname)) { - if ((!(tapDevs.count(std::string(devname))))&&(strcmp(devname,"lo"))) { + if ((!(ignoreDevices.count(std::string(devname))))&&(strcmp(devname,"lo"))) { while (*v6ip) fingerprint = ((fingerprint << 5) + fingerprint) + (uint64_t)*(v6ip++); } @@ -215,7 +213,7 @@ uint64_t SysEnv::getNetworkConfigurationFingerprint() #ifdef __WINDOWS__ -uint64_t SysEnv::getNetworkConfigurationFingerprint() +uint64_t SysEnv::getNetworkConfigurationFingerprint(const std::set &ignoreDevices) { // TODO: windows version return 1; diff --git a/node/SysEnv.hpp b/node/SysEnv.hpp index 4f4a4f168..d5797c16a 100644 --- a/node/SysEnv.hpp +++ b/node/SysEnv.hpp @@ -30,6 +30,8 @@ #include +#include + #include "NonCopyable.hpp" namespace ZeroTier { @@ -42,16 +44,16 @@ class RuntimeEnvironment; class SysEnv : NonCopyable { public: - SysEnv(const RuntimeEnvironment *renv); + SysEnv(); ~SysEnv(); /** + * This computes a CRC-type code from gathered information about your network settings + * + * @param ignoreDevices Ignore these local network devices by OS-specific name (e.g. our taps) * @return Fingerprint of currently running network environment */ - uint64_t getNetworkConfigurationFingerprint(); - -private: - const RuntimeEnvironment *_r; + uint64_t getNetworkConfigurationFingerprint(const std::set &ignoreDevices); }; } // namespace ZeroTier