*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
#endif
-#ifdef _WIN32
-#include <pcap-stdinc.h>
-#else /* _WIN32 */
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#elif HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#ifdef HAVE_SYS_BITYPES_H
-#include <sys/bitypes.h>
-#endif
+#include <pcap-types.h>
+#ifndef _WIN32
#include <sys/param.h>
-#include <sys/types.h>
#ifndef MSDOS
#include <sys/file.h>
#endif
#include <netinet/in.h>
#endif /* _WIN32 */
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
#include <fcntl.h>
#include <errno.h>
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#else
-#define INT_MAX 2147483647
-#endif
+
+#include "diag-control.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#include "pcap-int.h"
+#include "optimize.h"
+
#ifdef HAVE_DAG_API
#include "pcap-dag.h"
#endif /* HAVE_DAG_API */
#include "pcap-tc.h"
#endif /* HAVE_TC_API */
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
#include "pcap-usb-linux.h"
#endif
#include "pcap-dbus.h"
#endif
+#ifdef PCAP_SUPPORT_RDMASNIFF
+#include "pcap-rdmasniff.h"
+#endif
+
+#ifdef PCAP_SUPPORT_DPDK
+#include "pcap-dpdk.h"
+#endif
+
+#ifdef HAVE_AIRPCAP_API
+#include "pcap-airpcap.h"
+#endif
+
+#ifdef _WIN32
+/*
+ * To quote the WSAStartup() documentation:
+ *
+ * The WSAStartup function typically leads to protocol-specific helper
+ * DLLs being loaded. As a result, the WSAStartup function should not
+ * be called from the DllMain function in a application DLL. This can
+ * potentially cause deadlocks.
+ *
+ * and the WSACleanup() documentation:
+ *
+ * The WSACleanup function typically leads to protocol-specific helper
+ * DLLs being unloaded. As a result, the WSACleanup function should not
+ * be called from the DllMain function in a application DLL. This can
+ * potentially cause deadlocks.
+ *
+ * So we don't initialize Winsock in a DllMain() routine.
+ *
+ * pcap_init() should be called to initialize pcap on both UN*X and
+ * Windows; it will initialize Winsock on Windows. (It will also be
+ * initialized as needed if pcap_init() hasn't been called.)
+ */
+
+/*
+ * Start Winsock.
+ * Internal routine.
+ */
static int
-pcap_not_initialized(pcap_t *pcap)
+internal_wsockinit(char *errbuf)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ static int err = -1;
+ static int done = 0;
+ int status;
+
+ if (done)
+ return (err);
+
+ /*
+ * Versions of Windows that don't support Winsock 2.2 are
+ * too old for us.
+ */
+ wVersionRequested = MAKEWORD(2, 2);
+ status = WSAStartup(wVersionRequested, &wsaData);
+ done = 1;
+ if (status != 0) {
+ if (errbuf != NULL) {
+ pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE,
+ status, "WSAStartup() failed");
+ }
+ return (err);
+ }
+ atexit ((void(*)(void))WSACleanup);
+ err = 0;
+ return (err);
+}
+
+/*
+ * Exported in case some applications using WinPcap/Npcap called it,
+ * even though it wasn't exported.
+ */
+int
+wsockinit(void)
+{
+ return (internal_wsockinit(NULL));
+}
+
+/*
+ * This is the exported function; new programs should call this.
+ * *Newer* programs should call pcap_init().
+ */
+int
+pcap_wsockinit(void)
+{
+ return (internal_wsockinit(NULL));
+}
+#endif /* _WIN32 */
+
+/*
+ * Do whatever initialization is needed for libpcap.
+ *
+ * The argument specifies whether we use the local code page or UTF-8
+ * for strings; on UN*X, we just assume UTF-8 in places where the encoding
+ * would matter, whereas, on Windows, we use the local code page for
+ * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8.
+ *
+ * On Windows, we also disable the hack in pcap_create() to deal with
+ * being handed UTF-16 strings, because if the user calls this they're
+ * explicitly declaring that they will either be passing local code
+ * page strings or UTF-8 strings, so we don't need to allow UTF-16LE
+ * strings to be passed. For good measure, on Windows *and* UN*X,
+ * we disable pcap_lookupdev(), to prevent anybody from even
+ * *trying* to pass the result of pcap_lookupdev() - which might be
+ * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create()
+ * or pcap_open_live() or pcap_open().
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int pcap_new_api; /* pcap_lookupdev() always fails */
+int pcap_utf_8_mode; /* Strings should be in UTF-8. */
+
+int
+pcap_init(unsigned int opts, char *errbuf)
+{
+ static int initialized;
+
+ /*
+ * Don't allow multiple calls that set different modes; that
+ * may mean a library is initializing pcap in one mode and
+ * a program using that library, or another library used by
+ * that program, is initializing it in another mode.
+ */
+ switch (opts) {
+
+ case PCAP_CHAR_ENC_LOCAL:
+ /* Leave "UTF-8 mode" off. */
+ if (initialized) {
+ if (pcap_utf_8_mode) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Multiple pcap_init calls with different character encodings");
+ return (PCAP_ERROR);
+ }
+ }
+ break;
+
+ case PCAP_CHAR_ENC_UTF_8:
+ /* Turn on "UTF-8 mode". */
+ if (initialized) {
+ if (!pcap_utf_8_mode) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Multiple pcap_init calls with different character encodings");
+ return (PCAP_ERROR);
+ }
+ }
+ pcap_utf_8_mode = 1;
+ break;
+
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown options specified");
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * Turn the appropriate mode on for error messages; those routines
+ * are also used in rpcapd, which has no access to pcap's internal
+ * UTF-8 mode flag, so we have to call a routine to set its
+ * UTF-8 mode flag.
+ */
+ pcap_fmt_set_encoding(opts);
+
+ if (initialized) {
+ /*
+ * Nothing more to do; for example, on Windows, we've
+ * already initialized Winsock.
+ */
+ return (0);
+ }
+
+#ifdef _WIN32
+ /*
+ * Now set up Winsock.
+ */
+ if (internal_wsockinit(errbuf) == -1) {
+ /* Failed. */
+ return (PCAP_ERROR);
+ }
+#endif
+
+ /*
+ * We're done.
+ */
+ initialized = 1;
+ pcap_new_api = 1;
+ return (0);
+}
+
+/*
+ * String containing the library version.
+ * Not explicitly exported via a header file - the right API to use
+ * is pcap_lib_version() - but some programs included it, so we
+ * provide it.
+ *
+ * We declare it here, right before defining it, to squelch any
+ * warnings we might get from compilers about the lack of a
+ * declaration.
+ */
+PCAP_API char pcap_version[];
+PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION;
+
+static void
+pcap_set_not_initialized_message(pcap_t *pcap)
{
+ if (pcap->activated) {
+ /* A module probably forgot to set the function pointer */
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ "This operation isn't properly handled by that device");
+ return;
+ }
/* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
+}
+
+static int
+pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_,
+ u_char *user _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setfilter_not_initialized(pcap_t *pcap, struct bpf_program *fp _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setdirection_not_initialized(pcap_t *pcap, pcap_direction_t d _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_set_datalink_not_initialized(pcap_t *pcap, int dlt _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_getnonblock_not_initialized(pcap_t *pcap)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_)
+{
+ pcap_set_not_initialized_message(pcap);
/* this means 'not initialized' */
return (PCAP_ERROR_NOT_ACTIVATED);
}
#ifdef _WIN32
-static void *
-pcap_not_initialized_ptr(pcap_t *pcap)
+static struct pcap_stat *
+pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
{
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
- "This handle hasn't been activated yet");
+ pcap_set_not_initialized_message(pcap);
return (NULL);
}
+static int
+pcap_setbuff_not_initialized(pcap_t *pcap, int dim _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmode_not_initialized(pcap_t *pcap, int mode _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_setmintocopy_not_initialized(pcap_t *pcap, int size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ /* this means 'not initialized' */
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
static HANDLE
pcap_getevent_not_initialized(pcap_t *pcap)
{
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
- "This handle hasn't been activated yet");
+ pcap_set_not_initialized_message(pcap);
return (INVALID_HANDLE_VALUE);
}
+static int
+pcap_oid_get_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+ void *data _U_, size_t *lenp _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
+ const void *data _U_, size_t *lenp _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
static u_int
-pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+ int sync _U_)
{
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
- "This handle hasn't been activated yet");
+ pcap_set_not_initialized_message(pcap);
return (0);
}
+static int
+pcap_setuserbuffer_not_initialized(pcap_t *pcap, int size _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_not_initialized(pcap_t *pcap, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
+static int
+pcap_live_dump_ended_not_initialized(pcap_t *pcap, int sync _U_)
+{
+ pcap_set_not_initialized_message(pcap);
+ return (PCAP_ERROR_NOT_ACTIVATED);
+}
+
static PAirpcapHandle
pcap_get_airpcap_handle_not_initialized(pcap_t *pcap)
{
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
- "This handle hasn't been activated yet");
+ pcap_set_not_initialized_message(pcap);
return (NULL);
}
#endif
if (p->tstamp_type_count == 0) {
/*
* We don't support multiple time stamp types.
+ * That means the only type we support is PCAP_TSTAMP_HOST;
+ * set up a list containing only that type.
*/
- *tstamp_typesp = NULL;
+ *tstamp_typesp = (int*)malloc(sizeof(**tstamp_typesp));
+ if (*tstamp_typesp == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
+ return (PCAP_ERROR);
+ }
+ **tstamp_typesp = PCAP_TSTAMP_HOST;
+ return (1);
} else {
*tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
p->tstamp_type_count);
if (*tstamp_typesp == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
return (PCAP_ERROR);
}
(void)memcpy(*tstamp_typesp, p->tstamp_type_list,
sizeof(**tstamp_typesp) * p->tstamp_type_count);
+ return (p->tstamp_type_count);
}
- return (p->tstamp_type_count);
}
/*
* Return codes for pcap_offline_read() are:
* - 0: EOF
* - -1: error
- * - >1: OK
+ * - >0: OK - result is number of packets read, so
+ * it will be 1 in this case, as we've passed
+ * a maximum packet count of 1
* The first one ('0') conflicts with the return code of
* 0 from pcap_read() meaning "no packets arrived before
* the timeout expired", so we map it to -2 so you can
* - 0: timeout
* - -1: error
* - -2: loop was broken out of with pcap_breakloop()
- * - >1: OK
+ * - >0: OK, result is number of packets captured, so
+ * it will be 1 in this case, as we've passed
+ * a maximum packet count of 1
* The first one ('0') conflicts with the return code of 0 from
* pcap_offline_read() meaning "end of file".
*/
#ifdef PCAP_SUPPORT_BT_MONITOR
{ bt_monitor_findalldevs, bt_monitor_create },
#endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
{ usb_findalldevs, usb_create },
#endif
#ifdef PCAP_SUPPORT_NETFILTER
{ netfilter_findalldevs, netfilter_create },
#endif
-#ifdef PCAP_SUPPORT_NETFILTER
+#ifdef PCAP_SUPPORT_NETMAP
{ pcap_netmap_findalldevs, pcap_netmap_create },
#endif
#ifdef PCAP_SUPPORT_DBUS
{ dbus_findalldevs, dbus_create },
+#endif
+#ifdef PCAP_SUPPORT_RDMASNIFF
+ { rdmasniff_findalldevs, rdmasniff_create },
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+ { pcap_dpdk_findalldevs, pcap_dpdk_create },
+#endif
+#ifdef HAVE_AIRPCAP_API
+ { airpcap_findalldevs, airpcap_create },
#endif
{ NULL, NULL }
};
*
* The figure of merit, which is lower the "better" the interface is,
* has the uppermost bit set if the interface isn't running, the bit
- * below that set if the interface isn't up, the bit below that set
- * if the interface is a loopback interface, and the interface index
- * in the 29 bits below that. (Yes, we assume u_int is 32 bits.)
+ * below that set if the interface isn't up, the bit below that
+ * set if the interface is a loopback interface, and the bit below
+ * that set if it's the "any" interface.
+ *
+ * Note: we don't sort by unit number because 1) not all interfaces have
+ * a unit number (systemd, for example, might assign interface names
+ * based on the interface's MAC address or on the physical location of
+ * the adapter's connector), and 2) if the name does end with a simple
+ * unit number, it's not a global property of the interface, it's only
+ * useful as a sort key for device names with the same prefix, so xyz0
+ * shouldn't necessarily sort before abc2. This means that interfaces
+ * with the same figure of merit will be sorted by the order in which
+ * the mechanism from which we're getting the interfaces supplies them.
*/
static u_int
get_figure_of_merit(pcap_if_t *dev)
{
- const char *cp;
u_int n;
- if (strcmp(dev->name, "any") == 0) {
- /*
- * Give the "any" device an artificially high instance
- * number, so it shows up after all other non-loopback
- * interfaces.
- */
- n = 0x1FFFFFFF; /* 29 all-1 bits */
- } else {
- /*
- * A number at the end of the device name string is
- * assumed to be an instance number. Add 1 to the
- * instance number, and use 0 for "no instance
- * number", so we don't put "no instance number"
- * devices and "instance 0" devices together.
- */
- cp = dev->name + strlen(dev->name) - 1;
- while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9')
- cp--;
- if (*cp >= '0' && *cp <= '9')
- n = atoi(cp) + 1;
- else
- n = 0;
- }
+ n = 0;
if (!(dev->flags & PCAP_IF_RUNNING))
n |= 0x80000000;
if (!(dev->flags & PCAP_IF_UP))
n |= 0x40000000;
- if (dev->flags & PCAP_IF_LOOPBACK)
+
+ /*
+ * Give non-wireless interfaces that aren't disconnected a better
+ * figure of merit than interfaces that are disconnected, as
+ * "disconnected" should indicate that the interface isn't
+ * plugged into a network and thus won't give you any traffic.
+ *
+ * For wireless interfaces, it means "associated with a network",
+ * which we presume not to necessarily prevent capture, as you
+ * might run the adapter in some flavor of monitor mode.
+ */
+ if (!(dev->flags & PCAP_IF_WIRELESS) &&
+ (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED)
n |= 0x20000000;
+
+ /*
+ * Sort loopback devices after non-loopback devices, *except* for
+ * disconnected devices.
+ */
+ if (dev->flags & PCAP_IF_LOOPBACK)
+ n |= 0x10000000;
+
+ /*
+ * Sort the "any" device before loopback and disconnected devices,
+ * but after all other devices.
+ */
+ if (strcmp(dev->name, "any") == 0)
+ n |= 0x08000000;
+
return (n);
}
* description available, it still might be nice to get some description
* string based on the device type or something such as that.
*
- * In OS X, the System Configuration framework can apparently return
+ * In macOS, the System Configuration framework can apparently return
* names in 10.4 and later.
*
* It also appears that freedesktop.org's HAL offers an "info.product"
* description?
*/
static char *
+#ifdef SIOCGIFDESCR
get_if_description(const char *name)
{
-#ifdef SIOCGIFDESCR
char *description = NULL;
int s;
struct ifreq ifrdesc;
* Get the description for the interface.
*/
memset(&ifrdesc, 0, sizeof ifrdesc);
- strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
+ pcap_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s >= 0) {
#ifdef __FreeBSD__
}
#endif /* __FreeBSD__ */
close(s);
- if (description != NULL && strlen(description) == 0) {
+ if (description != NULL && description[0] == '\0') {
/*
* Description is empty, so discard it.
*/
* OK, it's a valid number that's not
* bigger than INT_MAX. Construct
* a description from it.
+ * (If that fails, we don't worry about
+ * it, we just return NULL.)
*/
- static const char descr_prefix[] = "USB bus number ";
- size_t descr_size;
-
- /*
- * Allow enough room for a 32-bit bus number.
- * sizeof (descr_prefix) includes the
- * terminating NUL.
- */
- descr_size = sizeof (descr_prefix) + 10;
- description = malloc(descr_size);
- if (description != NULL) {
- pcap_snprintf(description, descr_size,
- "%s%ld", descr_prefix, busnum);
+ if (pcap_asprintf(&description,
+ "USB bus number %ld", busnum) == -1) {
+ /* Failed. */
+ description = NULL;
}
}
}
#endif
return (description);
#else /* SIOCGIFDESCR */
+get_if_description(const char *name _U_)
+{
return (NULL);
#endif /* SIOCGIFDESCR */
}
*/
pcap_if_t *
find_or_add_if(pcap_if_list_t *devlistp, const char *name,
- bpf_u_int32 if_flags, char *errbuf)
+ bpf_u_int32 if_flags, get_if_flags_func get_flags_func, char *errbuf)
{
bpf_u_int32 pcap_flags;
* see if it looks like a loopback device.
*/
if (name[0] == 'l' && name[1] == 'o' &&
- (isdigit((unsigned char)(name[2])) || name[2] == '\0')
+ (PCAP_ISDIGIT(name[2]) || name[2] == '\0'))
pcap_flags |= PCAP_IF_LOOPBACK;
#endif
#ifdef IFF_UP
* attempt to add one.
*/
return (find_or_add_dev(devlistp, name, pcap_flags,
- get_if_description(name), errbuf));
+ get_flags_func, get_if_description(name), errbuf));
}
/*
*/
int
add_addr_to_if(pcap_if_list_t *devlistp, const char *name,
- bpf_u_int32 if_flags,
+ bpf_u_int32 if_flags, get_if_flags_func get_flags_func,
struct sockaddr *addr, size_t addr_size,
struct sockaddr *netmask, size_t netmask_size,
struct sockaddr *broadaddr, size_t broadaddr_size,
/*
* Check whether the device exists and, if not, add it.
*/
- curdev = find_or_add_if(devlistp, name, if_flags, errbuf);
+ curdev = find_or_add_if(devlistp, name, if_flags, get_flags_func,
+ errbuf);
if (curdev == NULL) {
/*
* Error - give up.
*/
curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
if (curaddr == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
return (-1);
}
if (addr != NULL && addr_size != 0) {
curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size);
if (curaddr->addr == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
free(curaddr);
return (-1);
}
if (netmask != NULL && netmask_size != 0) {
curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size);
if (curaddr->netmask == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
if (curaddr->addr != NULL)
free(curaddr->addr);
free(curaddr);
if (broadaddr != NULL && broadaddr_size != 0) {
curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size);
if (curaddr->broadaddr == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
if (curaddr->netmask != NULL)
free(curaddr->netmask);
if (curaddr->addr != NULL)
if (dstaddr != NULL && dstaddr_size != 0) {
curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size);
if (curaddr->dstaddr == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
if (curaddr->broadaddr != NULL)
free(curaddr->broadaddr);
if (curaddr->netmask != NULL)
*/
pcap_if_t *
find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags,
- const char *description, char *errbuf)
+ get_if_flags_func get_flags_func, const char *description, char *errbuf)
{
pcap_if_t *curdev;
}
/*
- * No, we didn't find it. Try to add it to the list of devices.
+ * No, we didn't find it.
+ */
+
+ /*
+ * Try to get additional flags for the device.
+ */
+ if ((*get_flags_func)(name, &flags, errbuf) == -1) {
+ /*
+ * Failed.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now, try to add it to the list of devices.
*/
return (add_dev(devlistp, name, flags, description, errbuf));
}
curdev = malloc(sizeof(pcap_if_t));
if (curdev == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
return (NULL);
}
curdev->next = NULL;
curdev->name = strdup(name);
if (curdev->name == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
free(curdev);
return (NULL);
}
*/
curdev->description = strdup(description);
if (curdev->description == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
free(curdev->name);
free(curdev);
return (NULL);
}
}
-#ifdef HAVE_REMOTE
-#include "pcap-rpcap.h"
-#endif
-
-pcap_t *
-pcap_create(const char *device, char *errbuf)
+/*
+ * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as
+ * it actually returns the names of all interfaces, with a NUL separator
+ * between them; some callers may depend on that.
+ *
+ * MS-DOS has its own pcap_lookupdev(), but that might be useful only
+ * as an optimization.
+ *
+ * In all other cases, we just use pcap_findalldevs() to get a list of
+ * devices, and pick from that list.
+ */
+#if !defined(HAVE_PACKET32) && !defined(MSDOS)
+/*
+ * Return the name of a network interface attached to the system, or NULL
+ * if none can be found. The interface must be configured up; the
+ * lowest unit number is preferred; loopback is ignored.
+ */
+char *
+pcap_lookupdev(char *errbuf)
{
- size_t i;
- int is_theirs;
- pcap_t *p;
- char *device_str;
+ pcap_if_t *alldevs;
+#ifdef _WIN32
+ /*
+ * Windows - use the same size as the old WinPcap 3.1 code.
+ * XXX - this is probably bigger than it needs to be.
+ */
+ #define IF_NAMESIZE 8192
+#else
+ /*
+ * UN*X - use the system's interface name size.
+ * XXX - that might not be large enough for capture devices
+ * that aren't regular network interfaces.
+ */
+ /* for old BSD systems, including bsdi3 */
+ #ifndef IF_NAMESIZE
+ #define IF_NAMESIZE IFNAMSIZ
+ #endif
+#endif
+ static char device[IF_NAMESIZE + 1];
+ char *ret;
/*
- * A null device name is equivalent to the "any" device -
- * which might not be supported on this platform, but
- * this means that you'll get a "not supported" error
- * rather than, say, a crash when we try to dereference
+ * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+ * it may return UTF-16 strings, for backwards-compatibility
+ * reasons, and we're also disabling the hack to make that work,
+ * for not-going-past-the-end-of-a-string reasons, and 2) we
+ * want its behavior to be consistent.
+ *
+ * In addition, it's not thread-safe, so we've marked it as
+ * deprecated.
+ */
+ if (pcap_new_api) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+ return (NULL);
+ }
+
+ if (pcap_findalldevs(&alldevs, errbuf) == -1)
+ return (NULL);
+
+ if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
+ /*
+ * There are no devices on the list, or the first device
+ * on the list is a loopback device, which means there
+ * are no non-loopback devices on the list. This means
+ * we can't return any device.
+ *
+ * XXX - why not return a loopback device? If we can't
+ * capture on it, it won't be on the list, and if it's
+ * on the list, there aren't any non-loopback devices,
+ * so why not just supply it as the default device?
+ */
+ (void)pcap_strlcpy(errbuf, "no suitable device found",
+ PCAP_ERRBUF_SIZE);
+ ret = NULL;
+ } else {
+ /*
+ * Return the name of the first device on the list.
+ */
+ (void)pcap_strlcpy(device, alldevs->name, sizeof(device));
+ ret = device;
+ }
+
+ pcap_freealldevs(alldevs);
+ return (ret);
+}
+#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */
+
+#if !defined(_WIN32) && !defined(MSDOS)
+/*
+ * We don't just fetch the entire list of devices, search for the
+ * particular device, and use its first IPv4 address, as that's too
+ * much work to get just one device's netmask.
+ *
+ * If we had an API to get attributes for a given device, we could
+ * use that.
+ */
+int
+pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
+ char *errbuf)
+{
+ register int fd;
+ register struct sockaddr_in *sin4;
+ struct ifreq ifr;
+
+ /*
+ * The pseudo-device "any" listens on all interfaces and therefore
+ * has the network address and -mask "0.0.0.0" therefore catching
+ * all traffic. Using NULL for the interface is the same as "any".
+ */
+ if (!device || strcmp(device, "any") == 0
+#ifdef HAVE_DAG_API
+ || strstr(device, "dag") != NULL
+#endif
+#ifdef HAVE_SEPTEL_API
+ || strstr(device, "septel") != NULL
+#endif
+#ifdef PCAP_SUPPORT_BT
+ || strstr(device, "bluetooth") != NULL
+#endif
+#ifdef PCAP_SUPPORT_LINUX_USBMON
+ || strstr(device, "usbmon") != NULL
+#endif
+#ifdef HAVE_SNF_API
+ || strstr(device, "snf") != NULL
+#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ || strncmp(device, "netmap:", 7) == 0
+ || strncmp(device, "vale", 4) == 0
+#endif
+#ifdef PCAP_SUPPORT_DPDK
+ || strncmp(device, "dpdk:", 5) == 0
+#endif
+ ) {
+ *netp = *maskp = 0;
+ return 0;
+ }
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "socket");
+ return (-1);
+ }
+ memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+ /* XXX Work around Linux kernel bug */
+ ifr.ifr_addr.sa_family = AF_INET;
+#endif
+ (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ if (errno == EADDRNOTAVAIL) {
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "%s: no IPv4 address assigned", device);
+ } else {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "SIOCGIFADDR: %s", device);
+ }
+ (void)close(fd);
+ return (-1);
+ }
+ sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
+ *netp = sin4->sin_addr.s_addr;
+ memset(&ifr, 0, sizeof(ifr));
+#ifdef linux
+ /* XXX Work around Linux kernel bug */
+ ifr.ifr_addr.sa_family = AF_INET;
+#endif
+ (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "SIOCGIFNETMASK: %s", device);
+ (void)close(fd);
+ return (-1);
+ }
+ (void)close(fd);
+ *maskp = sin4->sin_addr.s_addr;
+ if (*maskp == 0) {
+ if (IN_CLASSA(*netp))
+ *maskp = IN_CLASSA_NET;
+ else if (IN_CLASSB(*netp))
+ *maskp = IN_CLASSB_NET;
+ else if (IN_CLASSC(*netp))
+ *maskp = IN_CLASSC_NET;
+ else {
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "inet class for 0x%x unknown", *netp);
+ return (-1);
+ }
+ }
+ *netp &= *maskp;
+ return (0);
+}
+#endif /* !defined(_WIN32) && !defined(MSDOS) */
+
+#ifdef ENABLE_REMOTE
+#include "pcap-rpcap.h"
+
+/*
+ * Extract a substring from a string.
+ */
+static char *
+get_substring(const char *p, size_t len, char *ebuf)
+{
+ char *token;
+
+ token = malloc(len + 1);
+ if (token == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (NULL);
+ }
+ memcpy(token, p, len);
+ token[len] = '\0';
+ return (token);
+}
+
+/*
+ * Parse a capture source that might be a URL.
+ *
+ * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp
+ * are set to NULL, *pathp is set to point to the source, and 0 is
+ * returned.
+ *
+ * If source is a URL, and the URL refers to a local device (a special
+ * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set
+ * to NULL, *pathp is set to point to the device name, and 0 is returned.
+ *
+ * If source is a URL, and it's not a special case that refers to a local
+ * device, and the parse succeeds:
+ *
+ * *schemep is set to point to an allocated string containing the scheme;
+ *
+ * if user information is present in the URL, *userinfop is set to point
+ * to an allocated string containing the user information, otherwise
+ * it's set to NULL;
+ *
+ * if host information is present in the URL, *hostp is set to point
+ * to an allocated string containing the host information, otherwise
+ * it's set to NULL;
+ *
+ * if a port number is present in the URL, *portp is set to point
+ * to an allocated string containing the port number, otherwise
+ * it's set to NULL;
+ *
+ * *pathp is set to point to an allocated string containing the
+ * path;
+ *
+ * and 0 is returned.
+ *
+ * If the parse fails, ebuf is set to an error string, and -1 is returned.
+ */
+static int
+pcap_parse_source(const char *source, char **schemep, char **userinfop,
+ char **hostp, char **portp, char **pathp, char *ebuf)
+{
+ char *colonp;
+ size_t scheme_len;
+ char *scheme;
+ const char *endp;
+ size_t authority_len;
+ char *authority;
+ char *parsep, *atsignp, *bracketp;
+ char *userinfo, *host, *port, *path;
+
+ /*
+ * Start out returning nothing.
+ */
+ *schemep = NULL;
+ *userinfop = NULL;
+ *hostp = NULL;
+ *portp = NULL;
+ *pathp = NULL;
+
+ /*
+ * RFC 3986 says:
+ *
+ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ *
+ * hier-part = "//" authority path-abempty
+ * / path-absolute
+ * / path-rootless
+ * / path-empty
+ *
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ *
+ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ *
+ * Step 1: look for the ":" at the end of the scheme.
+ * A colon in the source is *NOT* sufficient to indicate that
+ * this is a URL, as interface names on some platforms might
+ * include colons (e.g., I think some Solaris interfaces
+ * might).
+ */
+ colonp = strchr(source, ':');
+ if (colonp == NULL) {
+ /*
+ * The source is the device to open.
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ *pathp = strdup(source);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * All schemes must have "//" after them, i.e. we only support
+ * hier-part = "//" authority path-abempty, not
+ * hier-part = path-absolute
+ * hier-part = path-rootless
+ * hier-part = path-empty
+ *
+ * We need that in order to distinguish between a local device
+ * name that happens to contain a colon and a URI.
+ */
+ if (strncmp(colonp + 1, "//", 2) != 0) {
+ /*
+ * The source is the device to open.
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ *pathp = strdup(source);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * XXX - check whether the purported scheme could be a scheme?
+ */
+
+ /*
+ * OK, this looks like a URL.
+ * Get the scheme.
+ */
+ scheme_len = colonp - source;
+ scheme = malloc(scheme_len + 1);
+ if (scheme == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ memcpy(scheme, source, scheme_len);
+ scheme[scheme_len] = '\0';
+
+ /*
+ * Treat file: specially - take everything after file:// as
+ * the pathname.
+ */
+ if (pcap_strcasecmp(scheme, "file") == 0) {
+ *pathp = strdup(colonp + 3);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(scheme);
+ return (-1);
+ }
+ *schemep = scheme;
+ return (0);
+ }
+
+ /*
+ * The WinPcap documentation says you can specify a local
+ * interface with "rpcap://{device}"; we special-case
+ * that here. If the scheme is "rpcap", and there are
+ * no slashes past the "//", we just return the device.
+ *
+ * XXX - %-escaping?
+ */
+ if ((pcap_strcasecmp(scheme, "rpcap") == 0 ||
+ pcap_strcasecmp(scheme, "rpcaps") == 0) &&
+ strchr(colonp + 3, '/') == NULL) {
+ /*
+ * Local device.
+ *
+ * Return a NULL pointer for the scheme, user information,
+ * host, and port, and return the device as the path.
+ */
+ free(scheme);
+ *pathp = strdup(colonp + 3);
+ if (*pathp == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * OK, now start parsing the authority.
+ * Get token, terminated with / or terminated at the end of
+ * the string.
+ */
+ authority_len = strcspn(colonp + 3, "/");
+ authority = get_substring(colonp + 3, authority_len, ebuf);
+ if (authority == NULL) {
+ /*
+ * Error.
+ */
+ free(scheme);
+ return (-1);
+ }
+ endp = colonp + 3 + authority_len;
+
+ /*
+ * Now carve the authority field into its components.
+ */
+ parsep = authority;
+
+ /*
+ * Is there a userinfo field?
+ */
+ atsignp = strchr(parsep, '@');
+ if (atsignp != NULL) {
+ /*
+ * Yes.
+ */
+ size_t userinfo_len;
+
+ userinfo_len = atsignp - parsep;
+ userinfo = get_substring(parsep, userinfo_len, ebuf);
+ if (userinfo == NULL) {
+ /*
+ * Error.
+ */
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = atsignp + 1;
+ } else {
+ /*
+ * No.
+ */
+ userinfo = NULL;
+ }
+
+ /*
+ * Is there a host field?
+ */
+ if (*parsep == '\0') {
+ /*
+ * No; there's no host field or port field.
+ */
+ host = NULL;
+ port = NULL;
+ } else {
+ /*
+ * Yes.
+ */
+ size_t host_len;
+
+ /*
+ * Is it an IP-literal?
+ */
+ if (*parsep == '[') {
+ /*
+ * Yes.
+ * Treat verything up to the closing square
+ * bracket as the IP-Literal; we don't worry
+ * about whether it's a valid IPv6address or
+ * IPvFuture (or an IPv4address, for that
+ * matter, just in case we get handed a
+ * URL with an IPv4 IP-Literal, of the sort
+ * that pcap_createsrcstr() used to generate,
+ * and that pcap_parsesrcstr(), in the original
+ * WinPcap code, accepted).
+ */
+ bracketp = strchr(parsep, ']');
+ if (bracketp == NULL) {
+ /*
+ * There's no closing square bracket.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "IP-literal in URL doesn't end with ]");
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ if (*(bracketp + 1) != '\0' &&
+ *(bracketp + 1) != ':') {
+ /*
+ * There's extra crud after the
+ * closing square bracketn.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Extra text after IP-literal in URL");
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ host_len = (bracketp - 1) - parsep;
+ host = get_substring(parsep + 1, host_len, ebuf);
+ if (host == NULL) {
+ /*
+ * Error.
+ */
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = bracketp + 1;
+ } else {
+ /*
+ * No.
+ * Treat everything up to a : or the end of
+ * the string as the host.
+ */
+ host_len = strcspn(parsep, ":");
+ host = get_substring(parsep, host_len, ebuf);
+ if (host == NULL) {
+ /*
+ * Error.
+ */
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ parsep = parsep + host_len;
+ }
+
+ /*
+ * Is there a port field?
+ */
+ if (*parsep == ':') {
+ /*
+ * Yes. It's the rest of the authority field.
+ */
+ size_t port_len;
+
+ parsep++;
+ port_len = strlen(parsep);
+ port = get_substring(parsep, port_len, ebuf);
+ if (port == NULL) {
+ /*
+ * Error.
+ */
+ free(host);
+ free(userinfo);
+ free(authority);
+ free(scheme);
+ return (-1);
+ }
+ } else {
+ /*
+ * No.
+ */
+ port = NULL;
+ }
+ }
+ free(authority);
+
+ /*
+ * Everything else is the path. Strip off the leading /.
+ */
+ if (*endp == '\0')
+ path = strdup("");
+ else
+ path = strdup(endp + 1);
+ if (path == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ free(port);
+ free(host);
+ free(userinfo);
+ free(scheme);
+ return (-1);
+ }
+ *schemep = scheme;
+ *userinfop = userinfo;
+ *hostp = host;
+ *portp = port;
+ *pathp = path;
+ return (0);
+}
+
+int
+pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
+ const char *name, unsigned char uses_ssl, char *errbuf)
+{
+ switch (type) {
+
+ case PCAP_SRC_FILE:
+ pcap_strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
+ if (name != NULL && *name != '\0') {
+ pcap_strlcat(source, name, PCAP_BUF_SIZE);
+ return (0);
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The file name cannot be NULL.");
+ return (-1);
+ }
+
+ case PCAP_SRC_IFREMOTE:
+ pcap_strlcpy(source,
+ (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING),
+ PCAP_BUF_SIZE);
+ if (host != NULL && *host != '\0') {
+ if (strchr(host, ':') != NULL) {
+ /*
+ * The host name contains a colon, so it's
+ * probably an IPv6 address, and needs to
+ * be included in square brackets.
+ */
+ pcap_strlcat(source, "[", PCAP_BUF_SIZE);
+ pcap_strlcat(source, host, PCAP_BUF_SIZE);
+ pcap_strlcat(source, "]", PCAP_BUF_SIZE);
+ } else
+ pcap_strlcat(source, host, PCAP_BUF_SIZE);
+
+ if (port != NULL && *port != '\0') {
+ pcap_strlcat(source, ":", PCAP_BUF_SIZE);
+ pcap_strlcat(source, port, PCAP_BUF_SIZE);
+ }
+
+ pcap_strlcat(source, "/", PCAP_BUF_SIZE);
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The host name cannot be NULL.");
+ return (-1);
+ }
+
+ if (name != NULL && *name != '\0')
+ pcap_strlcat(source, name, PCAP_BUF_SIZE);
+
+ return (0);
+
+ case PCAP_SRC_IFLOCAL:
+ pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+
+ if (name != NULL && *name != '\0')
+ pcap_strlcat(source, name, PCAP_BUF_SIZE);
+
+ return (0);
+
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The interface type is not valid.");
+ return (-1);
+ }
+}
+
+
+int
+pcap_createsrcstr(char *source, int type, const char *host, const char *port,
+ const char *name, char *errbuf)
+{
+ return (pcap_createsrcstr_ex(source, type, host, port, name, 0, errbuf));
+}
+
+int
+pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
+ char *name, unsigned char *uses_ssl, char *errbuf)
+{
+ char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
+
+ /* Initialization stuff */
+ if (host)
+ *host = '\0';
+ if (port)
+ *port = '\0';
+ if (name)
+ *name = '\0';
+ if (uses_ssl)
+ *uses_ssl = 0;
+
+ /* Parse the source string */
+ if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
+ &tmpport, &tmppath, errbuf) == -1) {
+ /*
+ * Fail.
+ */
+ return (-1);
+ }
+
+ if (scheme == NULL) {
+ /*
+ * Local device.
+ */
+ if (name && tmppath)
+ pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFLOCAL;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ return (0);
+ }
+
+ int is_rpcap = 0;
+ if (strcmp(scheme, "rpcaps") == 0) {
+ is_rpcap = 1;
+ if (uses_ssl) *uses_ssl = 1;
+ } else if (strcmp(scheme, "rpcap") == 0) {
+ is_rpcap = 1;
+ }
+
+ if (is_rpcap) {
+ /*
+ * rpcap[s]://
+ *
+ * pcap_parse_source() has already handled the case of
+ * rpcap[s]://device
+ */
+ if (host && tmphost) {
+ if (tmpuserinfo)
+ snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+ tmpuserinfo, tmphost);
+ else
+ pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
+ }
+ if (port && tmpport)
+ pcap_strlcpy(port, tmpport, PCAP_BUF_SIZE);
+ if (name && tmppath)
+ pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFREMOTE;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+ }
+
+ if (strcmp(scheme, "file") == 0) {
+ /*
+ * file://
+ */
+ if (name && tmppath)
+ pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_FILE;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+ }
+
+ /*
+ * Neither rpcap: nor file:; just treat the entire string
+ * as a local device.
+ */
+ if (name)
+ pcap_strlcpy(name, source, PCAP_BUF_SIZE);
+ if (type)
+ *type = PCAP_SRC_IFLOCAL;
+ free(tmppath);
+ free(tmpport);
+ free(tmphost);
+ free(tmpuserinfo);
+ free(scheme);
+ return (0);
+}
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+ char *name, char *errbuf)
+{
+ return (pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf));
+}
+#endif
+
+pcap_t *
+pcap_create(const char *device, char *errbuf)
+{
+ size_t i;
+ int is_theirs;
+ pcap_t *p;
+ char *device_str;
+
+ /*
+ * A null device name is equivalent to the "any" device -
+ * which might not be supported on this platform, but
+ * this means that you'll get a "not supported" error
+ * rather than, say, a crash when we try to dereference
* the null pointer.
*/
if (device == NULL)
else {
#ifdef _WIN32
/*
- * If the string appears to be little-endian UCS-2/UTF-16,
- * convert it to ASCII.
+ * On Windows, for backwards compatibility reasons,
+ * pcap_lookupdev() returns a pointer to a sequence of
+ * pairs of UTF-16LE device names and local code page
+ * description strings.
*
- * XXX - to UTF-8 instead? Or report an error if any
- * character isn't ASCII?
+ * This means that if a program uses pcap_lookupdev()
+ * to get a default device, and hands that to an API
+ * that opens devices, we'll get handed a UTF-16LE
+ * string, not a string in the local code page.
+ *
+ * To work around that, we check whether the string
+ * looks as if it might be a UTF-16LE string and, if
+ * so, convert it back to the local code page's
+ * extended ASCII.
+ *
+ * We disable that check in "new API" mode, because:
+ *
+ * 1) You *cannot* reliably detect whether a
+ * string is UTF-16LE or not; "a" could either
+ * be a one-character ASCII string or the first
+ * character of a UTF-16LE string.
+ *
+ * 2) Doing that test can run past the end of
+ * the string, if it's a 1-character ASCII
+ * string
+ *
+ * This particular version of this heuristic dates
+ * back to WinPcap 4.1.1; PacketOpenAdapter() does
+ * uses the same heuristic, with the exact same
+ * vulnerability.
+ *
+ * That's why we disable this in "new API" mode.
+ * We keep it around in legacy mode for backwards
+ * compatibility.
*/
- if (device[0] != '\0' && device[1] == '\0') {
+ if (!pcap_new_api && device[0] != '\0' && device[1] == '\0') {
size_t length;
length = wcslen((wchar_t *)device);
device_str = (char *)malloc(length + 1);
if (device_str == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "malloc");
return (NULL);
}
- pcap_snprintf(device_str, length + 1, "%ws",
+ snprintf(device_str, length + 1, "%ws",
(const wchar_t *)device);
} else
#endif
device_str = strdup(device);
}
if (device_str == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
return (NULL);
}
* an activated pcap_t to point to a routine that returns
* a "this isn't activated" error.
*/
- p->read_op = (read_op_t)pcap_not_initialized;
- p->inject_op = (inject_op_t)pcap_not_initialized;
- p->setfilter_op = (setfilter_op_t)pcap_not_initialized;
- p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
- p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
- p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
- p->stats_op = (stats_op_t)pcap_not_initialized;
+ p->read_op = pcap_read_not_initialized;
+ p->inject_op = pcap_inject_not_initialized;
+ p->setfilter_op = pcap_setfilter_not_initialized;
+ p->setdirection_op = pcap_setdirection_not_initialized;
+ p->set_datalink_op = pcap_set_datalink_not_initialized;
+ p->getnonblock_op = pcap_getnonblock_not_initialized;
+ p->stats_op = pcap_stats_not_initialized;
#ifdef _WIN32
- p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
- p->setbuff_op = (setbuff_op_t)pcap_not_initialized;
- p->setmode_op = (setmode_op_t)pcap_not_initialized;
- p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized;
+ p->stats_ex_op = pcap_stats_ex_not_initialized;
+ p->setbuff_op = pcap_setbuff_not_initialized;
+ p->setmode_op = pcap_setmode_not_initialized;
+ p->setmintocopy_op = pcap_setmintocopy_not_initialized;
p->getevent_op = pcap_getevent_not_initialized;
- p->oid_get_request_op = (oid_get_request_op_t)pcap_not_initialized;
- p->oid_set_request_op = (oid_set_request_op_t)pcap_not_initialized;
+ p->oid_get_request_op = pcap_oid_get_request_not_initialized;
+ p->oid_set_request_op = pcap_oid_set_request_not_initialized;
p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized;
- p->setuserbuffer_op = (setuserbuffer_op_t)pcap_not_initialized;
- p->live_dump_op = (live_dump_op_t)pcap_not_initialized;
- p->live_dump_ended_op = (live_dump_ended_op_t)pcap_not_initialized;
+ p->setuserbuffer_op = pcap_setuserbuffer_not_initialized;
+ p->live_dump_op = pcap_live_dump_not_initialized;
+ p->live_dump_ended_op = pcap_live_dump_ended_not_initialized;
p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized;
#endif
* be used for pcap_next()/pcap_next_ex().
*/
p->oneshot_callback = pcap_oneshot;
+
+ /*
+ * Default breakloop operation - implementations can override
+ * this, but should call pcap_breakloop_common() before doing
+ * their own logic.
+ */
+ p->breakloop_op = pcap_breakloop_common;
}
static pcap_t *
-pcap_alloc_pcap_t(char *ebuf, size_t size)
+pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset)
{
char *chunk;
pcap_t *p;
/*
- * Allocate a chunk of memory big enough for a pcap_t
- * plus a structure following it of size "size". The
- * structure following it is a private data structure
- * for the routines that handle this pcap_t.
+ * total_size is the size of a structure containing a pcap_t
+ * followed by a private structure.
*/
- chunk = malloc(sizeof (pcap_t) + size);
+ chunk = calloc(total_size, 1);
if (chunk == NULL) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
return (NULL);
}
- memset(chunk, 0, sizeof (pcap_t) + size);
/*
* Get a pointer to the pcap_t at the beginning.
*/
p = (pcap_t *)chunk;
-#ifndef _WIN32
+#ifdef _WIN32
+ p->handle = INVALID_HANDLE_VALUE; /* not opened yet */
+#else /* _WIN32 */
p->fd = -1; /* not opened yet */
+#ifndef MSDOS
p->selectable_fd = -1;
-#endif
+ p->required_select_timeout = NULL;
+#endif /* MSDOS */
+#endif /* _WIN32 */
- if (size == 0) {
- /* No private data was requested. */
- p->priv = NULL;
- } else {
- /*
- * Set the pointer to the private data; that's the structure
- * of size "size" following the pcap_t.
- */
- p->priv = (void *)(chunk + sizeof (pcap_t));
- }
+ /*
+ * private_offset is the offset, in bytes, of the private
+ * data from the beginning of the structure.
+ *
+ * Set the pointer to the private data; that's private_offset
+ * bytes past the pcap_t.
+ */
+ p->priv = (void *)(chunk + private_offset);
return (p);
}
pcap_t *
-pcap_create_common(char *ebuf, size_t size)
+pcap_create_common(char *ebuf, size_t total_size, size_t private_offset)
{
pcap_t *p;
- p = pcap_alloc_pcap_t(ebuf, size);
+ p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
if (p == NULL)
return (NULL);
initialize_ops(p);
/* put in some defaults*/
- p->snapshot = MAXIMUM_SNAPLEN; /* max packet size */
+ p->snapshot = 0; /* max packet size unspecified */
p->opt.timeout = 0; /* no timeout specified */
p->opt.buffer_size = 0; /* use the platform's default */
p->opt.promisc = 0;
p->opt.immediate = 0;
p->opt.tstamp_type = -1; /* default to not setting time stamp type */
p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
+ /*
+ * Platform-dependent options.
+ */
+#ifdef __linux__
+ p->opt.protocol = 0;
+#endif
+#ifdef _WIN32
+ p->opt.nocapture_local = 0;
+#endif
/*
* Start out with no BPF code generation flags set.
pcap_check_activated(pcap_t *p)
{
if (p->activated) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
" operation on activated capture");
return (-1);
}
{
if (pcap_check_activated(p))
return (PCAP_ERROR_ACTIVATED);
-
- /*
- * Turn invalid values, or excessively large values, into
- * the maximum allowed value.
- *
- * If some application really *needs* a bigger snapshot
- * length, we should just increase MAXIMUM_SNAPLEN.
- */
- if (snaplen <= 0 || snaplen > MAXIMUM_SNAPLEN)
- snaplen = MAXIMUM_SNAPLEN;
p->snapshot = snaplen;
return (0);
}
* handle errors other than PCAP_ERROR, return the
* error message corresponding to the status.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
pcap_statustostr(status));
}
{
pcap_t *p;
int status;
-#ifdef HAVE_REMOTE
+#ifdef ENABLE_REMOTE
char host[PCAP_BUF_SIZE + 1];
char port[PCAP_BUF_SIZE + 1];
char name[PCAP_BUF_SIZE + 1];
int srctype;
+ /*
+ * A null device name is equivalent to the "any" device -
+ * which might not be supported on this platform, but
+ * this means that you'll get a "not supported" error
+ * rather than, say, a crash when we try to dereference
+ * the null pointer.
+ */
+ if (device == NULL)
+ device = "any";
+
/*
* Retrofit - we have to make older applications compatible with
* remote capture.
NULL, errbuf));
}
if (srctype == PCAP_SRC_FILE) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
return (NULL);
}
if (srctype == PCAP_SRC_IFLOCAL) {
device += strlen(PCAP_SRC_IF_STRING);
}
}
-#endif /* HAVE_REMOTE */
+#endif /* ENABLE_REMOTE */
p = pcap_create(device, errbuf);
if (p == NULL)
goto fail;
return (p);
fail:
- if (status == PCAP_ERROR)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
- p->errbuf);
- else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
+ if (status == PCAP_ERROR) {
+ /*
+ * Another buffer is a bit cumbersome, but it avoids
+ * -Wformat-truncation.
+ */
+ char trimbuf[PCAP_ERRBUF_SIZE - 5]; /* 2 bytes shorter */
+
+ pcap_strlcpy(trimbuf, p->errbuf, sizeof(trimbuf));
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
+ PCAP_ERRBUF_SIZE - 3, trimbuf);
+ } else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
status == PCAP_ERROR_PERM_DENIED ||
- status == PCAP_ERROR_PROMISC_PERM_DENIED)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", device,
- pcap_statustostr(status), p->errbuf);
- else
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
+ status == PCAP_ERROR_PROMISC_PERM_DENIED) {
+ /*
+ * Only show the additional message if it's not
+ * empty.
+ */
+ if (p->errbuf[0] != '\0') {
+ /*
+ * Idem.
+ */
+ char trimbuf[PCAP_ERRBUF_SIZE - 8]; /* 2 bytes shorter */
+
+ pcap_strlcpy(trimbuf, p->errbuf, sizeof(trimbuf));
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)",
+ device, pcap_statustostr(status),
+ PCAP_ERRBUF_SIZE - 6, trimbuf);
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+ device, pcap_statustostr(status));
+ }
+ } else {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
pcap_statustostr(status));
+ }
pcap_close(p);
return (NULL);
}
pcap_t *
-pcap_open_offline_common(char *ebuf, size_t size)
+pcap_open_offline_common(char *ebuf, size_t total_size, size_t private_offset)
{
pcap_t *p;
- p = pcap_alloc_pcap_t(ebuf, size);
+ p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
if (p == NULL)
return (NULL);
void
pcap_breakloop(pcap_t *p)
{
- p->break_loop = 1;
+ p->breakloop_op(p);
}
int
*/
*dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
if (*dlt_buffer == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
return (PCAP_ERROR);
}
**dlt_buffer = p->linktype;
} else {
*dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
if (*dlt_buffer == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "malloc: %s", pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "malloc");
return (PCAP_ERROR);
}
(void)memcpy(*dlt_buffer, p->dlt_list,
unsupported:
dlt_name = pcap_datalink_val_to_name(dlt);
if (dlt_name != NULL) {
- (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ (void) snprintf(p->errbuf, sizeof(p->errbuf),
"%s is not one of the DLTs supported by this device",
dlt_name);
} else {
- (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ (void) snprintf(p->errbuf, sizeof(p->errbuf),
"DLT %d is not one of the DLTs supported by this device",
dlt);
}
DLT_CHOICE(RAW, "Raw IP"),
DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"),
DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"),
- DLT_CHOICE(ATM_CLIP, "Linux Classical IP-over-ATM"),
+ DLT_CHOICE(ATM_CLIP, "Linux Classical IP over ATM"),
DLT_CHOICE(PPP_SERIAL, "PPP over serial"),
DLT_CHOICE(PPP_ETHER, "PPPoE"),
DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"),
DLT_CHOICE(FRELAY, "Frame Relay"),
DLT_CHOICE(LOOP, "OpenBSD loopback"),
DLT_CHOICE(ENC, "OpenBSD encapsulated IP"),
- DLT_CHOICE(LINUX_SLL, "Linux cooked"),
+ DLT_CHOICE(LINUX_SLL, "Linux cooked v1"),
DLT_CHOICE(LTALK, "Localtalk"),
DLT_CHOICE(PFLOG, "OpenBSD pflog file"),
DLT_CHOICE(PFSYNC, "Packet filter state syncing"),
DLT_CHOICE(GPF_T, "GPF-T"),
DLT_CHOICE(GPF_F, "GPF-F"),
DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"),
- DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"),
+ DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"),
DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"),
DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"),
DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"),
DLT_CHOICE(SITA, "SITA pseudo-header"),
DLT_CHOICE(ERF, "Endace ERF header"),
DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"),
- DLT_CHOICE(IPMB, "IPMB"),
+ DLT_CHOICE(IPMB_KONTRON, "IPMB with Kontron pseudo-header"),
DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"),
DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"),
DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"),
+ DLT_CHOICE(IPMB_LINUX, "IPMB with Linux/Pigeon Point pseudo-header"),
DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"),
DLT_CHOICE(MPLS, "MPLS with label as link-layer header"),
DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"),
DLT_CHOICE(OPENFLOW, "OpenBSD DLT_OPENFLOW"),
DLT_CHOICE(SDLC, "IBM SDLC frames"),
DLT_CHOICE(TI_LLN_SNIFFER, "TI LLN sniffer frames"),
+ DLT_CHOICE(VSOCK, "Linux vsock"),
+ DLT_CHOICE(NORDIC_BLE, "Nordic Semiconductor Bluetooth LE sniffer frames"),
+ DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"),
+ DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
+ DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
+ DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
+ DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"),
+ DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"),
+ DLT_CHOICE(VPP_DISPATCH, "VPP graph dispatch tracer"),
+ DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"),
+ DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"),
+ DLT_CHOICE(IEEE802_15_4_TAP, "IEEE 802.15.4 with pseudo-header"),
+ DLT_CHOICE(DSA_TAG_DSA, "Marvell DSA"),
+ DLT_CHOICE(DSA_TAG_EDSA, "Marvell EDSA"),
+ DLT_CHOICE(ELEE, "ELEE lawful intercept packets"),
+ DLT_CHOICE(Z_WAVE_SERIAL, "Z-Wave serial frames between host and chip"),
+ DLT_CHOICE(USB_2_0, "USB 2.0/1.1/1.0 as transmitted over the cable"),
+ DLT_CHOICE(ATSC_ALP, "ATSC Link-Layer Protocol packets"),
DLT_CHOICE_SENTINEL
};
return (NULL);
}
+const char *
+pcap_datalink_val_to_description_or_dlt(int dlt)
+{
+ static char unkbuf[40];
+ const char *description;
+
+ description = pcap_datalink_val_to_description(dlt);
+ if (description != NULL) {
+ return description;
+ } else {
+ (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %d", dlt);
+ return unkbuf;
+ }
+}
+
struct tstamp_type_choice {
const char *name;
const char *description;
{ "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC },
{ "adapter", "Adapter", PCAP_TSTAMP_ADAPTER },
{ "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED },
+ { "host_hiprec_unsynced", "Host, high precision, not synced with system time", PCAP_TSTAMP_HOST_HIPREC_UNSYNCED },
{ NULL, NULL, 0 }
};
return (p->rfile);
}
+#ifdef _WIN32
int
pcap_fileno(pcap_t *p)
{
-#ifndef _WIN32
- return (p->fd);
-#else
- if (p->adapter != NULL)
- return ((int)(DWORD)p->adapter->hFile);
- else
+ if (p->handle != INVALID_HANDLE_VALUE) {
+ /*
+ * This is a bogus and now-deprecated API; we
+ * squelch the narrowing warning for the cast
+ * from HANDLE to intptr_t. If Windows programmmers
+ * need to get at the HANDLE for a pcap_t, *if*
+ * there is one, they should request such a
+ * routine (and be prepared for it to return
+ * INVALID_HANDLE_VALUE).
+ */
+DIAG_OFF_NARROWING
+ return ((int)(intptr_t)p->handle);
+DIAG_ON_NARROWING
+ } else
return (PCAP_ERROR);
-#endif
}
+#else /* _WIN32 */
+int
+pcap_fileno(pcap_t *p)
+{
+ return (p->fd);
+}
+#endif /* _WIN32 */
#if !defined(_WIN32) && !defined(MSDOS)
int
{
return (p->selectable_fd);
}
+
+const struct timeval *
+pcap_get_required_select_timeout(pcap_t *p)
+{
+ return (p->required_select_timeout);
+}
#endif
void
* We copy the error message to errbuf, so callers
* can find it in either place.
*/
- strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+ pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
}
return (ret);
}
fdflags = fcntl(p->fd, F_GETFL, 0);
if (fdflags == -1) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_GETFL");
return (-1);
}
if (fdflags & O_NONBLOCK)
* We copy the error message to errbuf, so callers
* can find it in either place.
*/
- strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+ pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
}
return (ret);
}
fdflags = fcntl(p->fd, F_GETFL, 0);
if (fdflags == -1) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_GETFL");
return (-1);
}
if (nonblock)
else
fdflags &= ~O_NONBLOCK;
if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
- pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "F_SETFL");
return (-1);
}
return (0);
}
#endif
-#ifdef _WIN32
-/*
- * Generate a string for a Win32-specific error (i.e. an error generated when
- * calling a Win32 API).
- * For errors occurred during standard C calls, we still use pcap_strerror()
- */
-void
-pcap_win32_err_to_str(DWORD error, char *errbuf)
-{
- size_t errlen;
- char *p;
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
- PCAP_ERRBUF_SIZE, NULL);
-
- /*
- * "FormatMessage()" "helpfully" sticks CR/LF at the end of the
- * message. Get rid of it.
- */
- errlen = strlen(errbuf);
- if (errlen >= 2) {
- errbuf[errlen - 1] = '\0';
- errbuf[errlen - 2] = '\0';
- }
- p = strchr(errbuf, '\0');
- pcap_snprintf (p, PCAP_ERRBUF_SIZE+1-(p-errbuf), " (%lu)", error);
-}
-#endif
-
/*
* Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values.
*/
return ("That operation is supported only in monitor mode");
case PCAP_ERROR_PERM_DENIED:
- return ("You don't have permission to capture on that device");
+ return ("You don't have permission to perform this capture on that device");
case PCAP_ERROR_IFACE_NOT_UP:
return ("That device is not up");
case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP:
return ("That device doesn't support that time stamp precision");
}
- (void)pcap_snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
+ (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
return(ebuf);
}
errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
if (err != 0) /* err = 0 if successful */
- strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
+ pcap_strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE);
return (errbuf);
#else
return (strerror(errnum));
if ((unsigned int)errnum < sys_nerr)
return ((char *)sys_errlist[errnum]);
- (void)pcap_snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
+ (void)snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
return (errbuf);
#endif
}
pcap_setdirection(pcap_t *p, pcap_direction_t d)
{
if (p->setdirection_op == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Setting direction is not implemented on this platform");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Setting direction is not supported on this device");
return (-1);
- } else
- return (p->setdirection_op(p, d));
+ } else {
+ switch (d) {
+
+ case PCAP_D_IN:
+ case PCAP_D_OUT:
+ case PCAP_D_INOUT:
+ /*
+ * Valid direction.
+ */
+ return (p->setdirection_op(p, d));
+
+ default:
+ /*
+ * Invalid direction.
+ */
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "Invalid direction");
+ return (-1);
+ }
+ }
}
int
return (p->stats_op(p, ps));
}
-static int
-pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Statistics aren't available from a pcap_open_dead pcap_t");
- return (-1);
-}
-
#ifdef _WIN32
struct pcap_stat *
pcap_stats_ex(pcap_t *p, int *pcap_stat_size)
return (p->setbuff_op(p, dim));
}
-static int
-pcap_setbuff_dead(pcap_t *p, int dim)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_setmode(pcap_t *p, int mode)
{
return (p->setmode_op(p, mode));
}
-static int
-pcap_setmode_dead(pcap_t *p, int mode)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "impossible to set mode on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_setmintocopy(pcap_t *p, int size)
{
return (p->setmintocopy_op(p, size));
}
-static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
- return (-1);
-}
-
HANDLE
pcap_getevent(pcap_t *p)
{
return (p->getevent_op(p));
}
-static HANDLE
-pcap_getevent_dead(pcap_t *p)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "A pcap_open_dead pcap_t has no event handle");
- return (INVALID_HANDLE_VALUE);
-}
-
int
pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp)
{
return (p->oid_get_request_op(p, oid, data, lenp));
}
-static int
-pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
- size_t *lenp _U_)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "An OID get request cannot be performed on a pcap_open_dead pcap_t");
- return (PCAP_ERROR);
-}
-
int
pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp)
{
return (p->oid_set_request_op(p, oid, data, lenp));
}
-static int
-pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
- size_t *lenp _U_)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "An OID set request cannot be performed on a pcap_open_dead pcap_t");
- return (PCAP_ERROR);
-}
-
pcap_send_queue *
pcap_sendqueue_alloc(u_int memsize)
{
return (p->sendqueue_transmit_op(p, queue, sync));
}
-static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Packets cannot be transmitted on a pcap_open_dead pcap_t");
- return (0);
-}
-
int
pcap_setuserbuffer(pcap_t *p, int size)
{
return (p->setuserbuffer_op(p, size));
}
-static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The user buffer cannot be set on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
{
return (p->live_dump_op(p, filename, maxsize, maxpacks));
}
-static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
- return (-1);
-}
-
int
pcap_live_dump_ended(pcap_t *p, int sync)
{
return (p->live_dump_ended_op(p, sync));
}
-static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
-{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
- return (-1);
-}
-
PAirpcapHandle
pcap_get_airpcap_handle(pcap_t *p)
{
handle = p->get_airpcap_handle_op(p);
if (handle == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ (void)snprintf(p->errbuf, sizeof(p->errbuf),
"This isn't an AirPcap device");
}
return (handle);
}
-
-static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
-{
- return (NULL);
-}
#endif
/*
{
struct pcap *handle;
- while ((handle = pcaps_to_close) != NULL)
+ while ((handle = pcaps_to_close) != NULL) {
pcap_close(handle);
+
+ /*
+ * If a pcap module adds a pcap_t to the "close all"
+ * list by calling pcap_add_to_pcaps_to_close(), it
+ * must have a cleanup routine that removes it from the
+ * list, by calling pcap_remove_from_pcaps_to_close(),
+ * and must make that cleanup routine the cleanup_op
+ * for the pcap_t.
+ *
+ * That means that, after pcap_close() - which calls
+ * the cleanup_op for the pcap_t - the pcap_t must
+ * have been removed from the list, so pcaps_to_close
+ * must not be equal to handle.
+ *
+ * We check for that, and abort if handle is still
+ * at the head of the list, to prevent infinite loops.
+ */
+ if (pcaps_to_close == handle)
+ abort();
+ }
}
int
/*
* "atexit()" failed; let our caller know.
*/
- strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE);
+ pcap_strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE);
return (0);
}
did_atexit = 1;
}
}
+void
+pcap_breakloop_common(pcap_t *p)
+{
+ p->break_loop = 1;
+}
+
+
void
pcap_cleanup_live_common(pcap_t *p)
{
+ if (p->opt.device != NULL) {
+ free(p->opt.device);
+ p->opt.device = NULL;
+ }
if (p->buffer != NULL) {
free(p->buffer);
p->buffer = NULL;
#if !defined(_WIN32) && !defined(MSDOS)
if (p->fd >= 0) {
close(p->fd);
- p->fd = -1;
- }
- p->selectable_fd = -1;
-#endif
-}
-
-static void
-pcap_cleanup_dead(pcap_t *p _U_)
-{
- /* Nothing to do. */
-}
-
-pcap_t *
-pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
-{
- pcap_t *p;
-
- switch (precision) {
-
- case PCAP_TSTAMP_PRECISION_MICRO:
- case PCAP_TSTAMP_PRECISION_NANO:
- break;
-
- default:
- return NULL;
- }
- p = malloc(sizeof(*p));
- if (p == NULL)
- return NULL;
- memset (p, 0, sizeof(*p));
- p->snapshot = snaplen;
- p->linktype = linktype;
- p->opt.tstamp_precision = precision;
- p->stats_op = pcap_stats_dead;
-#ifdef _WIN32
- p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
- p->setbuff_op = pcap_setbuff_dead;
- p->setmode_op = pcap_setmode_dead;
- p->setmintocopy_op = pcap_setmintocopy_dead;
- p->getevent_op = pcap_getevent_dead;
- p->oid_get_request_op = pcap_oid_get_request_dead;
- p->oid_set_request_op = pcap_oid_set_request_dead;
- p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
- p->setuserbuffer_op = pcap_setuserbuffer_dead;
- p->live_dump_op = pcap_live_dump_dead;
- p->live_dump_ended_op = pcap_live_dump_ended_dead;
- p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
-#endif
- p->cleanup_op = pcap_cleanup_dead;
-
- /*
- * A "dead" pcap_t never requires special BPF code generation.
- */
- p->bpf_codegen_flags = 0;
-
- p->activated = 1;
- return (p);
-}
-
-pcap_t *
-pcap_open_dead(int linktype, int snaplen)
-{
- return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
- PCAP_TSTAMP_PRECISION_MICRO));
+ p->fd = -1;
+ }
+ p->selectable_fd = -1;
+#endif
}
/*
int
pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
{
+ if (size <= 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The number of bytes to be sent must be positive");
+ return (PCAP_ERROR);
+ }
+
if (p->inject_op(p, buf, size) == -1)
return (-1);
return (0);
int
pcap_inject(pcap_t *p, const void *buf, size_t size)
{
- return (p->inject_op(p, buf, size));
+ /*
+ * We return the number of bytes written, so the number of
+ * bytes to write must fit in an int.
+ */
+ if (size > INT_MAX) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "More than %d bytes cannot be injected", INT_MAX);
+ return (PCAP_ERROR);
+ }
+
+ if (size == 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The number of bytes to be injected must not be zero");
+ return (PCAP_ERROR);
+ }
+
+ return (p->inject_op(p, buf, (int)size));
}
void
pcap_close(pcap_t *p)
{
- if (p->opt.device != NULL)
- free(p->opt.device);
p->cleanup_op(p);
free(p);
}
+/*
+ * Helpers for safely loading code at run time.
+ * Currently Windows-only.
+ */
+#ifdef _WIN32
+//
+// This wrapper around loadlibrary appends the system folder (usually
+// C:\Windows\System32) to the relative path of the DLL, so that the DLL
+// is always loaded from an absolute path (it's no longer possible to
+// load modules from the application folder).
+// This solves the DLL Hijacking issue discovered in August 2010:
+//
+// https://blog.rapid7.com/2010/08/23/exploiting-dll-hijacking-flaws/
+// https://blog.rapid7.com/2010/08/23/application-dll-load-hijacking/
+// (the purported Rapid7 blog post link in the first of those two links
+// is broken; the second of those links works.)
+//
+// If any links there are broken from all the content shuffling Rapid&
+// did, see archived versions of the posts at their original homes, at
+//
+// https://web.archive.org/web/20110122175058/http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
+// https://web.archive.org/web/20100828112111/http://blog.rapid7.com/?p=5325
+//
+pcap_code_handle_t
+pcap_load_code(const char *name)
+{
+ /*
+ * XXX - should this work in UTF-16LE rather than in the local
+ * ANSI code page?
+ */
+ CHAR path[MAX_PATH];
+ CHAR fullFileName[MAX_PATH];
+ UINT res;
+ HMODULE hModule = NULL;
+
+ do
+ {
+ res = GetSystemDirectoryA(path, MAX_PATH);
+
+ if (res == 0) {
+ //
+ // some bad failure occurred;
+ //
+ break;
+ }
+
+ if (res > MAX_PATH) {
+ //
+ // the buffer was not big enough
+ //
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ break;
+ }
+
+ if (res + 1 + strlen(name) + 1 < MAX_PATH) {
+ memcpy(fullFileName, path, res * sizeof(TCHAR));
+ fullFileName[res] = '\\';
+ memcpy(&fullFileName[res + 1], name, (strlen(name) + 1) * sizeof(TCHAR));
+
+ hModule = LoadLibraryA(fullFileName);
+ } else
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+
+ } while(FALSE);
+
+ return hModule;
+}
+
+pcap_funcptr_t
+pcap_find_function(pcap_code_handle_t code, const char *func)
+{
+ return (GetProcAddress(code, func));
+}
+#endif
+
/*
* Given a BPF program, a pcap_pkthdr structure for a packet, and the raw
* data for the packet, check whether the packet passes the filter.
const struct bpf_insn *fcode = fp->bf_insns;
if (fcode != NULL)
- return (bpf_filter(fcode, pkt, h->len, h->caplen));
+ return (pcap_filter(fcode, pkt, h->len, h->caplen));
else
return (0);
}
-#include "pcap_version.h"
+static int
+pcap_can_set_rfmon_dead(pcap_t *p)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
+
+static int
+pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
+ u_char *user _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets aren't available from a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static void
+pcap_breakloop_dead(pcap_t *p _U_)
+{
+ /*
+ * A "dead" pcap_t is just a placeholder to use in order to
+ * compile a filter to BPF code or to open a savefile for
+ * writing. It doesn't support any operations, including
+ * capturing or reading packets, so there will never be a
+ * get-packets loop in progress to break out *of*.
+ *
+ * As such, this routine doesn't need to do anything.
+ */
+}
+
+static int
+pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets can't be sent on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A filter cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The packet direction cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
+
+static int
+pcap_getnonblock_dead(pcap_t *p)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+ return (-1);
+}
+
+static int
+pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+ return (-1);
+}
-static const char *pcap_lib_version_string;
+static int
+pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from a pcap_open_dead pcap_t");
+ return (-1);
+}
#ifdef _WIN32
+static struct pcap_stat *
+pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Statistics aren't available from a pcap_open_dead pcap_t");
+ return (NULL);
+}
-#ifdef HAVE_VERSION_H
-/*
- * libpcap being built for Windows, as part of a WinPcap/Npcap source
- * tree. Include version.h from that source tree to get the WinPcap/Npcap
- * version.
- *
- * XXX - it'd be nice if we could somehow generate the WinPcap version number
- * when building WinPcap. (It'd be nice to do so for the packet.dll version
- * number as well.)
- */
-#include "../../version.h"
+static int
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
-static const char wpcap_version_string[] = WINPCAP_VER_STRING;
-static const char pcap_version_string_fmt[] =
- WINPCAP_PRODUCT_NAME " version %s, based on %s";
-static const char pcap_version_string_packet_dll_fmt[] =
- WINPCAP_PRODUCT_NAME " version %s (packet.dll version %s), based on %s";
+static int
+pcap_setmode_dead(pcap_t *p, int mode _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "impossible to set mode on a pcap_open_dead pcap_t");
+ return (-1);
+}
-const char *
-pcap_lib_version(void)
+static int
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
{
- char *packet_version_string;
- size_t full_pcap_version_string_len;
- char *full_pcap_version_string;
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
- if (pcap_lib_version_string == NULL) {
- /*
- * Generate the version string.
- */
- packet_version_string = PacketGetVersion();
- if (strcmp(wpcap_version_string, packet_version_string) == 0) {
- /*
- * WinPcap version string and packet.dll version
- * string are the same; just report the WinPcap
- * version.
- */
- full_pcap_version_string_len =
- (sizeof pcap_version_string_fmt - 4) +
- strlen(wpcap_version_string) +
- strlen(pcap_version_string);
- full_pcap_version_string =
- malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- pcap_version_string_fmt,
- wpcap_version_string,
- pcap_version_string);
- } else {
- /*
- * WinPcap version string and packet.dll version
- * string are different; that shouldn't be the
- * case (the two libraries should come from the
- * same version of WinPcap), so we report both
- * versions.
- */
- full_pcap_version_string_len =
- (sizeof pcap_version_string_packet_dll_fmt - 6) +
- strlen(wpcap_version_string) +
- strlen(packet_version_string) +
- strlen(pcap_version_string);
- full_pcap_version_string = malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- pcap_version_string_packet_dll_fmt,
- wpcap_version_string,
- packet_version_string,
- pcap_version_string);
- }
- pcap_lib_version_string = full_pcap_version_string;
- }
- return (pcap_lib_version_string);
+static HANDLE
+pcap_getevent_dead(pcap_t *p)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "A pcap_open_dead pcap_t has no event handle");
+ return (INVALID_HANDLE_VALUE);
}
-#else /* HAVE_VERSION_H */
+static int
+pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+ size_t *lenp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID get request cannot be performed on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
-/*
- * libpcap being built for Windows, not as part of a WinPcap/Npcap source
- * tree.
- */
-static const char pcap_version_string_packet_dll_fmt[] =
- "%s (packet.dll version %s)";
-const char *
-pcap_lib_version(void)
+static int
+pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+ size_t *lenp _U_)
{
- char *packet_version_string;
- size_t full_pcap_version_string_len;
- char *full_pcap_version_string;
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "An OID set request cannot be performed on a pcap_open_dead pcap_t");
+ return (PCAP_ERROR);
+}
- if (pcap_lib_version_string == NULL) {
- /*
- * Generate the version string. Report the packet.dll
- * version.
- */
- packet_version_string = PacketGetVersion();
- full_pcap_version_string_len =
- (sizeof pcap_version_string_packet_dll_fmt - 4) +
- strlen(pcap_version_string) +
- strlen(packet_version_string);
- full_pcap_version_string = malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- pcap_version_string_packet_dll_fmt,
- pcap_version_string,
- packet_version_string);
- pcap_lib_version_string = full_pcap_version_string;
- }
- return (pcap_lib_version_string);
+static u_int
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+ int sync _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Packets cannot be transmitted on a pcap_open_dead pcap_t");
+ return (0);
}
-#endif /* HAVE_VERSION_H */
+static int
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The user buffer cannot be set on a pcap_open_dead pcap_t");
+ return (-1);
+}
-#elif defined(MSDOS)
+static int
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+ return (-1);
+}
-const char *
-pcap_lib_version(void)
+static int
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
{
- char *packet_version_string;
- size_t full_pcap_version_string_len;
- char *full_pcap_version_string;
- static char dospfx[] = "DOS-";
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+ return (-1);
+}
- if (pcap_lib_version_string == NULL) {
- /*
- * Generate the version string.
- */
- full_pcap_version_string_len =
- sizeof dospfx + strlen(pcap_version_string);
- full_pcap_version_string =
- malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- strcpy(full_pcap_version_string, dospfx);
- strcat(full_pcap_version_string, pcap_version_string);
- pcap_lib_version_string = full_pcap_version_string;
- }
- return (pcap_lib_version_string);
+static PAirpcapHandle
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
+{
+ return (NULL);
}
+#endif /* _WIN32 */
-#else /* UN*X */
+static void
+pcap_cleanup_dead(pcap_t *p _U_)
+{
+ /* Nothing to do. */
+}
-const char *
-pcap_lib_version(void)
+pcap_t *
+pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
{
- const char *platform_version_string;
- size_t full_pcap_version_string_len;
- char *full_pcap_version_string;
+ pcap_t *p;
+
+ switch (precision) {
+
+ case PCAP_TSTAMP_PRECISION_MICRO:
+ case PCAP_TSTAMP_PRECISION_NANO:
+ break;
- if (pcap_lib_version_string == NULL) {
+ default:
/*
- * Generate the version string.
- * Get any platform-specific information.
- *
- * XXX - what about all the local capture modules other
- * that the "native interface" one? That could make
- * the version string really long.
+ * This doesn't really matter, but we don't have any way
+ * to report particular errors, so the only failure we
+ * should have is a memory allocation failure. Just
+ * pick microsecond precision.
*/
- platform_version_string = pcap_platform_lib_version();
- if (platform_version_string == NULL) {
- /*
- * No platform-specific information.
- */
- pcap_lib_version_string = pcap_version_string;
- } else {
- /*
- * Add on the platform-specific information.
- */
- full_pcap_version_string_len =
- strlen(pcap_version_string) + 2 + strlen(platform_version_string) + 1 + 1;
- full_pcap_version_string =
- malloc(full_pcap_version_string_len);
- if (full_pcap_version_string == NULL)
- return (NULL);
- pcap_snprintf(full_pcap_version_string,
- full_pcap_version_string_len,
- "%s (%s)", pcap_version_string,
- platform_version_string);
- pcap_lib_version_string = full_pcap_version_string;
- }
+ precision = PCAP_TSTAMP_PRECISION_MICRO;
+ break;
}
- return (pcap_lib_version_string);
-}
+ p = malloc(sizeof(*p));
+ if (p == NULL)
+ return NULL;
+ memset (p, 0, sizeof(*p));
+ p->snapshot = snaplen;
+ p->linktype = linktype;
+ p->opt.tstamp_precision = precision;
+ p->can_set_rfmon_op = pcap_can_set_rfmon_dead;
+ p->read_op = pcap_read_dead;
+ p->inject_op = pcap_inject_dead;
+ p->setfilter_op = pcap_setfilter_dead;
+ p->setdirection_op = pcap_setdirection_dead;
+ p->set_datalink_op = pcap_set_datalink_dead;
+ p->getnonblock_op = pcap_getnonblock_dead;
+ p->setnonblock_op = pcap_setnonblock_dead;
+ p->stats_op = pcap_stats_dead;
+#ifdef _WIN32
+ p->stats_ex_op = pcap_stats_ex_dead;
+ p->setbuff_op = pcap_setbuff_dead;
+ p->setmode_op = pcap_setmode_dead;
+ p->setmintocopy_op = pcap_setmintocopy_dead;
+ p->getevent_op = pcap_getevent_dead;
+ p->oid_get_request_op = pcap_oid_get_request_dead;
+ p->oid_set_request_op = pcap_oid_set_request_dead;
+ p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead;
+ p->setuserbuffer_op = pcap_setuserbuffer_dead;
+ p->live_dump_op = pcap_live_dump_dead;
+ p->live_dump_ended_op = pcap_live_dump_ended_dead;
+ p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead;
#endif
+ p->breakloop_op = pcap_breakloop_dead;
+ p->cleanup_op = pcap_cleanup_dead;
+
+ /*
+ * A "dead" pcap_t never requires special BPF code generation.
+ */
+ p->bpf_codegen_flags = 0;
+
+ p->activated = 1;
+ return (p);
+}
+
+pcap_t *
+pcap_open_dead(int linktype, int snaplen)
+{
+ return (pcap_open_dead_with_tstamp_precision(linktype, snaplen,
+ PCAP_TSTAMP_PRECISION_MICRO));
+}
#ifdef YYDEBUG
/*
PCAP_API_DEF void
pcap_set_parser_debug(int value)
{
- extern int pcap_debug;
-
pcap_debug = value;
}
#endif
-
-#ifdef BDEBUG
-/*
- * Set the internal "debug printout" flag for the filter expression optimizer.
- * The code to print that stuff is present only if BDEBUG is defined, so
- * the flag, and the routine to set it, are defined only if BDEBUG is
- * defined.
- *
- * This is intended for libpcap developers, not for general use.
- * If you want to set these in a program, you'll have to declare this
- * routine yourself, with the appropriate DLL import attribute on Windows;
- * it's not declared in any header file, and won't be declared in any
- * header file provided by libpcap.
- */
-PCAP_API void pcap_set_optimizer_debug(int value);
-
-PCAP_API_DEF void
-pcap_set_optimizer_debug(int value)
-{
- extern int pcap_optimizer_debug;
-
- pcap_optimizer_debug = value;
-}
-#endif