]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
LSP ping: Put the RFC number right. [skip ci]
[tcpdump] / tcpdump.c
index 1a15d3c5d8a772cfea8271f5ed326329e7a7878f..a0d627db6395c674de029dac8a2435b04963b688 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -124,6 +124,16 @@ The Regents of the University of California.  All rights reserved.\n";
 #include <grp.h>
 #endif /* _WIN32 */
 
+/*
+ * Pathname separator.
+ * Use this in pathnames, but do *not* use it in URLs.
+ */
+#ifdef _WIN32
+#define PATH_SEPARATOR '\\'
+#else
+#define PATH_SEPARATOR '/'
+#endif
+
 /* capabilities convenience library */
 /* If a code depends on HAVE_LIBCAP_NG, it depends also on HAVE_CAP_NG_H.
  * If HAVE_CAP_NG_H is not defined, undefine HAVE_LIBCAP_NG.
@@ -150,6 +160,8 @@ The Regents of the University of California.  All rights reserved.\n";
 
 #include "print.h"
 
+#include "fptype.h"
+
 #ifndef PATH_MAX
 #define PATH_MAX 1024
 #endif
@@ -203,6 +215,7 @@ static int Iflag;                   /* rfmon (monitor) mode */
 static int Jflag;                      /* list available time stamp types */
 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 */
@@ -213,9 +226,11 @@ static int Uflag;                  /* "unbuffered" output of dump files */
 static int Wflag;                      /* recycle output files after this number of files */
 static int WflagChars;
 static char *zflag = NULL;             /* compress each savefile using a specified command (like gzip or bzip2) */
+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 int infodelay;
 static int infoprint;
@@ -233,8 +248,8 @@ static NORETURN void exit_tcpdump(int);
 static void (*setsignal (int sig, void (*func)(int)))(int);
 static void cleanup(int);
 static void child_cleanup(int);
-static void print_version(void);
-static void print_usage(void);
+static void print_version(FILE *);
+static void print_usage(FILE *);
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
 static NORETURN void show_tstamp_types_and_exit(pcap_t *, const char *device);
 #endif
@@ -685,6 +700,8 @@ show_remote_devices_and_exit(void)
 #define OPTION_LIST_REMOTE_INTERFACES  132
 #define OPTION_TSTAMP_MICRO            133
 #define OPTION_TSTAMP_NANO             134
+#define OPTION_FP_TYPE                 135
+#define OPTION_COUNT                   136
 
 static const struct option longopts[] = {
 #if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
@@ -728,6 +745,8 @@ static const struct option longopts[] = {
        { "debug-filter-parser", no_argument, NULL, 'Y' },
 #endif
        { "relinquish-privileges", required_argument, NULL, 'Z' },
+       { "count", no_argument, NULL, OPTION_COUNT },
+       { "fp-type", no_argument, NULL, OPTION_FP_TYPE },
        { "number", no_argument, NULL, '#' },
        { "print", no_argument, NULL, OPTION_PRINT },
        { "version", no_argument, NULL, OPTION_VERSION },
@@ -932,7 +951,7 @@ tstamp_precision_to_string(int precision)
  * necessary to make the standard I/O library work with an fdopen()ed
  * FILE * from that descriptor.
  *
- * A long time ago, in a galaxy far far away, AT&T decided that, instead
+ * A long time ago in a galaxy far, far away, AT&T decided that, instead
  * of providing separate APIs for getting and setting the FD_ flags on a
  * descriptor, getting and setting the O_ flags on a descriptor, and
  * locking files, they'd throw them all into a kitchen-sink fcntl() call
@@ -1229,7 +1248,7 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                 */
                *ebuf = '\0';
                pc = pcap_open(device, ndo->ndo_snaplen,
-                   pflag ? 0 : PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL,
+                   pflag ? 0 : PCAP_OPENFLAG_PROMISCUOUS, timeout, NULL,
                    ebuf);
                if (pc == NULL) {
                        /*
@@ -1311,7 +1330,7 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                        error("%s: Can't set monitor mode: %s",
                            device, pcap_statustostr(status));
        }
-       status = pcap_set_timeout(pc, 1000);
+       status = pcap_set_timeout(pc, timeout);
        if (status != 0)
                error("%s: pcap_set_timeout failed: %s",
                    device, pcap_statustostr(status));
@@ -1347,8 +1366,6 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                         */
                        snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
                            device, pcap_statustostr(status), cp);
-                       pcap_close(pc);
-                       return (NULL);
                } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
                        error("%s: %s\n(%s)", device,
                            pcap_statustostr(status), cp);
@@ -1379,6 +1396,8 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                else
                        error("%s: %s", device,
                            pcap_statustostr(status));
+               pcap_close(pc);
+               return (NULL);
        } else if (status > 0) {
                /*
                 * pcap_activate() succeeded, but it's warning us
@@ -1411,7 +1430,7 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
         */
        if (ndo->ndo_snaplen == 0)
                ndo->ndo_snaplen = MAXIMUM_SNAPLEN;
-       pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, 1000, ebuf);
+       pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, timeout, ebuf);
        if (pc == NULL) {
                /*
                 * If this failed with "No such device", that means
@@ -1489,7 +1508,7 @@ main(int argc, char **argv)
        VFile = NULL;
        WFileName = NULL;
        dlt = -1;
-       if ((cp = strrchr(argv[0], '/')) != NULL)
+       if ((cp = strrchr(argv[0], PATH_SEPARATOR)) != NULL)
                ndo->program_name = program_name = cp + 1;
        else
                ndo->program_name = program_name = argv[0];
@@ -1619,7 +1638,7 @@ main(int argc, char **argv)
                        break;
 
                case 'h':
-                       print_usage();
+                       print_usage(stdout);
                        exit_tcpdump(S_SUCCESS);
                        break;
 
@@ -1668,6 +1687,7 @@ main(int argc, char **argv)
                        setvbuf(stdout, NULL, _IOLBF, 0);
 #endif
 #endif /* _WIN32 */
+                       lflag = 1;
                        break;
 
                case 'K':
@@ -1782,6 +1802,12 @@ main(int argc, char **argv)
                                ndo->ndo_packettype = PT_LMP;
                        else if (ascii_strcasecmp(optarg, "resp") == 0)
                                ndo->ndo_packettype = PT_RESP;
+                       else if (ascii_strcasecmp(optarg, "ptp") == 0)
+                               ndo->ndo_packettype = PT_PTP;
+                       else if (ascii_strcasecmp(optarg, "someip") == 0)
+                               ndo->ndo_packettype = PT_SOMEIP;
+                       else if (ascii_strcasecmp(optarg, "domain") == 0)
+                               ndo->ndo_packettype = PT_DOMAIN;
                        else
                                error("unknown packet type `%s'", optarg);
                        break;
@@ -1854,7 +1880,7 @@ main(int argc, char **argv)
                        break;
 
                case OPTION_VERSION:
-                       print_version();
+                       print_version(stdout);
                        exit_tcpdump(S_SUCCESS);
                        break;
 
@@ -1886,8 +1912,23 @@ main(int argc, char **argv)
                        break;
 #endif
 
+               case OPTION_FP_TYPE:
+                       /*
+                        * Print out the type of floating-point arithmetic
+                        * we're doing; it's probably IEEE, unless somebody
+                        * tries to run this on a VAX, but the precision
+                        * may differ (e.g., it might be 32-bit, 64-bit,
+                        * or 80-bit).
+                        */
+                       float_type_check(0x4e93312d);
+                       return 0;
+
+               case OPTION_COUNT:
+                       count_mode = 1;
+                       break;
+
                default:
-                       print_usage();
+                       print_usage(stderr);
                        exit_tcpdump(S_ERR_HOST_PROGRAM);
                        /* NOTREACHED */
                }
@@ -1901,6 +1942,14 @@ main(int argc, char **argv)
                show_remote_devices_and_exit();
 #endif
 
+#if defined(DLT_LINUX_SLL2) && defined(HAVE_PCAP_SET_DATALINK)
+/* Set default linktype DLT_LINUX_SLL2 when capturing on the "any" device */
+               if (device != NULL &&
+                   strncmp (device, "any", strlen("any")) == 0
+                   && yflag_dlt == -1)
+                       yflag_dlt = DLT_LINUX_SLL2;
+#endif
+
        switch (ndo->ndo_tflag) {
 
        case 0: /* Default */
@@ -1922,19 +1971,18 @@ main(int argc, char **argv)
        if (VFileName != NULL && RFileName != NULL)
                error("-V and -r are mutually exclusive.");
 
-#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
        /*
-        * If we're printing dissected packets to the standard output
-        * and the standard output is a terminal, use immediate mode,
-        * as the user's probably expecting to see packets pop up
-        * immediately.
+        * If we're printing dissected packets to the standard output,
+        * and either the standard output is a terminal or we're doing
+        * "line" buffering, set the capture timeout to .1 second rather
+        * than 1 second, as the user's probably expecting to see packets
+        * pop up immediately shortly after they arrive.
         *
-        * XXX - set the timeout to a lower value, instead?  If so,
-        * what value would be appropriate?
+        * XXX - would there be some value appropriate for all cases,
+        * based on, say, the buffer size and packet input rate?
         */
-       if ((WFileName == NULL || print) && isatty(1))
-               immediate_mode = 1;
-#endif
+       if ((WFileName == NULL || print) && (isatty(1) || lflag))
+               timeout = 100;
 
 #ifdef WITH_CHROOT
        /* if run as root, prepare for chrooting */
@@ -2150,7 +2198,8 @@ main(int argc, char **argv)
                        }
 #endif
                        (void)fprintf(stderr, "%s: data link type %s\n",
-                                     program_name, yflag_dlt_name);
+                                     program_name,
+                                     pcap_datalink_val_to_name(yflag_dlt));
                        (void)fflush(stderr);
                }
                i = pcap_snapshot(pd);
@@ -2361,7 +2410,7 @@ DIAG_ON_CLANG(assign-enum)
                }
                if (print) {
                        dlt = pcap_datalink(pd);
-                       ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+                       ndo->ndo_if_printer = get_if_printer(dlt);
                        dumpinfo.ndo = ndo;
                } else
                        dumpinfo.ndo = NULL;
@@ -2372,7 +2421,7 @@ DIAG_ON_CLANG(assign-enum)
 #endif
        } else {
                dlt = pcap_datalink(pd);
-               ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+               ndo->ndo_if_printer = get_if_printer(dlt);
                callback = print_packet;
                pcap_userdata = (u_char *)ndo;
        }
@@ -2389,11 +2438,14 @@ DIAG_ON_CLANG(assign-enum)
        (void)setsignal(SIGNAL_FLUSH_PCAP, flushpcap);
 #endif
 
-       if (ndo->ndo_vflag > 0 && WFileName && !print) {
+       if (ndo->ndo_vflag > 0 && WFileName && RFileName == NULL && !print) {
                /*
                 * When capturing to a file, if "--print" wasn't specified,
                 *"-v" means tcpdump should, once per second,
                 * "v"erbosely report the number of packets captured.
+                * Except when reading from a file, because -r, -w and -v
+                * together used to make a corner case, in which pcap_loop()
+                * errored due to EINTR (see GH #155 for details).
                 */
 #ifdef _WIN32
                /*
@@ -2431,7 +2483,7 @@ DIAG_ON_CLANG(assign-enum)
                 */
                if (!ndo->ndo_vflag && !WFileName) {
                        (void)fprintf(stderr,
-                           "%s: verbose output suppressed, use -v or -vv for full protocol decode\n",
+                           "%s: verbose output suppressed, use -v[v]... for full protocol decode\n",
                            program_name);
                } else
                        (void)fprintf(stderr, "%s: ", program_name);
@@ -2545,7 +2597,7 @@ DIAG_ON_CLANG(assign-enum)
                                         * the new DLT.
                                         */
                                        dlt = new_dlt;
-                                       ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+                                       ndo->ndo_if_printer = get_if_printer(dlt);
                                        if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
                                                error("%s", pcap_geterr(pd));
                                }
@@ -2574,6 +2626,10 @@ DIAG_ON_CLANG(assign-enum)
        }
        while (ret != NULL);
 
+       if (count_mode && RFileName != NULL)
+               fprintf(stderr, "%u packet%s\n", packets_captured,
+                       PLURAL_SUFFIX(packets_captured));
+
        free(cmdbuf);
        pcap_freecode(&fcode);
        exit_tcpdump(status == -1 ? 1 : 0);
@@ -3006,7 +3062,8 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 
        ++infodelay;
 
-       pretty_print_packet((netdissect_options *)user, h, sp, packets_captured);
+       if (!count_mode)
+               pretty_print_packet((netdissect_options *)user, h, sp, packets_captured);
 
        --infodelay;
        if (infoprint)
@@ -3063,7 +3120,7 @@ static void verbose_stats_dump(int sig _U_)
 
 USES_APPLE_DEPRECATED_API
 static void
-print_version(void)
+print_version(FILE *f)
 {
 #ifndef HAVE_PCAP_LIB_VERSION
   #ifdef HAVE_PCAP_VERSION
@@ -3074,59 +3131,61 @@ print_version(void)
 #endif /* HAVE_PCAP_LIB_VERSION */
        const char *smi_version_string;
 
-       (void)fprintf(stderr, "%s version " PACKAGE_VERSION "\n", program_name);
+       (void)fprintf(f, "%s version " PACKAGE_VERSION "\n", program_name);
 #ifdef HAVE_PCAP_LIB_VERSION
-       (void)fprintf(stderr, "%s\n", pcap_lib_version());
+       (void)fprintf(f, "%s\n", pcap_lib_version());
 #else /* HAVE_PCAP_LIB_VERSION */
-       (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
+       (void)fprintf(f, "libpcap version %s\n", pcap_version);
 #endif /* HAVE_PCAP_LIB_VERSION */
 
 #if defined(HAVE_LIBCRYPTO) && defined(SSLEAY_VERSION)
-       (void)fprintf (stderr, "%s\n", SSLeay_version(SSLEAY_VERSION));
+       (void)fprintf (f, "%s\n", SSLeay_version(SSLEAY_VERSION));
 #endif
 
        smi_version_string = nd_smi_version_string();
        if (smi_version_string != NULL)
-               (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string);
+               (void)fprintf (f, "SMI-library: %s\n", smi_version_string);
 
 #if defined(__SANITIZE_ADDRESS__)
-       (void)fprintf (stderr, "Compiled with AddressSanitizer/GCC.\n");
+       (void)fprintf (f, "Compiled with AddressSanitizer/GCC.\n");
 #elif defined(__has_feature)
 #  if __has_feature(address_sanitizer)
-       (void)fprintf (stderr, "Compiled with AddressSanitizer/CLang.\n");
+       (void)fprintf (f, "Compiled with AddressSanitizer/Clang.\n");
+#  elif __has_feature(memory_sanitizer)
+       (void)fprintf (f, "Compiled with MemorySanitizer/Clang.\n");
 #  endif
 #endif /* __SANITIZE_ADDRESS__ or __has_feature */
 }
 USES_APPLE_RST
 
 static void
-print_usage(void)
+print_usage(FILE *f)
 {
-       print_version();
-       (void)fprintf(stderr,
-"Usage: %s [-aAbd" D_FLAG "efhH" I_FLAG J_FLAG "KlLnNOpqStu" U_FLAG "vxX#]" B_FLAG_USAGE " [ -c count ]\n", program_name);
-       (void)fprintf(stderr,
+       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);
+       (void)fprintf(f,
 "\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t[ -i interface ]" IMMEDIATE_MODE_USAGE j_FLAG_USAGE "\n");
 #ifdef HAVE_PCAP_FINDALLDEVS_EX
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t" LIST_REMOTE_INTERFACES_USAGE "\n");
 #endif
 #ifdef USE_LIBSMI
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t" m_FLAG_USAGE "\n");
 #endif
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t[ -M secret ] [ --number ] [ --print ]" Q_FLAG_USAGE "\n");
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ --version ]\n");
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t[ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ]\n");
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t[ --time-stamp-precision precision ] [ --micro ] [ --nano ]\n");
 #endif
-       (void)fprintf(stderr,
+       (void)fprintf(f,
 "\t\t[ -z postrotate-command ] [ -Z user ] [ expression ]\n");
 }