From 367ffde00cf6eecbca0f9fff391dcaf7faf72c6e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Sep 2015 13:49:56 -0700 Subject: Plumb through localInterfaceId to track local interfaces corresponding with remote addresses. --- service/OneService.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'service/OneService.cpp') diff --git a/service/OneService.cpp b/service/OneService.cpp index e8b8ba60..c2b4636f 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -344,7 +344,7 @@ static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData); static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize); static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure); -static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,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); 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 StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); @@ -727,6 +727,7 @@ public: _lastDirectReceiveFromGlobal = OSUtils::now(); ZT1_ResultCode rc = _node->processWirePacket( OSUtils::now(), + 0, (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big data, len, @@ -875,6 +876,7 @@ public: if (from) { ZT1_ResultCode rc = _node->processWirePacket( OSUtils::now(), + 0, reinterpret_cast(&from), data, plen, @@ -1288,7 +1290,7 @@ static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name { return reinterpret_cast(uptr)->nodeDataStoreGetFunction(name,buf,bufSize,readIndex,totalSize); } static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure) { return reinterpret_cast(uptr)->nodeDataStorePutFunction(name,data,len,secure); } -static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,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(uptr)->nodeWirePacketSendFunction(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(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); } -- cgit v1.2.3 From 80dc7fb67584ee29e7e907b7ccd48c6f217923c3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Sep 2015 14:38:16 -0700 Subject: Pick random port on -p0 --- one.cpp | 4 +-- service/OneService.cpp | 73 +++++++++++++++++++++++++++++++++----------------- service/OneService.hpp | 6 ++++- 3 files changed, 56 insertions(+), 27 deletions(-) (limited to 'service/OneService.cpp') diff --git a/one.cpp b/one.cpp index 30d95cb9..b96fef72 100644 --- a/one.cpp +++ b/one.cpp @@ -910,7 +910,7 @@ static void printHelp(const char *cn,FILE *out) fprintf(out," -h - Display this help"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," -p - Port for UDP and TCP/HTTP (default: 9993)"ZT_EOL_S); + fprintf(out," -p - Port for UDP and TCP/HTTP (default: 9993, 0 for random)"ZT_EOL_S); //fprintf(out," -T - Override root topology, do not authenticate or update"ZT_EOL_S); #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 port = Utils::strToUInt(argv[i] + 2); - if ((port > 0xffff)||(port == 0)) { + if (port > 0xffff) { printHelp(argv[0],stdout); return 1; } 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;kclearLocalInterfaceAddresses(); #ifdef ZT_USE_MINIUPNPC - std::vector upnpAddresses(_upnpClient.get()); + std::vector upnpAddresses(_upnpClient->get()); for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) _node->addLocalInterfaceAddress(reinterpret_cast(&(*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(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(uptr)->nodeWirePacketSendFunction(addr,data,len); } +{ return reinterpret_cast(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(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( -- cgit v1.2.3 From 7821d1cbdd922faba9eccba62d90edd6d7b91c93 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Sep 2015 14:44:13 -0700 Subject: . --- service/OneService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'service/OneService.cpp') diff --git a/service/OneService.cpp b/service/OneService.cpp index d0cdd008..c7f82058 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -566,7 +566,7 @@ public: #ifdef ZT_AUTO_UPDATE if ((now - lastSoftwareUpdateCheck) >= ZT_AUTO_UPDATE_CHECK_PERIOD) { - lastSoftwareUpdateCheck = OSUtils::now(); + lastSoftwareUpdateCheck = now; Thread::start(&backgroundSoftwareUpdateChecker); } #endif // ZT_AUTO_UPDATE -- cgit v1.2.3 From 423412df9806f14a2eed7c87f5f3a5615a7f22b5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Sep 2015 15:16:20 -0700 Subject: Pick a random secondary UDP port for uPnP mapped traffic because of broken routers. --- service/OneService.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) (limited to 'service/OneService.cpp') diff --git a/service/OneService.cpp b/service/OneService.cpp index c7f82058..27874518 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -396,6 +396,10 @@ struct TcpConnection Mutex writeBuf_m; }; +// Interface IDs -- the uptr for UDP sockets is set to point to one of these +static const int ZT1_INTERFACE_ID_DEFAULT = 0; // default, usually port 9993 +static const int ZT1_INTERFACE_ID_UPNP = 1; // a randomly chosen UDP socket used with uPnP mappings, if enabled + class OneServiceImpl : public OneService { public: @@ -417,6 +421,7 @@ public: _termReason(ONE_STILL_RUNNING), _port(0), #ifdef ZT_USE_MINIUPNPC + _v4UpnpUdpSocket((PhySocket *)0), _upnpClient((UPNPClient *)0), #endif _run(true) @@ -432,18 +437,23 @@ public: port = 40000 + (randp % 25500); } - ::memset((void *)&in4,0,sizeof(in4)); + 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); + + _v4UdpSocket = _phy.udpBind((const struct sockaddr *)&in4,reinterpret_cast(const_cast(&ZT1_INTERFACE_ID_DEFAULT)),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)); + 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); + + _v6UdpSocket = _phy.udpBind((const struct sockaddr *)&in6,reinterpret_cast(const_cast(&ZT1_INTERFACE_ID_DEFAULT)),131072); + in6.sin6_addr.s6_addr[15] = 1; // listen for TCP only at localhost _v6TcpListenSocket = _phy.tcpListen((const struct sockaddr *)&in6,this); @@ -465,7 +475,25 @@ public: OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr)); #ifdef ZT_USE_MINIUPNPC - _upnpClient = new UPNPClient(_port); + // Bind a random 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<256;++k) { + unsigned int randp = 0; + Utils::getSecureRandom(&randp,sizeof(randp)); + unsigned int upnport = 40000 + (randp % 25500); + + memset((void *)&in4,0,sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_port = Utils::hton((uint16_t)upnport); + + _v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&in4,reinterpret_cast(const_cast(&ZT1_INTERFACE_ID_UPNP)),131072); + if (_v4UpnpUdpSocket) { + _upnpClient = new UPNPClient(upnport); + break; + } + } #endif } @@ -476,6 +504,7 @@ public: _phy.close(_v4TcpListenSocket); _phy.close(_v6TcpListenSocket); #ifdef ZT_USE_MINIUPNPC + _phy.close(_v4UpnpUdpSocket); delete _upnpClient; #endif } @@ -750,7 +779,7 @@ public: _lastDirectReceiveFromGlobal = OSUtils::now(); ZT1_ResultCode rc = _node->processWirePacket( OSUtils::now(), - 0, + *(reinterpret_cast(*uptr)), // for UDP sockets, we set uptr to point to their interface ID (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big data, len, @@ -1112,6 +1141,20 @@ public: inline int nodeWirePacketSendFunction(int localInterfaceId,const struct sockaddr_storage *addr,const void *data,unsigned int len) { +#ifdef ZT_USE_MINIUPNPC + if (localInterfaceId == ZT1_INTERFACE_ID_UPNP) { +#ifdef ZT_BREAK_UDP + if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) { +#endif + if (addr->ss_family == AF_INET) + return ((_phy.udpSend(_v4UpnpUdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1); + else return -1; +#ifdef ZT_BREAK_UDP + } +#endif + } +#endif // ZT_USE_MINIUPNPC + int result = -1; switch(addr->ss_family) { case AF_INET: @@ -1300,6 +1343,7 @@ private: unsigned int _port; #ifdef ZT_USE_MINIUPNPC + PhySocket *_v4UpnpUdpSocket; UPNPClient *_upnpClient; #endif -- cgit v1.2.3