]> The Tcpdump Group git mirrors - libpcap/commitdiff
Scan /proc/net/dev on Linux regardless of how we get the interface list.
authorGuy Harris <[email protected]>
Sun, 10 Jan 2010 02:46:02 +0000 (18:46 -0800)
committerGuy Harris <[email protected]>
Sun, 10 Jan 2010 02:46:02 +0000 (18:46 -0800)
It's a Linuxism, so it's not necessary on other platforms, and is useful
even if we have getifaddrs().

fad-gifc.c
pcap-linux.c

index 9d96130b9738ced090bd17f8acb02eece83b48db..d0a2e99e0f84f88167b5e51e7915f0b3d17736a2 100644 (file)
@@ -122,136 +122,6 @@ struct rtentry;           /* declarations in <net/if.h> */
  */
 #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) {
index 22339d6e9a58899b9b739b7ed0072e80924a44ca..08bd910ebfb688704fbe6e9f3a44bfb5e495ad2e 100644 (file)
@@ -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