diff options
author | Guy Harris <guy@alum.mit.edu> | 2016-06-28 02:29:46 -0700 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2016-06-28 02:30:09 -0700 |
commit | 01dabcda25ed695976e5c844cdd7fc6875a17bf6 (patch) | |
tree | 1942c269617b36aa4dcb03ce42f4cf26da8e599c /pcap-dlpi.c | |
parent | 71d90a93c5cb7f15e10254d6ee711f1f690b0a9c (diff) |
Let the platform decide how to check capturable interfaces.
(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.
Diffstat (limited to 'pcap-dlpi.c')
-rw-r--r-- | pcap-dlpi.c | 212 |
1 files changed, 137 insertions, 75 deletions
diff --git a/pcap-dlpi.c b/pcap-dlpi.c index 201b2b2b..144160e2 100644 --- a/pcap-dlpi.c +++ b/pcap-dlpi.c @@ -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 |