X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/4440cfa0dccc0be16d8da5af71f8451bc44e445a..ec799d60f6cd3f41041b57efe3963c28dda94d4a:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index d4310f61..da88d383 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -30,7 +30,7 @@ static const char copyright[] _U_ = "@(#) 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[] _U_ = - "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.278 2008-04-04 20:24:49 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.283 2008-09-25 21:45:50 guy Exp $ (LBL)"; #endif /* @@ -90,9 +90,9 @@ extern int SIZE_BUF; netdissect_options Gndo; netdissect_options *gndo = &Gndo; -int dflag; /* print filter code */ -int Lflag; /* list available data link types and exit */ -char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */ +static int dflag; /* print filter code */ +static int Lflag; /* list available data link types and exit */ +static char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */ static int infodelay; static int infoprint; @@ -105,7 +105,7 @@ int32_t thiszone; /* seconds offset from gmt to local time */ static RETSIGTYPE cleanup(int); static RETSIGTYPE child_cleanup(int); static void usage(void) __attribute__((noreturn)); -static void show_dlts_and_exit(pcap_t *pd) __attribute__((noreturn)); +static void show_dlts_and_exit(const char *device, pcap_t *pd) __attribute__((noreturn)); static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void ndo_default_print(netdissect_options *, const u_char *, u_int); @@ -131,12 +131,21 @@ 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; + if_printer f; int type; }; + +struct ndo_printer { + if_ndo_printer f; + int type; +}; + + static struct printer printers[] = { { arcnet_if_print, DLT_ARCNET }, #ifdef DLT_ARCNET_LINUX @@ -151,7 +160,7 @@ static struct printer printers[] = { { cip_if_print, DLT_CIP }, #endif #ifdef DLT_ATM_CLIP - { cip_if_print, DLT_ATM_CLIP }, + { cip_if_print, DLT_ATM_CLIP }, #endif { sl_if_print, DLT_SLIP }, #ifdef DLT_SLIP_BSDOS @@ -178,7 +187,7 @@ static struct printer printers[] = { { chdlc_if_print, DLT_HDLC }, #endif #ifdef DLT_PPP_SERIAL - { ppp_hdlc_if_print, DLT_PPP_SERIAL }, + { ppp_hdlc_if_print, DLT_PPP_SERIAL }, #endif #ifdef DLT_PPP_ETHER { pppoe_if_print, DLT_PPP_ETHER }, @@ -193,7 +202,7 @@ static struct printer printers[] = { { ltalk_if_print, DLT_LTALK }, #endif #if defined(DLT_PFLOG) && defined(HAVE_NET_PFVAR_H) - { pflog_if_print, DLT_PFLOG }, + { pflog_if_print, DLT_PFLOG }, #endif #ifdef DLT_FR { fr_if_print, DLT_FR }, @@ -214,10 +223,10 @@ static struct printer printers[] = { { ieee802_11_radio_if_print, DLT_IEEE802_11_RADIO }, #endif #ifdef DLT_ENC - { enc_if_print, DLT_ENC }, + { enc_if_print, DLT_ENC }, #endif #ifdef DLT_SYMANTEC_FIREWALL - { symantec_if_print, DLT_SYMANTEC_FIREWALL }, + { symantec_if_print, DLT_SYMANTEC_FIREWALL }, #endif #ifdef DLT_APPLE_IP_OVER_IEEE1394 { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 }, @@ -259,22 +268,46 @@ static struct printer printers[] = { { juniper_services_print, DLT_JUNIPER_SERVICES }, #endif #ifdef DLT_JUNIPER_ETHER - { juniper_ether_print, DLT_JUNIPER_ETHER }, + { juniper_ether_print, DLT_JUNIPER_ETHER }, #endif #ifdef DLT_JUNIPER_PPP - { juniper_ppp_print, DLT_JUNIPER_PPP }, + { juniper_ppp_print, DLT_JUNIPER_PPP }, #endif #ifdef DLT_JUNIPER_FRELAY - { juniper_frelay_print, DLT_JUNIPER_FRELAY }, + { juniper_frelay_print, DLT_JUNIPER_FRELAY }, #endif #ifdef DLT_JUNIPER_CHDLC - { juniper_chdlc_print, DLT_JUNIPER_CHDLC }, + { juniper_chdlc_print, DLT_JUNIPER_CHDLC }, #endif #ifdef DLT_MFR - { mfr_if_print, DLT_MFR }, + { mfr_if_print, DLT_MFR }, +#endif +#if defined(DLT_BLUETOOTH_HCI_H4_WITH_PHDR) && defined(HAVE_PCAP_BLUETOOTH_H) + { bt_if_print, DLT_BLUETOOTH_HCI_H4_WITH_PHDR}, +#endif +#ifdef HAVE_PCAP_USB_H +#ifdef DLT_USB_LINUX + { usb_linux_48_byte_print, DLT_USB_LINUX}, +#endif /* DLT_USB_LINUX */ +#ifdef DLT_USB_LINUX_MMAPPED + { usb_linux_64_byte_print, DLT_USB_LINUX_MMAPPED}, +#endif /* DLT_USB_LINUX_MMAPPED */ +#endif /* HAVE_PCAP_USB_H */ +#ifdef DLT_IPV4 + { raw_if_print, DLT_IPV4 }, +#endif +#ifdef DLT_IPV6 + { raw_if_print, DLT_IPV6 }, +#endif + { NULL, 0 }, +}; + +static struct ndo_printer ndo_printers[] = { +#ifdef DLT_IPNET + { ipnet_if_print, DLT_IPNET }, #endif -#ifdef DLT_BLUETOOTH_HCI_H4_WITH_PHDR - { bt_if_print, DLT_BLUETOOTH_HCI_H4_WITH_PHDR}, +#ifdef DLT_IEEE802_15_4 + { ieee802_15_4_if_print, DLT_IEEE802_15_4 }, #endif { NULL, 0 }, }; @@ -292,14 +325,34 @@ lookup_printer(int type) /* NOTREACHED */ } +static if_ndo_printer +lookup_ndo_printer(int type) +{ + struct ndo_printer *p; + + for (p = ndo_printers; p->f; ++p) + if (type == p->type) + return p->f; + + return NULL; + /* NOTREACHED */ +} + static pcap_t *pd; +static int supports_monitor_mode; + extern int optind; extern int opterr; extern char *optarg; struct print_info { - if_printer printer; + netdissect_options *ndo; + union { + if_printer printer; + if_ndo_printer ndo_printer; + } p; + int ndo_type; }; struct dump_info { @@ -310,7 +363,7 @@ struct dump_info { }; static void -show_dlts_and_exit(pcap_t *pd) +show_dlts_and_exit(const char *device, pcap_t *pd) { int n_dlts; int *dlts = 0; @@ -322,7 +375,21 @@ show_dlts_and_exit(pcap_t *pd) else if (n_dlts == 0 || !dlts) error("No data link types."); - (void) fprintf(stderr, "Data link types (use option -y to set):\n"); + /* + * If the interface is known to support monitor mode, indicate + * whether these are the data link types available when not in + * monitor mode, if -I wasn't specified, or when in monitor mode, + * when -I was specified (the link-layer types available in + * monitor mode might be different from the ones available when + * not in monitor mode). + */ + if (supports_monitor_mode) + (void) fprintf(stderr, "Data link types for %s %s (use option -y to set):\n", + device, + Iflag ? "when in monitor mode" : "when not in monitor mode"); + else + (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]); @@ -333,7 +400,8 @@ show_dlts_and_exit(pcap_t *pd) /* * OK, does tcpdump handle that type? */ - if (lookup_printer(dlts[n_dlts]) == NULL) + if (lookup_printer(dlts[n_dlts]) == NULL + && lookup_ndo_printer(dlts[n_dlts]) == NULL) (void) fprintf(stderr, " (printing not supported)"); putchar('\n'); } else { @@ -535,7 +603,7 @@ main(int argc, char **argv) opterr = 0; while ( - (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:G:i:" I_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:i:" I_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:Yz:Z:")) != -1) switch (op) { case 'a': @@ -546,6 +614,10 @@ main(int argc, char **argv) ++Aflag; break; + case 'b': + ++bflag; + break; + #if defined(HAVE_PCAP_CREATE) || defined(WIN32) case 'B': Bflag = atoi(optarg)*1024; @@ -646,11 +718,17 @@ main(int argc, char **argv) if (pcap_findalldevs(&devpointer, ebuf) < 0) error("%s", ebuf); else { - for (i = 0; i < devnum-1; i++){ - devpointer = devpointer->next; - if (devpointer == NULL) - error("Invalid adapter index"); - } + /* + * Look for the devnum-th entry + * in the list of devices + * (1-based). + */ + for (i = 0; + i < devnum-1 && devpointer != NULL; + i++, devpointer = devpointer->next) + ; + if (devpointer == NULL) + error("Invalid adapter index"); } device = devpointer->name; break; @@ -708,7 +786,7 @@ main(int argc, char **argv) #ifndef HAVE_LIBCRYPTO warning("crypto code not compiled in"); #endif - tcpmd5secret = optarg; + sigsecret = optarg; break; case 'n': @@ -745,10 +823,10 @@ main(int argc, char **argv) snaplen = strtol(optarg, &end, 0); if (optarg == end || *end != '\0' - || snaplen < 0 || snaplen > 65535) + || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) error("invalid snaplen %s", optarg); else if (snaplen == 0) - snaplen = 65535; + snaplen = MAXIMUM_SNAPLEN; break; } @@ -957,36 +1035,68 @@ main(int argc, char **argv) pd = pcap_create(device, ebuf); if (pd == NULL) error("%s", ebuf); + /* + * Is this an interface that supports monitor mode? + */ + if (pcap_can_set_rfmon(pd) == 1) + supports_monitor_mode = 1; + else + supports_monitor_mode = 0; status = pcap_set_snaplen(pd, snaplen); if (status != 0) error("%s: pcap_set_snaplen failed: %s", - device, pcap_strerror(status)); + device, pcap_statustostr(status)); status = pcap_set_promisc(pd, !pflag); if (status != 0) error("%s: pcap_set_promisc failed: %s", - device, pcap_strerror(status)); + device, pcap_statustostr(status)); if (Iflag) { status = pcap_set_rfmon(pd, 1); if (status != 0) error("%s: pcap_set_rfmon failed: %s", - device, pcap_strerror(status)); + device, pcap_statustostr(status)); } status = pcap_set_timeout(pd, 1000); if (status != 0) error("%s: pcap_set_timeout failed: %s", - device, pcap_strerror(status)); + device, pcap_statustostr(status)); if (Bflag != 0) { status = pcap_set_buffer_size(pd, Bflag); if (status != 0) error("%s: pcap_set_buffer_size failed: %s", - device, pcap_strerror(status)); + device, pcap_statustostr(status)); } status = pcap_activate(pd); - if (status != 0) { + if (status < 0) { + /* + * pcap_activate() failed. + */ + cp = pcap_geterr(pd); if (status == PCAP_ERROR) - error("%s", pcap_geterr(pd)); + error("%s", cp); + else if ((status == PCAP_ERROR_NO_SUCH_DEVICE || + status == PCAP_ERROR_PERM_DENIED) && + *cp != '\0') + error("%s: %s\n(%s)", device, + pcap_statustostr(status), cp); + else + error("%s: %s", device, + pcap_statustostr(status)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + cp = pcap_geterr(pd); + if (status == PCAP_WARNING) + warning("%s", cp); + else if (status == PCAP_WARNING_PROMISC_NOTSUP && + *cp != '\0') + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), cp); else - error("%s: %s", device, pcap_strerror(status)); + warning("%s: %s", device, + pcap_statustostr(status)); } #else *ebuf = '\0'; @@ -1010,7 +1120,7 @@ main(int argc, char **argv) } #endif /* !defined(HAVE_PCAP_CREATE) && defined(WIN32) */ if (Lflag) - show_dlts_and_exit(pd); + show_dlts_and_exit(device, pd); if (gndo->ndo_dlt >= 0) { #ifdef HAVE_PCAP_SET_DATALINK if (pcap_set_datalink(pd, gndo->ndo_dlt) < 0) @@ -1048,6 +1158,7 @@ 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); @@ -1099,15 +1210,21 @@ main(int argc, char **argv) } } else { type = pcap_datalink(pd); - printinfo.printer = lookup_printer(type); - if (printinfo.printer == NULL) { - gndo->ndo_dltname = pcap_datalink_val_to_name(type); - if (gndo->ndo_dltname != NULL) - error("unsupported data link type %s", - gndo->ndo_dltname); - else - error("unsupported data link type %d", type); - } + 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); + } + } callback = print_packet; pcap_userdata = (u_char *)&printinfo; } @@ -1262,6 +1379,11 @@ info(register int verbose) { struct pcap_stat stat; + /* + * Older versions of libpcap didn't set ps_ifdrop on some + * platforms; initialize it to 0 to handle that. + */ + stat.ps_ifdrop = 0; if (pcap_stats(pd, &stat) < 0) { (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd)); infoprint = 0; @@ -1276,12 +1398,21 @@ info(register int verbose) fputs(", ", stderr); else putc('\n', stderr); - (void)fprintf(stderr, "%d packets received by filter", stat.ps_recv); + (void)fprintf(stderr, "%u 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); + (void)fprintf(stderr, "%u packets dropped by kernel", 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); + } else + putc('\n', stderr); infoprint = 0; } @@ -1299,7 +1430,7 @@ compress_savefile(const char *filename) #else setpriority(PRIO_PROCESS, 0, 19); #endif - if (execlp(zflag, zflag, filename, NULL) == -1) + if (execlp(zflag, zflag, filename, (char *)NULL) == -1) fprintf(stderr, "compress_savefile:execlp(%s, %s): %s\n", zflag, @@ -1477,7 +1608,12 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) */ snapend = sp + h->caplen; - hdrlen = (*print_info->printer)(h, sp); + if(print_info->ndo_type) { + hdrlen = (*print_info->p.ndo_printer)(print_info->ndo, h, sp); + } else { + hdrlen = (*print_info->p.printer)(h, sp); + } + if (Xflag) { /* * Print the raw packet data in hex and ASCII. @@ -1647,7 +1783,7 @@ usage(void) #endif /* WIN32 */ #endif /* HAVE_PCAP_LIB_VERSION */ (void)fprintf(stderr, -"Usage: %s [-aAd" D_FLAG "ef" I_FLAG "KlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name); +"Usage: %s [-aAbd" D_FLAG "ef" I_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,