summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2016-12-12 16:25:41 -0800
committerAdam Ierymenko <adam.ierymenko@gmail.com>2016-12-12 16:25:41 -0800
commit890f6f0d35cc715f759cb3014c536a8801bd0c99 (patch)
treea2dbe08e9f9d7e2a51f9a41c9f55eebd5b25a917
parentbad4b72f823642ee076c98a267ff425b59c47b2c (diff)
downloadinfinitytier-890f6f0d35cc715f759cb3014c536a8801bd0c99.tar.gz
infinitytier-890f6f0d35cc715f759cb3014c536a8801bd0c99.zip
Make allow management from a local.conf parameters.
-rw-r--r--one.cpp11
-rw-r--r--service/OneService.cpp231
-rw-r--r--service/OneService.hpp6
3 files changed, 132 insertions, 116 deletions
diff --git a/one.cpp b/one.cpp
index 3dad2ed9..c4fc30e2 100644
--- a/one.cpp
+++ b/one.cpp
@@ -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();