diff --git a/one.cpp b/one.cpp index 8d4b8fc5b..0a945b337 100644 --- a/one.cpp +++ b/one.cpp @@ -607,6 +607,43 @@ static int cli(int argc,char **argv) cliPrintHelp(argv[0],stderr); return 2; } + } else if (command == "get") { + if (arg1.length() != 16) { + cliPrintHelp(argv[0],stderr); + return 2; + } + char jsons[1024], cl[128]; + OSUtils::ztsnprintf(cl,sizeof(cl),"%u",(unsigned int)strlen(jsons)); + requestHeaders["Content-Type"] = "application/json"; + requestHeaders["Content-Length"] = cl; + const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody); + + nlohmann::json j; + try { + j = OSUtils::jsonParse(responseBody); + } catch (std::exception &exc) { + printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); + return 1; + } catch ( ... ) { + printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); + return 1; + } + if (j.is_array()) { + for(unsigned long i=0;i localIfAddrs; PhySocket *udps,*tcps; Mutex::Lock _l(_lock); + bool interfacesEnumerated = true; #ifdef __WINDOWS__ @@ -167,6 +168,9 @@ public: a = a->Next; } } + else { + interfacesEnumerated = false; + } #else // not __WINDOWS__ @@ -195,6 +199,9 @@ public: } fclose(procf); } + else { + interfacesEnumerated = false; + } // Get IPv6 addresses (and any device names we don't already know) OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); @@ -314,12 +321,15 @@ public: } freeifaddrs(ifatbl); } + else { + interfacesEnumerated = false; + } } #endif // Default to binding to wildcard if we can't enumerate addresses - if (localIfAddrs.empty()) { + if (!interfacesEnumerated && localIfAddrs.empty()) { for(int x=0;x<(int)portCount;++x) { localIfAddrs.insert(std::pair(InetAddress((uint32_t)0,ports[x]),std::string())); localIfAddrs.insert(std::pair(InetAddress((const void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,ports[x]),std::string())); diff --git a/service/OneService.cpp b/service/OneService.cpp index 2e9c530d5..487ff4d0f 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -398,6 +398,7 @@ public: PhySocket *_localControlSocket4; PhySocket *_localControlSocket6; bool _updateAutoApply; + bool _allowTcpFallbackRelay; unsigned int _primaryPort; volatile unsigned int _udpPortPickerCounter; @@ -1125,6 +1126,7 @@ public: } json &settings = res["config"]["settings"]; settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; + settings["allowTcpFallbackRelay"] = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],_allowTcpFallbackRelay); #ifdef ZT_USE_MINIUPNPC settings["portMappingEnabled"] = OSUtils::jsonBool(settings["portMappingEnabled"],true); #else @@ -1452,6 +1454,7 @@ public: json &settings = lc["settings"]; _primaryPort = (unsigned int)OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; + _allowTcpFallbackRelay = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],true); _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true); #ifndef ZT_SDK @@ -2161,63 +2164,66 @@ public: inline int nodeWirePacketSendFunction(const int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { #ifdef ZT_TCP_FALLBACK_RELAY - if (addr->ss_family == AF_INET) { - // TCP fallback tunnel support, currently IPv4 only - if ((len >= 16)&&(reinterpret_cast(addr)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - // Engage TCP tunnel fallback if we haven't received anything valid from a global - // 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 (_tcpFallbackTunnel) { - bool flushNow = false; - { - Mutex::Lock _l(_tcpFallbackTunnel->writeq_m); - if (_tcpFallbackTunnel->writeq.size() < (1024 * 64)) { - if (_tcpFallbackTunnel->writeq.length() == 0) { - _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); - flushNow = true; + if(_allowTcpFallbackRelay) { + if (addr->ss_family == AF_INET) { + // TCP fallback tunnel support, currently IPv4 only + if ((len >= 16)&&(reinterpret_cast(addr)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { + // Engage TCP tunnel fallback if we haven't received anything valid from a global + // 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 (_tcpFallbackTunnel) { + bool flushNow = false; + { + Mutex::Lock _l(_tcpFallbackTunnel->writeq_m); + if (_tcpFallbackTunnel->writeq.size() < (1024 * 64)) { + if (_tcpFallbackTunnel->writeq.length() == 0) { + _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); + flushNow = true; + } + const unsigned long mlen = len + 7; + _tcpFallbackTunnel->writeq.push_back((char)0x17); + _tcpFallbackTunnel->writeq.push_back((char)0x03); + _tcpFallbackTunnel->writeq.push_back((char)0x03); // fake TLS 1.2 header + _tcpFallbackTunnel->writeq.push_back((char)((mlen >> 8) & 0xff)); + _tcpFallbackTunnel->writeq.push_back((char)(mlen & 0xff)); + _tcpFallbackTunnel->writeq.push_back((char)4); // IPv4 + _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))),4); + _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))),2); + _tcpFallbackTunnel->writeq.append((const char *)data,len); } - const unsigned long mlen = len + 7; - _tcpFallbackTunnel->writeq.push_back((char)0x17); - _tcpFallbackTunnel->writeq.push_back((char)0x03); - _tcpFallbackTunnel->writeq.push_back((char)0x03); // fake TLS 1.2 header - _tcpFallbackTunnel->writeq.push_back((char)((mlen >> 8) & 0xff)); - _tcpFallbackTunnel->writeq.push_back((char)(mlen & 0xff)); - _tcpFallbackTunnel->writeq.push_back((char)4); // IPv4 - _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))),4); - _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))),2); - _tcpFallbackTunnel->writeq.append((const char *)data,len); } + if (flushNow) { + void *tmpptr = (void *)_tcpFallbackTunnel; + phyOnTcpWritable(_tcpFallbackTunnel->sock,&tmpptr); + } + } else if (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2))) { + const InetAddress addr(ZT_TCP_FALLBACK_RELAY); + TcpConnection *tc = new TcpConnection(); + { + Mutex::Lock _l(_tcpConnections_m); + _tcpConnections.push_back(tc); + } + tc->type = TcpConnection::TCP_TUNNEL_OUTGOING; + tc->remoteAddr = addr; + tc->lastReceive = OSUtils::now(); + tc->parent = this; + tc->sock = (PhySocket *)0; // set in connect handler + tc->messageSize = 0; + bool connected = false; + _phy.tcpConnect(reinterpret_cast(&addr),connected,(void *)tc,true); } - if (flushNow) { - void *tmpptr = (void *)_tcpFallbackTunnel; - phyOnTcpWritable(_tcpFallbackTunnel->sock,&tmpptr); - } - } else if (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2))) { - const InetAddress addr(ZT_TCP_FALLBACK_RELAY); - TcpConnection *tc = new TcpConnection(); - { - Mutex::Lock _l(_tcpConnections_m); - _tcpConnections.push_back(tc); - } - tc->type = TcpConnection::TCP_TUNNEL_OUTGOING; - tc->remoteAddr = addr; - tc->lastReceive = OSUtils::now(); - tc->parent = this; - tc->sock = (PhySocket *)0; // set in connect handler - tc->messageSize = 0; - bool connected = false; - _phy.tcpConnect(reinterpret_cast(&addr),connected,(void *)tc,true); } + _lastSendToGlobalV4 = now; } - _lastSendToGlobalV4 = now; } } +#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. -#endif // ZT_TCP_FALLBACK_RELAY 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); @@ -2286,7 +2292,6 @@ public: return 0; } } - return 1; }