X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/c6d472bf63488b0c2ab7ab9f4b32c68dd2c8ea2b..c115ab8ae92fd369ac227e93419e76fd6ae8e75c:/tcpdump.c?ds=sidebyside diff --git a/tcpdump.c b/tcpdump.c index 59994fb4..6a96ea94 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -56,13 +56,13 @@ The Regents of the University of California. All rights reserved.\n"; #include -#ifdef WIN32 +#ifdef _WIN32 #include "w32_fzs.h" extern int strcasecmp (const char *__s1, const char *__s2); extern int SIZE_BUF; #define off_t long #define uint UINT -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef USE_LIBSMI #include @@ -94,12 +94,12 @@ extern int SIZE_BUF; #include #include #include -#ifndef WIN32 +#ifndef _WIN32 #include #include #include #include -#endif /* WIN32 */ +#endif /* _WIN32 */ /* capabilities convenience library */ /* If a code depends on HAVE_LIBCAP_NG, it depends also on HAVE_CAP_NG_H. @@ -513,7 +513,7 @@ show_tstamp_types_and_exit(const char *device, pcap_t *pd) static void show_dlts_and_exit(const char *device, pcap_t *pd) { - int n_dlts; + int n_dlts, i; int *dlts = 0; const char *dlt_name; @@ -539,22 +539,22 @@ show_dlts_and_exit(const char *device, pcap_t *pd) (void) fprintf(stderr, "Data link types for %s (use option -y to set):\n", device); - while (--n_dlts >= 0) { - dlt_name = pcap_datalink_val_to_name(dlts[n_dlts]); + 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, - pcap_datalink_val_to_description(dlts[n_dlts])); + pcap_datalink_val_to_description(dlts[i])); /* * OK, does tcpdump handle that type? */ - if (lookup_printer(dlts[n_dlts]) == NULL - && lookup_ndo_printer(dlts[n_dlts]) == NULL) + if (lookup_printer(dlts[i]) == NULL + && lookup_ndo_printer(dlts[i]) == NULL) (void) fprintf(stderr, " (printing not supported)"); fprintf(stderr, "\n"); } else { (void) fprintf(stderr, " DLT %d (printing not supported)\n", - dlts[n_dlts]); + dlts[i]); } } #ifdef HAVE_PCAP_FREE_DATALINKS @@ -607,19 +607,28 @@ show_devices_and_exit (void) * * OS X tcpdump uses -P to indicate that -w should write pcap-ng rather * than pcap files. + * + * OS X tcpdump also uses -Q to specify expressions that match packet + * metadata, including but not limited to the packet direction. + * The expression syntax is different from a simple "in|out|inout", + * and those expressions aren't accepted by OS X tcpdump, but the + * equivalents would be "in" = "dir=in", "out" = "dir=out", and + * "inout" = "dir=in or dir=out", and the parser could conceivably + * special-case "in", "out", and "inout" as expressions for backwards + * compatibility, so all is not (yet) lost. */ /* * Set up flags that might or might not be supported depending on the * version of libpcap we're using. */ -#if defined(HAVE_PCAP_CREATE) || defined(WIN32) +#if defined(HAVE_PCAP_CREATE) || defined(_WIN32) #define B_FLAG "B:" #define B_FLAG_USAGE " [ -B size ]" -#else /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ +#else /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */ #define B_FLAG #define B_FLAG_USAGE -#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ +#endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */ #ifdef HAVE_PCAP_CREATE #define I_FLAG "I" @@ -655,6 +664,8 @@ show_devices_and_exit (void) #define Q_FLAG #endif +#define SHORTOPTS "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpq" Q_FLAG "r:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#" + /* * Long options. * @@ -680,7 +691,7 @@ show_devices_and_exit (void) #define OPTION_IMMEDIATE_MODE 130 static const struct option longopts[] = { -#if defined(HAVE_PCAP_CREATE) || defined(WIN32) +#if defined(HAVE_PCAP_CREATE) || defined(_WIN32) { "buffer-size", required_argument, NULL, 'B' }, #endif { "list-interfaces", no_argument, NULL, 'D' }, @@ -721,7 +732,7 @@ static const struct option longopts[] = { { NULL, 0, NULL, 0 } }; -#ifndef WIN32 +#ifndef _WIN32 /* Drop root privileges and chroot if necessary */ static void droproot(const char *username, const char *chroot_dir) @@ -782,7 +793,7 @@ droproot(const char *username, const char *chroot_dir) #endif /* HAVE_LIBCAP_NG */ } -#endif /* WIN32 */ +#endif /* _WIN32 */ static int getWflagChars(int x) @@ -914,6 +925,76 @@ tstamp_precision_to_string(int precision) } #endif +#ifdef HAVE_CAPSICUM +/* + * Ensure that, on a dump file's descriptor, we have all the rights + * necessary to make the standard I/O library work with an fdopen()ed + * FILE * from that descriptor. + * + * A long time ago, in a galaxy far far away, AT&T decided that, instead + * of providing separate APIs for getting and setting the FD_ flags on a + * descriptor, getting and setting the O_ flags on a descriptor, and + * locking files, they'd throw them all into a kitchen-sink fcntl() call + * along the lines of ioctl(), the fact that ioctl() operations are + * largely specific to particular character devices but fcntl() operations + * are either generic to all descriptors or generic to all descriptors for + * regular files nonwithstanding. + * + * The Capsicum people decided that fine-grained control of descriptor + * operations was required, so that you need to grant permission for + * reading, writing, seeking, and fcntl-ing. The latter, courtesy of + * AT&T's decision, means that "fcntl-ing" isn't a thing, but a motley + * collection of things, so there are *individual* fcntls for which + * permission needs to be granted. + * + * The FreeBSD standard I/O people implemented some optimizations that + * requires that the standard I/O routines be able to determine whether + * the descriptor for the FILE * is open append-only or not; as that + * descriptor could have come from an open() rather than an fopen(), + * that requires that it be able to do an F_GETFL fcntl() to read + * the O_ flags. + * + * Tcpdump uses ftell() to determine how much data has been written + * to a file in order to, when used with -C, determine when it's time + * to rotate capture files. ftell() therefore needs to do an lseek() + * to find out the file offset and must, thanks to the aforementioned + * optimization, also know whether the descriptor is open append-only + * or not. + * + * The net result of all the above is that we need to grant CAP_SEEK, + * CAP_WRITE, and CAP_FCNTL with the CAP_FCNTL_GETFL subcapability. + * + * Perhaps this is the universe's way of saying that either + * + * 1) there needs to be an fopenat() call and a pcap_dump_openat() call + * using it, so that Capsicum-capable tcpdump wouldn't need to do + * an fdopen() + * + * or + * + * 2) there needs to be a cap_fdopen() call in the FreeBSD standard + * I/O library that knows what rights are needed by the standard + * I/O library, based on the open mode, and assigns them, perhaps + * with an additional argument indicating, for example, whether + * seeking should be allowed, so that tcpdump doesn't need to know + * what the standard I/O library happens to require this week. + */ +static void +set_dumper_capsicum_rights(pcap_dumper_t *p) +{ + int fd = fileno(pcap_dump_file(p)); + cap_rights_t rights; + + cap_rights_init(&rights, CAP_SEEK, CAP_WRITE, CAP_FCNTL); + if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) { + error("unable to limit dump descriptor"); + } + if (cap_fcntls_limit(fd, CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) { + error("unable to limit dump descriptor fcntls"); + } +} +#endif + int main(int argc, char **argv) { @@ -926,7 +1007,7 @@ main(int argc, char **argv) int new_dlt; const char *dlt_name; struct bpf_program fcode; -#ifndef WIN32 +#ifndef _WIN32 RETSIGTYPE (*oldhandler)(int); #endif struct print_info printinfo; @@ -949,9 +1030,9 @@ main(int argc, char **argv) int cansandbox; #endif /* HAVE_CAPSICUM */ -#ifdef WIN32 +#ifdef _WIN32 if(wsockinit() != 0) return 1; -#endif /* WIN32 */ +#endif /* _WIN32 */ jflag=-1; /* not set */ gndo->ndo_Oflag=1; @@ -992,7 +1073,7 @@ main(int argc, char **argv) #endif while ( - (op = getopt_long(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpq" Q_FLAG "r:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#", longopts, NULL)) != -1) + (op = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != -1) switch (op) { case 'a': @@ -1007,13 +1088,13 @@ main(int argc, char **argv) ++bflag; break; -#if defined(HAVE_PCAP_CREATE) || defined(WIN32) +#if defined(HAVE_PCAP_CREATE) || defined(_WIN32) case 'B': Bflag = atoi(optarg)*1024; if (Bflag <= 0) error("invalid packet buffer size %s", optarg); break; -#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ +#endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */ case 'c': cnt = atoi(optarg); @@ -1143,24 +1224,24 @@ main(int argc, char **argv) #endif case 'l': -#ifdef WIN32 +#ifdef _WIN32 /* * _IOLBF is the same as _IOFBF in Microsoft's C * libraries; the only alternative they offer * is _IONBF. * * XXX - this should really be checking for MSVC++, - * not WIN32, if, for example, MinGW has its own + * not _WIN32, if, for example, MinGW has its own * C library that is more UNIX-compatible. */ setvbuf(stdout, NULL, _IONBF, 0); -#else /* WIN32 */ +#else /* _WIN32 */ #ifdef HAVE_SETLINEBUF setlinebuf(stdout); #else setvbuf(stdout, NULL, _IOLBF, 0); #endif -#endif /* WIN32 */ +#endif /* _WIN32 */ break; case 'K': @@ -1450,7 +1531,7 @@ main(int argc, char **argv) * In either case, we're reading a savefile, not doing * a live capture. */ -#ifndef WIN32 +#ifndef _WIN32 /* * We don't need network access, so relinquish any set-UID * or set-GID privileges we have (if any). @@ -1462,7 +1543,7 @@ main(int argc, char **argv) */ if (setgid(getgid()) != 0 || setuid(getuid()) != 0 ) fprintf(stderr, "Warning: setgid/setuid failed !\n"); -#endif /* WIN32 */ +#endif /* _WIN32 */ if (VFileName != NULL) { if (VFileName[0] == '-' && VFileName[1] == '\0') VFile = stdin; @@ -1514,7 +1595,7 @@ main(int argc, char **argv) if (device == NULL) error("%s", ebuf); } -#ifdef WIN32 +#ifdef _WIN32 /* * Print a message to the standard error on Windows. * XXX - why do it here, with a different message? @@ -1529,7 +1610,7 @@ main(int argc, char **argv) } fflush(stderr); -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_PCAP_CREATE pd = pcap_create(device, ebuf); if (pd == NULL) @@ -1646,16 +1727,16 @@ main(int argc, char **argv) /* * Let user own process after socket has been opened. */ -#ifndef WIN32 +#ifndef _WIN32 if (setgid(getgid()) != 0 || setuid(getuid()) != 0) fprintf(stderr, "Warning: setgid/setuid failed !\n"); -#endif /* WIN32 */ -#if !defined(HAVE_PCAP_CREATE) && defined(WIN32) +#endif /* _WIN32 */ +#if !defined(HAVE_PCAP_CREATE) && defined(_WIN32) if(Bflag != 0) if(pcap_setbuff(pd, Bflag)==-1){ error("%s", pcap_geterr(pd)); } -#endif /* !defined(HAVE_PCAP_CREATE) && defined(WIN32) */ +#endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */ if (Lflag) show_dlts_and_exit(device, pd); if (gndo->ndo_dlt >= 0) { @@ -1705,21 +1786,21 @@ main(int argc, char **argv) init_addrtoname(gndo, localnet, netmask); init_checksum(); -#ifndef WIN32 +#ifndef _WIN32 (void)setsignal(SIGPIPE, cleanup); (void)setsignal(SIGTERM, cleanup); (void)setsignal(SIGINT, cleanup); -#endif /* WIN32 */ +#endif /* _WIN32 */ #if defined(HAVE_FORK) || defined(HAVE_VFORK) (void)setsignal(SIGCHLD, child_cleanup); #endif /* Cooperate with nohup(1) */ -#ifndef WIN32 +#ifndef _WIN32 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) (void)setsignal(SIGHUP, oldhandler); -#endif /* WIN32 */ +#endif /* _WIN32 */ -#ifndef WIN32 +#ifndef _WIN32 /* * If a user name was specified with "-Z", attempt to switch to * that user's UID. This would probably be used with sudo, @@ -1764,7 +1845,7 @@ main(int argc, char **argv) droproot(username, chroot_dir); } -#endif /* WIN32 */ +#endif /* _WIN32 */ if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); @@ -1814,15 +1895,7 @@ main(int argc, char **argv) if (p == NULL) error("%s", pcap_geterr(pd)); #ifdef HAVE_CAPSICUM - cap_rights_init(&rights, CAP_SEEK, CAP_WRITE, CAP_FCNTL); - if (cap_rights_limit(fileno(pcap_dump_file(p)), &rights) < 0 && - errno != ENOSYS) { - error("unable to limit dump descriptor"); - } - if (cap_fcntls_limit(fileno(pcap_dump_file(p)), CAP_FCNTL_GETFL) < 0 && - errno != ENOSYS) { - error("unable to limit dump descriptor fcntls"); - } + set_dumper_capsicum_rights(p); #endif if (Cflag != 0 || Gflag != 0) { #ifdef HAVE_CAPSICUM @@ -1890,7 +1963,7 @@ main(int argc, char **argv) #endif } -#ifndef WIN32 +#ifndef _WIN32 if (RFileName == NULL) { /* * Live capture (if -V was specified, we set RFileName @@ -1915,7 +1988,7 @@ main(int argc, char **argv) } (void)fflush(stderr); } -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_CAPSICUM cansandbox = (nflag && VFileName == NULL && zflag == NULL); @@ -2147,9 +2220,6 @@ static void dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { struct dump_info *dump_info; -#ifdef HAVE_CAPSICUM - cap_rights_t rights; -#endif ++packets_captured; @@ -2260,11 +2330,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); #ifdef HAVE_CAPSICUM - cap_rights_init(&rights, CAP_SEEK, CAP_WRITE); - if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)), - &rights) < 0 && errno != ENOSYS) { - error("unable to limit dump descriptor"); - } + set_dumper_capsicum_rights(dump_info->p); #endif } } @@ -2335,15 +2401,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); #ifdef HAVE_CAPSICUM - cap_rights_init(&rights, CAP_SEEK, CAP_WRITE, CAP_FCNTL); - if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)), - &rights) < 0 && errno != ENOSYS) { - error("unable to limit dump descriptor"); - } - if (cap_fcntls_limit(fileno(pcap_dump_file(dump_info->p)), - CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) { - error("unable to limit dump descriptor fcntls"); - } + set_dumper_capsicum_rights(dump_info->p); #endif } } @@ -2480,7 +2538,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) info(0); } -#ifdef WIN32 +#ifdef _WIN32 /* * XXX - there should really be libpcap calls to get the version * number as a string (the string would be generated from #defines @@ -2561,28 +2619,28 @@ print_version(void) { extern char version[]; #ifndef HAVE_PCAP_LIB_VERSION -#if defined(WIN32) || defined(HAVE_PCAP_VERSION) +#if defined(_WIN32) || defined(HAVE_PCAP_VERSION) extern char pcap_version[]; -#else /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */ +#else /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */ static char pcap_version[] = "unknown"; -#endif /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */ +#endif /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */ #endif /* HAVE_PCAP_LIB_VERSION */ #ifdef HAVE_PCAP_LIB_VERSION -#ifdef WIN32 +#ifdef _WIN32 (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version); -#else /* WIN32 */ +#else /* _WIN32 */ (void)fprintf(stderr, "%s version %s\n", program_name, version); -#endif /* WIN32 */ +#endif /* _WIN32 */ (void)fprintf(stderr, "%s\n",pcap_lib_version()); #else /* HAVE_PCAP_LIB_VERSION */ -#ifdef WIN32 +#ifdef _WIN32 (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version); (void)fprintf(stderr, "WinPcap version %s, based on libpcap version %s\n",Wpcap_version, pcap_version); -#else /* WIN32 */ +#else /* _WIN32 */ (void)fprintf(stderr, "%s version %s\n", program_name, version); (void)fprintf(stderr, "libpcap version %s\n", pcap_version); -#endif /* WIN32 */ +#endif /* _WIN32 */ #endif /* HAVE_PCAP_LIB_VERSION */ #if defined(HAVE_LIBCRYPTO) && defined(SSLEAY_VERSION)