aboutsummaryrefslogtreecommitdiffstats
path: root/capture/capture-pcap-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'capture/capture-pcap-util.c')
-rw-r--r--capture/capture-pcap-util.c874
1 files changed, 746 insertions, 128 deletions
diff --git a/capture/capture-pcap-util.c b/capture/capture-pcap-util.c
index cd837fbb9d..d8f6641d16 100644
--- a/capture/capture-pcap-util.c
+++ b/capture/capture-pcap-util.c
@@ -13,7 +13,7 @@
#ifdef HAVE_LIBPCAP
-#include <glib.h>
+#include <wireshark.h>
#include <stdlib.h>
#include <stdio.h>
@@ -68,6 +68,11 @@
#include "capture/capture_ifinfo.h"
#include "capture/capture-pcap-util.h"
#include "capture/capture-pcap-util-int.h"
+#ifdef _WIN32
+#include "capture/capture-wpcap.h"
+#else
+#define ws_pcap_findalldevs_ex pcap_findalldevs_ex
+#endif
#include <wsutil/file_util.h>
#include <wsutil/please_report_bug.h>
@@ -75,6 +80,8 @@
#ifndef _WIN32
#include <netinet/in.h>
+#else
+#include <ws2tcpip.h>
#endif
#ifdef _WIN32
@@ -88,6 +95,7 @@
#include <errno.h>
#include <net/if.h>
#include <sys/sockio.h>
+#include <sys/ioctl.h>
#endif
/*
@@ -231,7 +239,7 @@ add_unix_interface_ifinfo(if_info_t *if_info, const char *name,
* Look for /sys/class/net/{device}/wireless. If it exists,
* it's a wireless interface.
*/
- wireless_path = g_strdup_printf("/sys/class/net/%s/wireless", name);
+ wireless_path = ws_strdup_printf("/sys/class/net/%s/wireless", name);
if (wireless_path != NULL) {
if (ws_stat64(wireless_path, &statb) == 0)
if_info->type = IF_WIRELESS;
@@ -252,7 +260,7 @@ add_unix_interface_ifinfo(if_info_t *if_info, const char *name,
if_info->type = IF_USB;
}
}
-#else
+#elif !defined(_WIN32)
/*
* On other UN*Xes, if there is a description, it's a friendly
* name, and there is no vendor description. ("Other UN*Xes"
@@ -386,7 +394,7 @@ if_info_get(const char *name)
descr_size = sizeof (descr_prefix) + 10;
description = g_malloc(descr_size);
if (description != NULL) {
- g_snprintf(description, descr_size,
+ snprintf(description, descr_size,
"%s%ld", descr_prefix, busnum);
}
}
@@ -394,24 +402,118 @@ if_info_get(const char *name)
}
#endif /* __FreeBSD__ */
#endif /* SIOCGIFDESCR */
- if_info = if_info_new(name, description, FALSE);
+ if_info = if_info_new(name, description, false);
g_free(description);
return if_info;
}
+if_addr_t *
+if_addr_copy(const if_addr_t *addr)
+{
+ if_addr_t *new_addr = g_new(if_addr_t, 1);
+ new_addr->ifat_type = addr->ifat_type;
+ switch (addr->ifat_type) {
+ case IF_AT_IPv4:
+ new_addr->addr.ip4_addr = addr->addr.ip4_addr;
+ break;
+ case IF_AT_IPv6:
+ memcpy(new_addr->addr.ip6_addr, addr->addr.ip6_addr, sizeof(addr->addr));
+ break;
+ default:
+ /* In case we add non-IP addresses */
+ break;
+ }
+ return new_addr;
+}
+
+static void*
+if_addr_copy_cb(const void *data, void *user_data _U_)
+{
+ return if_addr_copy((if_addr_t*)data);
+}
+
void
if_info_free(if_info_t *if_info)
{
+ if (if_info == NULL) {
+ return;
+ }
g_free(if_info->name);
g_free(if_info->friendly_name);
g_free(if_info->vendor_description);
g_free(if_info->extcap);
g_slist_free_full(if_info->addrs, g_free);
+ if (if_info->caps) {
+ free_if_capabilities(if_info->caps);
+ }
g_free(if_info);
}
+static void*
+copy_linktype_cb(const void *data, void *user_data _U_)
+{
+ data_link_info_t *linktype_info = (data_link_info_t *)data;
+
+ data_link_info_t *ret = g_new(data_link_info_t, 1);
+ ret->dlt = linktype_info->dlt;
+ ret->name = g_strdup(linktype_info->name);
+ ret->description = g_strdup(linktype_info->description);
+ return ret;
+}
+
+static void*
+copy_timestamp_cb(const void *data, void *user_data _U_)
+{
+ timestamp_info_t *timestamp_info = (timestamp_info_t *)data;
+
+ timestamp_info_t *ret = g_new(timestamp_info_t, 1);
+ ret->name = g_strdup(timestamp_info->name);
+ ret->description = g_strdup(timestamp_info->description);
+ return ret;
+}
+
+static if_capabilities_t *
+if_capabilities_copy(const if_capabilities_t *caps)
+{
+ if (caps == NULL) return NULL;
+
+ if_capabilities_t *ret = g_new(if_capabilities_t, 1);
+ ret->can_set_rfmon = caps->can_set_rfmon;
+ ret->data_link_types = g_list_copy_deep(caps->data_link_types, copy_linktype_cb, NULL);
+ ret->timestamp_types = g_list_copy_deep(caps->timestamp_types, copy_timestamp_cb, NULL);
+ ret->data_link_types_rfmon = g_list_copy_deep(caps->data_link_types_rfmon, copy_linktype_cb, NULL);
+ ret->primary_msg = g_strdup(caps->primary_msg);
+ ret->secondary_msg = caps->secondary_msg;
+
+ return ret;
+}
+
+if_info_t *
+if_info_copy(const if_info_t *if_info)
+{
+ if_info_t *new_if_info;
+ new_if_info = g_new(if_info_t, 1);
+ new_if_info->name = g_strdup(if_info->name);
+ /* g_strdup accepts NULL as input and returns NULL. */
+ new_if_info->friendly_name = g_strdup(if_info->friendly_name);
+ new_if_info->vendor_description = g_strdup(if_info->vendor_description);
+ new_if_info->addrs = g_slist_copy_deep(if_info->addrs, if_addr_copy_cb, NULL);
+ new_if_info->type = if_info->type;
+ new_if_info->loopback = if_info->loopback;
+ new_if_info->extcap = g_strdup(if_info->extcap);
+ new_if_info->caps = if_capabilities_copy(if_info->caps);
+
+ return new_if_info;
+}
+
+static void*
+if_info_copy_cb(const void* data, void *user_data _U_)
+{
+ return if_info_copy((const if_info_t*)data);
+}
+
if_info_t *
-if_info_new(const char *name, const char *description, gboolean loopback)
+if_info_new(const char *name, const char *description, bool loopback)
{
if_info_t *if_info;
#ifdef _WIN32
@@ -449,8 +551,8 @@ if_info_new(const char *name, const char *description, gboolean loopback)
} else if (description && (strstr(description, "Wireless") != NULL ||
strstr(description,"802.11") != NULL)) {
if_info->type = IF_WIRELESS;
- } else if (description && strstr(description, "AirPcap") != NULL ||
- strstr(name, "airpcap") != NULL) {
+ } else if (description && (strstr(description, "AirPcap") != NULL ||
+ strstr(name, "airpcap") != NULL)) {
if_info->type = IF_AIRPCAP;
} else if (description && strstr(description, "Bluetooth") != NULL ) {
if_info->type = IF_BLUETOOTH;
@@ -541,6 +643,7 @@ if_info_new(const char *name, const char *description, gboolean loopback)
#endif
if_info->loopback = loopback;
if_info->addrs = NULL;
+ if_info->caps = NULL;
return if_info;
}
@@ -557,8 +660,7 @@ if_info_add_address(if_info_t *if_info, struct sockaddr *addr)
ai = (struct sockaddr_in *)(void *)addr;
if_addr = (if_addr_t *)g_malloc(sizeof(*if_addr));
if_addr->ifat_type = IF_AT_IPv4;
- if_addr->addr.ip4_addr =
- *((guint32 *)&(ai->sin_addr.s_addr));
+ if_addr->addr.ip4_addr = ai->sin_addr.s_addr;
if_info->addrs = g_slist_prepend(if_info->addrs, if_addr);
break;
@@ -613,6 +715,19 @@ get_interface_list_findalldevs_ex(const char *hostname, const char *port,
if (pcap_createsrcstr(source, PCAP_SRC_IFREMOTE, hostname, port,
NULL, errbuf) == -1) {
*err = CANT_GET_INTERFACE_LIST;
+ if (strcmp(errbuf, "not supported") == 0) {
+ /*
+ * macOS 14's pcap_createsrcstr(), which is a
+ * stub that always returns -1 with an error
+ * message of "not supported".
+ *
+ * In this case, as we passed it an rpcap://
+ * URL, treat that as meaning "remote capture
+ * not supported".
+ */
+ g_strlcpy(errbuf, "Remote capture not supported",
+ PCAP_ERRBUF_SIZE);
+ }
if (err_str != NULL)
*err_str = cant_get_if_list_error_message(errbuf);
return NULL;
@@ -622,8 +737,21 @@ get_interface_list_findalldevs_ex(const char *hostname, const char *port,
auth.username = g_strdup(username);
auth.password = g_strdup(passwd);
- if (pcap_findalldevs_ex(source, &auth, &alldevs, errbuf) == -1) {
+ if (ws_pcap_findalldevs_ex(source, &auth, &alldevs, errbuf) == -1) {
*err = CANT_GET_INTERFACE_LIST;
+ if (strcmp(errbuf, "not supported") == 0) {
+ /*
+ * macOS 14's pcap_findalldevs_ex(), which is a
+ * stub that always returns -1 with an error
+ * message of "not supported".
+ *
+ * In this case, as we passed it an rpcap://
+ * URL, treat that as meaning "remote capture
+ * not supported".
+ */
+ g_strlcpy(errbuf, "Remote capture not supported",
+ PCAP_ERRBUF_SIZE);
+ }
if (err_str != NULL)
*err_str = cant_get_if_list_error_message(errbuf);
g_free(auth.username);
@@ -645,7 +773,7 @@ get_interface_list_findalldevs_ex(const char *hostname, const char *port,
for (dev = alldevs; dev != NULL; dev = dev->next) {
if_info = if_info_new(dev->name, dev->description,
- (dev->flags & PCAP_IF_LOOPBACK) ? TRUE : FALSE);
+ (dev->flags & PCAP_IF_LOOPBACK) ? true : false);
il = g_list_append(il, if_info);
if_info_ip(if_info, dev);
}
@@ -684,7 +812,7 @@ get_interface_list_findalldevs(int *err, char **err_str)
for (dev = alldevs; dev != NULL; dev = dev->next) {
if_info = if_info_new(dev->name, dev->description,
- (dev->flags & PCAP_IF_LOOPBACK) ? TRUE : FALSE);
+ (dev->flags & PCAP_IF_LOOPBACK) ? true : false);
il = g_list_append(il, if_info);
if_info_ip(if_info, dev);
}
@@ -694,7 +822,7 @@ get_interface_list_findalldevs(int *err, char **err_str)
}
static void
-free_if_cb(gpointer data, gpointer user_data _U_)
+free_if_cb(void * data, void * user_data _U_)
{
if_info_free((if_info_t *)data);
}
@@ -706,8 +834,14 @@ free_interface_list(GList *if_list)
g_list_free(if_list);
}
+GList*
+interface_list_copy(GList *if_list)
+{
+ return g_list_copy_deep(if_list, if_info_copy_cb, NULL);
+}
+
static void
-free_linktype_cb(gpointer data, gpointer user_data _U_)
+free_linktype_cb(void * data)
{
data_link_info_t *linktype_info = (data_link_info_t *)data;
@@ -717,7 +851,7 @@ free_linktype_cb(gpointer data, gpointer user_data _U_)
}
static void
-free_timestamp_cb(gpointer data, gpointer user_data _U_)
+free_timestamp_cb(void * data)
{
timestamp_info_t *timestamp_info = (timestamp_info_t *)data;
@@ -729,11 +863,12 @@ free_timestamp_cb(gpointer data, gpointer user_data _U_)
void
free_if_capabilities(if_capabilities_t *caps)
{
- g_list_foreach(caps->data_link_types, free_linktype_cb, NULL);
- g_list_free(caps->data_link_types);
+ g_list_free_full(caps->data_link_types, free_linktype_cb);
+ g_list_free_full(caps->data_link_types_rfmon, free_linktype_cb);
- g_list_foreach(caps->timestamp_types, free_timestamp_cb, NULL);
- g_list_free(caps->timestamp_types);
+ g_list_free_full(caps->timestamp_types, free_timestamp_cb);
+
+ g_free(caps->primary_msg);
g_free(caps);
}
@@ -877,7 +1012,7 @@ get_pcap_datalink(pcap_t *pch,
}
/* Set the data link type on a pcap. */
-gboolean
+bool
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)
@@ -885,22 +1020,22 @@ set_pcap_datalink(pcap_t *pcap_h, int datalink, char *name,
char *set_datalink_err_str;
if (datalink == -1)
- return TRUE; /* just use the default */
+ return true; /* just use the default */
if (pcap_set_datalink(pcap_h, datalink) == 0)
- return TRUE; /* no error */
+ return true; /* no error */
set_datalink_err_str = pcap_geterr(pcap_h);
- g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type on interface '%s' (%s).",
+ snprintf(errmsg, 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,
+ snprintf(secondary_errmsg, secondary_errmsg_len,
"%s", please_report_bug());
else
secondary_errmsg[0] = '\0';
- return FALSE;
+ return false;
}
static data_link_info_t *
@@ -915,7 +1050,7 @@ create_data_link_info(int dlt)
if (text != NULL)
data_link_info->name = g_strdup(text);
else
- data_link_info->name = g_strdup_printf("DLT %d", dlt);
+ data_link_info->name = ws_strdup_printf("DLT %d", dlt);
text = pcap_datalink_val_to_description(dlt);
data_link_info->description = g_strdup(text);
return data_link_info;
@@ -945,20 +1080,26 @@ get_data_link_types(pcap_t *pch, interface_options *interface_opts,
* PCAP_ERROR_NOT_ACTIVATED. and we should report
* them properly.
*/
- if (nlt == PCAP_ERROR) {
- *status = CAP_DEVICE_OPEN_ERR_GENERIC;
- *status_str = g_strdup_printf("pcap_list_datalinks() failed: %s",
+ switch (nlt) {
+
+ case PCAP_ERROR:
+ *status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *status_str = ws_strdup_printf("pcap_list_datalinks() failed: %s",
pcap_geterr(pch));
- } else {
- if (nlt == PCAP_ERROR_PERM_DENIED)
- *status = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
- else
- *status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
- *status_str = g_strdup(pcap_statustostr(nlt));
+ break;
+
+ default:
+ /*
+ * This "shouldn't happen".
+ */
+ *status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *status_str = ws_strdup_printf("pcap_list_datalinks() failed: %s - %s",
+ pcap_statustostr(nlt), pcap_geterr(pch));
+ break;
}
#else /* HAVE_PCAP_CREATE */
- *status = CAP_DEVICE_OPEN_ERR_GENERIC;
- *status_str = g_strdup_printf("pcap_list_datalinks() failed: %s",
+ *status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *status_str = ws_strdup_printf("pcap_list_datalinks() failed: %s",
pcap_geterr(pch));
#endif /* HAVE_PCAP_CREATE */
return NULL;
@@ -1040,17 +1181,15 @@ get_pcap_timestamp_types(pcap_t *pch _U_, char **err_str _U_)
/*
* Request high-resolution time stamps.
*
- * We don't check for errors - if this fails, we just live with boring old
- * microsecond-resolution time stamps. The only errors pcap_set_tstamp_precision()
- * is documenting as returning are PCAP_ERROR_TSTAMP_PRECISION_NOTSUP, which just
- * means we can't do nanosecond precision on this adapter, in which case we
- * just live with whatever resolution we get by default, and
- * PCAP_ERROR_ACTIVATED, which shouldn't happen as we shouldn't call this
- * after we've activated the pcap_t.
+ * If this fails with PCAP_ERROR_TSTAMP_PRECISION_NOTSUP, that means
+ * that boring old microsecond-resolution time stamps are all that
+ * are supported, so we just live with that.
*/
-void
+static int
request_high_resolution_timestamp(pcap_t *pcap_h)
{
+ int status;
+
#ifdef __APPLE__
/*
* On macOS, if you build with a newer SDK, pcap_set_tstamp_precision()
@@ -1067,51 +1206,64 @@ request_high_resolution_timestamp(pcap_t *pcap_h)
* libpcap, and dlsym() to find a pointer to pcap_set_tstamp_precision(),
* and if we find the pointer, call it.
*/
- static gboolean initialized = FALSE;
+ static bool initialized = false;
static int (*p_pcap_set_tstamp_precision)(pcap_t *, int);
if (!initialized) {
p_pcap_set_tstamp_precision =
(int (*)(pcap_t *, int))
dlsym(RTLD_NEXT, "pcap_set_tstamp_precision");
- initialized = TRUE;
+ initialized = true;
+ }
+ if (p_pcap_set_tstamp_precision != NULL) {
+ status = (*p_pcap_set_tstamp_precision)(pcap_h,
+ PCAP_TSTAMP_PRECISION_NANO);
+ } else {
+ /*
+ * Older libpcap, which doesn't have support
+ * for setting the time stamp resolution.
+ */
+ status = PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
}
- if (p_pcap_set_tstamp_precision != NULL)
- (*p_pcap_set_tstamp_precision)(pcap_h, PCAP_TSTAMP_PRECISION_NANO);
#else /* __APPLE__ */
/*
* On other UN*Xes we require that we be run on an OS version
* with a libpcap equal to or later than the version with which
* we were built.
*/
- pcap_set_tstamp_precision(pcap_h, PCAP_TSTAMP_PRECISION_NANO);
+ status = pcap_set_tstamp_precision(pcap_h, PCAP_TSTAMP_PRECISION_NANO);
#endif /* __APPLE__ */
+ if (status == PCAP_ERROR_TSTAMP_PRECISION_NOTSUP) {
+ /* This isn't a fatal error. */
+ status = 0;
+ }
+ return status;
}
/*
- * Return TRUE if the pcap_t in question is set up for high-precision
- * time stamps, FALSE otherwise.
+ * Return true if the pcap_t in question is set up for high-precision
+ * time stamps, false otherwise.
*/
-gboolean
+bool
have_high_resolution_timestamp(pcap_t *pcap_h)
{
#ifdef __APPLE__
/*
* See above.
*/
- static gboolean initialized = FALSE;
+ static bool initialized = false;
static int (*p_pcap_get_tstamp_precision)(pcap_t *);
if (!initialized) {
p_pcap_get_tstamp_precision =
(int (*)(pcap_t *))
dlsym(RTLD_NEXT, "pcap_get_tstamp_precision");
- initialized = TRUE;
+ initialized = true;
}
if (p_pcap_get_tstamp_precision != NULL)
return (*p_pcap_get_tstamp_precision)(pcap_h) == PCAP_TSTAMP_PRECISION_NANO;
else
- return FALSE; /* Can't get implies couldn't set */
+ return false; /* Can't get implies couldn't set */
#else /* __APPLE__ */
/*
* On other UN*Xes we require that we be run on an OS version
@@ -1126,7 +1278,7 @@ have_high_resolution_timestamp(pcap_t *pcap_h)
#ifdef HAVE_PCAP_CREATE
#ifdef HAVE_BONDING
-static gboolean
+static bool
is_linux_bonding_device(const char *ifname)
{
int fd;
@@ -1135,7 +1287,7 @@ is_linux_bonding_device(const char *ifname)
fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd == -1)
- return FALSE;
+ return false;
memset(&ifr, 0, sizeof ifr);
(void) g_strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
@@ -1144,23 +1296,23 @@ is_linux_bonding_device(const char *ifname)
#if defined(SIOCBONDINFOQUERY)
if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) {
close(fd);
- return TRUE;
+ return true;
}
#else
if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) {
close(fd);
- return TRUE;
+ return true;
}
#endif
close(fd);
- return FALSE;
+ return false;
}
#else
-static gboolean
+static bool
is_linux_bonding_device(const char *ifname _U_)
{
- return FALSE;
+ return false;
}
#endif
@@ -1175,7 +1327,7 @@ get_if_capabilities_pcap_create(interface_options *interface_opts,
pch = pcap_create(interface_opts->name, errbuf);
if (pch == NULL) {
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
*open_status_str = g_strdup(errbuf);
return NULL;
}
@@ -1195,30 +1347,46 @@ get_if_capabilities_pcap_create(interface_options *interface_opts,
}
if (status < 0) {
/* Error. */
- if (status == PCAP_ERROR) {
- *open_status = CAP_DEVICE_OPEN_ERR_GENERIC;
- *open_status_str = g_strdup_printf("pcap_can_set_rfmon() failed: %s",
+ switch (status) {
+
+ case PCAP_ERROR_NO_SUCH_DEVICE:
+ *open_status = CAP_DEVICE_OPEN_ERROR_NO_SUCH_DEVICE;
+ *open_status_str = ws_strdup_printf("pcap_can_set_rfmon() failed: %s",
pcap_geterr(pch));
- } else {
- if (status == PCAP_ERROR_PERM_DENIED)
- *open_status = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
- else
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
- *open_status_str = g_strdup(pcap_statustostr(status));
+ break;
+
+ case PCAP_ERROR_PERM_DENIED:
+ *open_status = CAP_DEVICE_OPEN_ERROR_PERM_DENIED;
+ *open_status_str = ws_strdup_printf("pcap_can_set_rfmon() failed: %s",
+ pcap_geterr(pch));
+ break;
+
+ case PCAP_ERROR:
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *open_status_str = ws_strdup_printf("pcap_can_set_rfmon() failed: %s",
+ pcap_geterr(pch));
+ break;
+
+ default:
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *open_status_str = ws_strdup_printf("pcap_can_set_rfmon() failed: %s - %s",
+ pcap_statustostr(status), pcap_geterr(pch));
+ break;
}
pcap_close(pch);
return NULL;
}
- caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+ caps = (if_capabilities_t *)g_malloc0(sizeof *caps);
if (status == 0)
- caps->can_set_rfmon = FALSE;
+ caps->can_set_rfmon = false;
else if (status == 1) {
- caps->can_set_rfmon = TRUE;
- if (interface_opts->monitor_mode)
- pcap_set_rfmon(pch, 1);
+ caps->can_set_rfmon = true;
} else {
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
- *open_status_str = g_strdup_printf("pcap_can_set_rfmon() returned %d",
+ /*
+ * This "should not happen".
+ */
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *open_status_str = ws_strdup_printf("pcap_can_set_rfmon() returned %d",
status);
pcap_close(pch);
g_free(caps);
@@ -1228,16 +1396,37 @@ get_if_capabilities_pcap_create(interface_options *interface_opts,
status = pcap_activate(pch);
if (status < 0) {
/* Error. */
- if (status == PCAP_ERROR) {
- *open_status = CAP_DEVICE_OPEN_ERR_GENERIC;
- *open_status_str = g_strdup_printf("pcap_activate() failed: %s",
+ switch (status) {
+
+ case PCAP_ERROR_NO_SUCH_DEVICE:
+ *open_status = CAP_DEVICE_OPEN_ERROR_NO_SUCH_DEVICE;
+ *open_status_str = ws_strdup_printf("pcap_activate() failed: %s",
pcap_geterr(pch));
- } else {
- if (status == PCAP_ERROR_PERM_DENIED)
- *open_status = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
- else
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
- *open_status_str = g_strdup(pcap_statustostr(status));
+ break;
+
+ case PCAP_ERROR_PERM_DENIED:
+ *open_status = CAP_DEVICE_OPEN_ERROR_PERM_DENIED;
+ *open_status_str = ws_strdup_printf("pcap_activate() failed: %s",
+ pcap_geterr(pch));
+ break;
+
+ case PCAP_ERROR_IFACE_NOT_UP:
+ *open_status = CAP_DEVICE_OPEN_ERROR_IFACE_NOT_UP;
+ *open_status_str = ws_strdup_printf("pcap_activate() failed: %s",
+ pcap_geterr(pch));
+ break;
+
+ case PCAP_ERROR:
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *open_status_str = ws_strdup_printf("pcap_activate() failed: %s",
+ pcap_geterr(pch));
+ break;
+
+ default:
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *open_status_str = ws_strdup_printf("pcap_activate() failed: %s - %s",
+ pcap_statustostr(status), pcap_geterr(pch));
+ break;
}
pcap_close(pch);
g_free(caps);
@@ -1256,11 +1445,83 @@ get_if_capabilities_pcap_create(interface_options *interface_opts,
pcap_close(pch);
+ if (caps->can_set_rfmon) {
+ /* This devices claims it can set rfmon. Get the capabilities
+ * when in monitor mode. We just succeeded above, so if we
+ * fail on anything here, just say that despite claims we
+ * can't actually set monitor mode.
+ */
+ pch = pcap_create(interface_opts->name, errbuf);
+ if (pch == NULL) {
+ /*
+ * This "should not happen".
+ * It just succeeded above, what can this mean?
+ */
+ return caps;
+ }
+
+ status = pcap_set_rfmon(pch, 1);
+ if (status < 0) {
+ /*
+ * This "should not happen".
+ * It claims that monitor mode can be set, but
+ * there's an error when we try to do so.
+ */
+#if 0
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ *open_status_str = ws_strdup_printf("pcap_set_rfmon() returned %d",
+ status);
+#endif
+ caps->can_set_rfmon = false;
+ pcap_close(pch);
+ return caps;
+ }
+
+ status = pcap_activate(pch);
+ if (status < 0) {
+ /*
+ * This "should not happen". (It just succeeded above.)
+ * pcap_set_rfmon didn't return an error, but it
+ * can't be activated after setting monitor mode?
+ */
+ caps->can_set_rfmon = false;
+ pcap_close(pch);
+ return NULL;
+ }
+
+ caps->data_link_types_rfmon = get_data_link_types(pch,
+ interface_opts, open_status, open_status_str);
+ if (caps->data_link_types == NULL) {
+ caps->can_set_rfmon = false;
+ }
+
+ pcap_close(pch);
+ }
+
+ *open_status = CAP_DEVICE_OPEN_NO_ERR;
if (open_status_str != NULL)
*open_status_str = NULL;
return caps;
}
+static void
+set_open_status_str(int status, pcap_t *pcap_h,
+ char (*open_status_str)[PCAP_ERRBUF_SIZE])
+{
+ switch (status) {
+
+ case PCAP_ERROR:
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+
+ default:
+ (void) g_strlcpy(*open_status_str, pcap_statustostr(status),
+ sizeof *open_status_str);
+ break;
+ }
+}
+
pcap_t *
open_capture_device_pcap_create(
#if defined(HAVE_PCAP_SET_TSTAMP_PRECISION)
@@ -1279,18 +1540,39 @@ open_capture_device_pcap_create(
pcap_h = pcap_create(interface_opts->name, *open_status_str);
ws_debug("pcap_create() returned %p.", (void *)pcap_h);
if (pcap_h == NULL) {
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
return NULL;
}
if (interface_opts->has_snaplen) {
ws_debug("Calling pcap_set_snaplen() with snaplen %d.",
interface_opts->snaplen);
- pcap_set_snaplen(pcap_h, interface_opts->snaplen);
+ status = pcap_set_snaplen(pcap_h, interface_opts->snaplen);
+ if (status < 0) {
+ /* Error. */
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ pcap_close(pcap_h);
+ return NULL;
+ }
}
ws_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);
+ status = pcap_set_promisc(pcap_h, interface_opts->promisc_mode);
+ if (status < 0) {
+ /* Error. */
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ pcap_close(pcap_h);
+ return NULL;
+ }
+ status = pcap_set_timeout(pcap_h, timeout);
+ if (status < 0) {
+ /* Error. */
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ pcap_close(pcap_h);
+ return NULL;
+ }
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
/*
@@ -1312,8 +1594,16 @@ open_capture_device_pcap_create(
* nanosecond resolution timing), we just use microsecond-
* resolution time stamps.
*/
- if (capture_opts->use_pcapng)
- request_high_resolution_timestamp(pcap_h);
+ if (capture_opts->use_pcapng) {
+ status = request_high_resolution_timestamp(pcap_h);
+ if (status < 0) {
+ /* Error. */
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ pcap_close(pcap_h);
+ return NULL;
+ }
+ }
#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
@@ -1323,10 +1613,9 @@ open_capture_device_pcap_create(
* XXX - what if it fails because that time stamp type
* isn't supported?
*/
- if (status == PCAP_ERROR) {
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
- (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
- sizeof *open_status_str);
+ if (status < 0) {
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
pcap_close(pcap_h);
return NULL;
}
@@ -1334,27 +1623,75 @@ open_capture_device_pcap_create(
#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
ws_debug("buffersize %d.", interface_opts->buffer_size);
- if (interface_opts->buffer_size != 0)
- pcap_set_buffer_size(pcap_h,
+ if (interface_opts->buffer_size != 0) {
+ status = pcap_set_buffer_size(pcap_h,
interface_opts->buffer_size * 1024 * 1024);
+ if (status < 0) {
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ pcap_close(pcap_h);
+ return NULL;
+ }
+ }
ws_debug("monitor_mode %d.", interface_opts->monitor_mode);
- if (interface_opts->monitor_mode)
- pcap_set_rfmon(pcap_h, 1);
+ if (interface_opts->monitor_mode) {
+ status = pcap_set_rfmon(pcap_h, 1);
+ if (status < 0) {
+ set_open_status_str(status, pcap_h, open_status_str);
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ pcap_close(pcap_h);
+ return NULL;
+ }
+ }
status = pcap_activate(pcap_h);
ws_debug("pcap_activate() returned %d.", status);
if (status < 0) {
/* Failed to activate, set to NULL */
- if (status == PCAP_ERROR) {
- *open_status = CAP_DEVICE_OPEN_ERR_GENERIC;
+ switch (status) {
+
+ case PCAP_ERROR_NO_SUCH_DEVICE:
+ *open_status = CAP_DEVICE_OPEN_ERROR_NO_SUCH_DEVICE;
(void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
sizeof *open_status_str);
- } else {
- if (status == PCAP_ERROR_PERM_DENIED)
- *open_status = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
- else
- *open_status = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
- (void) g_strlcpy(*open_status_str, pcap_statustostr(status),
+ break;
+
+ case PCAP_ERROR_PERM_DENIED:
+ *open_status = CAP_DEVICE_OPEN_ERROR_PERM_DENIED;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+
+#ifdef HAVE_PCAP_ERROR_PROMISC_PERM_DENIED
+ case PCAP_ERROR_PROMISC_PERM_DENIED:
+ *open_status = CAP_DEVICE_OPEN_ERROR_PROMISC_PERM_DENIED;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+#endif
+
+ case PCAP_ERROR_RFMON_NOTSUP:
+ *open_status = CAP_DEVICE_OPEN_ERROR_RFMON_NOTSUP;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+
+ case PCAP_ERROR_IFACE_NOT_UP:
+ *open_status = CAP_DEVICE_OPEN_ERROR_IFACE_NOT_UP;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+
+ case PCAP_ERROR:
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
sizeof *open_status_str);
+ break;
+
+ default:
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
+ snprintf(*open_status_str, sizeof *open_status_str,
+ "%s - %s", pcap_statustostr(status), pcap_geterr(pcap_h));
+ break;
}
pcap_close(pcap_h);
return NULL;
@@ -1364,13 +1701,33 @@ open_capture_device_pcap_create(
* Warning. The call succeeded, but something happened
* that the user might want to know.
*/
- *open_status = CAP_DEVICE_OPEN_WARNING_GENERIC;
- if (status == PCAP_WARNING) {
- g_snprintf(*open_status_str, sizeof *open_status_str,
- "Warning: %s", pcap_geterr(pcap_h));
- } else {
- g_snprintf(*open_status_str, sizeof *open_status_str,
- "Warning: %s", pcap_statustostr(status));
+ switch (status) {
+
+ case PCAP_WARNING_PROMISC_NOTSUP:
+ *open_status = CAP_DEVICE_OPEN_WARNING_PROMISC_NOTSUP;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+
+#ifdef HAVE_PCAP_WARNING_TSTAMP_TYPE_NOTSUP
+ case PCAP_WARNING_TSTAMP_TYPE_NOTSUP:
+ *open_status = CAP_DEVICE_OPEN_WARNING_TSTAMP_TYPE_NOTSUP;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+#endif
+
+ case PCAP_WARNING:
+ *open_status = CAP_DEVICE_OPEN_WARNING_OTHER;
+ (void) g_strlcpy(*open_status_str, pcap_geterr(pcap_h),
+ sizeof *open_status_str);
+ break;
+
+ default:
+ *open_status = CAP_DEVICE_OPEN_WARNING_OTHER;
+ snprintf(*open_status_str, sizeof *open_status_str,
+ "%s - %s", pcap_statustostr(status), pcap_geterr(pcap_h));
+ break;
}
} else {
/*
@@ -1393,13 +1750,13 @@ get_if_capabilities_pcap_open_live(interface_options *interface_opts,
pch = pcap_open_live(interface_opts->name, MIN_PACKET_SIZE, 0, 0,
errbuf);
if (pch == NULL) {
- *open_status = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
*open_status_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
return NULL;
}
- caps = (if_capabilities_t *)g_malloc(sizeof *caps);
- caps->can_set_rfmon = FALSE;
+ caps = (if_capabilities_t *)g_malloc0(sizeof *caps);
+ caps->can_set_rfmon = false;
caps->data_link_types = get_data_link_types(pch, interface_opts,
open_status, open_status_str);
if (caps->data_link_types == NULL) {
@@ -1451,7 +1808,7 @@ open_capture_device_pcap_open_live(interface_options *interface_opts,
interface_opts->promisc_mode, timeout, *open_status_str);
ws_debug("pcap_open_live() returned %p.", (void *)pcap_h);
if (pcap_h == NULL) {
- *open_status = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *open_status = CAP_DEVICE_OPEN_ERROR_OTHER;
return NULL;
}
if ((*open_status_str)[0] != '\0') {
@@ -1459,7 +1816,7 @@ open_capture_device_pcap_open_live(interface_options *interface_opts,
* Warning. The call succeeded, but something happened
* that the user might want to know.
*/
- *open_status = CAP_DEVICE_OPEN_WARNING_GENERIC;
+ *open_status = CAP_DEVICE_OPEN_WARNING_OTHER;
} else {
/*
* No warning issued.
@@ -1530,13 +1887,26 @@ get_if_capabilities(interface_options *interface_opts,
* permission for their own remote account or will have
* to use an account that *does* have permissions.
*/
- *status = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *status = CAP_DEVICE_OPEN_ERROR_GENERIC;
+ if (strcmp(errbuf, "not supported") == 0) {
+ /*
+ * macOS 14's pcap_open(), which is a stub that
+ * always returns NULL with an error message of
+ * "not supported".
+ *
+ * In this case, as we passed it an rpcap://
+ * URL, treat that as meaning "remote capture
+ * not supported".
+ */
+ g_strlcpy(errbuf, "Remote capture not supported",
+ PCAP_ERRBUF_SIZE);
+ }
*status_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
return NULL;
}
- caps = (if_capabilities_t *)g_malloc(sizeof *caps);
- caps->can_set_rfmon = FALSE;
+ caps = (if_capabilities_t *)g_malloc0(sizeof *caps);
+ caps->can_set_rfmon = false;
caps->data_link_types = NULL;
deflt = get_pcap_datalink(pch, interface_opts->name);
data_link_info = create_data_link_info(deflt);
@@ -1620,7 +1990,22 @@ open_capture_device(capture_options *capture_opts,
* or maybe we just have to ask politely for
* permission.)
*/
- *open_status = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *open_status = CAP_DEVICE_OPEN_ERROR_GENERIC;
+ if (strcmp(*open_status_str, "not supported") == 0) {
+ /*
+ * macOS 14's pcap_open(), which is a stub
+ * that always returns NULL with an error
+ * message of "not supported".
+ *
+ * In this case, as we passed it an rpcap://
+ * URL, treat that as meaning "remote capture
+ * not supported".
+ */
+ g_strlcpy(*open_status_str,
+ "Remote capture not supported",
+ PCAP_ERRBUF_SIZE);
+ }
+
/* Did pcap actually supply an error message? */
if ((*open_status_str)[0] == '\0') {
/*
@@ -1650,6 +2035,239 @@ open_capture_device(capture_options *capture_opts,
return pcap_h;
}
+/*
+ * Platform-dependent suggestions for fixing permissions.
+ */
+
+#ifdef HAVE_LIBCAP
+ #define LIBCAP_PERMISSIONS_SUGGESTION \
+ "\n\n" \
+ "If you did not install Wireshark from a package, ensure that Dumpcap " \
+ "has the needed CAP_NET_RAW and CAP_NET_ADMIN capabilities by running " \
+ "\n\n" \
+ " sudo setcap cap_net_raw,cap_net_admin=ep {path/to/}dumpcap" \
+ "\n\n" \
+ "and then restarting Wireshark."
+#else
+ #define LIBCAP_PERMISSIONS_SUGGESTION
+#endif
+
+#if defined(__linux__)
+ #define PLATFORM_PERMISSIONS_SUGGESTION \
+ "\n\n" \
+ "On Debian and Debian derivatives such as Ubuntu, if you have " \
+ "installed Wireshark from a package, try running" \
+ "\n\n" \
+ " sudo dpkg-reconfigure wireshark-common" \
+ "\n\n" \
+ "selecting \"<Yes>\" in response to the question" \
+ "\n\n" \
+ " Should non-superusers be able to capture packets?" \
+ "\n\n" \
+ "adding yourself to the \"wireshark\" group by running" \
+ "\n\n" \
+ " sudo usermod -a -G wireshark {your username}" \
+ "\n\n" \
+ "and then logging out and logging back in again." \
+ LIBCAP_PERMISSIONS_SUGGESTION
+#elif defined(__APPLE__)
+ #define PLATFORM_PERMISSIONS_SUGGESTION \
+ "\n\n" \
+ "If you installed Wireshark using the package from wireshark.org, " \
+ "close this dialog and click on the \"installing ChmodBPF\" link in " \
+ "\"You can fix this by installing ChmodBPF.\" on the main screen, " \
+ "and then complete the installation procedure."
+#else
+ #define PLATFORM_PERMISSIONS_SUGGESTION
+#endif
+
+#if defined(_WIN32)
+static const char *
+get_platform_pcap_failure_secondary_error_message(const char *open_status_str)
+{
+ /*
+ * The error string begins with the error produced by WinPcap
+ * and Npcap if attempting to set promiscuous mode fails.
+ * (Note that this string could have a specific error message
+ * from an NDIS error after the initial part, so we do a prefix
+ * check rather than an exact match check.)
+ *
+ * If this is with Npcap 1.71 through 1.73, which have bugs that
+ * cause this error on Windows 11 with some drivers, suggest that
+ * the user upgrade to the current version of Npcap;
+ * otherwise, suggest that they turn off promiscuous mode
+ * on that device.
+ */
+ static const char promisc_failed[] =
+ "failed to set hardware filter to promiscuous mode";
+
+ if (strncmp(open_status_str, promisc_failed, sizeof promisc_failed - 1) == 0) {
+ unsigned int npcap_major, npcap_minor;
+
+ if (caplibs_get_npcap_version(&npcap_major, &npcap_minor)) {
+ if (npcap_major == 1 &&
+ (npcap_minor >= 71 && npcap_minor <= 73)) {
+ return
+"This is a bug in your version of Npcap.\n"
+"\n"
+"If you need to use promiscuous mode, you must upgrade to the current "
+"version of Npcap, which is available from https://npcap.com/\n"
+"\n"
+"Otherwise, turn off promiscuous mode for this device.";
+ }
+ }
+ return
+ "Please turn off promiscuous mode for this device.";
+ }
+ return NULL;
+}
+#elif defined(__linux__)
+static const char *
+get_platform_pcap_failure_secondary_error_message(const char *open_status_str)
+{
+ /*
+ * The error string is the message provided by libpcap on
+ * Linux if an attempt to open a PF_PACKET socket failed
+ * with EAFNOSUPPORT. This probably means that either 1)
+ * the kernel doesn't have PF_PACKET support configured in
+ * or 2) this is a Flatpak version of Wireshark that's been
+ * sandboxed in a way that disallows opening PF_PACKET
+ * sockets.
+ *
+ * Suggest that the user find some other package of
+ * Wireshark if they want to capture traffic and are
+ * running a Flatpak of Wireshark or that they configure
+ * PF_PACKET support back in if it's configured out.
+ */
+ static const char af_notsup[] =
+ "socket: Address family not supported by protocol";
+
+ if (strcmp(open_status_str, af_notsup) == 0) {
+ return
+ "If you are running Wireshark from a Flatpak package, "
+ "it does not support packet capture; you will need "
+ "to run a different version of Wireshark in order "
+ "to capture traffic.\n"
+ "\n"
+ "Otherwise, if your machine is running a kernel that "
+ "was not configured with CONFIG_PACKET, that kernel "
+ "does not support packet capture; you will need to "
+ "use a kernel configured with CONFIG_PACKET.";
+ }
+ return NULL;
+}
+#else
+static const char *
+get_platform_pcap_failure_secondary_error_message(const char *open_status_str _U_)
+{
+ /* No such message for platforms not handled above. */
+ return NULL;
+}
+#endif
+
+const char *
+get_pcap_failure_secondary_error_message(cap_device_open_status open_status,
+ const char *open_status_str)
+{
+ const char *platform_secondary_error_message;
+
+#ifdef _WIN32
+ /*
+ * On Windows, first make sure they *have* Npcap installed.
+ */
+ if (!has_wpcap) {
+ return
+ "In order to capture packets, Npcap or WinPcap must be installed. See\n"
+ "\n"
+ " https://npcap.com/\n"
+ "\n"
+ "for a downloadable version of Npcap and for instructions on how to\n"
+ "install it.";
+ }
+#endif
+
+ /*
+ * OK, now just return a largely platform-independent error that might
+ * have platform-specific suggestions at the end (for example, suggestions
+ * for how to get permission to capture).
+ */
+ switch (open_status) {
+
+ case CAP_DEVICE_OPEN_NO_ERR:
+ case CAP_DEVICE_OPEN_WARNING_PROMISC_NOTSUP:
+ case CAP_DEVICE_OPEN_WARNING_TSTAMP_TYPE_NOTSUP:
+ case CAP_DEVICE_OPEN_WARNING_OTHER:
+ /* This should not happen, as those aren't errors. */
+ return "";
+
+ case CAP_DEVICE_OPEN_ERROR_NO_SUCH_DEVICE:
+ case CAP_DEVICE_OPEN_ERROR_RFMON_NOTSUP:
+ case CAP_DEVICE_OPEN_ERROR_IFACE_NOT_UP:
+ /*
+ * Not clear what suggestions to make for these cases.
+ */
+ return "";
+
+ case CAP_DEVICE_OPEN_ERROR_PERM_DENIED:
+ case CAP_DEVICE_OPEN_ERROR_PROMISC_PERM_DENIED:
+ /*
+ * This is a permissions error, so no need to specify any other
+ * warnings.
+ */
+ return
+ "Please check to make sure you have sufficient permissions."
+ PLATFORM_PERMISSIONS_SUGGESTION;
+ break;
+
+ case CAP_DEVICE_OPEN_ERROR_OTHER:
+ case CAP_DEVICE_OPEN_ERROR_GENERIC:
+ /*
+ * We don't know what kind of error it is. See if there's a hint
+ * in the error string; if not, throw all generic suggestions at
+ * the user.
+ *
+ * First, check for some text that pops up in some errors.
+ * Do platform-specific checks first.
+ */
+ platform_secondary_error_message =
+ get_platform_pcap_failure_secondary_error_message(open_status_str);
+ if (platform_secondary_error_message != NULL) {
+ /* We got one, so return it. */
+ return platform_secondary_error_message;
+ }
+
+ /*
+ * Not one of those particular problems. Was this a "generic"
+ * error from pcap_open_live() or pcap_open(), in which case
+ * it might be a permissions error?
+ */
+ if (open_status == CAP_DEVICE_OPEN_ERROR_GENERIC) {
+ /* Yes. */
+ return
+ "Please check to make sure you have sufficient permissions, and that you have "
+ "the proper interface or pipe specified."
+ PLATFORM_PERMISSIONS_SUGGESTION;
+ } else {
+ /*
+ * This is not a permissions error, so no need to suggest
+ * checking permissions.
+ */
+ return
+ "Please check that you have the proper interface or pipe specified.";
+ }
+ break;
+
+ default:
+ /*
+ * This is not a permissions error, so no need to suggest
+ * checking permissions.
+ */
+ return
+ "Please check that you have the proper interface or pipe specified.";
+ break;
+ }
+}
+
#endif /* HAVE_LIBPCAP */
/*