]> The Tcpdump Group git mirrors - libpcap/commitdiff
Let the platform decide how to check capturable interfaces.
authorGuy Harris <[email protected]>
Tue, 28 Jun 2016 09:29:46 +0000 (02:29 -0700)
committerGuy Harris <[email protected]>
Tue, 28 Jun 2016 09:30:09 +0000 (02:30 -0700)
(Git's annoying policy of expecting a short one-line description of every
change means that the first line isn't very explanatory.)

Make pcap_findalldevs_interfaces() take as an argument a function that's
used to check whether an interface can be captured on or not, rather
than doing the check by trying to open the device for capturing.

This lets pcap_findalldevs() find interfaces even if you don't have
permission to capture on them; that way, instead of users saying "why
isn't {tcpdump -D, tshark -D, dumpcap -D, Wireshark, etc.} showing me
any interfaces?", they'll say "why am I getting a 'you don't have
permissions' error when I try to capture on this interface?", which is a
better description of the underlying problem.

On some platforms, it also avoids a bunch of extra work when getting a
list of interfaces.

12 files changed:
fad-getad.c
fad-gifc.c
fad-glifc.c
pcap-bpf.c
pcap-dlpi.c
pcap-int.h
pcap-libdlpi.c
pcap-linux.c
pcap-nit.c
pcap-pf.c
pcap-snit.c
pcap-snoop.c

index ec77f334ff619fc5db78a444137f56ea5ce6f9aa..b67b5cdcd46aa9c2c34dc508e62c1d637555d8c1 100644 (file)
@@ -144,7 +144,8 @@ get_sa_len(struct sockaddr *addr)
  * could be opened.
  */
 int
-pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
+pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf,
+    int (*check_usable)(const char *))
 {
        pcap_if_t *devlist = NULL;
        struct ifaddrs *ifap, *ifa;
@@ -173,6 +174,45 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
                return (-1);
        }
        for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+               /*
+                * If this entry has a colon followed by a number at
+                * the end, we assume it's a logical interface.  Those
+                * are just the way you assign multiple IP addresses to
+                * a real interface on Linux, so an entry for a logical
+                * interface should be treated like the entry for the
+                * real interface; we do that by stripping off the ":"
+                * and the number.
+                *
+                * XXX - should we do this only on Linux?
+                */
+               p = strchr(ifa->ifa_name, ':');
+               if (p != NULL) {
+                       /*
+                        * We have a ":"; is it followed by a number?
+                        */
+                       q = p + 1;
+                       while (isdigit((unsigned char)*q))
+                               q++;
+                       if (*q == '\0') {
+                               /*
+                                * All digits after the ":" until the end.
+                                * Strip off the ":" and everything after
+                                * it.
+                                */
+                              *p = '\0';
+                       }
+               }
+
+               /*
+                * Can we capture on this device?
+                */
+               if (!(*check_usable)(ifa->ifa_name)) {
+                       /*
+                        * No.
+                        */
+                       continue;
+               }
+
                /*
                 * "ifa_addr" was apparently null on at least one
                 * interface on some system.  Therefore, we supply
@@ -222,35 +262,6 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
                        dstaddr_size = 0;
                }
 
-               /*
-                * If this entry has a colon followed by a number at
-                * the end, we assume it's a logical interface.  Those
-                * are just the way you assign multiple IP addresses to
-                * a real interface on Linux, so an entry for a logical
-                * interface should be treated like the entry for the
-                * real interface; we do that by stripping off the ":"
-                * and the number.
-                *
-                * XXX - should we do this only on Linux?
-                */
-               p = strchr(ifa->ifa_name, ':');
-               if (p != NULL) {
-                       /*
-                        * We have a ":"; is it followed by a number?
-                        */
-                       q = p + 1;
-                       while (isdigit((unsigned char)*q))
-                               q++;
-                       if (*q == '\0') {
-                               /*
-                                * All digits after the ":" until the end.
-                                * Strip off the ":" and everything after
-                                * it.
-                                */
-                              *p = '\0';
-                       }
-               }
-
                /*
                 * Add information for this address to the list.
                 */
index 9627a0b038aa24919e0636e0a3db6942b9edb0c3..8d6bb63e6925bd3009a683d5d716c899ae1f2e65 100644 (file)
@@ -132,7 +132,8 @@ struct rtentry;             /* declarations in <net/if.h> */
  * we already have that.
  */
 int
-pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
+pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf,
+    int (*check_usable)(const char *))
 {
        pcap_if_t *devlist = NULL;
        register int fd;
@@ -236,6 +237,16 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
                if (strncmp(ifrp->ifr_name, "dummy", 5) == 0)
                        continue;
 
+               /*
+                * Can we capture on this device?
+                */
+               if (!(*check_usable)(ifrp->ifr_name)) {
+                       /*
+                        * No.
+                        */
+                       continue;
+               }
+
                /*
                 * Get the flags for this interface.
                 */
index 9107b44e3a2adbc5b17209dc19c67494a741ff9a..5830628ba05854789c187122075e367b1f9952a3 100644 (file)
@@ -75,7 +75,8 @@ struct rtentry;               /* declarations in <net/if.h> */
  * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
  */
 int
-pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
+pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf,
+    int (*check_usable)(const char *))
 {
        pcap_if_t *devlist = NULL;
        register int fd4, fd6, fd;
@@ -164,14 +165,6 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
        ifend = (struct lifreq *)(buf + ifc.lifc_len);
 
        for (; ifrp < ifend; ifrp++) {
-               /*
-                * IPv6 or not?
-                */
-               if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
-                       fd = fd6;
-               else
-                       fd = fd4;
-
                /*
                 * Skip entries that begin with "dummy".
                 * XXX - what are these?  Is this Linux-specific?
@@ -202,6 +195,24 @@ pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
                }
 #endif
 
+               /*
+                * Can we capture on this device?
+                */
+               if (!(*check_usable)(ifrp->lifr_name)) {
+                       /*
+                        * No.
+                        */
+                       continue;
+               }
+
+               /*
+                * IPv6 or not?
+                */
+               if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
+                       fd = fd6;
+               else
+                       fd = fd4;
+
                /*
                 * Get the flags for this interface.
                 */
index ea9f67ae3f7f3fc58d9878f1ed61e02039884ae6..57e40fe2fe5a0c3410c9d646ca46d3eeed96185f 100644 (file)
@@ -447,7 +447,7 @@ pcap_create_interface(const char *device, char *ebuf)
  * On failure, returns a PCAP_ERROR_ value, and sets p->errbuf.
  */
 static int
-bpf_open(pcap_t *p)
+bpf_open(char *errbuf)
 {
        int fd;
 #ifdef HAVE_CLONING_BPF
@@ -463,7 +463,7 @@ bpf_open(pcap_t *p)
         * and create the BPF device entries, if they don't
         * already exist.
         */
-       if (bpf_load(p->errbuf) == PCAP_ERROR)
+       if (bpf_load(errbuf) == PCAP_ERROR)
                return (PCAP_ERROR);
 #endif
 
@@ -474,7 +474,7 @@ bpf_open(pcap_t *p)
                        fd = PCAP_ERROR_PERM_DENIED;
                else
                        fd = PCAP_ERROR;
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
                  "(cannot open device) %s: %s", device, pcap_strerror(errno));
        }
 #else
@@ -516,7 +516,7 @@ bpf_open(pcap_t *p)
                                 * means we probably have no BPF
                                 * devices.
                                 */
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "(there are no BPF devices)");
                        } else {
                                /*
@@ -525,7 +525,7 @@ bpf_open(pcap_t *p)
                                 * devices, but all the ones
                                 * that exist are busy.
                                 */
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
                                    "(all BPF devices are busy)");
                        }
                        break;
@@ -537,7 +537,7 @@ bpf_open(pcap_t *p)
                         * if any.
                         */
                        fd = PCAP_ERROR_PERM_DENIED;
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "(cannot open BPF device) %s: %s", device,
                            pcap_strerror(errno));
                        break;
@@ -547,7 +547,7 @@ bpf_open(pcap_t *p)
                         * Some other problem.
                         */
                        fd = PCAP_ERROR;
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
                            "(cannot open BPF device) %s: %s", device,
                            pcap_strerror(errno));
                        break;
@@ -558,6 +558,63 @@ bpf_open(pcap_t *p)
        return (fd);
 }
 
+/*
+ * Open and bind to a device; used if we're not actually going to use
+ * the device, but are just testing whether it can be opened, or opening
+ * it to get information about it.
+ *
+ * Returns an error code on failure (always negative), and an FD for
+ * the now-bound BPF device on success (always non-negative).
+ */
+static int
+bpf_open_and_bind(const char *name, char *errbuf)
+{
+       int fd;
+       struct ifreq ifr;
+
+       fd = bpf_open(errbuf);
+       if (fd < 0)
+               return (fd);    /* fd is the appropriate error code */
+
+       /*
+        * Now bind to the device.
+        */
+       (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+               switch (errno) {
+
+               case ENXIO:
+                       /*
+                        * There's no such device.
+                        */
+                       close(fd);
+                       return (PCAP_ERROR_NO_SUCH_DEVICE);
+
+               case ENETDOWN:
+                       /*
+                        * Return a "network down" indication, so that
+                        * the application can report that rather than
+                        * saying we had a mysterious failure and
+                        * suggest that they report a problem to the
+                        * libpcap developers.
+                        */
+                       close(fd);
+                       return (PCAP_ERROR_IFACE_NOT_UP);
+
+               default:
+                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "BIOCSETIF: %s: %s", name, pcap_strerror(errno));
+                       close(fd);
+                       return (PCAP_ERROR);
+               }
+       }
+
+       /*
+        * Success.
+        */
+       return (fd);
+}
+
 #ifdef BIOCGDLTLIST
 static int
 get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
@@ -722,7 +779,7 @@ pcap_can_set_rfmon_bpf(pcap_t *p)
         *
         * First, open a BPF device.
         */
-       fd = bpf_open(p);
+       fd = bpf_open(p->errbuf);
        if (fd < 0)
                return (fd);    /* fd is the appropriate error code */
 
@@ -1543,7 +1600,7 @@ pcap_activate_bpf(pcap_t *p)
        u_int bufmode, zbufmax;
 #endif
 
-       fd = bpf_open(p);
+       fd = bpf_open(p->errbuf);
        if (fd < 0) {
                status = fd;
                goto bad;
@@ -2419,19 +2476,64 @@ pcap_activate_bpf(pcap_t *p)
 }
 
 /*
- * We might have USB sniffing support, so try looking for USB interfaces.
+ * Not all interfaces can be bound to by BPF, so try to bind to
+ * the specified interface; return 0 if we fail with
+ * PCAP_ERROR_NO_SUCH_DEVICE (which means we got an ENXIO when we tried
+ * to bind, which means this interface isn't in the list of interfaces
+ * attached to BPF) and 1 otherwise.
  */
+static int
+check_bpf_bindable(const char *name)
+{
+       int fd;
+       char errbuf[PCAP_ERRBUF_SIZE];
+
+       fd = bpf_open_and_bind(name, errbuf);
+       if (fd < 0) {
+               /*
+                * Error - was it PCAP_ERROR_NO_SUCH_DEVICE?
+                */
+               if (fd == PCAP_ERROR_NO_SUCH_DEVICE) {
+                       /*
+                        * Yes, so we can't bind to this because it's
+                        * not something supported by BPF.
+                        */
+                       return (0);
+               }
+               /*
+                * No, so we don't know whether it's supported or not;
+                * say it is, so that the user can at least try to
+                * open it and report the error (which is probably
+                * "you don't have permission to open BPF devices";
+                * reporting those interfaces means users will ask
+                * "why am I getting a permissions error when I try
+                * to capture" rather than "why am I not seeing any
+                * interfaces", making the underlying problem clearer).
+                */
+               return (1);
+       }
+
+       /*
+        * Success.
+        */
+       close(fd);
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
        /*
         * Get the list of regular interfaces first.
         */
-       if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1)
+       if (pcap_findalldevs_interfaces(alldevsp, errbuf, check_bpf_bindable) == -1)
                return (-1);    /* failure */
 
 #if defined(__FreeBSD__) && defined(SIOCIFCREATE2)
        /*
+        * We might have USB sniffing support, so try looking for USB
+        * interfaces.
+        *
         * We want to report a usbusN device for each USB bus, but
         * usbusN interfaces might, or might not, exist for them -
         * we create one if there isn't already one.
index 201b2b2b47d832fef31288c515e0bf4317331156..144160e2d57de26b447ff2f6e503c96284944e3c 100644 (file)
@@ -331,28 +331,12 @@ pcap_cleanup_dlpi(pcap_t *p)
 }
 
 static int
-pcap_activate_dlpi(pcap_t *p)
+open_dlpi_device(const char *name, int *ppa, char *errbuf)
 {
-#ifdef DL_HP_RAWDLS
-       struct pcap_dlpi *pd = p->priv;
-#endif
-       int status = 0;
-       int retv;
-       register char *cp;
-       int ppa;
-#ifdef HAVE_SOLARIS
-       int isatm = 0;
-#endif
-       register dl_info_ack_t *infop;
-#ifdef HAVE_SYS_BUFMOD_H
-       bpf_u_int32 ss;
-#ifdef HAVE_SOLARIS
-       register char *release;
-       bpf_u_int32 osmajor, osminor, osmicro;
-#endif
-#endif
-       bpf_u_int32 buf[MAXDLBUF];
+       int status;
        char dname[100];
+       char *cp;
+       int fd;
 #ifndef HAVE_DEV_DLPI
        char dname2[100];
 #endif
@@ -361,9 +345,9 @@ pcap_activate_dlpi(pcap_t *p)
        /*
        ** Remove any "/dev/" on the front of the device.
        */
-       cp = strrchr(p->opt.source, '/');
+       cp = strrchr(name, '/');
        if (cp == NULL)
-               strlcpy(dname, p->opt.source, sizeof(dname));
+               strlcpy(dname, name, sizeof(dname));
        else
                strlcpy(dname, cp + 1, sizeof(dname));
 
@@ -371,11 +355,9 @@ pcap_activate_dlpi(pcap_t *p)
         * Split the device name into a device type name and a unit number;
         * chop off the unit number, so "dname" is just a device type name.
         */
-       cp = split_dname(dname, &ppa, p->errbuf);
-       if (cp == NULL) {
-               status = PCAP_ERROR_NO_SUCH_DEVICE;
-               goto bad;
-       }
+       cp = split_dname(dname, ppa, errbuf);
+       if (cp == NULL)
+               return (PCAP_ERROR_NO_SUCH_DEVICE);
        *cp = '\0';
 
        /*
@@ -390,39 +372,24 @@ pcap_activate_dlpi(pcap_t *p)
         * device number, rather than hardwiring "/dev/dlpi".
         */
        cp = "/dev/dlpi";
-       if ((p->fd = open(cp, O_RDWR)) < 0) {
+       if ((fd = open(cp, O_RDWR)) < 0) {
                if (errno == EPERM || errno == EACCES)
                        status = PCAP_ERROR_PERM_DENIED;
                else
                        status = PCAP_ERROR;
-               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
                    "%s: %s", cp, pcap_strerror(errno));
-               goto bad;
+               return (status);
        }
 
-#ifdef DL_HP_RAWDLS
-       /*
-        * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and
-        * receiving packets on the same descriptor - you need separate
-        * descriptors for sending and receiving, bound to different SAPs.
-        *
-        * If the open fails, we just leave -1 in "pd->send_fd" and reject
-        * attempts to send packets, just as if, in pcap-bpf.c, we fail
-        * to open the BPF device for reading and writing, we just try
-        * to open it for reading only and, if that succeeds, just let
-        * the send attempts fail.
-        */
-       pd->send_fd = open(cp, O_RDWR);
-#endif
-
        /*
         * Get a table of all PPAs for that device, and search that
         * table for the specified device type name and unit number.
         */
-       ppa = get_dlpi_ppa(p->fd, dname, ppa, p->errbuf);
+       *ppa = get_dlpi_ppa(fd, dname, *ppa, errbuf);
        if (ppa < 0) {
-               status = ppa;
-               goto bad;
+               close(fd);
+               return (ppa);
        }
 #else
        /*
@@ -431,21 +398,19 @@ pcap_activate_dlpi(pcap_t *p)
         * otherwise, concatenate the device directory name and the
         * device name.
         */
-       if (*p->opt.source == '/')
-               strlcpy(dname, p->opt.source, sizeof(dname));
+       if (*name == '/')
+               strlcpy(dname, name, sizeof(dname));
        else
                pcap_snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
-                   p->opt.source);
+                   name);
 
        /*
         * Get the unit number, and a pointer to the end of the device
         * type name.
         */
-       cp = split_dname(dname, &ppa, p->errbuf);
-       if (cp == NULL) {
-               status = PCAP_ERROR_NO_SUCH_DEVICE;
-               goto bad;
-       }
+       cp = split_dname(dname, ppa, errbuf);
+       if (cp == NULL)
+               return (PCAP_ERROR_NO_SUCH_DEVICE);
 
        /*
         * Make a copy of the device pathname, and then remove the unit
@@ -455,19 +420,19 @@ pcap_activate_dlpi(pcap_t *p)
        *cp = '\0';
 
        /* Try device without unit number */
-       if ((p->fd = open(dname, O_RDWR)) < 0) {
+       if ((fd = open(dname, O_RDWR)) < 0) {
                if (errno != ENOENT) {
                        if (errno == EPERM || errno == EACCES)
                                status = PCAP_ERROR_PERM_DENIED;
                        else
                                status = PCAP_ERROR;
-                       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
+                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
                            pcap_strerror(errno));
-                       goto bad;
+                       return (status);
                }
 
                /* Try again with unit number */
-               if ((p->fd = open(dname2, O_RDWR)) < 0) {
+               if ((fd = open(dname2, O_RDWR)) < 0) {
                        if (errno == ENOENT) {
                                status = PCAP_ERROR_NO_SUCH_DEVICE;
 
@@ -482,32 +447,79 @@ pcap_activate_dlpi(pcap_t *p)
                                 * found" with the device name, so people
                                 * don't get confused and think, for example,
                                 * that if they can't capture on "lo0"
-                                * on Solaris the fix is to change libpcap
-                                * (or the application that uses it) to
-                                * look for something other than "/dev/lo0",
-                                * as the fix is to look for an operating
-                                * system other than Solaris - you just
-                                * *can't* capture on a loopback interface
-                                * on Solaris, the lack of a DLPI device
-                                * for the loopback interface is just a
-                                * symptom of that inability.
+                                * on Solaris prior to Solaris 11 the fix
+                                * is to change libpcap (or the application
+                                * that uses it) to look for something other
+                                * than "/dev/lo0", as the fix is to use
+                                * Solaris 11 or some operating system
+                                * other than Solaris - you just *can't*
+                                * capture on a loopback interface
+                                * on Solaris prior to Solaris 11, the lack
+                                * of a DLPI device for the loopback
+                                * interface is just a symptom of that
+                                * inability.
                                 */
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-                                   "%s: No DLPI device found", p->opt.source);
+                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                                   "%s: No DLPI device found", name);
                        } else {
                                if (errno == EPERM || errno == EACCES)
                                        status = PCAP_ERROR_PERM_DENIED;
                                else
                                        status = PCAP_ERROR;
-                               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+                               pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
                                    dname2, pcap_strerror(errno));
                        }
-                       goto bad;
+                       return (status);
                }
                /* XXX Assume unit zero */
-               ppa = 0;
+               *ppa = 0;
        }
 #endif
+       return (fd);
+}
+
+static int
+pcap_activate_dlpi(pcap_t *p)
+{
+#ifdef DL_HP_RAWDLS
+       struct pcap_dlpi *pd = p->priv;
+#endif
+       int status = 0;
+       int retv;
+       int ppa;
+#ifdef HAVE_SOLARIS
+       int isatm = 0;
+#endif
+       register dl_info_ack_t *infop;
+#ifdef HAVE_SYS_BUFMOD_H
+       bpf_u_int32 ss;
+#ifdef HAVE_SOLARIS
+       register char *release;
+       bpf_u_int32 osmajor, osminor, osmicro;
+#endif
+#endif
+       bpf_u_int32 buf[MAXDLBUF];
+
+       p->fd = open_dlpi_device(p->opt.source, &ppa, p->errbuf);
+       if (p->fd < 0) {
+               status = p->fd;
+               goto bad;
+       }
+
+#ifdef DL_HP_RAWDLS
+       /*
+        * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and
+        * receiving packets on the same descriptor - you need separate
+        * descriptors for sending and receiving, bound to different SAPs.
+        *
+        * If the open fails, we just leave -1 in "pd->send_fd" and reject
+        * attempts to send packets, just as if, in pcap-bpf.c, we fail
+        * to open the BPF device for reading and writing, we just try
+        * to open it for reading only and, if that succeeds, just let
+        * the send attempts fail.
+        */
+       pd->send_fd = open("/dev/dlpi", O_RDWR);
+#endif
 
        /*
        ** Attach if "style 2" provider
@@ -960,6 +972,56 @@ dlpromiscon(pcap_t *p, bpf_u_int32 level)
        return (0);
 }
 
+/*
+ * Not all interfaces are DLPI interfaces, and thus not all interfaces
+ * can be opened with DLPI (for example, the loopback interface is not
+ * a DLPI interface on Solaris prior to Solaris 11), so try to open
+ * the specified interface; return 0 if we fail with PCAP_ERROR_NO_SUCH_DEVICE
+ * and 1 otherwise.
+ */
+static int
+is_dlpi_interface(const char *name)
+{
+       int fd;
+       int ppa;
+       char errbuf[PCAP_ERRBUF_SIZE];
+
+       fd = open_dlpi_device(name, &ppa, errbuf);
+       if (fd < 0) {
+               /*
+                * Error - was it PCAP_ERROR_NO_SUCH_DEVICE?
+                */
+               if (fd == PCAP_ERROR_NO_SUCH_DEVICE) {
+                       /*
+                        * Yes, so we can't open this because it's
+                        * not a DLPI interface.
+                        */
+                       return (0);
+               }
+               /*
+                * No, so, in the case where there's a single DLPI
+                * device for all interfaces of this type ("style
+                * 2" providers?), we don't know whether it's a DLPI
+                * interface or not, as we didn't try an attach.
+                * Say it is a DLPI device, so that the user can at
+                * least try to open it and report the error (which
+                * is probably "you don't have permission to open that
+                * DLPI device"; reporting those interfaces means
+                * users will ask "why am I getting a permissions error
+                * when I try to capture" rather than "why am I not
+                * seeing any interfaces", making the underlying problem
+                * clearer).
+                */
+               return (1);
+       }
+
+       /*
+        * Success.
+        */
+       close(fd);
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
@@ -977,7 +1039,7 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
        /*
         * Get the list of regular interfaces first.
         */
-       if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1)
+       if (pcap_findalldevs_interfaces(alldevsp, errbuf, is_dlpi_interface) == -1)
                return (-1);    /* failure */
 
 #ifdef HAVE_SOLARIS
index 5adf25f787903906183c49675ea41d857566656a..f4b3ca4d94524cfa33e5ea08803c36a8aebeca54 100644 (file)
@@ -468,7 +468,8 @@ int pcap_check_activated(pcap_t *);
  */
 int    pcap_platform_finddevs(pcap_if_t **, char *);
 #if !defined(_WIN32) && !defined(MSDOS)
-int    pcap_findalldevs_interfaces(pcap_if_t **, char *);
+int    pcap_findalldevs_interfaces(pcap_if_t **, char *,
+           int (*)(const char *));
 #endif
 int    add_addr_to_iflist(pcap_if_t **, const char *, bpf_u_int32,
            struct sockaddr *, size_t, struct sockaddr *, size_t,
index 0c69898da01f760755db3f72198f73c715b43cfa..0e4aff59c05e0245ff15b8ba7b3f43d3745f4516 100644 (file)
@@ -265,6 +265,17 @@ dlpromiscon(pcap_t *p, bpf_u_int32 level)
        return (0);
 }
 
+/*
+ * Presumably everything returned by dlpi_walk() is a DLPI device,
+ * so there's no work to be done here to check whether name refers
+ * to a DLPI device.
+ */
+static int
+is_dlpi_interface(const char *name _U_)
+{
+       return (1);
+}
+
 /*
  * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find
  * network links that are plumbed and are up. dlpi_walk(3DLPI) will find
@@ -282,7 +293,7 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
        /*
         * Get the list of regular interfaces first.
         */
-       if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1)
+       if (pcap_findalldevs_interfaces(alldevsp, errbuf, is_dlpi_interface) == -1)
                return (-1);    /* failure */
 
        /* dlpi_walk() for loopback will be added here. */
index 104546e9697cd9e9e5fe18fa1147c27a82bf386e..4aeb7ec3664b677e27d160712e4be8333cfae6b4 100644 (file)
@@ -2505,6 +2505,15 @@ scan_proc_net_dev(pcap_if_t **devlistp, char *errbuf)
  */
 static const char any_descr[] = "Pseudo-device that captures on all interfaces";
 
+/*
+ * A SOCK_PACKET or PF_PACKET socket can be bound to any network interface.
+ */
+static int
+can_be_bound(const char *name _U_)
+{
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
@@ -2513,7 +2522,7 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
        /*
         * Get the list of regular interfaces first.
         */
-       if (pcap_findalldevs_interfaces(alldevsp, errbuf) == -1)
+       if (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound) == -1)
                return (-1);    /* failure */
 
        /*
index db1be00c1a8468e14d8102a25449323702d9afe3..2aa84ba465ed011faf0a91a9da2cace6005a3255 100644 (file)
@@ -288,6 +288,13 @@ pcap_activate_nit(pcap_t *p)
        (void)strncpy(snit.snit_ifname, p->opt.source, NITIFSIZ);
 
        if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
+               /*
+                * XXX - there's probably a particular bind error that
+                * means "there's no such device" and a particular bind
+                * error that means "that device doesn't support NIT";
+                * they might be the same error, if they both end up
+                * meaning "NIT doesn't know about that device".
+                */
                pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
                goto bad;
@@ -360,8 +367,18 @@ pcap_create_interface(const char *device, char *ebuf)
        return (p);
 }
 
+/*
+ * XXX - there's probably a particular bind error that means "that device
+ * doesn't support NIT"; if so, we should try a bind and use that.
+ */
+static int
+can_be_bound(const char *name _U_)
+{
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
-       return (pcap_findalldevs_interfaces(alldevsp, errbuf));
+       return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound));
 }
index 0d7a9eb7c0efa71f74001cad96b7186b3dc7870b..33bb7b7c61dfd018a1f7376263b0a274bb9bb28b 100644 (file)
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -321,6 +321,9 @@ pcap_activate_pf(pcap_t *p)
         * its argument, even though it takes a "char *" rather than a
         * "const char *" as its first argument.  That appears to be
         * the case, at least on Digital UNIX 4.0.
+        *
+        * XXX - is there an error that means "no such device"?  Is
+        * there one that means "that device doesn't support pf"?
         */
        p->fd = pfopen(p->opt.source, O_RDWR);
        if (p->fd == -1 && errno == EACCES)
@@ -515,10 +518,20 @@ pcap_create_interface(const char *device, char *ebuf)
        return (p);
 }
 
+/*
+ * XXX - is there an error from pfopen() that means "no such device"?
+ * Is there one that means "that device doesn't support pf"?
+ */
+static int
+can_be_bound(const char *name _U_)
+{
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
-       return (pcap_findalldevs_interfaces(alldevsp, errbuf));
+       return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound));
 }
 
 static int
index 3a50007edfd780e4cac971b936e002ba79b6b217..a1f5e035ce7c9889816f046403f00597c0ba694f 100644 (file)
@@ -354,6 +354,11 @@ pcap_activate_snit(pcap_t *p)
        si.ic_len = sizeof(ifr);
        si.ic_dp = (char *)&ifr;
        if (ioctl(fd, I_STR, (char *)&si) < 0) {
+               /*
+                * XXX - is there an error that means "no such device"?
+                * Is there one that means "that device doesn't support
+                * STREAMS NIT"?
+                */
                pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCBIND: %s: %s",
                        ifr.ifr_name, pcap_strerror(errno));
                goto bad;
@@ -438,8 +443,18 @@ pcap_create_interface(const char *device, char *ebuf)
        return (p);
 }
 
+/*
+ * XXX - there's probably a NIOCBIND error that means "that device
+ * doesn't support NIT"; if so, we should try an NIOCBIND and use that.
+ */
+static int
+can_be_bound(const char *name _U_)
+{
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
-       return (pcap_findalldevs_interfaces(alldevsp, errbuf));
+       return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound));
 }
index 948d38813a061cc3583027dd6856cd32513d78f4..9bf0d261415c7f4919876afbb91938f56f50f78e 100644 (file)
@@ -221,6 +221,13 @@ pcap_activate_snoop(pcap_t *p)
        sr.sr_family = AF_RAW;
        (void)strncpy(sr.sr_ifname, p->opt.source, sizeof(sr.sr_ifname));
        if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) {
+               /*
+                * XXX - there's probably a particular bind error that
+                * means "there's no such device" and a particular bind
+                * error that means "that device doesn't support snoop";
+                * they might be the same error, if they both end up
+                * meaning "snoop doesn't know about that device".
+                */
                pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop bind: %s",
                    pcap_strerror(errno));
                goto bad;
@@ -411,8 +418,18 @@ pcap_create_interface(const char *device, char *ebuf)
        return (p);
 }
 
+/*
+ * XXX - there's probably a particular bind error that means "that device
+ * doesn't support snoop"; if so, we should try a bind and use that.
+ */
+static int
+can_be_bound(const char *name _U_)
+{
+       return (1);
+}
+
 int
 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
-       return (pcap_findalldevs_interfaces(alldevsp, errbuf));
+       return (pcap_findalldevs_interfaces(alldevsp, errbuf, can_be_bound));
 }