X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/7885cfa165458a05ef818c34ee03affc79f03725..a36b3aeb877e4357918cfd99ddad5ce913a3a0b6:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index 06d3d9b9..2efb549b 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -124,6 +124,16 @@ The Regents of the University of California. All rights reserved.\n"; #include #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. @@ -141,6 +151,7 @@ The Regents of the University of California. All rights reserved.\n"; #include #endif /* __FreeBSD__ */ +#include "netdissect-stdinc.h" #include "netdissect.h" #include "interface.h" #include "addrtoname.h" @@ -232,29 +243,15 @@ cap_channel_t *capdns; #endif /* Forwards */ -static NORETURN void error(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); -static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); -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); -#ifdef HAVE_PCAP_SET_TSTAMP_TYPE -static NORETURN void show_tstamp_types_and_exit(pcap_t *, const char *device); -#endif -static NORETURN void show_dlts_and_exit(pcap_t *, const char *device); -#ifdef HAVE_PCAP_FINDALLDEVS -static NORETURN void show_devices_and_exit(void); -#endif -#ifdef HAVE_PCAP_FINDALLDEVS_EX -static NORETURN void show_remote_devices_and_exit(void); -#endif +static void print_version(FILE *); +static void print_usage(FILE *); static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); -static void droproot(const char *, const char *); #ifdef SIGNAL_REQ_INFO static void requestinfo(int); @@ -361,9 +358,16 @@ extern void pcap_set_optimizer_debug(int); #endif +static void NORETURN +exit_tcpdump(const int status) +{ + nd_cleanup(); + exit(status); +} + /* VARARGS */ -static void -error(const char *fmt, ...) +static void NORETURN PRINTFLIKE(1, 2) +error(FORMAT_STRING(const char *fmt), ...) { va_list ap; @@ -381,8 +385,8 @@ error(const char *fmt, ...) } /* VARARGS */ -static void -warning(const char *fmt, ...) +static void PRINTFLIKE(1, 2) +warning(FORMAT_STRING(const char *fmt), ...) { va_list ap; @@ -397,15 +401,8 @@ warning(const char *fmt, ...) } } -static void -exit_tcpdump(int status) -{ - nd_cleanup(); - exit(status); -} - #ifdef HAVE_PCAP_SET_TSTAMP_TYPE -static void +static void NORETURN show_tstamp_types_and_exit(pcap_t *pc, const char *device) { int n_tstamp_types; @@ -422,15 +419,15 @@ show_tstamp_types_and_exit(pcap_t *pc, const char *device) device); exit_tcpdump(S_SUCCESS); } - fprintf(stderr, "Time stamp types for %s (use option -j to set):\n", + fprintf(stdout, "Time stamp types for %s (use option -j to set):\n", device); for (i = 0; i < n_tstamp_types; i++) { tstamp_type_name = pcap_tstamp_type_val_to_name(tstamp_types[i]); if (tstamp_type_name != NULL) { - (void) fprintf(stderr, " %s (%s)\n", tstamp_type_name, + (void) fprintf(stdout, " %s (%s)\n", tstamp_type_name, pcap_tstamp_type_val_to_description(tstamp_types[i])); } else { - (void) fprintf(stderr, " %d\n", tstamp_types[i]); + (void) fprintf(stdout, " %d\n", tstamp_types[i]); } } pcap_free_tstamp_types(tstamp_types); @@ -438,7 +435,7 @@ show_tstamp_types_and_exit(pcap_t *pc, const char *device) } #endif -static void +static void NORETURN show_dlts_and_exit(pcap_t *pc, const char *device) { int n_dlts, i; @@ -459,28 +456,30 @@ show_dlts_and_exit(pcap_t *pc, const char *device) * monitor mode might be different from the ones available when * not in monitor mode). */ + (void) fprintf(stdout, "Data link types for "); if (supports_monitor_mode) - (void) fprintf(stderr, "Data link types for %s %s (use option -y to set):\n", + (void) fprintf(stdout, "%s %s", device, Iflag ? "when in monitor mode" : "when not in monitor mode"); else - (void) fprintf(stderr, "Data link types for %s (use option -y to set):\n", + (void) fprintf(stdout, "%s", device); + (void) fprintf(stdout, " (use option -y to set):\n"); for (i = 0; i < n_dlts; i++) { dlt_name = pcap_datalink_val_to_name(dlts[i]); if (dlt_name != NULL) { - (void) fprintf(stderr, " %s (%s)", dlt_name, + (void) fprintf(stdout, " %s (%s)", dlt_name, pcap_datalink_val_to_description(dlts[i])); /* * OK, does tcpdump handle that type? */ if (!has_printer(dlts[i])) - (void) fprintf(stderr, " (printing not supported)"); - fprintf(stderr, "\n"); + (void) fprintf(stdout, " (printing not supported)"); + fprintf(stdout, "\n"); } else { - (void) fprintf(stderr, " DLT %d (printing not supported)\n", + (void) fprintf(stdout, " DLT %d (printing not supported)\n", dlts[i]); } } @@ -491,7 +490,7 @@ show_dlts_and_exit(pcap_t *pc, const char *device) } #ifdef HAVE_PCAP_FINDALLDEVS -static void +static void NORETURN show_devices_and_exit(void) { pcap_if_t *dev, *devlist; @@ -556,7 +555,7 @@ show_devices_and_exit(void) #endif /* HAVE_PCAP_FINDALLDEVS */ #ifdef HAVE_PCAP_FINDALLDEVS_EX -static void +static void NORETURN show_remote_devices_and_exit(void) { pcap_if_t *dev, *devlist; @@ -831,7 +830,7 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars) { char *filename = malloc(PATH_MAX + 1); if (filename == NULL) - error("Makefilename: malloc"); + error("%s: malloc", __func__); /* Process with strftime if Gflag is set. */ if (Gflag != 0) { @@ -839,7 +838,7 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars) /* Convert Gflag_time to a usable format */ if ((local_tm = localtime(&Gflag_time)) == NULL) { - error("MakeTimedFilename: localtime"); + error("%s: localtime", __func__); } /* There's no good way to detect an error in strftime since a return @@ -1025,7 +1024,7 @@ copy_argv(char **argv) buf = (char *)malloc(len); if (buf == NULL) - error("copy_argv: malloc"); + error("%s: malloc", __func__); p = argv; dst = buf; @@ -1055,15 +1054,22 @@ read_infile(char *fname) int i, fd; ssize_t cc; char *cp; - struct stat buf; + our_statb buf; fd = open(fname, O_RDONLY|O_BINARY); if (fd < 0) error("can't open %s: %s", fname, pcap_strerror(errno)); - if (fstat(fd, &buf) < 0) + if (our_fstat(fd, &buf) < 0) error("can't stat %s: %s", fname, pcap_strerror(errno)); + /* + * Reject files whose size doesn't fit into an int; a filter + * *that* large will probably be too big. + */ + if (buf.st_size > INT_MAX) + error("%s is too large", fname); + cp = malloc((u_int)buf.st_size + 1); if (cp == NULL) error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, @@ -1072,7 +1078,8 @@ read_infile(char *fname) if (cc < 0) error("read %s: %s", fname, pcap_strerror(errno)); if (cc != buf.st_size) - error("short read %s (%zd != %d)", fname, cc, (int)buf.st_size); + error("short read %s (%d != %d)", fname, (int) cc, + (int)buf.st_size); close(fd); /* replace "# comment" with spaces */ @@ -1477,6 +1484,7 @@ main(int argc, char **argv) int yflag_dlt = -1; const char *yflag_dlt_name = NULL; int print = 0; + long Cflagmult = 1000000; netdissect_options Ndo; netdissect_options *ndo = &Ndo; @@ -1498,7 +1506,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]; @@ -1553,6 +1561,18 @@ main(int argc, char **argv) case 'C': errno = 0; + if (optarg[strlen(optarg)-1] == 'k') { + Cflagmult = 1024; + optarg[strlen(optarg)-1] = '\0'; + } + if (optarg[strlen(optarg)-1] == 'm') { + Cflagmult = 1024*1024; + optarg[strlen(optarg)-1] = '\0'; + } + if (optarg[strlen(optarg)-1] == 'g') { + Cflagmult = 1024*1024*1024; + optarg[strlen(optarg)-1] = '\0'; + } #ifdef HAVE_PCAP_DUMP_FTELL64 Cflag = strtoint64_t(optarg, &endp, 10); #else @@ -1562,15 +1582,15 @@ main(int argc, char **argv) || Cflag <= 0) error("invalid file size %s", optarg); /* - * Will multiplying it by 1000000 overflow? + * Will multiplying it by multiplier overflow? */ #ifdef HAVE_PCAP_DUMP_FTELL64 - if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffff) / 1000000) + if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffff) / Cflagmult) #else - if (Cflag > LONG_MAX / 1000000) + if (Cflag > LONG_MAX / Cflagmult) #endif error("file size %s is too large", optarg); - Cflag *= 1000000; + Cflag *= Cflagmult; break; case 'd': @@ -1622,13 +1642,13 @@ main(int argc, char **argv) /* Grab the current time for rotation use. */ if ((Gflag_time = time(NULL)) == (time_t)-1) { - error("main: can't get current time: %s", - pcap_strerror(errno)); + error("%s: can't get current time: %s", + __func__, pcap_strerror(errno)); } break; case 'h': - print_usage(); + print_usage(stdout); exit_tcpdump(S_SUCCESS); break; @@ -1870,7 +1890,7 @@ main(int argc, char **argv) break; case OPTION_VERSION: - print_version(); + print_version(stdout); exit_tcpdump(S_SUCCESS); break; @@ -1918,7 +1938,7 @@ main(int argc, char **argv) break; default: - print_usage(); + print_usage(stderr); exit_tcpdump(S_ERR_HOST_PROGRAM); /* NOTREACHED */ } @@ -2400,7 +2420,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; @@ -2411,7 +2431,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; } @@ -2428,11 +2448,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 /* @@ -2584,7 +2607,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)); } @@ -2614,7 +2637,7 @@ DIAG_ON_CLANG(assign-enum) while (ret != NULL); if (count_mode && RFileName != NULL) - fprintf(stderr, "%u packet%s\n", packets_captured, + fprintf(stdout, "%u packet%s\n", packets_captured, PLURAL_SUFFIX(packets_captured)); free(cmdbuf); @@ -2827,8 +2850,8 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s /* Get the current time */ if ((t = time(NULL)) == (time_t)-1) { - error("dump_and_trunc_packet: can't get current_time: %s", - pcap_strerror(errno)); + error("%s: can't get current_time: %s", + __func__, pcap_strerror(errno)); } @@ -2969,7 +2992,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s free(dump_info->CurrentFileName); dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1); if (dump_info->CurrentFileName == NULL) - error("dump_packet_and_trunc: malloc"); + error("%s: malloc", __func__); MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars); #ifdef HAVE_LIBCAP_NG capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); @@ -3107,7 +3130,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 @@ -3118,61 +3141,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 (stderr, "Compiled with MemorySanitizer/Clang.\n"); + (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, + 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(stderr, + (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"); }