X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/bbc1cfa669a5f51ed26bae3784447076e3fbc80f..a9a7c86c7875a38358a9ff1f2a35e93febf6f41e:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index 06160f7f..a347bc2c 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.218 2003-11-16 09:36:44 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.283 2008-09-25 21:45:50 guy Exp $ (LBL)"; #endif /* @@ -56,12 +56,26 @@ extern int SIZE_BUF; #define uint UINT #endif /* WIN32 */ +#ifdef HAVE_SMI_H +#include +#endif + #include #include #include #include #include +#include +#ifndef WIN32 +#include +#include +#include +#include +#include +#endif /* WIN32 */ + +#include "netdissect.h" #include "interface.h" #include "addrtoname.h" #include "machdep.h" @@ -69,33 +83,19 @@ extern int SIZE_BUF; #include "gmt2local.h" #include "pcap-missing.h" -int dflag; /* print filter code */ -int eflag; /* print ethernet header */ -int fflag; /* don't translate "foreign" IP address */ -int Lflag; /* list available data link types and exit */ -int nflag; /* leave addresses as numbers */ -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; /* "unbuffered" output of dump files */ -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 */ -int dlt = -1; /* if != -1, ask libpcap for the DLT it names */ - -const char *dlt_name = NULL; - -char *espsecret = NULL; /* ESP secret key */ - -int packettype; +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +netdissect_options Gndo; +netdissect_options *gndo = &Gndo; + +static int dflag; /* print filter code */ +static int Lflag; /* list available data link types and exit */ +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE +static int Jflag; /* list available time stamp types */ +#endif +static char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */ static int infodelay; static int infoprint; @@ -106,30 +106,49 @@ int32_t thiszone; /* seconds offset from gmt to local time */ /* Forwards */ 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); 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_warning(netdissect_options *ndo, const char *fmt, ...); #ifdef SIGINFO RETSIGTYPE requestinfo(int); #endif +#if defined(USE_WIN32_MM_TIMER) + #include + static UINT timer_id; + static void CALLBACK verbose_stats_dump(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR); +#elif defined(HAVE_ALARM) + static void verbose_stats_dump(int sig); +#endif + static void info(int); static u_int packets_captured; -/* Length of saved portion of packet. */ -int snaplen = DEFAULT_SNAPLEN; - 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 @@ -144,13 +163,16 @@ 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 { sl_bsdos_if_print, DLT_SLIP_BSDOS }, #endif { ppp_if_print, DLT_PPP }, +#ifdef DLT_PPP_WITHDIRECTION + { ppp_if_print, DLT_PPP_WITHDIRECTION }, +#endif #ifdef DLT_PPP_BSDOS { ppp_bsdos_if_print, DLT_PPP_BSDOS }, #endif @@ -168,7 +190,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 }, @@ -182,8 +204,8 @@ static struct printer printers[] = { #ifdef DLT_LTALK { ltalk_if_print, DLT_LTALK }, #endif -#ifdef DLT_PFLOG - { pflog_if_print, DLT_PFLOG }, +#if defined(DLT_PFLOG) && defined(HAVE_NET_PFVAR_H) + { pflog_if_print, DLT_PFLOG }, #endif #ifdef DLT_FR { fr_if_print, DLT_FR }, @@ -204,7 +226,88 @@ 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 }, +#endif +#ifdef DLT_APPLE_IP_OVER_IEEE1394 + { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 }, +#endif +#ifdef DLT_IEEE802_11_RADIO_AVS + { ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS }, +#endif +#ifdef DLT_JUNIPER_ATM1 + { juniper_atm1_print, DLT_JUNIPER_ATM1 }, +#endif +#ifdef DLT_JUNIPER_ATM2 + { juniper_atm2_print, DLT_JUNIPER_ATM2 }, +#endif +#ifdef DLT_JUNIPER_MFR + { juniper_mfr_print, DLT_JUNIPER_MFR }, +#endif +#ifdef DLT_JUNIPER_MLFR + { juniper_mlfr_print, DLT_JUNIPER_MLFR }, +#endif +#ifdef DLT_JUNIPER_MLPPP + { juniper_mlppp_print, DLT_JUNIPER_MLPPP }, +#endif +#ifdef DLT_JUNIPER_PPPOE + { juniper_pppoe_print, DLT_JUNIPER_PPPOE }, +#endif +#ifdef DLT_JUNIPER_PPPOE_ATM + { juniper_pppoe_atm_print, DLT_JUNIPER_PPPOE_ATM }, +#endif +#ifdef DLT_JUNIPER_GGSN + { juniper_ggsn_print, DLT_JUNIPER_GGSN }, +#endif +#ifdef DLT_JUNIPER_ES + { juniper_es_print, DLT_JUNIPER_ES }, +#endif +#ifdef DLT_JUNIPER_MONITOR + { juniper_monitor_print, DLT_JUNIPER_MONITOR }, +#endif +#ifdef DLT_JUNIPER_SERVICES + { juniper_services_print, DLT_JUNIPER_SERVICES }, +#endif +#ifdef DLT_JUNIPER_ETHER + { juniper_ether_print, DLT_JUNIPER_ETHER }, +#endif +#ifdef DLT_JUNIPER_PPP + { juniper_ppp_print, DLT_JUNIPER_PPP }, +#endif +#ifdef DLT_JUNIPER_FRELAY + { juniper_frelay_print, DLT_JUNIPER_FRELAY }, +#endif +#ifdef DLT_JUNIPER_CHDLC + { juniper_chdlc_print, DLT_JUNIPER_CHDLC }, +#endif +#ifdef 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 { NULL, 0 }, }; @@ -222,24 +325,79 @@ 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 { char *WFileName; + char *CurrentFileName; pcap_t *pd; pcap_dumper_t *p; }; +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE static void -show_dlts_and_exit(pcap_t *pd) +show_tstamp_types_and_exit(const char *device, pcap_t *pd) +{ + 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); + if (n_tstamp_types < 0) + error("%s", pcap_geterr(pd)); + + if (n_tstamp_types == 0) { + fprintf(stderr, "Time stamp type cannot be set for %s\n", + device); + exit(0); + } + fprintf(stderr, "Time stamp types for %s (use option -j to set):\n", + device); + for (i = 0; i < n_tstamp_types; i++) { + tstamp_type_name = pcap_tstamp_type_val_to_name(tstamp_types[i]); + if (tstamp_type_name != NULL) { + (void) fprintf(stderr, " %s (%s)\n", tstamp_type_name, + pcap_tstamp_type_val_to_description(tstamp_types[i])); + } else { + (void) fprintf(stderr, " %d\n", tstamp_types[i]); + } + } + pcap_free_tstamp_types(tstamp_types); + exit(0); +} +#endif + +static void +show_dlts_and_exit(const char *device, pcap_t *pd) { int n_dlts; int *dlts = 0; @@ -251,25 +409,41 @@ 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]); if (dlt_name != NULL) { - (void) fprintf(stderr, " %s", dlt_name); + (void) fprintf(stderr, " %s (%s)", dlt_name, + pcap_datalink_val_to_description(dlts[n_dlts])); /* * OK, does tcpdump handle that type? */ - if (lookup_printer(dlts[n_dlts]) == NULL) - (void) fprintf(stderr, " (not supported)"); - putchar('\n'); + if (lookup_printer(dlts[n_dlts]) == NULL + && lookup_ndo_printer(dlts[n_dlts]) == NULL) + (void) fprintf(stderr, " (printing not supported)"); + fprintf(stderr, "\n"); } else { - (void) fprintf(stderr, " DLT %d (not supported)\n", + (void) fprintf(stderr, " DLT %d (printing not supported)\n", dlts[n_dlts]); } } - free(dlts); + pcap_free_datalinks(dlts); exit(0); } @@ -277,13 +451,35 @@ show_dlts_and_exit(pcap_t *pd) * Set up flags that might or might not be supported depending on the * version of libpcap we're using. */ -#ifdef WIN32 +#if defined(HAVE_PCAP_CREATE) || defined(WIN32) #define B_FLAG "B:" #define B_FLAG_USAGE " [ -B size ]" -#else /* WIN32 */ +#else /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ #define B_FLAG #define B_FLAG_USAGE -#endif /* WIN32 */ +#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ + +#ifdef HAVE_PCAP_CREATE +#define I_FLAG "I" +#else /* HAVE_PCAP_CREATE */ +#define I_FLAG +#endif /* HAVE_PCAP_CREATE */ + +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE +#define j_FLAG "j:" +#define j_FLAG_USAGE " [ -j tstamptype ]" +#define J_FLAG "J" +#else /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */ +#define j_FLAG +#define j_FLAG_USAGE +#define J_FLAG +#endif /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */ + +#ifdef HAVE_PCAP_FINDALLDEVS +#ifndef HAVE_PCAP_IF_T +#undef HAVE_PCAP_FINDALLDEVS +#endif +#endif #ifdef HAVE_PCAP_FINDALLDEVS #define D_FLAG "D" @@ -297,6 +493,105 @@ show_dlts_and_exit(pcap_t *pd) #define U_FLAG #endif +#ifndef WIN32 +/* Drop root privileges and chroot if necessary */ +static void +droproot(const char *username, const char *chroot_dir) +{ + struct passwd *pw = NULL; + + if (chroot_dir && !username) { + fprintf(stderr, "tcpdump: Chroot without dropping root is insecure\n"); + exit(1); + } + + pw = getpwnam(username); + if (pw) { + if (chroot_dir) { + if (chroot(chroot_dir) != 0 || chdir ("/") != 0) { + fprintf(stderr, "tcpdump: Couldn't chroot/chdir to '%.64s': %s\n", + chroot_dir, pcap_strerror(errno)); + exit(1); + } + } + 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", + username, + (unsigned long)pw->pw_uid, + (unsigned long)pw->pw_gid, + pcap_strerror(errno)); + exit(1); + } + } + else { + fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n", + username); + exit(1); + } +} +#endif /* WIN32 */ + +static int +getWflagChars(int x) +{ + int c = 0; + + x -= 1; + while (x > 0) { + c += 1; + x /= 10; + } + + return c; +} + + +static void +MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars) +{ + char *filename = malloc(NAME_MAX + 1); + + /* Process with strftime if Gflag is set. */ + if (Gflag != 0) { + struct tm *local_tm; + + /* Convert Gflag_time to a usable format */ + if ((local_tm = localtime(&Gflag_time)) == NULL) { + error("MakeTimedFilename: localtime"); + } + + /* There's no good way to detect an error in strftime since a return + * value of 0 isn't necessarily failure. + */ + strftime(filename, NAME_MAX, orig_name, local_tm); + } else { + strncpy(filename, orig_name, NAME_MAX); + } + + if (cnt == 0 && max_chars == 0) + strncpy(buffer, filename, NAME_MAX + 1); + else + if (snprintf(buffer, NAME_MAX + 1, "%s%0*d", filename, max_chars, cnt) > NAME_MAX) + /* Report an error if the filename is too large */ + error("too many output files or filename is too long (> %d)", NAME_MAX); + free(filename); +} + +static int tcpdump_printf(netdissect_options *ndo _U_, + const char *fmt, ...) +{ + + va_list args; + int ret; + + va_start(args, fmt); + ret=vfprintf(stdout, fmt, args); + va_end(args); + + return ret; +} + int main(int argc, char **argv) { @@ -313,16 +608,27 @@ main(int argc, char **argv) struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; + char *username = NULL; + char *chroot_dir = NULL; #ifdef HAVE_PCAP_FINDALLDEVS pcap_if_t *devpointer; int devnum; #endif int status; #ifdef WIN32 - u_int UserBufferSize = 1000000; if(wsockinit() != 0) return 1; #endif /* WIN32 */ + jflag=-1; /* not set */ + gndo->ndo_Oflag=1; + gndo->ndo_Rflag=1; + gndo->ndo_dlt=-1; + gndo->ndo_default_print=ndo_default_print; + gndo->ndo_printf=tcpdump_printf; + gndo->ndo_error=ndo_error; + gndo->ndo_warning=ndo_warning; + gndo->ndo_snaplen = DEFAULT_SNAPLEN; + cnt = -1; device = NULL; infile = NULL; @@ -342,7 +648,7 @@ main(int argc, char **argv) opterr = 0; while ( - (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:i:lLm:nNOpqr:Rs:StT:u" U_FLAG "vw:xXy:Y")) != -1) + (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) switch (op) { case 'a': @@ -350,18 +656,20 @@ main(int argc, char **argv) break; case 'A': - ++xflag; - ++Xflag; ++Aflag; break; -#ifdef WIN32 + case 'b': + ++bflag; + break; + +#if defined(HAVE_PCAP_CREATE) || defined(WIN32) case 'B': - UserBufferSize = atoi(optarg)*1024; - if (UserBufferSize < 0) + Bflag = atoi(optarg)*1024; + if (Bflag <= 0) error("invalid packet buffer size %s", optarg); break; -#endif /* WIN32 */ +#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */ case 'c': cnt = atoi(optarg); @@ -407,7 +715,7 @@ main(int argc, char **argv) #ifndef HAVE_LIBCRYPTO warning("crypto code not compiled in"); #endif - espsecret = optarg; + gndo->ndo_espsecret = optarg; break; case 'f': @@ -418,6 +726,25 @@ main(int argc, char **argv) infile = optarg; break; + case 'G': + Gflag = atoi(optarg); + if (Gflag < 0) + error("invalid number of seconds %s", optarg); + + /* We will create one file initially. */ + Gflag_count = 0; + + /* Grab the current time for rotation use. */ + if ((Gflag_time = time(NULL)) == (time_t)-1) { + error("main: can't get current time: %s", + pcap_strerror(errno)); + } + break; + + case 'h': + ++hflag; + break; + case 'i': if (optarg[0] == '0' && optarg[1] == 0) error("Invalid adapter index"); @@ -440,11 +767,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; @@ -453,33 +786,77 @@ main(int argc, char **argv) device = optarg; break; +#ifdef HAVE_PCAP_CREATE + case 'I': + ++Iflag; + break; +#endif /* HAVE_PCAP_CREATE */ + +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + case 'j': + jflag = pcap_tstamp_type_name_to_val(optarg); + if (jflag < 0) + error("invalid time stamp type %s", optarg); + break; + + case 'J': + Jflag++; + break; +#endif + case 'l': +#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 + * C library that is more UNIX-compatible. + */ + setvbuf(stdout, NULL, _IONBF, 0); +#else /* WIN32 */ #ifdef HAVE_SETLINEBUF setlinebuf(stdout); #else setvbuf(stdout, NULL, _IOLBF, 0); #endif +#endif /* WIN32 */ break; - case 'n': - ++nflag; - break; - - case 'N': - ++Nflag; + case 'K': + ++Kflag; break; case 'm': #ifdef LIBSMI - if (smiLoadModule(optarg) == 0) { + 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 + break; + + case 'M': + /* TCP-MD5 shared secret */ +#ifndef HAVE_LIBCRYPTO + warning("crypto code not compiled in"); +#endif + sigsecret = optarg; + break; + + case 'n': + ++nflag; + break; + + case 'N': + ++Nflag; + break; case 'O': Oflag = 0; @@ -491,6 +868,7 @@ main(int argc, char **argv) case 'q': ++qflag; + ++suppress_default_print; break; case 'r': @@ -506,10 +884,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; } @@ -518,7 +896,7 @@ main(int argc, char **argv) break; case 't': - --tflag; + ++tflag; break; case 'T': @@ -562,20 +940,29 @@ main(int argc, char **argv) WFileName = optarg; break; + case 'W': + Wflag = atoi(optarg); + if (Wflag < 0) + error("invalid number of output files %s", optarg); + WflagChars = getWflagChars(Wflag); + break; + case 'x': ++xflag; + ++suppress_default_print; break; case 'X': - ++xflag; ++Xflag; + ++suppress_default_print; break; case 'y': - dlt_name = optarg; - dlt = pcap_datalink_name_to_val(dlt_name); - if (dlt < 0) - error("invalid data link type %s", dlt_name); + gndo->ndo_dltname = optarg; + gndo->ndo_dlt = + pcap_datalink_name_to_val(gndo->ndo_dltname); + if (gndo->ndo_dlt < 0) + error("invalid data link type %s", gndo->ndo_dltname); break; #if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG) @@ -592,13 +979,65 @@ main(int argc, char **argv) } break; #endif + case 'z': + if (optarg) { + zflag = strdup(optarg); + } else { + usage(); + /* NOTREACHED */ + } + break; + + case 'Z': + if (optarg) { + username = strdup(optarg); + } + else { + usage(); + /* NOTREACHED */ + } + break; + default: usage(); /* NOTREACHED */ } - if (tflag > 0) + switch (tflag) { + + case 0: /* Default */ + case 4: /* Default + Date*/ thiszone = gmt2local(0); + break; + + case 1: /* No time stamp */ + case 2: /* Unix timeval style */ + case 3: /* Microseconds since previous packet */ + case 5: /* Microseconds since first packet */ + break; + + default: /* Not supported */ + error("only -t, -tt, -ttt, -tttt and -ttttt are supported"); + break; + } + +#ifdef WITH_CHROOT + /* if run as root, prepare for chrooting */ + if (getuid() == 0 || geteuid() == 0) { + /* future extensibility for cmd-line arguments */ + if (!chroot_dir) + chroot_dir = WITH_CHROOT; + } +#endif + +#ifdef WITH_USER + /* if run as root, prepare for dropping root privileges */ + if (getuid() == 0 || geteuid() == 0) { + /* Run with '-Z root' to restore old behaviour */ + if (!username) + username = WITH_USER; + } +#endif if (RFileName != NULL) { int dlt; @@ -614,17 +1053,23 @@ main(int argc, char **argv) * people's trace files (especially if we're set-UID * root). */ - setuid(getuid()); + if (setgid(getgid()) != 0 || setuid(getuid()) != 0 ) + fprintf(stderr, "Warning: setgid/setuid failed !\n"); #endif /* WIN32 */ pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); dlt = pcap_datalink(pd); dlt_name = pcap_datalink_val_to_name(dlt); - if (dlt_name == NULL) - dlt_name = "???"; - printf("reading from file %s, link-type %u (%s)\n", - RFileName, dlt, dlt_name); + if (dlt_name == NULL) { + fprintf(stderr, "reading from file %s, link-type %u\n", + RFileName, dlt); + } else { + fprintf(stderr, + "reading from file %s, link-type %s (%s)\n", + RFileName, dlt_name, + pcap_datalink_val_to_description(dlt)); + } localnet = 0; netmask = 0; if (fflag != 0) @@ -636,11 +1081,8 @@ main(int argc, char **argv) error("%s", ebuf); } #ifdef WIN32 - if(IsTextUnicode(device, - wcslen((short*)device), // Device always ends with a double \0, so this way to determine its - // length should be always valid - NULL)) - { + if(strlen(device) == 1) //we assume that an ASCII string is always longer than 1 char + { //a Unicode string has a \0 as second byte (so strlen() is 1) fprintf(stderr, "%s: listening on %ws\n", program_name, device); } else @@ -650,23 +1092,111 @@ main(int argc, char **argv) fflush(stderr); #endif /* WIN32 */ +#ifdef HAVE_PCAP_CREATE + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + if (Jflag) + show_tstamp_types_and_exit(device, pd); +#endif + /* + * 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: Can't set snapshot length: %s", + device, pcap_statustostr(status)); + status = pcap_set_promisc(pd, !pflag); + if (status != 0) + error("%s: Can't set promiscuous mode: %s", + device, pcap_statustostr(status)); + if (Iflag) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: Can't set monitor mode: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + if (Bflag != 0) { + status = pcap_set_buffer_size(pd, Bflag); + if (status != 0) + error("%s: Can't set buffer size: %s", + device, pcap_statustostr(status)); + } +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + if (jflag != -1) { + status = pcap_set_tstamp_type(pd, jflag); + if (status < 0) + error("%s: Can't set time stamp type: %s", + device, pcap_statustostr(status)); + } +#endif + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + cp = pcap_geterr(pd); + if (status == PCAP_ERROR) + 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 + warning("%s: %s", device, + pcap_statustostr(status)); + } +#else *ebuf = '\0'; - pd = pcap_open_live(device, snaplen, !pflag, 10000, ebuf); + pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); if (pd == NULL) error("%s", ebuf); else if (*ebuf) warning("%s", ebuf); -#ifdef WIN32 - if(UserBufferSize != 1000000) - if(pcap_setbuff(pd, UserBufferSize)==-1){ +#endif /* HAVE_PCAP_CREATE */ + /* + * Let user own process after socket has been opened. + */ +#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) + if(Bflag != 0) + if(pcap_setbuff(pd, Bflag)==-1){ error("%s", pcap_geterr(pd)); } -#endif /* WIN32 */ +#endif /* !defined(HAVE_PCAP_CREATE) && defined(WIN32) */ if (Lflag) - show_dlts_and_exit(pd); - if (dlt >= 0) { + show_dlts_and_exit(device, pd); + if (gndo->ndo_dlt >= 0) { #ifdef HAVE_PCAP_SET_DATALINK - if (pcap_set_datalink(pd, dlt) < 0) + if (pcap_set_datalink(pd, gndo->ndo_dlt) < 0) error("%s", pcap_geterr(pd)); #else /* @@ -674,13 +1204,13 @@ main(int argc, char **argv) * data link type, so we only let them * set it to what it already is. */ - if (dlt != pcap_datalink(pd)) { + if (gndo->ndo_dlt != pcap_datalink(pd)) { error("%s is not one of the DLTs supported by this device\n", - dlt_name); + gndo->ndo_dltname); } #endif (void)fprintf(stderr, "%s: data link type %s\n", - program_name, dlt_name); + program_name, gndo->ndo_dltname); (void)fflush(stderr); } i = pcap_snapshot(pd); @@ -693,12 +1223,6 @@ main(int argc, char **argv) netmask = 0; warning("%s", ebuf); } - /* - * Let user own process after socket has been opened. - */ -#ifndef WIN32 - setuid(getuid()); -#endif /* WIN32 */ } if (infile) cmdbuf = read_infile(infile); @@ -707,31 +1231,71 @@ 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); exit(0); } init_addrtoname(localnet, netmask); + init_checksum(); #ifndef WIN32 (void)setsignal(SIGPIPE, cleanup); -#endif /* WIN32 */ (void)setsignal(SIGTERM, cleanup); (void)setsignal(SIGINT, cleanup); + (void)setsignal(SIGCHLD, child_cleanup); +#endif /* WIN32 */ /* Cooperate with nohup(1) */ #ifndef WIN32 if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) (void)setsignal(SIGHUP, oldhandler); #endif /* 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, + * to allow tcpdump to be run in a special restricted + * account (if you just want to allow users to open capture + * devices, and can't just give users that permission, + * you'd make tcpdump set-UID or set-GID). + * + * Tcpdump doesn't necessarily write only to one savefile; + * the general only way to allow a -Z instance to write to + * savefiles as the user under whose UID it's run, rather + * than as the user specified with -Z, would thus be to switch + * to the original user ID before opening a capture file and + * then switch back to the -Z user ID after opening the savefile. + * Switching to the -Z user ID only after opening the first + * savefile doesn't handle the general case. + */ + if (getuid() == 0 || geteuid() == 0) { + if (username || chroot_dir) + droproot(username, chroot_dir); + } +#endif /* WIN32 */ + if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); if (WFileName) { - pcap_dumper_t *p = pcap_dump_open(pd, WFileName); + pcap_dumper_t *p; + /* Do not exceed the default NAME_MAX for files. */ + dumpinfo.CurrentFileName = (char *)malloc(NAME_MAX + 1); + + if (dumpinfo.CurrentFileName == NULL) + error("malloc of dumpinfo.CurrentFileName"); + + /* We do not need numbering for dumpfiles if Cflag isn't set. */ + if (Cflag != 0) + MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, WflagChars); + else + MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0); + + p = pcap_dump_open(pd, dumpinfo.CurrentFileName); if (p == NULL) error("%s", pcap_geterr(pd)); - if (Cflag != 0) { + if (Cflag != 0 || Gflag != 0) { callback = dump_packet_and_trunc; dumpinfo.WFileName = WFileName; dumpinfo.pd = pd; @@ -741,22 +1305,56 @@ main(int argc, char **argv) callback = dump_packet; pcap_userdata = (u_char *)p; } +#ifdef HAVE_PCAP_DUMP_FLUSH + if (Uflag) + pcap_dump_flush(p); +#endif } else { type = pcap_datalink(pd); - printinfo.printer = lookup_printer(type); - if (printinfo.printer == NULL) { - dlt_name = pcap_datalink_val_to_name(type); - if (dlt_name != NULL) - error("unsupported data link type %s", dlt_name); - 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; } + #ifdef SIGINFO - (void)setsignal(SIGINFO, requestinfo); + /* + * We can't get statistics when reading from a file rather + * than capturing from a device. + */ + if (RFileName == NULL) + (void)setsignal(SIGINFO, requestinfo); #endif + + if (vflag > 0 && WFileName) { + /* + * When capturing to a file, "-v" means tcpdump should, + * every 10 secodns, "v"erbosely report the number of + * packets captured. + */ +#ifdef USE_WIN32_MM_TIMER + /* call verbose_stats_dump() each 1000 +/-100msec */ + timer_id = timeSetEvent(1000, 100, verbose_stats_dump, 0, TIME_PERIODIC); + setvbuf(stderr, NULL, _IONBF, 0); +#elif defined(HAVE_ALARM) + (void)setsignal(SIGALRM, verbose_stats_dump); + alarm(1); +#endif + } + #ifndef WIN32 if (RFileName == NULL) { int dlt; @@ -770,10 +1368,14 @@ main(int argc, char **argv) (void)fprintf(stderr, "%s: ", program_name); dlt = pcap_datalink(pd); dlt_name = pcap_datalink_val_to_name(dlt); - if (dlt_name == NULL) - dlt_name = "???"; - (void)fprintf(stderr, "listening on %s, link-type %u (%s), capture size %u bytes\n", - device, dlt, dlt_name, snaplen); + if (dlt_name == NULL) { + (void)fprintf(stderr, "listening on %s, link-type %u, capture size %u bytes\n", + device, dlt, snaplen); + } else { + (void)fprintf(stderr, "listening on %s, link-type %s (%s), capture size %u bytes\n", + device, dlt_name, + pcap_datalink_val_to_description(dlt), snaplen); + } (void)fflush(stderr); } #endif /* WIN32 */ @@ -815,6 +1417,14 @@ main(int argc, char **argv) static RETSIGTYPE cleanup(int signo _U_) { +#ifdef USE_WIN32_MM_TIMER + if (timer_id) + timeKillEvent(timer_id); + timer_id = 0; +#elif defined(HAVE_ALARM) + alarm(0); +#endif + #ifdef HAVE_PCAP_BREAKLOOP /* * We have "pcap_breakloop()"; use it, so that we do as little @@ -844,13 +1454,31 @@ cleanup(int signo _U_) #endif } +/* + On windows, we do not use a fork, so we do not care less about + waiting a child processes to die + */ +#ifndef WIN32 +static RETSIGTYPE +child_cleanup(int signo _U_) +{ + wait(NULL); +} +#endif /* WIN32 */ + static void 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; return; } @@ -862,48 +1490,58 @@ 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; } +#ifndef WIN32 static void -reverse(char *s) +compress_savefile(const char *filename) { - 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; - } + if (fork()) + return; + /* + * Set to lowest priority so that this doesn't disturb the capture + */ +#ifdef NZERO + setpriority(PRIO_PROCESS, 0, NZERO - 1); +#else + setpriority(PRIO_PROCESS, 0, 19); +#endif + if (execlp(zflag, zflag, filename, (char *)NULL) == -1) + fprintf(stderr, + "compress_savefile:execlp(%s, %s): %s\n", + zflag, + filename, + strerror(errno)); } - - +#else /* WIN32 */ static void -swebitoa(unsigned int n, char *s) +compress_savefile(const char *filename) { - unsigned int i; - - i = 0; - do { - s[i++] = n % 10 + '0'; - } while ((n /= 10) > 0); - - s[i] = '\0'; - reverse(s); + fprintf(stderr, + "compress_savefile failed. Functionality not implemented under windows\n"); } +#endif /* WIN32 */ static void dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { struct dump_info *dump_info; - static uint cnt = 2; - char *name; ++packets_captured; @@ -911,21 +1549,104 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s dump_info = (struct dump_info *)user; + /* + * XXX - this won't force the file to rotate on the specified time + * boundary, but it will rotate on the first packet received after the + * specified Gflag number of seconds. Note: if a Gflag time boundary + * and a Cflag size boundary coincide, the time rotation will occur + * first thereby cancelling the Cflag boundary (since the file should + * be 0). + */ + if (Gflag != 0) { + /* Check if it is time to rotate */ + time_t t; + + /* Get the current time */ + if ((t = time(NULL)) == (time_t)-1) { + error("dump_and_trunc_packet: can't get current_time: %s", + pcap_strerror(errno)); + } + + + /* If the time is greater than the specified window, rotate */ + if (t - Gflag_time >= Gflag) { + /* Update the Gflag_time */ + Gflag_time = t; + /* Update Gflag_count */ + Gflag_count++; + /* + * Close the current file and open a new one. + */ + pcap_dump_close(dump_info->p); + + /* + * Compress the file we just closed, if the user asked for it + */ + if (zflag != NULL) + compress_savefile(dump_info->CurrentFileName); + + /* + * Check to see if we've exceeded the Wflag (when + * not using Cflag). + */ + if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) { + (void)fprintf(stderr, "Maximum file limit reached: %d\n", + Wflag); + exit(0); + /* NOTREACHED */ + } + if (dump_info->CurrentFileName != NULL) + free(dump_info->CurrentFileName); + /* Allocate space for max filename + \0. */ + dump_info->CurrentFileName = (char *)malloc(NAME_MAX + 1); + if (dump_info->CurrentFileName == NULL) + error("dump_packet_and_trunc: malloc"); + /* + * This is always the first file in the Cflag + * rotation: e.g. 0 + * We also don't need numbering if Cflag is not set. + */ + if (Cflag != 0) + MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, + WflagChars); + else + MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0); + + dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); + if (dump_info->p == NULL) + error("%s", pcap_geterr(pd)); + } + } + /* * 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 *)dump_info->p) > Cflag) { - name = (char *) malloc(strlen(dump_info->WFileName) + 4); - if (name == NULL) - error("dump_packet_and_trunc: malloc"); - strcpy(name, dump_info->WFileName); - swebitoa(cnt, name + strlen(dump_info->WFileName)); - cnt++; + if (Cflag != 0 && pcap_dump_ftell(dump_info->p) > Cflag) { + /* + * Close the current file and open a new one. + */ pcap_dump_close(dump_info->p); - dump_info->p = pcap_dump_open(dump_info->pd, name); - free(name); + + /* + * Compress the file we just closed, if the user asked for it + */ + if (zflag != NULL) + compress_savefile(dump_info->CurrentFileName); + + Cflag_count++; + if (Wflag > 0) { + if (Cflag_count >= Wflag) + Cflag_count = 0; + } + if (dump_info->CurrentFileName != NULL) + free(dump_info->CurrentFileName); + dump_info->CurrentFileName = (char *)malloc(NAME_MAX + 1); + if (dump_info->CurrentFileName == NULL) + error("dump_packet_and_trunc: malloc"); + MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars); + dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); } @@ -979,16 +1700,40 @@ 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 (xflag) { + 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. + */ + if (Xflag > 1) { + /* + * Include the link-layer header. + */ + hex_and_ascii_print("\n\t", sp, h->caplen); + } else { + /* + * Don't include the link-layer header - and if + * we have nothing past the link-layer header, + * print nothing. + */ + if (h->caplen > hdrlen) + hex_and_ascii_print("\n\t", sp + hdrlen, + h->caplen - hdrlen); + } + } else if (xflag) { /* - * Print the raw packet data. + * Print the raw packet data in hex. */ if (xflag > 1) { /* * Include the link-layer header. */ - default_print_unaligned(sp, h->caplen); + hex_print("\n\t", sp, h->caplen); } else { /* * Don't include the link-layer header - and if @@ -996,9 +1741,27 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) * print nothing. */ if (h->caplen > hdrlen) - default_print_unaligned(sp + hdrlen, + hex_print("\n\t", sp + hdrlen, h->caplen - hdrlen); } + } else if (Aflag) { + /* + * Print the raw packet data in ASCII. + */ + if (Aflag > 1) { + /* + * Include the link-layer header. + */ + ascii_print(sp, h->caplen); + } else { + /* + * Don't include the link-layer header - and if + * we have nothing past the link-layer header, + * print nothing. + */ + if (h->caplen > hdrlen) + ascii_print(sp + hdrlen, h->caplen - hdrlen); + } } putchar('\n'); @@ -1008,32 +1771,6 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) info(0); } -/* Like default_print() but data need not be aligned */ -void -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) { - if ((i++ % 8) == 0) - (void)printf("\n\t\t\t"); - s = *cp++; - (void)printf(" %02x%02x", s, *cp++); - } - if (length & 1) { - if ((i % 8) == 0) - (void)printf("\n\t\t\t"); - (void)printf(" %02x", *cp); - } -} - #ifdef WIN32 /* * XXX - there should really be libpcap calls to get the version @@ -1054,18 +1791,26 @@ default_print_unaligned(register const u_char *cp, register u_int length) * "Wpcap_version" information on Windows. */ char WDversion[]="current-cvs.tcpdump.org"; +#if !defined(HAVE_GENERATED_VERSION) char version[]="current-cvs.tcpdump.org"; +#endif char pcap_version[]="current-cvs.tcpdump.org"; - char Wpcap_version[]="3.0 alpha"; + char Wpcap_version[]="3.1"; #endif /* - * By default, print the specified data out in hex. + * By default, print the specified data out in hex and ASCII. */ +static void +ndo_default_print(netdissect_options *ndo _U_, const u_char *bp, u_int length) +{ + hex_and_ascii_print("\n\t", bp, length); /* pass on lf and identation string */ +} + void -default_print(register const u_char *bp, register u_int length) +default_print(const u_char *bp, u_int length) { - default_print_unaligned(bp, length); + ndo_default_print(gndo, bp, length); } #ifdef SIGINFO @@ -1078,6 +1823,29 @@ RETSIGTYPE requestinfo(int signo _U_) } #endif +/* + * Called once each second in verbose mode while dumping to file + */ +#ifdef USE_WIN32_MM_TIMER +void CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_, + DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_) +{ + struct pcap_stat stat; + + if (infodelay == 0 && pcap_stats(pd, &stat) >= 0) + fprintf(stderr, "Got %u\r", packets_captured); +} +#elif defined(HAVE_ALARM) +static void verbose_stats_dump(int sig _U_) +{ + struct pcap_stat stat; + + if (infodelay == 0 && pcap_stats(pd, &stat) >= 0) + fprintf(stderr, "Got %u\r", packets_captured); + alarm(1); +} +#endif + static void usage(void) { @@ -1091,8 +1859,12 @@ usage(void) #endif /* HAVE_PCAP_LIB_VERSION */ #ifdef HAVE_PCAP_LIB_VERSION +#ifdef WIN32 + (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version); +#else /* WIN32 */ (void)fprintf(stderr, "%s version %s\n", program_name, version); - (void)fprintf(stderr, "%s\n", pcap_lib_version()); +#endif /* WIN32 */ + (void)fprintf(stderr, "%s\n",pcap_lib_version()); #else /* HAVE_PCAP_LIB_VERSION */ #ifdef WIN32 (void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version); @@ -1103,12 +1875,54 @@ usage(void) #endif /* WIN32 */ #endif /* HAVE_PCAP_LIB_VERSION */ (void)fprintf(stderr, -"Usage: %s [-aAd" D_FLAG "eflLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [-c count] [ -C file_size ]\n", program_name); +"Usage: %s [-aAbd" D_FLAG "efh" 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[ -E algo:secret ] [ -F file ] [ -i interface ] [ -r file ]\n"); +"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n"); (void)fprintf(stderr, -"\t\t[ -s snaplen ] [ -T type ] [ -w file ] [ -y datalinktype ]\n"); +"\t\t[ -W filecount ] [ -y datalinktype ] [ -z command ]\n"); (void)fprintf(stderr, -"\t\t[ expression ]\n"); +"\t\t[ -Z user ] [ expression ]\n"); exit(1); } + + + +/* VARARGS */ +static void +ndo_error(netdissect_options *ndo _U_, const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +ndo_warning(netdissect_options *ndo _U_, const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +}