]> The Tcpdump Group git mirrors - libpcap/commitdiff
Define pcap_open() etc. even without remote capture. 1223/head
authorGuy Harris <[email protected]>
Fri, 22 Sep 2023 21:47:35 +0000 (14:47 -0700)
committerGuy Harris <[email protected]>
Fri, 22 Sep 2023 23:45:30 +0000 (16:45 -0700)
They also support local capture, and we build them even without remote
capture, as their absence may complicate code build on macOS 14 with
Xcode 15, as that platform supports "weakly linked symbols":

https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html

which are symbols in dynamically-linked shared libraries, declared in
such a fashion that if a program linked against a newer software
development kit (SDK), and using a symbol present in the OS version for
which that SDK is provided, is run on an older OS version that lacks
that symbol, that symbol's value is a NULL pointer.  This allows those
programs to test for the presence of that symbol by checking whether
it's non-null and, if it is, using the symbol, otherwise not using it.

See Wireshark issue 19349:

https://gitlab.com/wireshark/wireshark/-/issues/19349

and this note in that issue:

https://gitlab.com/wireshark/wireshark/-/issues/19349#note_1573375784

for a possible example of such a complication (Apple may have added a
stub pcap_open() to handle this, but that breaks code that expects
pcap_open() to work if present).

Add pcap_open() support in the opentest test program, with the -o flag.

CMakeLists.txt
Makefile.in
configure.ac
pcap-new.c [deleted file]
pcap.c
pcap/pcap.h
testprogs/findalldevstest.c
testprogs/opentest.c

index fb06e579cd46bc154d7da8a8af19417b97d366ac..7090eced237a0debc4f57b2cac1e6dc1f38c60af 100644 (file)
@@ -2693,7 +2693,7 @@ if(ENABLE_REMOTE)
     check_struct_has_member("struct msghdr" msg_flags "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_FLAGS)
     cmake_pop_check_state()
     set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C}
-        pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c)
+        pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c)
 endif(ENABLE_REMOTE)
 
 ###################################################################
index b5025c3336f85facd4897d1447763642b80ba1da..df26df32b647688819086c6ca6a31ae625df67d2 100644 (file)
@@ -321,7 +321,6 @@ EXTRA_DIST = \
        pcap-libdlpi.c \
        pcap-linux.c \
        pcap-namedb.h \
-       pcap-new.c \
        pcap-netfilter-linux.c \
        pcap-netfilter-linux.h \
        pcap-netmap.c \
index eea5a7a1f2f2d233ae46a0ca9dde420ba532e9a4..3c28908cf932dfbf8c634dee086cd17fd6b7e432 100644 (file)
@@ -1945,7 +1945,7 @@ return 0;
 
        AC_DEFINE(ENABLE_REMOTE,,
            [Define to 1 if remote packet capture is to be supported])
-       REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
+       REMOTE_C_SRC="$REMOTE_C_SRC pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
        BUILD_RPCAPD=build-rpcapd
        INSTALL_RPCAPD=install-rpcapd
        ;;
diff --git a/pcap-new.c b/pcap-new.c
deleted file mode 100644 (file)
index 76388a9..0000000
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
- * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the Politecnico di Torino, CACE Technologies
- * nor the names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "ftmacros.h"
-#include "diag-control.h"
-
-/*
- * sockutils.h may include <crtdbg.h> on Windows, and pcap-int.h will
- * include portability.h, and portability.h, on Windows, expects that
- * <crtdbg.h> has already been included, so include sockutils.h first.
- */
-#include "sockutils.h"
-#include "pcap-int.h"  // for the details of the pcap_t structure
-#include "pcap-rpcap.h"
-#include "rpcap-protocol.h"
-#include <errno.h>             // for the errno variable
-#include <stdlib.h>            // for malloc(), free(), ...
-#include <string.h>            // for strstr, etc
-
-#ifndef _WIN32
-#include <dirent.h>            // for readdir
-#endif
-
-/* String identifier to be used in the pcap_findalldevs_ex() */
-#define PCAP_TEXT_SOURCE_FILE "File"
-#define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1)
-/* String identifier to be used in the pcap_findalldevs_ex() */
-#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
-#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1)
-
-/* String identifier to be used in the pcap_findalldevs_ex() */
-#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
-#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1)
-
-/****************************************************
- *                                                  *
- * Function bodies                                  *
- *                                                  *
- ****************************************************/
-
-int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
-{
-       int type;
-       char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
-       size_t pathlen;
-       size_t stringlen;
-       pcap_t *fp;
-       char tmpstring[PCAP_BUF_SIZE + 1];              /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
-       pcap_if_t *lastdev;     /* Last device in the pcap_if_t list */
-       pcap_if_t *dev;         /* Device we're adding to the pcap_if_t list */
-
-       /* List starts out empty. */
-       (*alldevs) = NULL;
-       lastdev = NULL;
-
-       if (strlen(source) > PCAP_BUF_SIZE)
-       {
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
-               return -1;
-       }
-
-       /*
-        * Determine the type of the source (file, local, remote)
-        * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters.
-        * In the first case, the name of the directory we have to look into must be present (therefore
-        * the 'name' parameter of the pcap_parsesrcstr() is present).
-        * In the second case, the name of the adapter is not required (we need just the host). So, we have
-        * to use a first time this function to get the source type, and a second time to get the appropriate
-        * info, which depends on the source type.
-        */
-       if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
-               return -1;
-
-       switch (type)
-       {
-       case PCAP_SRC_IFLOCAL:
-               if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
-                       return -1;
-
-               /* Initialize temporary string */
-               tmpstring[PCAP_BUF_SIZE] = 0;
-
-               /* The user wants to retrieve adapters from a local host */
-               if (pcap_findalldevs(alldevs, errbuf) == -1)
-                       return -1;
-
-               if (*alldevs == NULL)
-               {
-                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                               "No interfaces found! Make sure libpcap/Npcap is properly installed"
-                               " on the local machine.");
-                       return -1;
-               }
-
-               /* Scan all the interfaces and modify name and description */
-               /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */
-               dev = *alldevs;
-               while (dev)
-               {
-                       char *localdesc, *desc;
-
-                       /* Create the new device identifier */
-                       if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
-                               return -1;
-
-                       /* Delete the old pointer */
-                       free(dev->name);
-
-                       /* Make a copy of the new device identifier */
-                       dev->name = strdup(tmpstring);
-                       if (dev->name == NULL)
-                       {
-                               pcap_fmt_errmsg_for_errno(errbuf,
-                                   PCAP_ERRBUF_SIZE, errno,
-                                   "malloc() failed");
-                               pcap_freealldevs(*alldevs);
-                               return -1;
-                       }
-
-                       /*
-                        * Create the description.
-                        */
-                       if ((dev->description == NULL) || (dev->description[0] == 0))
-                               localdesc = dev->name;
-                       else
-                               localdesc = dev->description;
-                       if (pcap_asprintf(&desc, "%s '%s' %s",
-                           PCAP_TEXT_SOURCE_ADAPTER, localdesc,
-                           PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1)
-                       {
-                               pcap_fmt_errmsg_for_errno(errbuf,
-                                   PCAP_ERRBUF_SIZE, errno,
-                                   "malloc() failed");
-                               pcap_freealldevs(*alldevs);
-                               return -1;
-                       }
-
-                       /* Now overwrite the description */
-                       free(dev->description);
-                       dev->description = desc;
-
-                       dev = dev->next;
-               }
-
-               return 0;
-
-       case PCAP_SRC_FILE:
-       {
-#ifdef _WIN32
-               WIN32_FIND_DATA filedata;
-               HANDLE filehandle;
-#else
-               struct dirent *filedata;
-               DIR *unixdir;
-#endif
-
-               if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
-                       return -1;
-
-               /* Check that the filename is correct */
-               stringlen = strlen(name);
-
-               /* The directory must end with '\' in Win32 and '/' in UNIX */
-#ifdef _WIN32
-#define ENDING_CHAR '\\'
-#else
-#define ENDING_CHAR '/'
-#endif
-
-               if (name[stringlen - 1] != ENDING_CHAR)
-               {
-                       name[stringlen] = ENDING_CHAR;
-                       name[stringlen + 1] = 0;
-
-                       stringlen++;
-               }
-
-               /* Save the path for future reference */
-               snprintf(path, sizeof(path), "%s", name);
-               pathlen = strlen(path);
-
-#ifdef _WIN32
-               /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
-               if (name[stringlen - 1] != '*')
-               {
-                       name[stringlen] = '*';
-                       name[stringlen + 1] = 0;
-               }
-
-               filehandle = FindFirstFile(name, &filedata);
-
-               if (filehandle == INVALID_HANDLE_VALUE)
-               {
-                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
-                       return -1;
-               }
-
-#else
-               /* opening the folder */
-               unixdir= opendir(path);
-
-               /* get the first file into it */
-               filedata= readdir(unixdir);
-
-               if (filedata == NULL)
-               {
-                       DIAG_OFF_FORMAT_TRUNCATION
-                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
-                       DIAG_ON_FORMAT_TRUNCATION
-                       closedir(unixdir);
-                       return -1;
-               }
-#endif
-
-               /* Add all files we find to the list. */
-               do
-               {
-#ifdef _WIN32
-                       /* Skip the file if the pathname won't fit in the buffer */
-                       if (pathlen + strlen(filedata.cFileName) >= sizeof(filename))
-                               continue;
-                       snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
-#else
-                       if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
-                               continue;
-                       DIAG_OFF_FORMAT_TRUNCATION
-                       snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
-                       DIAG_ON_FORMAT_TRUNCATION
-#endif
-
-                       fp = pcap_open_offline(filename, errbuf);
-
-                       if (fp)
-                       {
-                               /* allocate the main structure */
-                               dev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
-                               if (dev == NULL)
-                               {
-                                       pcap_fmt_errmsg_for_errno(errbuf,
-                                           PCAP_ERRBUF_SIZE, errno,
-                                           "malloc() failed");
-                                       pcap_freealldevs(*alldevs);
-#ifdef _WIN32
-                                       FindClose(filehandle);
-#else
-                                       closedir(unixdir);
-#endif
-                                       return -1;
-                               }
-
-                               /* Initialize the structure to 'zero' */
-                               memset(dev, 0, sizeof(pcap_if_t));
-
-                               /* Append it to the list. */
-                               if (lastdev == NULL)
-                               {
-                                       /*
-                                        * List is empty, so it's also
-                                        * the first device.
-                                        */
-                                       *alldevs = dev;
-                               }
-                               else
-                               {
-                                       /*
-                                        * Append after the last device.
-                                        */
-                                       lastdev->next = dev;
-                               }
-                               /* It's now the last device. */
-                               lastdev = dev;
-
-                               /* Create the new source identifier */
-                               if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
-                               {
-                                       pcap_freealldevs(*alldevs);
-#ifdef _WIN32
-                                       FindClose(filehandle);
-#else
-                                       closedir(unixdir);
-#endif
-                                       return -1;
-                               }
-
-                               dev->name = strdup(tmpstring);
-                               if (dev->name == NULL)
-                               {
-                                       pcap_fmt_errmsg_for_errno(errbuf,
-                                           PCAP_ERRBUF_SIZE, errno,
-                                           "malloc() failed");
-                                       pcap_freealldevs(*alldevs);
-#ifdef _WIN32
-                                       FindClose(filehandle);
-#else
-                                       closedir(unixdir);
-#endif
-                                       return -1;
-                               }
-
-                               /*
-                                * Create the description.
-                                */
-                               if (pcap_asprintf(&dev->description,
-                                   "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
-                                   filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1)
-                               {
-                                       pcap_fmt_errmsg_for_errno(errbuf,
-                                           PCAP_ERRBUF_SIZE, errno,
-                                           "malloc() failed");
-                                       pcap_freealldevs(*alldevs);
-#ifdef _WIN32
-                                       FindClose(filehandle);
-#else
-                                       closedir(unixdir);
-#endif
-                                       return -1;
-                               }
-
-                               pcap_close(fp);
-                       }
-               }
-#ifdef _WIN32
-               while (FindNextFile(filehandle, &filedata) != 0);
-#else
-               while ( (filedata= readdir(unixdir)) != NULL);
-#endif
-
-
-               /* Close the search handle. */
-#ifdef _WIN32
-               FindClose(filehandle);
-#else
-               closedir(unixdir);
-#endif
-
-               return 0;
-       }
-
-       case PCAP_SRC_IFREMOTE:
-               return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf);
-
-       default:
-               pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
-               return -1;
-       }
-}
-
-pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
-{
-       char name[PCAP_BUF_SIZE];
-       int type;
-       pcap_t *fp;
-       int status;
-
-       /*
-        * 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 (source == NULL)
-               source = "any";
-
-       if (strlen(source) > PCAP_BUF_SIZE)
-       {
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
-               return NULL;
-       }
-
-       /*
-        * Determine the type of the source (file, local, remote) and,
-        * if it's file or local, the name of the file or capture device.
-        */
-       if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
-               return NULL;
-
-       switch (type)
-       {
-       case PCAP_SRC_FILE:
-               return pcap_open_offline(name, errbuf);
-
-       case PCAP_SRC_IFLOCAL:
-               fp = pcap_create(name, errbuf);
-               break;
-
-       case PCAP_SRC_IFREMOTE:
-               /*
-                * Although we already have host, port and iface, we prefer
-                * to pass only 'source' to pcap_open_rpcap(), so that it
-                * has to call pcap_parsesrcstr() again.
-                * This is less optimized, but much clearer.
-                */
-               return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
-
-       default:
-               pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
-               return NULL;
-       }
-
-       if (fp == NULL)
-               return (NULL);
-       status = pcap_set_snaplen(fp, snaplen);
-       if (status < 0)
-               goto fail;
-       if (flags & PCAP_OPENFLAG_PROMISCUOUS)
-       {
-               status = pcap_set_promisc(fp, 1);
-               if (status < 0)
-                       goto fail;
-       }
-       if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
-       {
-               status = pcap_set_immediate_mode(fp, 1);
-               if (status < 0)
-                       goto fail;
-       }
-#ifdef _WIN32
-       /*
-        * This flag is supported on Windows only.
-        * XXX - is there a way to support it with
-        * the capture mechanisms on UN*X?  It's not
-        * exactly a "set direction" operation; I
-        * think it means "do not capture packets
-        * injected with pcap_sendpacket() or
-        * pcap_inject()".
-        */
-       /* disable loopback capture if requested */
-       if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
-               fp->opt.nocapture_local = 1;
-#endif /* _WIN32 */
-       status = pcap_set_timeout(fp, read_timeout);
-       if (status < 0)
-               goto fail;
-       status = pcap_activate(fp);
-       if (status < 0)
-               goto fail;
-       return fp;
-
-fail:
-       DIAG_OFF_FORMAT_TRUNCATION
-       if (status == PCAP_ERROR)
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
-                   name, fp->errbuf);
-       else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
-           status == PCAP_ERROR_PERM_DENIED ||
-           status == PCAP_ERROR_PROMISC_PERM_DENIED)
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
-                   name, pcap_statustostr(status), fp->errbuf);
-       else
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
-                   name, pcap_statustostr(status));
-       DIAG_ON_FORMAT_TRUNCATION
-       pcap_close(fp);
-       return NULL;
-}
-
-struct pcap_samp *pcap_setsampling(pcap_t *p)
-{
-       return &p->rmt_samp;
-}
diff --git a/pcap.c b/pcap.c
index 5f777c08124e005d947d42cc725d4eba7a646f42..e4f55b2dbff2809165a3fe40864b590527db3dc5 100644 (file)
--- a/pcap.c
+++ b/pcap.c
 #include <config.h>
 #endif
 
+/*
+ * Include this before including any system header files, as it
+ * may do some #defines that cause those headerss to declare
+ * more functions that it does by default.
+ */
+#include "ftmacros.h"
+
 #include <pcap-types.h>
 #ifndef _WIN32
 #include <sys/param.h>
@@ -125,6 +132,10 @@ struct rtentry;            /* declarations in <net/if.h> */
 #include "pcap-airpcap.h"
 #endif
 
+#ifdef ENABLE_REMOTE
+#include "pcap-rpcap.h"
+#endif
+
 #ifdef _WIN32
 /*
  * To quote the WSAStartup() documentation:
@@ -1625,7 +1636,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
 #endif
            ) {
                *netp = *maskp = 0;
-               return 0;
+               return (0);
        }
 
        fd = socket(AF_INET, SOCK_DGRAM, 0);
@@ -1702,9 +1713,6 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
 }
 #endif /* !defined(_WIN32) */
 
-#ifdef ENABLE_REMOTE
-#include "pcap-rpcap.h"
-
 /*
  * Extract a substring from a string.
  */
@@ -2287,7 +2295,6 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
 {
        return (pcap_parsesrcstr_ex(source, type, NULL, host, port, name, NULL, errbuf));
 }
-#endif
 
 pcap_t *
 pcap_create(const char *device, char *errbuf)
@@ -4523,3 +4530,509 @@ pcap_set_parser_debug(int value)
        pcap_debug = value;
 }
 #endif
+
+/*
+ * APIs.added in WinPcap for remote capture.
+ *
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _WIN32
+#include <dirent.h>            // for readdir
+#endif
+
+/* String identifier to be used in the pcap_findalldevs_ex() */
+#define PCAP_TEXT_SOURCE_FILE "File"
+#define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1)
+/* String identifier to be used in the pcap_findalldevs_ex() */
+#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
+#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1)
+
+/* String identifier to be used in the pcap_findalldevs_ex() */
+#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
+#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1)
+
+/****************************************************
+ *                                                  *
+ * Function bodies                                  *
+ *                                                  *
+ ****************************************************/
+
+#ifdef ENABLE_REMOTE
+ #define _USED_FOR_REMOTE
+#else
+ #define _USED_FOR_REMOTE _U_
+#endif
+
+int
+pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth _USED_FOR_REMOTE,
+    pcap_if_t **alldevs, char *errbuf)
+{
+       int type;
+       char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
+       size_t pathlen;
+       size_t stringlen;
+       pcap_t *fp;
+       char tmpstring[PCAP_BUF_SIZE + 1];              /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
+       pcap_if_t *lastdev;     /* Last device in the pcap_if_t list */
+       pcap_if_t *dev;         /* Device we're adding to the pcap_if_t list */
+
+       /* List starts out empty. */
+       (*alldevs) = NULL;
+       lastdev = NULL;
+
+       if (strlen(source) > PCAP_BUF_SIZE) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "The source string is too long. Cannot handle it correctly.");
+               return (PCAP_ERROR);
+       }
+
+       /*
+        * Determine the type of the source (file, local, remote).
+        *
+        * There are some differences if pcap_findalldevs_ex() is called to
+        * list files and remote adapters.
+        *
+        * In the first case, the name of the directory we have to look into
+        * must be present (therefore the 'name' parameter of the
+        * pcap_parsesrcstr() is present).
+        *
+        * In the second case, the name of the adapter is not required
+        * (we need just the host). So, we have to use this function a
+        * first time to get the source type, and a second time to get
+        * the appropriate info, which depends on the source type.
+        */
+       if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
+               return (PCAP_ERROR);
+
+       switch (type) {
+
+       case PCAP_SRC_IFLOCAL:
+               if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
+                       return (PCAP_ERROR);
+
+               /* Initialize temporary string */
+               tmpstring[PCAP_BUF_SIZE] = 0;
+
+               /* The user wants to retrieve adapters from a local host */
+               if (pcap_findalldevs(alldevs, errbuf) == -1)
+                       return (PCAP_ERROR);
+
+               if (*alldevs == NULL) {
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "No interfaces found! Make sure libpcap/Npcap is properly installed"
+                           " on the local machine.");
+                       return (PCAP_ERROR);
+               }
+
+               /*
+                * Scan all the interfaces and modify name and description.
+                *
+                * This is a trick in order to avoid the re-implementation
+                * of pcap_findalldevs here.
+                */
+               dev = *alldevs;
+               while (dev) {
+                       char *localdesc, *desc;
+
+                       /* Create the new device identifier */
+                       if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
+                               return (PCAP_ERROR);
+
+                       /* Delete the old pointer */
+                       free(dev->name);
+
+                       /* Make a copy of the new device identifier */
+                       dev->name = strdup(tmpstring);
+                       if (dev->name == NULL) {
+                               pcap_fmt_errmsg_for_errno(errbuf,
+                                   PCAP_ERRBUF_SIZE, errno,
+                                   "malloc() failed");
+                               pcap_freealldevs(*alldevs);
+                               return (PCAP_ERROR);
+                       }
+
+                       /*
+                        * Create the description.
+                        */
+                       if ((dev->description == NULL) ||
+                           (dev->description[0] == 0))
+                               localdesc = dev->name;
+                       else
+                               localdesc = dev->description;
+                       if (pcap_asprintf(&desc, "%s '%s' %s",
+                           PCAP_TEXT_SOURCE_ADAPTER, localdesc,
+                           PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) {
+                               pcap_fmt_errmsg_for_errno(errbuf,
+                                   PCAP_ERRBUF_SIZE, errno,
+                                   "malloc() failed");
+                               pcap_freealldevs(*alldevs);
+                               return (PCAP_ERROR);
+                       }
+
+                       /* Now overwrite the description */
+                       free(dev->description);
+                       dev->description = desc;
+
+                       dev = dev->next;
+               }
+
+               return (0);
+
+       case PCAP_SRC_FILE:
+       {
+#ifdef _WIN32
+               WIN32_FIND_DATA filedata;
+               HANDLE filehandle;
+#else
+               struct dirent *filedata;
+               DIR *unixdir;
+#endif
+
+               if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
+                       return (PCAP_ERROR);
+
+               /* Check that the filename is correct */
+               stringlen = strlen(name);
+
+               /*
+                * The directory must end with '\' in Windows and
+                * '/' in UN*Xes.
+                */
+#ifdef _WIN32
+#define ENDING_CHAR '\\'
+#else
+#define ENDING_CHAR '/'
+#endif
+
+               if (name[stringlen - 1] != ENDING_CHAR) {
+                       name[stringlen] = ENDING_CHAR;
+                       name[stringlen + 1] = 0;
+
+                       stringlen++;
+               }
+
+               /* Save the path for future reference */
+               snprintf(path, sizeof(path), "%s", name);
+               pathlen = strlen(path);
+
+#ifdef _WIN32
+               /*
+                * To perform directory listing, Windows must have an
+                * asterisk as the ending character.
+                */
+               if (name[stringlen - 1] != '*') {
+                       name[stringlen] = '*';
+                       name[stringlen + 1] = 0;
+               }
+
+               filehandle = FindFirstFile(name, &filedata);
+
+               if (filehandle == INVALID_HANDLE_VALUE) {
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "Error when listing files: does folder '%s' exist?", path);
+                       return (PCAP_ERROR);
+               }
+
+#else
+               /* opening the folder */
+               unixdir= opendir(path);
+
+               /* get the first file into it */
+               filedata= readdir(unixdir);
+
+               if (filedata == NULL) {
+                       DIAG_OFF_FORMAT_TRUNCATION
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "Error when listing files: does folder '%s' exist?", path);
+                       DIAG_ON_FORMAT_TRUNCATION
+                       closedir(unixdir);
+                       return (PCAP_ERROR);
+               }
+#endif
+
+               /* Add all files we find to the list. */
+               do {
+#ifdef _WIN32
+                       /* Skip the file if the pathname won't fit in the buffer */
+                       if (pathlen + strlen(filedata.cFileName) >= sizeof(filename))
+                               continue;
+                       snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
+#else
+                       if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
+                               continue;
+                       DIAG_OFF_FORMAT_TRUNCATION
+                       snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
+                       DIAG_ON_FORMAT_TRUNCATION
+#endif
+
+                       fp = pcap_open_offline(filename, errbuf);
+
+                       if (fp) {
+                               /* allocate the main structure */
+                               dev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
+                               if (dev == NULL) {
+                                       pcap_fmt_errmsg_for_errno(errbuf,
+                                           PCAP_ERRBUF_SIZE, errno,
+                                           "malloc() failed");
+                                       pcap_freealldevs(*alldevs);
+#ifdef _WIN32
+                                       FindClose(filehandle);
+#else
+                                       closedir(unixdir);
+#endif
+                                       return (PCAP_ERROR);
+                               }
+
+                               /* Initialize the structure to 'zero' */
+                               memset(dev, 0, sizeof(pcap_if_t));
+
+                               /* Append it to the list. */
+                               if (lastdev == NULL) {
+                                       /*
+                                        * List is empty, so it's also
+                                        * the first device.
+                                        */
+                                       *alldevs = dev;
+                               } else {
+                                       /*
+                                        * Append after the last device.
+                                        */
+                                       lastdev->next = dev;
+                               }
+                               /* It's now the last device. */
+                               lastdev = dev;
+
+                               /* Create the new source identifier */
+                               if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE,
+                                   NULL, NULL, filename, errbuf) == -1) {
+                                       pcap_freealldevs(*alldevs);
+#ifdef _WIN32
+                                       FindClose(filehandle);
+#else
+                                       closedir(unixdir);
+#endif
+                                       return (PCAP_ERROR);
+                               }
+
+                               dev->name = strdup(tmpstring);
+                               if (dev->name == NULL) {
+                                       pcap_fmt_errmsg_for_errno(errbuf,
+                                           PCAP_ERRBUF_SIZE, errno,
+                                           "malloc() failed");
+                                       pcap_freealldevs(*alldevs);
+#ifdef _WIN32
+                                       FindClose(filehandle);
+#else
+                                       closedir(unixdir);
+#endif
+                                       return (PCAP_ERROR);
+                               }
+
+                               /*
+                                * Create the description.
+                                */
+                               if (pcap_asprintf(&dev->description,
+                                   "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
+                                   filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) {
+                                       pcap_fmt_errmsg_for_errno(errbuf,
+                                           PCAP_ERRBUF_SIZE, errno,
+                                           "malloc() failed");
+                                       pcap_freealldevs(*alldevs);
+#ifdef _WIN32
+                                       FindClose(filehandle);
+#else
+                                       closedir(unixdir);
+#endif
+                                       return (PCAP_ERROR);
+                               }
+
+                               pcap_close(fp);
+                       }
+               }
+#ifdef _WIN32
+               while (FindNextFile(filehandle, &filedata) != 0);
+#else
+               while ( (filedata= readdir(unixdir)) != NULL);
+#endif
+
+
+               /* Close the search handle. */
+#ifdef _WIN32
+               FindClose(filehandle);
+#else
+               closedir(unixdir);
+#endif
+
+               return (0);
+       }
+
+       case PCAP_SRC_IFREMOTE:
+#ifdef ENABLE_REMOTE
+               return (pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf));
+#else
+               pcap_strlcpy(errbuf, "Remote packte capture is not supported",
+                   PCAP_ERRBUF_SIZE);
+               return (PCAP_ERROR);
+#endif
+
+       default:
+               pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
+               return (PCAP_ERROR);
+       }
+}
+
+pcap_t *
+pcap_open(const char *source, int snaplen, int flags, int read_timeout,
+    struct pcap_rmtauth *auth _USED_FOR_REMOTE, char *errbuf)
+{
+       char name[PCAP_BUF_SIZE];
+       int type;
+       pcap_t *fp;
+       int status;
+
+       /*
+        * 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 (source == NULL)
+               source = "any";
+
+       if (strlen(source) > PCAP_BUF_SIZE) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "The source string is too long. Cannot handle it correctly.");
+               return (NULL);
+       }
+
+       /*
+        * Determine the type of the source (file, local, remote) and,
+        * if it's file or local, the name of the file or capture device.
+        */
+       if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
+               return (NULL);
+
+       switch (type) {
+       case PCAP_SRC_FILE:
+               return pcap_open_offline(name, errbuf);
+
+       case PCAP_SRC_IFLOCAL:
+               fp = pcap_create(name, errbuf);
+               break;
+
+       case PCAP_SRC_IFREMOTE:
+#ifdef ENABLE_REMOTE
+               /*
+                * Although we already have host, port and iface, we prefer
+                * to pass only 'source' to pcap_open_rpcap(), so that it
+                * has to call pcap_parsesrcstr() again.
+                * This is less optimized, but much clearer.
+                */
+               return (pcap_open_rpcap(source, snaplen, flags, read_timeout,
+                   auth, errbuf));
+#else
+               pcap_strlcpy(errbuf, "Remote packte capture is not supported",
+                   PCAP_ERRBUF_SIZE);
+               return (NULL);
+#endif
+
+       default:
+               pcap_strlcpy(errbuf, "Source type not supported",
+                   PCAP_ERRBUF_SIZE);
+               return (NULL);
+       }
+
+       if (fp == NULL)
+               return (NULL);
+       status = pcap_set_snaplen(fp, snaplen);
+       if (status < 0)
+               goto fail;
+       if (flags & PCAP_OPENFLAG_PROMISCUOUS) {
+               status = pcap_set_promisc(fp, 1);
+               if (status < 0)
+                       goto fail;
+       }
+       if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS) {
+               status = pcap_set_immediate_mode(fp, 1);
+               if (status < 0)
+                       goto fail;
+       }
+#ifdef _WIN32
+       /*
+        * This flag is supported on Windows only.
+        * XXX - is there a way to support it with
+        * the capture mechanisms on UN*X?  It's not
+        * exactly a "set direction" operation; I
+        * think it means "do not capture packets
+        * injected with pcap_sendpacket() or
+        * pcap_inject()".
+        */
+       /* disable loopback capture if requested */
+       if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
+               fp->opt.nocapture_local = 1;
+#endif /* _WIN32 */
+       status = pcap_set_timeout(fp, read_timeout);
+       if (status < 0)
+               goto fail;
+       status = pcap_activate(fp);
+       if (status < 0)
+               goto fail;
+       return fp;
+
+fail:
+       DIAG_OFF_FORMAT_TRUNCATION
+       if (status == PCAP_ERROR)
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+                   name, fp->errbuf);
+       else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
+           status == PCAP_ERROR_PERM_DENIED ||
+           status == PCAP_ERROR_PROMISC_PERM_DENIED)
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
+                   name, pcap_statustostr(status), fp->errbuf);
+       else
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+                   name, pcap_statustostr(status));
+       DIAG_ON_FORMAT_TRUNCATION
+       pcap_close(fp);
+       return (NULL);
+}
+
+struct pcap_samp *
+pcap_setsampling(pcap_t *p _USED_FOR_REMOTE)
+{
+#ifdef ENABLE_REMOTE
+       return (&p->rmt_samp);
+#else
+       return (NULL);
+#endif
+}
index 3228a39f15af91c2a636c513287d38ea142c773c..74cac40a0ee099566a0d65c921792d8936103b8c 100644 (file)
@@ -903,10 +903,31 @@ PCAP_API const char *pcap_lib_version(void);
 #endif /* _WIN32/MSDOS/UN*X */
 
 /*
- * Remote capture definitions.
- *
- * These routines are only present if libpcap has been configured to
- * include remote capture support.
+ * APIs.added in WinPcap for remote capture.
+ *
+ * They are present even if remote capture isn't enabled, as they
+ * also support local capture, and as their absence may complicate
+ * code build on macOS 14 with Xcode 15, as that platform supports
+ * "weakly linked symbols":
+ *
+ *    https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
+ *
+ * which are symbols in dynamically-linked shared libraries, declare in
+ * such a fashion that if a program linked against a newer software
+ * development kit (SDK), and using a symbol present in the OS version
+ * for which that SDK is provided, is run on an older OS version that
+ * lacks that symbol, that symbol's value is a NULL pointer.  This
+ * allows those programs to test for the presence of that symbol
+ * by checking whether it's non-null and, if it is, using the symbol,
+ * otherwise not using it.
+ *
+ * (This is a slightly more convenient alternative to the usual
+ * technique used on Windows - and also available, and sometimes
+ * used, on UN*Xes - of loading the library containing the symbol
+ * at run time with dlopen() on UN*Xes and LoadLibrary() on Windows,
+ * looking up the symbol with dlsym() on UN*Xes and GetProcAddress()
+ * on Windows, and using the symbol with the returned pointer if it's
+ * not null.)
  */
 
 /*
index 1aacfd93cfaffb05bf39b555882b8af4582b8c23..d0eba2dddba8dbc4a4f5d30c1adf1ac5035f9e40 100644 (file)
@@ -95,25 +95,18 @@ getpass(const char *prompt)
 }
 #endif
 
-#ifdef ENABLE_REMOTE
 int main(int argc, char **argv)
-#else
-int main(int argc _U_, char **argv _U_)
-#endif
 {
   pcap_if_t *alldevs;
   pcap_if_t *d;
   bpf_u_int32 net, mask;
   int exit_status = 0;
   char errbuf[PCAP_ERRBUF_SIZE+1];
-#ifdef ENABLE_REMOTE
   struct pcap_rmtauth auth;
   char username[128+1];
   char *p;
   char *password;
-#endif
 
-#ifdef ENABLE_REMOTE
   if (argc >= 2)
   {
     if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1)
@@ -139,7 +132,6 @@ int main(int argc _U_, char **argv _U_)
     }
   }
   else
-#endif
   {
     if (pcap_findalldevs(&alldevs, errbuf) == -1)
     {
index a441dda1268f7a0a54fc13939537d59f8960c7db..2db5229fefda2ef044dba3d5a06d46a5e2c6097e 100644 (file)
@@ -59,7 +59,7 @@ main(int argc, char **argv)
 {
        register int op;
        register char *cp, *device;
-       int dorfmon, dopromisc, snaplen, useactivate, bufsize;
+       int dorfmon, dopromisc, snaplen, useactivate, useopen, bufsize;
        char ebuf[PCAP_ERRBUF_SIZE];
        pcap_if_t *devlist;
        pcap_t *pd;
@@ -71,13 +71,14 @@ main(int argc, char **argv)
        snaplen = MAXIMUM_SNAPLEN;
        bufsize = 0;
        useactivate = 0;
+       useopen = 0;
        if ((cp = strrchr(argv[0], '/')) != NULL)
                program_name = cp + 1;
        else
                program_name = argv[0];
 
        opterr = 0;
-       while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) {
+       while ((op = getopt(argc, argv, "i:Iops:aB:")) != -1) {
                switch (op) {
 
                case 'i':
@@ -89,6 +90,10 @@ main(int argc, char **argv)
                        useactivate = 1;        /* required for rfmon */
                        break;
 
+               case 'o':
+                       useopen = 1;
+                       break;
+
                case 'p':
                        dopromisc = 1;
                        break;
@@ -182,6 +187,16 @@ main(int argc, char **argv)
                            pcap_statustostr(status), pcap_geterr(pd));
                } else
                        printf("%s opened successfully\n", device);
+       } else if (useopen) {
+               *ebuf = '\0';
+               pd = pcap_open(device, 65535, PCAP_OPENFLAG_PROMISCUOUS,
+                   1000, NULL, ebuf);
+               if (pd == NULL)
+                       error("%s", ebuf);
+               else if (*ebuf)
+                       warning("%s", ebuf);
+               else
+                       printf("%s opened successfully\n", device);
        } else {
                *ebuf = '\0';
                pd = pcap_open_live(device, 65535, 0, 1000, ebuf);