]> The Tcpdump Group git mirrors - libpcap/blobdiff - pcap-npf.c
Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21
[libpcap] / pcap-npf.c
index 0099a68fc1c45bf8c2109858a929f3a08f8cd8a6..99b5981e5a571a97896bcc4ad2ebd5aaa8787c1f 100644 (file)
@@ -901,7 +901,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                        }
                }
 
-               /* 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)
@@ -912,7 +912,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
                        }
                }
 
-               /* 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;
 
@@ -985,8 +985,6 @@ pcap_breakloop_npf(pcap_t *p)
 }
 
 /*
- * Vendor-specific error codes.
- *
  * These are NTSTATUS values:
  *
  *    https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781
@@ -995,15 +993,28 @@ pcap_breakloop_npf(pcap_t *p)
  * 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)
@@ -1062,14 +1073,22 @@ 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:
@@ -1285,7 +1304,13 @@ pcap_activate_npf(pcap_t *p)
 
                        /*
                         * 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
@@ -1307,8 +1332,17 @@ pcap_activate_npf(pcap_t *p)
                         * 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,
@@ -1339,7 +1373,7 @@ pcap_activate_npf(pcap_t *p)
                         * 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,
@@ -1556,30 +1590,22 @@ pcap_can_set_rfmon_npf(pcap_t *p)
        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
+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 = ERROR_SUCCESS;
        ULONG *modes = NULL;
-#endif
-
-       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;
+       int status = 0;
 
-#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
        do {
-               /* Must fill out ebuf to signal an error at end of do/while */
-               ebuf[0] = '\0';
                /*
                 * First, find out how many time stamp modes we have.
                 * To do that, we have to open the adapter.
@@ -1591,6 +1617,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                device_copy = strdup(device);
                if (device_copy == NULL) {
                        pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
+                       status = -1;
                        break;
                }
 
@@ -1598,11 +1625,49 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                if (adapter == NULL)
                {
                        error = GetLastError();
-                       /* 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");
+                       /*
+                        * 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;
                }
+
                /*
                 * Get the total number of time stamp modes.
                 *
@@ -1653,6 +1718,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                                         */
                                        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;
                                }
 
@@ -1662,6 +1728,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                                pcap_fmt_errmsg_for_win32_err(ebuf,
                                    PCAP_ERRBUF_SIZE, error,
                                    "Error calling PacketGetTimestampModes");
+                               status = -1;
                                break;
                        }
                }
@@ -1678,6 +1745,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                if (num_ts_modes == 0) {
                        snprintf(ebuf, PCAP_ERRBUF_SIZE,
                            "PacketGetTimestampModes() reports 0 modes supported.");
+                       status = -1;
                        break;
                }
 
@@ -1692,6 +1760,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                if (modes == NULL) {
                        /* Out of memory. */
                        pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
+                       status = -1;
                        break;
                }
                modes[0] = 1 + num_ts_modes;
@@ -1699,12 +1768,14 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                        pcap_fmt_errmsg_for_win32_err(ebuf,
                            PCAP_ERRBUF_SIZE, GetLastError(),
                            "Error calling PacketGetTimestampModes");
+                       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]);
+                       status = -1;
                        break;
                }
 
@@ -1716,6 +1787,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                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");
+                       status = -1;
                        break;
                }
                u_int num_ts_types = 0;
@@ -1778,18 +1850,35 @@ pcap_create_interface(const char *device _U_, char *ebuf)
                PacketCloseAdapter(adapter);
        }
 
-       /* Error condition signaled by ebuf containing an error message */
-       if (ebuf[0] != '\0') {
-               /* Undo any changes. Must not use pcap_close()
-                * since none of the ops have been set. */
-               if (p->tstamp_type_list != NULL) {
-                       free(p->tstamp_type_list);
-               }
-               free(p);
-               p = NULL;
-       }
+       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);
 }
 
@@ -1996,8 +2085,8 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
   #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 */
@@ -2050,7 +2139,7 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
                *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);
@@ -2309,7 +2398,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
                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.