aboutsummaryrefslogtreecommitdiff
path: root/pcap.c
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2018-07-23 17:26:52 -0700
committerHaibo Huang <hhb@google.com>2018-07-24 09:44:25 -0700
commit165065aed040e9658cb43fc1194d6799c9227043 (patch)
tree8b959bf9d2b44f2b12c86dfdc5810210d587e99e /pcap.c
parentba51ee392e9b2d5dd04faaf695b1da82488d0323 (diff)
downloadlibpcap-165065aed040e9658cb43fc1194d6799c9227043.tar.gz
Update libpcap to 1.9.0
Test: compile Change-Id: I5b036bc4544b3150629b943d3a7896d7dc03fec9
Diffstat (limited to 'pcap.c')
-rw-r--r--pcap.c2390
1 files changed, 2009 insertions, 381 deletions
diff --git a/pcap.c b/pcap.c
index 77a709f8..942c472a 100644
--- a/pcap.c
+++ b/pcap.c
@@ -32,23 +32,28 @@
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
#endif
-#ifdef _WIN32
-#include <pcap-stdinc.h>
-#else /* _WIN32 */
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#elif HAVE_STDINT_H
-#include <stdint.h>
+#include <pcap-types.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#ifndef MSDOS
+#include <sys/file.h>
#endif
-#ifdef HAVE_SYS_BITYPES_H
-#include <sys/bitypes.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
#endif
-#include <sys/types.h>
+
+struct mbuf; /* Squelch compiler warnings on some platforms for */
+struct rtentry; /* declarations in <net/if.h> */
+#include <net/if.h>
+#include <netinet/in.h>
#endif /* _WIN32 */
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -57,6 +62,11 @@
#endif
#include <fcntl.h>
#include <errno.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#else
+#define INT_MAX 2147483647
+#endif
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
@@ -68,6 +78,8 @@
#include "pcap-int.h"
+#include "optimize.h"
+
#ifdef HAVE_DAG_API
#include "pcap-dag.h"
#endif /* HAVE_DAG_API */
@@ -100,13 +112,89 @@
#include "pcap-netfilter-linux.h"
#endif
+#ifdef PCAP_SUPPORT_NETMAP
+#include "pcap-netmap.h"
+#endif
+
#ifdef PCAP_SUPPORT_DBUS
#include "pcap-dbus.h"
#endif
+#ifdef PCAP_SUPPORT_RDMASNIFF
+#include "pcap-rdmasniff.h"
+#endif
+
+#ifdef _WIN32
+/*
+ * DllMain(), required when built as a Windows DLL.
+ */
+BOOL WINAPI DllMain(
+ HANDLE hinstDLL,
+ DWORD dwReason,
+ LPVOID lpvReserved
+)
+{
+ return (TRUE);
+}
+
+/*
+ * Start WinSock.
+ * Exported in case some applications using WinPcap called it,
+ * even though it wasn't exported.
+ */
+int
+wsockinit(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ static int err = -1;
+ static int done = 0;
+
+ if (done)
+ return (err);
+
+ wVersionRequested = MAKEWORD( 1, 1);
+ err = WSAStartup( wVersionRequested, &wsaData );
+ atexit ((void(*)(void))WSACleanup);
+ done = 1;
+
+ if ( err != 0 )
+ err = -1;
+ return (err);
+}
+
+/*
+ * This is the exported function; new programs should call this.
+ */
+int
+pcap_wsockinit(void)
+{
+ return (wsockinit());
+}
+#endif /* _WIN32 */
+
+/*
+ * String containing the library version.
+ * Not explicitly exported via a header file - the right API to use
+ * is pcap_lib_version() - but some programs included it, so we
+ * provide it.
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API char pcap_version[];
+PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION;
+
static int
pcap_not_initialized(pcap_t *pcap)
{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return (PCAP_ERROR);
+ }
/* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
@@ -118,6 +206,12 @@ pcap_not_initialized(pcap_t *pcap)
static void *
pcap_not_initialized_ptr(pcap_t *pcap)
{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return (NULL);
+ }
(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
return (NULL);
@@ -126,6 +220,12 @@ pcap_not_initialized_ptr(pcap_t *pcap)
static HANDLE
pcap_getevent_not_initialized(pcap_t *pcap)
{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return (INVALID_HANDLE_VALUE);
+ }
(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
return (INVALID_HANDLE_VALUE);
@@ -134,6 +234,12 @@ pcap_getevent_not_initialized(pcap_t *pcap)
static u_int
pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return (0);
+ }
(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
return (0);
@@ -142,6 +248,12 @@ pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, in
static PAirpcapHandle
pcap_get_airpcap_handle_not_initialized(pcap_t *pcap)
{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return (NULL);
+ }
(void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
return (NULL);
@@ -190,8 +302,8 @@ pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
*tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
p->tstamp_type_count);
if (*tstamp_typesp == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
return (PCAP_ERROR);
}
(void)memcpy(*tstamp_typesp, p->tstamp_type_list,
@@ -295,8 +407,15 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s));
}
+/*
+ * Implementation of a pcap_if_list_t.
+ */
+struct pcap_if_list {
+ pcap_if_t *beginning;
+};
+
static struct capture_source_type {
- int (*findalldevs_op)(pcap_if_t **, char *);
+ int (*findalldevs_op)(pcap_if_list_t *, char *);
pcap_t *(*create_op)(const char *, char *, int *);
} capture_source_types[] = {
#ifdef HAVE_DAG_API
@@ -323,9 +442,15 @@ static struct capture_source_type {
#ifdef PCAP_SUPPORT_NETFILTER
{ netfilter_findalldevs, netfilter_create },
#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ { pcap_netmap_findalldevs, pcap_netmap_create },
+#endif
#ifdef PCAP_SUPPORT_DBUS
{ dbus_findalldevs, dbus_create },
#endif
+#ifdef PCAP_SUPPORT_RDMASNIFF
+ { rdmasniff_findalldevs, rdmasniff_create },
+#endif
{ NULL, NULL }
};
@@ -339,34 +464,1502 @@ int
pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
{
size_t i;
+ pcap_if_list_t devlist;
/*
* Find all the local network interfaces on which we
* can capture.
*/
- if (pcap_platform_finddevs(alldevsp, errbuf) == -1)
+ devlist.beginning = NULL;
+ if (pcap_platform_finddevs(&devlist, errbuf) == -1) {
+ /*
+ * Failed - free all of the entries we were given
+ * before we failed.
+ */
+ if (devlist.beginning != NULL)
+ pcap_freealldevs(devlist.beginning);
+ *alldevsp = NULL;
return (-1);
+ }
/*
* Ask each of the non-local-network-interface capture
* source types what interfaces they have.
*/
for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) {
- if (capture_source_types[i].findalldevs_op(alldevsp, errbuf) == -1) {
+ if (capture_source_types[i].findalldevs_op(&devlist, errbuf) == -1) {
/*
* We had an error; free the list we've been
* constructing.
*/
- if (*alldevsp != NULL) {
- pcap_freealldevs(*alldevsp);
- *alldevsp = NULL;
+ if (devlist.beginning != NULL)
+ pcap_freealldevs(devlist.beginning);
+ *alldevsp = NULL;
+ return (-1);
+ }
+ }
+
+ /*
+ * Return the first entry of the list of all devices.
+ */
+ *alldevsp = devlist.beginning;
+ return (0);
+}
+
+static struct sockaddr *
+dup_sockaddr(struct sockaddr *sa, size_t sa_length)
+{
+ struct sockaddr *newsa;
+
+ if ((newsa = malloc(sa_length)) == NULL)
+ return (NULL);
+ return (memcpy(newsa, sa, sa_length));
+}
+
+/*
+ * Construct a "figure of merit" for an interface, for use when sorting
+ * the list of interfaces, in which interfaces that are up are superior
+ * to interfaces that aren't up, interfaces that are up and running are
+ * superior to interfaces that are up but not running, and non-loopback
+ * interfaces that are up and running are superior to loopback interfaces,
+ * and interfaces with the same flags have a figure of merit that's higher
+ * the lower the instance number.
+ *
+ * The goal is to try to put the interfaces most likely to be useful for
+ * capture at the beginning of the list.
+ *
+ * The figure of merit, which is lower the "better" the interface is,
+ * has the uppermost bit set if the interface isn't running, the bit
+ * below that set if the interface isn't up, the bit below that set
+ * if the interface is a loopback interface, and the interface index
+ * in the 29 bits below that. (Yes, we assume u_int is 32 bits.)
+ */
+static u_int
+get_figure_of_merit(pcap_if_t *dev)
+{
+ const char *cp;
+ u_int n;
+
+ if (strcmp(dev->name, "any") == 0) {
+ /*
+ * Give the "any" device an artificially high instance
+ * number, so it shows up after all other non-loopback
+ * interfaces.
+ */
+ n = 0x1FFFFFFF; /* 29 all-1 bits */
+ } else {
+ /*
+ * A number at the end of the device name string is
+ * assumed to be an instance number. Add 1 to the
+ * instance number, and use 0 for "no instance
+ * number", so we don't put "no instance number"
+ * devices and "instance 0" devices together.
+ */
+ cp = dev->name + strlen(dev->name) - 1;
+ while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9')
+ cp--;
+ if (*cp >= '0' && *cp <= '9')
+ n = atoi(cp) + 1;
+ else
+ n = 0;
+ }
+ if (!(dev->flags & PCAP_IF_RUNNING))
+ n |= 0x80000000;
+ if (!(dev->flags & PCAP_IF_UP))
+ n |= 0x40000000;
+
+ /*
+ * Give non-wireless interfaces that aren't disconnected a better
+ * figure of merit than interfaces that are disconnected, as
+ * "disconnected" should indicate that the interface isn't
+ * plugged into a network and thus won't give you any traffic.
+ *
+ * For wireless interfaces, it means "associated with a network",
+ * which we presume not to necessarily prevent capture, as you
+ * might run the adapter in some flavor of monitor mode.
+ */
+ if (!(dev->flags & PCAP_IF_WIRELESS) &&
+ (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
+ n |= 0x20000000;
+
+ /*
+ * Sort loopback devices after non-loopback devices, *except* for
+ * disconnected devices.
+ */
+ if (dev->flags & PCAP_IF_LOOPBACK)
+ n |= 0x10000000;
+
+ return (n);
+}
+
+#ifndef _WIN32
+/*
+ * Try to get a description for a given device.
+ * Returns a mallocated description if it could and NULL if it couldn't.
+ *
+ * XXX - on FreeBSDs that support it, should it get the sysctl named
+ * "dev.{adapter family name}.{adapter unit}.%desc" to get a description
+ * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800"
+ * with my Cisco 350 card, so the name isn't entirely descriptive. The
+ * "dev.an.0.%pnpinfo" has a better description, although one might argue
+ * that the problem is really a driver bug - if it can find out that it's
+ * a Cisco 340 or 350, rather than an old Aironet card, it should use
+ * that in the description.
+ *
+ * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD
+ * and OpenBSD let you get a description, but it's not generated by the OS,
+ * it's set with another ioctl that ifconfig supports; we use that to get
+ * a description in FreeBSD and OpenBSD, but if there is no such
+ * description available, it still might be nice to get some description
+ * string based on the device type or something such as that.
+ *
+ * In macOS, the System Configuration framework can apparently return
+ * names in 10.4 and later.
+ *
+ * It also appears that freedesktop.org's HAL offers an "info.product"
+ * string, but the HAL specification says it "should not be used in any
+ * UI" and "subsystem/capability specific properties" should be used
+ * instead and, in any case, I think HAL is being deprecated in
+ * favor of other stuff such as DeviceKit. DeviceKit doesn't appear
+ * to have any obvious product information for devices, but maybe
+ * I haven't looked hard enough.
+ *
+ * Using the System Configuration framework, or HAL, or DeviceKit, or
+ * whatever, would require that libpcap applications be linked with
+ * the frameworks/libraries in question. That shouldn't be a problem
+ * for programs linking with the shared version of libpcap (unless
+ * you're running on AIX - which I think is the only UN*X that doesn't
+ * support linking a shared library with other libraries on which it
+ * depends, and having an executable linked only with the first shared
+ * library automatically pick up the other libraries when started -
+ * and using HAL or whatever). Programs linked with the static
+ * version of libpcap would have to use pcap-config with the --static
+ * flag in order to get the right linker flags in order to pick up
+ * the additional libraries/frameworks; those programs need that anyway
+ * for libpcap 1.1 and beyond on Linux, as, by default, it requires
+ * -lnl.
+ *
+ * Do any other UN*Xes, or desktop environments support getting a
+ * description?
+ */
+static char *
+#ifdef SIOCGIFDESCR
+get_if_description(const char *name)
+{
+ char *description = NULL;
+ int s;
+ struct ifreq ifrdesc;
+#ifndef IFDESCRSIZE
+ size_t descrlen = 64;
+#else
+ size_t descrlen = IFDESCRSIZE;
+#endif /* IFDESCRSIZE */
+
+ /*
+ * Get the description for the interface.
+ */
+ memset(&ifrdesc, 0, sizeof ifrdesc);
+ strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+#ifdef __FreeBSD__
+ /*
+ * On FreeBSD, if the buffer isn't big enough for the
+ * description, the ioctl succeeds, but the description
+ * isn't copied, ifr_buffer.length is set to the description
+ * length, and ifr_buffer.buffer is set to NULL.
+ */
+ for (;;) {
+ free(description);
+ if ((description = malloc(descrlen)) != NULL) {
+ ifrdesc.ifr_buffer.buffer = description;
+ ifrdesc.ifr_buffer.length = descrlen;
+ if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) {
+ if (ifrdesc.ifr_buffer.buffer ==
+ description)
+ break;
+ else
+ descrlen = ifrdesc.ifr_buffer.length;
+ } else {
+ /*
+ * Failed to get interface description.
+ */
+ free(description);
+ description = NULL;
+ break;
+ }
+ } else
+ break;
+ }
+#else /* __FreeBSD__ */
+ /*
+ * The only other OS that currently supports
+ * SIOCGIFDESCR is OpenBSD, and it has no way
+ * to get the description length - it's clamped
+ * to a maximum of IFDESCRSIZE.
+ */
+ if ((description = malloc(descrlen)) != NULL) {
+ ifrdesc.ifr_data = (caddr_t)description;
+ if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) {
+ /*
+ * Failed to get interface description.
+ */
+ free(description);
+ description = NULL;
+ }
+ }
+#endif /* __FreeBSD__ */
+ close(s);
+ if (description != NULL && strlen(description) == 0) {
+ /*
+ * Description is empty, so discard it.
+ */
+ free(description);
+ description = NULL;
+ }
+ }
+
+#ifdef __FreeBSD__
+ /*
+ * For FreeBSD, if we didn't get a description, and this is
+ * a device with a name of the form usbusN, label it as a USB
+ * bus.
+ */
+ if (description == NULL) {
+ if (strncmp(name, "usbus", 5) == 0) {
+ /*
+ * OK, it begins with "usbus".
+ */
+ long busnum;
+ char *p;
+
+ errno = 0;
+ busnum = strtol(name + 5, &p, 10);
+ if (errno == 0 && p != name + 5 && *p == '\0' &&
+ busnum >= 0 && busnum <= INT_MAX) {
+ /*
+ * OK, it's a valid number that's not
+ * bigger than INT_MAX. Construct
+ * a description from it.
+ */
+ static const char descr_prefix[] = "USB bus number ";
+ size_t descr_size;
+
+ /*
+ * Allow enough room for a 32-bit bus number.
+ * sizeof (descr_prefix) includes the
+ * terminating NUL.
+ */
+ descr_size = sizeof (descr_prefix) + 10;
+ description = malloc(descr_size);
+ if (description != NULL) {
+ pcap_snprintf(description, descr_size,
+ "%s%ld", descr_prefix, busnum);
+ }
+ }
+ }
+ }
+#endif
+ return (description);
+#else /* SIOCGIFDESCR */
+get_if_description(const char *name _U_)
+{
+ return (NULL);
+#endif /* SIOCGIFDESCR */
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, return a pointer to its entry.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * IFF_ flags and description, and, if that succeeds, return a pointer to
+ * the new entry, otherwise return NULL and set errbuf to an error message.
+ */
+pcap_if_t *
+find_or_add_if(pcap_if_list_t *devlistp, const char *name,
+ bpf_u_int32 if_flags, get_if_flags_func get_flags_func, char *errbuf)
+{
+ bpf_u_int32 pcap_flags;
+
+ /*
+ * Convert IFF_ flags to pcap flags.
+ */
+ pcap_flags = 0;
+#ifdef IFF_LOOPBACK
+ if (if_flags & IFF_LOOPBACK)
+ pcap_flags |= PCAP_IF_LOOPBACK;
+#else
+ /*
+ * We don't have IFF_LOOPBACK, so look at the device name to
+ * see if it looks like a loopback device.
+ */
+ if (name[0] == 'l' && name[1] == 'o' &&
+ (isdigit((unsigned char)(name[2])) || name[2] == '\0')
+ pcap_flags |= PCAP_IF_LOOPBACK;
+#endif
+#ifdef IFF_UP
+ if (if_flags & IFF_UP)
+ pcap_flags |= PCAP_IF_UP;
+#endif
+#ifdef IFF_RUNNING
+ if (if_flags & IFF_RUNNING)
+ pcap_flags |= PCAP_IF_RUNNING;
+#endif
+
+ /*
+ * Attempt to find an entry for this device; if we don't find one,
+ * attempt to add one.
+ */
+ return (find_or_add_dev(devlistp, name, pcap_flags,
+ get_flags_func, get_if_description(name), errbuf));
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, then, if the specified address isn't null, add it to
+ * the list of addresses for the device and return 0.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * IFF_ flags and description, and, if that succeeds, add the specified
+ * address to its list of addresses if that address is non-null, and
+ * return 0, otherwise return -1 and set errbuf to an error message.
+ *
+ * (We can get called with a null address because we might get a list
+ * of interface name/address combinations from the underlying OS, with
+ * the address being absent in some cases, rather than a list of
+ * interfaces with each interface having a list of addresses, so this
+ * call may be the only call made to add to the list, and we want to
+ * add interfaces even if they have no addresses.)
+ */
+int
+add_addr_to_if(pcap_if_list_t *devlistp, const char *name,
+ bpf_u_int32 if_flags, get_if_flags_func get_flags_func,
+ struct sockaddr *addr, size_t addr_size,
+ struct sockaddr *netmask, size_t netmask_size,
+ struct sockaddr *broadaddr, size_t broadaddr_size,
+ struct sockaddr *dstaddr, size_t dstaddr_size,
+ char *errbuf)
+{
+ pcap_if_t *curdev;
+
+ /*
+ * Check whether the device exists and, if not, add it.
+ */
+ curdev = find_or_add_if(devlistp, name, if_flags, get_flags_func,
+ errbuf);
+ if (curdev == NULL) {
+ /*
+ * Error - give up.
+ */
+ return (-1);
+ }
+
+ if (addr == NULL) {
+ /*
+ * There's no address to add; this entry just meant
+ * "here's a new interface".
+ */
+ return (0);
+ }
+
+ /*
+ * "curdev" is an entry for this interface, and we have an
+ * address for it; add an entry for that address to the
+ * interface's list of addresses.
+ */
+ return (add_addr_to_dev(curdev, addr, addr_size, netmask,
+ netmask_size, broadaddr, broadaddr_size, dstaddr,
+ dstaddr_size, errbuf));
+}
+#endif /* _WIN32 */
+
+/*
+ * Add an entry to the list of addresses for an interface.
+ * "curdev" is the entry for that interface.
+ */
+int
+add_addr_to_dev(pcap_if_t *curdev,
+ struct sockaddr *addr, size_t addr_size,
+ struct sockaddr *netmask, size_t netmask_size,
+ struct sockaddr *broadaddr, size_t broadaddr_size,
+ struct sockaddr *dstaddr, size_t dstaddr_size,
+ char *errbuf)
+{
+ pcap_addr_t *curaddr, *prevaddr, *nextaddr;
+
+ /*
+ * Allocate the new entry and fill it in.
+ */
+ curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
+ if (curaddr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+
+ curaddr->next = NULL;
+ if (addr != NULL && addr_size != 0) {
+ curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size);
+ if (curaddr->addr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(curaddr);
+ return (-1);
+ }
+ } else
+ curaddr->addr = NULL;
+
+ if (netmask != NULL && netmask_size != 0) {
+ curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size);
+ if (curaddr->netmask == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ if (curaddr->addr != NULL)
+ free(curaddr->addr);
+ free(curaddr);
+ return (-1);
+ }
+ } else
+ curaddr->netmask = NULL;
+
+ if (broadaddr != NULL && broadaddr_size != 0) {
+ curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size);
+ if (curaddr->broadaddr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ if (curaddr->netmask != NULL)
+ free(curaddr->netmask);
+ if (curaddr->addr != NULL)
+ free(curaddr->addr);
+ free(curaddr);
+ return (-1);
+ }
+ } else
+ curaddr->broadaddr = NULL;
+
+ if (dstaddr != NULL && dstaddr_size != 0) {
+ curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size);
+ if (curaddr->dstaddr == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ if (curaddr->broadaddr != NULL)
+ free(curaddr->broadaddr);
+ if (curaddr->netmask != NULL)
+ free(curaddr->netmask);
+ if (curaddr->addr != NULL)
+ free(curaddr->addr);
+ free(curaddr);
+ return (-1);
+ }
+ } else
+ curaddr->dstaddr = NULL;
+
+ /*
+ * Find the end of the list of addresses.
+ */
+ for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
+ nextaddr = prevaddr->next;
+ if (nextaddr == NULL) {
+ /*
+ * This is the end of the list.
+ */
+ break;
+ }
+ }
+
+ if (prevaddr == NULL) {
+ /*
+ * The list was empty; this is the first member.
+ */
+ curdev->addresses = curaddr;
+ } else {
+ /*
+ * "prevaddr" is the last member of the list; append
+ * this member to it.
+ */
+ prevaddr->next = curaddr;
+ }
+
+ return (0);
+}
+
+/*
+ * Look for a given device in the specified list of devices.
+ *
+ * If we find it, return 0 and set *curdev_ret to point to it.
+ *
+ * If we don't find it, attempt to add an entry for it, with the specified
+ * flags and description, and, if that succeeds, return 0, otherwise
+ * return -1 and set errbuf to an error message.
+ */
+pcap_if_t *
+find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
+ get_if_flags_func get_flags_func, const char *description, char *errbuf)
+{
+ pcap_if_t *curdev;
+
+ /*
+ * Is there already an entry in the list for this device?
+ */
+ curdev = find_dev(devlistp, name);
+ if (curdev != NULL) {
+ /*
+ * Yes, return it.
+ */
+ return (curdev);
+ }
+
+ /*
+ * No, we didn't find it.
+ */
+
+ /*
+ * Try to get additional flags for the device.
+ */
+ if ((*get_flags_func)(name, &flags, errbuf) == -1) {
+ /*
+ * Failed.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now, try to add it to the list of devices.
+ */
+ return (add_dev(devlistp, name, flags, description, errbuf));
+}
+
+/*
+ * Look for a given device in the specified list of devices, and return
+ * the entry for it if we find it or NULL if we don't.
+ */
+pcap_if_t *
+find_dev(pcap_if_list_t *devlistp, const char *name)
+{
+ pcap_if_t *curdev;
+
+ /*
+ * Is there an entry in the list for this device?
+ */
+ for (curdev = devlistp->beginning; curdev != NULL;
+ curdev = curdev->next) {
+ if (strcmp(name, curdev->name) == 0) {
+ /*
+ * We found it, so, yes, there is. No need to
+ * add it. Provide the entry we found to our
+ * caller.
+ */
+ return (curdev);
+ }
+ }
+
+ /*
+ * No.
+ */
+ return (NULL);
+}
+
+/*
+ * Attempt to add an entry for a device, with the specified flags
+ * and description, and, if that succeeds, return 0 and return a pointer
+ * to the new entry, otherwise return NULL and set errbuf to an error
+ * message.
+ *
+ * If we weren't given a description, try to get one.
+ */
+pcap_if_t *
+add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
+ const char *description, char *errbuf)
+{
+ pcap_if_t *curdev, *prevdev, *nextdev;
+ u_int this_figure_of_merit, nextdev_figure_of_merit;
+
+ curdev = malloc(sizeof(pcap_if_t));
+ if (curdev == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+
+ /*
+ * Fill in the entry.
+ */
+ curdev->next = NULL;
+ curdev->name = strdup(name);
+ if (curdev->name == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(curdev);
+ return (NULL);
+ }
+ if (description == NULL) {
+ /*
+ * We weren't handed a description for the interface.
+ */
+ curdev->description = NULL;
+ } else {
+ /*
+ * We were handed a description; make a copy.
+ */
+ curdev->description = strdup(description);
+ if (curdev->description == NULL) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(curdev->name);
+ free(curdev);
+ return (NULL);
+ }
+ }
+ curdev->addresses = NULL; /* list starts out as empty */
+ curdev->flags = flags;
+
+ /*
+ * Add it to the list, in the appropriate location.
+ * First, get the "figure of merit" for this interface.
+ */
+ this_figure_of_merit = get_figure_of_merit(curdev);
+
+ /*
+ * Now look for the last interface with an figure of merit
+ * less than or equal to the new interface's figure of merit.
+ *
+ * We start with "prevdev" being NULL, meaning we're before
+ * the first element in the list.
+ */
+ prevdev = NULL;
+ for (;;) {
+ /*
+ * Get the interface after this one.
+ */
+ if (prevdev == NULL) {
+ /*
+ * The next element is the first element.
+ */
+ nextdev = devlistp->beginning;
+ } else
+ nextdev = prevdev->next;
+
+ /*
+ * Are we at the end of the list?
+ */
+ if (nextdev == NULL) {
+ /*
+ * Yes - we have to put the new entry after "prevdev".
+ */
+ break;
+ }
+
+ /*
+ * Is the new interface's figure of merit less
+ * than the next interface's figure of merit,
+ * meaning that the new interface is better
+ * than the next interface?
+ */
+ nextdev_figure_of_merit = get_figure_of_merit(nextdev);
+ if (this_figure_of_merit < nextdev_figure_of_merit) {
+ /*
+ * Yes - we should put the new entry
+ * before "nextdev", i.e. after "prevdev".
+ */
+ break;
+ }
+
+ prevdev = nextdev;
+ }
+
+ /*
+ * Insert before "nextdev".
+ */
+ curdev->next = nextdev;
+
+ /*
+ * Insert after "prevdev" - unless "prevdev" is null,
+ * in which case this is the first interface.
+ */
+ if (prevdev == NULL) {
+ /*
+ * This is the first interface. Make it
+ * the first element in the list of devices.
+ */
+ devlistp->beginning = curdev;
+ } else
+ prevdev->next = curdev;
+ return (curdev);
+}
+
+/*
+ * Free a list of interfaces.
+ */
+void
+pcap_freealldevs(pcap_if_t *alldevs)
+{
+ pcap_if_t *curdev, *nextdev;
+ pcap_addr_t *curaddr, *nextaddr;
+
+ for (curdev = alldevs; curdev != NULL; curdev = nextdev) {
+ nextdev = curdev->next;
+
+ /*
+ * Free all addresses.
+ */
+ for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {
+ nextaddr = curaddr->next;
+ if (curaddr->addr)
+ free(curaddr->addr);
+ if (curaddr->netmask)
+ free(curaddr->netmask);
+ if (curaddr->broadaddr)
+ free(curaddr->broadaddr);
+ if (curaddr->dstaddr)
+ free(curaddr->dstaddr);
+ free(curaddr);
+ }
+
+ /*
+ * Free the name string.
+ */
+ free(curdev->name);
+
+ /*
+ * Free the description string, if any.
+ */
+ if (curdev->description != NULL)
+ free(curdev->description);
+
+ /*
+ * Free the interface.
+ */
+ free(curdev);
+ }
+}
+
+/*
+ * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as
+ * it actually returns the names of all interfaces, with a NUL separator
+ * between them; some callers may depend on that.
+ *
+ * MS-DOS has its own pcap_lookupdev(), but that might be useful only
+ * as an optimization.
+ *
+ * In all other cases, we just use pcap_findalldevs() to get a list of
+ * devices, and pick from that list.
+ */
+#if !defined(HAVE_PACKET32) && !defined(MSDOS)
+/*
+ * Return the name of a network interface attached to the system, or NULL
+ * if none can be found. The interface must be configured up; the
+ * lowest unit number is preferred; loopback is ignored.
+ */
+char *
+pcap_lookupdev(char *errbuf)
+{
+ pcap_if_t *alldevs;
+#ifdef _WIN32
+ /*
+ * Windows - use the same size as the old WinPcap 3.1 code.
+ * XXX - this is probably bigger than it needs to be.
+ */
+ #define IF_NAMESIZE 8192
+#else
+ /*
+ * UN*X - use the system's interface name size.
+ * XXX - that might not be large enough for capture devices
+ * that aren't regular network interfaces.
+ */
+ /* for old BSD systems, including bsdi3 */
+ #ifndef IF_NAMESIZE
+ #define IF_NAMESIZE IFNAMSIZ
+ #endif
+#endif
+ static char device[IF_NAMESIZE + 1];
+ char *ret;
+
+ if (pcap_findalldevs(&alldevs, errbuf) == -1)
+ return (NULL);
+
+ if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
+ /*
+ * There are no devices on the list, or the first device
+ * on the list is a loopback device, which means there
+ * are no non-loopback devices on the list. This means
+ * we can't return any device.
+ *
+ * XXX - why not return a loopback device? If we can't
+ * capture on it, it won't be on the list, and if it's
+ * on the list, there aren't any non-loopback devices,
+ * so why not just supply it as the default device?
+ */
+ (void)strlcpy(errbuf, "no suitable device found",
+ PCAP_ERRBUF_SIZE);
+ ret = NULL;
+ } else {
+ /*
+ * Return the name of the first device on the list.
+ */
+ (void)strlcpy(device, alldevs->name, sizeof(device));
+ ret = device;
+ }
+
+ pcap_freealldevs(alldevs);
+ return (ret);
+}
+#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+/*
+ * We don't just fetch the entire list of devices, search for the
+ * particular device, and use its first IPv4 address, as that's too
+ * much work to get just one device's netmask.
+ *
+ * If we had an API to get attributes for a given device, we could
+ * use that.
+ */
+int
+pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
+ char *errbuf)
+{
+ register int fd;
+ register struct sockaddr_in *sin4;
+ struct ifreq ifr;
+
+ /*
+ * The pseudo-device "any" listens on all interfaces and therefore
+ * has the network address and -mask "0.0.0.0" therefore catching
+ * all traffic. Using NULL for the interface is the same as "any".
+ */
+ if (!device || strcmp(device, "any") == 0
+#ifdef HAVE_DAG_API
+ || strstr(device, "dag") != NULL
+#endif
+#ifdef HAVE_SEPTEL_API
+ || strstr(device, "septel") != NULL
+#endif
+#ifdef PCAP_SUPPORT_BT
+ || strstr(device, "bluetooth") != NULL
+#endif
+#ifdef PCAP_SUPPORT_USB
+ || strstr(device, "usbmon") != NULL
+#endif
+#ifdef HAVE_SNF_API
+ || strstr(device, "snf") != NULL
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ || strncmp(device, "netmap:", 7) == 0
+ || strncmp(device, "vale", 4) == 0
+#endif
+ ) {
+ *netp = *maskp = 0;
+ return 0;
+ }
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "socket");
+ return (-1);
+ }
+ memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+ /* XXX Work around Linux kernel bug */
+ ifr.ifr_addr.sa_family = AF_INET;
+#endif
+ (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ if (errno == EADDRNOTAVAIL) {
+ (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "%s: no IPv4 address assigned", device);
+ } else {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "SIOCGIFADDR: %s", device);
+ }
+ (void)close(fd);
+ return (-1);
+ }
+ sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
+ *netp = sin4->sin_addr.s_addr;
+ memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+ /* XXX Work around Linux kernel bug */
+ ifr.ifr_addr.sa_family = AF_INET;
+#endif
+ (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "SIOCGIFNETMASK: %s", device);
+ (void)close(fd);
+ return (-1);
+ }
+ (void)close(fd);
+ *maskp = sin4->sin_addr.s_addr;
+ if (*maskp == 0) {
+ if (IN_CLASSA(*netp))
+ *maskp = IN_CLASSA_NET;
+ else if (IN_CLASSB(*netp))
+ *maskp = IN_CLASSB_NET;
+ else if (IN_CLASSC(*netp))
+ *maskp = IN_CLASSC_NET;
+ else {
+ (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "inet class for 0x%x unknown", *netp);
+ return (-1);
+ }
+ }
+ *netp &= *maskp;
+ return (0);
+}
+#endif /* !defined(_WIN32) && !defined(MSDOS) */
+
+#ifdef ENABLE_REMOTE
+#include "pcap-rpcap.h"
+
+/*
+ * Extract a substring from a string.
+ */
+static char *
+get_substring(const char *p, size_t len, char *ebuf)
+{
+ char *token;
+
+ token = malloc(len + 1);
+ if (token == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+ memcpy(token, p, len);
+ token[len] = '\0';
+ return (token);
+}
+
+/*
+ * Parse a capture source that might be a URL.
+ *
+ * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
+ * are set to NULL, *pathp is set to point to the source, and 0 is
+ * returned.
+ *
+ * If source is a URL, and the URL refers to a local device (a special
+ * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set
+ * to NULL, *pathp is set to point to the device name, and 0 is returned.
+ *
+ * If source is a URL, and it's not a special case that refers to a local
+ * device, and the parse succeeds:
+ *
+ * *schemep is set to point to an allocated string containing the scheme;
+ *
+ * if user information is present in the URL, *userinfop is set to point
+ * to an allocated string containing the user information, otherwise
+ * it's set to NULL;
+ *
+ * if host information is present in the URL, *hostp is set to point
+ * to an allocated string containing the host information, otherwise
+ * it's set to NULL;
+ *
+ * if a port number is present in the URL, *portp is set to point
+ * to an allocated string containing the port number, otherwise
+ * it's set to NULL;
+ *
+ * *pathp is set to point to an allocated string containing the
+ * path;
+ *
+ * and 0 is returned.
+ *
+ * If the parse fails, ebuf is set to an error string, and -1 is returned.
+ */
+static int
+pcap_parse_source(const char *source, char **schemep, char **userinfop,
+ char **hostp, char **portp, char **pathp, char *ebuf)
+{
+ char *colonp;
+ size_t scheme_len;
+ char *scheme;
+ const char *endp;
+ size_t authority_len;
+ char *authority;
+ char *parsep, *atsignp, *bracketp;
+ char *userinfo, *host, *port, *path;
+
+ /*
+ * Start out returning nothing.
+ */
+ *schemep = NULL;
+ *userinfop = NULL;
+ *hostp = NULL;
+ *portp = NULL;
+ *pathp = NULL;
+
+ /*
+ * RFC 3986 says:
+ *
+ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ *
+ * hier-part = "//" authority path-abempty
+ * / path-absolute
+ * / path-rootless
+ * / path-empty
+ *
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ *
+ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ *
+ * Step 1: look for the ":" at the end of the scheme.
+ * A colon in the source is *NOT* sufficient to indicate that
+ * this is a URL, as interface names on some platforms might
+ * include colons (e.g., I think some Solaris interfaces
+ * might).
+ */
+ colonp = strchr(source, ':');
+ if (colonp == NULL) {
+ /*
+ * The source is the device to open.
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ *pathp = strdup(source);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * All schemes must have "//" after them, i.e. we only support
+ * hier-part = "//" authority path-abempty, not
+ * hier-part = path-absolute
+ * hier-part = path-rootless
+ * hier-part = path-empty
+ *
+ * We need that in order to distinguish between a local device
+ * name that happens to contain a colon and a URI.
+ */
+ if (strncmp(colonp + 1, "//", 2) != 0) {
+ /*
+ * The source is the device to open.
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ *pathp = strdup(source);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * XXX - check whether the purported scheme could be a scheme?
+ */
+
+ /*
+ * OK, this looks like a URL.
+ * Get the scheme.
+ */
+ scheme_len = colonp - source;
+ scheme = malloc(scheme_len + 1);
+ if (scheme == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ memcpy(scheme, source, scheme_len);
+ scheme[scheme_len] = '\0';
+
+ /*
+ * Treat file: specially - take everything after file:// as
+ * the pathname.
+ */
+ if (pcap_strcasecmp(scheme, "file") == 0) {
+ *schemep = scheme;
+ *pathp = strdup(colonp + 3);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * The WinPcap documentation says you can specify a local
+ * interface with "rpcap://{device}"; we special-case
+ * that here. If the scheme is "rpcap", and there are
+ * no slashes past the "//", we just return the device.
+ *
+ * XXX - %-escaping?
+ */
+ if (pcap_strcasecmp(scheme, "rpcap") == 0 &&
+ strchr(colonp + 3, '/') == NULL) {
+ /*
+ * Local device.
+ *
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ free(scheme);
+ *pathp = strdup(colonp + 3);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * OK, now start parsing the authority.
+ * Get token, terminated with / or terminated at the end of
+ * the string.
+ */
+ authority_len = strcspn(colonp + 3, "/");
+ authority = get_substring(colonp + 3, authority_len, ebuf);
+ if (authority == NULL) {
+ /*
+ * Error.
+ */
+ free(scheme);
+ return (-1);
+ }
+ endp = colonp + 3 + authority_len;
+
+ /*
+ * Now carve the authority field into its components.
+ */
+ parsep = authority;
+
+ /*
+ * Is there a userinfo field?
+ */
+ atsignp = strchr(parsep, '@');
+ if (atsignp != NULL) {
+ /*
+ * Yes.
+ */
+ size_t userinfo_len;
+
+ userinfo_len = atsignp - parsep;
+ userinfo = get_substring(parsep, userinfo_len, ebuf);
+ if (userinfo == NULL) {
+ /*
+ * Error.
+ */
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = atsignp + 1;
+ } else {
+ /*
+ * No.
+ */
+ userinfo = NULL;
+ }
+
+ /*
+ * Is there a host field?
+ */
+ if (*parsep == '\0') {
+ /*
+ * No; there's no host field or port field.
+ */
+ host = NULL;
+ port = NULL;
+ } else {
+ /*
+ * Yes.
+ */
+ size_t host_len;
+
+ /*
+ * Is it an IP-literal?
+ */
+ if (*parsep == '[') {
+ /*
+ * Yes.
+ * Treat verything up to the closing square
+ * bracket as the IP-Literal; we don't worry
+ * about whether it's a valid IPv6address or
+ * IPvFuture.
+ */
+ bracketp = strchr(parsep, ']');
+ if (bracketp == NULL) {
+ /*
+ * There's no closing square bracket.
+ */
+ pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "IP-literal in URL doesn't end with ]");
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ if (*(bracketp + 1) != '\0' &&
+ *(bracketp + 1) != ':') {
+ /*
+ * There's extra crud after the
+ * closing square bracketn.
+ */
+ pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Extra text after IP-literal in URL");
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ host_len = (bracketp - 1) - parsep;
+ host = get_substring(parsep + 1, host_len, ebuf);
+ if (host == NULL) {
+ /*
+ * Error.
+ */
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = bracketp + 1;
+ } else {
+ /*
+ * No.
+ * Treat everything up to a : or the end of
+ * the string as the host.
+ */
+ host_len = strcspn(parsep, ":");
+ host = get_substring(parsep, host_len, ebuf);
+ if (host == NULL) {
+ /*
+ * Error.
+ */
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = parsep + host_len;
+ }
+
+ /*
+ * Is there a port field?
+ */
+ if (*parsep == ':') {
+ /*
+ * Yes. It's the rest of the authority field.
+ */
+ size_t port_len;
+
+ parsep++;
+ port_len = strlen(parsep);
+ port = get_substring(parsep, port_len, ebuf);
+ if (port == NULL) {
+ /*
+ * Error.
+ */
+ free(host);
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ } else {
+ /*
+ * No.
+ */
+ port = NULL;
+ }
+ }
+ free(authority);
+
+ /*
+ * Everything else is the path. Strip off the leading /.
+ */
+ if (*endp == '\0')
+ path = strdup("");
+ else
+ path = strdup(endp + 1);
+ if (path == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(port);
+ free(host);
+ free(userinfo);
+ free(scheme);
+ return (-1);
+ }
+ *schemep = scheme;
+ *userinfop = userinfo;
+ *hostp = host;
+ *portp = port;
+ *pathp = path;
+ return (0);
+}
+
+int
+pcap_createsrcstr(char *source, int type, const char *host, const char *port,
+ const char *name, char *errbuf)
+{
+ switch (type) {
+
+ case PCAP_SRC_FILE:
+ strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
+ if (name != NULL && *name != '\0') {
+ strlcat(source, name, PCAP_BUF_SIZE);
+ return (0);
+ } else {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The file name cannot be NULL.");
+ return (-1);
+ }
+
+ case PCAP_SRC_IFREMOTE:
+ strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+ if (host != NULL && *host != '\0') {
+ if (strchr(host, ':') != NULL) {
+ /*
+ * The host name contains a colon, so it's
+ * probably an IPv6 address, and needs to
+ * be included in square brackets.
+ */
+ strlcat(source, "[", PCAP_BUF_SIZE);
+ strlcat(source, host, PCAP_BUF_SIZE);
+ strlcat(source, "]", PCAP_BUF_SIZE);
+ } else
+ strlcat(source, host, PCAP_BUF_SIZE);
+
+ if (port != NULL && *port != '\0') {
+ strlcat(source, ":", PCAP_BUF_SIZE);
+ strlcat(source, port, PCAP_BUF_SIZE);
}
+
+ strlcat(source, "/", PCAP_BUF_SIZE);
+ } else {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The host name cannot be NULL.");
return (-1);
}
+
+ if (name != NULL && *name != '\0')
+ strlcat(source, name, PCAP_BUF_SIZE);
+
+ return (0);
+
+ case PCAP_SRC_IFLOCAL:
+ strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+
+ if (name != NULL && *name != '\0')
+ strlcat(source, name, PCAP_BUF_SIZE);
+
+ return (0);
+
+ default:
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The interface type is not valid.");
+ return (-1);
+ }
+}
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+ char *name, char *errbuf)
+{
+ char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
+
+ /* Initialization stuff */
+ if (host)
+ *host = '\0';
+ if (port)
+ *port = '\0';
+ if (name)
+ *name = '\0';
+
+ /* Parse the source string */
+ if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
+ &tmpport, &tmppath, errbuf) == -1) {
+ /*
+ * Fail.
+ */
+ return (-1);
+ }
+
+ if (scheme == NULL) {
+ /*
+ * Local device.
+ */
+ if (name && tmppath)
+ strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFLOCAL;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ return (0);
+ }
+
+ if (strcmp(scheme, "rpcap") == 0) {
+ /*
+ * rpcap://
+ *
+ * pcap_parse_source() has already handled the case of
+ * rpcap://device
+ */
+ if (host && tmphost) {
+ if (tmpuserinfo)
+ pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+ tmpuserinfo, tmphost);
+ else
+ strlcpy(host, tmphost, PCAP_BUF_SIZE);
+ }
+ if (port && tmpport)
+ strlcpy(port, tmpport, PCAP_BUF_SIZE);
+ if (name && tmppath)
+ strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFREMOTE;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
}
+ if (strcmp(scheme, "file") == 0) {
+ /*
+ * file://
+ */
+ if (name && tmppath)
+ strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_FILE;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+ }
+
+ /*
+ * Neither rpcap: nor file:; just treat the entire string
+ * as a local device.
+ */
+ if (name)
+ strlcpy(name, source, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFLOCAL;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
return (0);
}
+#endif
pcap_t *
pcap_create(const char *device, char *errbuf)
@@ -400,8 +1993,9 @@ pcap_create(const char *device, char *errbuf)
length = wcslen((wchar_t *)device);
device_str = (char *)malloc(length + 1);
if (device_str == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "malloc");
return (NULL);
}
@@ -412,8 +2006,8 @@ pcap_create(const char *device, char *errbuf)
device_str = strdup(device);
}
if (device_str == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
return (NULL);
}
@@ -463,6 +2057,18 @@ pcap_create(const char *device, char *errbuf)
return (p);
}
+/*
+ * Set nonblocking mode on an unactivated pcap_t; this sets a flag
+ * checked by pcap_activate(), which sets the mode after calling
+ * the activate routine.
+ */
+static int
+pcap_setnonblock_unactivated(pcap_t *p, int nonblock)
+{
+ p->opt.nonblock = nonblock;
+ return (0);
+}
+
static void
initialize_ops(pcap_t *p)
{
@@ -477,7 +2083,6 @@ initialize_ops(pcap_t *p)
p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
- p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized;
p->stats_op = (stats_op_t)pcap_not_initialized;
#ifdef _WIN32
p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
@@ -519,24 +2124,38 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
* plus a structure following it of size "size". The
* structure following it is a private data structure
* for the routines that handle this pcap_t.
+ *
+ * The structure following it must be aligned on
+ * the appropriate alignment boundary for this platform.
+ * We align on an 8-byte boundary as that's probably what
+ * at least some platforms do, even with 32-bit integers,
+ * and because we can't be sure that some values won't
+ * require 8-byte alignment even on platforms with 32-bit
+ * integers.
*/
- chunk = malloc(sizeof (pcap_t) + size);
+#define PCAP_T_ALIGNED_SIZE ((sizeof(pcap_t) + 7) & ~0x7)
+ chunk = malloc(PCAP_T_ALIGNED_SIZE + size);
if (chunk == NULL) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
return (NULL);
}
- memset(chunk, 0, sizeof (pcap_t) + size);
+ memset(chunk, 0, PCAP_T_ALIGNED_SIZE + size);
/*
* Get a pointer to the pcap_t at the beginning.
*/
p = (pcap_t *)chunk;
-#ifndef _WIN32
+#ifdef _WIN32
+ p->handle = INVALID_HANDLE_VALUE; /* not opened yet */
+#else /* _WIN32 */
p->fd = -1; /* not opened yet */
+#ifndef MSDOS
p->selectable_fd = -1;
-#endif
+ p->required_select_timeout = NULL;
+#endif /* MSDOS */
+#endif /* _WIN32 */
if (size == 0) {
/* No private data was requested. */
@@ -546,7 +2165,7 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
* Set the pointer to the private data; that's the structure
* of size "size" following the pcap_t.
*/
- p->priv = (void *)(chunk + sizeof (pcap_t));
+ p->priv = (void *)(chunk + PCAP_T_ALIGNED_SIZE);
}
return (p);
@@ -569,10 +2188,17 @@ pcap_create_common(char *ebuf, size_t size)
*/
p->can_set_rfmon_op = pcap_cant_set_rfmon;
+ /*
+ * If pcap_setnonblock() is called on a not-yet-activated
+ * pcap_t, default to setting a flag and turning
+ * on non-blocking mode when activated.
+ */
+ p->setnonblock_op = pcap_setnonblock_unactivated;
+
initialize_ops(p);
/* put in some defaults*/
- p->snapshot = MAXIMUM_SNAPLEN; /* max packet size */
+ p->snapshot = 0; /* max packet size unspecified */
p->opt.timeout = 0; /* no timeout specified */
p->opt.buffer_size = 0; /* use the platform's default */
p->opt.promisc = 0;
@@ -580,6 +2206,15 @@ pcap_create_common(char *ebuf, size_t size)
p->opt.immediate = 0;
p->opt.tstamp_type = -1; /* default to not setting time stamp type */
p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
+ /*
+ * Platform-dependent options.
+ */
+#ifdef __linux__
+ p->opt.protocol = 0;
+#endif
+#ifdef _WIN32
+ p->opt.nocapture_local = 0;
+#endif
/*
* Start out with no BPF code generation flags set.
@@ -605,16 +2240,6 @@ pcap_set_snaplen(pcap_t *p, int snaplen)
{
if (pcap_check_activated(p))
return (PCAP_ERROR_ACTIVATED);
-
- /*
- * Turn invalid values, or excessively large values, into
- * the maximum allowed value.
- *
- * If some application really *needs* a bigger snapshot
- * length, we should just increase MAXIMUM_SNAPLEN.
- */
- if (snaplen <= 0 || snaplen > MAXIMUM_SNAPLEN)
- snaplen = MAXIMUM_SNAPLEN;
p->snapshot = snaplen;
return (0);
}
@@ -785,9 +2410,25 @@ pcap_activate(pcap_t *p)
if (pcap_check_activated(p))
return (PCAP_ERROR_ACTIVATED);
status = p->activate_op(p);
- if (status >= 0)
+ if (status >= 0) {
+ /*
+ * If somebody requested non-blocking mode before
+ * calling pcap_activate(), turn it on now.
+ */
+ if (p->opt.nonblock) {
+ status = p->setnonblock_op(p, 1);
+ if (status < 0) {
+ /*
+ * Failed. Undo everything done by
+ * the activate operation.
+ */
+ p->cleanup_op(p);
+ initialize_ops(p);
+ return (status);
+ }
+ }
p->activated = 1;
- else {
+ } else {
if (p->errbuf[0] == '\0') {
/*
* No error message supplied by the activate routine;
@@ -813,6 +2454,53 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
{
pcap_t *p;
int status;
+#ifdef ENABLE_REMOTE
+ char host[PCAP_BUF_SIZE + 1];
+ char port[PCAP_BUF_SIZE + 1];
+ char name[PCAP_BUF_SIZE + 1];
+ int srctype;
+
+ /*
+ * Retrofit - we have to make older applications compatible with
+ * remote capture.
+ * So we're calling pcap_open_remote() from here; this is a very
+ * dirty hack.
+ * Obviously, we cannot exploit all the new features; for instance,
+ * we cannot send authentication, we cannot use a UDP data connection,
+ * and so on.
+ */
+ if (pcap_parsesrcstr(device, &srctype, host, port, name, errbuf))
+ return (NULL);
+
+ if (srctype == PCAP_SRC_IFREMOTE) {
+ /*
+ * Although we already have host, port and iface, we prefer
+ * to pass only 'device' to pcap_open_rpcap(), so that it has
+ * to call pcap_parsesrcstr() again.
+ * This is less optimized, but much clearer.
+ */
+ return (pcap_open_rpcap(device, snaplen,
+ promisc ? PCAP_OPENFLAG_PROMISCUOUS : 0, to_ms,
+ NULL, errbuf));
+ }
+ if (srctype == PCAP_SRC_FILE) {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
+ return (NULL);
+ }
+ if (srctype == PCAP_SRC_IFLOCAL) {
+ /*
+ * If it starts with rpcap://, that refers to a local device
+ * (no host part in the URL). Remove the rpcap://, and
+ * fall through to the regular open path.
+ */
+ if (strncmp(device, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0) {
+ size_t len = strlen(device) - strlen(PCAP_SRC_IF_STRING) + 1;
+
+ if (len > 0)
+ device += strlen(PCAP_SRC_IF_STRING);
+ }
+ }
+#endif /* ENABLE_REMOTE */
p = pcap_create(device, errbuf);
if (p == NULL)
@@ -946,8 +2634,8 @@ pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
*/
*dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
if (*dlt_buffer == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
return (PCAP_ERROR);
}
**dlt_buffer = p->linktype;
@@ -955,8 +2643,8 @@ pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
} else {
*dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
if (*dlt_buffer == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
return (PCAP_ERROR);
}
(void)memcpy(*dlt_buffer, p->dlt_list,
@@ -1271,6 +2959,15 @@ static struct dlt_choice dlt_choices[] = {
DLT_CHOICE(WATTSTOPPER_DLM, "WattStopper Digital Lighting Management (DLM) and Legrand Nitoo Open protocol"),
DLT_CHOICE(ISO_14443, "ISO 14443 messages"),
DLT_CHOICE(RDS, "IEC 62106 Radio Data System groups"),
+ DLT_CHOICE(USB_DARWIN, "USB with Darwin header"),
+ DLT_CHOICE(OPENFLOW, "OpenBSD DLT_OPENFLOW"),
+ DLT_CHOICE(SDLC, "IBM SDLC frames"),
+ DLT_CHOICE(TI_LLN_SNIFFER, "TI LLN sniffer frames"),
+ DLT_CHOICE(VSOCK, "Linux vsock"),
+ DLT_CHOICE(NORDIC_BLE, "Nordic Semiconductor Bluetooth LE sniffer frames"),
+ DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"),
+ DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
+ DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
DLT_CHOICE_SENTINEL
};
@@ -1393,6 +3090,14 @@ pcap_minor_version(pcap_t *p)
return (p->version_minor);
}
+int
+pcap_bufsize(pcap_t *p)
+{
+ if (!p->activated)
+ return (PCAP_ERROR_NOT_ACTIVATED);
+ return (p->bufsize);
+}
+
FILE *
pcap_file(pcap_t *p)
{
@@ -1405,8 +3110,8 @@ pcap_fileno(pcap_t *p)
#ifndef _WIN32
return (p->fd);
#else
- if (p->adapter != NULL)
- return ((int)(DWORD)p->adapter->hFile);
+ if (p->handle != INVALID_HANDLE_VALUE)
+ return ((int)(DWORD)p->handle);
else
return (PCAP_ERROR);
#endif
@@ -1418,6 +3123,12 @@ pcap_get_selectable_fd(pcap_t *p)
{
return (p->selectable_fd);
}
+
+struct timeval *
+pcap_get_required_select_timeout(pcap_t *p)
+{
+ return (p->required_select_timeout);
+}
#endif
void
@@ -1437,14 +3148,18 @@ pcap_getnonblock(pcap_t *p, char *errbuf)
{
int ret;
- ret = p->getnonblock_op(p, errbuf);
+ ret = p->getnonblock_op(p);
if (ret == -1) {
/*
- * In case somebody depended on the bug wherein
- * the error message was put into p->errbuf
- * by pcap_getnonblock_fd().
+ * The get nonblock operation sets p->errbuf; this
+ * function *shouldn't* have had a separate errbuf
+ * argument, as it didn't need one, but I goofed
+ * when adding it.
+ *
+ * We copy the error message to errbuf, so callers
+ * can find it in either place.
*/
- strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE);
+ strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
}
return (ret);
}
@@ -1455,14 +3170,14 @@ pcap_getnonblock(pcap_t *p, char *errbuf)
*/
#if !defined(_WIN32) && !defined(MSDOS)
int
-pcap_getnonblock_fd(pcap_t *p, char *errbuf)
+pcap_getnonblock_fd(pcap_t *p)
{
int fdflags;
fdflags = fcntl(p->fd, F_GETFL, 0);
if (fdflags == -1) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_GETFL");
return (-1);
}
if (fdflags & O_NONBLOCK)
@@ -1477,14 +3192,18 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
{
int ret;
- ret = p->setnonblock_op(p, nonblock, errbuf);
+ ret = p->setnonblock_op(p, nonblock);
if (ret == -1) {
/*
- * In case somebody depended on the bug wherein
- * the error message was put into p->errbuf
- * by pcap_setnonblock_fd().
+ * The set nonblock operation sets p->errbuf; this
+ * function *shouldn't* have had a separate errbuf
+ * argument, as it didn't need one, but I goofed
+ * when adding it.
+ *
+ * We copy the error message to errbuf, so callers
+ * can find it in either place.
*/
- strlcpy(p->errbuf, errbuf, PCAP_ERRBUF_SIZE);
+ strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
}
return (ret);
}
@@ -1497,14 +3216,14 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
* needs to do some additional work.)
*/
int
-pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf)
+pcap_setnonblock_fd(pcap_t *p, int nonblock)
{
int fdflags;
fdflags = fcntl(p->fd, F_GETFL, 0);
if (fdflags == -1) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_GETFL");
return (-1);
}
if (nonblock)
@@ -1512,8 +3231,8 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf)
else
fdflags &= ~O_NONBLOCK;
if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_SETFL");
return (-1);
}
return (0);
@@ -1532,7 +3251,7 @@ pcap_win32_err_to_str(DWORD error, char *errbuf)
size_t errlen;
char *p;
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
PCAP_ERRBUF_SIZE, NULL);
/*
@@ -1617,9 +3336,9 @@ pcap_strerror(int errnum)
#ifdef HAVE_STRERROR
#ifdef _WIN32
static char errbuf[PCAP_ERRBUF_SIZE];
- errno_t errno;
- errno = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
- if (errno != 0) /* errno = 0 if successful */
+ errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
+
+ if (err != 0) /* err = 0 if successful */
strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
return (errbuf);
#else
@@ -1666,14 +3385,6 @@ pcap_stats(pcap_t *p, struct pcap_stat *ps)
return (p->stats_op(p, ps));
}
-static int
-pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Statistics aren't available from a pcap_open_dead pcap_t");
- return (-1);
-}
-
#ifdef _WIN32
struct pcap_stat *
pcap_stats_ex(pcap_t *p, int *pcap_stat_size)
@@ -1687,86 +3398,36 @@ pcap_setbuff(pcap_t *p, int dim)
return (p->setbuff_op(p, dim));
}
-static int
-pcap_setbuff_dead(pcap_t *p, int dim)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_setmode(pcap_t *p, int mode)
{
return (p->setmode_op(p, mode));
}
-static int
-pcap_setmode_dead(pcap_t *p, int mode)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "impossible to set mode on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_setmintocopy(pcap_t *p, int size)
{
return (p->setmintocopy_op(p, size));
}
-static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
- return (-1);
-}
-
HANDLE
pcap_getevent(pcap_t *p)
{
return (p->getevent_op(p));
}
-static HANDLE
-pcap_getevent_dead(pcap_t *p)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "A pcap_open_dead pcap_t has no event handle");
- return (INVALID_HANDLE_VALUE);
-}
-
int
pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp)
{
return (p->oid_get_request_op(p, oid, data, lenp));
}
-static int
-pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
- size_t *lenp _U_)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "An OID get request cannot be performed on a pcap_open_dead pcap_t");
- return (PCAP_ERROR);
-}
-
int
pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp)
{
return (p->oid_set_request_op(p, oid, data, lenp));
}
-static int
-pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
- size_t *lenp _U_)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "An OID set request cannot be performed on a pcap_open_dead pcap_t");
- return (PCAP_ERROR);
-}
-
pcap_send_queue *
pcap_sendqueue_alloc(u_int memsize)
{
@@ -1822,56 +3483,24 @@ pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
return (p->sendqueue_transmit_op(p, queue, sync));
}
-static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Packets cannot be transmitted on a pcap_open_dead pcap_t");
- return (0);
-}
-
int
pcap_setuserbuffer(pcap_t *p, int size)
{
return (p->setuserbuffer_op(p, size));
}
-static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The user buffer cannot be set on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
{
return (p->live_dump_op(p, filename, maxsize, maxpacks));
}
-static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_live_dump_ended(pcap_t *p, int sync)
{
return (p->live_dump_ended_op(p, sync));
}
-static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
- return (-1);
-}
-
PAirpcapHandle
pcap_get_airpcap_handle(pcap_t *p)
{
@@ -1884,12 +3513,6 @@ pcap_get_airpcap_handle(pcap_t *p)
}
return (handle);
}
-
-static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
-{
- return (NULL);
-}
#endif
/*
@@ -2012,66 +3635,6 @@ pcap_cleanup_live_common(pcap_t *p)
#endif
}
-static void
-pcap_cleanup_dead(pcap_t *p _U_)
-{
- /* Nothing to do. */
-}
-
-pcap_t *
-pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
-{
- pcap_t *p;
-
- switch (precision) {
-
- case PCAP_TSTAMP_PRECISION_MICRO:
- case PCAP_TSTAMP_PRECISION_NANO:
- break;
-
- default:
- return NULL;
- }
- p = malloc(sizeof(*p));
- if (p == NULL)
- return NULL;
- memset (p, 0, sizeof(*p));
- p->snapshot = snaplen;
- p->linktype = linktype;
- p->opt.tstamp_precision = precision;
- p->stats_op = pcap_stats_dead;
-#ifdef _WIN32
- p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
- p->setbuff_op = pcap_setbuff_dead;
- p->setmode_op = pcap_setmode_dead;
- p->setmintocopy_op = pcap_setmintocopy_dead;
- p->getevent_op = pcap_getevent_dead;
- p->oid_get_request_op = pcap_oid_get_request_dead;
- p->oid_set_request_op = pcap_oid_set_request_dead;
- p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
- p->setuserbuffer_op = pcap_setuserbuffer_dead;
- p->live_dump_op = pcap_live_dump_dead;
- p->live_dump_ended_op = pcap_live_dump_ended_dead;
- p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
-#endif
- p->cleanup_op = pcap_cleanup_dead;
-
- /*
- * A "dead" pcap_t never requires special BPF code generation.
- */
- p->bpf_codegen_flags = 0;
-
- p->activated = 1;
- return (p);
-}
-
-pcap_t *
-pcap_open_dead(int linktype, int snaplen)
-{
- return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
- PCAP_TSTAMP_PRECISION_MICRO));
-}
-
/*
* API compatible with WinPcap's "send a packet" routine - returns -1
* on error, 0 otherwise.
@@ -2123,160 +3686,251 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
return (0);
}
-#include "pcap_version.h"
+static int
+pcap_can_set_rfmon_dead(pcap_t *p)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
+
+static int
+pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
+ u_char *user _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets aren't available from a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_inject_dead(pcap_t *p, const void *buf _U_, size_t size _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets can't be sent on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A filter cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The packet direction cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_getnonblock_dead(pcap_t *p)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+ return (-1);
+}
+
+static int
+pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+ return (-1);
+}
+
+static int
+pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from a pcap_open_dead pcap_t");
+ return (-1);
+}
#ifdef _WIN32
+struct pcap_stat *
+pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from a pcap_open_dead pcap_t");
+ return (NULL);
+}
-static char *full_pcap_version_string;
+static int
+pcap_setbuff_dead(pcap_t *p, int dim)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
-#ifdef HAVE_VERSION_H
-/*
- * libpcap being built for Windows, as part of a WinPcap/Npcap source
- * tree. Include version.h from that source tree to get the WinPcap/Npcap
- * version.
- *
- * XXX - it'd be nice if we could somehow generate the WinPcap version number
- * when building WinPcap. (It'd be nice to do so for the packet.dll version
- * number as well.)
- */
-#include "../../version.h"
+static int
+pcap_setmode_dead(pcap_t *p, int mode)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "impossible to set mode on a pcap_open_dead pcap_t");
+ return (-1);
+}
-static const char wpcap_version_string[] = WINPCAP_VER_STRING;
-static const char pcap_version_string_fmt[] =
- WINPCAP_PRODUCT_NAME " version %s, based on %s";
-static const char pcap_version_string_packet_dll_fmt[] =
- WINPCAP_PRODUCT_NAME " version %s (packet.dll version %s), based on %s";
+static int
+pcap_setmintocopy_dead(pcap_t *p, int size)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
-const char *
-pcap_lib_version(void)
+static HANDLE
+pcap_getevent_dead(pcap_t *p)
{
- char *packet_version_string;
- size_t full_pcap_version_string_len;
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t has no event handle");
+ return (INVALID_HANDLE_VALUE);
+}
- if (full_pcap_version_string == NULL) {
- /*
- * Generate the version string.
- */
- packet_version_string = PacketGetVersion();
- if (strcmp(wpcap_version_string, packet_version_string) == 0) {
- /*
- * WinPcap version string and packet.dll version
- * string are the same; just report the WinPcap
- * version.
- */
- full_pcap_version_string_len =
- (sizeof pcap_version_string_fmt - 4) +
- strlen(wpcap_version_string) +
- strlen(pcap_version_string);
- full_pcap_version_string =
- malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- pcap_version_string_fmt,
- wpcap_version_string,
- pcap_version_string);
- } else {
- /*
- * WinPcap version string and packet.dll version
- * string are different; that shouldn't be the
- * case (the two libraries should come from the
- * same version of WinPcap), so we report both
- * versions.
- */
- full_pcap_version_string_len =
- (sizeof pcap_version_string_packet_dll_fmt - 6) +
- strlen(wpcap_version_string) +
- strlen(packet_version_string) +
- strlen(pcap_version_string);
- full_pcap_version_string = malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- pcap_version_string_packet_dll_fmt,
- wpcap_version_string,
- packet_version_string,
- pcap_version_string);
- }
- }
- return (full_pcap_version_string);
+static int
+pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+ size_t *lenp _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID get request cannot be performed on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
}
-#else /* HAVE_VERSION_H */
+static int
+pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+ size_t *lenp _U_)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID set request cannot be performed on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
-/*
- * libpcap being built for Windows, not as part of a WinPcap/Npcap source
- * tree.
- */
-static const char pcap_version_string_packet_dll_fmt[] =
- "%s (packet.dll version %s)";
-const char *
-pcap_lib_version(void)
+static u_int
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
{
- char *packet_version_string;
- size_t full_pcap_version_string_len;
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets cannot be transmitted on a pcap_open_dead pcap_t");
+ return (0);
+}
- if (full_pcap_version_string == NULL) {
- /*
- * Generate the version string. Report the packet.dll
- * version.
- */
- packet_version_string = PacketGetVersion();
- full_pcap_version_string_len =
- (sizeof pcap_version_string_packet_dll_fmt - 4) +
- strlen(pcap_version_string) +
- strlen(packet_version_string);
- full_pcap_version_string = malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- pcap_version_string_packet_dll_fmt,
- pcap_version_string,
- packet_version_string);
- }
- return (full_pcap_version_string);
+static int
+pcap_setuserbuffer_dead(pcap_t *p, int size)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The user buffer cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
}
-#endif /* HAVE_VERSION_H */
+static int
+pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+ return (-1);
+}
-#elif defined(MSDOS)
+static int
+pcap_live_dump_ended_dead(pcap_t *p, int sync)
+{
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static PAirpcapHandle
+pcap_get_airpcap_handle_dead(pcap_t *p)
+{
+ return (NULL);
+}
+#endif /* _WIN32 */
-static char *full_pcap_version_string;
+static void
+pcap_cleanup_dead(pcap_t *p _U_)
+{
+ /* Nothing to do. */
+}
-const char *
-pcap_lib_version (void)
+pcap_t *
+pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
{
- char *packet_version_string;
- size_t full_pcap_version_string_len;
- static char dospfx[] = "DOS-";
+ pcap_t *p;
+
+ switch (precision) {
+
+ case PCAP_TSTAMP_PRECISION_MICRO:
+ case PCAP_TSTAMP_PRECISION_NANO:
+ break;
- if (full_pcap_version_string == NULL) {
+ default:
/*
- * Generate the version string.
+ * This doesn't really matter, but we don't have any way
+ * to report particular errors, so the only failure we
+ * should have is a memory allocation failure. Just
+ * pick microsecond precision.
*/
- full_pcap_version_string_len =
- sizeof dospfx + strlen(pcap_version_string);
- full_pcap_version_string =
- malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- strcpy(full_pcap_version_string, dospfx);
- strcat(full_pcap_version_string, pcap_version_string);
+ precision = PCAP_TSTAMP_PRECISION_MICRO;
+ break;
}
- return (full_pcap_version_string);
-}
+ p = malloc(sizeof(*p));
+ if (p == NULL)
+ return NULL;
+ memset (p, 0, sizeof(*p));
+ p->snapshot = snaplen;
+ p->linktype = linktype;
+ p->opt.tstamp_precision = precision;
+ p->can_set_rfmon_op = pcap_can_set_rfmon_dead;
+ p->read_op = pcap_read_dead;
+ p->inject_op = pcap_inject_dead;
+ p->setfilter_op = pcap_setfilter_dead;
+ p->setdirection_op = pcap_setdirection_dead;
+ p->set_datalink_op = pcap_set_datalink_dead;
+ p->getnonblock_op = pcap_getnonblock_dead;
+ p->setnonblock_op = pcap_setnonblock_dead;
+ p->stats_op = pcap_stats_dead;
+#ifdef _WIN32
+ p->stats_ex_op = pcap_stats_ex_dead;
+ p->setbuff_op = pcap_setbuff_dead;
+ p->setmode_op = pcap_setmode_dead;
+ p->setmintocopy_op = pcap_setmintocopy_dead;
+ p->getevent_op = pcap_getevent_dead;
+ p->oid_get_request_op = pcap_oid_get_request_dead;
+ p->oid_set_request_op = pcap_oid_set_request_dead;
+ p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
+ p->setuserbuffer_op = pcap_setuserbuffer_dead;
+ p->live_dump_op = pcap_live_dump_dead;
+ p->live_dump_ended_op = pcap_live_dump_ended_dead;
+ p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
+#endif
+ p->cleanup_op = pcap_cleanup_dead;
-#else /* UN*X */
+ /*
+ * A "dead" pcap_t never requires special BPF code generation.
+ */
+ p->bpf_codegen_flags = 0;
-const char *
-pcap_lib_version(void)
+ p->activated = 1;
+ return (p);
+}
+
+pcap_t *
+pcap_open_dead(int linktype, int snaplen)
{
- return (pcap_version_string);
+ return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
+ PCAP_TSTAMP_PRECISION_MICRO));
}
-#endif
#ifdef YYDEBUG
/*
@@ -2296,32 +3950,6 @@ PCAP_API void pcap_set_parser_debug(int value);
PCAP_API_DEF void
pcap_set_parser_debug(int value)
{
- extern int pcap_debug;
-
pcap_debug = value;
}
#endif
-
-#ifdef BDEBUG
-/*
- * Set the internal "debug printout" flag for the filter expression optimizer.
- * The code to print that stuff is present only if BDEBUG is defined, so
- * the flag, and the routine to set it, are defined only if BDEBUG is
- * defined.
- *
- * This is intended for libpcap developers, not for general use.
- * If you want to set these in a program, you'll have to declare this
- * routine yourself, with the appropriate DLL import attribute on Windows;
- * it's not declared in any header file, and won't be declared in any
- * header file provided by libpcap.
- */
-PCAP_API void pcap_set_optimizer_debug(int value);
-
-PCAP_API_DEF void
-pcap_set_optimizer_debug(int value)
-{
- extern int pcap_optimizer_debug;
-
- pcap_optimizer_debug = value;
-}
-#endif