aboutsummaryrefslogtreecommitdiff
path: root/pcap-dlpi.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2016-06-28 02:29:46 -0700
committerGuy Harris <guy@alum.mit.edu>2016-06-28 02:30:09 -0700
commit01dabcda25ed695976e5c844cdd7fc6875a17bf6 (patch)
tree1942c269617b36aa4dcb03ce42f4cf26da8e599c /pcap-dlpi.c
parent71d90a93c5cb7f15e10254d6ee711f1f690b0a9c (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.c212
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