diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-12-12 16:25:41 -0800 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-12-12 16:25:41 -0800 |
commit | 890f6f0d35cc715f759cb3014c536a8801bd0c99 (patch) | |
tree | a2dbe08e9f9d7e2a51f9a41c9f55eebd5b25a917 | |
parent | bad4b72f823642ee076c98a267ff425b59c47b2c (diff) | |
download | infinitytier-890f6f0d35cc715f759cb3014c536a8801bd0c99.tar.gz infinitytier-890f6f0d35cc715f759cb3014c536a8801bd0c99.zip |
Make allow management from a local.conf parameters.
-rw-r--r-- | one.cpp | 11 | ||||
-rw-r--r-- | service/OneService.cpp | 231 | ||||
-rw-r--r-- | service/OneService.hpp | 6 |
3 files changed, 132 insertions, 116 deletions
@@ -973,7 +973,6 @@ int main(int argc,char **argv) std::string homeDir; unsigned int port = ZT_DEFAULT_PORT; bool skipRootCheck = false; - const char *allowManagementFrom = (const char *)0; for(int i=1;i<argc;++i) { if (argv[i][0] == '-') { @@ -987,14 +986,6 @@ int main(int argc,char **argv) } break; - case 'M': // allow management from this IP/bits network - allowManagementFrom = argv[i] + 2; - if (!strlen(allowManagementFrom)) { - printHelp(argv[0],stdout); - return 1; - } - break; - #ifdef __UNIX_LIKE__ case 'd': // Run in background as daemon runAsDaemon = true; @@ -1176,7 +1167,7 @@ int main(int argc,char **argv) unsigned int returnValue = 0; for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port,allowManagementFrom); + zt1Service = OneService::newInstance(homeDir.c_str(),port); switch(zt1Service->run()) { case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done case OneService::ONE_NORMAL_TERMINATION: diff --git a/service/OneService.cpp b/service/OneService.cpp index b925fc1b..2e256307 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -514,10 +514,10 @@ public: const std::string _homePath; BackgroundResolver _tcpFallbackResolver; - InetAddress _allowManagementFrom; EmbeddedNetworkController *_controller; Phy<OneServiceImpl *> _phy; Node *_node; + unsigned int _primaryPort; // Local configuration and memo-ized static path definitions json _localConfig; @@ -527,6 +527,7 @@ public: Hashtable< uint64_t,std::vector<InetAddress> > _v6Blacklists; std::vector< InetAddress > _globalV4Blacklist; std::vector< InetAddress > _globalV6Blacklist; + std::vector< InetAddress > _allowManagementFrom; std::vector< std::string > _interfacePrefixBlacklist; Mutex _localConfig_m; @@ -612,12 +613,13 @@ public: // end member variables ---------------------------------------------------- - OneServiceImpl(const char *hp,unsigned int port,const char *allowManagementFrom) : + OneServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : ".") ,_tcpFallbackResolver(ZT_TCP_FALLBACK_RELAY) ,_controller((EmbeddedNetworkController *)0) ,_phy(this,false,true) ,_node((Node *)0) + ,_primaryPort(port) ,_controlPlane((ControlPlane *)0) ,_lastDirectReceiveFromGlobal(0) #ifdef ZT_TCP_FALLBACK_RELAY @@ -637,63 +639,9 @@ public: #endif ,_run(true) { - if (allowManagementFrom) - _allowManagementFrom.fromString(allowManagementFrom); - _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 = 20000 + (randp % 45500); - } - - 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)((allowManagementFrom) ? 0 : 0x7f000001)); // right now we just listen for TCP @127.0.0.1 - in4.sin_port = Utils::hton((uint16_t)port); - _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; - if (!allowManagementFrom) - 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 { - if (_v4TcpControlSocket) - _phy.close(_v4TcpControlSocket,false); - if (_v6TcpControlSocket) - _phy.close(_v6TcpControlSocket,false); - port = 0; - } - } else { - port = 0; - } - } - - if (_ports[0] == 0) - throw std::runtime_error("cannot bind to local control interface port"); - - char portstr[64]; - 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() @@ -758,49 +706,7 @@ public: _node = new Node(this,&cb,OSUtils::now()); } - // 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]); - + // Read local configuration { uint64_t trustedPathIds[ZT_MAX_TRUSTED_PATHS]; InetAddress trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; @@ -872,6 +778,103 @@ public: } applyLocalConfig(); + // Bind TCP control socket + const int portTrials = (_primaryPort == 0) ? 256 : 1; // if port is 0, pick random + for(int k=0;k<portTrials;++k) { + if (_primaryPort == 0) { + unsigned int randp = 0; + Utils::getSecureRandom(&randp,sizeof(randp)); + _primaryPort = 20000 + (randp % 45500); + } + + if (_trialBind(_primaryPort)) { + struct sockaddr_in in4; + memset(&in4,0,sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_addr.s_addr = Utils::hton((uint32_t)((_allowManagementFrom.size() > 0) ? 0 : 0x7f000001)); // right now we just listen for TCP @127.0.0.1 + in4.sin_port = Utils::hton((uint16_t)_primaryPort); + _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; + if (_allowManagementFrom.size() == 0) + 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] = _primaryPort; + break; + } else { + if (_v4TcpControlSocket) + _phy.close(_v4TcpControlSocket,false); + if (_v6TcpControlSocket) + _phy.close(_v6TcpControlSocket,false); + _primaryPort = 0; + } + } else { + _primaryPort = 0; + } + } + if (_ports[0] == 0) { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = "cannot bind to local control interface port"; + return _termReason; + } + + // Write file containing primary port to be read by CLIs, etc. + char portstr[64]; + Utils::snprintf(portstr,sizeof(portstr),"%u",_ports[0]); + OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr)); + + // 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 + + // Populate ports in big-endian format for quick compare + for(int i=0;i<3;++i) + _portsBE[i] = Utils::hton((uint16_t)_ports[i]); + _controller = new EmbeddedNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str()); _node->setNetconfMaster((void *)_controller); @@ -1218,6 +1221,7 @@ public: } } + _allowManagementFrom.clear(); _interfacePrefixBlacklist.clear(); json &settings = _localConfig["settings"]; if (settings.is_object()) { @@ -1236,6 +1240,15 @@ public: _interfacePrefixBlacklist.push_back(tmp); } } + + json &amf = settings["allowManagementFrom"]; + if (amf.is_array()) { + for(unsigned long i=0;i<amf.size();++i) { + const InetAddress nw(_jS(amf[i],"")); + if (nw) + _allowManagementFrom.push_back(nw); + } + } } } @@ -1928,7 +1941,23 @@ public: std::string contentType("text/plain"); // default if not changed in handleRequest() unsigned int scode = 404; - if ( ((!_allowManagementFrom)&&(tc->from.ipScope() == InetAddress::IP_SCOPE_LOOPBACK)) || (_allowManagementFrom.containsAddress(tc->from)) ) { + bool allow; + { + Mutex::Lock _l(_localConfig_m); + if (_allowManagementFrom.size() == 0) { + allow = (tc->from.ipScope() == InetAddress::IP_SCOPE_LOOPBACK); + } else { + allow = false; + for(std::vector<InetAddress>::const_iterator i(_allowManagementFrom.begin());i!=_allowManagementFrom.end();++i) { + if (i->containsAddress(tc->from)) { + allow = true; + break; + } + } + } + } + + if (allow) { try { if (_controlPlane) scode = _controlPlane->handleRequest(tc->from,tc->parser.method,tc->url,tc->headers,tc->body,data,contentType); @@ -2230,7 +2259,7 @@ std::string OneService::autoUpdateUrl() return std::string(); } -OneService *OneService::newInstance(const char *hp,unsigned int port,const char *allowManagementFrom) { return new OneServiceImpl(hp,port,allowManagementFrom); } +OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); } OneService::~OneService() {} } // namespace ZeroTier diff --git a/service/OneService.hpp b/service/OneService.hpp index 553bfd5e..aebc051b 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -98,12 +98,8 @@ public: * * @param hp Home path * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) - * @param allowManagementFrom If non-NULL, allow control from supplied IP/netmask */ - static OneService *newInstance( - const char *hp, - unsigned int port, - const char *allowManagementFrom = (const char *)0); + static OneService *newInstance(const char *hp,unsigned int port); virtual ~OneService(); |