Selaa lähdekoodia

Merge pull request #434 from zielmicha/fix-ip

Binder.hpp: gather all IPv4 interface addresses
Adam Ierymenko 8 vuotta sitten
vanhempi
commit
989cbb4d8d
1 muutettua tiedostoa jossa 37 lisäystä ja 21 poistoa
  1. 37 21
      osdep/Binder.hpp

+ 37 - 21
osdep/Binder.hpp

@@ -236,30 +236,46 @@ public:
 		// Get IPv4 addresses for each device
 		if (ifnames.size() > 0) {
 			const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0);
-			if (controlfd >= 0) {
-				for(std::set<std::string>::iterator devname(ifnames.begin());devname!=ifnames.end();++devname) {
-					struct ifreq ifr;
-					memset(&ifr,0,sizeof(ifr));
-					ifr.ifr_addr.sa_family = AF_INET;
-					Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),devname->c_str());
-					if (ioctl(controlfd,SIOCGIFADDR,&ifr) >= 0) {
-						InetAddress ip(&(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),4,0);
-						if (ifChecker.shouldBindInterface(devname->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:
-									ip.setPort(port);
-									localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,*devname));
-									break;
-							}
-						}
+			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:
+						ip.setPort(port);
+						localIfAddrs.insert(std::pair<InetAddress,std::string>(ip, ifname));
+						break;
 					}
 				}
-				close(controlfd);
 			}
+
+		ip4_address_error:
+			free(configuration.ifc_buf);
+			if (controlfd > 0) close(controlfd);
 		}
 
 		const bool gotViaProc = (localIfAddrs.size() > 0);