X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/ce1fc8263da72437c1df54b8b3ee682413d9e6ed..c115ab8ae92fd369ac227e93419e76fd6ae8e75c:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index 251c73a3..6a96ea94 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -43,39 +43,76 @@ The Regents of the University of California. All rights reserved.\n"; #include "config.h" #endif +/* + * Mac OS X may ship pcap.h from libpcap 0.6 with a libpcap based on + * 0.8. That means it has pcap_findalldevs() but the header doesn't + * define pcap_if_t, meaning that we can't actually *use* pcap_findalldevs(). + */ +#ifdef HAVE_PCAP_FINDALLDEVS +#ifndef HAVE_PCAP_IF_T +#undef HAVE_PCAP_FINDALLDEVS +#endif +#endif + #include -#ifdef WIN32 -#include "getopt.h" +#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 HAVE_SMI_H +#ifdef USE_LIBSMI #include #endif +#ifdef HAVE_LIBCRYPTO +#include +#endif + +#ifdef HAVE_GETOPT_LONG +#include +#else +#include "getopt_long.h" +#endif +/* Capsicum-specific code requires macros from , which will fail + * to compile if has already been included; including the headers + * in the opposite order works fine. + */ +#ifdef HAVE_CAPSICUM +#include +#include +#include +#include +#include +#endif /* HAVE_CAPSICUM */ #include #include #include #include #include #include -#ifndef WIN32 +#ifndef _WIN32 #include #include #include #include -#include -#endif /* WIN32 */ +#endif /* _WIN32 */ -/* capabilities convinience library */ +/* capabilities convenience library */ +/* If a code depends on HAVE_LIBCAP_NG, it depends also on HAVE_CAP_NG_H. + * If HAVE_CAP_NG_H is not defined, undefine HAVE_LIBCAP_NG. + * Thus, the later tests are done only on HAVE_LIBCAP_NG. + */ +#ifdef HAVE_LIBCAP_NG #ifdef HAVE_CAP_NG_H #include +#else +#undef HAVE_LIBCAP_NG #endif /* HAVE_CAP_NG_H */ +#endif /* HAVE_LIBCAP_NG */ #include "netdissect.h" #include "interface.h" @@ -119,7 +156,8 @@ 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 print_version(void); +static void print_usage(void); 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 *); @@ -167,37 +205,92 @@ struct ndo_printer { static const struct printer printers[] = { - { token_if_print, DLT_IEEE802 }, - { sl_if_print, DLT_SLIP }, -#ifdef DLT_SLIP_BSDOS - { sl_bsdos_if_print, DLT_SLIP_BSDOS }, + { NULL, 0 }, +}; + +static const struct ndo_printer ndo_printers[] = { + { ether_if_print, DLT_EN10MB }, +#ifdef DLT_IPNET + { ipnet_if_print, DLT_IPNET }, #endif - { ppp_if_print, DLT_PPP }, -#ifdef DLT_PPP_WITHDIRECTION - { ppp_if_print, DLT_PPP_WITHDIRECTION }, +#ifdef DLT_IEEE802_15_4 + { ieee802_15_4_if_print, DLT_IEEE802_15_4 }, #endif -#ifdef DLT_PPP_BSDOS - { ppp_bsdos_if_print, DLT_PPP_BSDOS }, +#ifdef DLT_IEEE802_15_4_NOFCS + { ieee802_15_4_if_print, DLT_IEEE802_15_4_NOFCS }, #endif - { fddi_if_print, DLT_FDDI }, - { atm_if_print, DLT_ATM_RFC1483 }, -#ifdef DLT_PPP_SERIAL - { ppp_hdlc_if_print, DLT_PPP_SERIAL }, +#ifdef DLT_PPI + { ppi_if_print, DLT_PPI }, #endif -#ifdef DLT_PPP_ETHER - { pppoe_if_print, DLT_PPP_ETHER }, +#ifdef DLT_NETANALYZER + { netanalyzer_if_print, DLT_NETANALYZER }, #endif -#ifdef DLT_LINUX_SLL - { sll_if_print, DLT_LINUX_SLL }, +#ifdef DLT_NETANALYZER_TRANSPARENT + { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT }, #endif -#ifdef DLT_IEEE802_11 - { ieee802_11_if_print, DLT_IEEE802_11}, +#if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H) + { nflog_if_print, DLT_NFLOG}, #endif -#ifdef DLT_LTALK - { ltalk_if_print, DLT_LTALK }, +#ifdef DLT_CIP + { cip_if_print, DLT_CIP }, +#endif +#ifdef DLT_ATM_CLIP + { cip_if_print, DLT_ATM_CLIP }, +#endif +#ifdef DLT_IP_OVER_FC + { ipfc_if_print, DLT_IP_OVER_FC }, +#endif + { null_if_print, DLT_NULL }, +#ifdef DLT_LOOP + { null_if_print, DLT_LOOP }, +#endif +#ifdef DLT_APPLE_IP_OVER_IEEE1394 + { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 }, +#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 DLT_LANE8023 + { lane_if_print, DLT_LANE8023 }, +#endif + { arcnet_if_print, DLT_ARCNET }, +#ifdef DLT_ARCNET_LINUX + { arcnet_linux_if_print, DLT_ARCNET_LINUX }, +#endif + { raw_if_print, DLT_RAW }, +#ifdef DLT_IPV4 + { raw_if_print, DLT_IPV4 }, +#endif +#ifdef DLT_IPV6 + { raw_if_print, DLT_IPV6 }, +#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_SYMANTEC_FIREWALL + { symantec_if_print, DLT_SYMANTEC_FIREWALL }, +#endif +#ifdef DLT_C_HDLC + { chdlc_if_print, DLT_C_HDLC }, +#endif +#ifdef DLT_HDLC + { chdlc_if_print, DLT_HDLC }, +#endif +#ifdef DLT_PPP_ETHER + { pppoe_if_print, DLT_PPP_ETHER }, #endif #if defined(DLT_PFLOG) && defined(HAVE_NET_PFVAR_H) { pflog_if_print, DLT_PFLOG }, +#endif + { token_if_print, DLT_IEEE802 }, + { fddi_if_print, DLT_FDDI }, +#ifdef DLT_LINUX_SLL + { sll_if_print, DLT_LINUX_SLL }, #endif #ifdef DLT_FR { fr_if_print, DLT_FR }, @@ -205,20 +298,22 @@ static const struct printer printers[] = { #ifdef DLT_FRELAY { fr_if_print, DLT_FRELAY }, #endif +#ifdef DLT_MFR + { mfr_if_print, DLT_MFR }, +#endif + { atm_if_print, DLT_ATM_RFC1483 }, #ifdef DLT_SUNATM { sunatm_if_print, DLT_SUNATM }, #endif -#ifdef DLT_PRISM_HEADER - { prism_if_print, DLT_PRISM_HEADER }, -#endif -#ifdef DLT_IEEE802_11_RADIO - { ieee802_11_radio_if_print, DLT_IEEE802_11_RADIO }, -#endif #ifdef DLT_ENC { enc_if_print, DLT_ENC }, #endif -#ifdef DLT_IEEE802_11_RADIO_AVS - { ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS }, + { sl_if_print, DLT_SLIP }, +#ifdef DLT_SLIP_BSDOS + { sl_bsdos_if_print, DLT_SLIP_BSDOS }, +#endif +#ifdef DLT_LTALK + { ltalk_if_print, DLT_LTALK }, #endif #ifdef DLT_JUNIPER_ATM1 { juniper_atm1_print, DLT_JUNIPER_ATM1 }, @@ -265,84 +360,30 @@ static const struct printer printers[] = { #ifdef DLT_JUNIPER_CHDLC { juniper_chdlc_print, DLT_JUNIPER_CHDLC }, #endif -#ifdef DLT_MFR - { mfr_if_print, DLT_MFR }, -#endif - { NULL, 0 }, -}; - -static const struct ndo_printer ndo_printers[] = { - { ether_if_print, DLT_EN10MB }, -#ifdef DLT_IPNET - { ipnet_if_print, DLT_IPNET }, -#endif -#ifdef DLT_IEEE802_15_4 - { ieee802_15_4_if_print, DLT_IEEE802_15_4 }, -#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 -#if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H) - { nflog_if_print, DLT_NFLOG}, -#endif -#ifdef DLT_CIP - { cip_if_print, DLT_CIP }, -#endif -#ifdef DLT_ATM_CLIP - { cip_if_print, DLT_ATM_CLIP }, -#endif -#ifdef DLT_IP_OVER_FC - { ipfc_if_print, DLT_IP_OVER_FC }, +#ifdef DLT_PKTAP + { pktap_if_print, DLT_PKTAP }, #endif - { null_if_print, DLT_NULL }, -#ifdef DLT_LOOP - { null_if_print, DLT_LOOP }, -#endif -#ifdef DLT_APPLE_IP_OVER_IEEE1394 - { ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 }, -#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 DLT_LANE8023 - { lane_if_print, DLT_LANE8023 }, +#ifdef DLT_IEEE802_11_RADIO + { ieee802_11_radio_if_print, DLT_IEEE802_11_RADIO }, #endif - { arcnet_if_print, DLT_ARCNET }, -#ifdef DLT_ARCNET_LINUX - { arcnet_linux_if_print, DLT_ARCNET_LINUX }, +#ifdef DLT_IEEE802_11 + { ieee802_11_if_print, DLT_IEEE802_11}, #endif - { raw_if_print, DLT_RAW }, -#ifdef DLT_IPV4 - { raw_if_print, DLT_IPV4 }, +#ifdef DLT_IEEE802_11_RADIO_AVS + { ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS }, #endif -#ifdef DLT_IPV6 - { raw_if_print, DLT_IPV6 }, +#ifdef DLT_PRISM_HEADER + { prism_if_print, DLT_PRISM_HEADER }, #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_SYMANTEC_FIREWALL - { symantec_if_print, DLT_SYMANTEC_FIREWALL }, + { ppp_if_print, DLT_PPP }, +#ifdef DLT_PPP_WITHDIRECTION + { ppp_if_print, DLT_PPP_WITHDIRECTION }, #endif -#ifdef DLT_C_HDLC - { chdlc_if_print, DLT_C_HDLC }, +#ifdef DLT_PPP_BSDOS + { ppp_bsdos_if_print, DLT_PPP_BSDOS }, #endif -#ifdef DLT_HDLC - { chdlc_if_print, DLT_HDLC }, +#ifdef DLT_PPP_SERIAL + { ppp_hdlc_if_print, DLT_PPP_SERIAL }, #endif { NULL, 0 }, }; @@ -380,6 +421,30 @@ lookup_ndo_printer(int type) if (type == p->type) return p->f; +#if defined(DLT_USER2) && defined(DLT_PKTAP) + /* + * Apple incorrectly chose to use DLT_USER2 for their PKTAP + * header. + * + * We map DLT_PKTAP, whether it's DLT_USER2 as it is on Darwin- + * based OSes or the same value as LINKTYPE_PKTAP as it is on + * other OSes, to LINKTYPE_PKTAP, so files written with + * this version of libpcap for a DLT_PKTAP capture have a link- + * layer header type of LINKTYPE_PKTAP. + * + * However, files written on OS X Mavericks for a DLT_PKTAP + * capture have a link-layer header type of LINKTYPE_USER2. + * If we don't have a printer for DLT_USER2, and type is + * DLT_USER2, we look up the printer for DLT_PKTAP and use + * that. + */ + if (type == DLT_USER2) { + for (p = ndo_printers; p->f; ++p) + if (DLT_PKTAP == p->type) + return p->f; + } +#endif + return NULL; /* NOTREACHED */ } @@ -406,6 +471,9 @@ struct dump_info { char *CurrentFileName; pcap_t *pd; pcap_dumper_t *p; +#ifdef HAVE_CAPSICUM + int dirfd; +#endif }; #ifdef HAVE_PCAP_SET_TSTAMP_TYPE @@ -445,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; @@ -471,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 @@ -520,17 +588,47 @@ show_devices_and_exit (void) } #endif /* HAVE_PCAP_FINDALLDEVS */ +/* + * Short options. + * + * Note that there we use all letters for short options except for g, k, + * o, and P, and those are used by other versions of tcpdump, and we should + * only use them for the same purposes that the other versions of tcpdump + * use them: + * + * OS X tcpdump uses -g to force non--v output for IP to be on one + * line, making it more "g"repable; + * + * OS X tcpdump uses -k tospecify that packet comments in pcap-ng files + * should be printed; + * + * OpenBSD tcpdump uses -o to indicate that OS fingerprinting should be done + * for hosts sending TCP SYN packets; + * + * 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" @@ -548,12 +646,6 @@ show_devices_and_exit (void) #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" #else @@ -572,7 +664,75 @@ show_devices_and_exit (void) #define Q_FLAG #endif -#ifndef WIN32 +#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. + * + * We do not currently have long options corresponding to all short + * options; we should probably pick appropriate option names for them. + * + * However, the short options where the number of times the option is + * specified matters, such as -v and -d and -t, should probably not + * just map to a long option, as saying + * + * tcpdump --verbose --verbose + * + * doesn't make sense; it should be --verbosity={N} or something such + * as that. + * + * For long options with no corresponding short options, we define values + * outside the range of ASCII graphic characters, make that the last + * component of the entry for the long option, and have a case for that + * option in the switch statement. + */ +#define OPTION_VERSION 128 +#define OPTION_TSTAMP_PRECISION 129 +#define OPTION_IMMEDIATE_MODE 130 + +static const struct option longopts[] = { +#if defined(HAVE_PCAP_CREATE) || defined(_WIN32) + { "buffer-size", required_argument, NULL, 'B' }, +#endif + { "list-interfaces", no_argument, NULL, 'D' }, + { "help", no_argument, NULL, 'h' }, + { "interface", required_argument, NULL, 'i' }, +#ifdef HAVE_PCAP_CREATE + { "monitor-mode", no_argument, NULL, 'I' }, +#endif +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + { "time-stamp-type", required_argument, NULL, 'j' }, + { "list-time-stamp-types", no_argument, NULL, 'J' }, +#endif +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION + { "time-stamp-precision", required_argument, NULL, OPTION_TSTAMP_PRECISION}, +#endif + { "dont-verify-checksums", no_argument, NULL, 'K' }, + { "list-data-link-types", no_argument, NULL, 'L' }, + { "no-optimize", no_argument, NULL, 'O' }, + { "no-promiscuous-mode", no_argument, NULL, 'p' }, +#ifdef HAVE_PCAP_SETDIRECTION + { "direction", required_argument, NULL, 'Q' }, +#endif + { "snapshot-length", required_argument, NULL, 's' }, + { "absolute-tcp-sequence-numbers", no_argument, NULL, 'S' }, +#ifdef HAVE_PCAP_DUMP_FLUSH + { "packet-buffered", no_argument, NULL, 'U' }, +#endif + { "linktype", required_argument, NULL, 'y' }, +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + { "immediate-mode", no_argument, NULL, OPTION_IMMEDIATE_MODE }, +#endif +#if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG) + { "debug-filter-parser", no_argument, NULL, 'Y' }, +#endif + { "relinquish-privileges", required_argument, NULL, 'Z' }, + { "number", no_argument, NULL, '#' }, + { "version", no_argument, NULL, OPTION_VERSION }, + { NULL, 0, NULL, 0 } +}; + +#ifndef _WIN32 /* Drop root privileges and chroot if necessary */ static void droproot(const char *username, const char *chroot_dir) @@ -593,18 +753,14 @@ droproot(const char *username, const char *chroot_dir) exit(1); } } -#ifdef HAVE_CAP_NG_H +#ifdef HAVE_LIBCAP_NG int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG); if (ret < 0) { - printf("error : ret %d\n", ret); + fprintf(stderr, "error : ret %d\n", ret); + } + else { + fprintf(stderr, "dropped privs to %s\n", username); } - /* 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) { @@ -615,15 +771,29 @@ droproot(const char *username, const char *chroot_dir) pcap_strerror(errno)); exit(1); } -#endif /* HAVE_CAP_NG_H */ + else { + fprintf(stderr, "dropped privs to %s\n", username); + } +#endif /* HAVE_LIBCAP_NG */ } else { fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n", username); exit(1); } +#ifdef HAVE_LIBCAP_NG + /* We don't need CAP_SETUID and CAP_SETGID any more. */ + capng_updatev( + CAPNG_DROP, + CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_SETUID, + CAP_SETGID, + -1); + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ + } -#endif /* WIN32 */ +#endif /* _WIN32 */ static int getWflagChars(int x) @@ -725,6 +895,106 @@ get_next_file(FILE *VFile, char *ptr) return ret; } +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION +static int +tstamp_precision_from_string(const char *precision) +{ + if (strncmp(precision, "nano", strlen("nano")) == 0) + return PCAP_TSTAMP_PRECISION_NANO; + + if (strncmp(precision, "micro", strlen("micro")) == 0) + return PCAP_TSTAMP_PRECISION_MICRO; + + return -EINVAL; +} + +static const char * +tstamp_precision_to_string(int precision) +{ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + return "micro"; + + case PCAP_TSTAMP_PRECISION_NANO: + return "nano"; + + default: + return "unknown"; + } +} +#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) { @@ -737,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; @@ -755,9 +1025,14 @@ main(int argc, char **argv) #endif int status; FILE *VFile; -#ifdef WIN32 +#ifdef HAVE_CAPSICUM + cap_rights_t rights; + int cansandbox; +#endif /* HAVE_CAPSICUM */ + +#ifdef _WIN32 if(wsockinit() != 0) return 1; -#endif /* WIN32 */ +#endif /* _WIN32 */ jflag=-1; /* not set */ gndo->ndo_Oflag=1; @@ -768,6 +1043,7 @@ main(int argc, char **argv) gndo->ndo_error=ndo_error; gndo->ndo_warning=ndo_warning; gndo->ndo_snaplen = DEFAULT_SNAPLEN; + gndo->ndo_immediate = 0; cnt = -1; device = NULL; @@ -782,15 +1058,22 @@ main(int argc, char **argv) else program_name = argv[0]; + /* + * On platforms where the CPU doesn't support unaligned loads, + * force unaligned accesses to abort with SIGBUS, rather than + * being fixed up (slowly) by the OS kernel; on those platforms, + * misaligned accesses are bugs, and we want tcpdump to crash so + * that the bugs are reported. + */ if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0) error("%s", ebuf); -#ifdef LIBSMI +#ifdef USE_LIBSMI smiInit("tcpdump"); #endif while ( - (op = getopt(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:")) != -1) + (op = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != -1) switch (op) { case 'a': @@ -805,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); @@ -872,7 +1155,8 @@ main(int argc, char **argv) break; case 'h': - usage(); + print_usage(); + exit(0); break; case 'H': @@ -940,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': @@ -965,7 +1249,7 @@ main(int argc, char **argv) break; case 'm': -#ifdef LIBSMI +#ifdef USE_LIBSMI if (smiLoadModule(optarg) == 0) { error("could not load MIB module %s", optarg); } @@ -1150,8 +1434,32 @@ main(int argc, char **argv) username = strdup(optarg); break; + case '#': + gndo->ndo_packet_number = 1; + break; + + case OPTION_VERSION: + print_version(); + exit(0); + break; + +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION + case OPTION_TSTAMP_PRECISION: + gndo->ndo_tstamp_precision = tstamp_precision_from_string(optarg); + if (gndo->ndo_tstamp_precision < 0) + error("unsupported time stamp precision"); + break; +#endif + +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + case OPTION_IMMEDIATE_MODE: + gndo->ndo_immediate = 1; + break; +#endif + default: - usage(); + print_usage(); + exit(1); /* NOTREACHED */ } @@ -1184,6 +1492,17 @@ main(int argc, char **argv) if (VFileName != NULL && RFileName != NULL) error("-V and -r are mutually exclusive."); +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + /* + * If we're printing dissected packets to the standard output + * rather than saving raw packets to a file, and the standard + * output is a terminal, use immediate mode, as the user's + * probably expecting to see packets pop up immediately. + */ + if (WFileName == NULL && isatty(1)) + gndo->ndo_immediate = 1; +#endif + #ifdef WITH_CHROOT /* if run as root, prepare for chrooting */ if (getuid() == 0 || geteuid() == 0) { @@ -1212,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). @@ -1224,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; @@ -1240,9 +1559,22 @@ main(int argc, char **argv) RFileName = VFileLine; } +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION + pd = pcap_open_offline_with_tstamp_precision(RFileName, + gndo->ndo_tstamp_precision, ebuf); +#else pd = pcap_open_offline(RFileName, ebuf); +#endif + if (pd == NULL) error("%s", ebuf); +#ifdef HAVE_CAPSICUM + cap_rights_init(&rights, CAP_READ); + if (cap_rights_limit(fileno(pcap_file(pd)), &rights) < 0 && + errno != ENOSYS) { + error("unable to limit pcap descriptor"); + } +#endif dlt = pcap_datalink(pd); dlt_name = pcap_datalink_val_to_name(dlt); if (dlt_name == NULL) { @@ -1263,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? @@ -1278,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) @@ -1286,6 +1618,24 @@ main(int argc, char **argv) #ifdef HAVE_PCAP_SET_TSTAMP_TYPE if (Jflag) show_tstamp_types_and_exit(device, pd); +#endif +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION + status = pcap_set_tstamp_precision(pd, gndo->ndo_tstamp_precision); + if (status != 0) + error("%s: Can't set %ssecond time stamp precision: %s", + device, + tstamp_precision_to_string(gndo->ndo_tstamp_precision), + pcap_statustostr(status)); +#endif + +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + if (gndo->ndo_immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: Can't set immediate mode: %s", + device, + pcap_statustostr(status)); + } #endif /* * Is this an interface that supports monitor mode? @@ -1323,7 +1673,7 @@ main(int argc, char **argv) status = pcap_set_tstamp_type(pd, jflag); if (status < 0) error("%s: Can't set time stamp type: %s", - device, pcap_statustostr(status)); + device, pcap_statustostr(status)); } #endif status = pcap_activate(pd); @@ -1377,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) { @@ -1433,24 +1783,24 @@ main(int argc, char **argv) free(cmdbuf); exit(0); } - init_addrtoname(localnet, netmask); + 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, @@ -1469,35 +1819,51 @@ main(int argc, char **argv) * 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 (getuid() == 0 || geteuid() == 0) { +#ifdef HAVE_LIBCAP_NG + /* Initialize capng */ + capng_clear(CAPNG_SELECT_BOTH); 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); + capng_updatev( + CAPNG_ADD, + CAPNG_PERMITTED | CAPNG_EFFECTIVE, + CAP_SETUID, + CAP_SETGID, + -1); } - } -#endif /* HAVE_CAP_NG_H */ - if (getuid() == 0 || geteuid() == 0) { + if (WFileName) { + capng_update( + CAPNG_ADD, + CAPNG_PERMITTED | CAPNG_EFFECTIVE, + CAP_DAC_OVERRIDE + ); + } + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ if (username || chroot_dir) droproot(username, chroot_dir); } -#endif /* WIN32 */ +#endif /* _WIN32 */ if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); +#ifdef HAVE_CAPSICUM + if (RFileName == NULL && VFileName == NULL) { + static const unsigned long cmds[] = { BIOCGSTATS }; + + cap_rights_init(&rights, CAP_IOCTL, CAP_READ); + if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 && + errno != ENOSYS) { + error("unable to limit pcap descriptor"); + } + if (cap_ioctls_limit(pcap_fileno(pd), cmds, + sizeof(cmds) / sizeof(cmds[0])) < 0 && errno != ENOSYS) { + error("unable to limit ioctls on pcap descriptor"); + } + } +#endif if (WFileName) { pcap_dumper_t *p; /* Do not exceed the default PATH_MAX for files. */ @@ -1513,15 +1879,47 @@ 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 +#ifdef HAVE_LIBCAP_NG + /* Give up CAP_DAC_OVERRIDE capability. + * Only allow it to be restored if the -C or -G flag have been + * set since we may need to create more files later on. + */ + capng_update( + CAPNG_DROP, + (Cflag || Gflag ? 0 : CAPNG_PERMITTED) + | CAPNG_EFFECTIVE, + CAP_DAC_OVERRIDE + ); + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ if (p == NULL) error("%s", pcap_geterr(pd)); +#ifdef HAVE_CAPSICUM + set_dumper_capsicum_rights(p); +#endif if (Cflag != 0 || Gflag != 0) { - callback = dump_packet_and_trunc; +#ifdef HAVE_CAPSICUM + dumpinfo.WFileName = strdup(basename(WFileName)); + dumpinfo.dirfd = open(dirname(WFileName), + O_DIRECTORY | O_RDONLY); + if (dumpinfo.dirfd < 0) { + error("unable to open directory %s", + dirname(WFileName)); + } + cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, + CAP_FTRUNCATE, CAP_LOOKUP, CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(dumpinfo.dirfd, &rights) < 0 && + errno != ENOSYS) { + error("unable to limit directory rights"); + } + if (cap_fcntls_limit(dumpinfo.dirfd, CAP_FCNTL_GETFL) < 0 && + errno != ENOSYS) { + error("unable to limit dump descriptor fcntls"); + } +#else /* !HAVE_CAPSICUM */ dumpinfo.WFileName = WFileName; +#endif + callback = dump_packet_and_trunc; dumpinfo.pd = pd; dumpinfo.p = p; pcap_userdata = (u_char *)&dumpinfo; @@ -1565,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 @@ -1590,7 +1988,16 @@ main(int argc, char **argv) } (void)fflush(stderr); } -#endif /* WIN32 */ +#endif /* _WIN32 */ + +#ifdef HAVE_CAPSICUM + cansandbox = (nflag && VFileName == NULL && zflag == NULL); + if (cansandbox && cap_enter() < 0 && errno != ENOSYS) + error("unable to enter the capability mode"); + if (cap_sandboxed()) + fprintf(stderr, "capability mode sandbox enabled\n"); +#endif /* HAVE_CAPSICUM */ + do { status = pcap_loop(pd, cnt, callback, pcap_userdata); if (WFileName == NULL) { @@ -1638,6 +2045,13 @@ main(int argc, char **argv) pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); +#ifdef HAVE_CAPSICUM + cap_rights_init(&rights, CAP_READ); + if (cap_rights_limit(fileno(pcap_file(pd)), + &rights) < 0 && errno != ENOSYS) { + error("unable to limit pcap descriptor"); + } +#endif new_dlt = pcap_datalink(pd); if (WFileName && new_dlt != dlt) error("%s: new dlt does not match original", RFileName); @@ -1834,6 +2248,11 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s /* If the time is greater than the specified window, rotate */ if (t - Gflag_time >= Gflag) { +#ifdef HAVE_CAPSICUM + FILE *fp; + int fd; +#endif + /* Update the Gflag_time */ Gflag_time = t; /* Update Gflag_count */ @@ -1883,17 +2302,36 @@ 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 +#ifdef HAVE_LIBCAP_NG capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); - capng_apply(CAPNG_EFFECTIVE); -#endif /* HAVE_CAP_NG_H */ + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ +#ifdef HAVE_CAPSICUM + fd = openat(dump_info->dirfd, + dump_info->CurrentFileName, + O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd < 0) { + error("unable to open file %s", + dump_info->CurrentFileName); + } + fp = fdopen(fd, "w"); + if (fp == NULL) { + error("unable to fdopen file %s", + dump_info->CurrentFileName); + } + dump_info->p = pcap_dump_fopen(dump_info->pd, fp); +#else /* !HAVE_CAPSICUM */ dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); -#ifdef HAVE_CAP_NG_H +#endif +#ifdef HAVE_LIBCAP_NG capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); - capng_apply(CAPNG_EFFECTIVE); -#endif /* HAVE_CAP_NG_H */ + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ if (dump_info->p == NULL) error("%s", pcap_geterr(pd)); +#ifdef HAVE_CAPSICUM + set_dumper_capsicum_rights(dump_info->p); +#endif } } @@ -1902,32 +2340,70 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s * larger than Cflag - the last packet written to the * file could put it over Cflag. */ - 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); + if (Cflag != 0) { + long size = pcap_dump_ftell(dump_info->p); - /* - * Compress the file we just closed, if the user asked for it - */ - if (zflag != NULL) - compress_savefile(dump_info->CurrentFileName); + if (size == -1) + error("ftell fails on output file"); + if (size > Cflag) { +#ifdef HAVE_CAPSICUM + FILE *fp; + int fd; +#endif + + /* + * 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); - Cflag_count++; - if (Wflag > 0) { - if (Cflag_count >= Wflag) - Cflag_count = 0; + 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(PATH_MAX + 1); + if (dump_info->CurrentFileName == NULL) + error("dump_packet_and_trunc: malloc"); + MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars); +#ifdef HAVE_LIBCAP_NG + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ +#ifdef HAVE_CAPSICUM + fd = openat(dump_info->dirfd, dump_info->CurrentFileName, + O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd < 0) { + error("unable to open file %s", + dump_info->CurrentFileName); + } + fp = fdopen(fd, "w"); + if (fp == NULL) { + error("unable to fdopen file %s", + dump_info->CurrentFileName); + } + dump_info->p = pcap_dump_fopen(dump_info->pd, fp); +#else /* !HAVE_CAPSICUM */ + dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName); +#endif +#ifdef HAVE_LIBCAP_NG + capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE); + capng_apply(CAPNG_SELECT_BOTH); +#endif /* HAVE_LIBCAP_NG */ + if (dump_info->p == NULL) + error("%s", pcap_geterr(pd)); +#ifdef HAVE_CAPSICUM + set_dumper_capsicum_rights(dump_info->p); +#endif } - if (dump_info->CurrentFileName != NULL) - free(dump_info->CurrentFileName); - dump_info->CurrentFileName = (char *)malloc(PATH_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)); } pcap_dump((u_char *)dump_info->p, h, sp); @@ -1969,15 +2445,20 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) ++packets_captured; ++infodelay; - ts_print(&h->ts); print_info = (struct print_info *)user; ndo = print_info->ndo; + if(ndo->ndo_packet_number) + ND_PRINT((ndo, "%5u ", packets_captured)); + + ts_print(ndo, &h->ts); + /* * Some printers want to check that they're not walking off the * end of the packet. - * Rather than pass it all the way down, we set this global. + * Rather than pass it all the way down, we set this member + * of the netdissect_options structure. */ ndo->ndo_snapend = sp + h->caplen; @@ -1987,6 +2468,11 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) hdrlen = (*print_info->p.printer)(h, sp); } + /* + * Restore the original snapend, as a printer might have + * changed it. + */ + ndo->ndo_snapend = sp + h->caplen; if (ndo->ndo_Xflag) { /* * Print the raw packet data in hex and ASCII. @@ -1995,7 +2481,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) /* * Include the link-layer header. */ - hex_and_ascii_print("\n\t", sp, h->caplen); + hex_and_ascii_print(ndo, "\n\t", sp, h->caplen); } else { /* * Don't include the link-layer header - and if @@ -2003,7 +2489,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) * print nothing. */ if (h->caplen > hdrlen) - hex_and_ascii_print("\n\t", sp + hdrlen, + hex_and_ascii_print(ndo, "\n\t", sp + hdrlen, h->caplen - hdrlen); } } else if (ndo->ndo_xflag) { @@ -2033,7 +2519,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) /* * Include the link-layer header. */ - ascii_print(sp, h->caplen); + ascii_print(ndo, sp, h->caplen); } else { /* * Don't include the link-layer header - and if @@ -2041,7 +2527,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) * print nothing. */ if (h->caplen > hdrlen) - ascii_print(sp + hdrlen, h->caplen - hdrlen); + ascii_print(ndo, sp + hdrlen, h->caplen - hdrlen); } } @@ -2052,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 @@ -2083,9 +2569,9 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) * 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) +ndo_default_print(netdissect_options *ndo, const u_char *bp, u_int length) { - hex_and_ascii_print("\n\t", bp, length); /* pass on lf and identation string */ + hex_and_ascii_print(ndo, "\n\t", bp, length); /* pass on lf and indentation string */ } void @@ -2127,51 +2613,75 @@ static void verbose_stats_dump(int sig _U_) } #endif +USES_APPLE_DEPRECATED_API static void -usage(void) +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) + (void)fprintf (stderr, "%s\n", SSLeay_version(SSLEAY_VERSION)); +#endif + +#ifdef USE_LIBSMI + (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string); +#endif +} +USES_APPLE_RST + +static void +print_usage(void) +{ + print_version(); (void)fprintf(stderr, -"Usage: %s [-aAbd" D_FLAG "efhH" 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"); +"\t\t[ -i interface ]" j_FLAG_USAGE " [ -M secret ] [ --number ]\n"); #ifdef HAVE_PCAP_SETDIRECTION (void)fprintf(stderr, "\t\t[ -Q in|out|inout ]\n"); #endif (void)fprintf(stderr, -"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -V file ] [ -w file ]\n"); +"\t\t[ -r file ] [ -s snaplen ] "); +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION + (void)fprintf(stderr, "[ --time-stamp-precision precision ]\n"); + (void)fprintf(stderr, +"\t\t"); +#endif +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + (void)fprintf(stderr, "[ --immediate-mode ] "); +#endif + (void)fprintf(stderr, "[ -T type ] [ --version ] [ -V file ]\n"); (void)fprintf(stderr, -"\t\t[ -W filecount ] [ -y datalinktype ] [ -z command ]\n"); +"\t\t[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z command ]\n"); (void)fprintf(stderr, "\t\t[ -Z user ] [ expression ]\n"); - exit(1); }