X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/11e8f0a2ecaf6e391ab412b1b23ece0ddac2dd0c..c602726f3a91f2c344bde10c6e2f3c6149a15adc:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index bddf963f..d5766712 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -34,6 +34,9 @@ */ #include +#ifndef TCPDUMP_CONFIG_H_ +#error "The included config.h header is not from the tcpdump build." +#endif #include "netdissect-stdinc.h" @@ -141,7 +144,6 @@ The Regents of the University of California. All rights reserved.\n"; #include "netdissect.h" #include "interface.h" #include "addrtoname.h" -#include "pcap-missing.h" #include "ascii_strcasecmp.h" #include "print.h" @@ -165,11 +167,7 @@ The Regents of the University of California. All rights reserved.\n"; #endif static int Bflag; /* buffer size */ -#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 */ static int Dflag; /* list available devices and exit */ #ifdef HAVE_PCAP_FINDALLDEVS_EX @@ -205,12 +203,15 @@ static int Qflag = -1; /* restrict captured packet by send/receive direction * static int Uflag; /* "unbuffered" output of dump files */ 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; @@ -218,9 +219,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 *); @@ -314,7 +323,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) /* @@ -329,7 +338,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) @@ -406,7 +415,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) @@ -514,7 +523,7 @@ show_devices_and_exit(void) break; } } -#endif +#endif // PCAP_IF_WIRELESS printf("]"); } printf("\n"); @@ -641,6 +650,8 @@ show_remote_devices_and_exit(void) #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[] = { { "buffer-size", required_argument, NULL, 'B' }, @@ -682,6 +693,8 @@ static const struct option longopts[] = { { "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 } }; @@ -719,7 +732,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); } @@ -895,7 +908,7 @@ tstamp_precision_to_string(int precision) return "unknown"; } } -#endif +#endif // HAVE_PCAP_SET_TSTAMP_PRECISION #ifdef HAVE_CAPSICUM /* @@ -965,7 +978,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. @@ -1096,7 +1109,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 { @@ -1161,7 +1174,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); @@ -1339,6 +1352,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) { @@ -1356,13 +1374,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)); @@ -1417,7 +1435,6 @@ main(int argc, char **argv) const char *chroot_dir = NULL; #endif char *ret = NULL; - char *end; pcap_if_t *devlist; long devnum; int status; @@ -1435,6 +1452,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. */ @@ -1489,26 +1657,24 @@ main(int argc, char **argv) break; 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; 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') { /* @@ -1553,7 +1719,7 @@ main(int argc, char **argv) break; default: - error("invalid file size %s", optarg); + error("invalid file size %s (invalid units)", optarg); } /* @@ -1564,7 +1730,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); } } @@ -1572,7 +1738,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 @@ -1618,9 +1784,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; @@ -1739,11 +1904,8 @@ main(int argc, char **argv) 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': @@ -1822,9 +1984,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; @@ -1855,7 +2016,11 @@ main(int argc, char **argv) break; #endif case 'z': +#if defined(HAVE_FORK) || defined(HAVE_VFORK) zflag = optarg; +#else + error("-z cannot be used. Fork subprocess not implemented."); +#endif break; case 'Z': @@ -1870,6 +2035,10 @@ main(int argc, char **argv) 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); @@ -1896,9 +2065,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 @@ -1932,6 +2105,27 @@ main(int argc, char **argv) /* NOTREACHED */ } + 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(); #ifdef HAVE_PCAP_FINDALLDEVS_EX @@ -1955,7 +2149,7 @@ main(int argc, char **argv) } 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."); @@ -2023,11 +2217,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; } @@ -2199,7 +2393,11 @@ DIAG_ON_WARN_UNUSED_RESULT #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); @@ -2214,6 +2412,7 @@ DIAG_ON_WARN_UNUSED_RESULT capdns = capdns_setup(); #endif /* HAVE_CASPER */ + // Both localnet and netmask are in network byte order. init_print(ndo, localnet, netmask); #ifndef _WIN32 @@ -2527,7 +2726,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, @@ -2615,7 +2816,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)); } @@ -2652,6 +2857,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. */ @@ -2787,8 +3120,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) { @@ -2807,24 +3140,15 @@ 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 */ -static void -compress_savefile(const char *filename) -{ - fprintf(stderr, - "compress_savefile failed. Functionality not implemented under your system\n"); -} -#endif /* HAVE_FORK && HAVE_VFORK */ +#endif /* HAVE_FORK || HAVE_VFORK */ static void close_old_dump_file(struct dump_info *dump_info) @@ -2834,11 +3158,13 @@ close_old_dump_file(struct dump_info *dump_info) */ 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 @@ -2889,6 +3215,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 @@ -3018,6 +3347,9 @@ 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); if (Uflag) pcap_dump_flush(dump_info->pdd); @@ -3037,7 +3369,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; @@ -3145,7 +3477,7 @@ print_usage(FILE *f) (void)fprintf(f, "\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