瀏覽代碼

Make allow management from a local.conf parameters.

Adam Ierymenko 8 年之前
父節點
當前提交
890f6f0d35
共有 3 個文件被更改,包括 132 次插入116 次删除
  1. 1 10
      one.cpp
  2. 130 101
      service/OneService.cpp
  3. 1 5
      service/OneService.hpp

+ 1 - 10
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:

+ 130 - 101
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

+ 1 - 5
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();