]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
Change -z command help text to -z postrotate-command
[tcpdump] / tcpdump.c
index cebc1f2dc0c65662e5bc782e0c03b97b275664c9..3d491c4e9315341c3b6a914878ff46a130fb3e2f 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -130,7 +130,19 @@ The Regents of the University of California.  All rights reserved.\n";
 static int Cflag;                      /* rotate dump files after this many bytes */
 static int Cflag_count;                        /* Keep track of which file number we're writing */
 static int Dflag;                      /* list available devices and exit */
-static int dflag;                      /* print filter code */
+/*
+ * This is exported because, in some versions of libpcap, if libpcap
+ * is built with optimizer debugging code (which is *NOT* the default
+ * configuration!), the library *imports*(!) a variable named dflag,
+ * under the expectation that tcpdump is exporting it, to govern
+ * how much debugging information to print when optimizing
+ * the generated BPF code.
+ *
+ * This is a horrible hack; newer versions of libpcap don't import
+ * dflag but, instead, *if* built with optimizer debugging code,
+ * *export* a routine to set that flag.
+ */
+int dflag;                             /* print filter code */
 static int Gflag;                      /* rotate dump files after this many seconds */
 static int Gflag_count;                        /* number of files created with Gflag rotation */
 static time_t Gflag_time;              /* The last time_t the dump file was rotated. */
@@ -209,6 +221,57 @@ struct dump_info {
 #endif
 };
 
+#if defined(HAVE_PCAP_SET_PARSER_DEBUG)
+/*
+ * We have pcap_set_parser_debug() in libpcap; declare it (it's not declared
+ * by any libpcap header, because it's a special hack, only available if
+ * libpcap was configured to include it, and only intended for use by
+ * libpcap developers trying to debug the parser for filter expressions).
+ */
+#ifdef _WIN32
+__declspec(dllimport)
+#else /* _WIN32 */
+extern
+#endif /* _WIN32 */
+void pcap_set_parser_debug(int);
+#elif defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG)
+/*
+ * We don't have pcap_set_parser_debug() in libpcap, but we do have
+ * pcap_debug or yydebug.  Make a local version of pcap_set_parser_debug()
+ * to set the flag, and define HAVE_PCAP_SET_PARSER_DEBUG.
+ */
+static void
+pcap_set_parser_debug(int value)
+{
+#ifdef HAVE_PCAP_DEBUG
+       extern int pcap_debug;
+
+       pcap_debug = value;
+#else /* HAVE_PCAP_DEBUG */
+       extern int yydebug;
+
+       yydebug = value;
+#endif /* HAVE_PCAP_DEBUG */
+}
+
+#define HAVE_PCAP_SET_PARSER_DEBUG
+#endif
+
+#if defined(HAVE_PCAP_SET_OPTIMIZER_DEBUG)
+/*
+ * We have pcap_set_optimizer_debug() in libpcap; declare it (it's not declared
+ * by any libpcap header, because it's a special hack, only available if
+ * libpcap was configured to include it, and only intended for use by
+ * libpcap developers trying to debug the optimizer for filter expressions).
+ */
+#ifdef _WIN32
+__declspec(dllimport)
+#else /* _WIN32 */
+extern
+#endif /* _WIN32 */
+void pcap_set_optimizer_debug(int);
+#endif
+
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
 static void
 show_tstamp_types_and_exit(const char *device)
@@ -299,23 +362,21 @@ show_dlts_and_exit(const char *device)
 static void
 show_devices_and_exit (void)
 {
-       pcap_if_t *devpointer;
+       pcap_if_t *dev, *devlist;
        char ebuf[PCAP_ERRBUF_SIZE];
        int i;
 
-       if (pcap_findalldevs(&devpointer, ebuf) < 0)
+       if (pcap_findalldevs(&devlist, ebuf) < 0)
                error("%s", ebuf);
-       else {
-               for (i = 0; devpointer != NULL; i++) {
-                       printf("%d.%s", i+1, devpointer->name);
-                       if (devpointer->description != NULL)
-                               printf(" (%s)", devpointer->description);
-                       if (devpointer->flags != 0)
-                               printf(" [%s]", bittok2str(status_flags, "none", devpointer->flags));
-                       printf("\n");
-                       devpointer = devpointer->next;
-               }
+       for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) {
+               printf("%d.%s", i+1, dev->name);
+               if (dev->description != NULL)
+                       printf(" (%s)", dev->description);
+               if (dev->flags != 0)
+                       printf(" [%s]", bittok2str(status_flags, "none", dev->flags));
+               printf("\n");
        }
+       pcap_freealldevs(devlist);
        exit(0);
 }
 #endif /* HAVE_PCAP_FINDALLDEVS */
@@ -455,7 +516,7 @@ static const struct option longopts[] = {
 #ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
        { "immediate-mode", no_argument, NULL, OPTION_IMMEDIATE_MODE },
 #endif
-#if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG)
+#ifdef HAVE_PCAP_SET_PARSER_DEBUG
        { "debug-filter-parser", no_argument, NULL, 'Y' },
 #endif
        { "relinquish-privileges", required_argument, NULL, 'Z' },
@@ -701,7 +762,6 @@ main(int argc, char **argv)
        register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName;
        pcap_handler callback;
        int dlt;
-       int new_dlt;
        const char *dlt_name;
        struct bpf_program fcode;
 #ifndef _WIN32
@@ -716,7 +776,7 @@ main(int argc, char **argv)
        char *ret = NULL;
        char *end;
 #ifdef HAVE_PCAP_FINDALLDEVS
-       pcap_if_t *devpointer;
+       pcap_if_t *dev, *devlist;
        int devnum;
 #endif
        int status;
@@ -883,20 +943,20 @@ main(int argc, char **argv)
                                if (devnum < 0)
                                        error("Invalid adapter index");
 
-                               if (pcap_findalldevs(&devpointer, ebuf) < 0)
+                               if (pcap_findalldevs(&devlist, ebuf) < 0)
                                        error("%s", ebuf);
                                /*
                                 * Look for the devnum-th entry in the
                                 * list of devices (1-based).
                                 */
-                               for (i = 0;
-                                   i < devnum-1 && devpointer != NULL;
-                                   i++, devpointer = devpointer->next)
+                               for (i = 0, dev = devlist;
+                                   i < devnum-1 && dev != NULL;
+                                   i++, dev = dev->next)
                                        ;
-                               if (devpointer == NULL)
+                               if (dev == NULL)
                                        error("Invalid adapter index");
-                               device = strdup(devpointer->name);
-                               pcap_freealldevs(devpointer);
+                               device = strdup(dev->name);
+                               pcap_freealldevs(devlist);
                                break;
                        }
 #endif /* HAVE_PCAP_FINDALLDEVS */
@@ -1055,6 +1115,8 @@ main(int argc, char **argv)
                                ndo->ndo_packettype = PT_PGM_ZMTP1;
                        else if (ascii_strcasecmp(optarg, "lmp") == 0)
                                ndo->ndo_packettype = PT_LMP;
+            else if (strcasecmp(optarg, "resp") == 0)
+                ndo->ndo_packettype = PT_RESP;
                        else
                                error("unknown packet type `%s'", optarg);
                        break;
@@ -1106,30 +1168,20 @@ main(int argc, char **argv)
                                error("invalid data link type %s", yflag_dlt_name);
                        break;
 
-#if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG)
+#ifdef HAVE_PCAP_SET_PARSER_DEBUG
                case 'Y':
                        {
                        /* Undocumented flag */
-#ifdef HAVE_PCAP_DEBUG
-                       extern int pcap_debug;
-                       pcap_debug = 1;
-#else
-                       extern int yydebug;
-                       yydebug = 1;
-#endif
+                       pcap_set_parser_debug(1);
                        }
                        break;
 #endif
                case 'z':
-                       zflag = strdup(optarg);
-                       if (zflag == NULL)
-                               error("Unable to allocate memory for -z argument");
+                       zflag = optarg;
                        break;
 
                case 'Z':
-                       username = strdup(optarg);
-                       if (username == NULL)
-                               error("Unable to allocate memory for -Z argument");
+                       username = optarg;
                        break;
 
                case '#':
@@ -1249,7 +1301,7 @@ main(int argc, char **argv)
                                VFile = fopen(VFileName, "r");
 
                        if (VFile == NULL)
-                               error("Unable to open file: %s\n", strerror(errno));
+                               error("Unable to open file: %s\n", pcap_strerror(errno));
 
                        ret = get_next_file(VFile, VFileLine);
                        if (!ret)
@@ -1290,10 +1342,10 @@ main(int argc, char **argv)
                 */
                if (device == NULL) {
 #ifdef HAVE_PCAP_FINDALLDEVS
-                       if (pcap_findalldevs(&devpointer, ebuf) >= 0 &&
-                           devpointer != NULL) {
-                               device = strdup(devpointer->name);
-                               pcap_freealldevs(devpointer);
+                       if (pcap_findalldevs(&devlist, ebuf) >= 0 &&
+                           devlist != NULL) {
+                               device = strdup(devlist->name);
+                               pcap_freealldevs(devlist);
                        }
 #else /* HAVE_PCAP_FINDALLDEVS */
                        device = pcap_lookupdev(ebuf);
@@ -1482,12 +1534,16 @@ main(int argc, char **argv)
        else
                cmdbuf = copy_argv(&argv[optind]);
 
+#ifdef HAVE_PCAP_SET_OPTIMIZER_DEBUG
+       pcap_set_optimizer_debug(dflag);
+#endif
        if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
                error("%s", pcap_geterr(pd));
        if (dflag) {
                bpf_dump(&fcode, dflag);
                pcap_close(pd);
                free(cmdbuf);
+               pcap_freecode(&fcode);
                exit(0);
        }
        init_print(ndo, localnet, netmask, timezone_offset);
@@ -1557,7 +1613,7 @@ main(int argc, char **argv)
                error("%s", pcap_geterr(pd));
 #ifdef HAVE_CAPSICUM
        if (RFileName == NULL && VFileName == NULL) {
-               static const unsigned long cmds[] = { BIOCGSTATS };
+               static const unsigned long cmds[] = { BIOCGSTATS, BIOCROTZBUF };
 
                cap_rights_init(&rights, CAP_IOCTL, CAP_READ);
                if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 &&
@@ -1749,6 +1805,8 @@ main(int argc, char **argv)
                if (VFileName != NULL) {
                        ret = get_next_file(VFile, VFileLine);
                        if (ret) {
+                               int new_dlt;
+
                                RFileName = VFileLine;
                                pd = pcap_open_offline(RFileName, ebuf);
                                if (pd == NULL)
@@ -1761,29 +1819,66 @@ main(int argc, char **argv)
                                }
 #endif
                                new_dlt = pcap_datalink(pd);
-                               if (WFileName && new_dlt != dlt)
-                                       error("%s: new dlt does not match original", RFileName);
-                               ndo->ndo_if_printer = get_if_printer(ndo, new_dlt);
-                               dlt_name = pcap_datalink_val_to_name(new_dlt);
+                               if (new_dlt != dlt) {
+                                       /*
+                                        * The new file has a different
+                                        * link-layer header type from the
+                                        * previous one.
+                                        */
+                                       if (WFileName != NULL) {
+                                               /*
+                                                * We're writing raw packets
+                                                * that match the filter to
+                                                * a pcap file.  pcap files
+                                                * don't support multiple
+                                                * different link-layer
+                                                * header types, so we fail
+                                                * here.
+                                                */
+                                               error("%s: new dlt does not match original", RFileName);
+                                       }
+
+                                       /*
+                                        * We're printing the decoded packets;
+                                        * switch to the new DLT.
+                                        *
+                                        * To do that, we need to change
+                                        * the printer, change the DLT name,
+                                        * and recompile the filter with
+                                        * the new DLT.
+                                        */
+                                       dlt = new_dlt;
+                                       ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+                                       dlt_name = pcap_datalink_val_to_name(dlt);
+                                       if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+                                               error("%s", pcap_geterr(pd));
+                               }
+
+                               /*
+                                * Set the filter on the new file.
+                                */
+                               if (pcap_setfilter(pd, &fcode) < 0)
+                                       error("%s", pcap_geterr(pd));
+
+                               /*
+                                * Report the new file.
+                                */
                                if (dlt_name == NULL) {
                                        fprintf(stderr, "reading from file %s, link-type %u\n",
-                                       RFileName, new_dlt);
+                                           RFileName, dlt);
                                } else {
                                        fprintf(stderr,
                                        "reading from file %s, link-type %s (%s)\n",
-                                       RFileName, dlt_name,
-                                       pcap_datalink_val_to_description(new_dlt));
+                                           RFileName, dlt_name,
+                                           pcap_datalink_val_to_description(dlt));
                                }
-                               if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
-                                       error("%s", pcap_geterr(pd));
-                               if (pcap_setfilter(pd, &fcode) < 0)
-                                       error("%s", pcap_geterr(pd));
                        }
                }
        }
        while (ret != NULL);
 
        free(cmdbuf);
+       pcap_freecode(&fcode);
        exit(status == -1 ? 1 : 0);
 }
 
@@ -1886,17 +1981,31 @@ info(register int verbose)
 }
 
 #if defined(HAVE_FORK) || defined(HAVE_VFORK)
+#ifdef HAVE_FORK
+#define fork_subprocess() fork()
+#else
+#define fork_subprocess() vfork()
+#endif
 static void
 compress_savefile(const char *filename)
 {
-# ifdef HAVE_FORK
-       if (fork())
-# else
-       if (vfork())
-# endif
+       pid_t child;
+
+       child = fork_subprocess();
+       if (child == -1) {
+               fprintf(stderr,
+                       "compress_savefile: fork failed: %s\n",
+                       pcap_strerror(errno));
                return;
+       }
+       if (child != 0) {
+               /* Parent process. */
+               return;
+       }
+
        /*
-        * Set to lowest priority so that this doesn't disturb the capture
+        * Child process.
+        * Set to lowest priority so that this doesn't disturb the capture.
         */
 #ifdef NZERO
        setpriority(PRIO_PROCESS, 0, NZERO - 1);
@@ -1905,15 +2014,15 @@ compress_savefile(const char *filename)
 #endif
        if (execlp(zflag, zflag, filename, (char *)NULL) == -1)
                fprintf(stderr,
-                       "compress_savefile:execlp(%s, %s): %s\n",
+                       "compress_savefile: execlp(%s, %s) failed: %s\n",
                        zflag,
                        filename,
-                       strerror(errno));
-# ifdef HAVE_FORK
+                       pcap_strerror(errno));
+#ifdef HAVE_FORK
        exit(1);
-# else
+#else
        _exit(1);
-# endif
+#endif
 }
 #else  /* HAVE_FORK && HAVE_VFORK */
 static void
@@ -2279,7 +2388,7 @@ print_usage(void)
 #endif
        (void)fprintf(stderr, "[ -T type ] [ --version ] [ -V file ]\n");
        (void)fprintf(stderr,
-"\t\t[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z command ]\n");
+"\t\t[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ]\n");
        (void)fprintf(stderr,
 "\t\t[ -Z user ] [ expression ]\n");
 }