X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/12857bf113ae8409fbdf994ca9c6a5977dd77856..refs/heads/tcpdump-4.9:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index ff8d8e8c..8f27ba2a 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -108,6 +108,7 @@ The Regents of the University of California. All rights reserved.\n"; #endif /* HAVE_CAP_NG_H */ #endif /* HAVE_LIBCAP_NG */ +#include "netdissect-stdinc.h" #include "netdissect.h" #include "interface.h" #include "addrtoname.h" @@ -130,7 +131,7 @@ The Regents of the University of California. All rights reserved.\n"; #endif static int Bflag; /* buffer size */ -static int Cflag; /* rotate dump files after this many bytes */ +static long 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 */ /* @@ -157,7 +158,7 @@ static int Jflag; /* list available time stamp types */ static int jflag = -1; /* packet time stamp source */ static int pflag; /* don't go promiscuous */ #ifdef HAVE_PCAP_SETDIRECTION -int Qflag = -1; /* restrict captured packet by send/receive direction */ +static int Qflag = -1; /* restrict captured packet by send/receive direction */ #endif static int Uflag; /* "unbuffered" output of dump files */ static int Wflag; /* recycle output files after this number of files */ @@ -171,24 +172,18 @@ static int infoprint; char *program_name; /* Forwards */ -static void error(const char *, ...) - __attribute__((noreturn)) -#ifdef __ATTRIBUTE___FORMAT_OK - __attribute__((format (printf, 1, 2))) -#endif /* __ATTRIBUTE___FORMAT_OK */ - ; -static void warning(const char *, ...) -#ifdef __ATTRIBUTE___FORMAT_OK - __attribute__((format (printf, 1, 2))) -#endif /* __ATTRIBUTE___FORMAT_OK */ - ; -static void exit_tcpdump(int) __attribute__((noreturn)); +static void error(FORMAT_STRING(const char *), ...) NORETURN PRINTFLIKE(1, 2); +static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); +static void exit_tcpdump(int) NORETURN; static RETSIGTYPE cleanup(int); static RETSIGTYPE child_cleanup(int); static void print_version(void); static void print_usage(void); -static void show_tstamp_types_and_exit(const char *device) __attribute__((noreturn)); -static void show_dlts_and_exit(const char *device) __attribute__((noreturn)); +static void show_tstamp_types_and_exit(pcap_t *, const char *device) NORETURN; +static void show_dlts_and_exit(pcap_t *, const char *device) NORETURN; +#ifdef HAVE_PCAP_FINDALLDEVS +static void show_devices_and_exit (void) NORETURN; +#endif 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 *); @@ -337,16 +332,16 @@ exit_tcpdump(int status) #ifdef HAVE_PCAP_SET_TSTAMP_TYPE static void -show_tstamp_types_and_exit(const char *device) +show_tstamp_types_and_exit(pcap_t *pc, const char *device) { int n_tstamp_types; int *tstamp_types = 0; const char *tstamp_type_name; int i; - n_tstamp_types = pcap_list_tstamp_types(pd, &tstamp_types); + n_tstamp_types = pcap_list_tstamp_types(pc, &tstamp_types); if (n_tstamp_types < 0) - error("%s", pcap_geterr(pd)); + error("%s", pcap_geterr(pc)); if (n_tstamp_types == 0) { fprintf(stderr, "Time stamp type cannot be set for %s\n", @@ -370,15 +365,15 @@ show_tstamp_types_and_exit(const char *device) #endif static void -show_dlts_and_exit(const char *device) +show_dlts_and_exit(pcap_t *pc, const char *device) { int n_dlts, i; int *dlts = 0; const char *dlt_name; - n_dlts = pcap_list_datalinks(pd, &dlts); + n_dlts = pcap_list_datalinks(pc, &dlts); if (n_dlts < 0) - error("%s", pcap_geterr(pd)); + error("%s", pcap_geterr(pc)); else if (n_dlts == 0 || !dlts) error("No data link types."); @@ -455,7 +450,7 @@ show_devices_and_exit (void) * OS X tcpdump uses -g to force non--v output for IP to be on one * line, making it more "g"repable; * - * OS X tcpdump uses -k tospecify that packet comments in pcap-ng files + * OS X tcpdump uses -k to specify that packet comments in pcap-ng files * should be printed; * * OpenBSD tcpdump uses -o to indicate that OS fingerprinting should be done @@ -613,11 +608,10 @@ droproot(const char *username, const char *chroot_dir) #ifdef HAVE_LIBCAP_NG { int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG); - if (ret < 0) { - fprintf(stderr, "error : ret %d\n", ret); - } else { + if (ret < 0) + error("capng_change_id(): return %d\n", ret); + else fprintf(stderr, "dropped privs to %s\n", username); - } } #else if (initgroups(pw->pw_name, pw->pw_gid) != 0 || @@ -640,12 +634,13 @@ droproot(const char *username, const char *chroot_dir) exit_tcpdump(1); } #ifdef HAVE_LIBCAP_NG - /* We don't need CAP_SETUID and CAP_SETGID any more. */ + /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */ capng_updatev( CAPNG_DROP, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_SETUID, CAP_SETGID, + CAP_SYS_CHROOT, -1); capng_apply(CAPNG_SELECT_BOTH); #endif /* HAVE_LIBCAP_NG */ @@ -705,13 +700,15 @@ static char * get_next_file(FILE *VFile, char *ptr) { char *ret; + size_t len; ret = fgets(ptr, PATH_MAX, VFile); if (!ret) return NULL; - if (ptr[strlen(ptr) - 1] == '\n') - ptr[strlen(ptr) - 1] = '\0'; + len = strlen (ptr); + if (len > 0 && ptr[len - 1] == '\n') + ptr[len - 1] = '\0'; return ret; } @@ -865,15 +862,22 @@ read_infile(char *fname) { register int i, fd, cc; register 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, @@ -882,7 +886,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 (%d != %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 */ @@ -971,7 +976,7 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf) } #ifdef HAVE_PCAP_SET_TSTAMP_TYPE if (Jflag) - show_tstamp_types_and_exit(device); + show_tstamp_types_and_exit(pc, device); #endif #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION status = pcap_set_tstamp_precision(pc, ndo->ndo_tstamp_precision); @@ -1028,6 +1033,10 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf) if (status < 0) error("%s: Can't set time stamp type: %s", device, pcap_statustostr(status)); + else if (status > 0) + warning("When trying to set timestamp type '%s' on %s: %s", + pcap_tstamp_type_val_to_name(jflag), device, + pcap_statustostr(status)); } #endif status = pcap_activate(pc); @@ -1042,9 +1051,9 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf) /* * Return an error for our caller to handle. */ - pcap_close(pc); 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, @@ -1726,7 +1735,7 @@ main(int argc, char **argv) } #endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */ if (Lflag) - show_dlts_and_exit(device); + show_dlts_and_exit(pd, device); if (yflag_dlt >= 0) { #ifdef HAVE_PCAP_SET_DATALINK if (pcap_set_datalink(pd, yflag_dlt) < 0) @@ -1822,6 +1831,13 @@ main(int argc, char **argv) CAP_SETGID, -1); } + if (chroot_dir) { + capng_update( + CAPNG_ADD, + CAPNG_PERMITTED | CAPNG_EFFECTIVE, + CAP_SYS_CHROOT + ); + } if (WFileName) { capng_update( @@ -1844,7 +1860,12 @@ main(int argc, char **argv) if (RFileName == NULL && VFileName == NULL) { static const unsigned long cmds[] = { BIOCGSTATS, BIOCROTZBUF }; - cap_rights_init(&rights, CAP_IOCTL, CAP_READ); + /* + * The various libpcap devices use a combination of + * read (bpf), ioctl (bpf, netmap), poll (netmap) + * so we add the relevant access rights. + */ + cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_EVENT); if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 && errno != ENOSYS) { error("unable to limit pcap descriptor"); @@ -2319,6 +2340,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) { (void)fprintf(stderr, "Maximum file limit reached: %d\n", Wflag); + info(1); exit_tcpdump(0); /* NOTREACHED */ } @@ -2587,6 +2609,14 @@ print_version(void) smi_version_string = nd_smi_version_string(); if (smi_version_string != NULL) (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string); + +#if defined(__SANITIZE_ADDRESS__) + (void)fprintf (stderr, "Compiled with AddressSanitizer/GCC.\n"); +#elif defined(__has_feature) +# if __has_feature(address_sanitizer) + (void)fprintf (stderr, "Compiled with AddressSanitizer/CLang.\n"); +# endif +#endif /* __SANITIZE_ADDRESS__ or __has_feature */ } USES_APPLE_RST