From 6831a814896d7f1c31bfa68af85028e8d4182543 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sat, 9 Jan 2010 18:46:02 -0800 Subject: Scan /proc/net/dev on Linux regardless of how we get the interface list. It's a Linuxism, so it's not necessary on other platforms, and is useful even if we have getifaddrs(). --- fad-gifc.c | 144 -------------------------------------------------- pcap-linux.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 144 deletions(-) diff --git a/fad-gifc.c b/fad-gifc.c index 9d96130..d0a2e99 100644 --- a/fad-gifc.c +++ b/fad-gifc.c @@ -122,136 +122,6 @@ struct rtentry; /* declarations in */ */ #define MAX_SA_LEN 255 -#ifdef HAVE_PROC_NET_DEV -/* - * Get from "/proc/net/dev" all interfaces listed there; if they're - * already in the list of interfaces we have, that won't add another - * instance, but if they're not, that'll add them. - * - * We don't bother getting any addresses for them; it appears you can't - * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and, - * although some other types of addresses can be fetched with SIOCGIFADDR, - * we don't bother with them for now. - * - * We also don't fail if we couldn't open "/proc/net/dev"; we just leave - * the list of interfaces as is. - */ -static int -scan_proc_net_dev(pcap_if_t **devlistp, int fd, char *errbuf) -{ - FILE *proc_net_f; - char linebuf[512]; - int linenum; - unsigned char *p; - char name[512]; /* XXX - pick a size */ - char *q, *saveq; - struct ifreq ifrflags; - int ret = 0; - - proc_net_f = fopen("/proc/net/dev", "r"); - if (proc_net_f == NULL) - return (0); - - for (linenum = 1; - fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) { - /* - * Skip the first two lines - they're headers. - */ - if (linenum <= 2) - continue; - - p = &linebuf[0]; - - /* - * Skip leading white space. - */ - while (*p != '\0' && isspace(*p)) - p++; - if (*p == '\0' || *p == '\n') - continue; /* blank line */ - - /* - * Get the interface name. - */ - q = &name[0]; - while (*p != '\0' && !isspace(*p)) { - if (*p == ':') { - /* - * This could be the separator between a - * name and an alias number, or it could be - * the separator between a name with no - * alias number and the next field. - * - * If there's a colon after digits, it - * separates the name and the alias number, - * otherwise it separates the name and the - * next field. - */ - saveq = q; - while (isdigit(*p)) - *q++ = *p++; - if (*p != ':') { - /* - * That was the next field, - * not the alias number. - */ - q = saveq; - } - break; - } else - *q++ = *p++; - } - *q = '\0'; - - /* - * Get the flags for this interface, and skip it if - * it's not up. - */ - strncpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name)); - if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { - if (errno == ENXIO) - continue; - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFFLAGS: %.*s: %s", - (int)sizeof(ifrflags.ifr_name), - ifrflags.ifr_name, - pcap_strerror(errno)); - ret = -1; - break; - } - if (!(ifrflags.ifr_flags & IFF_UP)) - continue; - - /* - * Add an entry for this interface, with no addresses. - */ - if (pcap_add_if(devlistp, name, ifrflags.ifr_flags, NULL, - errbuf) == -1) { - /* - * Failure. - */ - ret = -1; - break; - } - } - if (ret != -1) { - /* - * Well, we didn't fail for any other reason; did we - * fail due to an error reading the file? - */ - if (ferror(proc_net_f)) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Error reading /proc/net/dev: %s", - pcap_strerror(errno)); - ret = -1; - } - } - - (void)fclose(proc_net_f); - return (ret); -} -#endif /* HAVE_PROC_NET_DEV */ - /* * Get a list of all interfaces that are up and that we can open. * Returns -1 on error, 0 otherwise. @@ -537,20 +407,6 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) } } free(buf); - -#ifdef HAVE_PROC_NET_DEV - if (ret != -1) { - /* - * We haven't had any errors yet; now read "/proc/net/dev", - * and add to the list of interfaces all interfaces listed - * there that we don't already have, because, on Linux, - * SIOCGIFCONF reports only interfaces with IPv4 addresses, - * so you need to read "/proc/net/dev" to get the names of - * the rest of the interfaces. - */ - ret = scan_proc_net_dev(&devlist, fd, errbuf); - } -#endif (void)close(fd); if (ret != -1) { diff --git a/pcap-linux.c b/pcap-linux.c index 22339d6..08bd910 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -1774,6 +1774,148 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats) return 0; } +#ifdef HAVE_PROC_NET_DEV +/* + * Get from "/proc/net/dev" all interfaces listed there; if they're + * already in the list of interfaces we have, that won't add another + * instance, but if they're not, that'll add them. + * + * We don't bother getting any addresses for them; it appears you can't + * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and, + * although some other types of addresses can be fetched with SIOCGIFADDR, + * we don't bother with them for now. + * + * We also don't fail if we couldn't open "/proc/net/dev"; we just leave + * the list of interfaces as is. + */ +static int +scan_proc_net_dev(pcap_if_t **devlistp, char *errbuf) +{ + FILE *proc_net_f; + int fd; + char linebuf[512]; + int linenum; + unsigned char *p; + char name[512]; /* XXX - pick a size */ + char *q, *saveq; + struct ifreq ifrflags; + int ret = 0; + + proc_net_f = fopen("/proc/net/dev", "r"); + if (proc_net_f == NULL) + return (0); + + /* + * Create a socket from which to fetch interface information. + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "socket: %s", pcap_strerror(errno)); + return (-1); + } + + for (linenum = 1; + fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) { + /* + * Skip the first two lines - they're headers. + */ + if (linenum <= 2) + continue; + + p = &linebuf[0]; + + /* + * Skip leading white space. + */ + while (*p != '\0' && isspace(*p)) + p++; + if (*p == '\0' || *p == '\n') + continue; /* blank line */ + + /* + * Get the interface name. + */ + q = &name[0]; + while (*p != '\0' && !isspace(*p)) { + if (*p == ':') { + /* + * This could be the separator between a + * name and an alias number, or it could be + * the separator between a name with no + * alias number and the next field. + * + * If there's a colon after digits, it + * separates the name and the alias number, + * otherwise it separates the name and the + * next field. + */ + saveq = q; + while (isdigit(*p)) + *q++ = *p++; + if (*p != ':') { + /* + * That was the next field, + * not the alias number. + */ + q = saveq; + } + break; + } else + *q++ = *p++; + } + *q = '\0'; + + /* + * Get the flags for this interface, and skip it if + * it's not up. + */ + strncpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO) + continue; + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFFLAGS: %.*s: %s", + (int)sizeof(ifrflags.ifr_name), + ifrflags.ifr_name, + pcap_strerror(errno)); + ret = -1; + break; + } + if (!(ifrflags.ifr_flags & IFF_UP)) + continue; + + /* + * Add an entry for this interface, with no addresses. + */ + if (pcap_add_if(devlistp, name, ifrflags.ifr_flags, NULL, + errbuf) == -1) { + /* + * Failure. + */ + ret = -1; + break; + } + } + if (ret != -1) { + /* + * Well, we didn't fail for any other reason; did we + * fail due to an error reading the file? + */ + if (ferror(proc_net_f)) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Error reading /proc/net/dev: %s", + pcap_strerror(errno)); + ret = -1; + } + } + + (void)close(fd); + (void)fclose(proc_net_f); + return (ret); +} +#endif /* HAVE_PROC_NET_DEV */ + /* * Description string for the "any" device. */ @@ -1782,25 +1924,53 @@ static const char any_descr[] = "Pseudo-device that captures on all interfaces"; int pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) { +#ifdef HAVE_PROC_NET_DEV + /* + * Read "/proc/net/dev", and add to the list of interfaces all + * interfaces listed there that we don't already have, because, + * on Linux, SIOCGIFCONF reports only interfaces with IPv4 addresses, + * and even getifaddrs() won't return information about + * interfaces with no addresses, so you need to read "/proc/net/dev" + * to get the names of the rest of the interfaces. + */ + if (scan_proc_net_dev(alldevsp, errbuf) == -1) + return (-1); +#endif + + /* + * Add the "any" device. + */ if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0) return (-1); #ifdef HAVE_DAG_API + /* + * Add DAG devices. + */ if (dag_platform_finddevs(alldevsp, errbuf) < 0) return (-1); #endif /* HAVE_DAG_API */ #ifdef HAVE_SEPTEL_API + /* + * Add Septel devices. + */ if (septel_platform_finddevs(alldevsp, errbuf) < 0) return (-1); #endif /* HAVE_SEPTEL_API */ #ifdef PCAP_SUPPORT_BT + /* + * Add Bluetooth devices. + */ if (bt_platform_finddevs(alldevsp, errbuf) < 0) return (-1); #endif #ifdef PCAP_SUPPORT_USB + /* + * Add USB devices. + */ if (usb_platform_finddevs(alldevsp, errbuf) < 0) return (-1); #endif -- cgit v1.2.3