#include <netinet/in.h>
#endif /* _WIN32 */
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
+#include "diag-control.h"
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
#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-dpdk.h"
#endif
+#ifdef HAVE_AIRPCAP_API
+#include "pcap-airpcap.h"
+#endif
+
#ifdef _WIN32
/*
- * DllMain(), required when built as a Windows DLL.
+ * 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.)
*/
-BOOL WINAPI DllMain(
- HANDLE hinstDLL,
- DWORD dwReason,
- LPVOID lpvReserved
-)
-{
- return (TRUE);
-}
/*
- * Start WinSock.
- * Exported in case some applications using WinPcap called it,
- * even though it wasn't exported.
+ * Start Winsock.
+ * Internal routine.
*/
-int
-wsockinit(void)
+static int
+internal_wsockinit(char *errbuf)
{
WORD wVersionRequested;
WSADATA wsaData;
static int err = -1;
static int done = 0;
+ int status;
if (done)
return (err);
- wVersionRequested = MAKEWORD( 1, 1);
- err = WSAStartup( wVersionRequested, &wsaData );
- atexit ((void(*)(void))WSACleanup);
+ /*
+ * 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 ( err != 0 )
- err = -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 (wsockinit());
+ 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
{
if (pcap->activated) {
/* A module probably forgot to set the function pointer */
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ (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");
}
}
#ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
{
pcap_set_not_initialized_message(pcap);
}
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_)
{
pcap_set_not_initialized_message(pcap);
return (0);
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);
}
(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
#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))
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);
}
* 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
static char device[IF_NAMESIZE + 1];
char *ret;
+ /*
+ * 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);
#ifdef PCAP_SUPPORT_BT
|| strstr(device, "bluetooth") != NULL
#endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
|| strstr(device, "usbmon") != NULL
#endif
#ifdef HAVE_SNF_API
(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
if (errno == EADDRNOTAVAIL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"%s: no IPv4 address assigned", device);
} else {
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
else if (IN_CLASSC(*netp))
*maskp = IN_CLASSC_NET;
else {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"inet class for 0x%x unknown", *netp);
return (-1);
}
/*
* There's no closing square bracket.
*/
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"IP-literal in URL doesn't end with ]");
free(userinfo);
free(authority);
* There's extra crud after the
* closing square bracketn.
*/
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"Extra text after IP-literal in URL");
free(userinfo);
free(authority);
pcap_strlcat(source, name, PCAP_BUF_SIZE);
return (0);
} else {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The file name cannot be NULL.");
return (-1);
}
pcap_strlcat(source, "/", PCAP_BUF_SIZE);
} else {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The host name cannot be NULL.");
return (-1);
}
return (0);
default:
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The interface type is not valid.");
return (-1);
}
*/
if (host && tmphost) {
if (tmpuserinfo)
- pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+ snprintf(host, PCAP_BUF_SIZE, "%s@%s",
tmpuserinfo, tmphost);
else
pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
* 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 strinh and, if
+ * looks as if it might be a UTF-16LE string and, if
* so, convert it back to the local code page's
* extended ASCII.
*
- * XXX - 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. This particular
- * version of this heuristic dates back to WinPcap
- * 4.1.1; PacketOpenAdapter() does uses the same
- * heuristic, with the exact same vulnerability.
+ * 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);
return (NULL);
}
- pcap_snprintf(device_str, length + 1, "%ws",
+ snprintf(device_str, length + 1, "%ws",
(const wchar_t *)device);
} else
#endif
}
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.
- *
- * The structure following it must be aligned on
- * the appropriate alignment boundary for this platform.
- * We align on an 8-byte boundary as that's probably what
- * at least some platforms do, even with 32-bit integers,
- * and because we can't be sure that some values won't
- * require 8-byte alignment even on platforms with 32-bit
- * integers.
+ * total_size is the size of a structure containing a pcap_t
+ * followed by a private structure.
*/
-#define PCAP_T_ALIGNED_SIZE ((sizeof(pcap_t) + 7) & ~0x7)
- chunk = malloc(PCAP_T_ALIGNED_SIZE + size);
+ chunk = calloc(total_size, 1);
if (chunk == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
errno, "malloc");
return (NULL);
}
- memset(chunk, 0, PCAP_T_ALIGNED_SIZE + size);
/*
* Get a pointer to the pcap_t at the beginning.
#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 + PCAP_T_ALIGNED_SIZE);
- }
+ /*
+ * 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);
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);
}
* 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));
}
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) {
goto fail;
return (p);
fail:
- if (status == PCAP_ERROR)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
- PCAP_ERRBUF_SIZE - 3, 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), PCAP_ERRBUF_SIZE - 6, 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);
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(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
};
if (description != NULL) {
return description;
} else {
- (void)pcap_snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
+ (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %d", dlt);
return unkbuf;
}
}
{ "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->handle != INVALID_HANDLE_VALUE)
- return ((int)(DWORD)p->handle);
- 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);
}
-struct timeval *
+const struct timeval *
pcap_get_required_select_timeout(pcap_t *p)
{
return (p->required_select_timeout);
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);
}
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
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);
{
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
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;
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.
static int
pcap_can_set_rfmon_dead(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
return (PCAP_ERROR);
}
pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
u_char *user _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ 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_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packets can't be sent on a pcap_open_dead pcap_t");
return (-1);
}
static int
pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A filter cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The packet direction cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The link-layer header type cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
pcap_getnonblock_dead(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A pcap_open_dead pcap_t does not have a non-blocking mode setting");
return (-1);
}
static int
pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A pcap_open_dead pcap_t does not have a non-blocking mode setting");
return (-1);
}
static int
pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from a pcap_open_dead pcap_t");
return (-1);
}
#ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from a pcap_open_dead pcap_t");
return (NULL);
}
static int
-pcap_setbuff_dead(pcap_t *p, int dim)
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_setmode_dead(pcap_t *p, int mode)
+pcap_setmode_dead(pcap_t *p, int mode _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"impossible to set mode on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static HANDLE
pcap_getevent_dead(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A pcap_open_dead pcap_t has no event handle");
return (INVALID_HANDLE_VALUE);
}
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,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID get request cannot be performed on a pcap_open_dead pcap_t");
return (PCAP_ERROR);
}
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,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID set request cannot be performed on a pcap_open_dead pcap_t");
return (PCAP_ERROR);
}
static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+ int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packets cannot be transmitted on a pcap_open_dead pcap_t");
return (0);
}
static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The user buffer cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
return (-1);
}
static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
{
return (NULL);
}
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;
/*