[dhcp/f17] use getifaddrs() to scan for interfaces on Linux (#449946)

Jiří Popelka jpopelka at fedoraproject.org
Wed Mar 21 16:16:57 UTC 2012


commit c40b021d75a09191628a290cdce33dd33c784af0
Author: Jiri Popelka <jpopelka at redhat.com>
Date:   Wed Mar 21 16:46:07 2012 +0100

    use getifaddrs() to scan for interfaces on Linux (#449946)

 dhcp-4.2.3-P2-getifaddrs.patch |  412 ++++++++++++++++++++++++++++++++++++++++
 dhcp.spec                      |    9 +-
 2 files changed, 420 insertions(+), 1 deletions(-)
---
diff --git a/dhcp-4.2.3-P2-getifaddrs.patch b/dhcp-4.2.3-P2-getifaddrs.patch
new file mode 100644
index 0000000..ef9093f
--- /dev/null
+++ b/dhcp-4.2.3-P2-getifaddrs.patch
@@ -0,0 +1,412 @@
+diff -up dhcp-4.2.3-P2/common/discover.c.getifaddrs dhcp-4.2.3-P2/common/discover.c
+--- dhcp-4.2.3-P2/common/discover.c.getifaddrs	2012-03-21 16:28:08.537760099 +0100
++++ dhcp-4.2.3-P2/common/discover.c	2012-03-21 16:29:58.134389955 +0100
+@@ -379,394 +379,13 @@ end_iface_scan(struct iface_conf_list *i
+ 	ifaces->sock = -1;
+ }
+ 
+-#elif __linux /* !HAVE_SIOCGLIFCONF */
+-/* 
+- * Linux support
+- * -------------
+- *
+- * In Linux, we use the /proc pseudo-filesystem to get information
+- * about interfaces, along with selected ioctl() calls.
+- *
+- * Linux low level access is documented in the netdevice man page.
+- */
+-
+-/* 
+- * Structure holding state about the scan.
+- */
+-struct iface_conf_list {
+-	int sock;	/* file descriptor used to get information */
+-	FILE *fp;	/* input from /proc/net/dev */
+-#ifdef DHCPv6
+-	FILE *fp6;	/* input from /proc/net/if_inet6 */
+-#endif
+-};
+-
+-/* 
+- * Structure used to return information about a specific interface.
+- */
+-struct iface_info {
+-	char name[IFNAMSIZ];		/* name of the interface, e.g. "eth0" */
+-	struct sockaddr_storage addr;	/* address information */
+-	isc_uint64_t flags;		/* interface flags, e.g. IFF_LOOPBACK */
+-};
+-
+-/* 
+- * Start a scan of interfaces.
+- *
+- * The iface_conf_list structure maintains state for this process.
+- */
+-int 
+-begin_iface_scan(struct iface_conf_list *ifaces) {
+-	char buf[256];
+-	int len;
+-	int i;
+-
+-	ifaces->fp = fopen("/proc/net/dev", "re");
+-	if (ifaces->fp == NULL) {
+-		log_error("Error opening '/proc/net/dev' to list interfaces");
+-		return 0;
+-	}
+-
+-	/*
+-	 * The first 2 lines are header information, so read and ignore them.
+-	 */
+-	for (i=0; i<2; i++) {
+-		if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
+-			log_error("Error reading headers from '/proc/net/dev'");
+-			fclose(ifaces->fp);
+-			ifaces->fp = NULL;
+-			return 0;
+-		}
+-		len = strlen(buf);
+-		if ((len <= 0) || (buf[len-1] != '\n')) { 
+-			log_error("Bad header line in '/proc/net/dev'");
+-			fclose(ifaces->fp);
+-			ifaces->fp = NULL;
+-			return 0;
+-		}
+-	}
+-
+-	ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+-	if (ifaces->sock < 0) {
+-		log_error("Error creating socket to list interfaces; %m");
+-		fclose(ifaces->fp);
+-		ifaces->fp = NULL;
+-		return 0;
+-	}
+-
+-#ifdef DHCPv6
+-	if ((local_family == AF_INET6) && !access("/proc/net/if_inet6", R_OK)) {
+-		ifaces->fp6 = fopen("/proc/net/if_inet6", "re");
+-		if (ifaces->fp6 == NULL) {
+-			log_error("Error opening '/proc/net/if_inet6' to "
+-				  "list IPv6 interfaces; %m");
+-			close(ifaces->sock);
+-			ifaces->sock = -1;
+-			fclose(ifaces->fp);
+-			ifaces->fp = NULL;
+-			return 0;
+-		}
+-	} else {
+-		ifaces->fp6 = NULL;
+-	}
+-#endif
+-
+-	return 1;
+-}
+-
+-/*
+- * Read our IPv4 interfaces from /proc/net/dev.
+- *
+- * The file looks something like this:
+- *
+- * Inter-|   Receive ...
+- *  face |bytes    packets errs drop fifo frame ...
+- *     lo: 1580562    4207    0    0    0     0 ...
+- *   eth0:       0       0    0    0    0     0 ...
+- *   eth1:1801552440   37895    0   14    0     ...
+- *
+- * We only care about the interface name, which is at the start of 
+- * each line.
+- *
+- * We use an ioctl() to get the address and flags for each interface.
+- */
+-static int
+-next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
+-	char buf[256];
+-	int len;
+-	char *p;
+-	char *name;
+-	struct ifreq tmp;
+-
+-	/*
+-	 * Loop exits when we find an interface that has an address, or 
+-	 * when we run out of interfaces.
+-	 */
+-	for (;;) {
+-		do {
+-			/*
+-	 		 *  Read the next line in the file.
+-	 		 */
+-			if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
+-				if (ferror(ifaces->fp)) {
+-					*err = 1;
+-					log_error("Error reading interface "
+-					  	"information");
+-				} else {
+-					*err = 0;
+-				}
+-				return 0;
+-			}
+-
+-			/*
+-	 		 * Make sure the line is a nice, 
+-			 * newline-terminated line.
+-	 		 */
+-			len = strlen(buf);
+-			if ((len <= 0) || (buf[len-1] != '\n')) { 
+-				log_error("Bad line reading interface "
+-					  "information");
+-				*err = 1;
+-				return 0;
+-			}
+-
+-			/*
+-	 		 * Figure out our name.
+-	 		 */
+-			p = strrchr(buf, ':');
+-			if (p == NULL) {
+-				log_error("Bad line reading interface "
+-					  "information (no colon)");
+-				*err = 1;
+-				return 0;
+-			}
+-			*p = '\0';
+-			name = buf;
+-			while (isspace(*name)) {
+-				name++;
+-			}
+-
+-			/* 
+-		 	 * Copy our name into our interface structure.
+-		 	 */
+-			len = p - name;
+-			if (len >= sizeof(info->name)) {
+-				*err = 1;
+-				log_error("Interface name '%s' too long", name);
+-				return 0;
+-			}
+-			strcpy(info->name, name);
+-
+-#ifdef ALIAS_NAMED_PERMUTED
+-			/* interface aliases look like "eth0:1" or "wlan1:3" */
+-			s = strchr(info->name, ':');
+-			if (s != NULL) {
+-				*s = '\0';
+-			}
+-#endif
+-
+-#ifdef SKIP_DUMMY_INTERFACES
+-		} while (strncmp(info->name, "dummy", 5) == 0);
+-#else
+-		} while (0);
+-#endif
+-
+-		memset(&tmp, 0, sizeof(tmp));
+-		strcpy(tmp.ifr_name, name);
+-		if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) {
+-			if (errno == EADDRNOTAVAIL) {
+-				continue;
+-			}
+-			log_error("Error getting interface address "
+-				  "for '%s'; %m", name);
+-			*err = 1;
+-			return 0;
+-		}
+-		memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
+-
+-		memset(&tmp, 0, sizeof(tmp));
+-		strcpy(tmp.ifr_name, name);
+-		if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
+-			log_error("Error getting interface flags for '%s'; %m", 
+-			  	name);
+-			*err = 1;
+-			return 0;
+-		}
+-		info->flags = tmp.ifr_flags;
+-
+-		*err = 0;
+-		return 1;
+-	}
+-}
+-
+-#ifdef DHCPv6
+-/*
+- * Read our IPv6 interfaces from /proc/net/if_inet6.
+- *
+- * The file looks something like this:
+- *
+- * fe80000000000000025056fffec00008 05 40 20 80   vmnet8
+- * 00000000000000000000000000000001 01 80 10 80       lo
+- * fe80000000000000025056fffec00001 06 40 20 80   vmnet1
+- * 200108881936000202166ffffe497d9b 03 40 00 00     eth1
+- * fe8000000000000002166ffffe497d9b 03 40 20 80     eth1
+- *
+- * We get IPv6 address from the start, the interface name from the end, 
+- * and ioctl() to get flags.
+- */
+-static int
+-next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
+-	char buf[256];
+-	int len;
+-	char *p;
+-	char *name;
+-	int i;
+-	struct sockaddr_in6 addr;
+-	struct ifreq tmp;
+-
+-	do {
+-		/*
+-		 *  Read the next line in the file.
+-		 */
+-		if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) {
+-			if (ferror(ifaces->fp6)) {
+-				*err = 1;
+-				log_error("Error reading IPv6 "
+-					  "interface information");
+-			} else {
+-				*err = 0;
+-			}
+-			return 0;
+-		}
+-
+-		/*
+-		 * Make sure the line is a nice, newline-terminated line.
+-		 */
+-		len = strlen(buf);
+-		if ((len <= 0) || (buf[len-1] != '\n')) { 
+-			log_error("Bad line reading IPv6 "
+-				  "interface information");
+-			*err = 1;
+-			return 0;
+-		}
+-
+-		/*
+- 		 * Figure out our name.
+- 		 */
+-		buf[--len] = '\0';
+-		p = strrchr(buf, ' ');
+-		if (p == NULL) {
+-			log_error("Bad line reading IPv6 interface "
+-			          "information (no space)");
+-			*err = 1;
+-			return 0;
+-		}
+-		name = p+1;
+-
+-		/* 
+- 		 * Copy our name into our interface structure.
+- 		 */
+-		len = strlen(name);
+-		if (len >= sizeof(info->name)) {
+-			*err = 1;
+-			log_error("IPv6 interface name '%s' too long", name);
+-			return 0;
+-		}
+-		strcpy(info->name, name);
+-
+-#ifdef SKIP_DUMMY_INTERFACES
+-	} while (strncmp(info->name, "dummy", 5) == 0);
+-#else
+-	} while (0);
+-#endif
+-
+-	/*
+-	 * Double-check we start with the IPv6 address.
+-	 */
+-	for (i=0; i<32; i++) {
+-		if (!isxdigit(buf[i]) || isupper(buf[i])) {
+-			*err = 1;
+-			log_error("Bad line reading IPv6 interface address "
+-				  "for '%s'", name);
+-			return 0;
+-		}
+-	}
+-
+-	/* 
+-	 * Load our socket structure.
+-	 */
+-	memset(&addr, 0, sizeof(addr));
+-	addr.sin6_family = AF_INET6;
+-	for (i=0; i<16; i++) {
+-		unsigned char byte;
+-                static const char hex[] = "0123456789abcdef";
+-                byte = ((index(hex, buf[i * 2]) - hex) << 4) |
+-			(index(hex, buf[i * 2 + 1]) - hex);
+-		addr.sin6_addr.s6_addr[i] = byte;
+-	}
+-	memcpy(&info->addr, &addr, sizeof(addr));
+-
+-	/*
+-	 * Get our flags.
+-	 */
+-	memset(&tmp, 0, sizeof(tmp));
+-	strcpy(tmp.ifr_name, name);
+-	if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
+-		log_error("Error getting interface flags for '%s'; %m", name);
+-		*err = 1;
+-		return 0;
+-	}
+-	info->flags = tmp.ifr_flags;
+-
+-	*err = 0;
+-	return 1;
+-}
+-#endif /* DHCPv6 */
+-
+-/*
+- * Retrieve the next interface.
+- *
+- * Returns information in the info structure. 
+- * Sets err to 1 if there is an error, otherwise 0.
+- */
+-int
+-next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
+-	if (next_iface4(info, err, ifaces)) {
+-		return 1;
+-	}
+-#ifdef DHCPv6
+-	if (!(*err) && ifaces->fp6) {
+-		if (local_family == AF_INET6)
+-			return next_iface6(info, err, ifaces);
+-	}
+-#endif
+-	return 0;
+-}
+-
+-/*
+- * End scan of interfaces.
+- */
+-void
+-end_iface_scan(struct iface_conf_list *ifaces) {
+-	fclose(ifaces->fp);
+-	ifaces->fp = NULL;
+-	close(ifaces->sock);
+-	ifaces->sock = -1;
+-#ifdef DHCPv6
+-	if (local_family == AF_INET6) {
+-		if (ifaces->fp6)
+-			fclose(ifaces->fp6);
+-		ifaces->fp6 = NULL;
+-	}
+-#endif
+-}
+ #else
+ 
+ /* 
+  * BSD support
+  * -----------
+  *
+- * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs() 
++ * FreeBSD, NetBSD, OpenBSD, OS X and Linux all have the getifaddrs() 
+  * function.
+  *
+  * The getifaddrs() man page describes the use.
+@@ -826,7 +445,12 @@ next_iface(struct iface_info *info, int
+ 	}
+ 	strcpy(info->name, ifaces->next->ifa_name);
+ 	memcpy(&info->addr, ifaces->next->ifa_addr, 
++#if __linux
++	       (ifaces->next->ifa_addr->sa_family== AF_INET) ?
++		sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
++#else
+ 	       ifaces->next->ifa_addr->sa_len);
++#endif
+ 	info->flags = ifaces->next->ifa_flags;
+ 	ifaces->next = ifaces->next->ifa_next;
+ 	*err = 0;
diff --git a/dhcp.spec b/dhcp.spec
index 7eebf85..9fc4a00 100644
--- a/dhcp.spec
+++ b/dhcp.spec
@@ -22,7 +22,7 @@
 Summary:  Dynamic host configuration protocol software
 Name:     dhcp
 Version:  4.2.3
-Release:  19.%{patchver}%{?dist}
+Release:  20.%{patchver}%{?dist}
 # NEVER CHANGE THE EPOCH on this package.  The previous maintainer (prior to
 # dcantrell maintaining the package) made incorrect use of the epoch and
 # that's why it is at 12 now.  It should have never been used, but it was.
@@ -74,6 +74,7 @@ Patch35:  dhcp-4.2.2-gpxe-cid.patch
 Patch36:  dhcp-4.2.2-systemtap.patch
 Patch37:  dhcp-4.2.3-dhclient-decline-onetry.patch
 Patch38:  dhcp-4.2.3-P2-log_perror.patch
+Patch39:  dhcp-4.2.3-P2-getifaddrs.patch
 
 BuildRequires: autoconf
 BuildRequires: automake
@@ -305,6 +306,9 @@ rm bind/bind.tar.gz
 # (Submitted to dhcp-bugs at isc.org - [ISC-Bugs #28049])
 %patch38 -p1 -b .log_perror
 
+# Use getifaddrs() to scan for interfaces on Linux (#449946)
+%patch39 -p1 -b .getifaddrs
+
 # Copy in the Fedora/RHEL dhclient script
 %{__install} -p -m 0755 %{SOURCE1} client/scripts/linux
 %{__install} -p -m 0644 %{SOURCE2} .
@@ -612,6 +616,9 @@ fi
 
 
 %changelog
+* Wed Mar 21 2012 Jiri Popelka <jpopelka at redhat.com> - 12:4.2.3-20.P2
+- use getifaddrs() to scan for interfaces on Linux (#449946)
+
 * Wed Feb 22 2012 Jiri Popelka <jpopelka at redhat.com> - 12:4.2.3-19.P2
 - don't send log messages to the standard error descriptor by default (#790387)
 


More information about the scm-commits mailing list