diff --git a/README.md b/README.md index 327ca8f71..abe494b6c 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Access control is via the ZeroTier control interface itself and `metricstoken.se curl -H "X-ZT1-Auth: $(sudo cat /var/lib/zerotier-one/metricstoken.secret)" http://localhost:9993/metrics // macOS - curl -H "X-XT1-Auth: $(sudo cat /Library/Application\ Support/ZeroTier/One/metricstoken.secret)" http://localhost:9993/metrics + curl -H "X-ZT1-Auth: $(sudo cat /Library/Application\ Support/ZeroTier/One/metricstoken.secret)" http://localhost:9993/metrics // Windows PowerShell (Admin) Invoke-RestMethod -Headers @{'X-ZT1-Auth' = "$(Get-Content C:\ProgramData\ZeroTier\One\metricstoken.secret)"; } -Uri http://localhost:9993/metrics diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 86f3f1e8c..b94557e67 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,6 +1,11 @@ ZeroTier Release Notes ====== +# 2023-09-12 -- Version 1.12.2 + + * More improvements to macOS full tunnel mode. + * Faster recovery after changes to physical network settings. + # 2023-08-25 -- Version 1.12.1 * Minor release to fix a port binding issue in Linux. diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index ac1947ce4..a01b68a9d 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -867,12 +867,33 @@ void EmbeddedNetworkController::configureHTTPControlPlane( const std::function setContent) { // Control plane Endpoints + std::string controllerPath = "/controller"; std::string networkListPath = "/controller/network"; std::string networkPath = "/controller/network/([0-9a-fA-F]{16})"; std::string oldAndBustedNetworkCreatePath = "/controller/network/([0-9a-fA-F]{10})______"; std::string memberListPath = "/controller/network/([0-9a-fA-F]{16})/member"; std::string memberPath = "/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})"; + auto controllerGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { + char tmp[4096]; + const bool dbOk = _db.isReady(); + OSUtils::ztsnprintf( + tmp, + sizeof(tmp), + "{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"databaseReady\": %s\n}\n", + ZT_NETCONF_CONTROLLER_API_VERSION, + (unsigned long long)OSUtils::now(), + dbOk ? "true" : "false"); + + if (!dbOk) { + res.status = 503; + } + + setContent(req, res, tmp); + }; + s.Get(controllerPath, controllerGet); + sv6.Get(controllerPath, controllerGet); + auto networkListGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { std::set networkIds; _db.networks(networkIds); @@ -997,16 +1018,14 @@ void EmbeddedNetworkController::configureHTTPControlPlane( return; } - json out = json::array(); + json out = json::object(); std::vector memTmp; if (_db.get(nwid, network, memTmp)) { for (auto m = memTmp.begin(); m != memTmp.end(); ++m) { int revision = OSUtils::jsonInt((*m)["revision"], 0); std::string id = OSUtils::jsonString((*m)["id"], ""); if (id.length() == 10) { - json tmp = json::object(); - tmp[id] = revision; - out.push_back(tmp); + out[id] = revision; } } } diff --git a/debian/changelog b/debian/changelog index 0ba464399..6f9357610 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +zerotier-one (1.12.2) unstable; urgency=medium + + * See RELEASE-NOTES.md for release notes. + + -- Adam Ierymenko Tue, 12 Sep 2023 01:00:00 -0700 + zerotier-one (1.12.1) unstable; urgency=medium * See RELEASE-NOTES.md for release notes. diff --git a/ext/installfiles/mac/ZeroTier One.pkgproj b/ext/installfiles/mac/ZeroTier One.pkgproj index 67a4fd452..b4ac69c2b 100755 --- a/ext/installfiles/mac/ZeroTier One.pkgproj +++ b/ext/installfiles/mac/ZeroTier One.pkgproj @@ -701,7 +701,7 @@ USE_HFS+_COMPRESSION VERSION - 1.12.1 + 1.12.2 TYPE 0 diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index cd016670a..71e89975d 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -24,10 +24,10 @@ - + - + @@ -62,7 +62,7 @@ - + @@ -352,8 +352,8 @@ - - + + @@ -368,17 +368,17 @@ - - - - + + + + @@ -498,7 +498,7 @@ - + diff --git a/node/Switch.cpp b/node/Switch.cpp index 5cbbeff85..5ea1653c2 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -509,7 +509,17 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const adv[42] = (checksum >> 8) & 0xff; adv[43] = checksum & 0xff; - RR->node->putFrame(tPtr,network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); + // + // call on separate background thread + // this prevents problems related to trying to do rx while inside of doing tx, such as acquiring same lock recursively + // + + std::thread([=]() { + + RR->node->putFrame(tPtr, network->id(), network->userPtr(), peerMac, from, ZT_ETHERTYPE_IPV6, 0, adv, 72); + + }).detach(); + return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query. } // else no NDP emulation } // else no NDP emulation @@ -546,8 +556,18 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const data, len); } else if (to == network->mac()) { + // Destination is this node, so just reinject it - RR->node->putFrame(tPtr,network->id(),network->userPtr(),from,to,etherType,vlanId,data,len); + + // + // same pattern as putFrame call above + // + std::thread([=]() { + + RR->node->putFrame(tPtr, network->id(), network->userPtr(), from, to, etherType, vlanId, data, len); + + }).detach(); + } else if (to[0] == MAC::firstOctetForNetwork(network->id())) { // Destination is another ZeroTier peer on the same network diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index a06ba11a3..d51e548bb 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -484,58 +484,57 @@ bool ManagedRoute::sync() if (!hasRoute) { - if (_target && _target.netmaskBits() == 0) { + if (_target && _target.netmaskBits() == 0) { // Allow Default InetAddress newSystemVia; char newSystemDevice[128]; newSystemDevice[0] = (char)0; - // If macos has a network hiccup, it deletes what _systemVia we had set. - // Then we don't know how to set the default route again. - // So use the one we had set previously. Don't overwrite it. - if (!_systemVia) { - // Find system default route that this route should override - // We need to put it back when default route is turned off - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if (r->via) { - if ( !_systemVia && r->isDefault == 1 && (strcmp(r->device,_device) != 0) ) { - - newSystemVia = r->via; - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - } - } - } - if (newSystemVia) { _systemVia = newSystemVia; } + // if our routes got deleted + // delete the systemd via that we had added with -ifscope + if (_systemVia && !!_systemDevice[0]) { + _routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0); } + _systemVia = newSystemVia; + Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); + // If macos has a network hiccup, it deletes what the route we set, and it's own physical routes. + // if !hasRoute (our 0.0.0.0 has been deleted), the OS has changed stuff + // So don't assume _systemX are valid anymore. Always get for _system{Via,Device} - // char buf1[255], buf2[255]; - // fprintf(stderr, "_systemVia %s new %s\n", _systemVia.toString(buf1), newSystemVia.toString(buf2)); - if (!_systemVia) { return false; } + // Find system default route that this route should override + // We need to put it back when default route is turned off + for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { + if (r->via) { + if ( r->isDefault == 1 && (strcmp(r->device,_device) != 0) ) { - if (!_systemDevice[0]) { - // Get device corresponding to route if we don't have that already - if ((newSystemVia)&&(!newSystemDevice[0])) { - rtes = _getRTEs(newSystemVia,true); - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if ( (r->device[0]) && (strcmp(r->device,_device) != 0) && r->target.netmaskBits() != 0) { - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - break; - } + // char buf[255]; + // fprintf(stderr, "system device1 %s %s\n", r->via.toString(buf), r->device); + + newSystemVia = r->via; + Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); + break; } } + } - if (newSystemDevice[0]) { - Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); - } + if (newSystemVia) { _systemVia = newSystemVia; } + if (newSystemDevice[0]) { + Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); } - // fprintf(stderr, "_systemDevice %s new %s\n", _systemDevice, newSystemDevice); - if (!_systemDevice[0]) { return false; } + // if there's no newSystemVia, the OS might not have + // ipv4 or ipv6 connectivity. + // we should still add our ZeroTier ipv4 or 6 routes though + + if (!!_systemVia && !!_systemDevice[0]) { + _routeCmd("delete",_target,_systemVia,(const char *)0,(const char *)0); + } - // Do Default Route route commands - _routeCmd("delete",_target,_systemVia,(const char *)0,(const char *)0); _routeCmd("add",_target,_via,(const char *)0,(const char *)0); - _routeCmd("add",_target,_systemVia,_systemDevice,(const char *)0); + + if (!!_systemVia && !!_systemDevice[0]) { + _routeCmd("add",_target,_systemVia,_systemDevice,(const char *)0); + } _applied[_target] = true; @@ -595,8 +594,8 @@ void ManagedRoute::remove() for(std::map::iterator r(_applied.begin());r!=_applied.end();++r) { #ifdef __BSD__ // ------------------------------------------------------------ if (_target && _target.netmaskBits() == 0) { - if (_systemVia) { - _routeCmd("delete",_target,_via,(const char *)0,(const char *)0); + _routeCmd("delete",_target,_via,(const char *)0,(const char *)0); + if (_systemVia && _systemDevice[0]) { _routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0); _routeCmd("add",_target,_systemVia,(const char *)0,(const char *)0); diff --git a/service/OneService.cpp b/service/OneService.cpp index dfa5df056..8a0aee294 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1067,7 +1067,7 @@ class OneServiceImpl : public OneService if (_secondaryPort) { _ports[1] = _secondaryPort; } else { - _ports[1] = _secondaryPort = _getRandomPort(); + _ports[1] = _getRandomPort(); } } #ifdef ZT_USE_MINIUPNPC @@ -1129,7 +1129,6 @@ class OneServiceImpl : public OneService int64_t lastBindRefresh = 0; int64_t lastUpdateCheck = clockShouldBe; int64_t lastCleanedPeersDb = 0; - int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle int64_t lastLocalConfFileCheck = OSUtils::now(); int64_t lastOnline = lastLocalConfFileCheck; for(;;) { @@ -1176,16 +1175,22 @@ class OneServiceImpl : public OneService // If secondary port is not configured to a constant value and we've been offline for a while, // bind a new secondary port. This is a workaround for a "coma" issue caused by buggy NATs that stop // working on one port after a while. - if (_node->online()) { - lastOnline = now; - } else if ((_secondaryPort == 0)&&((now - lastOnline) > ZT_PATH_HEARTBEAT_PERIOD)) { - _secondaryPort = _getRandomPort(); - lastBindRefresh = 0; + if (_secondaryPort == 0) { + if (_node->online()) { + lastOnline = now; + } + if ((now - lastOnline) > ZT_PATH_HEARTBEAT_PERIOD || restarted) { + _ports[1] = _getRandomPort(); +#if ZT_DEBUG==1 + fprintf(stderr, "randomized secondary port. Now it's %d\n", _ports[1]); +#endif + lastOnline = now; // don't keep spamming this branch. online() will be false for a few seconds + } } + // Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default) - if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD))||(restarted)) { - lastBindRefresh = now; + if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD))||restarted) { unsigned int p[3]; unsigned int pc = 0; for(int i=0;i<3;++i) { @@ -1196,6 +1201,23 @@ class OneServiceImpl : public OneService // Only bother binding UDP ports if we aren't forcing TCP-relay mode _binder.refresh(_phy,p,pc,explicitBind,*this); } + + lastBindRefresh = now; + + // Sync information about physical network interfaces + _node->clearLocalInterfaceAddresses(); +#ifdef ZT_USE_MINIUPNPC + if (_portMapper) { + std::vector mappedAddresses(_portMapper->get()); + for(std::vector::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); + } +#endif + std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); + for(std::vector::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) { + _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); + } + { Mutex::Lock _l(_nets_m); for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) { @@ -1239,26 +1261,6 @@ class OneServiceImpl : public OneService } } - // Sync information about physical network interfaces - if ((now - lastLocalInterfaceAddressCheck) >= (_node->bondController()->inUse() ? ZT_LOCAL_INTERFACE_CHECK_INTERVAL / 8 : ZT_LOCAL_INTERFACE_CHECK_INTERVAL)) { - lastLocalInterfaceAddressCheck = now; - - _node->clearLocalInterfaceAddresses(); - -#ifdef ZT_USE_MINIUPNPC - if (_portMapper) { - std::vector mappedAddresses(_portMapper->get()); - for(std::vector::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); - } -#endif - - std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); - for(std::vector::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) { - _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); - } - } - // Clean peers.d periodically if ((now - lastCleanedPeersDb) >= 3600000) { lastCleanedPeersDb = now; @@ -2037,7 +2039,7 @@ class OneServiceImpl : public OneService settings["allowTcpFallbackRelay"] = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],_allowTcpFallbackRelay); settings["forceTcpRelay"] = OSUtils::jsonBool(settings["forceTcpRelay"],_forceTcpRelay); settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; - settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"],(uint64_t)_secondaryPort) & 0xffff; + settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"],(uint64_t)_ports[1]) & 0xffff; settings["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"],(uint64_t)_tertiaryPort) & 0xffff; // Enumerate all local address/port pairs that this node is listening on std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); diff --git a/version.h b/version.h index 8c3a6c879..fa6f0402d 100644 --- a/version.h +++ b/version.h @@ -27,7 +27,7 @@ /** * Revision */ -#define ZEROTIER_ONE_VERSION_REVISION 1 +#define ZEROTIER_ONE_VERSION_REVISION 2 /** * Build version diff --git a/zerotier-one.spec b/zerotier-one.spec index a6ae2faf7..87329705c 100644 --- a/zerotier-one.spec +++ b/zerotier-one.spec @@ -1,5 +1,5 @@ Name: zerotier-one -Version: 1.12.1 +Version: 1.12.2 Release: 1%{?dist} Summary: ZeroTier network virtualization service @@ -143,6 +143,9 @@ chmod 0755 $RPM_BUILD_ROOT/etc/init.d/zerotier-one %endif %changelog +* Tue Sep 12 2023 Adam Ierymenko - 1.12.2 +- see https://github.com/zerotier/ZeroTierOne for release notes + * Fri Aug 25 2023 Adam Ierymenko - 1.12.1 - see https://github.com/zerotier/ZeroTierOne for release notes