diff --git a/one.cpp b/one.cpp index 62710547c..3b158cc14 100644 --- a/one.cpp +++ b/one.cpp @@ -449,12 +449,16 @@ static int cli(int argc,char **argv) if (json) { printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); } else { - printf("200 peers\n " ZT_EOL_S); + bool anyTunneled = false; + printf("200 peers\n " ZT_EOL_S); if (j.is_array()) { for(unsigned long k=0;k &bond) +static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer, SharedPtr &bond, bool isTunneled) { char tmp[256]; @@ -542,6 +542,7 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer, SharedPtr pj["latency"] = peer->latency; pj["role"] = prole; pj["isBonded"] = peer->isBonded; + pj["tunneled"] = isTunneled; if (bond && peer->isBonded) { pj["bondingPolicyCode"] = peer->bondingPolicy; pj["bondingPolicyStr"] = Bond::getPolicyStrByCode(peer->bondingPolicy); @@ -714,6 +715,7 @@ public: PhySocket *_localControlSocket6; bool _updateAutoApply; bool _allowTcpFallbackRelay; + bool _forceTcpRelay; bool _allowSecondaryPort; unsigned int _primaryPort; @@ -812,6 +814,7 @@ public: ,_localControlSocket4((PhySocket *)0) ,_localControlSocket6((PhySocket *)0) ,_updateAutoApply(false) + ,_forceTcpRelay(false) ,_primaryPort(port) ,_udpPortPickerCounter(0) ,_lastDirectReceiveFromGlobal(0) @@ -1093,7 +1096,10 @@ public: if (_ports[i]) p[pc++] = _ports[i]; } - _binder.refresh(_phy,p,pc,explicitBind,*this); + if (!_forceTcpRelay) { + // Only bother binding UDP ports if we aren't forcing TCP-relay mode + _binder.refresh(_phy,p,pc,explicitBind,*this); + } { Mutex::Lock _l(_nets_m); for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) { @@ -1111,8 +1117,9 @@ public: } // Close TCP fallback tunnel if we have direct UDP - if ((_tcpFallbackTunnel)&&((now - _lastDirectReceiveFromGlobal) < (ZT_TCP_FALLBACK_AFTER / 2))) + if (!_forceTcpRelay && (_tcpFallbackTunnel) && ((now - _lastDirectReceiveFromGlobal) < (ZT_TCP_FALLBACK_AFTER / 2))) { _phy.close(_tcpFallbackTunnel->sock); + } // Sync multicast group memberships if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) { @@ -1488,7 +1495,7 @@ public: if (ps[1] == "show") { SharedPtr bond = _node->bondController()->getBondByPeerId(wantp); if (bond) { - _peerToJson(res,&(pl->peers[i]),bond); + _peerToJson(res,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0)); scode = 200; } else { scode = 400; @@ -1530,6 +1537,7 @@ public: } json &settings = res["config"]["settings"]; 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["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"],(uint64_t)_tertiaryPort) & 0xffff; @@ -1634,7 +1642,7 @@ public: const uint64_t id = pl->peers[i].address; bond = _node->bondController()->getBondByPeerId(id); } - _peerToJson(pj,&(pl->peers[i]),bond); + _peerToJson(pj,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0)); res.push_back(pj); } @@ -1649,7 +1657,7 @@ public: if (pl->peers[i].isBonded) { bond = _node->bondController()->getBondByPeerId(wantp); } - _peerToJson(res,&(pl->peers[i]),bond); + _peerToJson(res,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0)); scode = 200; break; } @@ -2118,6 +2126,8 @@ public: // bondingPolicy cannot be used with allowTcpFallbackRelay _allowTcpFallbackRelay = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],true); + _forceTcpRelay = OSUtils::jsonBool(settings["forceTcpRelay"],false); + #ifdef ZT_TCP_FALLBACK_RELAY _fallbackRelayAddress = InetAddress(OSUtils::jsonString(settings["tcpFallbackRelay"], ZT_TCP_FALLBACK_RELAY).c_str()); #endif @@ -2404,6 +2414,9 @@ public: inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) { + if (_forceTcpRelay) { + return; + } const uint64_t now = OSUtils::now(); if ((len >= 16)&&(reinterpret_cast(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) _lastDirectReceiveFromGlobal = now; @@ -3112,7 +3125,7 @@ public: // IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting // valid direct traffic we'll stop using it and close the socket after a while. const int64_t now = OSUtils::now(); - if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { + if (_forceTcpRelay || (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER))) { if (_tcpFallbackTunnel) { bool flushNow = false; { @@ -3138,7 +3151,7 @@ public: void *tmpptr = (void *)_tcpFallbackTunnel; phyOnTcpWritable(_tcpFallbackTunnel->sock,&tmpptr); } - } else if (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2))) { + } else if (_forceTcpRelay || (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2)))) { const InetAddress addr(_fallbackRelayAddress); TcpConnection *tc = new TcpConnection(); { @@ -3159,12 +3172,15 @@ public: } } } + if (_forceTcpRelay) { + // Shortcut here so that we don't emit any UDP packets + return 0; + } #endif // ZT_TCP_FALLBACK_RELAY // Even when relaying we still send via UDP. This way if UDP starts // working we can instantly "fail forward" to it and stop using TCP // proxy fallback, which is slow. - if ((localSocket != -1)&&(localSocket != 0)&&(_binder.isUdpSocketValid((PhySocket *)((uintptr_t)localSocket)))) { if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),ttl); const bool r = _phy.udpSend((PhySocket *)((uintptr_t)localSocket),(const struct sockaddr *)addr,data,len);