X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/0501579a69b85ae7a3f060f416a787723d080728..68a0f9980d04dc89b2fb29e5b721ad7606d9733b:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index cebc1f2d..282d44c9 100644 --- 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; @@ -804,7 +864,7 @@ main(int argc, char **argv) case 'C': Cflag = atoi(optarg) * 1000000; - if (Cflag < 0) + if (Cflag <= 0) error("invalid file size %s", optarg); break; @@ -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; @@ -1083,7 +1145,7 @@ main(int argc, char **argv) case 'W': Wflag = atoi(optarg); - if (Wflag < 0) + if (Wflag <= 0) error("invalid number of output files %s", optarg); WflagChars = getWflagChars(Wflag); 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); + 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. + */ + dlt_name = pcap_datalink_val_to_name(dlt); 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"); }