Pick random port on -p0

This commit is contained in:
Adam Ierymenko 2015-09-23 14:38:16 -07:00
parent a3ed5277ef
commit 80dc7fb675
3 changed files with 56 additions and 27 deletions

View File

@ -910,7 +910,7 @@ static void printHelp(const char *cn,FILE *out)
fprintf(out," -h - Display this help"ZT_EOL_S); fprintf(out," -h - Display this help"ZT_EOL_S);
fprintf(out," -v - Show version"ZT_EOL_S); fprintf(out," -v - Show version"ZT_EOL_S);
fprintf(out," -U - Run as unprivileged user (skip privilege check)"ZT_EOL_S); fprintf(out," -U - Run as unprivileged user (skip privilege check)"ZT_EOL_S);
fprintf(out," -p<port> - Port for UDP and TCP/HTTP (default: 9993)"ZT_EOL_S); fprintf(out," -p<port> - Port for UDP and TCP/HTTP (default: 9993, 0 for random)"ZT_EOL_S);
//fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S); //fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S);
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
@ -985,7 +985,7 @@ int main(int argc,char **argv)
case 'p': // port -- for both UDP and TCP, packets and control plane case 'p': // port -- for both UDP and TCP, packets and control plane
port = Utils::strToUInt(argv[i] + 2); port = Utils::strToUInt(argv[i] + 2);
if ((port > 0xffff)||(port == 0)) { if (port > 0xffff) {
printHelp(argv[0],stdout); printHelp(argv[0],stdout);
return 1; return 1;
} }

View File

@ -415,38 +415,58 @@ public:
_nextBackgroundTaskDeadline(0), _nextBackgroundTaskDeadline(0),
_tcpFallbackTunnel((TcpConnection *)0), _tcpFallbackTunnel((TcpConnection *)0),
_termReason(ONE_STILL_RUNNING), _termReason(ONE_STILL_RUNNING),
_port(port), _port(0),
#ifdef ZT_USE_MINIUPNPC #ifdef ZT_USE_MINIUPNPC
_upnpClient((int)port), _upnpClient((UPNPClient *)0),
#endif #endif
_run(true) _run(true)
{ {
struct sockaddr_in in4; struct sockaddr_in in4;
struct sockaddr_in6 in6; struct sockaddr_in6 in6;
::memset((void *)&in4,0,sizeof(in4)); const int portTrials = (port == 0) ? 256 : 1; // if port is 0, pick random
in4.sin_family = AF_INET; for(int k=0;k<portTrials;++k) {
in4.sin_port = Utils::hton((uint16_t)port); if (port == 0) {
_v4UdpSocket = _phy.udpBind((const struct sockaddr *)&in4,this,131072); unsigned int randp = 0;
if (!_v4UdpSocket) Utils::getSecureRandom(&randp,sizeof(randp));
throw std::runtime_error("cannot bind to port (UDP/IPv4)"); port = 40000 + (randp % 25500);
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 *)&in4,0,sizeof(in4));
_phy.close(_v4UdpSocket); in4.sin_family = AF_INET;
throw std::runtime_error("cannot bind to port (TCP/IPv4)"); 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)); if (_port == 0)
in6.sin6_family = AF_INET6; throw std::runtime_error("cannot bind to port");
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);
char portstr[64]; 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)); 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() virtual ~OneServiceImpl()
@ -455,6 +475,9 @@ public:
_phy.close(_v6UdpSocket); _phy.close(_v6UdpSocket);
_phy.close(_v4TcpListenSocket); _phy.close(_v4TcpListenSocket);
_phy.close(_v6TcpListenSocket); _phy.close(_v6TcpListenSocket);
#ifdef ZT_USE_MINIUPNPC
delete _upnpClient;
#endif
} }
virtual ReasonForTermination run() virtual ReasonForTermination run()
@ -583,7 +606,7 @@ public:
_node->clearLocalInterfaceAddresses(); _node->clearLocalInterfaceAddresses();
#ifdef ZT_USE_MINIUPNPC #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) 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); _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext)),0,ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL);
#endif #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; int result = -1;
switch(addr->ss_family) { switch(addr->ss_family) {
@ -1144,6 +1167,7 @@ public:
#endif // ZT1_TCP_FALLBACK_RELAY #endif // ZT1_TCP_FALLBACK_RELAY
break; break;
case AF_INET6: case AF_INET6:
#ifdef ZT_BREAK_UDP #ifdef ZT_BREAK_UDP
if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) { if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) {
@ -1154,6 +1178,7 @@ public:
} }
#endif #endif
break; break;
default: default:
return -1; return -1;
} }
@ -1275,7 +1300,7 @@ private:
unsigned int _port; unsigned int _port;
#ifdef ZT_USE_MINIUPNPC #ifdef ZT_USE_MINIUPNPC
UPNPClient _upnpClient; UPNPClient *_upnpClient;
#endif #endif
bool _run; 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) 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); } { 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) 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) 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); } { reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); }

View File

@ -89,8 +89,12 @@ public:
* Once created, you must call the run() method to actually start * Once created, you must call the run() method to actually start
* processing. * 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 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) * @param overrideRootTopology String-serialized root topology (for testing, default: NULL)
*/ */
static OneService *newInstance( static OneService *newInstance(