X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/d2c7d4e92b665cb6dafe654e51a0b5baa487e6ed..4c2790a43252b9cac1fe7f6b50b51c3c55d2370a:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index c8da36ba..59aae527 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -74,6 +74,10 @@ extern int SIZE_BUF; #include #endif /* WIN32 */ +/* capabilities convinience library */ +#ifdef HAVE_CAP_NG_H +#include +#endif /* HAVE_CAP_NG_H */ #include "netdissect.h" #include "interface.h" @@ -87,6 +91,12 @@ extern int SIZE_BUF; #define NAME_MAX 255 #endif +#ifdef SIGINFO +#define SIGNAL_REQ_INFO SIGINFO +#elif SIGUSR1 +#define SIGNAL_REQ_INFO SIGUSR1 +#endif + netdissect_options Gndo; netdissect_options *gndo = &Gndo; @@ -115,10 +125,11 @@ static void ndo_default_print(netdissect_options *, const u_char *, u_int); 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 *); -static void ndo_error(netdissect_options *ndo, const char *fmt, ...); +static void ndo_error(netdissect_options *ndo, const char *fmt, ...) + __attribute__ ((noreturn, format (printf, 2, 3))); static void ndo_warning(netdissect_options *ndo, const char *fmt, ...); -#ifdef SIGINFO +#ifdef SIGNAL_REQ_INFO RETSIGTYPE requestinfo(int); #endif @@ -133,10 +144,6 @@ RETSIGTYPE requestinfo(int); static void info(int); static u_int packets_captured; -typedef u_int (*if_printer)(const struct pcap_pkthdr *, const u_char *); -typedef u_int (*if_ndo_printer)(struct netdissect_options *ndo, - const struct pcap_pkthdr *, const u_char *); - struct printer { if_printer f; int type; @@ -314,11 +321,20 @@ static struct ndo_printer ndo_printers[] = { #endif #ifdef DLT_IEEE802_15_4_NOFCS { ieee802_15_4_if_print, DLT_IEEE802_15_4_NOFCS }, +#endif +#ifdef DLT_PPI + { ppi_if_print, DLT_PPI }, +#endif +#ifdef DLT_NETANALYZER + { netanalyzer_if_print, DLT_NETANALYZER }, +#endif +#ifdef DLT_NETANALYZER_TRANSPARENT + { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT }, #endif { NULL, 0 }, }; -static if_printer +if_printer lookup_printer(int type) { struct printer *p; @@ -331,7 +347,7 @@ lookup_printer(int type) /* NOTREACHED */ } -static if_ndo_printer +if_ndo_printer lookup_ndo_printer(int type) { struct ndo_printer *p; @@ -449,7 +465,9 @@ show_dlts_and_exit(const char *device, pcap_t *pd) dlts[n_dlts]); } } +#ifdef HAVE_PCAP_FREE_DATALINKS pcap_free_datalinks(dlts); +#endif exit(0); } @@ -520,6 +538,19 @@ droproot(const char *username, const char *chroot_dir) exit(1); } } +#ifdef HAVE_CAP_NG_H + int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG); + if (ret < 0) { + printf("error : ret %d\n", ret); + } + /* We don't need CAP_SETUID and CAP_SETGID */ + capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID); + capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID); + capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_SETUID); + capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_SETUID); + capng_apply(CAPNG_SELECT_BOTH); + +#else if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", @@ -529,6 +560,7 @@ droproot(const char *username, const char *chroot_dir) pcap_strerror(errno)); exit(1); } +#endif /* HAVE_CAP_NG_H */ } else { fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n", @@ -598,14 +630,51 @@ static int tcpdump_printf(netdissect_options *ndo _U_, return ret; } +struct print_info get_print_info(int type) { + struct print_info printinfo; + + printinfo.ndo_type = 1; + printinfo.ndo = gndo; + printinfo.p.ndo_printer = lookup_ndo_printer(type); + if (printinfo.p.ndo_printer == NULL) { + printinfo.p.printer = lookup_printer(type); + printinfo.ndo_type = 0; + if (printinfo.p.printer == NULL) { + gndo->ndo_dltname = pcap_datalink_val_to_name(type); + if (gndo->ndo_dltname != NULL) + error("packet printing is not supported for link type %s: use -w", + gndo->ndo_dltname); + else + error("packet printing is not supported for link type %d: use -w", type); + } + } + return (printinfo); +} + +char *get_next_file(FILE *VFile, char *ptr) { + char *ret; + + ret = fgets(ptr, NAME_MAX, VFile); + if (!ret) + return NULL; + + if (ptr[strlen(ptr) - 1] == '\n') + ptr[strlen(ptr) - 1] = '\0'; + + return ret; +} + int main(int argc, char **argv) { register int cnt, op, i; bpf_u_int32 localnet, netmask; - register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; + register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName; pcap_handler callback; int type; + int dlt; + int new_dlt; + const char *dlt_name; struct bpf_program fcode; #ifndef WIN32 RETSIGTYPE (*oldhandler)(int); @@ -614,13 +683,16 @@ main(int argc, char **argv) struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; + char VFileLine[NAME_MAX + 1]; char *username = NULL; char *chroot_dir = NULL; + char *ret = NULL; #ifdef HAVE_PCAP_FINDALLDEVS pcap_if_t *devpointer; int devnum; #endif int status; + FILE *VFile; #ifdef WIN32 if(wsockinit() != 0) return 1; #endif /* WIN32 */ @@ -639,6 +711,7 @@ main(int argc, char **argv) device = NULL; infile = NULL; RFileName = NULL; + VFileName = NULL; WFileName = NULL; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; @@ -652,9 +725,8 @@ main(int argc, char **argv) smiInit("tcpdump"); #endif - opterr = 0; while ( - (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:Yz:Z:")) != -1) + (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "V:vw:W:xXy:Yz:Z:")) != -1) switch (op) { case 'a': @@ -748,7 +820,11 @@ main(int argc, char **argv) break; case 'h': - ++hflag; + usage(); + break; + + case 'H': + ++Hflag; break; case 'i': @@ -924,6 +1000,10 @@ main(int argc, char **argv) packettype = PT_TFTP; else if (strcasecmp(optarg, "aodv") == 0) packettype = PT_AODV; + else if (strcasecmp(optarg, "carp") == 0) + packettype = PT_CARP; + else if (strcasecmp(optarg, "radius") == 0) + packettype = PT_RADIUS; else error("unknown packet type `%s'", optarg); break; @@ -942,6 +1022,10 @@ main(int argc, char **argv) ++vflag; break; + case 'V': + VFileName = optarg; + break; + case 'w': WFileName = optarg; break; @@ -1027,6 +1111,12 @@ main(int argc, char **argv) break; } + if (fflag != 0 && (VFileName != NULL || RFileName != NULL)) + error("-f can not be used with -V or -r"); + + if (VFileName != NULL && RFileName != NULL) + error("-V and -r are mutually exclusive."); + #ifdef WITH_CHROOT /* if run as root, prepare for chrooting */ if (getuid() == 0 || geteuid() == 0) { @@ -1045,10 +1135,7 @@ main(int argc, char **argv) } #endif - if (RFileName != NULL) { - int dlt; - const char *dlt_name; - + if (RFileName != NULL || VFileName != NULL) { #ifndef WIN32 /* * We don't need network access, so relinquish any set-UID @@ -1062,6 +1149,21 @@ main(int argc, char **argv) if (setgid(getgid()) != 0 || setuid(getuid()) != 0 ) fprintf(stderr, "Warning: setgid/setuid failed !\n"); #endif /* WIN32 */ + if (VFileName != NULL) { + if (VFileName[0] == '-' && VFileName[1] == '\0') + VFile = stdin; + else + VFile = fopen(VFileName, "r"); + + if (VFile == NULL) + error("Unable to open file: %s\n", strerror(errno)); + + ret = get_next_file(VFile, VFileLine); + if (!ret) + error("Nothing in %s\n", VFileName); + RFileName = VFileLine; + } + pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); @@ -1078,8 +1180,6 @@ main(int argc, char **argv) } localnet = 0; netmask = 0; - if (fflag != 0) - error("-f and -r options are incompatible"); } else { if (device == NULL) { device = pcap_lookupdev(ebuf); @@ -1237,10 +1337,10 @@ main(int argc, char **argv) if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); - free(cmdbuf); if (dflag) { bpf_dump(&fcode, dflag); pcap_close(pd); + free(cmdbuf); exit(0); } init_addrtoname(localnet, netmask); @@ -1250,8 +1350,10 @@ main(int argc, char **argv) (void)setsignal(SIGPIPE, cleanup); (void)setsignal(SIGTERM, cleanup); (void)setsignal(SIGINT, cleanup); - (void)setsignal(SIGCHLD, child_cleanup); #endif /* WIN32 */ +#if defined(HAVE_FORK) || defined(HAVE_VFORK) + (void)setsignal(SIGCHLD, child_cleanup); +#endif /* Cooperate with nohup(1) */ #ifndef WIN32 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) @@ -1276,9 +1378,31 @@ main(int argc, char **argv) * Switching to the -Z user ID only after opening the first * savefile doesn't handle the general case. */ + +#ifdef HAVE_CAP_NG_H + /* We are running as root and we will be writing to savefile */ + if ((getuid() == 0 || geteuid() == 0) && WFileName) { + if (username) { + /* Drop all capabilities from effective set */ + capng_clear(CAPNG_EFFECTIVE); + /* Add capabilities we will need*/ + capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_SETUID); + capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_SETGID); + capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_DAC_OVERRIDE); + + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_SETUID); + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_SETGID); + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); + + capng_apply(CAPNG_SELECT_BOTH); + } + } +#endif /* HAVE_CAP_NG_H */ + if (getuid() == 0 || geteuid() == 0) { if (username || chroot_dir) droproot(username, chroot_dir); + } #endif /* WIN32 */ @@ -1299,6 +1423,10 @@ main(int argc, char **argv) MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0); p = pcap_dump_open(pd, dumpinfo.CurrentFileName); +#ifdef HAVE_CAP_NG_H + /* Give up capabilities, clear Effective set */ + capng_clear(CAPNG_EFFECTIVE); +#endif if (p == NULL) error("%s", pcap_geterr(pd)); if (Cflag != 0 || Gflag != 0) { @@ -1317,32 +1445,18 @@ main(int argc, char **argv) #endif } else { type = pcap_datalink(pd); - printinfo.ndo_type = 1; - printinfo.ndo = gndo; - printinfo.p.ndo_printer = lookup_ndo_printer(type); - if (printinfo.p.ndo_printer == NULL) { - printinfo.p.printer = lookup_printer(type); - printinfo.ndo_type = 0; - if (printinfo.p.printer == NULL) { - gndo->ndo_dltname = pcap_datalink_val_to_name(type); - if (gndo->ndo_dltname != NULL) - error("packet printing is not supported for link type %s: use -w", - gndo->ndo_dltname); - else - error("packet printing is not supported for link type %d: use -w", type); - } - } + printinfo = get_print_info(type); callback = print_packet; pcap_userdata = (u_char *)&printinfo; } -#ifdef SIGINFO +#ifdef SIGNAL_REQ_INFO /* * We can't get statistics when reading from a file rather * than capturing from a device. */ if (RFileName == NULL) - (void)setsignal(SIGINFO, requestinfo); + (void)setsignal(SIGNAL_REQ_INFO, requestinfo); #endif if (vflag > 0 && WFileName) { @@ -1363,9 +1477,6 @@ main(int argc, char **argv) #ifndef WIN32 if (RFileName == NULL) { - int dlt; - const char *dlt_name; - if (!vflag && !WFileName) { (void)fprintf(stderr, "%s: verbose output suppressed, use -v or -vv for full protocol decode\n", @@ -1385,37 +1496,69 @@ main(int argc, char **argv) (void)fflush(stderr); } #endif /* WIN32 */ - status = pcap_loop(pd, cnt, callback, pcap_userdata); - if (WFileName == NULL) { - /* - * We're printing packets. Flush the printed output, - * so it doesn't get intermingled with error output. - */ - if (status == -2) { + do { + status = pcap_loop(pd, cnt, callback, pcap_userdata); + if (WFileName == NULL) { /* - * We got interrupted, so perhaps we didn't - * manage to finish a line we were printing. - * Print an extra newline, just in case. + * We're printing packets. Flush the printed output, + * so it doesn't get intermingled with error output. */ - putchar('\n'); + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + } + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + if (RFileName == NULL) { + /* + * We're doing a live capture. Report the capture + * statistics. + */ + info(1); + } + pcap_close(pd); + if (VFileName != NULL) { + ret = get_next_file(VFile, VFileLine); + if (ret) { + RFileName = VFileLine; + pd = pcap_open_offline(RFileName, ebuf); + if (pd == NULL) + error("%s", ebuf); + new_dlt = pcap_datalink(pd); + if (WFileName && new_dlt != dlt) + error("%s: new dlt does not match original", RFileName); + printinfo = get_print_info(new_dlt); + dlt_name = pcap_datalink_val_to_name(new_dlt); + if (dlt_name == NULL) { + fprintf(stderr, "reading from file %s, link-type %u\n", + RFileName, new_dlt); + } else { + fprintf(stderr, + "reading from file %s, link-type %s (%s)\n", + RFileName, dlt_name, + pcap_datalink_val_to_description(new_dlt)); + } + if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + } } - (void)fflush(stdout); - } - if (status == -1) { - /* - * Error. Report it. - */ - (void)fprintf(stderr, "%s: pcap_loop: %s\n", - program_name, pcap_geterr(pd)); - } - if (RFileName == NULL) { - /* - * We're doing a live capture. Report the capture - * statistics. - */ - info(1); } - pcap_close(pd); + while (ret != NULL); + + free(cmdbuf); exit(status == -1 ? 1 : 0); } @@ -1464,13 +1607,13 @@ cleanup(int signo _U_) On windows, we do not use a fork, so we do not care less about waiting a child processes to die */ -#ifndef WIN32 +#if defined(HAVE_FORK) || defined(HAVE_VFORK) static RETSIGTYPE child_cleanup(int signo _U_) { wait(NULL); } -#endif /* WIN32 */ +#endif /* HAVE_FORK && HAVE_VFORK */ static void info(register int verbose) @@ -1491,34 +1634,41 @@ info(register int verbose) if (!verbose) fprintf(stderr, "%s: ", program_name); - (void)fprintf(stderr, "%u packets captured", packets_captured); + (void)fprintf(stderr, "%u packet%s captured", packets_captured, + PLURAL_SUFFIX(packets_captured)); if (!verbose) fputs(", ", stderr); else putc('\n', stderr); - (void)fprintf(stderr, "%u packets received by filter", stat.ps_recv); + (void)fprintf(stderr, "%u packet%s received by filter", stat.ps_recv, + PLURAL_SUFFIX(stat.ps_recv)); if (!verbose) fputs(", ", stderr); else putc('\n', stderr); - (void)fprintf(stderr, "%u packets dropped by kernel", stat.ps_drop); + (void)fprintf(stderr, "%u packet%s dropped by kernel", stat.ps_drop, + PLURAL_SUFFIX(stat.ps_drop)); if (stat.ps_ifdrop != 0) { if (!verbose) fputs(", ", stderr); else putc('\n', stderr); - (void)fprintf(stderr, "%u packets dropped by interface\n", - stat.ps_ifdrop); + (void)fprintf(stderr, "%u packet%s dropped by interface\n", + stat.ps_ifdrop, PLURAL_SUFFIX(stat.ps_ifdrop)); } else putc('\n', stderr); infoprint = 0; } -#ifndef WIN32 +#if defined(HAVE_FORK) || defined(HAVE_VFORK) static void compress_savefile(const char *filename) { +# ifdef HAVE_FORK if (fork()) +# else + if (vfork()) +# endif return; /* * Set to lowest priority so that this doesn't disturb the capture @@ -1534,15 +1684,20 @@ compress_savefile(const char *filename) zflag, filename, strerror(errno)); +# ifdef HAVE_FORK + exit(1); +# else + _exit(1); +# endif } -#else /* WIN32 */ +#else /* HAVE_FORK && HAVE_VFORK */ static void compress_savefile(const char *filename) { fprintf(stderr, - "compress_savefile failed. Functionality not implemented under windows\n"); + "compress_savefile failed. Functionality not implemented under your system\n"); } -#endif /* WIN32 */ +#endif /* HAVE_FORK && HAVE_VFORK */ static void dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) @@ -1618,7 +1773,15 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s else MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0); +#ifdef HAVE_CAP_NG_H + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); + capng_apply(CAPNG_EFFECTIVE); +#endif /* HAVE_CAP_NG_H */ dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); +#ifdef HAVE_CAP_NG_H + capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); + capng_apply(CAPNG_EFFECTIVE); +#endif /* HAVE_CAP_NG_H */ if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); } @@ -1819,7 +1982,7 @@ default_print(const u_char *bp, u_int length) ndo_default_print(gndo, bp, length); } -#ifdef SIGINFO +#ifdef SIGNAL_REQ_INFO RETSIGTYPE requestinfo(int signo _U_) { if (infodelay) @@ -1881,13 +2044,13 @@ usage(void) #endif /* WIN32 */ #endif /* HAVE_PCAP_LIB_VERSION */ (void)fprintf(stderr, -"Usage: %s [-aAbd" D_FLAG "efh" I_FLAG J_FLAG "KlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name); +"Usage: %s [-aAbd" D_FLAG "efhH" I_FLAG J_FLAG "KlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name); (void)fprintf(stderr, "\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n"); (void)fprintf(stderr, "\t\t[ -i interface ]" j_FLAG_USAGE " [ -M secret ]\n"); (void)fprintf(stderr, -"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n"); +"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -V file ] [ -w file ]\n"); (void)fprintf(stderr, "\t\t[ -W filecount ] [ -y datalinktype ] [ -z command ]\n"); (void)fprintf(stderr,