X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/f6fa6a40d4156cdf5dea882024beb7b10d2412f1..464c44fbd1394ac006d8d99f16e80ead423c1c47:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index fbc41128..43fad291 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -17,14 +17,20 @@ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Support for splitting captures into multiple files with a maximum + * file size: + * + * Copyright (c) 2001 + * Seth Webster */ #ifndef lint static const char copyright[] = - "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997\n\ + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ The Regents of the University of California. All rights reserved.\n"; static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.130 1999-10-17 21:37:17 mcr Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.179 2002-07-11 09:17:25 guy Exp $ (LBL)"; #endif /* @@ -35,6 +41,10 @@ static const char rcsid[] = * combined efforts of Van, Steve McCanne and Craig Leres of LBL. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include @@ -46,6 +56,8 @@ static const char rcsid[] = #include #include #include +#include + #include "interface.h" #include "addrtoname.h" @@ -62,24 +74,37 @@ int Nflag; /* remove domains from printed host names */ int Oflag = 1; /* run filter code optimizer */ int pflag; /* don't go promiscuous */ int qflag; /* quick (shorter) output */ +int Rflag = 1; /* print sequence # field in AH/ESP*/ +int sflag = 0; /* use the libsmi to translate OIDs */ int Sflag; /* print raw TCP sequence numbers */ int tflag = 1; /* print packet arrival time */ +int uflag = 0; /* Print undecoded NFS handles */ int vflag; /* verbose */ int xflag; /* print packet in hex */ +int Xflag; /* print packet in ascii as well as hex */ +off_t Cflag = 0; /* rotate dump files after this many bytes */ +int Aflag = 0; /* print packet only in ascii observing LF, CR, TAB, SPACE */ + +char *espsecret = NULL; /* ESP secret key */ int packettype; +int infodelay; +int infoprint; char *program_name; int32_t thiszone; /* seconds offset from gmt to local time */ -/* Externs */ -extern void bpf_dump(struct bpf_program *, int); - /* Forwards */ -RETSIGTYPE cleanup(int); -extern __dead void usage(void) __attribute__((volatile)); +static RETSIGTYPE cleanup(int); +static void usage(void) __attribute__((noreturn)); + +static void dump_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *); + +#ifdef SIGINFO +RETSIGTYPE requestinfo(int); +#endif /* Length of saved portion of packet. */ int snaplen = DEFAULT_SNAPLEN; @@ -90,16 +115,62 @@ struct printer { }; static struct printer printers[] = { + { arcnet_if_print, DLT_ARCNET }, { ether_if_print, DLT_EN10MB }, - { ether_if_print, DLT_IEEE802 }, + { token_if_print, DLT_IEEE802 }, +#ifdef DLT_LANE8023 + { lane_if_print, DLT_LANE8023 }, +#endif +#ifdef DLT_CIP + { cip_if_print, DLT_CIP }, +#endif +#ifdef DLT_ATM_CLIP + { cip_if_print, DLT_ATM_CLIP }, +#endif { sl_if_print, DLT_SLIP }, { sl_bsdos_if_print, DLT_SLIP_BSDOS }, { ppp_if_print, DLT_PPP }, { ppp_bsdos_if_print, DLT_PPP_BSDOS }, { fddi_if_print, DLT_FDDI }, { null_if_print, DLT_NULL }, +#ifdef DLT_LOOP + { null_if_print, DLT_LOOP }, +#endif { raw_if_print, DLT_RAW }, { atm_if_print, DLT_ATM_RFC1483 }, +#ifdef DLT_C_HDLC + { chdlc_if_print, DLT_C_HDLC }, +#endif +#ifdef DLT_HDLC + { chdlc_if_print, DLT_HDLC }, +#endif +#ifdef DLT_PPP_SERIAL + { ppp_hdlc_if_print, DLT_PPP_SERIAL }, +#endif +#ifdef DLT_PPP_ETHER + { pppoe_if_print, DLT_PPP_ETHER }, +#endif +#ifdef DLT_LINUX_SLL + { sll_if_print, DLT_LINUX_SLL }, +#endif +#ifdef DLT_IEEE802_11 + { ieee802_11_if_print, DLT_IEEE802_11}, +#endif +#ifdef DLT_LTALK + { ltalk_if_print, DLT_LTALK }, +#endif +#ifdef DLT_PFLOG + { pflog_if_print, DLT_PFLOG }, +#endif +#ifdef DLT_FR + { fr_if_print, DLT_FR }, +#endif +#ifdef DLT_FRELAY + { fr_if_print, DLT_FRELAY }, +#endif +#ifdef DLT_SUNATM + { sunatm_if_print, DLT_SUNATM }, +#endif { NULL, 0 }, }; @@ -112,7 +183,7 @@ lookup_printer(int type) if (type == p->type) return p->f; - error("unknown data link type 0x%x", type); + error("unknown data link type %d", type); /* NOTREACHED */ } @@ -122,6 +193,12 @@ extern int optind; extern int opterr; extern char *optarg; +struct dump_info { + char *WFileName; + pcap_t *pd; + pcap_dumper_t *p; +}; + int main(int argc, char **argv) { @@ -131,6 +208,7 @@ main(int argc, char **argv) pcap_handler printer; struct bpf_program fcode; RETSIGTYPE (*oldhandler)(int); + struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; @@ -144,24 +222,40 @@ main(int argc, char **argv) else program_name = argv[0]; - if (abort_on_misalignment(ebuf) < 0) + if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0) error("%s", ebuf); +#ifdef LIBSMI + smiInit("tcpdump"); +#endif + opterr = 0; while ( - (op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xY")) != EOF) + (op = getopt(argc, argv, "aAc:C:deE:fF:i:lm:nNOpqr:Rs:StT:uvw:xXY")) != -1) switch (op) { case 'a': ++aflag; break; + case 'A': + ++xflag; + ++Xflag; + ++Aflag; + break; + case 'c': cnt = atoi(optarg); if (cnt <= 0) error("invalid packet count %s", optarg); break; + case 'C': + Cflag = atoi(optarg) * 1000000; + if (Cflag < 0) + error("invalid file size %s", optarg); + break; + case 'd': ++dflag; break; @@ -170,6 +264,13 @@ main(int argc, char **argv) ++eflag; break; + case 'E': +#ifndef HAVE_LIBCRYPTO + warning("crypto code not compiled in"); +#endif + espsecret = optarg; + break; + case 'f': ++fflag; break; @@ -198,6 +299,18 @@ main(int argc, char **argv) ++Nflag; break; + case 'm': +#ifdef LIBSMI + if (smiLoadModule(optarg) == 0) { + error("could not load MIB module %s", optarg); + } + sflag = 1; +#else + (void)fprintf(stderr, "%s: ignoring option `-m %s' ", + program_name, optarg); + (void)fprintf(stderr, "(no libsmi support)\n"); +#endif + case 'O': Oflag = 0; break; @@ -214,11 +327,21 @@ main(int argc, char **argv) RFileName = optarg; break; - case 's': - snaplen = atoi(optarg); - if (snaplen <= 0) + case 'R': + Rflag = 0; + break; + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > 65535) error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = 65535; break; + } case 'S': ++Sflag; @@ -241,10 +364,16 @@ main(int argc, char **argv) packettype = PT_RTCP; else if (strcasecmp(optarg, "snmp") == 0) packettype = PT_SNMP; + else if (strcasecmp(optarg, "cnfp") == 0) + packettype = PT_CNFP; else error("unknown packet type `%s'", optarg); break; + case 'u': + ++uflag; + break; + case 'v': ++vflag; break; @@ -252,6 +381,16 @@ main(int argc, char **argv) case 'w': WFileName = optarg; break; + + case 'x': + ++xflag; + break; + + case 'X': + ++xflag; + ++Xflag; + break; + #ifdef YYDEBUG case 'Y': { @@ -261,10 +400,6 @@ main(int argc, char **argv) } break; #endif - case 'x': - ++xflag; - break; - default: usage(); /* NOTREACHED */ @@ -297,9 +432,12 @@ main(int argc, char **argv) if (device == NULL) error("%s", ebuf); } + *ebuf = '\0'; pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); if (pd == NULL) error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); i = pcap_snapshot(pd); if (snaplen < i) { warning("snaplen raised from %d to %d", snaplen, i); @@ -340,11 +478,22 @@ main(int argc, char **argv) pcap_dumper_t *p = pcap_dump_open(pd, WFileName); if (p == NULL) error("%s", pcap_geterr(pd)); - printer = pcap_dump; - pcap_userdata = (u_char *)p; + if (Cflag != 0) { + printer = dump_and_trunc; + dumpinfo.WFileName = WFileName; + dumpinfo.pd = pd; + dumpinfo.p = p; + pcap_userdata = (u_char *)&dumpinfo; + } else { + printer = pcap_dump; + pcap_userdata = (u_char *)p; + } } else { printer = lookup_printer(pcap_datalink(pd)); pcap_userdata = 0; +#ifdef SIGINFO + (void)setsignal(SIGINFO, requestinfo); +#endif } if (RFileName == NULL) { (void)fprintf(stderr, "%s: listening on %s\n", @@ -354,33 +503,107 @@ main(int argc, char **argv) if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { (void)fprintf(stderr, "%s: pcap_loop: %s\n", program_name, pcap_geterr(pd)); + cleanup(0); + pcap_close(pd); exit(1); } + if (RFileName == NULL) + info(1); pcap_close(pd); exit(0); } /* make a clean exit on interrupts */ -RETSIGTYPE +static RETSIGTYPE cleanup(int signo) { - struct pcap_stat stat; /* Can't print the summary if reading from a savefile */ if (pd != NULL && pcap_file(pd) == NULL) { (void)fflush(stdout); putc('\n', stderr); - if (pcap_stats(pd, &stat) < 0) - (void)fprintf(stderr, "pcap_stats: %s\n", - pcap_geterr(pd)); - else { - (void)fprintf(stderr, "%d packets received by filter\n", - stat.ps_recv); - (void)fprintf(stderr, "%d packets dropped by kernel\n", - stat.ps_drop); - } + info(1); + } + if (signo) + exit(0); +} + +void +info(register int verbose) +{ + struct pcap_stat stat; + + if (pcap_stats(pd, &stat) < 0) { + (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd)); + return; + } + if (!verbose) + fprintf(stderr, "%s: ", program_name); + (void)fprintf(stderr, "%d packets received by filter", stat.ps_recv); + if (!verbose) + fputs(", ", stderr); + else + putc('\n', stderr); + (void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop); + infoprint = 0; +} + +static void +reverse(char *s) +{ + int i, j, c; + + for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; } - exit(0); +} + + +static void +swebitoa(unsigned int n, char *s) +{ + unsigned int i; + + i = 0; + do { + s[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + + s[i] = '\0'; + reverse(s); +} + +static void +dump_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + struct dump_info *info; + static uint cnt = 2; + char *name; + + info = (struct dump_info *)user; + + /* + * XXX - this won't prevent capture files from getting + * larger than Cflag - the last packet written to the + * file could put it over Cflag. + */ + if (ftell((FILE *)info->p) > Cflag) { + name = (char *) malloc(strlen(info->WFileName) + 4); + if (name == NULL) + error("dump_and_trunc: malloc"); + strcpy(name, info->WFileName); + swebitoa(cnt, name + strlen(info->WFileName)); + cnt++; + pcap_dump_close(info->p); + info->p = pcap_dump_open(info->pd, name); + free(name); + if (info->p == NULL) + error("%s", pcap_geterr(pd)); + } + + pcap_dump((u_char *)info->p, h, sp); } /* Like default_print() but data need not be aligned */ @@ -390,6 +613,10 @@ default_print_unaligned(register const u_char *cp, register u_int length) register u_int i, s; register int nshorts; + if (Xflag) { + ascii_print(cp, length); + return; + } nshorts = (u_int) length / sizeof(u_short); i = 0; while (--nshorts >= 0) { @@ -407,36 +634,24 @@ default_print_unaligned(register const u_char *cp, register u_int length) /* * By default, print the packet out in hex. - * - * (BTW, please don't send us patches to print the packet out in ascii) */ void default_print(register const u_char *bp, register u_int length) { - register const u_short *sp; - register u_int i; - register int nshorts; + default_print_unaligned(bp, length); +} - if ((long)bp & 1) { - default_print_unaligned(bp, length); - return; - } - sp = (u_short *)bp; - nshorts = (u_int) length / sizeof(u_short); - i = 0; - while (--nshorts >= 0) { - if ((i++ % 8) == 0) - (void)printf("\n\t\t\t"); - (void)printf(" %04x", ntohs(*sp++)); - } - if (length & 1) { - if ((i % 8) == 0) - (void)printf("\n\t\t\t"); - (void)printf(" %02x", *(u_char *)sp); - } +#ifdef SIGINFO +RETSIGTYPE requestinfo(int signo) +{ + if (infodelay) + ++infoprint; + else + info(0); } +#endif -__dead void +static void usage(void) { extern char version[]; @@ -445,10 +660,10 @@ usage(void) (void)fprintf(stderr, "%s version %s\n", program_name, version); (void)fprintf(stderr, "libpcap version %s\n", pcap_version); (void)fprintf(stderr, -"Usage: %s [-adeflnNOpqStvx] [-c count] [ -F file ]\n", program_name); +"Usage: %s [-aAdeflnNOpqRStuvxX] [ -c count ] [ -C file_size ]\n", program_name); (void)fprintf(stderr, -"\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n"); +"\t\t[ -F file ] [ -i interface ] [ -r file ] [ -s snaplen ]\n"); (void)fprintf(stderr, -"\t\t[ -T type ] [ -w file ] [ expression ]\n"); - exit(-1); +"\t\t[ -T type ] [ -w file ] [ -E algo:secret ] [ expression ]\n"); + exit(1); }