aboutsummaryrefslogblamecommitdiff
path: root/net/isc-dhcp30-server/files/patch-common::discover.c
blob: 1cfcc2094098929d8b07e7ba31aa5e0c7092bc34 (plain) (tree)













































































































































































































































                                                                                
--- common/discover.c.orig	Fri Jul 25 21:44:15 2003
+++ common/discover.c	Fri Mar  5 23:33:04 2004
@@ -47,6 +47,7 @@
 #endif /* not lint */
 
 #include "dhcpd.h"
+#include <ifaddrs.h>
 #include <sys/ioctl.h>
 
 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
@@ -135,10 +136,7 @@
 {
 	struct interface_info *tmp, *ip;
 	struct interface_info *last, *next;
-	char buf [2048];
-	struct ifconf ic;
-	struct ifreq ifr;
-	int i;
+	struct ifaddrs *ifap, *ifa;
 	int sock;
 	int address_count = 0;
 	struct subnet *subnet;
@@ -157,61 +155,6 @@
 	if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
 		log_fatal ("Can't create addrlist socket");
 
-	/* Get the interface configuration information... */
-
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	/* linux will only tell us how long a buffer it wants if we give it
-	 * a null buffer first. So, do a dry run to figure out the length.
-	 * 
-	 * XXX this code is duplicated from below because trying to fold
-	 * the logic into the if statement and goto resulted in excesssive
-	 * obfuscation. The intent is that unless you run Linux you shouldn't
-	 * have to deal with this. */
-
-	ic.ifc_len = 0;
-	ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
-#else
-	/* otherwise, we just feed it a starting size, and it'll tell us if
-	 * it needs more */
-
-	ic.ifc_len = sizeof buf;
-	ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-#endif
-
-      gifconf_again:
-	i = ioctl(sock, SIOCGIFCONF, &ic);
-
-	if (i < 0)
-		log_fatal ("ioctl: SIOCGIFCONF: %m");
-
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	/* Workaround for SIOCGIFCONF bug on some Linux versions. */
-	if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
-		ic.ifc_len = sizeof buf;
-		ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-		goto gifconf_again;
-	}
-#endif
-
-	/* If the SIOCGIFCONF resulted in more data than would fit in
-	   a buffer, allocate a bigger buffer. */
-	if ((ic.ifc_ifcu.ifcu_buf == buf 
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	     || ic.ifc_ifcu.ifcu_buf == 0
-#endif
-		) && ic.ifc_len > sizeof buf) {
-		ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
-		if (!ic.ifc_ifcu.ifcu_buf)
-			log_fatal ("Can't allocate SIOCGIFCONF buffer.");
-		goto gifconf_again;
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	} else if (ic.ifc_ifcu.ifcu_buf == 0) {
-		ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-		ic.ifc_len = sizeof buf;
-		goto gifconf_again;
-#endif
-	}
-
 		
 	/* If we already have a list of interfaces, and we're running as
 	   a DHCP server, the interfaces were requested. */
@@ -224,51 +167,38 @@
 	else
 		ir = INTERFACE_REQUESTED;
 
+	if (getifaddrs(&ifap) != 0)
+		log_fatal ("getifaddrs failed");
+
 	/* Cycle through the list of interfaces looking for IP addresses. */
-	for (i = 0; i < ic.ifc_len;) {
-		struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
-#ifdef HAVE_SA_LEN
-		if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
-			i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
-		else
-#endif
-			i += sizeof *ifp;
+	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
 
 #ifdef ALIAS_NAMES_PERMUTED
-		if ((s = strrchr (ifp -> ifr_name, ':'))) {
+		if ((s = strrchr (ifa -> ifa_name, ':'))) {
 			*s = 0;
 		}
 #endif
 
 #ifdef SKIP_DUMMY_INTERFACES
-		if (!strncmp (ifp -> ifr_name, "dummy", 5))
+		if (!strncmp (ifa -> ifa_name, "dummy", 5))
 			continue;
 #endif
 
-
-		/* See if this is the sort of interface we want to
-		   deal with. */
-		strcpy (ifr.ifr_name, ifp -> ifr_name);
-		if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
-			log_fatal ("Can't get interface flags for %s: %m",
-			       ifr.ifr_name);
-
 		/* See if we've seen an interface that matches this one. */
 		for (tmp = interfaces; tmp; tmp = tmp -> next)
-			if (!strcmp (tmp -> name, ifp -> ifr_name))
+			if (!strcmp (tmp -> name, ifa -> ifa_name))
 				break;
 
-		/* Skip non broadcast interfaces (plus loopback and
-		   point-to-point in case an OS incorrectly marks them
-		   as broadcast). Also skip down interfaces unless we're
+		/* See if this is the sort of interface we want to
+		   deal with.  Skip loopback, point-to-point and down
+		   interfaces, except don't skip down interfaces if we're
 		   trying to get a list of configurable interfaces. */
-		if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
-		      ifr.ifr_flags & IFF_LOOPBACK ||
-		      ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
-		    (!(ifr.ifr_flags & IFF_UP) &&
+		if ((ifa->ifa_flags & IFF_LOOPBACK) ||
+		     (ifa->ifa_flags & IFF_POINTOPOINT) ||
+		     (!(ifa->ifa_flags & IFF_UP) &&
 		     state != DISCOVER_UNCONFIGURED))
 			continue;
-		
+
 		/* If there isn't already an interface by this name,
 		   allocate one. */
 		if (!tmp) {
@@ -276,9 +206,9 @@
 			status = interface_allocate (&tmp, MDL);
 			if (status != ISC_R_SUCCESS)
 				log_fatal ("Error allocating interface %s: %s",
-					   ifp -> ifr_name,
+					   ifa -> ifa_name,
 					   isc_result_totext (status));
-			strcpy (tmp -> name, ifp -> ifr_name);
+			strcpy (tmp -> name, ifa -> ifa_name);
 			interface_snorf (tmp, ir);
 			interface_dereference (&tmp, MDL);
 			tmp = interfaces; /* XXX */
@@ -290,9 +220,9 @@
 		/* If we have the capability, extract link information
 		   and record it in a linked list. */
 #ifdef HAVE_AF_LINK
-		if (ifp -> ifr_addr.sa_family == AF_LINK) {
+		if (ifa -> ifa_addr->sa_family == AF_LINK) {
 			struct sockaddr_dl *foo = ((struct sockaddr_dl *)
-						   (&ifp -> ifr_addr));
+						   (ifa -> ifa_addr));
 #if defined (HAVE_SIN_LEN)
 			tmp -> hw_address.hlen = foo -> sdl_alen;
 #else
@@ -305,12 +235,11 @@
 		} else
 #endif /* AF_LINK */
 
-		if (ifp -> ifr_addr.sa_family == AF_INET) {
+		if (ifa -> ifa_addr->sa_family == AF_INET) {
 			struct iaddr addr;
 
 			/* Get a pointer to the address... */
-			memcpy (&foo, &ifp -> ifr_addr,
-				sizeof ifp -> ifr_addr);
+			bcopy(ifa->ifa_addr, &foo, sizeof(foo));
 
 			/* We don't want the loopback interface. */
 			if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
@@ -323,16 +252,15 @@
 			   found, keep a pointer to ifreq structure in
 			   which we found it. */
 			if (!tmp -> ifp) {
-#ifdef HAVE_SA_LEN
-				unsigned len = ((sizeof ifp -> ifr_name) +
-						ifp -> ifr_addr.sa_len);
-#else
-				unsigned len = sizeof *ifp;
-#endif
+
+				int len = (IFNAMSIZ +
+					ifa -> ifa_addr->sa_len);
 				tif = (struct ifreq *)dmalloc (len, MDL);
 				if (!tif)
 					log_fatal ("no space for ifp.");
-				memcpy (tif, ifp, len);
+				strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ);
+				memcpy(&tif->ifr_addr, ifa->ifa_addr,
+					ifa->ifa_addr->sa_len);
 				tmp -> ifp = tif;
 				tmp -> primary_address = foo.sin_addr;
 			}
@@ -346,9 +274,6 @@
 		}
 	}
 
-	/* If we allocated a buffer, free it. */
-	if (ic.ifc_ifcu.ifcu_buf != buf)
-		dfree (ic.ifc_ifcu.ifcu_buf, MDL);
 
 #if defined (LINUX_SLASHPROC_DISCOVERY)
 	/* On Linux, interfaces that don't have IP addresses don't
@@ -529,6 +454,7 @@
 	   be able to configure, we can quit now. */
 	if (state == DISCOVER_UNCONFIGURED) {
 		close (sock);
+		freeifaddrs(ifap);
 		return;
 	}
 
@@ -674,6 +600,7 @@
 	}
 
 	close (sock);
+	freeifaddrs(ifap);
 
 	if (state == DISCOVER_SERVER && wifcount == 0) {
 		log_info ("%s", "");