]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
BGP: Fix the uses of the pointer to the end of current packet
[tcpdump] / tcpdump.c
index 695cedb7fe53c2401f45662e65836e0352e89484..4ab2c2493b4e30795b9d5a800900671950eb3ea5 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
  *     Seth Webster <[email protected]>
  */
 
-#ifndef lint
-static const char copyright[] _U_ =
-    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
-The Regents of the University of California.  All rights reserved.\n";
-#endif
-
 /*
  * tcpdump - dump traffic on a network
  *
@@ -40,7 +34,7 @@ The Regents of the University of California.  All rights reserved.\n";
  */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
 /*
@@ -55,7 +49,17 @@ The Regents of the University of California.  All rights reserved.\n";
 #endif
 #endif
 
-#include <netdissect-stdinc.h>
+#include "netdissect-stdinc.h"
+
+/*
+ * This must appear after including netdissect-stdinc.h, so that _U_ is
+ * defined.
+ */
+#ifndef lint
+static const char copyright[] _U_ =
+    "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
+The Regents of the University of California.  All rights reserved.\n";
+#endif
 
 #include <sys/stat.h>
 
@@ -97,7 +101,10 @@ The Regents of the University of California.  All rights reserved.\n";
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
-#ifndef _WIN32
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
 #include <pwd.h>
@@ -142,7 +149,7 @@ The Regents of the University of California.  All rights reserved.\n";
 #endif
 
 static int Bflag;                      /* buffer size */
-#ifdef HAVE_PCAP_FTELL64
+#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 */
@@ -223,13 +230,12 @@ static void droproot(const char *, const char *);
 void requestinfo(int);
 #endif
 
-#if defined(USE_WIN32_MM_TIMER)
-  #include <MMsystem.h>
-  static UINT timer_id;
-  static void CALLBACK verbose_stats_dump(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR);
-#elif defined(HAVE_ALARM)
+#ifdef _WIN32
+    static HANDLE timer_handle = INVALID_HANDLE_VALUE;
+    static void CALLBACK verbose_stats_dump(PVOID param, BOOLEAN timer_fired);
+#else /* _WIN32 */
   static void verbose_stats_dump(int sig);
-#endif
+#endif /* _WIN32 */
 
 static void info(int);
 static u_int packets_captured;
@@ -332,7 +338,7 @@ error(const char *fmt, ...)
                if (fmt[-1] != '\n')
                        (void)fputc('\n', stderr);
        }
-       exit_tcpdump(1);
+       exit_tcpdump(S_ERR_HOST_PROGRAM);
        /* NOTREACHED */
 }
 
@@ -376,7 +382,7 @@ show_tstamp_types_and_exit(pcap_t *pc, const char *device)
        if (n_tstamp_types == 0) {
                fprintf(stderr, "Time stamp type cannot be set for %s\n",
                    device);
-               exit_tcpdump(0);
+               exit_tcpdump(S_SUCCESS);
        }
        fprintf(stderr, "Time stamp types for %s (use option -j to set):\n",
            device);
@@ -390,7 +396,7 @@ show_tstamp_types_and_exit(pcap_t *pc, const char *device)
                }
        }
        pcap_free_tstamp_types(tstamp_types);
-       exit_tcpdump(0);
+       exit_tcpdump(S_SUCCESS);
 }
 #endif
 
@@ -443,7 +449,7 @@ show_dlts_and_exit(pcap_t *pc, const char *device)
 #ifdef HAVE_PCAP_FREE_DATALINKS
        pcap_free_datalinks(dlts);
 #endif
-       exit_tcpdump(0);
+       exit_tcpdump(S_SUCCESS);
 }
 
 #ifdef HAVE_PCAP_FINDALLDEVS
@@ -465,7 +471,7 @@ show_devices_and_exit(void)
                printf("\n");
        }
        pcap_freealldevs(devlist);
-       exit_tcpdump(0);
+       exit_tcpdump(S_SUCCESS);
 }
 #endif /* HAVE_PCAP_FINDALLDEVS */
 
@@ -489,7 +495,7 @@ show_remote_devices_and_exit(void)
                printf("\n");
        }
        pcap_freealldevs(devlist);
-       exit_tcpdump(0);
+       exit_tcpdump(S_SUCCESS);
 }
 #endif /* HAVE_PCAP_FINDALLDEVS */
 
@@ -501,22 +507,22 @@ show_remote_devices_and_exit(void)
  * only use them for the same purposes that the other versions of tcpdump
  * use them:
  *
- * OS X tcpdump uses -g to force non--v output for IP to be on one
+ * macOS tcpdump uses -g to force non--v output for IP to be on one
  * line, making it more "g"repable;
  *
- * OS X tcpdump uses -k to specify that packet comments in pcap-ng files
+ * macOS tcpdump uses -k to specify that packet comments in pcapng files
  * should be printed;
  *
  * OpenBSD tcpdump uses -o to indicate that OS fingerprinting should be done
  * for hosts sending TCP SYN packets;
  *
- * OS X tcpdump uses -P to indicate that -w should write pcap-ng rather
+ * macOS tcpdump uses -P to indicate that -w should write pcapng rather
  * than pcap files.
  *
- * OS X tcpdump also uses -Q to specify expressions that match packet
+ * macOS tcpdump also uses -Q to specify expressions that match packet
  * metadata, including but not limited to the packet direction.
  * The expression syntax is different from a simple "in|out|inout",
- * and those expressions aren't accepted by OS X tcpdump, but the
+ * and those expressions aren't accepted by macOS tcpdump, but the
  * equivalents would be "in" = "dir=in", "out" = "dir=out", and
  * "inout" = "dir=in or dir=out", and the parser could conceivably
  * special-case "in", "out", and "inout" as expressions for backwards
@@ -673,7 +679,7 @@ droproot(const char *username, const char *chroot_dir)
        if (chroot_dir && !username) {
                fprintf(stderr, "%s: Chroot without dropping root is insecure\n",
                        program_name);
-               exit_tcpdump(1);
+               exit_tcpdump(S_ERR_HOST_PROGRAM);
        }
 
        pw = getpwnam(username);
@@ -682,7 +688,7 @@ droproot(const char *username, const char *chroot_dir)
                        if (chroot(chroot_dir) != 0 || chdir ("/") != 0) {
                                fprintf(stderr, "%s: Couldn't chroot/chdir to '%.64s': %s\n",
                                        program_name, chroot_dir, pcap_strerror(errno));
-                               exit_tcpdump(1);
+                               exit_tcpdump(S_ERR_HOST_PROGRAM);
                        }
                }
 #ifdef HAVE_LIBCAP_NG
@@ -702,7 +708,7 @@ droproot(const char *username, const char *chroot_dir)
                                (unsigned long)pw->pw_uid,
                                (unsigned long)pw->pw_gid,
                                pcap_strerror(errno));
-                       exit_tcpdump(1);
+                       exit_tcpdump(S_ERR_HOST_PROGRAM);
                }
                else {
                        fprintf(stderr, "dropped privs to %s\n", username);
@@ -712,10 +718,11 @@ droproot(const char *username, const char *chroot_dir)
        else {
                fprintf(stderr, "%s: Couldn't find user '%.32s'\n",
                        program_name, username);
-               exit_tcpdump(1);
+               exit_tcpdump(S_ERR_HOST_PROGRAM);
        }
 #ifdef HAVE_LIBCAP_NG
        /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */
+DIAG_OFF_CLANG(assign-enum)
        capng_updatev(
                CAPNG_DROP,
                CAPNG_EFFECTIVE | CAPNG_PERMITTED,
@@ -723,6 +730,7 @@ droproot(const char *username, const char *chroot_dir)
                CAP_SETGID,
                CAP_SYS_CHROOT,
                -1);
+DIAG_ON_CLANG(assign-enum)
        capng_apply(CAPNG_SELECT_BOTH);
 #endif /* HAVE_LIBCAP_NG */
 
@@ -771,7 +779,7 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
        if (cnt == 0 && max_chars == 0)
                strncpy(buffer, filename, PATH_MAX + 1);
        else
-               if (snprintf(buffer, PATH_MAX + 1, "%s%0*d", filename, max_chars, cnt) > PATH_MAX)
+               if (nd_snprintf(buffer, PATH_MAX + 1, "%s%0*d", filename, max_chars, cnt) > PATH_MAX)
                   /* Report an error if the filename is too large */
                   error("too many output files or filename is too long (> %d)", PATH_MAX);
         free(filename);
@@ -925,10 +933,10 @@ set_dumper_capsicum_rights(pcap_dumper_t *p)
  * Copy arg vector into a new buffer, concatenating arguments with spaces.
  */
 static char *
-copy_argv(register char **argv)
+copy_argv(char **argv)
 {
-       register char **p;
-       register u_int len = 0;
+       char **p;
+       u_int len = 0;
        char *buf;
        char *src, *dst;
 
@@ -968,8 +976,8 @@ copy_argv(register char **argv)
 static char *
 read_infile(char *fname)
 {
-       register int i, fd, cc;
-       register char *cp;
+       int i, fd, cc;
+       char *cp;
        struct stat buf;
 
        fd = open(fname, O_RDONLY|O_BINARY);
@@ -1190,7 +1198,7 @@ fprintf(stderr, "Opening %s\n", device);
                        /*
                         * Return an error for our caller to handle.
                         */
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
+                       nd_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
                            device, pcap_statustostr(status), cp);
                        pcap_close(pc);
                        return (NULL);
@@ -1204,7 +1212,7 @@ fprintf(stderr, "Opening %s\n", device);
                        char sysctl[32];
                        size_t s = sizeof(parent);
 
-                       snprintf(sysctl, sizeof(sysctl),
+                       nd_snprintf(sysctl, sizeof(sysctl),
                            "net.wlan.%d.%%parent", atoi(device + 4));
                        sysctlbyname(sysctl, parent, &s, NULL, 0);
                        strlcpy(newdev, device, sizeof(newdev));
@@ -1278,10 +1286,10 @@ fprintf(stderr, "Opening %s\n", device);
 int
 main(int argc, char **argv)
 {
-       register int cnt, op, i;
+       int cnt, op, i;
        bpf_u_int32 localnet = 0, netmask = 0;
        int timezone_offset = 0;
-       register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName;
+       char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName;
        char *endp;
        pcap_handler callback;
        int dlt;
@@ -1319,7 +1327,7 @@ main(int argc, char **argv)
        /*
         * Initialize the netdissect code.
         */
-       if (nd_init(ebuf, sizeof ebuf) == -1)
+       if (nd_init(ebuf, sizeof(ebuf)) == -1)
                error("%s", ebuf);
 
        memset(ndo, 0, sizeof(*ndo));
@@ -1338,10 +1346,13 @@ main(int argc, char **argv)
        else
                ndo->program_name = program_name = argv[0];
 
-#ifdef _WIN32
+#if defined(HAVE_PCAP_WSOCKINIT)
        if (pcap_wsockinit() != 0)
                error("Attempting to initialize Winsock failed");
-#endif /* _WIN32 */
+#elif defined(HAVE_WSOCKINIT)
+       if (wsockinit() != 0)
+               error("Attempting to initialize Winsock failed");
+#endif
 
        /*
         * On platforms where the CPU doesn't support unaligned loads,
@@ -1385,7 +1396,7 @@ main(int argc, char **argv)
 
                case 'C':
                        errno = 0;
-#ifdef HAVE_PCAP_FTELL64
+#ifdef HAVE_PCAP_DUMP_FTELL64
                        Cflag = strtoint64_t(optarg, &endp, 10);
 #else
                        Cflag = strtol(optarg, &endp, 10);
@@ -1396,8 +1407,8 @@ main(int argc, char **argv)
                        /*
                         * Will multiplying it by 1000000 overflow?
                         */
-#ifdef HAVE_PCAP_FTELL64
-                       if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffffU) / 1000000)
+#ifdef HAVE_PCAP_DUMP_FTELL64
+                       if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffff) / 1000000)
 #else
                        if (Cflag > LONG_MAX / 1000000)
 #endif
@@ -1461,7 +1472,7 @@ main(int argc, char **argv)
 
                case 'h':
                        print_usage();
-                       exit_tcpdump(0);
+                       exit_tcpdump(S_SUCCESS);
                        break;
 
                case 'H':
@@ -1517,7 +1528,7 @@ main(int argc, char **argv)
 
                case 'm':
                        if (nd_have_smi_support()) {
-                               if (nd_load_smi_module(optarg, ebuf, sizeof ebuf) == -1)
+                               if (nd_load_smi_module(optarg, ebuf, sizeof(ebuf)) == -1)
                                        error("%s", ebuf);
                        } else {
                                (void)fprintf(stderr, "%s: ignoring option `-m %s' ",
@@ -1695,7 +1706,7 @@ main(int argc, char **argv)
 
                case OPTION_VERSION:
                        print_version();
-                       exit_tcpdump(0);
+                       exit_tcpdump(S_SUCCESS);
                        break;
 
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
@@ -1718,7 +1729,7 @@ main(int argc, char **argv)
 
                default:
                        print_usage();
-                       exit_tcpdump(1);
+                       exit_tcpdump(S_ERR_HOST_PROGRAM);
                        /* NOTREACHED */
                }
 
@@ -1991,7 +2002,7 @@ main(int argc, char **argv)
                pcap_close(pd);
                free(cmdbuf);
                pcap_freecode(&fcode);
-               exit_tcpdump(0);
+               exit_tcpdump(S_SUCCESS);
        }
 
 #ifdef HAVE_CASPER
@@ -2004,8 +2015,8 @@ main(int argc, char **argv)
 #ifndef _WIN32
        (void)setsignal(SIGPIPE, cleanup);
        (void)setsignal(SIGTERM, cleanup);
-       (void)setsignal(SIGINT, cleanup);
 #endif /* _WIN32 */
+       (void)setsignal(SIGINT, cleanup);
 #if defined(HAVE_FORK) || defined(HAVE_VFORK)
        (void)setsignal(SIGCHLD, child_cleanup);
 #endif
@@ -2039,27 +2050,33 @@ main(int argc, char **argv)
                /* Initialize capng */
                capng_clear(CAPNG_SELECT_BOTH);
                if (username) {
+DIAG_OFF_CLANG(assign-enum)
                        capng_updatev(
                                CAPNG_ADD,
                                CAPNG_PERMITTED | CAPNG_EFFECTIVE,
                                CAP_SETUID,
                                CAP_SETGID,
                                -1);
+DIAG_ON_CLANG(assign-enum)
                }
                if (chroot_dir) {
+DIAG_OFF_CLANG(assign-enum)
                        capng_update(
                                CAPNG_ADD,
                                CAPNG_PERMITTED | CAPNG_EFFECTIVE,
                                CAP_SYS_CHROOT
                                );
+DIAG_ON_CLANG(assign-enum)
                }
 
                if (WFileName) {
+DIAG_OFF_CLANG(assign-enum)
                        capng_update(
                                CAPNG_ADD,
                                CAPNG_PERMITTED | CAPNG_EFFECTIVE,
                                CAP_DAC_OVERRIDE
                                );
+DIAG_ON_CLANG(assign-enum)
                }
                capng_apply(CAPNG_SELECT_BOTH);
 #endif /* HAVE_LIBCAP_NG */
@@ -2194,14 +2211,32 @@ main(int argc, char **argv)
                 *"-v" means tcpdump should, once per second,
                 * "v"erbosely report the number of packets captured.
                 */
-#ifdef USE_WIN32_MM_TIMER
-               /* call verbose_stats_dump() each 1000 +/-100msec */
-               timer_id = timeSetEvent(1000, 100, verbose_stats_dump, 0, TIME_PERIODIC);
+#ifdef _WIN32
+               /*
+                * https://blogs.msdn.microsoft.com/oldnewthing/20151230-00/?p=92741
+                *
+                * suggests that this dates back to W2K.
+                *
+                * I don't know what a "long wait" is, but we'll assume
+                * that printing the stats could be a "long wait".
+                */
+               CreateTimerQueueTimer(&timer_handle, NULL,
+                   verbose_stats_dump, NULL, 1000, 1000,
+                   WT_EXECUTEDEFAULT|WT_EXECUTELONGFUNCTION);
                setvbuf(stderr, NULL, _IONBF, 0);
-#elif defined(HAVE_ALARM)
+#else /* _WIN32 */
+               /*
+                * Assume this is UN*X, and that it has setitimer(); that
+                * dates back to UNIX 95.
+                */
+               struct itimerval timer;
                (void)setsignal(SIGALRM, verbose_stats_dump);
-               alarm(1);
-#endif
+               timer.it_interval.tv_sec = 1;
+               timer.it_interval.tv_usec = 0;
+               timer.it_value.tv_sec = 1;
+               timer.it_value.tv_usec = 1;
+               setitimer(ITIMER_REAL, &timer, NULL);
+#endif /* _WIN32 */
        }
 
        if (RFileName == NULL) {
@@ -2385,13 +2420,21 @@ static void
 static void
 cleanup(int signo _U_)
 {
-#ifdef USE_WIN32_MM_TIMER
-       if (timer_id)
-               timeKillEvent(timer_id);
-       timer_id = 0;
-#elif defined(HAVE_ALARM)
-       alarm(0);
-#endif
+#ifdef _WIN32
+       if (timer_handle != INVALID_HANDLE_VALUE) {
+               DeleteTimerQueueTimer(NULL, timer_handle, NULL);
+               CloseHandle(timer_handle);
+               timer_handle = INVALID_HANDLE_VALUE;
+        }
+#else /* _WIN32 */
+       struct itimerval timer;
+
+       timer.it_interval.tv_sec = 0;
+       timer.it_interval.tv_usec = 0;
+       timer.it_value.tv_sec = 0;
+       timer.it_value.tv_usec = 0;
+       setitimer(ITIMER_REAL, &timer, NULL);
+#endif /* _WIN32 */
 
 #ifdef HAVE_PCAP_BREAKLOOP
        /*
@@ -2418,7 +2461,7 @@ cleanup(int signo _U_)
                (void)fflush(stdout);
                info(1);
        }
-       exit_tcpdump(0);
+       exit_tcpdump(S_SUCCESS);
 #endif
 }
 
@@ -2435,7 +2478,7 @@ child_cleanup(int signo _U_)
 #endif /* HAVE_FORK && HAVE_VFORK */
 
 static void
-info(register int verbose)
+info(int verbose)
 {
        struct pcap_stat stats;
 
@@ -2518,9 +2561,9 @@ compress_savefile(const char *filename)
                        filename,
                        pcap_strerror(errno));
 #ifdef HAVE_FORK
-       exit(1);
+       exit(S_ERR_HOST_PROGRAM);
 #else
-       _exit(1);
+       _exit(S_ERR_HOST_PROGRAM);
 #endif
 }
 #else  /* HAVE_FORK && HAVE_VFORK */
@@ -2592,7 +2635,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                                (void)fprintf(stderr, "Maximum file limit reached: %d\n",
                                    Wflag);
                                info(1);
-                               exit_tcpdump(0);
+                               exit_tcpdump(S_SUCCESS);
                                /* NOTREACHED */
                        }
                        if (dump_info->CurrentFileName != NULL)
@@ -2658,7 +2701,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
         * file could put it over Cflag.
         */
        if (Cflag != 0) {
-#ifdef HAVE_PCAP_FTELL64
+#ifdef HAVE_PCAP_DUMP_FTELL64
                int64_t size = pcap_dump_ftell64(dump_info->p);
 #else
                /*
@@ -2786,33 +2829,6 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
                info(0);
 }
 
-#ifdef _WIN32
-       /*
-        * XXX - there should really be libpcap calls to get the version
-        * number as a string (the string would be generated from #defines
-        * at run time, so that it's not generated from string constants
-        * in the library, as, on many UNIX systems, those constants would
-        * be statically linked into the application executable image, and
-        * would thus reflect the version of libpcap on the system on
-        * which the application was *linked*, not the system on which it's
-        * *running*.
-        *
-        * That routine should be documented, unlike the "version[]"
-        * string, so that UNIX vendors providing their own libpcaps
-        * don't omit it (as a couple of vendors have...).
-        *
-        * Packet.dll should perhaps also export a routine to return the
-        * version number of the Packet.dll code, to supply the
-        * "Wpcap_version" information on Windows.
-        */
-       char WDversion[]="current-git.tcpdump.org";
-#if !defined(HAVE_GENERATED_VERSION)
-       char version[]="current-git.tcpdump.org";
-#endif
-       char pcap_version[]="current-git.tcpdump.org";
-       char Wpcap_version[]="3.1";
-#endif
-
 #ifdef SIGNAL_REQ_INFO
 void requestinfo(int signo _U_)
 {
@@ -2838,36 +2854,35 @@ print_packets_captured (void)
 /*
  * Called once each second in verbose mode while dumping to file
  */
-#ifdef USE_WIN32_MM_TIMER
-void CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_,
-                                 DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_)
+#ifdef _WIN32
+static void CALLBACK verbose_stats_dump(PVOID param _U_,
+    BOOLEAN timer_fired _U_)
 {
        print_packets_captured();
 }
-#elif defined(HAVE_ALARM)
+#else /* _WIN32 */
 static void verbose_stats_dump(int sig _U_)
 {
        print_packets_captured();
-       alarm(1);
 }
-#endif
+#endif /* _WIN32 */
 
 USES_APPLE_DEPRECATED_API
 static void
 print_version(void)
 {
 #ifndef HAVE_PCAP_LIB_VERSION
-#if defined(_WIN32) || defined(HAVE_PCAP_VERSION)
+  #ifdef HAVE_PCAP_VERSION
        extern char pcap_version[];
-#else /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */
+  #else /* HAVE_PCAP_VERSION */
        static char pcap_version[] = "unknown";
-#endif /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */
+  #endif /* HAVE_PCAP_VERSION */
 #endif /* HAVE_PCAP_LIB_VERSION */
        const char *smi_version_string;
 
        (void)fprintf(stderr, "%s version " PACKAGE_VERSION "\n", program_name);
 #ifdef HAVE_PCAP_LIB_VERSION
-       (void)fprintf(stderr, "%s\n",pcap_lib_version());
+       (void)fprintf(stderr, "%s\n", pcap_lib_version());
 #else /* HAVE_PCAP_LIB_VERSION */
        (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
 #endif /* HAVE_PCAP_LIB_VERSION */