Browse Source

Add bindToWildcard local.conf option.

Adam Ierymenko 7 years ago
parent
commit
125ec622ca
3 changed files with 167 additions and 160 deletions
  1. 159 157
      osdep/Binder.hpp
  2. 6 2
      service/OneService.cpp
  3. 2 1
      service/README.md

+ 159 - 157
osdep/Binder.hpp

@@ -125,184 +125,110 @@ public:
 	 *
 	 * @param phy Physical interface
 	 * @param ports Ports to bind on all interfaces
-	 * @param ignoreInterfacesByName Ignore these interfaces by name
-	 * @param ignoreInterfacesByNamePrefix Ignore these interfaces by name-prefix (starts-with, e.g. zt ignores zt*)
-	 * @param ignoreInterfacesByAddress Ignore these interfaces by address
+	 * @param portCount Number of ports
+	 * @param bindtoWildcard If true, bind wildcard instead of per-interface IPs
+	 * @param ifChecker Interface checker function to see if an interface should be used
 	 * @tparam PHY_HANDLER_TYPE Type for Phy<> template
 	 * @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method
 	 */
 	template<typename PHY_HANDLER_TYPE,typename INTERFACE_CHECKER>
-	void refresh(Phy<PHY_HANDLER_TYPE> &phy,unsigned int *ports,unsigned int portCount,INTERFACE_CHECKER &ifChecker)
+	void refresh(Phy<PHY_HANDLER_TYPE> &phy,unsigned int *ports,unsigned int portCount,bool bindToWildcard,INTERFACE_CHECKER &ifChecker)
 	{
 		std::map<InetAddress,std::string> localIfAddrs;
 		PhySocket *udps,*tcps;
 		Mutex::Lock _l(_lock);
 		bool interfacesEnumerated = true;
 
+		if (!bindToWildcard) {
 #ifdef __WINDOWS__
 
-		char aabuf[32768];
-		ULONG aalen = sizeof(aabuf);
-		if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf),&aalen) == NO_ERROR) {
-			PIP_ADAPTER_ADDRESSES a = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf);
-			while (a) {
-				PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress;
-				while (ua) {
-					InetAddress ip(ua->Address.lpSockaddr);
-					if (ifChecker.shouldBindInterface("",ip)) {
-						switch(ip.ipScope()) {
-							default: break;
-							case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
-							case InetAddress::IP_SCOPE_GLOBAL:
-							case InetAddress::IP_SCOPE_SHARED:
-							case InetAddress::IP_SCOPE_PRIVATE:
-								for(int x=0;x<(int)portCount;++x) {
-									ip.setPort(ports[x]);
-									localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string()));
-								}
-								break;
+			char aabuf[32768];
+			ULONG aalen = sizeof(aabuf);
+			if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf),&aalen) == NO_ERROR) {
+				PIP_ADAPTER_ADDRESSES a = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf);
+				while (a) {
+					PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress;
+					while (ua) {
+						InetAddress ip(ua->Address.lpSockaddr);
+						if (ifChecker.shouldBindInterface("",ip)) {
+							switch(ip.ipScope()) {
+								default: break;
+								case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+								case InetAddress::IP_SCOPE_GLOBAL:
+								case InetAddress::IP_SCOPE_SHARED:
+								case InetAddress::IP_SCOPE_PRIVATE:
+									for(int x=0;x<(int)portCount;++x) {
+										ip.setPort(ports[x]);
+										localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string()));
+									}
+									break;
+							}
 						}
+						ua = ua->Next;
 					}
-					ua = ua->Next;
+					a = a->Next;
 				}
-				a = a->Next;
 			}
-		}
-		else {
-			interfacesEnumerated = false;
-		}
+			else {
+				interfacesEnumerated = false;
+			}
 
 #else // not __WINDOWS__
 
-		/* On Linux we use an alternative method if available since getifaddrs()
-		 * gets very slow when there are lots of network namespaces. This won't
-		 * work unless /proc/PID/net/if_inet6 exists and it may not on some
-		 * embedded systems, so revert to getifaddrs() there. */
+			/* On Linux we use an alternative method if available since getifaddrs()
+			 * gets very slow when there are lots of network namespaces. This won't
+			 * work unless /proc/PID/net/if_inet6 exists and it may not on some
+			 * embedded systems, so revert to getifaddrs() there. */
 
 #ifdef __LINUX__
-		char fn[256],tmp[256];
-		std::set<std::string> ifnames;
-		const unsigned long pid = (unsigned long)getpid();
-
-		// Get all device names
-		OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid);
-		FILE *procf = fopen(fn,"r");
-		if (procf) {
-			while (fgets(tmp,sizeof(tmp),procf)) {
-				tmp[255] = 0;
-				char *saveptr = (char *)0;
-				for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) {
-					if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0))
-						ifnames.insert(f);
-					break; // we only want the first field
-				}
-			}
-			fclose(procf);
-		}
-		else {
-			interfacesEnumerated = false;
-		}
-
-		// Get IPv6 addresses (and any device names we don't already know)
-		OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid);
-		procf = fopen(fn,"r");
-		if (procf) {
-			while (fgets(tmp,sizeof(tmp),procf)) {
-				tmp[255] = 0;
-				char *saveptr = (char *)0;
-				unsigned char ipbits[16];
-				memset(ipbits,0,sizeof(ipbits));
-				char *devname = (char *)0;
-				int n = 0;
-				for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) {
-					switch(n++) {
-						case 0: // IP in hex
-							Utils::unhex(f,32,ipbits,16);
-							break;
-						case 5: // device name
-							devname = f;
-							break;
-					}
-				}
-				if (devname) {
-					ifnames.insert(devname);
-					InetAddress ip(ipbits,16,0);
-					if (ifChecker.shouldBindInterface(devname,ip)) {
-						switch(ip.ipScope()) {
-							default: break;
-							case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
-							case InetAddress::IP_SCOPE_GLOBAL:
-							case InetAddress::IP_SCOPE_SHARED:
-							case InetAddress::IP_SCOPE_PRIVATE:
-								for(int x=0;x<(int)portCount;++x) {
-									ip.setPort(ports[x]);
-									localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(devname)));
-								}
-								break;
-						}
+			char fn[256],tmp[256];
+			std::set<std::string> ifnames;
+			const unsigned long pid = (unsigned long)getpid();
+
+			// Get all device names
+			OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid);
+			FILE *procf = fopen(fn,"r");
+			if (procf) {
+				while (fgets(tmp,sizeof(tmp),procf)) {
+					tmp[255] = 0;
+					char *saveptr = (char *)0;
+					for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) {
+						if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0))
+							ifnames.insert(f);
+						break; // we only want the first field
 					}
 				}
+				fclose(procf);
+			}
+			else {
+				interfacesEnumerated = false;
 			}
-			fclose(procf);
-		}
 
-		// Get IPv4 addresses for each device
-		if (ifnames.size() > 0) {
-			const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0);
-			struct ifconf configuration;
-			configuration.ifc_len = 0;
-			configuration.ifc_buf = nullptr;
-
-			if (controlfd < 0) goto ip4_address_error;
-			if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
-			configuration.ifc_buf = (char*)malloc(configuration.ifc_len);
-			if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
-
-			for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) {
-				struct ifreq& request = configuration.ifc_req[i];
-				struct sockaddr* addr = &request.ifr_ifru.ifru_addr;
-				if (addr->sa_family != AF_INET) continue;
-				std::string ifname = request.ifr_ifrn.ifrn_name;
-				// name can either be just interface name or interface name followed by ':' and arbitrary label
-				if (ifname.find(':') != std::string::npos)
-					ifname = ifname.substr(0, ifname.find(':'));
-
-				InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0);
-				if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) {
-					switch(ip.ipScope()) {
-					default: break;
-					case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
-					case InetAddress::IP_SCOPE_GLOBAL:
-					case InetAddress::IP_SCOPE_SHARED:
-					case InetAddress::IP_SCOPE_PRIVATE:
-						for(int x=0;x<(int)portCount;++x) {
-							ip.setPort(ports[x]);
-							localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,ifname));
+			// Get IPv6 addresses (and any device names we don't already know)
+			OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid);
+			procf = fopen(fn,"r");
+			if (procf) {
+				while (fgets(tmp,sizeof(tmp),procf)) {
+					tmp[255] = 0;
+					char *saveptr = (char *)0;
+					unsigned char ipbits[16];
+					memset(ipbits,0,sizeof(ipbits));
+					char *devname = (char *)0;
+					int n = 0;
+					for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) {
+						switch(n++) {
+							case 0: // IP in hex
+								Utils::unhex(f,32,ipbits,16);
+								break;
+							case 5: // device name
+								devname = f;
+								break;
 						}
-						break;
 					}
-				}
-			}
-
-		ip4_address_error:
-			free(configuration.ifc_buf);
-			if (controlfd > 0) close(controlfd);
-		}
-
-		const bool gotViaProc = (localIfAddrs.size() > 0);
-#else
-		const bool gotViaProc = false;
-#endif
-
-		if (!gotViaProc) {
-			struct ifaddrs *ifatbl = (struct ifaddrs *)0;
-			struct ifaddrs *ifa;
-			if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) {
-				ifa = ifatbl;
-				while (ifa) {
-					if ((ifa->ifa_name)&&(ifa->ifa_addr)) {
-						InetAddress ip = *(ifa->ifa_addr);
-						if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) {
+					if (devname) {
+						ifnames.insert(devname);
+						InetAddress ip(ipbits,16,0);
+						if (ifChecker.shouldBindInterface(devname,ip)) {
 							switch(ip.ipScope()) {
 								default: break;
 								case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
@@ -311,23 +237,99 @@ public:
 								case InetAddress::IP_SCOPE_PRIVATE:
 									for(int x=0;x<(int)portCount;++x) {
 										ip.setPort(ports[x]);
-										localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(ifa->ifa_name)));
+										localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(devname)));
 									}
 									break;
 							}
 						}
 					}
-					ifa = ifa->ifa_next;
 				}
-				freeifaddrs(ifatbl);
+				fclose(procf);
 			}
-			else {
-				interfacesEnumerated = false;
+
+			// Get IPv4 addresses for each device
+			if (ifnames.size() > 0) {
+				const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0);
+				struct ifconf configuration;
+				configuration.ifc_len = 0;
+				configuration.ifc_buf = nullptr;
+
+				if (controlfd < 0) goto ip4_address_error;
+				if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
+				configuration.ifc_buf = (char*)malloc(configuration.ifc_len);
+				if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
+
+				for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) {
+					struct ifreq& request = configuration.ifc_req[i];
+					struct sockaddr* addr = &request.ifr_ifru.ifru_addr;
+					if (addr->sa_family != AF_INET) continue;
+					std::string ifname = request.ifr_ifrn.ifrn_name;
+					// name can either be just interface name or interface name followed by ':' and arbitrary label
+					if (ifname.find(':') != std::string::npos)
+						ifname = ifname.substr(0, ifname.find(':'));
+
+					InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0);
+					if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) {
+						switch(ip.ipScope()) {
+						default: break;
+						case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+						case InetAddress::IP_SCOPE_GLOBAL:
+						case InetAddress::IP_SCOPE_SHARED:
+						case InetAddress::IP_SCOPE_PRIVATE:
+							for(int x=0;x<(int)portCount;++x) {
+								ip.setPort(ports[x]);
+								localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,ifname));
+							}
+							break;
+						}
+					}
+				}
+
+			ip4_address_error:
+				free(configuration.ifc_buf);
+				if (controlfd > 0) close(controlfd);
 			}
-		}
 
+			const bool gotViaProc = (localIfAddrs.size() > 0);
+#else
+			const bool gotViaProc = false;
 #endif
 
+			if (!gotViaProc) {
+				struct ifaddrs *ifatbl = (struct ifaddrs *)0;
+				struct ifaddrs *ifa;
+				if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) {
+					ifa = ifatbl;
+					while (ifa) {
+						if ((ifa->ifa_name)&&(ifa->ifa_addr)) {
+							InetAddress ip = *(ifa->ifa_addr);
+							if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) {
+								switch(ip.ipScope()) {
+									default: break;
+									case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+									case InetAddress::IP_SCOPE_GLOBAL:
+									case InetAddress::IP_SCOPE_SHARED:
+									case InetAddress::IP_SCOPE_PRIVATE:
+										for(int x=0;x<(int)portCount;++x) {
+											ip.setPort(ports[x]);
+											localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(ifa->ifa_name)));
+										}
+										break;
+								}
+							}
+						}
+						ifa = ifa->ifa_next;
+					}
+					freeifaddrs(ifatbl);
+				}
+				else {
+					interfacesEnumerated = false;
+				}
+			}
+
+#endif
+		}
+
 		// Default to binding to wildcard if we can't enumerate addresses
 		if (!interfacesEnumerated && localIfAddrs.empty()) {
 			for(int x=0;x<(int)portCount;++x) {

+ 6 - 2
service/OneService.cpp

@@ -565,6 +565,7 @@ public:
 			}
 
 			// Read local configuration
+			bool bindToWildcard = false;
 			{
 				std::map<InetAddress,ZT_PhysicalPathConfiguration> ppc;
 
@@ -626,12 +627,15 @@ public:
 					}
 				}
 
-				// Allow controller DB path to be put somewhere else
 				json &settings = _localConfig["settings"];
 				if (settings.is_object()) {
+					// Allow controller DB path to be put somewhere else
 					const std::string cdbp(OSUtils::jsonString(settings["controllerDbPath"],""));
 					if (cdbp.length() > 0)
 						_controllerDbPath = cdbp;
+
+					// Bind to wildcard instead of to specific interfaces (disables full tunnel capability)
+					bindToWildcard = OSUtils::jsonBool(settings["bindToWildcard"],false);
 				}
 
 				// Set trusted paths if there are any
@@ -801,7 +805,7 @@ public:
 						if (_ports[i])
 							p[pc++] = _ports[i];
 					}
-					_binder.refresh(_phy,p,pc,*this);
+					_binder.refresh(_phy,p,pc,bindToWildcard,*this);
 					{
 						Mutex::Lock _l(_nets_m);
 						for(std::map<uint64_t,NetworkState>::iterator n(_nets.begin());n!=_nets.end();++n) {

+ 2 - 1
service/README.md

@@ -31,7 +31,8 @@ Settings available in `local.conf` (this is not valid JSON, and JSON does not al
 		"softwareUpdateChannel": "release"|"beta", /* Software update channel */
 		"softwareUpdateDist": true|false, /* If true, distribute software updates (only really useful to ZeroTier, Inc. itself, default is false) */
 		"interfacePrefixBlacklist": [ "XXX",... ], /* Array of interface name prefixes (e.g. eth for eth#) to blacklist for ZT traffic */
-		"allowManagementFrom": "NETWORK/bits"|null /* If non-NULL, allow JSON/HTTP management from this IP network. Default is 127.0.0.1 only. */
+		"allowManagementFrom": "NETWORK/bits"|null, /* If non-NULL, allow JSON/HTTP management from this IP network. Default is 127.0.0.1 only. */
+		"bindToWildcard": true|false /* If true, bind to wildcard e.g. 0.0.0.0 instead of per interface */
 	}
 }
 ```