#endif
#include <errno.h>
+#include <limits.h> /* for INT_MAX */
#define PCAP_DONT_INCLUDE_PCAP_BPF_H
#include <Packet32.h>
#include <pcap-int.h>
return (0);
}
+#ifdef HAVE_NPCAP_PACKET_API
+/*
+ * Kernel dump mode isn't supported in Npcap; calls to PacketSetDumpName(),
+ * PacketSetDumpLimits(), and PacketIsDumpEnded() will get compile-time
+ * deprecation warnings.
+ *
+ * Avoid calling them; just return errors indicating that kernel dump
+ * mode isn't supported in Npcap.
+ */
+static int
+pcap_live_dump_npf(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Npcap doesn't support kernel dump mode");
+ return (-1);
+}
+static int
+pcap_live_dump_ended_npf(pcap_t *p, int sync)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Npcap doesn't support kernel dump mode");
+ return (-1);
+}
+#else /* HAVE_NPCAP_PACKET_API */
static int
pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks)
{
return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync));
}
+#endif /* HAVE_NPCAP_PACKET_API */
#ifdef HAVE_AIRPCAP_API
static PAirpcapHandle
/*
* Loop through each packet.
+ *
+ * This assumes that a single buffer of packets will have
+ * <= INT_MAX packets, so the packet count doesn't overflow.
*/
#define bhp ((struct bpf_hdr *)bp)
n = 0;
endofbuf = (char*)header + cc;
+ /*
+ * This can conceivably process more than INT_MAX packets,
+ * which would overflow the packet count, causing it either
+ * to look like a negative number, and thus cause us to
+ * return a value that looks like an error, or overflow
+ * back into positive territory, and thus cause us to
+ * return a too-low count.
+ *
+ * Therefore, if the packet count is unlimited, we clip
+ * it at INT_MAX; this routine is not expected to
+ * process packets indefinitely, so that's not an issue.
+ */
+ if (PACKET_COUNT_IS_UNLIMITED(cnt))
+ cnt = INT_MAX;
+
/*
* Cycle through the packets
*/
}
}
- /* No underlaying filtering system. We need to filter on our own */
+ /* No underlying filtering system. We need to filter on our own */
if (p->fcode.bf_insns)
{
if (pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
}
}
- /* Fill the header for the user suppplied callback function */
+ /* Fill the header for the user supplied callback function */
pcap_header.caplen = caplen;
pcap_header.len = packet_len;
}
/*
- * Vendor-specific error codes.
- *
* These are NTSTATUS values:
*
* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781
* mapped to Windows error values in userland; they're returned by
* GetLastError().
*
- * Attempting to set non-promiscuous mode on a Microsoft Surface Pro's
- * Mobile Broadband Adapter returns an error; that error can safely be
- * ignored, as it's always in non-promiscuous mode.
+ * Note that "driver" here includes the Npcap NPF driver, as various
+ * versions would take NT status values and set the "Customer" bit
+ * before returning the status code. The commit message for the
+ * change that started doing that is
+ *
+ * Returned a customer-defined NTSTATUS in OID requests to avoid
+ * NTSTATUS-to-Win32 Error code translation.
+ *
+ * but I don't know why the goal was to avoid that translation.
+ *
+ * Attempting to set the hardware filter on a Microsoft Surface Pro's
+ * Mobile Broadband Adapter returns an error that appears to be
+ * NDIS_STATUS_NOT_SUPPORTED ORed with the "Customer" bit, so it's
+ * probably indicating that it doesn't support that.
*
* It is likely that there are other devices which throw spurious errors,
* at which point this will need refactoring to efficiently check against
- * a list, but for now we can just check this one value.
+ * a list, but for now we can just check this one value. Perhaps the
+ * right way to do this is compare against various NDIS errors with
+ * the "customer" bit ORed in.
*/
-#define NPF_SURFACE_MOBILE_NONPROMISC 0xe00000bb
+#define NT_STATUS_CUSTOMER_DEFINED 0x20000000
static int
pcap_activate_npf(pcap_t *p)
case ERROR_BAD_UNIT:
/*
* There's no such device.
+ * There's nothing to add, so clear the error
+ * message.
*/
+ p->errbuf[0] = '\0';
return (PCAP_ERROR_NO_SUCH_DEVICE);
case ERROR_ACCESS_DENIED:
/*
* There is, but we don't have permission to
* use it.
+ *
+ * XXX - we currently get ERROR_BAD_UNIT if the
+ * user says "no" to the UAC prompt.
*/
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The helper program for \"Admin-only Mode\" must be allowed to make changes to your device");
return (PCAP_ERROR_PERM_DENIED);
default:
/*
* Suppress spurious error generated by non-compiant
- * MS Surface mobile adapters.
+ * MS Surface mobile adapters that appear to
+ * return NDIS_STATUS_NOT_SUPPORTED for attempts
+ * to set the hardware filter.
+ *
+ * It appears to be reporting NDIS_STATUS_NOT_SUPPORTED,
+ * but with the NT status value "Customer" bit set;
+ * the Npcap NPF driver sets that bit in some cases.
*
* If we knew that this meant "promiscuous mode
* isn't supported", we could add a "promiscuous
* and rejecting it with an error could disrupt
* attempts to capture, as many programs (tcpdump,
* *shark) default to promiscuous mode.
+ *
+ * Alternatively, we could return the "promiscuous
+ * mode not supported" *warning* value, so that
+ * correct code will either ignore it or report
+ * it and continue capturing. (This may require
+ * a pcap_init() flag to request that return
+ * value, so that old incorrect programs that
+ * assume a non-zero return from pcap_activate()
+ * is an error don't break.)
*/
- if (errcode != NPF_SURFACE_MOBILE_NONPROMISC)
+ if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED))
{
pcap_fmt_errmsg_for_win32_err(p->errbuf,
PCAP_ERRBUF_SIZE, errcode,
* Suppress spurious error generated by non-compiant
* MS Surface mobile adapters.
*/
- if (errcode != NPF_SURFACE_MOBILE_NONPROMISC)
+ if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED))
{
pcap_fmt_errmsg_for_win32_err(p->errbuf,
PCAP_ERRBUF_SIZE, errcode,
return (PacketIsMonitorModeSupported(p->opt.device) == 1);
}
-pcap_t *
-pcap_create_interface(const char *device _U_, char *ebuf)
-{
- pcap_t *p;
+/*
+ * Get a list of time stamp types.
+ */
#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
- char *device_copy;
- ADAPTER *adapter;
+static int
+get_ts_types(const char *device, pcap_t *p, char *ebuf)
+{
+ char *device_copy = NULL;
+ ADAPTER *adapter = NULL;
ULONG num_ts_modes;
BOOL ret;
- DWORD error;
- ULONG *modes;
-#endif
+ DWORD error = ERROR_SUCCESS;
+ ULONG *modes = NULL;
+ int status = 0;
- p = PCAP_CREATE_COMMON(ebuf, struct pcap_win);
- if (p == NULL)
- return (NULL);
+ do {
+ /*
+ * First, find out how many time stamp modes we have.
+ * To do that, we have to open the adapter.
+ *
+ * XXX - PacketOpenAdapter() takes a non-const pointer
+ * as an argument, so we make a copy of the argument and
+ * pass that to it.
+ */
+ device_copy = strdup(device);
+ if (device_copy == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
+ status = -1;
+ break;
+ }
- p->activate_op = pcap_activate_npf;
- p->can_set_rfmon_op = pcap_can_set_rfmon_npf;
+ adapter = PacketOpenAdapter(device_copy);
+ if (adapter == NULL)
+ {
+ error = GetLastError();
+ /*
+ * If we can't open the device now, we won't be
+ * able to later, either.
+ *
+ * If the error is something that indicates
+ * that the device doesn't exist, or that they
+ * don't have permission to open the device - or
+ * perhaps that they don't have permission to get
+ * a list of devices, if PacketOpenAdapter() does
+ * that - the user will find that out when they try
+ * to activate the device; just return an empty
+ * list of time stamp types.
+ *
+ * Treating either of those as errors will, for
+ * example, cause "tcpdump -i <number>" to fail,
+ * because it first tries to pass the interface
+ * name to pcap_create() and pcap_activate(),
+ * in order to handle OSes where interfaces can
+ * have names that are just numbers (stand up
+ * and say hello, Linux!), and, if pcap_activate()
+ * fails with a "no such device" error, checks
+ * whether the interface name is a valid number
+ * and, if so, tries to use it as an index in
+ * the list of interfaces.
+ *
+ * That means pcap_create() must succeed even
+ * for interfaces that don't exist, with the
+ * failure occurring at pcap_activate() time.
+ */
+ if (error == ERROR_BAD_UNIT ||
+ error == ERROR_ACCESS_DENIED) {
+ p->tstamp_type_count = 0;
+ p->tstamp_type_list = NULL;
+ status = 0;
+ } else {
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, error,
+ "Error opening adapter");
+ status = -1;
+ }
+ break;
+ }
-#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
- /*
- * First, find out how many time stamp modes we have.
- * To do that, we have to open the adapter.
- *
- * XXX - PacketOpenAdapter() takes a non-const pointer
- * as an argument, so we make a copy of the argument and
- * pass that to it.
- */
- device_copy = strdup(device);
- adapter = PacketOpenAdapter(device_copy);
- error = GetLastError();
- free(device_copy);
- if (adapter == NULL)
- {
- /* If we can't open the device now, we won't be able to later, either. */
- pcap_fmt_errmsg_for_win32_err(ebuf, PCAP_ERRBUF_SIZE,
- error, "Error opening adapter");
- pcap_close(p);
- return (NULL);
- }
- /*
- * Get the total number of time stamp modes.
- *
- * The buffer for PacketGetTimestampModes() is
- * a sequence of 1 or more ULONGs. What's
- * passed to PacketGetTimestampModes() should have
- * the total number of ULONGs in the first ULONG;
- * what's returned *from* PacketGetTimestampModes()
- * has the total number of time stamp modes in
- * the first ULONG.
- *
- * Yes, that means if there are N time stamp
- * modes, the first ULONG should be set to N+1
- * on input, and will be set to N on output.
- *
- * We first make a call to PacketGetTimestampModes()
- * with a pointer to a single ULONG set to 1; the
- * call should fail with ERROR_MORE_DATA (unless
- * there are *no* modes, but that should never
- * happen), and that ULONG should be set to the
- * number of modes.
- */
- num_ts_modes = 1;
- ret = PacketGetTimestampModes(adapter, &num_ts_modes);
- if (!ret) {
/*
- * OK, it failed. Did it fail with
- * ERROR_MORE_DATA?
+ * Get the total number of time stamp modes.
+ *
+ * The buffer for PacketGetTimestampModes() is
+ * a sequence of 1 or more ULONGs. What's
+ * passed to PacketGetTimestampModes() should have
+ * the total number of ULONGs in the first ULONG;
+ * what's returned *from* PacketGetTimestampModes()
+ * has the total number of time stamp modes in
+ * the first ULONG.
+ *
+ * Yes, that means if there are N time stamp
+ * modes, the first ULONG should be set to N+1
+ * on input, and will be set to N on output.
+ *
+ * We first make a call to PacketGetTimestampModes()
+ * with a pointer to a single ULONG set to 1; the
+ * call should fail with ERROR_MORE_DATA (unless
+ * there are *no* modes, but that should never
+ * happen), and that ULONG should be set to the
+ * number of modes.
*/
- error = GetLastError();
- if (error != ERROR_MORE_DATA) {
+ num_ts_modes = 1;
+ ret = PacketGetTimestampModes(adapter, &num_ts_modes);
+ if (!ret) {
/*
- * No, did it fail with ERROR_INVALID_FUNCTION?
+ * OK, it failed. Did it fail with
+ * ERROR_MORE_DATA?
*/
- if (error == ERROR_INVALID_FUNCTION) {
+ error = GetLastError();
+ if (error != ERROR_MORE_DATA) {
/*
- * This is probably due to
- * the driver with which Packet.dll
- * communicates being older, or
- * being a WinPcap driver, so
- * that it doesn't support
- * BIOCGTIMESTAMPMODES.
- *
- * Tell the user to try uninstalling
- * Npcap - and WinPcap if installed -
- * and re-installing it, to flush
- * out all older drivers.
+ * No, did it fail with ERROR_INVALID_FUNCTION?
*/
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "PacketGetTimestampModes() failed with ERROR_INVALID_FUNCTION; try uninstalling Npcap, and WinPcap if installed, and re-installing it from npcap.org");
- pcap_close(p);
- return (NULL);
- }
+ if (error == ERROR_INVALID_FUNCTION) {
+ /*
+ * This is probably due to
+ * the driver with which Packet.dll
+ * communicates being older, or
+ * being a WinPcap driver, so
+ * that it doesn't support
+ * BIOCGTIMESTAMPMODES.
+ *
+ * Tell the user to try uninstalling
+ * Npcap - and WinPcap if installed -
+ * and re-installing it, to flush
+ * out all older drivers.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "PacketGetTimestampModes() failed with ERROR_INVALID_FUNCTION; try uninstalling Npcap, and WinPcap if installed, and re-installing it from npcap.com");
+ status = -1;
+ break;
+ }
- /*
- * No, some other error. Fail.
- */
- pcap_fmt_errmsg_for_win32_err(ebuf,
- PCAP_ERRBUF_SIZE, error,
- "Error calling PacketGetTimestampModes");
- pcap_close(p);
- return (NULL);
+ /*
+ * No, some other error. Fail.
+ */
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, error,
+ "Error calling PacketGetTimestampModes");
+ status = -1;
+ break;
+ }
}
+ /* else (ret == TRUE)
+ * Unexpected success. Let's act like we got ERROR_MORE_DATA.
+ * If it doesn't work, we'll hit some other error condition farther on.
+ */
/* If the driver reports no modes supported *and*
* ERROR_MORE_DATA, something is seriously wrong.
* settable timestamp modes, but that would hide a bug.
*/
if (num_ts_modes == 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "PacketGetTimestampModes() reports 0 modes supported.");
- pcap_close(p);
- return (NULL);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "PacketGetTimestampModes() reports 0 modes supported.");
+ status = -1;
+ break;
}
/*
if (modes == NULL) {
/* Out of memory. */
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
- pcap_close(p);
- return (NULL);
+ status = -1;
+ break;
}
modes[0] = 1 + num_ts_modes;
if (!PacketGetTimestampModes(adapter, modes)) {
pcap_fmt_errmsg_for_win32_err(ebuf,
PCAP_ERRBUF_SIZE, GetLastError(),
"Error calling PacketGetTimestampModes");
- free(modes);
- pcap_close(p);
- return (NULL);
+ status = -1;
+ break;
}
if (modes[0] != num_ts_modes) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"First PacketGetTimestampModes() call gives %lu modes, second call gives %lu modes",
num_ts_modes, modes[0]);
- free(modes);
- pcap_close(p);
- return (NULL);
+ status = -1;
+ break;
}
/*
p->tstamp_type_list = malloc((1 + num_ts_modes) * sizeof(u_int));
if (p->tstamp_type_list == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
- free(modes);
- pcap_close(p);
- return (NULL);
+ status = -1;
+ break;
}
u_int num_ts_types = 0;
p->tstamp_type_list[num_ts_types] =
}
}
p->tstamp_type_count = num_ts_types;
+ } while (0);
+
+ /* Clean up temporary allocations */
+ if (device_copy != NULL) {
+ free(device_copy);
+ }
+ if (modes != NULL) {
free(modes);
}
- PacketCloseAdapter(adapter);
+ if (adapter != NULL) {
+ PacketCloseAdapter(adapter);
+ }
+
+ return status;
+}
+#else /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+static int
+get_ts_types(const char *device _U_, pcap_t *p _U_, char *ebuf _U_)
+{
+ /*
+ * Nothing to fetch, so it always "succeeds".
+ */
+ return 0;
+}
#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+pcap_t *
+pcap_create_interface(const char *device _U_, char *ebuf)
+{
+ pcap_t *p;
+
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_win);
+ if (p == NULL)
+ return (NULL);
+
+ p->activate_op = pcap_activate_npf;
+ p->can_set_rfmon_op = pcap_can_set_rfmon_npf;
+
+ if (get_ts_types(device, p, ebuf) == -1) {
+ pcap_close(p);
+ return (NULL);
+ }
return (p);
}
#ifdef OID_GEN_PHYSICAL_MEDIUM_EX
OID_GEN_PHYSICAL_MEDIUM_EX,
#endif
- OID_GEN_PHYSICAL_MEDIUM
- };
+ OID_GEN_PHYSICAL_MEDIUM
+ };
#define N_GEN_PHYSICAL_MEDIUM_OIDS (sizeof gen_physical_medium_oids / sizeof gen_physical_medium_oids[0])
size_t i;
#endif /* OID_GEN_PHYSICAL_MEDIUM */
*flags |= PCAP_IF_WIRELESS;
/*
- * A "network assosiation state" makes no sense for airpcap.
+ * A "network association state" makes no sense for airpcap.
*/
*flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
PacketCloseAdapter(adapter);
desc++;
/*
- * Found it - "desc" points to the first of the two
+ * Found it - "desc" points to the first of the two
* nulls at the end of the list of names, so the
* first byte of the list of descriptions is two bytes
* after it.