429 lines
10 KiB
Diff
429 lines
10 KiB
Diff
diff -up dhcp-4.3.1b1/common/discover.c.AyFwkY dhcp-4.3.1b1/common/discover.c
|
|
--- dhcp-4.3.1b1/common/discover.c.AyFwkY 2014-07-02 19:58:38.000000000 +0200
|
|
+++ dhcp-4.3.1b1/common/discover.c 2014-07-10 17:58:21.588696480 +0200
|
|
@@ -373,391 +373,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[IF_LINE_LENGTH];
|
|
- int len;
|
|
- int i;
|
|
-
|
|
- ifaces->fp = fopen("/proc/net/dev", "r");
|
|
- 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) {
|
|
- ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
|
|
- 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;
|
|
- }
|
|
- }
|
|
-#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[IF_LINE_LENGTH];
|
|
- 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[IF_LINE_LENGTH];
|
|
- 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)) {
|
|
- 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) {
|
|
- 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.
|
|
@@ -805,6 +427,8 @@ begin_iface_scan(struct iface_conf_list
|
|
*/
|
|
int
|
|
next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
|
+ size_t sa_len = 0;
|
|
+
|
|
if (ifaces->next == NULL) {
|
|
*err = 0;
|
|
return 0;
|
|
@@ -816,8 +440,20 @@ next_iface(struct iface_info *info, int
|
|
return 0;
|
|
}
|
|
strcpy(info->name, ifaces->next->ifa_name);
|
|
- memcpy(&info->addr, ifaces->next->ifa_addr,
|
|
- ifaces->next->ifa_addr->sa_len);
|
|
+
|
|
+ memset(&info->addr, 0 , sizeof(info->addr));
|
|
+
|
|
+ if (ifaces->next->ifa_addr != NULL) {
|
|
+#ifdef HAVE_SA_LEN
|
|
+ sa_len = ifaces->next->ifa_addr->sa_len;
|
|
+#else
|
|
+ if (ifaces->next->ifa_addr->sa_family == AF_INET)
|
|
+ sa_len = sizeof(struct sockaddr_in);
|
|
+ else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
|
|
+ sa_len = sizeof(struct sockaddr_in6);
|
|
+#endif
|
|
+ memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
|
|
+ }
|
|
info->flags = ifaces->next->ifa_flags;
|
|
ifaces->next = ifaces->next->ifa_next;
|
|
*err = 0;
|