]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / tcpdump.c
index a7756be5624c0322d403c7b56403da6601509dc6..e59756716de5438422efb332861807e4ed647f06 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
  * combined efforts of Van, Steve McCanne and Craig Leres of LBL.
  */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
-
-/*
- * Some older versions of Mac OS X ship pcap.h from libpcap 0.6 with a
- * libpcap based on 0.8.  That means it has pcap_findalldevs() but the
- * header doesn't define pcap_if_t, meaning that we can't actually *use*
- * pcap_findalldevs().
- */
-#ifdef HAVE_PCAP_FINDALLDEVS
-#ifndef HAVE_PCAP_IF_T
-#undef HAVE_PCAP_FINDALLDEVS
-#endif
+#ifndef TCPDUMP_CONFIG_H_
+#error "The included config.h header is not from the tcpdump build."
 #endif
 
 #include "netdissect-stdinc.h"
@@ -63,9 +52,7 @@ The Regents of the University of California.  All rights reserved.\n";
 
 #include <sys/stat.h>
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 
 #ifdef HAVE_LIBCRYPTO
 #include <openssl/crypto.h>
@@ -153,12 +140,9 @@ The Regents of the University of California.  All rights reserved.\n";
 #include <sys/sysctl.h>
 #endif /* __FreeBSD__ */
 
-#include "netdissect-stdinc.h"
 #include "netdissect.h"
 #include "interface.h"
 #include "addrtoname.h"
-#include "machdep.h"
-#include "pcap-missing.h"
 #include "ascii_strcasecmp.h"
 
 #include "print.h"
@@ -177,22 +161,14 @@ The Regents of the University of California.  All rights reserved.\n";
 #define SIGNAL_REQ_INFO SIGUSR1
 #endif
 
-#if defined(HAVE_PCAP_DUMP_FLUSH) && defined(SIGUSR2)
+#if defined(SIGUSR2)
 #define SIGNAL_FLUSH_PCAP SIGUSR2
 #endif
 
-#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
 static int Bflag;                      /* buffer size */
-#endif
-#ifdef HAVE_PCAP_DUMP_FTELL64
 static int64_t Cflag;                  /* rotate dump files after this many bytes */
-#else
-static long Cflag;                     /* rotate dump files after this many bytes */
-#endif
 static int Cflag_count;                        /* Keep track of which file number we're writing */
-#ifdef HAVE_PCAP_FINDALLDEVS
 static int Dflag;                      /* list available devices and exit */
-#endif
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
 static char *remote_interfaces_source; /* list available devices from this source and exit */
 #endif
@@ -222,20 +198,19 @@ static int jflag = -1;                    /* packet time stamp source */
 #endif
 static int lflag;                      /* line-buffered output */
 static int pflag;                      /* don't go promiscuous */
-#ifdef HAVE_PCAP_SETDIRECTION
 static int Qflag = -1;                 /* restrict captured packet by send/receive direction */
-#endif
-#ifdef HAVE_PCAP_DUMP_FLUSH
 static int Uflag;                      /* "unbuffered" output of dump files */
-#endif
 static int Wflag;                      /* recycle output files after this number of files */
 static int WflagChars;
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
 static char *zflag = NULL;             /* compress each savefile using a specified command (like gzip or bzip2) */
+#endif
 static int timeout = 1000;             /* default timeout = 1000 ms = 1 s */
 #ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
 static int immediate_mode;
 #endif
 static int count_mode;
+static u_int packets_to_skip;
 
 static int infodelay;
 static int infoprint;
@@ -243,9 +218,17 @@ static int infoprint;
 char *program_name;
 
 /* Forwards */
+static int parse_int(const char *argname, const char *string, char **endp,
+    int minval, int maxval, int base);
+static u_int parse_u_int(const char *argname, const char *string, char **endp,
+    u_int minval, u_int maxval, int base);
+static int64_t parse_int64(const char *argname, const char *string,
+    char **endp, int64_t minval, int64_t maxval, int base);
 static void (*setsignal (int sig, void (*func)(int)))(int);
 static void cleanup(int);
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
 static void child_cleanup(int);
+#endif
 static void print_version(FILE *);
 static void print_usage(FILE *);
 
@@ -271,7 +254,6 @@ static void flushpcap(int);
 static void info(int);
 static u_int packets_captured;
 
-#ifdef HAVE_PCAP_FINDALLDEVS
 static const struct tok status_flags[] = {
 #ifdef PCAP_IF_UP
        { PCAP_IF_UP,       "Up"       },
@@ -285,7 +267,6 @@ static const struct tok status_flags[] = {
 #endif
        { 0, NULL }
 };
-#endif
 
 static pcap_t *pd;
 static pcap_dumper_t *pdd = NULL;
@@ -341,7 +322,7 @@ pcap_set_parser_debug(int value)
 }
 
 #define HAVE_PCAP_SET_PARSER_DEBUG
-#endif
+#endif // HAVE_PCAP_SET_PARSER_DEBUG, HAVE_PCAP_DEBUG, HAVE_YYDEBUG
 
 #if defined(HAVE_PCAP_SET_OPTIMIZER_DEBUG)
 /*
@@ -356,7 +337,7 @@ __declspec(dllimport)
 extern
 #endif /* _WIN32 */
 void pcap_set_optimizer_debug(int);
-#endif
+#endif // HAVE_PCAP_SET_OPTIMIZER_DEBUG
 
 static void NORETURN
 exit_tcpdump(const int status)
@@ -433,7 +414,7 @@ show_tstamp_types_and_exit(pcap_t *pc, const char *device)
        pcap_free_tstamp_types(tstamp_types);
        exit_tcpdump(S_SUCCESS);
 }
-#endif
+#endif // HAVE_PCAP_SET_TSTAMP_TYPE
 
 static void NORETURN
 show_dlts_and_exit(pcap_t *pc, const char *device)
@@ -483,13 +464,10 @@ show_dlts_and_exit(pcap_t *pc, const char *device)
                            dlts[i]);
                }
        }
-#ifdef HAVE_PCAP_FREE_DATALINKS
        pcap_free_datalinks(dlts);
-#endif
        exit_tcpdump(S_SUCCESS);
 }
 
-#ifdef HAVE_PCAP_FINDALLDEVS
 static void NORETURN
 show_devices_and_exit(void)
 {
@@ -544,7 +522,7 @@ show_devices_and_exit(void)
                                        break;
                                }
                        }
-#endif
+#endif // PCAP_IF_WIRELESS
                        printf("]");
                }
                printf("\n");
@@ -552,7 +530,6 @@ show_devices_and_exit(void)
        pcap_freealldevs(devlist);
        exit_tcpdump(S_SUCCESS);
 }
-#endif /* HAVE_PCAP_FINDALLDEVS */
 
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
 static void NORETURN
@@ -589,7 +566,7 @@ show_remote_devices_and_exit(void)
        pcap_freealldevs(devlist);
        exit_tcpdump(S_SUCCESS);
 }
-#endif /* HAVE_PCAP_FINDALLDEVS */
+#endif /* HAVE_PCAP_FINDALLDEVS_EX */
 
 /*
  * Short options.
@@ -625,55 +602,41 @@ show_remote_devices_and_exit(void)
  * Set up flags that might or might not be supported depending on the
  * version of libpcap we're using.
  */
-#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
-#define B_FLAG         "B:"
-#define B_FLAG_USAGE   " [ -B size ]"
-#else /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */
-#define B_FLAG
-#define B_FLAG_USAGE
-#endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */
-
-#ifdef HAVE_PCAP_FINDALLDEVS
-#define D_FLAG "D"
-#else
-#define D_FLAG
-#endif
-
-#ifdef HAVE_PCAP_CREATE
-#define I_FLAG         "I"
-#else /* HAVE_PCAP_CREATE */
-#define I_FLAG
-#endif /* HAVE_PCAP_CREATE */
-
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
 #define j_FLAG         "j:"
 #define j_FLAG_USAGE   " [ -j tstamptype ]"
 #define J_FLAG         "J"
-#else /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */
+#else /* HAVE_PCAP_SET_TSTAMP_TYPE */
 #define j_FLAG
 #define j_FLAG_USAGE
 #define J_FLAG
-#endif /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */
+#endif /* HAVE_PCAP_SET_TSTAMP_TYPE */
 
 #ifdef USE_LIBSMI
 #define m_FLAG_USAGE "[ -m module ] ..."
 #endif
 
-#ifdef HAVE_PCAP_SETDIRECTION
-#define Q_FLAG "Q:"
-#define Q_FLAG_USAGE " [ -Q in|out|inout ]"
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
+#define z_FLAG         "z:"
+#define z_FLAG_USAGE    "[ -z postrotate-command ] "
 #else
-#define Q_FLAG
-#define Q_FLAG_USAGE
+#define z_FLAG
+#define z_FLAG_USAGE
 #endif
 
-#ifdef HAVE_PCAP_DUMP_FLUSH
-#define U_FLAG "U"
+#ifdef HAVE_LIBCRYPTO
+#define E_FLAG         "E:"
+#define E_FLAG_USAGE    "[ -E algo:secret ] "
+#define M_FLAG         "M:"
+#define M_FLAG_USAGE   "[ -M secret ] "
 #else
-#define U_FLAG
+#define E_FLAG
+#define E_FLAG_USAGE
+#define M_FLAG
+#define M_FLAG_USAGE
 #endif
 
-#define SHORTOPTS "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpq" Q_FLAG "r:s:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#"
+#define SHORTOPTS "aAbB:c:C:dDe" E_FLAG "fF:G:hHi:I" j_FLAG J_FLAG "KlLm:" M_FLAG "nNOpqQ:r:s:StT:uUvV:w:W:xXy:Y" z_FLAG "Z:#"
 
 /*
  * Long options.
@@ -705,20 +668,19 @@ show_remote_devices_and_exit(void)
 #define OPTION_FP_TYPE                 135
 #define OPTION_COUNT                   136
 #define OPTION_PRINT_SAMPLING          137
+#define OPTION_LENGTHS                 138
+#define OPTION_TIME_T_SIZE             139
+#define OPTION_SKIP                    140
 
 static const struct option longopts[] = {
-#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
        { "buffer-size", required_argument, NULL, 'B' },
-#endif
        { "list-interfaces", no_argument, NULL, 'D' },
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
        { "list-remote-interfaces", required_argument, NULL, OPTION_LIST_REMOTE_INTERFACES },
 #endif
        { "help", no_argument, NULL, 'h' },
        { "interface", required_argument, NULL, 'i' },
-#ifdef HAVE_PCAP_CREATE
        { "monitor-mode", no_argument, NULL, 'I' },
-#endif
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
        { "time-stamp-type", required_argument, NULL, 'j' },
        { "list-time-stamp-types", no_argument, NULL, 'J' },
@@ -732,14 +694,10 @@ static const struct option longopts[] = {
        { "list-data-link-types", no_argument, NULL, 'L' },
        { "no-optimize", no_argument, NULL, 'O' },
        { "no-promiscuous-mode", no_argument, NULL, 'p' },
-#ifdef HAVE_PCAP_SETDIRECTION
        { "direction", required_argument, NULL, 'Q' },
-#endif
        { "snapshot-length", required_argument, NULL, 's' },
        { "absolute-tcp-sequence-numbers", no_argument, NULL, 'S' },
-#ifdef HAVE_PCAP_DUMP_FLUSH
        { "packet-buffered", no_argument, NULL, 'U' },
-#endif
        { "linktype", required_argument, NULL, 'y' },
 #ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
        { "immediate-mode", no_argument, NULL, OPTION_IMMEDIATE_MODE },
@@ -753,12 +711,15 @@ static const struct option longopts[] = {
        { "number", no_argument, NULL, '#' },
        { "print", no_argument, NULL, OPTION_PRINT },
        { "print-sampling", required_argument, NULL, OPTION_PRINT_SAMPLING },
+       { "lengths", no_argument, NULL, OPTION_LENGTHS },
+       { "time-t-size", no_argument, NULL, OPTION_TIME_T_SIZE },
+       { "skip", required_argument, NULL, OPTION_SKIP },
        { "version", no_argument, NULL, OPTION_VERSION },
        { NULL, 0, NULL, 0 }
 };
 
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
-#define LIST_REMOTE_INTERFACES_USAGE "[ --list-remote-interfaces remote-source ]"
+#define LIST_REMOTE_INTERFACES_USAGE " [ --list-remote-interfaces remote-source ]"
 #else
 #define LIST_REMOTE_INTERFACES_USAGE
 #endif
@@ -790,7 +751,7 @@ droproot(const char *username, const char *chroot_dir)
                {
                        int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG);
                        if (ret < 0)
-                               error("capng_change_id(): return %d\n", ret);
+                               error("capng_change_id(): return %d", ret);
                        else
                                fprintf(stderr, "dropped privs to %s\n", username);
                }
@@ -966,7 +927,7 @@ tstamp_precision_to_string(int precision)
                return "unknown";
        }
 }
-#endif
+#endif // HAVE_PCAP_SET_TSTAMP_PRECISION
 
 #ifdef HAVE_CAPSICUM
 /*
@@ -997,7 +958,7 @@ tstamp_precision_to_string(int precision)
  * that requires that it be able to do an F_GETFL fcntl() to read
  * the O_ flags.
  *
- * Tcpdump uses ftell() to determine how much data has been written
+ * tcpdump uses ftell() to determine how much data has been written
  * to a file in order to, when used with -C, determine when it's time
  * to rotate capture files.  ftell() therefore needs to do an lseek()
  * to find out the file offset and must, thanks to the aforementioned
@@ -1036,7 +997,7 @@ set_dumper_capsicum_rights(pcap_dumper_t *p)
                error("unable to limit dump descriptor fcntls");
        }
 }
-#endif
+#endif // HAVE_CAPSICUM
 
 /*
  * Copy arg vector into a new buffer, concatenating arguments with spaces.
@@ -1126,7 +1087,6 @@ read_infile(char *fname)
        return (cp);
 }
 
-#ifdef HAVE_PCAP_FINDALLDEVS
 static long
 parse_interface_number(const char *device)
 {
@@ -1168,7 +1128,7 @@ parse_interface_number(const char *device)
                        /*
                         * No, it's not an ordinal.
                         */
-                       error("Invalid adapter index");
+                       error("Invalid adapter index %s", device);
                }
                return (devnum);
        } else {
@@ -1233,7 +1193,7 @@ _U_
                status = pcap_findalldevs_ex(host_url, NULL, &devlist, ebuf);
                free(host_url);
        } else
-#endif
+#endif // HAVE_PCAP_FINDALLDEVS_EX
        status = pcap_findalldevs(&devlist, ebuf);
        if (status < 0)
                error("%s", ebuf);
@@ -1243,13 +1203,15 @@ _U_
        for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
            i++, dev = dev->next)
                ;
-       if (dev == NULL)
-               error("Invalid adapter index");
+       if (dev == NULL) {
+               pcap_freealldevs(devlist);
+               error("Invalid adapter index %ld: only %ld interfaces found",
+                   devnum, i);
+       }
        device = strdup(dev->name);
        pcap_freealldevs(devlist);
        return (device);
 }
-#endif
 
 #ifdef HAVE_PCAP_OPEN
 /*
@@ -1263,10 +1225,8 @@ static pcap_t *
 open_interface(const char *device, netdissect_options *ndo, char *ebuf)
 {
        pcap_t *pc;
-#ifdef HAVE_PCAP_CREATE
        int status;
        char *cp;
-#endif
 
 #ifdef HAVE_PCAP_OPEN
        /*
@@ -1312,7 +1272,6 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
        }
 #endif /* HAVE_PCAP_OPEN */
 
-#ifdef HAVE_PCAP_CREATE
        pc = pcap_create(device, ebuf);
        if (pc == NULL) {
                /*
@@ -1412,6 +1371,11 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
                        error("%s: %s\n(%s)", device,
                            pcap_statustostr(status), cp);
+#ifdef PCAP_ERROR_CAPTURE_NOTSUP
+               else if (status == PCAP_ERROR_CAPTURE_NOTSUP && *cp != '\0')
+                       error("%s: %s\n(%s)", device,
+                           pcap_statustostr(status), cp);
+#endif
 #ifdef __FreeBSD__
                else if (status == PCAP_ERROR_RFMON_NOTSUP &&
                    strncmp(device, "wlan", 4) == 0) {
@@ -1429,13 +1393,13 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                         * specific case would be an error message that looks a bit odd.
                         */
                        newdev[strlen(newdev)-1]++;
-                       error("%s is not a monitor mode VAP\n"
+                       error("%s is not a monitor mode VAP"
                            "To create a new monitor mode VAP use:\n"
                            "  ifconfig %s create wlandev %s wlanmode monitor\n"
                            "and use %s as the tcpdump interface",
                            device, newdev, parent, newdev);
                }
-#endif
+#endif // __FreeBSD__
                else
                        error("%s: %s", device,
                            pcap_statustostr(status));
@@ -1457,37 +1421,12 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                        warning("%s: %s", device,
                            pcap_statustostr(status));
        }
-#ifdef HAVE_PCAP_SETDIRECTION
        if (Qflag != -1) {
                status = pcap_setdirection(pc, Qflag);
                if (status != 0)
                        error("%s: pcap_setdirection() failed: %s",
                              device,  pcap_geterr(pc));
        }
-#endif /* HAVE_PCAP_SETDIRECTION */
-#else /* HAVE_PCAP_CREATE */
-       *ebuf = '\0';
-       /*
-        * If no snapshot length was specified, or a length of 0 was
-        * specified, default to 256KB.
-        */
-       if (ndo->ndo_snaplen == 0)
-               ndo->ndo_snaplen = MAXIMUM_SNAPLEN;
-       pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, timeout, ebuf);
-       if (pc == NULL) {
-               /*
-                * If this failed with "No such device", that means
-                * the interface doesn't exist; return NULL, so that
-                * the caller can see whether the device name is
-                * actually an interface index.
-                */
-               if (strstr(ebuf, "No such device") != NULL)
-                       return (NULL);
-               error("%s", ebuf);
-       }
-       if (*ebuf)
-               warning("%s", ebuf);
-#endif /* HAVE_PCAP_CREATE */
 
        return (pc);
 }
@@ -1515,11 +1454,8 @@ main(int argc, char **argv)
        const char *chroot_dir = NULL;
 #endif
        char *ret = NULL;
-       char *end;
-#ifdef HAVE_PCAP_FINDALLDEVS
        pcap_if_t *devlist;
        long devnum;
-#endif
        int status;
        FILE *VFile;
 #ifdef HAVE_CAPSICUM
@@ -1535,6 +1471,157 @@ main(int argc, char **argv)
        netdissect_options Ndo;
        netdissect_options *ndo = &Ndo;
 
+#ifdef _WIN32
+       /*
+        * We need to look for wpcap.dll in \Windows\System32\Npcap first,
+        * as either:
+        *
+        *  1) WinPcap isn't installed and Npcap isn't installed in "WinPcap
+        *     API-compatible Mode", so there's no wpcap.dll in
+        *     \Windows\System32, only in \Windows\System32\Npcap;
+        *
+        *  2) WinPcap is installed and Npcap isn't installed in "WinPcap
+        *     API-compatible Mode", so the wpcap.dll in \Windows\System32
+        *     is a WinPcap DLL, but we'd prefer an Npcap DLL (we should
+        *     work with either one if we're configured against WinPcap,
+        *     and we'll probably require Npcap if we're configured against
+        *     it), and that's in \Windows\System32\Npcap;
+        *
+        *  3) Npcap is installed in "WinPcap API-compatible Mode", so both
+        *     \Windows\System32 and \Windows\System32\Npcap have an Npcap
+        *     wpcap.dll.
+        *
+        * Unfortunately, Windows has no notion of an rpath, so we can't
+        * set the rpath to include \Windows\System32\Npcap at link time;
+        * what we need to do is to link wpcap as a delay-load DLL and
+        * add \Windows\System32\Npcap to the DLL search path early in
+        * main() with a call to SetDllDirectory().
+        *
+        * The same applies to packet.dll.
+        *
+        * We add \Windows\System32\Npcap here.
+        *
+        * See https://npcap.com/guide/npcap-devguide.html#npcap-feature-native-dll-implicitly
+        */
+       WCHAR *dll_directory = NULL;
+       size_t dll_directory_buf_len = 0;       /* units of bytes */
+       UINT system_directory_buf_len = 0;      /* units of WCHARs */
+       UINT system_directory_len;              /* units of WCHARs */
+       static const WCHAR npcap[] = L"\\Npcap";
+
+       /*
+        * Get the system directory path, in UTF-16, into a buffer that's
+        * large enough for that directory path plus "\Npcap".
+        *
+        * String manipulation in C, plus fetching a variable-length
+        * string into a buffer whose size is fixed at the time of
+        * the call, with an oddball return value (see below), is just
+        * a huge bag of fun.
+        *
+        * And it's even more fun when dealing with UTF-16, so that the
+        * buffer sizes used in GetSystemDirectoryW() are in different
+        * units from the buffer sizes used in realloc()!   We maintain
+        * all sizes/length in units of bytes, not WCHARs, so that our
+        * heads don't explode.
+        */
+       for (;;) {
+               /*
+                * Try to fetch the system directory.
+                *
+                * GetSystemDirectoryW() expects a buffer size in units
+                * of WCHARs, not bytes, and returns a directory path
+                * length in units of WCHARs, not bytes.
+                *
+                * For extra fun, if GetSystemDirectoryW() succeeds,
+                * the return value is the length of the directory
+                * path in units of WCHARs, *not* including the
+                * terminating '\0', but if it fails because the
+                * path string wouldn't fit, the return value is
+                * the length of the directory path in units of WCHARs,
+                * *including* the terminating '\0'.
+                */
+               system_directory_len = GetSystemDirectoryW(dll_directory,
+                   system_directory_buf_len);
+               if (system_directory_len == 0)
+                       error("GetSystemDirectoryW() failed");
+
+               /*
+                * Did the directory path fit in the buffer?
+                *
+                * As per the above, this means that the return value
+                * *plus 1*, so that the terminating '\0' is counted,
+                * is <= the buffer size.
+                *
+                * (If the directory path, complete with the terminating
+                * '\0', fits *exactly*, the return value would be the
+                * size of the buffer minus 1, as it doesn't count the
+                * terminating '\0', so the test below would succeed.
+                *
+                * If everything *but* the terminating '\0' fits,
+                * the return value would be the size of the buffer + 1,
+                * i.e., the size that the string in question would
+                * have required.
+                *
+                * The astute reader will note that returning the
+                * size of the buffer is not one of the two cases
+                * above, and should never happen.)
+                */
+               if ((system_directory_len + 1) <= system_directory_buf_len) {
+                       /*
+                        * No.  We have a buffer that's large enough
+                        * for our purposes.
+                        */
+                       break;
+               }
+
+               /*
+                * Yes.  Grow the buffer.
+                *
+                * The space we'll need in the buffer for the system
+                * directory, in units of WCHARs, is system_directory_len,
+                * as that's the length of the system directory path
+                * including the terminating '\0'.
+                */
+               system_directory_buf_len = system_directory_len;
+
+               /*
+                * The size of the DLL directory buffer, in *bytes*, must
+                * be the number of WCHARs taken by the system directory,
+                * *minus* the terminating '\0' (as we'll overwrite that
+                * with the "\" of the "\Npcap" string), multiplied by
+                * sizeof(WCHAR) to convert it to the number of bytes,
+                * plus the size of the "\Npcap" string, in bytes (which
+                * will include the terminating '\0', as that will become
+                * the DLL path's terminating '\0').
+                */
+               dll_directory_buf_len =
+                   ((system_directory_len - 1)*sizeof(WCHAR)) + sizeof npcap;
+               dll_directory = realloc(dll_directory, dll_directory_buf_len);
+               if (dll_directory == NULL)
+                       error("Can't allocate string for Npcap directory");
+       }
+
+       /*
+        * OK, that worked.
+        *
+        * Now append \Npcap.  We add the length of the system directory path,
+        * in WCHARs, *not* including the terminating '\0' (which, since
+        * GetSystemDirectoryW() succeeded, is the return value of
+        * GetSystemDirectoryW(), as per the above), to the pointer to the
+        * beginning of the path, to go past the end of the system directory
+        * to point to the terminating '\0'.
+        */
+       memcpy(dll_directory + system_directory_len, npcap, sizeof npcap);
+
+       /*
+        * Now add that as a system DLL directory.
+        */
+       if (!SetDllDirectoryW(dll_directory))
+               error("SetDllDirectory failed");
+
+       free(dll_directory);
+#endif // _WIN32
+
        /*
         * Initialize the netdissect code.
         */
@@ -1565,16 +1652,6 @@ main(int argc, char **argv)
                error("Attempting to initialize Winsock failed");
 #endif
 
-       /*
-        * On platforms where the CPU doesn't support unaligned loads,
-        * force unaligned accesses to abort with SIGBUS, rather than
-        * being fixed up (slowly) by the OS kernel; on those platforms,
-        * misaligned accesses are bugs, and we want tcpdump to crash so
-        * that the bugs are reported.
-        */
-       if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0)
-               error("%s", ebuf);
-
        /*
         * An explicit tzset() call is usually not needed as it happens
         * implicitly the first time we call localtime() or mktime(),
@@ -1598,29 +1675,25 @@ main(int argc, char **argv)
                        ++ndo->ndo_bflag;
                        break;
 
-#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
                case 'B':
-                       Bflag = atoi(optarg)*1024;
-                       if (Bflag <= 0)
-                               error("invalid packet buffer size %s", optarg);
+                       Bflag = parse_int("packet buffer size", optarg, NULL, 1,
+                           INT_MAX, 10);
+                       /*
+                        * Will multiplying it by 1024 overflow?
+                        */
+                       if (Bflag > INT_MAX / 1024)
+                               error("packet buffer size %s is too large", optarg);
+                       Bflag *= 1024;
                        break;
-#endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */
 
                case 'c':
-                       cnt = atoi(optarg);
-                       if (cnt <= 0)
-                               error("invalid packet count %s", optarg);
+                       cnt = parse_int("packet count", optarg, NULL, 1,
+                           INT_MAX, 10);
                        break;
 
                case 'C':
-                       errno = 0;
-#ifdef HAVE_PCAP_DUMP_FTELL64
-                       Cflag = strtoint64_t(optarg, &endp, 10);
-#else
-                       Cflag = strtol(optarg, &endp, 10);
-#endif
-                       if (endp == optarg || errno != 0 || Cflag <= 0)
-                               error("invalid file size %s", optarg);
+                       Cflag = parse_int64("file size", optarg, &endp, 1,
+                           INT64_MAX, 10);
 
                        if (*endp == '\0') {
                                /*
@@ -1665,7 +1738,7 @@ main(int argc, char **argv)
                                        break;
 
                                default:
-                                       error("invalid file size %s", optarg);
+                                       error("invalid file size %s (invalid units)", optarg);
                                }
 
                                /*
@@ -1676,7 +1749,7 @@ main(int argc, char **argv)
                                endp++;
                                if (*endp != '\0') {
                                        /* Yes - error */
-                                       error("invalid file size %s", optarg);
+                                       error("invalid file size %s (invalid units)", optarg);
                                }
                        }
 
@@ -1684,7 +1757,7 @@ main(int argc, char **argv)
                         * Will multiplying it by multiplier overflow?
                         */
 #ifdef HAVE_PCAP_DUMP_FTELL64
-                       if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffff) / Cflagmult)
+                       if (Cflag > INT64_MAX / Cflagmult)
 #else
                        if (Cflag > LONG_MAX / Cflagmult)
 #endif
@@ -1696,11 +1769,9 @@ main(int argc, char **argv)
                        ++dflag;
                        break;
 
-#ifdef HAVE_PCAP_FINDALLDEVS
                case 'D':
                        Dflag++;
                        break;
-#endif
 
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
                case OPTION_LIST_REMOTE_INTERFACES:
@@ -1716,12 +1787,11 @@ main(int argc, char **argv)
                        ++ndo->ndo_eflag;
                        break;
 
+#ifdef HAVE_LIBCRYPTO
                case 'E':
-#ifndef HAVE_LIBCRYPTO
-                       warning("crypto code not compiled in");
-#endif
                        ndo->ndo_espsecret = optarg;
                        break;
+#endif
 
                case 'f':
                        ++ndo->ndo_fflag;
@@ -1732,9 +1802,8 @@ main(int argc, char **argv)
                        break;
 
                case 'G':
-                       Gflag = atoi(optarg);
-                       if (Gflag < 0)
-                               error("invalid number of seconds %s", optarg);
+                       Gflag = parse_int("number of seconds", optarg, NULL, 0,
+                           INT_MAX, 10);
 
                         /* We will create one file initially. */
                         Gflag_count = 0;
@@ -1749,7 +1818,7 @@ main(int argc, char **argv)
                case 'h':
                        print_usage(stdout);
                        exit_tcpdump(S_SUCCESS);
-                       break;
+                       /* NOTREACHED */
 
                case 'H':
                        ++ndo->ndo_Hflag;
@@ -1759,11 +1828,9 @@ main(int argc, char **argv)
                        device = optarg;
                        break;
 
-#ifdef HAVE_PCAP_CREATE
                case 'I':
                        ++Iflag;
                        break;
-#endif /* HAVE_PCAP_CREATE */
 
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
                case 'j':
@@ -1790,11 +1857,7 @@ main(int argc, char **argv)
                         */
                        setvbuf(stdout, NULL, _IONBF, 0);
 #else /* _WIN32 */
-#ifdef HAVE_SETLINEBUF
-                       setlinebuf(stdout);
-#else
                        setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
 #endif /* _WIN32 */
                        lflag = 1;
                        break;
@@ -1814,13 +1877,12 @@ main(int argc, char **argv)
                        }
                        break;
 
+#ifdef HAVE_LIBCRYPTO
                case 'M':
                        /* TCP-MD5 shared secret */
-#ifndef HAVE_LIBCRYPTO
-                       warning("crypto code not compiled in");
-#endif
                        ndo->ndo_sigsecret = optarg;
                        break;
+#endif
 
                case 'n':
                        ++ndo->ndo_nflag;
@@ -1843,7 +1905,6 @@ main(int argc, char **argv)
                        ++ndo->ndo_suppress_default_print;
                        break;
 
-#ifdef HAVE_PCAP_SETDIRECTION
                case 'Q':
                        if (ascii_strcasecmp(optarg, "in") == 0)
                                Qflag = PCAP_D_IN;
@@ -1854,18 +1915,14 @@ main(int argc, char **argv)
                        else
                                error("unknown capture direction '%s'", optarg);
                        break;
-#endif /* HAVE_PCAP_SETDIRECTION */
 
                case 'r':
                        RFileName = optarg;
                        break;
 
                case 's':
-                       ndo->ndo_snaplen = (int)strtol(optarg, &end, 0);
-                       if (optarg == end || *end != '\0'
-                           || ndo->ndo_snaplen < 0 || ndo->ndo_snaplen > MAXIMUM_SNAPLEN)
-                               error("invalid snaplen %s (must be >= 0 and <= %d)",
-                                     optarg, MAXIMUM_SNAPLEN);
+                       ndo->ndo_snaplen = parse_int("snaplen", optarg, NULL,
+                           0, MAXIMUM_SNAPLEN, 0);
                        break;
 
                case 'S':
@@ -1927,11 +1984,9 @@ main(int argc, char **argv)
                        ++ndo->ndo_uflag;
                        break;
 
-#ifdef HAVE_PCAP_DUMP_FLUSH
                case 'U':
                        ++Uflag;
                        break;
-#endif
 
                case 'v':
                        ++ndo->ndo_vflag;
@@ -1946,9 +2001,8 @@ main(int argc, char **argv)
                        break;
 
                case 'W':
-                       Wflag = atoi(optarg);
-                       if (Wflag <= 0)
-                               error("invalid number of output files %s", optarg);
+                       Wflag = parse_int("number of output files", optarg,
+                           NULL, 1, INT_MAX, 10);
                        WflagChars = getWflagChars(Wflag);
                        break;
 
@@ -1978,9 +2032,12 @@ main(int argc, char **argv)
                        }
                        break;
 #endif
+
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
                case 'z':
                        zflag = optarg;
                        break;
+#endif
 
                case 'Z':
                        username = optarg;
@@ -1990,10 +2047,18 @@ main(int argc, char **argv)
                        ndo->ndo_packet_number = 1;
                        break;
 
+               case OPTION_LENGTHS:
+                       ndo->ndo_lengths = 1;
+                       break;
+
+               case OPTION_TIME_T_SIZE:
+                       printf("%zu\n", sizeof(time_t) * 8);
+                       return 0;
+
                case OPTION_VERSION:
                        print_version(stdout);
                        exit_tcpdump(S_SUCCESS);
-                       break;
+                       /* NOTREACHED */
 
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
                case OPTION_TSTAMP_PRECISION:
@@ -2016,9 +2081,13 @@ main(int argc, char **argv)
                case OPTION_PRINT_SAMPLING:
                        print = 1;
                        ++ndo->ndo_Sflag;
-                       ndo->ndo_print_sampling = atoi(optarg);
-                       if (ndo->ndo_print_sampling <= 0)
-                               error("invalid print sampling %s", optarg);
+                       ndo->ndo_print_sampling = parse_int("print sampling",
+                           optarg, NULL, 1, INT_MAX, 10);
+                       break;
+
+               case OPTION_SKIP:
+                       packets_to_skip = parse_u_int("packet skip count",
+                           optarg, NULL, 0, INT_MAX, 0);
                        break;
 
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
@@ -2052,10 +2121,29 @@ main(int argc, char **argv)
                        /* NOTREACHED */
                }
 
-#ifdef HAVE_PCAP_FINDALLDEVS
+       if (ndo->ndo_Aflag && ndo->ndo_xflag)
+               error("-A and -x[x] are mutually exclusive.");
+       if (ndo->ndo_Aflag && ndo->ndo_Xflag)
+               error("-A and -X[X] are mutually exclusive.");
+       if (ndo->ndo_xflag && ndo->ndo_Xflag)
+               error("-x[x] and -X[X] are mutually exclusive.");
+       if (Cflag != 0 && WFileName == NULL)
+               error("-C cannot be used without -w.");
+       if (Gflag != 0 && WFileName == NULL)
+               error("-G cannot be used without -w.");
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
+       if (zflag != NULL && (WFileName == NULL || (Cflag == 0 && Gflag == 0)))
+               error("-z cannot be used without -w and (-C or -G).");
+#endif
+
+       if (cnt != -1)
+               if ((int)packets_to_skip > (INT_MAX - cnt))
+                       // cnt + (int)packets_to_skip used in pcap_loop() call
+                       error("Overflow (-c count) %d + (--skip count) %d", cnt,
+                             (int)packets_to_skip);
+
        if (Dflag)
                show_devices_and_exit();
-#endif
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
        if (remote_interfaces_source != NULL)
                show_remote_devices_and_exit();
@@ -2073,11 +2161,11 @@ main(int argc, char **argv)
 
        default: /* Not supported */
                error("only -t, -tt, -ttt, -tttt and -ttttt are supported");
-               break;
+               /* NOTREACHED */
        }
 
        if (ndo->ndo_fflag != 0 && (VFileName != NULL || RFileName != NULL))
-               error("-f can not be used with -V or -r");
+               error("-f cannot be used with -V or -r.");
 
        if (VFileName != NULL && RFileName != NULL)
                error("-V and -r are mutually exclusive.");
@@ -2145,11 +2233,11 @@ main(int argc, char **argv)
                                VFile = fopen(VFileName, "r");
 
                        if (VFile == NULL)
-                               error("Unable to open file: %s\n", pcap_strerror(errno));
+                               error("Unable to open file: %s", pcap_strerror(errno));
 
                        ret = get_next_file(VFile, VFileLine);
                        if (!ret)
-                               error("Nothing in %s\n", VFileName);
+                               error("Nothing in %s", VFileName);
                        RFileName = VFileLine;
                }
 
@@ -2179,7 +2267,7 @@ main(int argc, char **argv)
                                pcap_datalink_val_to_description(dlt));
                }
                fprintf(stderr, ", snapshot length %d\n", pcap_snapshot(pd));
-#ifdef DLT_LINUX_SLL2
+#if defined(DLT_LINUX_SLL2) && defined(__linux__)
                if (dlt == DLT_LINUX_SLL2)
                        fprintf(stderr, "Warning: interface names might be incorrect\n");
 #endif
@@ -2214,7 +2302,6 @@ main(int argc, char **argv)
                        /*
                         * No interface was specified.  Pick one.
                         */
-#ifdef HAVE_PCAP_FINDALLDEVS
                        /*
                         * Find the list of interfaces, and pick
                         * the first interface.
@@ -2225,15 +2312,6 @@ main(int argc, char **argv)
                                error("no interfaces available for capture");
                        device = strdup(devlist->name);
                        pcap_freealldevs(devlist);
-#else /* HAVE_PCAP_FINDALLDEVS */
-                       /*
-                        * Use whatever interface pcap_lookupdev()
-                        * chooses.
-                        */
-                       device = pcap_lookupdev(ebuf);
-                       if (device == NULL)
-                               error("%s", ebuf);
-#endif
                }
 
                /*
@@ -2248,7 +2326,6 @@ main(int argc, char **argv)
                         * a 1-based index in the list of
                         * interfaces.
                         */
-#ifdef HAVE_PCAP_FINDALLDEVS
                        devnum = parse_interface_number(device);
                        if (devnum == -1) {
                                /*
@@ -2270,13 +2347,6 @@ main(int argc, char **argv)
                        pd = open_interface(device, ndo, ebuf);
                        if (pd == NULL)
                                error("%s", ebuf);
-#else /* HAVE_PCAP_FINDALLDEVS */
-                       /*
-                        * We can't get a list of interfaces; just
-                        * fail.
-                        */
-                       error("%s", ebuf);
-#endif /* HAVE_PCAP_FINDALLDEVS */
                }
 
                /*
@@ -2287,35 +2357,17 @@ main(int argc, char **argv)
                if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
                        fprintf(stderr, "Warning: setgid/setuid failed !\n");
 #endif /* _WIN32 */
-#if !defined(HAVE_PCAP_CREATE) && defined(_WIN32)
-               if(Bflag != 0)
-                       if(pcap_setbuff(pd, Bflag)==-1){
-                               error("%s", pcap_geterr(pd));
-                       }
-#endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */
                if (Lflag)
                        show_dlts_and_exit(pd, device);
                if (yflag_dlt >= 0) {
-#ifdef HAVE_PCAP_SET_DATALINK
                        if (pcap_set_datalink(pd, yflag_dlt) < 0)
                                error("%s", pcap_geterr(pd));
-#else
-                       /*
-                        * We don't actually support changing the
-                        * data link type, so we only let them
-                        * set it to what it already is.
-                        */
-                       if (yflag_dlt != pcap_datalink(pd)) {
-                               error("%s is not one of the DLTs supported by this device\n",
-                                     yflag_dlt_name);
-                       }
-#endif
                        (void)fprintf(stderr, "%s: data link type %s\n",
                                      program_name,
                                      pcap_datalink_val_to_name(yflag_dlt));
                        (void)fflush(stderr);
                }
-#if defined(DLT_LINUX_SLL2) && defined(HAVE_PCAP_SET_DATALINK)
+#if defined(DLT_LINUX_SLL2)
                else {
                        /*
                         * Attempt to set default linktype to
@@ -2326,8 +2378,11 @@ main(int argc, char **argv)
                         * on; this may be a non-Linux "any" device
                         * that doesn't support DLT_LINUX_SLL2.
                         */
-                       if (strcmp(device, "any") == 0)
+                       if (strcmp(device, "any") == 0) {
+DIAG_OFF_WARN_UNUSED_RESULT
                                (void) pcap_set_datalink(pd, DLT_LINUX_SLL2);
+DIAG_ON_WARN_UNUSED_RESULT
+                       }
                }
 #endif
                i = pcap_snapshot(pd);
@@ -2354,7 +2409,11 @@ main(int argc, char **argv)
 #ifdef HAVE_PCAP_SET_OPTIMIZER_DEBUG
        pcap_set_optimizer_debug(dflag);
 #endif
-       if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+       /*
+        * netmask is in network byte order, pcap_compile() takes it
+        * in host byte order.
+        */
+       if (pcap_compile(pd, &fcode, cmdbuf, Oflag, ntohl(netmask)) < 0)
                error("%s", pcap_geterr(pd));
        if (dflag) {
                bpf_dump(&fcode, dflag);
@@ -2369,6 +2428,7 @@ main(int argc, char **argv)
                capdns = capdns_setup();
 #endif /* HAVE_CASPER */
 
+       // Both localnet and netmask are in network byte order.
        init_print(ndo, localnet, netmask);
 
 #ifndef _WIN32
@@ -2381,7 +2441,21 @@ main(int argc, char **argv)
 #endif
        /* Cooperate with nohup(1) */
 #ifndef _WIN32
+       /*
+        * In illumos /usr/include/sys/iso/signal_iso.h causes Clang to
+        * generate a -Wstrict-prototypes warning here, see [1].  The
+        * __illumos__ macro is available since at least GCC 11 and Clang 13,
+        * see [2].
+        * 1: https://www.illumos.org/issues/16344
+        * 2: https://www.illumos.org/issues/13726
+        */
+#ifdef __illumos__
+       DIAG_OFF_STRICT_PROTOTYPES
+#endif /* __illumos__ */
        if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
+#ifdef __illumos__
+       DIAG_ON_STRICT_PROTOTYPES
+#endif /* __illumos__ */
                (void)setsignal(SIGHUP, oldhandler);
 #endif /* _WIN32 */
 
@@ -2394,7 +2468,7 @@ main(int argc, char **argv)
         * devices, and can't just give users that permission,
         * you'd make tcpdump set-UID or set-GID).
         *
-        * Tcpdump doesn't necessarily write only to one savefile;
+        * tcpdump doesn't necessarily write only to one savefile;
         * the general only way to allow a -Z instance to write to
         * savefiles as the user under whose UID it's run, rather
         * than as the user specified with -Z, would thus be to switch
@@ -2570,10 +2644,8 @@ DIAG_ON_ASSIGN_ENUM
                } else
                        dumpinfo.ndo = NULL;
 
-#ifdef HAVE_PCAP_DUMP_FLUSH
                if (Uflag)
                        pcap_dump_flush(pdd);
-#endif
        } else {
                dlt = pcap_datalink(pd);
                ndo->ndo_if_printer = get_if_printer(dlt);
@@ -2670,7 +2742,9 @@ DIAG_ON_ASSIGN_ENUM
 #endif /* HAVE_CAPSICUM */
 
        do {
-               status = pcap_loop(pd, cnt, callback, pcap_userdata);
+               status = pcap_loop(pd,
+                                  (cnt == -1 ? -1 : cnt + (int)packets_to_skip),
+                                  callback, pcap_userdata);
                if (WFileName == NULL) {
                        /*
                         * We're printing packets.  Flush the printed output,
@@ -2758,7 +2832,11 @@ DIAG_ON_ASSIGN_ENUM
                                        ndo->ndo_if_printer = get_if_printer(dlt);
                                        /* Free the old filter */
                                        pcap_freecode(&fcode);
-                                       if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+                                       /*
+                                        * netmask is in network byte order, pcap_compile() takes it
+                                        * in host byte order.
+                                        */
+                                       if (pcap_compile(pd, &fcode, cmdbuf, Oflag, ntohl(netmask)) < 0)
                                                error("%s", pcap_geterr(pd));
                                }
 
@@ -2795,6 +2873,134 @@ DIAG_ON_ASSIGN_ENUM
        exit_tcpdump(status == -1 ? S_ERR_HOST_PROGRAM : S_SUCCESS);
 }
 
+/*
+ * Routines to parse numerical command-line arguments and check for
+ * errors, including "too large for that type".
+ */
+static int
+parse_int(const char *argname, const char *string, char **endpp,
+    int minval, int maxval, int base)
+{
+       long val;
+       char *endp;
+
+       errno = 0;
+       val = strtol(string, &endp, base);
+
+       /*
+        * Did it either not parse any of the string, find extra stuff
+        * at the end that the caller isn't interested in, or get
+        * another parsing error?
+        */
+       if (string == endp || (endpp == NULL && *endp != '\0') ||
+           (val == 0 && errno == EINVAL)) {
+               error("invalid %s \"%s\" (not a valid number)", argname,
+                   string);
+       }
+
+       /*
+        * Did it get a value that's out of range?
+        */
+       if (((val == LONG_MAX || val == LONG_MIN) && errno == ERANGE) ||
+           val < minval || val > maxval) {
+               error("invalid %s %s (must be >= %d and <= %d)",
+                   argname, string, minval, maxval);
+       }
+
+       /*
+        * OK, it passes all the tests.
+        */
+       if (endpp != NULL)
+               *endpp = endp;
+       return ((int)val);
+}
+
+static u_int
+parse_u_int(const char *argname, const char *string, char **endpp,
+    u_int minval, u_int maxval, int base)
+{
+       unsigned long val;
+       char *endp;
+
+       errno = 0;
+
+       /*
+        * strtoul() does *NOT* report an error if the string
+        * begins with a minus sign. We do.
+        */
+       if (*string == '-') {
+               error("invalid %s \"%s\" (not a valid unsigned number)",
+                   argname, string);
+       }
+
+       val = strtoul(string, &endp, base);
+
+       /*
+        * Did it either not parse any of the string, find extra stuff
+        * at the end that the caller isn't interested in, or get
+        * another parsing error?
+        */
+       if (string == endp || (endpp == NULL && *endp != '\0') ||
+           (val == 0 && errno == EINVAL)) {
+               error("invalid %s \"%s\" (not a valid unsigned number)",
+                   argname, string);
+       }
+
+       /*
+        * Did it get a value that's out of range?
+        */
+       if ((val == ULONG_MAX && errno == ERANGE) ||
+           val < minval || val > maxval) {
+               error("invalid %s %s (must be >= %u and <= %u)",
+                   argname, string, minval, maxval);
+       }
+
+       /*
+        * OK, it passes all the tests.
+        */
+       if (endpp != NULL)
+               *endpp = endp;
+       return ((u_int)val);
+}
+
+static int64_t
+parse_int64(const char *argname, const char *string, char **endpp,
+    int64_t minval, int64_t maxval, int base)
+{
+       intmax_t val;
+       char *endp;
+
+       errno = 0;
+       val = strtoimax(string, &endp, base);
+
+       /*
+        * Did it either not parse any of the string, find extra stuff
+        * at the end that the caller isn't interested in, or get
+        * another parsing error?
+        */
+       if (string == endp || (endpp == NULL && *endp != '\0') ||
+           (val == 0 && errno == EINVAL)) {
+               error("invalid %s \"%s\" (not a valid number)", argname,
+                   string);
+       }
+
+       /*
+        * Did it get a value that's out of range?
+        */
+       if (((val == INTMAX_MAX || val == INTMAX_MIN) && errno == ERANGE) ||
+           val < minval || val > maxval) {
+               error("invalid %s %s (must be >= %" PRId64 " and <= %" PRId64 ")",
+                   argname, string, minval, maxval);
+       }
+
+       /*
+        * OK, it passes all the tests.
+        */
+       if (endpp != NULL)
+               *endpp = endp;
+       return ((int64_t)val);
+}
+
 /*
  * Catch a signal.
  */
@@ -2818,7 +3024,14 @@ static void
                )
                new.sa_flags = SA_RESTART;
        if (sigaction(sig, &new, &old) < 0)
+               /* The same workaround as for SIG_DFL above. */
+#ifdef __illumos__
+               DIAG_OFF_STRICT_PROTOTYPES
+#endif /* __illumos__ */
                return (SIG_ERR);
+#ifdef __illumos__
+               DIAG_ON_STRICT_PROTOTYPES
+#endif /* __illumos__ */
        return (old.sa_handler);
 #endif
 }
@@ -2843,7 +3056,6 @@ cleanup(int signo _U_)
        setitimer(ITIMER_REAL, &timer, NULL);
 #endif /* _WIN32 */
 
-#ifdef HAVE_PCAP_BREAKLOOP
        /*
         * We have "pcap_breakloop()"; use it, so that we do as little
         * as possible in the signal handler (it's probably not safe
@@ -2851,25 +3063,6 @@ cleanup(int signo _U_)
         * the ANSI C standard doesn't say it is).
         */
        pcap_breakloop(pd);
-#else
-       /*
-        * We don't have "pcap_breakloop()"; this isn't safe, but
-        * it's the best we can do.  Print the summary if we're
-        * not reading from a savefile - i.e., if we're doing a
-        * live capture - and exit.
-        */
-       if (pd != NULL && pcap_file(pd) == NULL) {
-               /*
-                * We got interrupted, so perhaps we didn't
-                * manage to finish a line we were printing.
-                * Print an extra newline, just in case.
-                */
-               putchar('\n');
-               (void)fflush(stdout);
-               info(1);
-       }
-       exit_tcpdump(S_SUCCESS);
-#endif
 }
 
 /*
@@ -2943,8 +3136,8 @@ compress_savefile(const char *filename)
        child = fork_subprocess();
        if (child == -1) {
                fprintf(stderr,
-                       "compress_savefile: fork failed: %s\n",
-                       pcap_strerror(errno));
+                       "%s: fork failed: %s\n",
+                       __func__, pcap_strerror(errno));
                return;
        }
        if (child != 0) {
@@ -2963,24 +3156,69 @@ compress_savefile(const char *filename)
 #endif
        if (execlp(zflag, zflag, filename, (char *)NULL) == -1)
                fprintf(stderr,
-                       "compress_savefile: execlp(%s, %s) failed: %s\n",
-                       zflag,
-                       filename,
-                       pcap_strerror(errno));
+                       "%s: execlp(%s, %s) failed: %s\n",
+                       __func__, zflag, filename, pcap_strerror(errno));
 #ifdef HAVE_FORK
        exit(S_ERR_HOST_PROGRAM);
 #else
        _exit(S_ERR_HOST_PROGRAM);
 #endif
 }
-#else  /* HAVE_FORK && HAVE_VFORK */
+#endif /* HAVE_FORK || HAVE_VFORK */
+
 static void
-compress_savefile(const char *filename)
+close_old_dump_file(struct dump_info *dump_info)
 {
-       fprintf(stderr,
-               "compress_savefile failed. Functionality not implemented under your system\n");
+       /*
+        * Close the current file and open a new one.
+        */
+       pcap_dump_close(dump_info->pdd);
+
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
+       /*
+        * Compress the file we just closed, if the user asked for it.
+        */
+       if (zflag != NULL)
+               compress_savefile(dump_info->CurrentFileName);
+#endif
+}
+
+static void
+open_new_dump_file(struct dump_info *dump_info)
+{
+#ifdef HAVE_CAPSICUM
+       FILE *fp;
+       int fd;
+#endif
+
+#ifdef HAVE_LIBCAP_NG
+       capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
+#ifdef HAVE_CAPSICUM
+       fd = openat(dump_info->dirfd, dump_info->CurrentFileName,
+           O_CREAT | O_WRONLY | O_TRUNC, 0644);
+       if (fd < 0) {
+               error("unable to open file %s", dump_info->CurrentFileName);
+       }
+       fp = fdopen(fd, "w");
+       if (fp == NULL) {
+               error("unable to fdopen file %s", dump_info->CurrentFileName);
+       }
+       dump_info->pdd = pcap_dump_fopen(dump_info->pd, fp);
+#else  /* !HAVE_CAPSICUM */
+       dump_info->pdd = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
+#endif
+#ifdef HAVE_LIBCAP_NG
+       capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+       capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
+       if (dump_info->pdd == NULL)
+               error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+       set_dumper_capsicum_rights(dump_info->pdd);
+#endif
 }
-#endif /* HAVE_FORK && HAVE_VFORK */
 
 static void
 dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
@@ -2993,6 +3231,9 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
 
        dump_info = (struct dump_info *)user;
 
+       if (packets_captured <= packets_to_skip)
+               return;
+
        /*
         * XXX - this won't force the file to rotate on the specified time
         * boundary, but it will rotate on the first packet received after the
@@ -3014,25 +3255,12 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
 
                /* If the time is greater than the specified window, rotate */
                if (t - Gflag_time >= Gflag) {
-#ifdef HAVE_CAPSICUM
-                       FILE *fp;
-                       int fd;
-#endif
-
                        /* Update the Gflag_time */
                        Gflag_time = t;
                        /* Update Gflag_count */
                        Gflag_count++;
-                       /*
-                        * Close the current file and open a new one.
-                        */
-                       pcap_dump_close(dump_info->pdd);
 
-                       /*
-                        * Compress the file we just closed, if the user asked for it
-                        */
-                       if (zflag != NULL)
-                               compress_savefile(dump_info->CurrentFileName);
+                       close_old_dump_file(dump_info);
 
                        /*
                         * Check to see if we've exceeded the Wflag (when
@@ -3069,36 +3297,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                        else
                                MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0);
 
-#ifdef HAVE_LIBCAP_NG
-                       capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
-                       capng_apply(CAPNG_SELECT_BOTH);
-#endif /* HAVE_LIBCAP_NG */
-#ifdef HAVE_CAPSICUM
-                       fd = openat(dump_info->dirfd,
-                           dump_info->CurrentFileName,
-                           O_CREAT | O_WRONLY | O_TRUNC, 0644);
-                       if (fd < 0) {
-                               error("unable to open file %s",
-                                   dump_info->CurrentFileName);
-                       }
-                       fp = fdopen(fd, "w");
-                       if (fp == NULL) {
-                               error("unable to fdopen file %s",
-                                   dump_info->CurrentFileName);
-                       }
-                       dump_info->pdd = pcap_dump_fopen(dump_info->pd, fp);
-#else  /* !HAVE_CAPSICUM */
-                       dump_info->pdd = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
-#endif
-#ifdef HAVE_LIBCAP_NG
-                       capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
-                       capng_apply(CAPNG_SELECT_BOTH);
-#endif /* HAVE_LIBCAP_NG */
-                       if (dump_info->pdd == NULL)
-                               error("%s", pcap_geterr(pd));
-#ifdef HAVE_CAPSICUM
-                       set_dumper_capsicum_rights(dump_info->pdd);
-#endif
+                       open_new_dump_file(dump_info);
                }
        }
 
@@ -3123,22 +3322,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                if (size == -1)
                        error("ftell fails on output file");
                if (size > Cflag) {
-#ifdef HAVE_CAPSICUM
-                       FILE *fp;
-                       int fd;
-#endif
-
-                       /*
-                        * Close the current file and open a new one.
-                        */
-                       pcap_dump_close(dump_info->pdd);
-
-                       /*
-                        * Compress the file we just closed, if the user
-                        * asked for it.
-                        */
-                       if (zflag != NULL)
-                               compress_savefile(dump_info->CurrentFileName);
+                       close_old_dump_file(dump_info);
 
                        Cflag_count++;
                        if (Wflag > 0) {
@@ -3151,43 +3335,14 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                        if (dump_info->CurrentFileName == NULL)
                                error("%s: malloc", __func__);
                        MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
-#ifdef HAVE_LIBCAP_NG
-                       capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
-                       capng_apply(CAPNG_SELECT_BOTH);
-#endif /* HAVE_LIBCAP_NG */
-#ifdef HAVE_CAPSICUM
-                       fd = openat(dump_info->dirfd, dump_info->CurrentFileName,
-                           O_CREAT | O_WRONLY | O_TRUNC, 0644);
-                       if (fd < 0) {
-                               error("unable to open file %s",
-                                   dump_info->CurrentFileName);
-                       }
-                       fp = fdopen(fd, "w");
-                       if (fp == NULL) {
-                               error("unable to fdopen file %s",
-                                   dump_info->CurrentFileName);
-                       }
-                       dump_info->pdd = pcap_dump_fopen(dump_info->pd, fp);
-#else  /* !HAVE_CAPSICUM */
-                       dump_info->pdd = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
-#endif
-#ifdef HAVE_LIBCAP_NG
-                       capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
-                       capng_apply(CAPNG_SELECT_BOTH);
-#endif /* HAVE_LIBCAP_NG */
-                       if (dump_info->pdd == NULL)
-                               error("%s", pcap_geterr(pd));
-#ifdef HAVE_CAPSICUM
-                       set_dumper_capsicum_rights(dump_info->pdd);
-#endif
+
+                       open_new_dump_file(dump_info);
                }
        }
 
        pcap_dump((u_char *)dump_info->pdd, h, sp);
-#ifdef HAVE_PCAP_DUMP_FLUSH
        if (Uflag)
                pcap_dump_flush(dump_info->pdd);
-#endif
 
        if (dump_info->ndo != NULL)
                pretty_print_packet(dump_info->ndo, h, sp, packets_captured);
@@ -3208,11 +3363,12 @@ dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 
        dump_info = (struct dump_info *)user;
 
+       if (packets_captured <= packets_to_skip)
+               return;
+
        pcap_dump((u_char *)dump_info->pdd, h, sp);
-#ifdef HAVE_PCAP_DUMP_FLUSH
        if (Uflag)
                pcap_dump_flush(dump_info->pdd);
-#endif
 
        if (dump_info->ndo != NULL)
                pretty_print_packet(dump_info->ndo, h, sp, packets_captured);
@@ -3229,7 +3385,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 
        ++infodelay;
 
-       if (!count_mode)
+       if (!count_mode && packets_captured > packets_to_skip)
                pretty_print_packet((netdissect_options *)user, h, sp, packets_captured);
 
        --infodelay;
@@ -3289,21 +3445,10 @@ DIAG_OFF_DEPRECATION
 static void
 print_version(FILE *f)
 {
-#ifndef HAVE_PCAP_LIB_VERSION
-  #ifdef HAVE_PCAP_VERSION
-       extern char pcap_version[];
-  #else /* HAVE_PCAP_VERSION */
-       static char pcap_version[] = "unknown";
-  #endif /* HAVE_PCAP_VERSION */
-#endif /* HAVE_PCAP_LIB_VERSION */
        const char *smi_version_string;
 
        (void)fprintf(f, "%s version " PACKAGE_VERSION "\n", program_name);
-#ifdef HAVE_PCAP_LIB_VERSION
        (void)fprintf(f, "%s\n", pcap_lib_version());
-#else /* HAVE_PCAP_LIB_VERSION */
-       (void)fprintf(f, "libpcap version %s\n", pcap_version);
-#endif /* HAVE_PCAP_LIB_VERSION */
 
 #if defined(HAVE_LIBCRYPTO) && defined(SSLEAY_VERSION)
        (void)fprintf (f, "%s\n", SSLeay_version(SSLEAY_VERSION));
@@ -3322,6 +3467,8 @@ print_version(FILE *f)
        (void)fprintf (f, "Compiled with MemorySanitizer/Clang.\n");
 #  endif
 #endif /* __SANITIZE_ADDRESS__ or __has_feature */
+       (void)fprintf (f, "%zu-bit build, %zu-bit time_t\n",
+                      sizeof(void *) * 8, sizeof(time_t) * 8);
 }
 DIAG_ON_DEPRECATION
 
@@ -3330,25 +3477,23 @@ print_usage(FILE *f)
 {
        print_version(f);
        (void)fprintf(f,
-"Usage: %s [-Abd" D_FLAG "efhH" I_FLAG J_FLAG "KlLnNOpqStu" U_FLAG "vxX#]" B_FLAG_USAGE " [ -c count ] [--count]\n", program_name);
+"Usage: %s [-AbdDefhHI" J_FLAG "KlLnNOpqStuUvxX#] [ -B size ] [ -c count ] [--count]\n", program_name);
        (void)fprintf(f,
-"\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
+"\t\t[ -C file_size ] " E_FLAG_USAGE "[ -F file ] [ -G seconds ]\n");
        (void)fprintf(f,
 "\t\t[ -i interface ]" IMMEDIATE_MODE_USAGE j_FLAG_USAGE "\n");
-#ifdef HAVE_PCAP_FINDALLDEVS_EX
        (void)fprintf(f,
-"\t\t" LIST_REMOTE_INTERFACES_USAGE "\n");
-#endif
+"\t\t[ --lengths ]" LIST_REMOTE_INTERFACES_USAGE "\n");
 #ifdef USE_LIBSMI
        (void)fprintf(f,
 "\t\t" m_FLAG_USAGE "\n");
 #endif
        (void)fprintf(f,
-"\t\t[ -M secret ] [ --number ] [ --print ]\n");
+"\t\t" M_FLAG_USAGE "[ --number ] [ --print ]\n");
        (void)fprintf(f,
-"\t\t[ --print-sampling nth ]" Q_FLAG_USAGE " [ -r file ]\n");
+"\t\t[ --print-sampling nth ] [ -Q in|out|inout ] [ -r file ]\n");
        (void)fprintf(f,
-"\t\t[ -s snaplen ] [ -T type ] [ --version ]\n");
+"\t\t[ -s snaplen ] [ --skip count ] [ -T type ] [ --version ]\n");
        (void)fprintf(f,
 "\t\t[ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ]\n");
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
@@ -3356,5 +3501,5 @@ print_usage(FILE *f)
 "\t\t[ --time-stamp-precision precision ] [ --micro ] [ --nano ]\n");
 #endif
        (void)fprintf(f,
-"\t\t[ -z postrotate-command ] [ -Z user ] [ expression ]\n");
+"\t\t" z_FLAG_USAGE "[ -Z user ] [ expression ]\n");
 }