X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/4a2fb51da7ada0cecf94a5a94c7146bc36dd72b0..febd0bc5aa33b3de9b5864e8c5565fe7b63f519f:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index bde74864..270f79b4 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -44,9 +44,10 @@ The Regents of the University of California. All rights reserved.\n"; #endif /* - * Mac OS X may ship pcap.h from libpcap 0.6 with a libpcap based on - * 0.8. That means it has pcap_findalldevs() but the header doesn't - * define pcap_if_t, meaning that we can't actually *use* pcap_findalldevs(). + * Some older versions of Mac OS X may ship pcap.h from libpcap 0.6 with a + * libpcap based on 0.8. That means it has pcap_findalldevs() but the + * header doesn't define pcap_if_t, meaning that we can't actually *use* + * pcap_findalldevs(). */ #ifdef HAVE_PCAP_FINDALLDEVS #ifndef HAVE_PCAP_IF_T @@ -80,6 +81,11 @@ The Regents of the University of California. All rights reserved.\n"; #include #include #include +#ifdef HAVE_CASPER +#include +#include +#include +#endif /* HAVE_CASPER */ #endif /* HAVE_CAPSICUM */ #include #include @@ -108,6 +114,10 @@ The Regents of the University of California. All rights reserved.\n"; #endif /* HAVE_CAP_NG_H */ #endif /* HAVE_LIBCAP_NG */ +#ifdef __FreeBSD__ +#include +#endif /* __FreeBSD__ */ + #include "netdissect.h" #include "interface.h" #include "addrtoname.h" @@ -130,7 +140,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 +167,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 */ @@ -170,27 +180,22 @@ static int infoprint; char *program_name; +#ifdef HAVE_CASPER +cap_channel_t *capdns; +#endif + /* 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 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 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 NORETURN void show_tstamp_types_and_exit(pcap_t *, const char *device); +static NORETURN void show_dlts_and_exit(pcap_t *, const char *device); #ifdef HAVE_PCAP_FINDALLDEVS -static void show_devices_and_exit (void) __attribute__((noreturn)); +static NORETURN void show_devices_and_exit(void); #endif static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); @@ -340,16 +345,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", @@ -373,15 +378,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."); @@ -458,7 +463,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 @@ -643,12 +648,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 */ @@ -719,6 +725,35 @@ get_next_file(FILE *VFile, char *ptr) return ret; } +#ifdef HAVE_CASPER +static cap_channel_t * +capdns_setup(void) +{ + cap_channel_t *capcas, *capdnsloc; + const char *types[1]; + int families[2]; + + capcas = cap_init(); + if (capcas == NULL) + error("unable to create casper process"); + capdnsloc = cap_service_open(capcas, "system.dns"); + /* Casper capability no longer needed. */ + cap_close(capcas); + if (capdnsloc == NULL) + error("unable to open system.dns service"); + /* Limit system.dns to reverse DNS lookups. */ + types[0] = "ADDR"; + if (cap_dns_type_limit(capdnsloc, types, 1) < 0) + error("unable to limit access to system.dns service"); + families[0] = AF_INET; + families[1] = AF_INET6; + if (cap_dns_family_limit(capdnsloc, families, 2) < 0) + error("unable to limit access to system.dns service"); + + return (capdnsloc); +} +#endif /* HAVE_CASPER */ + #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION static int tstamp_precision_from_string(const char *precision) @@ -974,7 +1009,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); @@ -1001,10 +1036,16 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf) supports_monitor_mode = 1; else supports_monitor_mode = 0; - status = pcap_set_snaplen(pc, ndo->ndo_snaplen); - if (status != 0) - error("%s: Can't set snapshot length: %s", - device, pcap_statustostr(status)); + if (ndo->ndo_snaplen != 0) { + /* + * A snapshot length was explicitly specified; + * use it. + */ + status = pcap_set_snaplen(pc, ndo->ndo_snaplen); + if (status != 0) + error("%s: Can't set snapshot length: %s", + device, pcap_statustostr(status)); + } status = pcap_set_promisc(pc, !pflag); if (status != 0) error("%s: Can't set promiscuous mode: %s", @@ -1045,13 +1086,37 @@ 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, pcap_statustostr(status), cp); +#ifdef __FreeBSD__ + else if (status == PCAP_ERROR_RFMON_NOTSUP && + strncmp(device, "wlan", 4) == 0) { + char parent[8], newdev[8]; + char sysctl[32]; + size_t s = sizeof(parent); + + snprintf(sysctl, sizeof(sysctl), + "net.wlan.%d.%%parent", atoi(device + 4)); + sysctlbyname(sysctl, parent, &s, NULL, 0); + strlcpy(newdev, device, sizeof(newdev)); + /* Suggest a new wlan device. */ + /* FIXME: incrementing the index this way is not going to work well + * when the index is 9 or greater but the only consequence in this + * 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" + "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 else error("%s: %s", device, pcap_statustostr(status)); @@ -1081,6 +1146,12 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf) #endif /* HAVE_PCAP_SETDIRECTION */ #else /* HAVE_PCAP_CREATE */ *ebuf = '\0'; + /* + * If no snapshot length was specified, or a length of 0 was + * specified, default to 256KB. + */ + if (ndo->ndo_snaplen == 0) + ndo->ndo_snaplen = 262144; pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, 1000, ebuf); if (pc == NULL) { /* @@ -1147,7 +1218,6 @@ main(int argc, char **argv) memset(ndo, 0, sizeof(*ndo)); ndo_set_function_pointers(ndo); - ndo->ndo_snaplen = DEFAULT_SNAPLEN; cnt = -1; device = NULL; @@ -1377,8 +1447,6 @@ main(int argc, char **argv) if (optarg == end || *end != '\0' || ndo->ndo_snaplen < 0 || ndo->ndo_snaplen > MAXIMUM_SNAPLEN) error("invalid snaplen %s", optarg); - else if (ndo->ndo_snaplen == 0) - ndo->ndo_snaplen = MAXIMUM_SNAPLEN; break; case 'S': @@ -1716,7 +1784,8 @@ main(int argc, char **argv) } /* - * Let user own process after socket has been opened. + * Let user own process after capture device has + * been opened. */ #ifndef _WIN32 if (setgid(getgid()) != 0 || setuid(getuid()) != 0) @@ -1729,7 +1798,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) @@ -1751,7 +1820,11 @@ main(int argc, char **argv) } i = pcap_snapshot(pd); if (ndo->ndo_snaplen < i) { - warning("snaplen raised from %d to %d", ndo->ndo_snaplen, i); + if (ndo->ndo_snaplen != 0) + warning("snaplen raised from %d to %d", ndo->ndo_snaplen, i); + ndo->ndo_snaplen = i; + } else if (ndo->ndo_snaplen > i) { + warning("snaplen lowered from %d to %d", ndo->ndo_snaplen, i); ndo->ndo_snaplen = i; } if(ndo->ndo_fflag != 0) { @@ -1778,6 +1851,12 @@ main(int argc, char **argv) pcap_freecode(&fcode); exit_tcpdump(0); } + +#ifdef HAVE_CASPER + if (!ndo->ndo_nflag) + capdns = capdns_setup(); +#endif /* HAVE_CASPER */ + init_print(ndo, localnet, netmask, timezone_offset); #ifndef _WIN32 @@ -1825,6 +1904,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( @@ -1847,7 +1933,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"); @@ -1987,7 +2078,12 @@ main(int argc, char **argv) } #ifdef HAVE_CAPSICUM - cansandbox = (ndo->ndo_nflag && VFileName == NULL && zflag == NULL); + cansandbox = (VFileName == NULL && zflag == NULL); +#ifdef HAVE_CASPER + cansandbox = (cansandbox && (ndo->ndo_nflag || capdns != NULL)); +#else + cansandbox = (cansandbox && ndo->ndo_nflag); +#endif /* HAVE_CASPER */ if (cansandbox && cap_enter() < 0 && errno != ENOSYS) error("unable to enter the capability mode"); #endif /* HAVE_CAPSICUM */ @@ -2322,6 +2418,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 */ } @@ -2590,6 +2687,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