aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--caputils/capture-pcap-util-int.h28
-rw-r--r--caputils/capture-pcap-util-unix.c29
-rw-r--r--caputils/capture-pcap-util.c715
-rw-r--r--caputils/capture-pcap-util.h21
-rw-r--r--caputils/capture-wpcap.c64
-rw-r--r--cmake/modules/FindPCAP.cmake25
-rw-r--r--dumpcap.c609
7 files changed, 852 insertions, 639 deletions
diff --git a/caputils/capture-pcap-util-int.h b/caputils/capture-pcap-util-int.h
index d49a0cef04..dc9600f3e1 100644
--- a/caputils/capture-pcap-util-int.h
+++ b/caputils/capture-pcap-util-int.h
@@ -34,6 +34,34 @@ extern GList *get_interface_list_findalldevs_ex(const char *source,
extern GList *get_interface_list_findalldevs(int *err, char **err_str);
#endif /* HAVE_PCAP_FINDALLDEVS */
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+/*
+ * Request that a pcap_t provide high-resolution (nanosecond) time
+ * stamps; if that request fails, we'll just silently continue to
+ * use the microsecond-resolution time stamps, and our caller will
+ * find out, when they call have_high_resolution_timestamp(), that
+ * we don't have high-resolution time stamps.
+ */
+extern void request_high_resolution_timestamp(pcap_t *pcap_h);
+#endif
+
+extern if_capabilities_t *get_if_capabilities_local(interface_options *interface_opts,
+ char **err_str);
+extern pcap_t *open_capture_device_local(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+#ifdef HAVE_PCAP_CREATE
+extern if_capabilities_t *get_if_capabilities_pcap_create(interface_options *interface_opts,
+ char **err_str);
+extern pcap_t *open_capture_device_pcap_create(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+#endif /* HAVE_PCAP_CREATE */
+extern if_capabilities_t *get_if_capabilities_pcap_open_live(interface_options *interface_opts,
+ char **err_str);
+extern pcap_t *open_capture_device_pcap_open_live(interface_options *interface_opts,
+ int timeout, char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+
/*
* Get an error message string for a CANT_GET_INTERFACE_LIST error from
* "get_interface_list()". This is used to let the error message string
diff --git a/caputils/capture-pcap-util-unix.c b/caputils/capture-pcap-util-unix.c
index a39ba0a020..244682772a 100644
--- a/caputils/capture-pcap-util-unix.c
+++ b/caputils/capture-pcap-util-unix.c
@@ -422,6 +422,35 @@ have_high_resolution_timestamp(pcap_t *pcap_h)
#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+if_capabilities_t *
+get_if_capabilities_local(interface_options *interface_opts, char **err_str)
+{
+#ifdef HAVE_PCAP_CREATE
+ return get_if_capabilities_pcap_create(interface_opts, err_str);
+#else
+ return get_if_capabilities_pcap_open_live(interface_opts, err_str);
+#endif
+}
+
+pcap_t *
+open_capture_device_local(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ /*
+ * We're not opening a remote device; use pcap_create() and
+ * pcap_activate() if we have them, so that we can set various
+ * options, otherwise use pcap_open_live().
+ */
+#ifdef HAVE_PCAP_CREATE
+ return open_capture_device_pcap_create(capture_opts,
+ interface_opts, timeout, open_err_str);
+#else
+ return open_capture_device_pcap_open_live(interface_opts, timeout,
+ open_err_str);
+#endif
+}
+
/*
* Get the versions of libpcap, libpcap, and libnl with which we were
* compiled, and append them to a GString.
diff --git a/caputils/capture-pcap-util.c b/caputils/capture-pcap-util.c
index 95aec2da72..8a498f6b9c 100644
--- a/caputils/capture-pcap-util.c
+++ b/caputils/capture-pcap-util.c
@@ -39,10 +39,45 @@
#include <sys/socket.h>
#endif
+/*
+ * Linux bonding devices mishandle unknown ioctls; they fail
+ * with ENODEV rather than ENOTSUP, EOPNOTSUPP, or ENOTTY,
+ * so pcap_can_set_rfmon() returns a "no such device" indication
+ * if we try to do SIOCGIWMODE on them.
+ *
+ * So, on Linux, we check for bonding devices, if we can, before
+ * trying pcap_can_set_rfmon(), as pcap_can_set_rfmon() will
+ * end up trying SIOCGIWMODE on the device if that ioctl exists.
+ */
+#if defined(HAVE_PCAP_CREATE) && defined(__linux__)
+
+#include <sys/ioctl.h>
+
+/*
+ * If we're building for a Linux version that supports bonding,
+ * HAVE_BONDING will be defined.
+ */
+
+#ifdef HAVE_LINUX_SOCKIOS_H
+#include <linux/sockios.h>
+#endif
+
+#ifdef HAVE_LINUX_IF_BONDING_H
+#include <linux/if_bonding.h>
+#endif
+
+#if defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY)
+#define HAVE_BONDING
+#endif
+
+#endif /* defined(HAVE_PCAP_CREATE) && defined(__linux__) */
+
#include "caputils/capture_ifinfo.h"
#include "caputils/capture-pcap-util.h"
#include "caputils/capture-pcap-util-int.h"
+#include "log.h"
+
#include <wsutil/file_util.h>
#ifndef _WIN32
@@ -54,6 +89,14 @@
#endif
/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+ "Please report this to the Wireshark developers.\n"
+ "https://bugs.wireshark.org/\n"
+ "(This is not a crash; please do not report it as such.)";
+
+/*
* Given an interface name, find the "friendly name" and interface
* type for the interface.
*/
@@ -635,11 +678,681 @@ linktype_val_to_name(int dlt)
return pcap_datalink_val_to_name(dlt);
}
-int linktype_name_to_val(const char *linktype)
+int
+linktype_name_to_val(const char *linktype)
{
return pcap_datalink_name_to_val(linktype);
}
+/*
+ * Get the data-link type for a libpcap device.
+ * This works around AIX 5.x's non-standard and incompatible-with-the-
+ * rest-of-the-universe libpcap.
+ */
+int
+get_pcap_datalink(pcap_t *pch, const char *devicename
+#ifndef _AIX
+ _U_)
+#else
+ )
+#endif
+{
+ int datalink;
+#ifdef _AIX
+ const char *ifacename;
+#endif
+
+ datalink = pcap_datalink(pch);
+#ifdef _AIX
+
+ /*
+ * The libpcap that comes with AIX 5.x uses RFC 1573 ifType values
+ * rather than DLT_ values for link-layer types; the ifType values
+ * for LAN devices are:
+ *
+ * Ethernet 6
+ * 802.3 7
+ * Token Ring 9
+ * FDDI 15
+ *
+ * and the ifType value for a loopback device is 24.
+ *
+ * The AIX names for LAN devices begin with:
+ *
+ * Ethernet en
+ * 802.3 et
+ * Token Ring tr
+ * FDDI fi
+ *
+ * and the AIX names for loopback devices begin with "lo".
+ *
+ * (The difference between "Ethernet" and "802.3" is presumably
+ * whether packets have an Ethernet header, with a packet type,
+ * or an 802.3 header, with a packet length, followed by an 802.2
+ * header and possibly a SNAP header.)
+ *
+ * If the device name matches "datalink" interpreted as an ifType
+ * value, rather than as a DLT_ value, we will assume this is AIX's
+ * non-standard, incompatible libpcap, rather than a standard libpcap,
+ * and will map the link-layer type to the standard DLT_ value for
+ * that link-layer type, as that's what the rest of Wireshark expects.
+ *
+ * (This means the capture files won't be readable by a tcpdump
+ * linked with AIX's non-standard libpcap, but so it goes. They
+ * *will* be readable by standard versions of tcpdump, Wireshark,
+ * and so on.)
+ *
+ * XXX - if we conclude we're using AIX libpcap, should we also
+ * set a flag to cause us to assume the time stamps are in
+ * seconds-and-nanoseconds form, and to convert them to
+ * seconds-and-microseconds form before processing them and
+ * writing them out?
+ */
+
+ /*
+ * Find the last component of the device name, which is the
+ * interface name.
+ */
+ ifacename = strchr(devicename, '/');
+ if (ifacename == NULL)
+ ifacename = devicename;
+
+ /* See if it matches any of the LAN device names. */
+ if (strncmp(ifacename, "en", 2) == 0) {
+ if (datalink == 6) {
+ /*
+ * That's the RFC 1573 value for Ethernet;
+ * map it to DLT_EN10MB.
+ */
+ datalink = 1;
+ }
+ } else if (strncmp(ifacename, "et", 2) == 0) {
+ if (datalink == 7) {
+ /*
+ * That's the RFC 1573 value for 802.3;
+ * map it to DLT_EN10MB.
+ *
+ * (libpcap, tcpdump, Wireshark, etc. don't
+ * care if it's Ethernet or 802.3.)
+ */
+ datalink = 1;
+ }
+ } else if (strncmp(ifacename, "tr", 2) == 0) {
+ if (datalink == 9) {
+ /*
+ * That's the RFC 1573 value for 802.5 (Token Ring);
+ * map it to DLT_IEEE802, which is what's used for
+ * Token Ring.
+ */
+ datalink = 6;
+ }
+ } else if (strncmp(ifacename, "fi", 2) == 0) {
+ if (datalink == 15) {
+ /*
+ * That's the RFC 1573 value for FDDI;
+ * map it to DLT_FDDI.
+ */
+ datalink = 10;
+ }
+ } else if (strncmp(ifacename, "lo", 2) == 0) {
+ if (datalink == 24) {
+ /*
+ * That's the RFC 1573 value for "software loopback"
+ * devices; map it to DLT_NULL, which is what's used
+ * for loopback devices on BSD.
+ */
+ datalink = 0;
+ }
+ }
+#endif
+
+ return datalink;
+}
+
+/* Set the data link type on a pcap. */
+gboolean
+set_pcap_datalink(pcap_t *pcap_h, int datalink, char *name,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len)
+{
+ char *set_datalink_err_str;
+
+ if (datalink == -1)
+ return TRUE; /* just use the default */
+#ifdef HAVE_PCAP_SET_DATALINK
+ if (pcap_set_datalink(pcap_h, datalink) == 0)
+ return TRUE; /* no error */
+ set_datalink_err_str = pcap_geterr(pcap_h);
+#else
+ /* Let them set it to the type it is; reject any other request. */
+ if (get_pcap_datalink(pcap_h, name) == datalink)
+ return TRUE; /* no error */
+ set_datalink_err_str =
+ "That DLT isn't one of the DLTs supported by this device";
+#endif
+ g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type on interface '%s' (%s).",
+ name, set_datalink_err_str);
+ /*
+ * If the error isn't "XXX is not one of the DLTs supported by this device",
+ * tell the user to tell the Wireshark developers about it.
+ */
+ if (strstr(set_datalink_err_str, "is not one of the DLTs supported by this device") == NULL)
+ g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
+ else
+ secondary_errmsg[0] = '\0';
+ return FALSE;
+}
+
+static data_link_info_t *
+create_data_link_info(int dlt)
+{
+ data_link_info_t *data_link_info;
+ const char *text;
+
+ data_link_info = (data_link_info_t *)g_malloc(sizeof (data_link_info_t));
+ data_link_info->dlt = dlt;
+ text = pcap_datalink_val_to_name(dlt);
+ if (text != NULL)
+ data_link_info->name = g_strdup(text);
+ else
+ data_link_info->name = g_strdup_printf("DLT %d", dlt);
+ text = pcap_datalink_val_to_description(dlt);
+ if (text != NULL)
+ data_link_info->description = g_strdup(text);
+ else
+ data_link_info->description = NULL;
+ return data_link_info;
+}
+
+#ifdef HAVE_PCAP_CREATE
+#if defined(HAVE_BONDING) && defined(HAVE_PCAP_CREATE)
+static gboolean
+is_linux_bonding_device(const char *ifname)
+{
+ int fd;
+ struct ifreq ifr;
+ ifbond ifb;
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd == -1)
+ return FALSE;
+
+ memset(&ifr, 0, sizeof ifr);
+ g_strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
+ memset(&ifb, 0, sizeof ifb);
+ ifr.ifr_data = (caddr_t)&ifb;
+#if defined(SIOCBONDINFOQUERY)
+ if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) {
+ close(fd);
+ return TRUE;
+ }
+#else
+ if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) {
+ close(fd);
+ return TRUE;
+ }
+#endif
+
+ close(fd);
+ return FALSE;
+}
+#elif defined(HAVE_PCAP_CREATE)
+static gboolean
+is_linux_bonding_device(const char *ifname _U_)
+{
+ return FALSE;
+}
+#endif
+
+static GList *
+get_data_link_types(pcap_t *pch, interface_options *interface_opts,
+ char **err_str)
+{
+ GList *data_link_types;
+ int deflt;
+#ifdef HAVE_PCAP_LIST_DATALINKS
+ int *linktypes;
+ int i, nlt;
+#endif
+ data_link_info_t *data_link_info;
+
+ deflt = get_pcap_datalink(pch, interface_opts->name);
+#ifdef HAVE_PCAP_LIST_DATALINKS
+ nlt = pcap_list_datalinks(pch, &linktypes);
+ if (nlt == 0 || linktypes == NULL) {
+ pcap_close(pch);
+ if (err_str != NULL)
+ *err_str = NULL; /* an empty list doesn't mean an error */
+ return NULL;
+ }
+ data_link_types = NULL;
+ for (i = 0; i < nlt; i++) {
+ data_link_info = create_data_link_info(linktypes[i]);
+
+ /*
+ * XXX - for 802.11, make the most detailed 802.11
+ * version the default, rather than the one the
+ * device has as the default?
+ */
+ if (linktypes[i] == deflt)
+ data_link_types = g_list_prepend(data_link_types,
+ data_link_info);
+ else
+ data_link_types = g_list_append(data_link_types,
+ data_link_info);
+ }
+#ifdef HAVE_PCAP_FREE_DATALINKS
+ pcap_free_datalinks(linktypes);
+#else
+ /*
+ * In Windows, there's no guarantee that if you have a library
+ * built with one version of the MSVC++ run-time library, and
+ * it returns a pointer to allocated data, you can free that
+ * data from a program linked with another version of the
+ * MSVC++ run-time library.
+ *
+ * This is not an issue on UN*X.
+ *
+ * See the mail threads starting at
+ *
+ * https://www.winpcap.org/pipermail/winpcap-users/2006-September/001421.html
+ *
+ * and
+ *
+ * https://www.winpcap.org/pipermail/winpcap-users/2008-May/002498.html
+ */
+#ifndef _WIN32
+#define xx_free free /* hack so checkAPIs doesn't complain */
+ xx_free(linktypes);
+#endif /* _WIN32 */
+#endif /* HAVE_PCAP_FREE_DATALINKS */
+#else /* HAVE_PCAP_LIST_DATALINKS */
+
+ data_link_info = create_data_link_info(deflt);
+ data_link_types = g_list_append(data_link_types, data_link_info);
+#endif /* HAVE_PCAP_LIST_DATALINKS */
+
+ if (err_str != NULL)
+ *err_str = NULL;
+ return data_link_types;
+}
+
+if_capabilities_t *
+get_if_capabilities_pcap_create(interface_options *interface_opts,
+ char **err_str)
+{
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pch;
+ int status;
+
+ /*
+ * Allocate the interface capabilities structure.
+ */
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+
+ pch = pcap_create(interface_opts->name, errbuf);
+ if (pch == NULL) {
+ if (err_str != NULL)
+ *err_str = g_strdup(errbuf);
+ g_free(caps);
+ return NULL;
+ }
+ if (is_linux_bonding_device(interface_opts->name)) {
+ /*
+ * Linux bonding device; not Wi-Fi, so no monitor mode, and
+ * calling pcap_can_set_rfmon() might get a "no such device"
+ * error.
+ */
+ status = 0;
+ } else {
+ /*
+ * Not a Linux bonding device, so go ahead.
+ */
+ status = pcap_can_set_rfmon(pch);
+ }
+ if (status < 0) {
+ /* Error. */
+ if (status == PCAP_ERROR)
+ *err_str = g_strdup_printf("pcap_can_set_rfmon() failed: %s",
+ pcap_geterr(pch));
+ else
+ *err_str = g_strdup(pcap_statustostr(status));
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+ if (status == 0)
+ caps->can_set_rfmon = FALSE;
+ else if (status == 1) {
+ caps->can_set_rfmon = TRUE;
+ if (interface_opts->monitor_mode)
+ pcap_set_rfmon(pch, 1);
+ } else {
+ if (err_str != NULL) {
+ *err_str = g_strdup_printf("pcap_can_set_rfmon() returned %d",
+ status);
+ }
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+
+ status = pcap_activate(pch);
+ if (status < 0) {
+ /* Error. We ignore warnings (status > 0). */
+ if (err_str != NULL) {
+ if (status == PCAP_ERROR)
+ *err_str = g_strdup_printf("pcap_activate() failed: %s",
+ pcap_geterr(pch));
+ else
+ *err_str = g_strdup(pcap_statustostr(status));
+ }
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+
+ caps->data_link_types = get_data_link_types(pch, interface_opts,
+ err_str);
+ if (caps->data_link_types == NULL) {
+ pcap_close(pch);
+ if (err_str != NULL)
+ *err_str = NULL; /* an empty list doesn't mean an error */
+ g_free(caps);
+ return NULL;
+ }
+
+ pcap_close(pch);
+
+ if (err_str != NULL)
+ *err_str = NULL;
+ return caps;
+}
+
+pcap_t *
+open_capture_device_pcap_create(capture_options *capture_opts
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+ ,
+#else
+ _U_,
+#endif
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ pcap_t *pcap_h;
+ int err;
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_create() using %s.", interface_opts->name);
+ pcap_h = pcap_create(interface_opts->name, *open_err_str);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_create() returned %p.", (void *)pcap_h);
+ if (pcap_h != NULL) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_set_snaplen() with snaplen %d.",
+ interface_opts->snaplen);
+ pcap_set_snaplen(pcap_h, interface_opts->snaplen);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_set_promisc() with promisc_mode %d.",
+ interface_opts->promisc_mode);
+ pcap_set_promisc(pcap_h, interface_opts->promisc_mode);
+ pcap_set_timeout(pcap_h, timeout);
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+ /*
+ * If we're writing pcap-ng files, try to enable
+ * nanosecond-resolution capture; any code that
+ * can read pcap-ng files must be able to handle
+ * nanosecond-resolution time stamps. We don't
+ * care whether it succeeds or fails - if it fails,
+ * we just use the microsecond-precision time stamps
+ * we get.
+ *
+ * If we're writing pcap files, don't try to enable
+ * nanosecond-resolution capture, as not all code
+ * that reads pcap files recognizes the nanosecond-
+ * resolution pcap file magic number.
+ * We don't care whether this succeeds or fails; if it
+ * fails (because we don't have pcap_set_tstamp_precision(),
+ * or because we do but the OS or device doesn't support
+ * nanosecond resolution timing), we just use microsecond-
+ * resolution time stamps.
+ */
+ if (capture_opts->use_pcapng)
+ request_high_resolution_timestamp(pcap_h);
+#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "buffersize %d.", interface_opts->buffer_size);
+ if (interface_opts->buffer_size != 0)
+ pcap_set_buffer_size(pcap_h,
+ interface_opts->buffer_size * 1024 * 1024);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "monitor_mode %d.", interface_opts->monitor_mode);
+ if (interface_opts->monitor_mode)
+ pcap_set_rfmon(pcap_h, 1);
+ err = pcap_activate(pcap_h);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_activate() returned %d.", err);
+ if (err < 0) {
+ /* Failed to activate, set to NULL */
+ if (err == PCAP_ERROR)
+ g_strlcpy(*open_err_str, pcap_geterr(pcap_h),
+ sizeof *open_err_str);
+ else
+ g_strlcpy(*open_err_str, pcap_statustostr(err),
+ sizeof *open_err_str);
+ pcap_close(pcap_h);
+ pcap_h = NULL;
+ }
+ }
+ return pcap_h;
+}
+#endif /* HAVE_PCAP_CREATE */
+
+if_capabilities_t *
+get_if_capabilities_pcap_open_live(interface_options *interface_opts,
+ char **err_str)
+{
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pch;
+
+ /*
+ * Allocate the interface capabilities structure.
+ */
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+
+ pch = pcap_open_live(interface_opts->name, MIN_PACKET_SIZE, 0, 0,
+ errbuf);
+ caps->can_set_rfmon = FALSE;
+ if (pch == NULL) {
+ if (err_str != NULL)
+ *err_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
+ g_free(caps);
+ return NULL;
+ }
+ caps->data_link_types = get_data_link_types(pch, interface_opts,
+ err_str);
+ if (caps->data_link_types == NULL) {
+ pcap_close(pch);
+ if (err_str != NULL)
+ *err_str = NULL; /* an empty list doesn't mean an error */
+ g_free(caps);
+ return NULL;
+ }
+
+ pcap_close(pch);
+
+ if (err_str != NULL)
+ *err_str = NULL;
+ return caps;
+}
+
+pcap_t *
+open_capture_device_pcap_open_live(interface_options *interface_opts,
+ int timeout, char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ pcap_t *pcap_h;
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_open_live() calling using name %s, snaplen %d, promisc_mode %d.",
+ interface_opts->name, interface_opts->snaplen,
+ interface_opts->promisc_mode);
+ pcap_h = pcap_open_live(interface_opts->name, interface_opts->snaplen,
+ interface_opts->promisc_mode, timeout, *open_err_str);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_open_live() returned %p.", (void *)pcap_h);
+
+#ifdef _WIN32
+ /* If the open succeeded, try to set the capture buffer size. */
+ if (pcap_h && interface_opts->buffer_size > 1) {
+ /*
+ * We have no mechanism to report a warning if this
+ * fails; we just keep capturing with the smaller buffer,
+ * as is the case on systems with BPF and pcap_create()
+ * and pcap_set_buffer_size(), where pcap_activate() just
+ * silently clamps the buffer size to the maximum.
+ */
+ pcap_setbuff(pcap_h, interface_opts->buffer_size * 1024 * 1024);
+ }
+#endif
+
+ return pcap_h;
+}
+
+/*
+ * Get the capabilities of a network device.
+ */
+if_capabilities_t *
+get_if_capabilities(interface_options *interface_opts, char **err_str)
+{
+#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pch;
+ int deflt;
+ data_link_info_t *data_link_info;
+
+ if (strncmp (interface_opts->name, "rpcap://", 8) == 0) {
+ struct pcap_rmtauth auth;
+
+ /*
+ * Allocate the interface capabilities structure.
+ */
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+
+ auth.type = interface_opts->auth_type == CAPTURE_AUTH_PWD ?
+ RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+ auth.username = interface_opts->auth_username;
+ auth.password = interface_opts->auth_password;
+
+ /*
+ * WinPcap 4.1.2, and possibly earlier versions, have a bug
+ * wherein, when an open with an rpcap: URL fails, the error
+ * message for the error is not copied to errbuf and whatever
+ * on-the-stack junk is in errbuf is treated as the error
+ * message.
+ *
+ * To work around that (and any other bugs of that sort), we
+ * initialize errbuf to an empty string. If we get an error
+ * and the string is empty, we report it as an unknown error.
+ * (If we *don't* get an error, and the string is *non*-empty,
+ * that could be a warning returned, such as "can't turn
+ * promiscuous mode on"; we currently don't do so.)
+ */
+ errbuf[0] = '\0';
+ pch = pcap_open(interface_opts->name, MIN_PACKET_SIZE, 0, 0, &auth,
+ errbuf);
+ if (pch == NULL) {
+ if (err_str != NULL)
+ *err_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
+ g_free(caps);
+ return NULL;
+ }
+ deflt = get_pcap_datalink(pch, interface_opts->name);
+ data_link_info = create_data_link_info(deflt);
+ caps->data_link_types = g_list_append(caps->data_link_types,
+ data_link_info);
+ pcap_close(pch);
+
+ if (err_str != NULL)
+ *err_str = NULL;
+ return caps;
+ }
+#endif /* defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE) */
+
+ /*
+ * Local interface.
+ */
+ return get_if_capabilities_local(interface_opts, err_str);
+}
+
+pcap_t *
+open_capture_device(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ pcap_t *pcap_h;
+#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
+ struct pcap_rmtauth auth;
+#endif
+
+ /* Open the network interface to capture from it.
+ Some versions of libpcap may put warnings into the error buffer
+ if they succeed; to tell if that's happened, we have to clear
+ the error buffer, and check if it's still a null string. */
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Entering open_capture_device().");
+ (*open_err_str)[0] = '\0';
+#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
+ /*
+ * If we're opening a remote device, use pcap_open(); that's currently
+ * the only open routine that supports remote devices.
+ */
+ if (strncmp (interface_opts->name, "rpcap://", 8) == 0) {
+ auth.type = interface_opts->auth_type == CAPTURE_AUTH_PWD ?
+ RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+ auth.username = interface_opts->auth_username;
+ auth.password = interface_opts->auth_password;
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_open() using name %s, snaplen %d, promisc_mode %d, datatx_udp %d, nocap_rpcap %d.",
+ interface_opts->name, interface_opts->snaplen,
+ interface_opts->promisc_mode, interface_opts->datatx_udp,
+ interface_opts->nocap_rpcap);
+ pcap_h = pcap_open(interface_opts->name, interface_opts->snaplen,
+ /* flags */
+ (interface_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
+ (interface_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
+ (interface_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
+ timeout, &auth, *open_err_str);
+ if (pcap_h == NULL) {
+ /* Error - did pcap actually supply an error message? */
+ if ((*open_err_str)[0] == '\0') {
+ /*
+ * Work around known WinPcap bug wherein
+ * no error message is filled in on a
+ * failure to open an rpcap: URL.
+ */
+ g_strlcpy(*open_err_str,
+ "Unknown error (pcap bug; actual error cause not reported)",
+ sizeof *open_err_str);
+ }
+ }
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_open() returned %p.", (void *)pcap_h);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "open_capture_device %s : %s", pcap_h ? "SUCCESS" : "FAILURE", interface_opts->name);
+ return pcap_h;
+ }
+#endif
+
+ pcap_h = open_capture_device_local(capture_opts, interface_opts,
+ timeout, open_err_str);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "open_capture_device %s : %s", pcap_h ? "SUCCESS" : "FAILURE", interface_opts->name);
+ return pcap_h;
+}
+
#endif /* HAVE_LIBPCAP */
/*
diff --git a/caputils/capture-pcap-util.h b/caputils/capture-pcap-util.h
index 3cec18305b..1eaad35e5c 100644
--- a/caputils/capture-pcap-util.h
+++ b/caputils/capture-pcap-util.h
@@ -31,6 +31,8 @@ extern "C" {
#include <pcap.h>
+#include "capture_opts.h"
+
/*
* A snapshot length of 0 is useless - and libpcap/WinPcap don't guarantee
* that a snapshot length of 0 will work, and, on some platforms, it won't
@@ -50,23 +52,28 @@ GList *get_remote_interface_list(const char *hostname, const char *port,
const char *linktype_val_to_name(int dlt);
int linktype_name_to_val(const char *linktype);
-#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
-/*
- * Get the versions of capture libraries with which we were compiled,
- * and append them to a GString.
- */
-void request_high_resolution_timestamp(pcap_t *pcap_h);
+int get_pcap_datalink(pcap_t *pch, const char *devicename);
+gboolean set_pcap_datalink(pcap_t *pcap_h, int datalink, char *name,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len);
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
/*
* Return TRUE if the pcap_t in question is set up for high-precision
* time stamps, FALSE otherwise.
*/
gboolean have_high_resolution_timestamp(pcap_t *pcap_h);
-
#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
#endif /* HAVE_LIBPCAP */
+extern if_capabilities_t *get_if_capabilities(interface_options *interface_opts,
+ char **err_str);
+extern pcap_t *open_capture_device(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+
extern void get_compiled_caplibs_version(GString *str);
/*
diff --git a/caputils/capture-wpcap.c b/caputils/capture-wpcap.c
index 26a64a92f1..50e8a06fa1 100644
--- a/caputils/capture-wpcap.c
+++ b/caputils/capture-wpcap.c
@@ -112,23 +112,23 @@ static int (*p_pcap_set_datalink)(pcap_t *, int);
#endif
#ifdef HAVE_PCAP_FREE_DATALINKS
-static int (*p_pcap_free_datalinks)(int *);
+static int (*p_pcap_free_datalinks)(int *);
#endif
#ifdef HAVE_BPF_IMAGE
-static char *(*p_bpf_image) (const struct bpf_insn *, int);
+static char *(*p_bpf_image)(const struct bpf_insn *, int);
#endif
#ifdef HAVE_PCAP_CREATE
-static pcap_t* (*p_pcap_create) (const char *, char *);
-static int (*p_pcap_set_snaplen) (pcap_t *, int);
-static int (*p_pcap_set_promisc) (pcap_t *, int);
-static int (*p_pcap_can_set_rfmon) (pcap_t *);
-static int (*p_pcap_set_rfmon) (pcap_t *, int);
-static int (*p_pcap_set_timeout) (pcap_t *, int);
-static int (*p_pcap_set_buffer_size) (pcap_t *, int);
-static int (*p_pcap_activate) (pcap_t *);
-static const char* (*p_pcap_statustostr)(int);
+static pcap_t *(*p_pcap_create)(const char *, char *);
+static int (*p_pcap_set_snaplen)(pcap_t *, int);
+static int (*p_pcap_set_promisc)(pcap_t *, int);
+static int (*p_pcap_can_set_rfmon)(pcap_t *);
+static int (*p_pcap_set_rfmon)(pcap_t *, int);
+static int (*p_pcap_set_timeout)(pcap_t *, int);
+static int (*p_pcap_set_buffer_size)(pcap_t *, int);
+static int (*p_pcap_activate)(pcap_t *);
+static const char *(*p_pcap_statustostr)(int);
#endif
typedef struct {
@@ -207,14 +207,14 @@ load_wpcap(void)
SYM(bpf_image, FALSE),
#endif
#ifdef HAVE_PCAP_CREATE
- SYM(pcap_create, FALSE),
- SYM(pcap_set_snaplen, FALSE),
- SYM(pcap_set_promisc, FALSE),
+ SYM(pcap_create, TRUE),
+ SYM(pcap_set_snaplen, TRUE),
+ SYM(pcap_set_promisc, TRUE),
SYM(pcap_can_set_rfmon, TRUE),
SYM(pcap_set_rfmon, TRUE),
SYM(pcap_set_timeout, FALSE),
SYM(pcap_set_buffer_size, FALSE),
- SYM(pcap_activate, FALSE),
+ SYM(pcap_activate, TRUE),
SYM(pcap_statustostr, TRUE),
#endif
{ NULL, NULL, FALSE }
@@ -981,6 +981,40 @@ cant_get_if_list_error_message(const char *err_str)
return g_strdup_printf("Can't get list of interfaces: %s", err_str);
}
+if_capabilities_t *
+get_if_capabilities_local(interface_options *interface_opts, char **err_str)
+{
+ /*
+ * We're not getting capaibilities for a remote device; use
+ * pcap_create() and pcap_activate() if we have them, so that
+ * we can set various options, otherwise use pcap_open_live().
+ */
+#ifdef HAVE_PCAP_CREATE
+ if (p_pcap_create != NULL)
+ return get_if_capabilities_pcap_create(interface_opts, err_str);
+#endif
+ return get_if_capabilities_pcap_open_live(interface_opts, err_str);
+}
+
+pcap_t *
+open_capture_device_local(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ /*
+ * We're not opening a remote device; use pcap_create() and
+ * pcap_activate() if we have them, so that we can set various
+ * options, otherwise use pcap_open_live().
+ */
+#ifdef HAVE_PCAP_CREATE
+ if (p_pcap_create != NULL)
+ return open_capture_device_pcap_create(capture_opts,
+ interface_opts, timeout, open_err_str);
+#endif
+ return open_capture_device_pcap_open_live(interface_opts, timeout,
+ open_err_str);
+}
+
/*
* Append the version of WinPcap with which we were compiled to a GString.
*/
diff --git a/cmake/modules/FindPCAP.cmake b/cmake/modules/FindPCAP.cmake
index d49cd35629..c362cc0c3b 100644
--- a/cmake/modules/FindPCAP.cmake
+++ b/cmake/modules/FindPCAP.cmake
@@ -61,21 +61,16 @@ check_function_exists( "pcap_freecode" HAVE_PCAP_FREECODE )
# update libpcap without updating the headers.
#
check_function_exists( "pcap_breakloop" HAVE_PCAP_BREAKLOOP )
-# FIXME: The code (at least) in dumpcap assumes that PCAP_CREATE is not
-# available on Windows
-if( WIN32 )
- #
- # This is always the case with WinPcap.
- #
- set(CAN_SET_CAPTURE_BUFFER_SIZE TRUE)
-else()
- check_function_exists( "pcap_create" HAVE_PCAP_CREATE )
- if ( HAVE_PCAP_CREATE )
- #
- # For libpcap, we can set the buffer size if we have pcap_create().
- #
- set( CAN_SET_CAPTURE_BUFFER_SIZE TRUE )
- endif()
+check_function_exists( "pcap_create" HAVE_PCAP_CREATE )
+if( HAVE_PCAP_CREATE OR WIN32 )
+ #
+ # If we have pcap_create(), we have pcap_set_buffer_size(), and
+ # can set the capture buffer size.
+ #
+ # Otherwise, if this is Windows, we have pcap_setbuff(), and can
+ # set the capture buffer size.
+ #
+ set( CAN_SET_CAPTURE_BUFFER_SIZE TRUE )
endif()
check_function_exists( "pcap_datalink_name_to_val" HAVE_PCAP_DATALINK_NAME_TO_VAL )
check_function_exists( "pcap_datalink_val_to_description" HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION )
diff --git a/dumpcap.c b/dumpcap.c
index 0375d3fa27..c9511bea03 100644
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -51,39 +51,6 @@
#include <sys/utsname.h>
#endif
-/*
- * Linux bonding devices mishandle unknown ioctls; they fail
- * with ENODEV rather than ENOTSUP, EOPNOTSUPP, or ENOTTY,
- * so pcap_can_set_rfmon() returns a "no such device" indication
- * if we try to do SIOCGIWMODE on them.
- *
- * So, on Linux, we check for bonding devices, if we can, before
- * trying pcap_can_set_rfmon(), as pcap_can_set_rfmon() will
- * end up trying SIOCGIWMODE on the device if that ioctl exists.
- */
-#if defined(HAVE_PCAP_CREATE) && defined(__linux__)
-
-#include <sys/ioctl.h>
-
-/*
- * If we're building for a Linux version that supports bonding,
- * HAVE_BONDING will be defined.
- */
-
-#ifdef HAVE_LINUX_SOCKIOS_H
-#include <linux/sockios.h>
-#endif
-
-#ifdef HAVE_LINUX_IF_BONDING_H
-#include <linux/if_bonding.h>
-#endif
-
-#if defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY)
-#define HAVE_BONDING
-#endif
-
-#endif /* defined(HAVE_PCAP_CREATE) && defined(__linux__) */
-
#include <signal.h>
#include <errno.h>
@@ -383,7 +350,6 @@ static const char please_report[] =
*/
static loop_data global_ld;
-
/*
* Timeout, in milliseconds, for reads from the stream of captured packets
* from a capture device.
@@ -650,155 +616,6 @@ relinquish_all_capabilities(void)
}
#endif
-static pcap_t *
-open_capture_device(capture_options *capture_opts
-#ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
- _U_
-#endif
- ,
- interface_options *interface_opts,
- char (*open_err_str)[PCAP_ERRBUF_SIZE])
-{
- pcap_t *pcap_h;
-#ifdef HAVE_PCAP_CREATE
- int err;
-#endif
-#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
- struct pcap_rmtauth auth;
-#endif
-
- /* Open the network interface to capture from it.
- Some versions of libpcap may put warnings into the error buffer
- if they succeed; to tell if that's happened, we have to clear
- the error buffer, and check if it's still a null string. */
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Entering open_capture_device().");
- (*open_err_str)[0] = '\0';
-#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
- /*
- * If we're opening a remote device, use pcap_open(); that's currently
- * the only open routine that supports remote devices.
- */
- if (strncmp (interface_opts->name, "rpcap://", 8) == 0) {
- auth.type = interface_opts->auth_type == CAPTURE_AUTH_PWD ?
- RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
- auth.username = interface_opts->auth_username;
- auth.password = interface_opts->auth_password;
-
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "Calling pcap_open() using name %s, snaplen %d, promisc_mode %d, datatx_udp %d, nocap_rpcap %d.",
- interface_opts->name, interface_opts->snaplen, interface_opts->promisc_mode,
- interface_opts->datatx_udp, interface_opts->nocap_rpcap);
- pcap_h = pcap_open(interface_opts->name, interface_opts->snaplen,
- /* flags */
- (interface_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
- (interface_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
- (interface_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
- CAP_READ_TIMEOUT, &auth, *open_err_str);
- if (pcap_h == NULL) {
- /* Error - did pcap actually supply an error message? */
- if ((*open_err_str)[0] == '\0') {
- /* Work around known WinPcap bug wherein no error message is
- filled in on a failure to open an rpcap: URL. */
- g_strlcpy(*open_err_str,
- "Unknown error (pcap bug; actual error cause not reported)",
- sizeof *open_err_str);
- }
- }
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "pcap_open() returned %p.", (void *)pcap_h);
- } else
-#endif
- {
- /*
- * If we're not opening a remote device, use pcap_create() and
- * pcap_activate() if we have them, so that we can set the buffer
- * size, otherwise use pcap_open_live().
- */
-#ifdef HAVE_PCAP_CREATE
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "Calling pcap_create() using %s.", interface_opts->name);
- pcap_h = pcap_create(interface_opts->name, *open_err_str);
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "pcap_create() returned %p.", (void *)pcap_h);
- if (pcap_h != NULL) {
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "Calling pcap_set_snaplen() with snaplen %d.", interface_opts->snaplen);
- pcap_set_snaplen(pcap_h, interface_opts->snaplen);
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "Calling pcap_set_promisc() with promisc_mode %d.", interface_opts->promisc_mode);
- pcap_set_promisc(pcap_h, interface_opts->promisc_mode);
- pcap_set_timeout(pcap_h, CAP_READ_TIMEOUT);
-
-#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
- /*
- * If we're writing pcap-ng files, try to enable
- * nanosecond-resolution capture; any code that
- * can read pcap-ng files must be able to handle
- * nanosecond-resolution time stamps.
- *
- * If we're writing pcap files, don't try to enable
- * nanosecond-resolution capture, as not all code
- * that reads pcap files recognizes the nanosecond-
- * resolution pcap file magic number.
- */
- if (capture_opts->use_pcapng)
- request_high_resolution_timestamp(pcap_h);
-#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
-
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "buffersize %d.", interface_opts->buffer_size);
- if (interface_opts->buffer_size != 0) {
- pcap_set_buffer_size(pcap_h, interface_opts->buffer_size * 1024 * 1024);
- }
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "monitor_mode %d.", interface_opts->monitor_mode);
- if (interface_opts->monitor_mode)
- pcap_set_rfmon(pcap_h, 1);
- err = pcap_activate(pcap_h);
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "pcap_activate() returned %d.", err);
- if (err < 0) {
- /* Failed to activate, set to NULL */
- if (err == PCAP_ERROR)
- g_strlcpy(*open_err_str, pcap_geterr(pcap_h), sizeof *open_err_str);
- else
- g_strlcpy(*open_err_str, pcap_statustostr(err), sizeof *open_err_str);
- pcap_close(pcap_h);
- pcap_h = NULL;
- }
- }
-#else
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "pcap_open_live() calling using name %s, snaplen %d, promisc_mode %d.",
- interface_opts->name, interface_opts->snaplen, interface_opts->promisc_mode);
- pcap_h = pcap_open_live(interface_opts->name, interface_opts->snaplen,
- interface_opts->promisc_mode, CAP_READ_TIMEOUT,
- *open_err_str);
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "pcap_open_live() returned %p.", (void *)pcap_h);
-
-/* Windows doesn't have pcap_create() yet */
-#ifdef _WIN32
- /* try to set the capture buffer size -- but not for remote devices */
- if (pcap_h && interface_opts->buffer_size > 1 &&
- pcap_setbuff(pcap_h, interface_opts->buffer_size * 1024 * 1024) != 0) {
- gchar *sync_secondary_msg_str;
-
- sync_secondary_msg_str = g_strdup_printf(
- "Unable to set a capture buffer size of %d MiB.\n"
- "Capturing using the default size of %d MiB instead.",
- interface_opts->buffer_size, DEFAULT_CAPTURE_BUFFER_SIZE);
- report_capture_error("Couldn't set the capture buffer size.",
- sync_secondary_msg_str);
- g_free(sync_secondary_msg_str);
- }
-#endif
-#endif
- }
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "open_capture_device %s : %s", pcap_h ? "SUCCESS" : "FAILURE", interface_opts->name);
- return pcap_h;
-}
-
static void
get_capture_device_open_failure_messages(const char *open_err_str,
const char *iface,
@@ -863,40 +680,6 @@ get_capture_device_open_failure_messages(const char *open_err_str,
#endif /* _WIN32 */
}
-/* Set the data link type on a pcap. */
-static gboolean
-set_pcap_linktype(pcap_t *pcap_h, int linktype, char *name,
- char *errmsg, size_t errmsg_len,
- char *secondary_errmsg, size_t secondary_errmsg_len)
-{
- char *set_linktype_err_str;
-
- if (linktype == -1)
- return TRUE; /* just use the default */
-#ifdef HAVE_PCAP_SET_DATALINK
- if (pcap_set_datalink(pcap_h, linktype) == 0)
- return TRUE; /* no error */
- set_linktype_err_str = pcap_geterr(pcap_h);
-#else
- /* Let them set it to the type it is; reject any other request. */
- if (get_pcap_linktype(pcap_h, name) == linktype)
- return TRUE; /* no error */
- set_linktype_err_str =
- "That DLT isn't one of the DLTs supported by this device";
-#endif
- g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type on interface '%s' (%s).",
- name, set_linktype_err_str);
- /*
- * If the error isn't "XXX is not one of the DLTs supported by this device",
- * tell the user to tell the Wireshark developers about it.
- */
- if (strstr(set_linktype_err_str, "is not one of the DLTs supported by this device") == NULL)
- g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
- else
- secondary_errmsg[0] = '\0';
- return FALSE;
-}
-
static gboolean
compile_capture_filter(const char *iface, pcap_t *pcap_h,
struct bpf_program *fcode, const char *cfilter)
@@ -947,7 +730,8 @@ show_filter_code(capture_options *capture_opts)
for (j = 0; j < capture_opts->ifaces->len; j++) {
interface_opts = g_array_index(capture_opts->ifaces, interface_options, j);
- pcap_h = open_capture_device(capture_opts, &interface_opts, &open_err_str);
+ pcap_h = open_capture_device(capture_opts, &interface_opts,
+ CAP_READ_TIMEOUT, &open_err_str);
if (pcap_h == NULL) {
/* Open failed; get messages */
get_capture_device_open_failure_messages(open_err_str,
@@ -961,7 +745,7 @@ show_filter_code(capture_options *capture_opts)
}
/* Set the link-layer type. */
- if (!set_pcap_linktype(pcap_h, interface_opts.linktype, interface_opts.name,
+ if (!set_pcap_datalink(pcap_h, interface_opts.linktype, interface_opts.name,
errmsg, sizeof errmsg,
secondary_errmsg, sizeof secondary_errmsg)) {
pcap_close(pcap_h);
@@ -1021,381 +805,6 @@ capture_interface_list(int *err, char **err_str, void(*update_cb)(void) _U_)
return get_interface_list(err, err_str);
}
-/*
- * Get the data-link type for a libpcap device.
- * This works around AIX 5.x's non-standard and incompatible-with-the-
- * rest-of-the-universe libpcap.
- */
-static int
-get_pcap_linktype(pcap_t *pch, const char *devicename
-#ifndef _AIX
- _U_
-#endif
-)
-{
- int linktype;
-#ifdef _AIX
- const char *ifacename;
-#endif
-
- linktype = pcap_datalink(pch);
-#ifdef _AIX
-
- /*
- * The libpcap that comes with AIX 5.x uses RFC 1573 ifType values
- * rather than DLT_ values for link-layer types; the ifType values
- * for LAN devices are:
- *
- * Ethernet 6
- * 802.3 7
- * Token Ring 9
- * FDDI 15
- *
- * and the ifType value for a loopback device is 24.
- *
- * The AIX names for LAN devices begin with:
- *
- * Ethernet en
- * 802.3 et
- * Token Ring tr
- * FDDI fi
- *
- * and the AIX names for loopback devices begin with "lo".
- *
- * (The difference between "Ethernet" and "802.3" is presumably
- * whether packets have an Ethernet header, with a packet type,
- * or an 802.3 header, with a packet length, followed by an 802.2
- * header and possibly a SNAP header.)
- *
- * If the device name matches "linktype" interpreted as an ifType
- * value, rather than as a DLT_ value, we will assume this is AIX's
- * non-standard, incompatible libpcap, rather than a standard libpcap,
- * and will map the link-layer type to the standard DLT_ value for
- * that link-layer type, as that's what the rest of Wireshark expects.
- *
- * (This means the capture files won't be readable by a tcpdump
- * linked with AIX's non-standard libpcap, but so it goes. They
- * *will* be readable by standard versions of tcpdump, Wireshark,
- * and so on.)
- *
- * XXX - if we conclude we're using AIX libpcap, should we also
- * set a flag to cause us to assume the time stamps are in
- * seconds-and-nanoseconds form, and to convert them to
- * seconds-and-microseconds form before processing them and
- * writing them out?
- */
-
- /*
- * Find the last component of the device name, which is the
- * interface name.
- */
- ifacename = strchr(devicename, '/');
- if (ifacename == NULL)
- ifacename = devicename;
-
- /* See if it matches any of the LAN device names. */
- if (strncmp(ifacename, "en", 2) == 0) {
- if (linktype == 6) {
- /*
- * That's the RFC 1573 value for Ethernet; map it to DLT_EN10MB.
- */
- linktype = 1;
- }
- } else if (strncmp(ifacename, "et", 2) == 0) {
- if (linktype == 7) {
- /*
- * That's the RFC 1573 value for 802.3; map it to DLT_EN10MB.
- * (libpcap, tcpdump, Wireshark, etc. don't care if it's Ethernet
- * or 802.3.)
- */
- linktype = 1;
- }
- } else if (strncmp(ifacename, "tr", 2) == 0) {
- if (linktype == 9) {
- /*
- * That's the RFC 1573 value for 802.5 (Token Ring); map it to
- * DLT_IEEE802, which is what's used for Token Ring.
- */
- linktype = 6;
- }
- } else if (strncmp(ifacename, "fi", 2) == 0) {
- if (linktype == 15) {
- /*
- * That's the RFC 1573 value for FDDI; map it to DLT_FDDI.
- */
- linktype = 10;
- }
- } else if (strncmp(ifacename, "lo", 2) == 0) {
- if (linktype == 24) {
- /*
- * That's the RFC 1573 value for "software loopback" devices; map it
- * to DLT_NULL, which is what's used for loopback devices on BSD.
- */
- linktype = 0;
- }
- }
-#endif
-
- return linktype;
-}
-
-static data_link_info_t *
-create_data_link_info(int dlt)
-{
- data_link_info_t *data_link_info;
- const char *text;
-
- data_link_info = (data_link_info_t *)g_malloc(sizeof (data_link_info_t));
- data_link_info->dlt = dlt;
- text = pcap_datalink_val_to_name(dlt);
- if (text != NULL)
- data_link_info->name = g_strdup(text);
- else
- data_link_info->name = g_strdup_printf("DLT %d", dlt);
- text = pcap_datalink_val_to_description(dlt);
- if (text != NULL)
- data_link_info->description = g_strdup(text);
- else
- data_link_info->description = NULL;
- return data_link_info;
-}
-
-#if defined(HAVE_BONDING) && defined(HAVE_PCAP_CREATE)
-static gboolean
-is_linux_bonding_device(const char *ifname)
-{
- int fd;
- struct ifreq ifr;
- ifbond ifb;
-
- fd = socket(PF_INET, SOCK_DGRAM, 0);
- if (fd == -1)
- return FALSE;
-
- memset(&ifr, 0, sizeof ifr);
- g_strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
- memset(&ifb, 0, sizeof ifb);
- ifr.ifr_data = (caddr_t)&ifb;
-#if defined(SIOCBONDINFOQUERY)
- if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) {
- close(fd);
- return TRUE;
- }
-#else
- if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) {
- close(fd);
- return TRUE;
- }
-#endif
-
- close(fd);
- return FALSE;
-}
-#elif defined(HAVE_PCAP_CREATE)
-static gboolean
-is_linux_bonding_device(const char *ifname _U_)
-{
- return FALSE;
-}
-#endif
-
-/*
- * Get the capabilities of a network device.
- */
-static if_capabilities_t *
-get_if_capabilities(interface_options *interface_opts, char **err_str)
-{
- if_capabilities_t *caps;
- char errbuf[PCAP_ERRBUF_SIZE];
- pcap_t *pch;
-#ifdef HAVE_PCAP_CREATE
- int status;
-#endif
- int deflt;
-#ifdef HAVE_PCAP_LIST_DATALINKS
- int *linktypes;
- int i, nlt;
-#endif
- data_link_info_t *data_link_info;
-
- /*
- * Allocate the interface capabilities structure.
- */
- caps = (if_capabilities_t *)g_malloc(sizeof *caps);
-
- /*
- * WinPcap 4.1.2, and possibly earlier versions, have a bug
- * wherein, when an open with an rpcap: URL fails, the error
- * message for the error is not copied to errbuf and whatever
- * on-the-stack junk is in errbuf is treated as the error
- * message.
- *
- * To work around that (and any other bugs of that sort, we
- * initialize errbuf to an empty string. If we get an error
- * and the string is empty, we report it as an unknown error.
- * (If we *don't* get an error, and the string is *non*-empty,
- * that could be a warning returned, such as "can't turn
- * promiscuous mode on"; we currently don't do so.)
- */
- errbuf[0] = '\0';
-#ifdef HAVE_PCAP_OPEN
-#ifdef HAVE_PCAP_REMOTE
- if (strncmp (interface_opts->name, "rpcap://", 8) == 0) {
- struct pcap_rmtauth auth;
-
- auth.type = interface_opts->auth_type == CAPTURE_AUTH_PWD ?
- RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
- auth.username = interface_opts->auth_username;
- auth.password = interface_opts->auth_password;
-
- pch = pcap_open(interface_opts->name, MIN_PACKET_SIZE, 0, 0, &auth, errbuf);
- } else
-#endif
- pch = pcap_open(interface_opts->name, MIN_PACKET_SIZE, 0, 0, NULL, errbuf);
- caps->can_set_rfmon = FALSE;
- if (pch == NULL) {
- if (err_str != NULL)
- *err_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
- g_free(caps);
- return NULL;
- }
-#elif defined(HAVE_PCAP_CREATE)
- pch = pcap_create(interface_opts->name, errbuf);
- if (pch == NULL) {
- if (err_str != NULL)
- *err_str = g_strdup(errbuf);
- g_free(caps);
- return NULL;
- }
- if (is_linux_bonding_device(interface_opts->name)) {
- /*
- * Linux bonding device; not Wi-Fi, so no monitor mode, and
- * calling pcap_can_set_rfmon() might get a "no such device"
- * error.
- */
- status = 0;
- } else {
- /*
- * Not a Linux bonding device, so go ahead.
- */
- status = pcap_can_set_rfmon(pch);
- }
- if (status < 0) {
- /* Error. */
- if (status == PCAP_ERROR)
- *err_str = g_strdup_printf("pcap_can_set_rfmon() failed: %s",
- pcap_geterr(pch));
- else
- *err_str = g_strdup(pcap_statustostr(status));
- pcap_close(pch);
- g_free(caps);
- return NULL;
- }
- if (status == 0)
- caps->can_set_rfmon = FALSE;
- else if (status == 1) {
- caps->can_set_rfmon = TRUE;
- if (interface_opts->monitor_mode)
- pcap_set_rfmon(pch, 1);
- } else {
- if (err_str != NULL) {
- *err_str = g_strdup_printf("pcap_can_set_rfmon() returned %d",
- status);
- }
- pcap_close(pch);
- g_free(caps);
- return NULL;
- }
-
- status = pcap_activate(pch);
- if (status < 0) {
- /* Error. We ignore warnings (status > 0). */
- if (err_str != NULL) {
- if (status == PCAP_ERROR)
- *err_str = g_strdup_printf("pcap_activate() failed: %s",
- pcap_geterr(pch));
- else
- *err_str = g_strdup(pcap_statustostr(status));
- }
- pcap_close(pch);
- g_free(caps);
- return NULL;
- }
-#else
- pch = pcap_open_live(interface_opts->name, MIN_PACKET_SIZE, 0, 0, errbuf);
- caps->can_set_rfmon = FALSE;
- if (pch == NULL) {
- if (err_str != NULL)
- *err_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
- g_free(caps);
- return NULL;
- }
-#endif
- deflt = get_pcap_linktype(pch, interface_opts->name);
-#ifdef HAVE_PCAP_LIST_DATALINKS
- nlt = pcap_list_datalinks(pch, &linktypes);
- if (nlt == 0 || linktypes == NULL) {
- pcap_close(pch);
- if (err_str != NULL)
- *err_str = NULL; /* an empty list doesn't mean an error */
- g_free(caps);
- return NULL;
- }
- caps->data_link_types = NULL;
- for (i = 0; i < nlt; i++) {
- data_link_info = create_data_link_info(linktypes[i]);
-
- /*
- * XXX - for 802.11, make the most detailed 802.11
- * version the default, rather than the one the
- * device has as the default?
- */
- if (linktypes[i] == deflt)
- caps->data_link_types = g_list_prepend(caps->data_link_types,
- data_link_info);
- else
- caps->data_link_types = g_list_append(caps->data_link_types,
- data_link_info);
- }
-#ifdef HAVE_PCAP_FREE_DATALINKS
- pcap_free_datalinks(linktypes);
-#else
- /*
- * In Windows, there's no guarantee that if you have a library
- * built with one version of the MSVC++ run-time library, and
- * it returns a pointer to allocated data, you can free that
- * data from a program linked with another version of the
- * MSVC++ run-time library.
- *
- * This is not an issue on UN*X.
- *
- * See the mail threads starting at
- *
- * https://www.winpcap.org/pipermail/winpcap-users/2006-September/001421.html
- *
- * and
- *
- * https://www.winpcap.org/pipermail/winpcap-users/2008-May/002498.html
- */
-#ifndef _WIN32
-#define xx_free free /* hack so checkAPIs doesn't complain */
- xx_free(linktypes);
-#endif /* _WIN32 */
-#endif /* HAVE_PCAP_FREE_DATALINKS */
-#else /* HAVE_PCAP_LIST_DATALINKS */
-
- data_link_info = create_data_link_info(deflt);
- caps->data_link_types = g_list_append(caps->data_link_types,
- data_link_info);
-#endif /* HAVE_PCAP_LIST_DATALINKS */
-
- pcap_close(pch);
-
- if (err_str != NULL)
- *err_str = NULL;
- return caps;
-}
-
#define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
/*
* Output a machine readable list of the interfaces
@@ -2758,7 +2167,8 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
g_array_append_val(ld->pcaps, pcap_opts);
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", interface_opts.name);
- pcap_opts->pcap_h = open_capture_device(capture_opts, &interface_opts, &open_err_str);
+ pcap_opts->pcap_h = open_capture_device(capture_opts, &interface_opts,
+ CAP_READ_TIMEOUT, &open_err_str);
if (pcap_opts->pcap_h != NULL) {
/* we've opened "iface" as a network device */
@@ -2800,12 +2210,13 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
#endif
/* setting the data link type only works on real interfaces */
- if (!set_pcap_linktype(pcap_opts->pcap_h, interface_opts.linktype, interface_opts.name,
+ if (!set_pcap_datalink(pcap_opts->pcap_h, interface_opts.linktype,
+ interface_opts.name,
errmsg, errmsg_len,
secondary_errmsg, secondary_errmsg_len)) {
return FALSE;
}
- pcap_opts->linktype = get_pcap_linktype(pcap_opts->pcap_h, interface_opts.name);
+ pcap_opts->linktype = get_pcap_datalink(pcap_opts->pcap_h, interface_opts.name);
} else {
/* We couldn't open "iface" as a network device. */
/* Try to open it as a pipe */
@@ -5307,10 +4718,6 @@ signal_pipe_check_running(void)
}
#endif
-
-
-
-
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*