diff options
Diffstat (limited to 'service')
-rw-r--r-- | service/OneService.cpp | 73 | ||||
-rw-r--r-- | service/OneService.hpp | 6 |
2 files changed, 54 insertions, 25 deletions
diff --git a/service/OneService.cpp b/service/OneService.cpp index c2b4636f..d0cdd008 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -415,38 +415,58 @@ public: _nextBackgroundTaskDeadline(0), _tcpFallbackTunnel((TcpConnection *)0), _termReason(ONE_STILL_RUNNING), - _port(port), + _port(0), #ifdef ZT_USE_MINIUPNPC - _upnpClient((int)port), + _upnpClient((UPNPClient *)0), #endif _run(true) { struct sockaddr_in in4; struct sockaddr_in6 in6; - ::memset((void *)&in4,0,sizeof(in4)); - in4.sin_family = AF_INET; - in4.sin_port = Utils::hton((uint16_t)port); - _v4UdpSocket = _phy.udpBind((const struct sockaddr *)&in4,this,131072); - if (!_v4UdpSocket) - throw std::runtime_error("cannot bind to port (UDP/IPv4)"); - in4.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); // right now we just listen for TCP @localhost - _v4TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in4,this); - if (!_v4TcpListenSocket) { - _phy.close(_v4UdpSocket); - throw std::runtime_error("cannot bind to port (TCP/IPv4)"); + 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); + } + + ::memset((void *)&in4,0,sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_port = Utils::hton((uint16_t)port); + _v4UdpSocket = _phy.udpBind((const struct sockaddr *)&in4,this,131072); + if (_v4UdpSocket) { + in4.sin_addr.s_addr = Utils::hton((uint32_t)0x7f000001); // right now we just listen for TCP @localhost + _v4TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in4,this); + if (_v4TcpListenSocket) { + ::memset((void *)&in6,0,sizeof(in6)); + in6.sin6_family = AF_INET6; + in6.sin6_port = in4.sin_port; + _v6UdpSocket = _phy.udpBind((const struct sockaddr *)&in6,this,131072); + in6.sin6_addr.s6_addr[15] = 1; // listen for TCP only at localhost + _v6TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in6,this); + + _port = port; + break; // success! + } else { + _phy.close(_v4UdpSocket,false); + } + } + + port = 0; } - ::memset((void *)&in6,0,sizeof(in6)); - in6.sin6_family = AF_INET6; - in6.sin6_port = in4.sin_port; - _v6UdpSocket = _phy.udpBind((const struct sockaddr *)&in6,this,131072); - in6.sin6_addr.s6_addr[15] = 1; // listen for TCP only at localhost - _v6TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in6,this); + if (_port == 0) + throw std::runtime_error("cannot bind to port"); char portstr[64]; - Utils::snprintf(portstr,sizeof(portstr),"%u",port); + Utils::snprintf(portstr,sizeof(portstr),"%u",_port); OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr)); + +#ifdef ZT_USE_MINIUPNPC + _upnpClient = new UPNPClient(_port); +#endif } virtual ~OneServiceImpl() @@ -455,6 +475,9 @@ public: _phy.close(_v6UdpSocket); _phy.close(_v4TcpListenSocket); _phy.close(_v6TcpListenSocket); +#ifdef ZT_USE_MINIUPNPC + delete _upnpClient; +#endif } virtual ReasonForTermination run() @@ -583,7 +606,7 @@ public: _node->clearLocalInterfaceAddresses(); #ifdef ZT_USE_MINIUPNPC - std::vector<InetAddress> upnpAddresses(_upnpClient.get()); + std::vector<InetAddress> upnpAddresses(_upnpClient->get()); for(std::vector<InetAddress>::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext)),0,ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); #endif @@ -1087,7 +1110,7 @@ public: } } - inline int nodeWirePacketSendFunction(const struct sockaddr_storage *addr,const void *data,unsigned int len) + inline int nodeWirePacketSendFunction(int localInterfaceId,const struct sockaddr_storage *addr,const void *data,unsigned int len) { int result = -1; switch(addr->ss_family) { @@ -1144,6 +1167,7 @@ public: #endif // ZT1_TCP_FALLBACK_RELAY break; + case AF_INET6: #ifdef ZT_BREAK_UDP if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) { @@ -1154,6 +1178,7 @@ public: } #endif break; + default: return -1; } @@ -1275,7 +1300,7 @@ private: unsigned int _port; #ifdef ZT_USE_MINIUPNPC - UPNPClient _upnpClient; + UPNPClient *_upnpClient; #endif bool _run; @@ -1291,7 +1316,7 @@ static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure) { return reinterpret_cast<OneServiceImpl *>(uptr)->nodeDataStorePutFunction(name,data,len,secure); } static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,int localInterfaceId,const struct sockaddr_storage *addr,const void *data,unsigned int len) -{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(addr,data,len); } +{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localInterfaceId,addr,data,len); } static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); } diff --git a/service/OneService.hpp b/service/OneService.hpp index 7a4f7827..70d024bc 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -89,8 +89,12 @@ public: * Once created, you must call the run() method to actually start * processing. * + * The port is saved to a file in the home path called zerotier-one.port, + * which is used by the CLI and can be used to see which port was chosen if + * 0 (random port) is picked. + * * @param hp Home path - * @param port TCP and UDP port for packets and HTTP control + * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) * @param overrideRootTopology String-serialized root topology (for testing, default: NULL) */ static OneService *newInstance( |