diff options
Diffstat (limited to 'service/OneService.cpp')
| -rw-r--r-- | service/OneService.cpp | 639 |
1 files changed, 349 insertions, 290 deletions
diff --git a/service/OneService.cpp b/service/OneService.cpp index 593f58aa..01828ffe 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -46,6 +46,7 @@ #include "../osdep/Http.hpp" #include "../osdep/BackgroundResolver.hpp" #include "../osdep/PortMapper.hpp" +#include "../osdep/Binder.hpp" #include "OneService.hpp" #include "ControlPlane.hpp" @@ -114,8 +115,9 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } #define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 64) #define ZT_MAX_HTTP_CONNECTIONS 64 -// Interface metric for ZeroTier taps -#define ZT_IF_METRIC 32768 +// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also +// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi. +#define ZT_IF_METRIC 5000 // How often to check for new multicast subscriptions on a tap device #define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000 @@ -134,7 +136,7 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } #define ZT_TCP_FALLBACK_AFTER 60000 // How often to check for local interface addresses -#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 300000 +#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 namespace ZeroTier { @@ -149,6 +151,7 @@ public: bool isValidSigningIdentity(const Identity &id) { return ( + /* 0001 - 0004 : obsolete, used in old versions */ /* 0005 */ (id == Identity("ba57ea350e:0:9d4be6d7f86c5660d5ee1951a3d759aa6e12a84fc0c0b74639500f1dbc1a8c566622e7d1c531967ebceb1e9d1761342f88324a8ba520c93c35f92f35080fa23f")) /* 0006 */ ||(id == Identity("5067b21b83:0:8af477730f5055c48135b84bed6720a35bca4c0e34be4060a4c636288b1ec22217eb22709d610c66ed464c643130c51411bbb0294eef12fbe8ecc1a1e2c63a7a")) /* 0007 */ ||(id == Identity("4f5e97a8f1:0:57880d056d7baeb04bbc057d6f16e6cb41388570e87f01492fce882485f65a798648595610a3ad49885604e7fb1db2dd3c2c534b75e42c3c0b110ad07b4bb138")) @@ -444,18 +447,90 @@ struct TcpConnection Mutex writeBuf_m; }; -// Use a bigger buffer on AMD64 since these are likely to be bigger and -// servers. Otherwise use a smaller buffer. This makes no difference -// except under very high load. -#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__)) -#define ZT_UDP_DESIRED_BUF_SIZE 1048576 -#else -#define ZT_UDP_DESIRED_BUF_SIZE 131072 -#endif +// Used to pseudo-randomize local source port picking +static volatile unsigned int _udpPortPickerCounter = 0; class OneServiceImpl : public OneService { public: + // begin member variables -------------------------------------------------- + + const std::string _homePath; + BackgroundResolver _tcpFallbackResolver; +#ifdef ZT_ENABLE_NETWORK_CONTROLLER + SqliteNetworkController *_controller; +#endif + Phy<OneServiceImpl *> _phy; + Node *_node; + + /* + * To properly handle NAT/gateway craziness we use three local UDP ports: + * + * [0] is the normal/default port, usually 9993 + * [1] is a port dervied from our ZeroTier address + * [2] is a port computed from the normal/default for use with uPnP/NAT-PMP mappings + * + * [2] exists because on some gateways trying to do regular NAT-t interferes + * destructively with uPnP port mapping behavior in very weird buggy ways. + * It's only used if uPnP/NAT-PMP is enabled in this build. + */ + + Binder _bindings[3]; + unsigned int _ports[3]; + uint16_t _portsBE[3]; // ports in big-endian network byte order as in sockaddr + + // Sockets for JSON API -- bound only to V4 and V6 localhost + PhySocket *_v4TcpControlSocket; + PhySocket *_v6TcpControlSocket; + + // JSON API handler + ControlPlane *_controlPlane; + + // Time we last received a packet from a global address + uint64_t _lastDirectReceiveFromGlobal; +#ifdef ZT_TCP_FALLBACK_RELAY + uint64_t _lastSendToGlobalV4; +#endif + + // Last potential sleep/wake event + uint64_t _lastRestart; + + // Deadline for the next background task service function + volatile uint64_t _nextBackgroundTaskDeadline; + + // Tap devices by network ID + std::map< uint64_t,EthernetTap * > _taps; + std::map< uint64_t,std::vector<InetAddress> > _tapAssignedIps; // ZeroTier assigned IPs, not user or dhcp assigned + Mutex _taps_m; + + // Active TCP/IP connections + std::set< TcpConnection * > _tcpConnections; // no mutex for this since it's done in the main loop thread only + TcpConnection *_tcpFallbackTunnel; + + // Termination status information + ReasonForTermination _termReason; + std::string _fatalErrorMessage; + Mutex _termReason_m; + + // uPnP/NAT-PMP port mapper if enabled +#ifdef ZT_USE_MINIUPNPC + PortMapper *_portMapper; +#endif + + // Cluster management instance if enabled +#ifdef ZT_ENABLE_CLUSTER + PhySocket *_clusterMessageSocket; + ClusterGeoIpService *_clusterGeoIpService; + ClusterDefinition *_clusterDefinition; + unsigned int _clusterMemberId; +#endif + + // Set to false to force service to stop + volatile bool _run; + Mutex _run_m; + + // end member variables ---------------------------------------------------- + OneServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : ".") ,_tcpFallbackResolver(ZT_TCP_FALLBACK_RELAY) @@ -466,14 +541,14 @@ public: ,_node((Node *)0) ,_controlPlane((ControlPlane *)0) ,_lastDirectReceiveFromGlobal(0) - ,_lastSendToGlobal(0) +#ifdef ZT_TCP_FALLBACK_RELAY + ,_lastSendToGlobalV4(0) +#endif ,_lastRestart(0) ,_nextBackgroundTaskDeadline(0) ,_tcpFallbackTunnel((TcpConnection *)0) ,_termReason(ONE_STILL_RUNNING) - ,_port(0) #ifdef ZT_USE_MINIUPNPC - ,_v4UpnpUdpSocket((PhySocket *)0) ,_portMapper((PortMapper *)0) #endif #ifdef ZT_ENABLE_CLUSTER @@ -484,65 +559,74 @@ public: #endif ,_run(true) { + _ports[0] = 0; + _ports[1] = 0; + _ports[2] = 0; + + // The control socket is bound to the default/static port on localhost. If we + // can do this, we have successfully allocated a port. The binders will take + // care of binding non-local addresses for ZeroTier traffic. const int portTrials = (port == 0) ? 256 : 1; // if port is 0, pick random for(int k=0;k<portTrials;++k) { if (port == 0) { unsigned int randp = 0; Utils::getSecureRandom(&randp,sizeof(randp)); - port = 40000 + (randp % 25500); + port = 20000 + (randp % 45500); } - _v4LocalAddress = InetAddress((uint32_t)0,port); - _v4UdpSocket = _phy.udpBind((const struct sockaddr *)&_v4LocalAddress,reinterpret_cast<void *>(&_v4LocalAddress),ZT_UDP_DESIRED_BUF_SIZE); - - if (_v4UdpSocket) { + if (_trialBind(port)) { struct sockaddr_in in4; memset(&in4,0,sizeof(in4)); in4.sin_family = AF_INET; - in4.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); // right now we just listen for TCP @localhost + in4.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); // right now we just listen for TCP @127.0.0.1 in4.sin_port = Utils::hton((uint16_t)port); - _v4TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in4,this); - - if (_v4TcpListenSocket) { - _v6LocalAddress = InetAddress("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,port); - _v6UdpSocket = _phy.udpBind((const struct sockaddr *)&_v6LocalAddress,reinterpret_cast<void *>(&_v6LocalAddress),ZT_UDP_DESIRED_BUF_SIZE); - - struct sockaddr_in6 in6; - memset((void *)&in6,0,sizeof(in6)); - in6.sin6_family = AF_INET6; - in6.sin6_port = in4.sin_port; - in6.sin6_addr.s6_addr[15] = 1; // IPv6 localhost == ::1 - _v6TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in6,this); - - _port = port; - break; // success! + _v4TcpControlSocket = _phy.tcpListen((const struct sockaddr *)&in4,this); + + struct sockaddr_in6 in6; + memset((void *)&in6,0,sizeof(in6)); + in6.sin6_family = AF_INET6; + in6.sin6_port = in4.sin_port; + in6.sin6_addr.s6_addr[15] = 1; // IPv6 localhost == ::1 + _v6TcpControlSocket = _phy.tcpListen((const struct sockaddr *)&in6,this); + + // We must bind one of IPv4 or IPv6 -- support either failing to support hosts that + // have only IPv4 or only IPv6 stacks. + if ((_v4TcpControlSocket)||(_v6TcpControlSocket)) { + _ports[0] = port; + break; } else { - _phy.close(_v4UdpSocket,false); + if (_v4TcpControlSocket) + _phy.close(_v4TcpControlSocket,false); + if (_v6TcpControlSocket) + _phy.close(_v6TcpControlSocket,false); + port = 0; } + } else { + port = 0; } - - port = 0; } - if (_port == 0) - throw std::runtime_error("cannot bind to port"); + if (_ports[0] == 0) + throw std::runtime_error("cannot bind to local control interface port"); char portstr[64]; - Utils::snprintf(portstr,sizeof(portstr),"%u",_port); + Utils::snprintf(portstr,sizeof(portstr),"%u",_ports[0]); OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr)); } virtual ~OneServiceImpl() { - _phy.close(_v4UdpSocket); - _phy.close(_v6UdpSocket); - _phy.close(_v4TcpListenSocket); - _phy.close(_v6TcpListenSocket); + for(int i=0;i<3;++i) + _bindings[i].closeAll(_phy); + + _phy.close(_v4TcpControlSocket); + _phy.close(_v6TcpControlSocket); + #ifdef ZT_ENABLE_CLUSTER _phy.close(_clusterMessageSocket); #endif + #ifdef ZT_USE_MINIUPNPC - _phy.close(_v4UpnpUdpSocket); delete _portMapper; #endif #ifdef ZT_ENABLE_NETWORK_CONTROLLER @@ -571,7 +655,9 @@ public: _termReason = ONE_UNRECOVERABLE_ERROR; _fatalErrorMessage = "authtoken.secret could not be written"; return _termReason; - } else OSUtils::lockDownFile(authTokenPath.c_str(),false); + } else { + OSUtils::lockDownFile(authTokenPath.c_str(),false); + } } } authToken = _trimString(authToken); @@ -587,24 +673,49 @@ public: SnodePathCheckFunction, SnodeEventCallback); -#ifdef ZT_USE_MINIUPNPC - // Bind a secondary port for use with uPnP, since some NAT routers - // (cough Ubiquity Edge cough) barf up a lung if you do both conventional - // NAT-t and uPnP from behind the same port. I think this is a bug, but - // everyone else's router bugs are our problem. :P - for(int k=0;k<512;++k) { - unsigned int mapperPort = 40000 + (((_port + 1) * (k + 1)) % 25500); - char uniqueName[64]; - _v4UpnpLocalAddress = InetAddress(0,mapperPort); - _v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&_v4UpnpLocalAddress,reinterpret_cast<void *>(&_v4UpnpLocalAddress),ZT_UDP_DESIRED_BUF_SIZE); - if (_v4UpnpUdpSocket) { - Utils::snprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.10llx",_node->address()); - _portMapper = new PortMapper(mapperPort,uniqueName); + // Attempt to bind to a secondary port chosen from our ZeroTier address. + // This exists because there are buggy NATs out there that fail if more + // than one device behind the same NAT tries to use the same internal + // private address port number. + _ports[1] = 20000 + ((unsigned int)_node->address() % 45500); + for(int i=0;;++i) { + if (i > 1000) { + _ports[1] = 0; break; + } else if (++_ports[1] >= 65536) { + _ports[1] = 20000; + } + if (_trialBind(_ports[1])) + break; + } + +#ifdef ZT_USE_MINIUPNPC + // If we're running uPnP/NAT-PMP, bind a *third* port for that. We can't + // use the other two ports for that because some NATs do really funky + // stuff with ports that are explicitly mapped that breaks things. + if (_ports[1]) { + _ports[2] = _ports[1]; + for(int i=0;;++i) { + if (i > 1000) { + _ports[2] = 0; + break; + } else if (++_ports[2] >= 65536) { + _ports[2] = 20000; + } + if (_trialBind(_ports[2])) + break; + } + if (_ports[2]) { + char uniqueName[64]; + Utils::snprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.10llx@%u",_node->address(),_ports[2]); + _portMapper = new PortMapper(_ports[2],uniqueName); } } #endif + for(int i=0;i<3;++i) + _portsBE[i] = Utils::hton((uint16_t)_ports[i]); + #ifdef ZT_ENABLE_NETWORK_CONTROLLER _controller = new SqliteNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str(),(_homePath + ZT_PATH_SEPARATOR_S + "circuitTestResults.d").c_str()); _node->setNetconfMaster((void *)_controller); @@ -699,6 +810,7 @@ public: _lastRestart = clockShouldBe; uint64_t lastTapMulticastGroupCheck = 0; uint64_t lastTcpFallbackResolve = 0; + uint64_t lastBindRefresh = 0; uint64_t lastLocalInterfaceAddressCheck = (OSUtils::now() - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle #ifdef ZT_AUTO_UPDATE uint64_t lastSoftwareUpdateCheck = 0; @@ -711,9 +823,28 @@ public: _termReason = ONE_NORMAL_TERMINATION; _termReason_m.unlock(); break; - } else _run_m.unlock(); + } else { + _run_m.unlock(); + } + + const uint64_t now = OSUtils::now(); - uint64_t now = OSUtils::now(); + // Attempt to detect sleep/wake events by detecting delay overruns + bool restarted = false; + if ((now > clockShouldBe)&&((now - clockShouldBe) > 10000)) { + _lastRestart = now; + restarted = true; + } + + // Refresh bindings in case device's interfaces have changed + if (((now - lastBindRefresh) >= ZT_BINDER_REFRESH_PERIOD)||(restarted)) { + lastBindRefresh = now; + for(int i=0;i<3;++i) { + if (_ports[i]) { + _bindings[i].refresh(_phy,_ports[i],*this); + } + } + } uint64_t dl = _nextBackgroundTaskDeadline; if (dl <= now) { @@ -721,10 +852,6 @@ public: dl = _nextBackgroundTaskDeadline; } - // Attempt to detect sleep/wake events by detecting delay overruns - if ((now > clockShouldBe)&&((now - clockShouldBe) > 2000)) - _lastRestart = now; - #ifdef ZT_AUTO_UPDATE if ((now - lastSoftwareUpdateCheck) >= ZT_AUTO_UPDATE_CHECK_PERIOD) { lastSoftwareUpdateCheck = now; @@ -756,76 +883,19 @@ public: if ((now - lastLocalInterfaceAddressCheck) >= ZT_LOCAL_INTERFACE_CHECK_INTERVAL) { lastLocalInterfaceAddressCheck = now; - _node->clearLocalInterfaceAddresses(); -#ifdef ZT_USE_MINIUPNPC - std::vector<InetAddress> mappedAddresses(_portMapper->get()); - for(std::vector<InetAddress>::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext))); -#endif + _node->clearLocalInterfaceAddresses(); -#ifdef __UNIX_LIKE__ - std::vector<std::string> ztDevices; - { - Mutex::Lock _l(_taps_m); - for(std::map< uint64_t,EthernetTap *>::const_iterator t(_taps.begin());t!=_taps.end();++t) - ztDevices.push_back(t->second->deviceName()); - } - struct ifaddrs *ifatbl = (struct ifaddrs *)0; - if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) { - struct ifaddrs *ifa = ifatbl; - while (ifa) { - if ((ifa->ifa_name)&&(ifa->ifa_addr)&&(!isBlacklistedLocalInterfaceForZeroTierTraffic(ifa->ifa_name))) { - bool isZT = false; - for(std::vector<std::string>::const_iterator d(ztDevices.begin());d!=ztDevices.end();++d) { - if (*d == ifa->ifa_name) { - isZT = true; - break; - } - } - if (!isZT) { - InetAddress ip(ifa->ifa_addr); - ip.setPort(_port); - _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip)); - } - } - ifa = ifa->ifa_next; - } - freeifaddrs(ifatbl); +#ifdef ZT_USE_MINIUPNPC + if (_portMapper) { + std::vector<InetAddress> mappedAddresses(_portMapper->get()); + for(std::vector<InetAddress>::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) + _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext))); } -#endif // __UNIX_LIKE__ +#endif -#ifdef __WINDOWS__ - std::vector<NET_LUID> ztDevices; - { - Mutex::Lock _l(_taps_m); - for(std::map< uint64_t,EthernetTap *>::const_iterator t(_taps.begin());t!=_taps.end();++t) - ztDevices.push_back(t->second->luid()); - } - char aabuf[16384]; - ULONG aalen = sizeof(aabuf); - if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf),&aalen) == NO_ERROR) { - PIP_ADAPTER_ADDRESSES a = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf); - while (a) { - bool isZT = false; - for(std::vector<NET_LUID>::const_iterator d(ztDevices.begin());d!=ztDevices.end();++d) { - if (a->Luid.Value == d->Value) { - isZT = true; - break; - } - } - if (!isZT) { - PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress; - while (ua) { - InetAddress ip(ua->Address.lpSockaddr); - ip.setPort(_port); - _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip)); - ua = ua->Next; - } - } - a = a->Next; - } - } -#endif // __WINDOWS__ + std::vector<InetAddress> boundAddrs(_bindings[0].allBoundLocalInterfaceAddresses()); + for(std::vector<InetAddress>::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) + _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*i))); } const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100; @@ -898,7 +968,7 @@ public: // Begin private implementation methods - inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) + inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) { #ifdef ZT_ENABLE_CLUSTER if (sock == _clusterMessageSocket) { @@ -915,9 +985,10 @@ public: if ((len >= 16)&&(reinterpret_cast<const InetAddress *>(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) _lastDirectReceiveFromGlobal = OSUtils::now(); - ZT_ResultCode rc = _node->processWirePacket( + + const ZT_ResultCode rc = _node->processWirePacket( OSUtils::now(), - reinterpret_cast<const struct sockaddr_storage *>(*uptr), + reinterpret_cast<const struct sockaddr_storage *>(localAddr), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big data, len, @@ -970,28 +1041,32 @@ public: inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) { - // Incoming TCP connections are HTTP JSON API requests. - - TcpConnection *tc = new TcpConnection(); - _tcpConnections.insert(tc); - - tc->type = TcpConnection::TCP_HTTP_INCOMING; - tc->shouldKeepAlive = true; - tc->parent = this; - tc->sock = sockN; - tc->from = from; - http_parser_init(&(tc->parser),HTTP_REQUEST); - tc->parser.data = (void *)tc; - tc->messageSize = 0; - tc->lastActivity = OSUtils::now(); - tc->currentHeaderField = ""; - tc->currentHeaderValue = ""; - tc->url = ""; - tc->status = ""; - tc->headers.clear(); - tc->body = ""; - tc->writeBuf = ""; - *uptrN = (void *)tc; + if ((!from)||(reinterpret_cast<const InetAddress *>(from)->ipScope() != InetAddress::IP_SCOPE_LOOPBACK)) { + // Non-Loopback: deny (for now) + _phy.close(sockN,false); + return; + } else { + // Loopback == HTTP JSON API request + TcpConnection *tc = new TcpConnection(); + _tcpConnections.insert(tc); + tc->type = TcpConnection::TCP_HTTP_INCOMING; + tc->shouldKeepAlive = true; + tc->parent = this; + tc->sock = sockN; + tc->from = from; + http_parser_init(&(tc->parser),HTTP_REQUEST); + tc->parser.data = (void *)tc; + tc->messageSize = 0; + tc->lastActivity = OSUtils::now(); + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + tc->url = ""; + tc->status = ""; + tc->headers.clear(); + tc->body = ""; + tc->writeBuf = ""; + *uptrN = (void *)tc; + } } inline void phyOnTcpClose(PhySocket *sock,void **uptr) @@ -1064,9 +1139,10 @@ public: } if (from) { - ZT_ResultCode rc = _node->processWirePacket( + InetAddress fakeTcpLocalInterfaceAddress((uint32_t)0xffffffff,0xffff); + const ZT_ResultCode rc = _node->processWirePacket( OSUtils::now(), - &ZT_SOCKADDR_NULL, + reinterpret_cast<struct sockaddr_storage *>(&fakeTcpLocalInterfaceAddress), reinterpret_cast<struct sockaddr_storage *>(&from), data, plen, @@ -1281,103 +1357,79 @@ public: inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { -#ifdef ZT_USE_MINIUPNPC - if ((localAddr->ss_family == AF_INET)&&(reinterpret_cast<const struct sockaddr_in *>(localAddr)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&_v4UpnpLocalAddress)->sin_port)) { -#ifdef ZT_BREAK_UDP - if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) { -#endif - if (addr->ss_family == AF_INET) { - if (ttl) - _phy.setIp4UdpTtl(_v4UpnpUdpSocket,ttl); - const int result = ((_phy.udpSend(_v4UpnpUdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1); - if (ttl) - _phy.setIp4UdpTtl(_v4UpnpUdpSocket,255); - return result; - } else { - return -1; - } -#ifdef ZT_BREAK_UDP + unsigned int fromBindingNo = 0; + + if (addr->ss_family == AF_INET) { + if (reinterpret_cast<const struct sockaddr_in *>(localAddr)->sin_port == 0) { + // If sender is sending from wildcard (null address), choose the secondary backup + // port 1/4 of the time. (but only for IPv4) + fromBindingNo = (++_udpPortPickerCounter & 0x4) >> 2; + if (!_ports[fromBindingNo]) + fromBindingNo = 0; + } else { + const uint16_t lp = reinterpret_cast<const struct sockaddr_in *>(localAddr)->sin_port; + if (lp == _portsBE[1]) + fromBindingNo = 1; + else if (lp == _portsBE[2]) + fromBindingNo = 2; } -#endif - } -#endif // ZT_USE_MINIUPNPC - - int result = -1; - switch(addr->ss_family) { - case AF_INET: -#ifdef ZT_BREAK_UDP - if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) { -#endif - if (_v4UdpSocket) { - if (ttl) - _phy.setIp4UdpTtl(_v4UdpSocket,ttl); - result = ((_phy.udpSend(_v4UdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1); - if (ttl) - _phy.setIp4UdpTtl(_v4UdpSocket,255); - } -#ifdef ZT_BREAK_UDP - } -#endif #ifdef ZT_TCP_FALLBACK_RELAY - // TCP fallback tunnel support - if ((len >= 16)&&(reinterpret_cast<const InetAddress *>(addr)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - uint64_t now = OSUtils::now(); - - // 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. - if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { - if (_tcpFallbackTunnel) { - Mutex::Lock _l(_tcpFallbackTunnel->writeBuf_m); - if (!_tcpFallbackTunnel->writeBuf.length()) - _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); - unsigned long mlen = len + 7; - _tcpFallbackTunnel->writeBuf.push_back((char)0x17); - _tcpFallbackTunnel->writeBuf.push_back((char)0x03); - _tcpFallbackTunnel->writeBuf.push_back((char)0x03); // fake TLS 1.2 header - _tcpFallbackTunnel->writeBuf.push_back((char)((mlen >> 8) & 0xff)); - _tcpFallbackTunnel->writeBuf.push_back((char)(mlen & 0xff)); - _tcpFallbackTunnel->writeBuf.push_back((char)4); // IPv4 - _tcpFallbackTunnel->writeBuf.append(reinterpret_cast<const char *>(reinterpret_cast<const void *>(&(reinterpret_cast<const struct sockaddr_in *>(addr)->sin_addr.s_addr))),4); - _tcpFallbackTunnel->writeBuf.append(reinterpret_cast<const char *>(reinterpret_cast<const void *>(&(reinterpret_cast<const struct sockaddr_in *>(addr)->sin_port))),2); - _tcpFallbackTunnel->writeBuf.append((const char *)data,len); - result = 0; - } else if (((now - _lastSendToGlobal) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobal) > (ZT_PING_CHECK_INVERVAL / 2))) { - std::vector<InetAddress> tunnelIps(_tcpFallbackResolver.get()); - if (tunnelIps.empty()) { - if (!_tcpFallbackResolver.running()) - _tcpFallbackResolver.resolveNow(); - } else { - bool connected = false; - InetAddress addr(tunnelIps[(unsigned long)now % tunnelIps.size()]); - addr.setPort(ZT_TCP_FALLBACK_RELAY_PORT); - _phy.tcpConnect(reinterpret_cast<const struct sockaddr *>(&addr),connected); - } + // TCP fallback tunnel support, currently IPv4 only + if ((len >= 16)&&(reinterpret_cast<const InetAddress *>(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 uint64_t now = OSUtils::now(); + if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { + if (_tcpFallbackTunnel) { + Mutex::Lock _l(_tcpFallbackTunnel->writeBuf_m); + if (!_tcpFallbackTunnel->writeBuf.length()) + _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); + unsigned long mlen = len + 7; + _tcpFallbackTunnel->writeBuf.push_back((char)0x17); + _tcpFallbackTunnel->writeBuf.push_back((char)0x03); + _tcpFallbackTunnel->writeBuf.push_back((char)0x03); // fake TLS 1.2 header + _tcpFallbackTunnel->writeBuf.push_back((char)((mlen >> 8) & 0xff)); + _tcpFallbackTunnel->writeBuf.push_back((char)(mlen & 0xff)); + _tcpFallbackTunnel->writeBuf.push_back((char)4); // IPv4 + _tcpFallbackTunnel->writeBuf.append(reinterpret_cast<const char *>(reinterpret_cast<const void *>(&(reinterpret_cast<const struct sockaddr_in *>(addr)->sin_addr.s_addr))),4); + _tcpFallbackTunnel->writeBuf.append(reinterpret_cast<const char *>(reinterpret_cast<const void *>(&(reinterpret_cast<const struct sockaddr_in *>(addr)->sin_port))),2); + _tcpFallbackTunnel->writeBuf.append((const char *)data,len); + } else if (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2))) { + std::vector<InetAddress> tunnelIps(_tcpFallbackResolver.get()); + if (tunnelIps.empty()) { + if (!_tcpFallbackResolver.running()) + _tcpFallbackResolver.resolveNow(); + } else { + bool connected = false; + InetAddress addr(tunnelIps[(unsigned long)now % tunnelIps.size()]); + addr.setPort(ZT_TCP_FALLBACK_RELAY_PORT); + _phy.tcpConnect(reinterpret_cast<const struct sockaddr *>(&addr),connected); } } - - _lastSendToGlobal = now; } + _lastSendToGlobalV4 = now; + } #endif // ZT_TCP_FALLBACK_RELAY + } else if (addr->ss_family == AF_INET6) { + if (reinterpret_cast<const struct sockaddr_in6 *>(localAddr)->sin6_port != 0) { + const uint16_t lp = reinterpret_cast<const struct sockaddr_in6 *>(localAddr)->sin6_port; + if (lp == _portsBE[1]) + fromBindingNo = 1; + else if (lp == _portsBE[2]) + fromBindingNo = 2; + } + } else { + return -1; + } - break; - - case AF_INET6: -#ifdef ZT_BREAK_UDP - if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) { -#endif - if (_v6UdpSocket) - result = ((_phy.udpSend(_v6UdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1); #ifdef ZT_BREAK_UDP - } + if (OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) + return 0; // silently break UDP #endif - break; - default: - return -1; - } - return result; + return (_bindings[fromBindingNo].udpSend(_phy,*(reinterpret_cast<const InetAddress *>(localAddr)),*(reinterpret_cast<const InetAddress *>(addr)),data,len,ttl)) ? 0 : -1; } inline void nodeVirtualNetworkFrameFunction(uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) @@ -1461,6 +1513,25 @@ public: _phy.close(tc->sock); // will call close handler, which deletes from _tcpConnections } + bool shouldBindInterface(const char *ifname,const InetAddress &ifaddr) + { + if (isBlacklistedLocalInterfaceForZeroTierTraffic(ifname)) + return false; + + Mutex::Lock _l(_taps_m); + for(std::map< uint64_t,EthernetTap * >::const_iterator t(_taps.begin());t!=_taps.end();++t) { + if (t->second) { + std::vector<InetAddress> ips(t->second->ips()); + for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) { + if (i->ipsEqual(ifaddr)) + return false; + } + } + } + + return true; + } + std::string _dataStorePrepPath(const char *name) const { std::string p(_homePath); @@ -1478,52 +1549,40 @@ public: return p; } - const std::string _homePath; - BackgroundResolver _tcpFallbackResolver; -#ifdef ZT_ENABLE_NETWORK_CONTROLLER - SqliteNetworkController *_controller; -#endif - Phy<OneServiceImpl *> _phy; - Node *_node; - InetAddress _v4LocalAddress,_v6LocalAddress; - PhySocket *_v4UdpSocket; - PhySocket *_v6UdpSocket; - PhySocket *_v4TcpListenSocket; - PhySocket *_v6TcpListenSocket; - ControlPlane *_controlPlane; - uint64_t _lastDirectReceiveFromGlobal; - uint64_t _lastSendToGlobal; - uint64_t _lastRestart; - volatile uint64_t _nextBackgroundTaskDeadline; - - std::map< uint64_t,EthernetTap * > _taps; - std::map< uint64_t,std::vector<InetAddress> > _tapAssignedIps; // ZeroTier assigned IPs, not user or dhcp assigned - Mutex _taps_m; - - std::set< TcpConnection * > _tcpConnections; // no mutex for this since it's done in the main loop thread only - TcpConnection *_tcpFallbackTunnel; - - ReasonForTermination _termReason; - std::string _fatalErrorMessage; - Mutex _termReason_m; - - unsigned int _port; - -#ifdef ZT_USE_MINIUPNPC - InetAddress _v4UpnpLocalAddress; - PhySocket *_v4UpnpUdpSocket; - PortMapper *_portMapper; -#endif + bool _trialBind(unsigned int port) + { + struct sockaddr_in in4; + struct sockaddr_in6 in6; + PhySocket *tb; + + memset(&in4,0,sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_port = Utils::hton((uint16_t)port); + tb = _phy.udpBind(reinterpret_cast<const struct sockaddr *>(&in4),(void *)0,0); + if (tb) { + _phy.close(tb,false); + tb = _phy.tcpListen(reinterpret_cast<const struct sockaddr *>(&in4),(void *)0); + if (tb) { + _phy.close(tb,false); + return true; + } + } -#ifdef ZT_ENABLE_CLUSTER - PhySocket *_clusterMessageSocket; - ClusterGeoIpService *_clusterGeoIpService; - ClusterDefinition *_clusterDefinition; - unsigned int _clusterMemberId; -#endif + memset(&in6,0,sizeof(in6)); + in6.sin6_family = AF_INET6; + in6.sin6_port = Utils::hton((uint16_t)port); + tb = _phy.udpBind(reinterpret_cast<const struct sockaddr *>(&in6),(void *)0,0); + if (tb) { + _phy.close(tb,false); + tb = _phy.tcpListen(reinterpret_cast<const struct sockaddr *>(&in6),(void *)0); + if (tb) { + _phy.close(tb,false); + return true; + } + } - bool _run; - Mutex _run_m; + return false; + } }; static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) |
