X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/91e08f888d86fc7bc83732ee216c4ea609691d1c..eedd51f5528535b2914e3f089db1aed0b642cda4:/tcpdump.c diff --git a/tcpdump.c b/tcpdump.c index be14145f..22fcf96f 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -44,9 +44,10 @@ The Regents of the University of California. All rights reserved.\n"; #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(). + * Some older versions of 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 @@ -62,10 +63,6 @@ The Regents of the University of California. All rights reserved.\n"; #include #endif -#ifdef USE_LIBSMI -#include -#endif - #ifdef HAVE_LIBCRYPTO #include #endif @@ -84,7 +81,15 @@ The Regents of the University of California. All rights reserved.\n"; #include #include #include +#ifdef HAVE_CASPER +#include +#include +#include +#endif /* HAVE_CASPER */ #endif /* HAVE_CAPSICUM */ +#ifdef HAVE_PCAP_OPEN +#define HAVE_REMOTE +#endif #include #include #include @@ -112,11 +117,14 @@ The Regents of the University of California. All rights reserved.\n"; #endif /* HAVE_CAP_NG_H */ #endif /* HAVE_LIBCAP_NG */ +#ifdef __FreeBSD__ +#include +#endif /* __FreeBSD__ */ + #include "netdissect.h" #include "interface.h" #include "addrtoname.h" #include "machdep.h" -#include "setsignal.h" #include "gmt2local.h" #include "pcap-missing.h" #include "ascii_strcasecmp.h" @@ -133,9 +141,20 @@ The Regents of the University of California. All rights reserved.\n"; #define SIGNAL_REQ_INFO SIGUSR1 #endif -static int Cflag; /* rotate dump files after this many bytes */ +static int Bflag; /* buffer size */ +#ifdef HAVE_PCAP_DUMP_FTELL64 +static int64_t Cflag; /* rotate dump files after this many bytes */ +#else +static long Cflag; /* rotate dump files after this many bytes */ +#endif static int Cflag_count; /* Keep track of which file number we're writing */ +#ifdef HAVE_PCAP_FINDALLDEVS static int Dflag; /* list available devices and exit */ +#endif +#ifdef HAVE_PCAP_FINDALLDEVS_EX +static char *remote_interfaces_source; /* list available devices from this source and exit */ +#endif + /* * This is exported because, in some versions of libpcap, if libpcap * is built with optimizer debugging code (which is *NOT* the default @@ -157,38 +176,43 @@ static int Iflag; /* rfmon (monitor) mode */ #ifdef HAVE_PCAP_SET_TSTAMP_TYPE static int Jflag; /* list available time stamp types */ #endif +static int jflag = -1; /* packet time stamp source */ +static int pflag; /* don't go promiscuous */ #ifdef HAVE_PCAP_SETDIRECTION -int Qflag = -1; /* restrict captured packet by send/receive direction */ +static int Qflag = -1; /* restrict captured packet by send/receive direction */ #endif static int Uflag; /* "unbuffered" output of dump files */ static int Wflag; /* recycle output files after this number of files */ static int WflagChars; static char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */ +static int immediate_mode; static int infodelay; static int infoprint; char *program_name; +#ifdef HAVE_CASPER +cap_channel_t *capdns; +#endif + /* Forwards */ -static void error(const char *, ...) - __attribute__((noreturn)) -#ifdef __ATTRIBUTE___FORMAT_OK - __attribute__((format (printf, 1, 2))) -#endif /* __ATTRIBUTE___FORMAT_OK */ - ; -static void warning(const char *, ...) -#ifdef __ATTRIBUTE___FORMAT_OK - __attribute__((format (printf, 1, 2))) -#endif /* __ATTRIBUTE___FORMAT_OK */ - ; -static void exit_tcpdump(int) __attribute__((noreturn)); -static RETSIGTYPE cleanup(int); -static RETSIGTYPE child_cleanup(int); +static NORETURN void error(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); +static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); +static NORETURN void exit_tcpdump(int); +static void (*setsignal (int sig, void (*func)(int)))(int); +static void cleanup(int); +static void child_cleanup(int); static void print_version(void); static void print_usage(void); -static void show_tstamp_types_and_exit(const char *device) __attribute__((noreturn)); -static void show_dlts_and_exit(const char *device) __attribute__((noreturn)); +static NORETURN void show_tstamp_types_and_exit(pcap_t *, const char *device); +static NORETURN void show_dlts_and_exit(pcap_t *, const char *device); +#ifdef HAVE_PCAP_FINDALLDEVS +static NORETURN void show_devices_and_exit(void); +#endif +#ifdef HAVE_PCAP_FINDALLDEVS_EX +static NORETURN void show_remote_devices_and_exit(void); +#endif static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *); @@ -196,20 +220,21 @@ static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void droproot(const char *, const char *); #ifdef SIGNAL_REQ_INFO -RETSIGTYPE requestinfo(int); +void 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) +#ifdef _WIN32 + #include + static UINT timer_id; + static void CALLBACK verbose_stats_dump(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR); +#else /* _WIN32 */ static void verbose_stats_dump(int sig); -#endif +#endif /* _WIN32 */ static void info(int); static u_int packets_captured; +#ifdef HAVE_PCAP_FINDALLDEVS static const struct tok status_flags[] = { #ifdef PCAP_IF_UP { PCAP_IF_UP, "Up" }, @@ -220,6 +245,7 @@ static const struct tok status_flags[] = { { PCAP_IF_LOOPBACK, "Loopback" }, { 0, NULL } }; +#endif static pcap_t *pd; @@ -234,6 +260,7 @@ struct dump_info { char *CurrentFileName; pcap_t *pd; pcap_dumper_t *p; + netdissect_options *ndo; #ifdef HAVE_CAPSICUM int dirfd; #endif @@ -335,16 +362,16 @@ exit_tcpdump(int status) #ifdef HAVE_PCAP_SET_TSTAMP_TYPE static void -show_tstamp_types_and_exit(const char *device) +show_tstamp_types_and_exit(pcap_t *pc, const char *device) { 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); + n_tstamp_types = pcap_list_tstamp_types(pc, &tstamp_types); if (n_tstamp_types < 0) - error("%s", pcap_geterr(pd)); + error("%s", pcap_geterr(pc)); if (n_tstamp_types == 0) { fprintf(stderr, "Time stamp type cannot be set for %s\n", @@ -368,15 +395,15 @@ show_tstamp_types_and_exit(const char *device) #endif static void -show_dlts_and_exit(const char *device) +show_dlts_and_exit(pcap_t *pc, const char *device) { int n_dlts, i; int *dlts = 0; const char *dlt_name; - n_dlts = pcap_list_datalinks(pd, &dlts); + n_dlts = pcap_list_datalinks(pc, &dlts); if (n_dlts < 0) - error("%s", pcap_geterr(pd)); + error("%s", pcap_geterr(pc)); else if (n_dlts == 0 || !dlts) error("No data link types."); @@ -421,7 +448,7 @@ show_dlts_and_exit(const char *device) #ifdef HAVE_PCAP_FINDALLDEVS static void -show_devices_and_exit (void) +show_devices_and_exit(void) { pcap_if_t *dev, *devlist; char ebuf[PCAP_ERRBUF_SIZE]; @@ -442,6 +469,30 @@ show_devices_and_exit (void) } #endif /* HAVE_PCAP_FINDALLDEVS */ +#ifdef HAVE_PCAP_FINDALLDEVS_EX +static void +show_remote_devices_and_exit(void) +{ + pcap_if_t *dev, *devlist; + char ebuf[PCAP_ERRBUF_SIZE]; + int i; + + if (pcap_findalldevs_ex(remote_interfaces_source, NULL, &devlist, + ebuf) < 0) + error("%s", ebuf); + for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) { + printf("%d.%s", i+1, dev->name); + if (dev->description != NULL) + printf(" (%s)", dev->description); + if (dev->flags != 0) + printf(" [%s]", bittok2str(status_flags, "none", dev->flags)); + printf("\n"); + } + pcap_freealldevs(devlist); + exit_tcpdump(0); +} +#endif /* HAVE_PCAP_FINDALLDEVS */ + /* * Short options. * @@ -453,7 +504,7 @@ show_devices_and_exit (void) * 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 + * OS X tcpdump uses -k to specify that packet comments in pcap-ng files * should be printed; * * OpenBSD tcpdump uses -o to indicate that OS fingerprinting should be done @@ -484,6 +535,12 @@ show_devices_and_exit (void) #define B_FLAG_USAGE #endif /* defined(HAVE_PCAP_CREATE) || defined(_WIN32) */ +#ifdef HAVE_PCAP_FINDALLDEVS +#define D_FLAG "D" +#else +#define D_FLAG +#endif + #ifdef HAVE_PCAP_CREATE #define I_FLAG "I" #else /* HAVE_PCAP_CREATE */ @@ -500,10 +557,12 @@ show_devices_and_exit (void) #define J_FLAG #endif /* PCAP_ERROR_TSTAMP_TYPE_NOTSUP */ -#ifdef HAVE_PCAP_FINDALLDEVS -#define D_FLAG "D" +#ifdef HAVE_PCAP_SETDIRECTION +#define Q_FLAG "Q:" +#define Q_FLAG_USAGE " [ -Q in|out|inout ]" #else -#define D_FLAG +#define Q_FLAG +#define Q_FLAG_USAGE #endif #ifdef HAVE_PCAP_DUMP_FLUSH @@ -512,12 +571,6 @@ show_devices_and_exit (void) #define U_FLAG #endif -#ifdef HAVE_PCAP_SETDIRECTION -#define Q_FLAG "Q:" -#else -#define Q_FLAG -#endif - #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:s:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#" /* @@ -540,15 +593,20 @@ show_devices_and_exit (void) * 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 +#define OPTION_VERSION 128 +#define OPTION_TSTAMP_PRECISION 129 +#define OPTION_IMMEDIATE_MODE 130 +#define OPTION_PRINT 131 +#define OPTION_LIST_REMOTE_INTERFACES 132 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' }, +#ifdef HAVE_PCAP_FINDALLDEVS_EX + { "list-remote-interfaces", required_argument, NULL, OPTION_LIST_REMOTE_INTERFACES }, +#endif { "help", no_argument, NULL, 'h' }, { "interface", required_argument, NULL, 'i' }, #ifdef HAVE_PCAP_CREATE @@ -582,10 +640,29 @@ static const struct option longopts[] = { #endif { "relinquish-privileges", required_argument, NULL, 'Z' }, { "number", no_argument, NULL, '#' }, + { "print", no_argument, NULL, OPTION_PRINT }, { "version", no_argument, NULL, OPTION_VERSION }, { NULL, 0, NULL, 0 } }; +#ifdef HAVE_PCAP_FINDALLDEVS_EX +#define LIST_REMOTE_INTERFACES_USAGE "[ --list-remote-interfaces remote-source ]" +#else +#define LIST_REMOTE_INTERFACES_USAGE +#endif + +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE +#define IMMEDIATE_MODE_USAGE " [ --immediate-mode ]" +#else +#define IMMEDIATE_MODE_USAGE "" +#endif + +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION +#define TIME_STAMP_PRECISION_USAGE " [ --time-stamp-precision precision ]" +#else +#define TIME_STAMP_PRECISION_USAGE +#endif + #ifndef _WIN32 /* Drop root privileges and chroot if necessary */ static void @@ -638,13 +715,16 @@ droproot(const char *username, const char *chroot_dir) exit_tcpdump(1); } #ifdef HAVE_LIBCAP_NG - /* We don't need CAP_SETUID and CAP_SETGID any more. */ + /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */ +DIAG_OFF_CLANG(assign-enum) capng_updatev( CAPNG_DROP, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_SETUID, CAP_SETGID, + CAP_SYS_CHROOT, -1); +DIAG_ON_CLANG(assign-enum) capng_apply(CAPNG_SELECT_BOTH); #endif /* HAVE_LIBCAP_NG */ @@ -714,6 +794,35 @@ get_next_file(FILE *VFile, char *ptr) return ret; } +#ifdef HAVE_CASPER +static cap_channel_t * +capdns_setup(void) +{ + cap_channel_t *capcas, *capdnsloc; + const char *types[1]; + int families[2]; + + capcas = cap_init(); + if (capcas == NULL) + error("unable to create casper process"); + capdnsloc = cap_service_open(capcas, "system.dns"); + /* Casper capability no longer needed. */ + cap_close(capcas); + if (capdnsloc == NULL) + error("unable to open system.dns service"); + /* Limit system.dns to reverse DNS lookups. */ + types[0] = "ADDR"; + if (cap_dns_type_limit(capdnsloc, types, 1) < 0) + error("unable to limit access to system.dns service"); + families[0] = AF_INET; + families[1] = AF_INET6; + if (cap_dns_family_limit(capdnsloc, families, 2) < 0) + error("unable to limit access to system.dns service"); + + return (capdnsloc); +} +#endif /* HAVE_CASPER */ + #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION static int tstamp_precision_from_string(const char *precision) @@ -826,7 +935,7 @@ copy_argv(register char **argv) char *src, *dst; p = argv; - if (*p == 0) + if (*p == NULL) return 0; while (*p) @@ -893,19 +1002,295 @@ read_infile(char *fname) return (cp); } +#ifdef HAVE_PCAP_FINDALLDEVS +static long +parse_interface_number(const char *device) +{ + long devnum; + char *end; + + devnum = strtol(device, &end, 10); + if (device != end && *end == '\0') { + /* + * It's all-numeric, but is it a valid number? + */ + if (devnum <= 0) { + /* + * No, it's not an ordinal. + */ + error("Invalid adapter index"); + } + return (devnum); + } else { + /* + * It's not all-numeric; return -1, so our caller + * knows that. + */ + return (-1); + } +} + +static char * +find_interface_by_number(long devnum) +{ + pcap_if_t *dev, *devlist; + long i; + char ebuf[PCAP_ERRBUF_SIZE]; + char *device; + + if (pcap_findalldevs(&devlist, ebuf) < 0) + error("%s", ebuf); + /* + * Look for the devnum-th entry in the list of devices (1-based). + */ + for (i = 0, dev = devlist; i < devnum-1 && dev != NULL; + i++, dev = dev->next) + ; + if (dev == NULL) + error("Invalid adapter index"); + device = strdup(dev->name); + pcap_freealldevs(devlist); + return (device); +} +#endif + +#ifdef HAVE_PCAP_OPEN +/* + * Prefix for rpcap URLs. + */ +static char rpcap_prefix[] = "rpcap://"; +#endif + +static pcap_t * +open_interface(const char *device, netdissect_options *ndo, char *ebuf) +{ + pcap_t *pc; +#ifdef HAVE_PCAP_CREATE + int status; + char *cp; +#endif + +#ifdef HAVE_PCAP_OPEN + /* + * Is this an rpcap URL? + */ + if (strncmp(device, rpcap_prefix, sizeof(rpcap_prefix) - 1) == 0) { + /* + * Yes. Open it with pcap_open(). + */ + *ebuf = '\0'; +fprintf(stderr, "Opening %s\n", device); + pc = pcap_open(device, ndo->ndo_snaplen, + pflag ? 0 : PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, + ebuf); + if (pc == NULL) { + /* + * If this failed with "No such device", that means + * the interface doesn't exist; return NULL, so that + * the caller can see whether the device name is + * actually an interface index. + */ + if (strstr(ebuf, "No such device") != NULL) + return (NULL); + error("%s", ebuf); + } + if (*ebuf) + warning("%s", ebuf); + return (pc); + } +#endif /* HAVE_PCAP_OPEN */ + +#ifdef HAVE_PCAP_CREATE + pc = pcap_create(device, ebuf); + if (pc == NULL) { + /* + * If this failed with "No such device", that means + * the interface doesn't exist; return NULL, so that + * the caller can see whether the device name is + * actually an interface index. + */ + if (strstr(ebuf, "No such device") != NULL) + return (NULL); + error("%s", ebuf); + } +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + if (Jflag) + show_tstamp_types_and_exit(pc, device); +#endif +#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION + status = pcap_set_tstamp_precision(pc, ndo->ndo_tstamp_precision); + if (status != 0) + error("%s: Can't set %ssecond time stamp precision: %s", + device, + tstamp_precision_to_string(ndo->ndo_tstamp_precision), + pcap_statustostr(status)); +#endif + +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + if (immediate_mode) { + status = pcap_set_immediate_mode(pc, 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? + */ + if (pcap_can_set_rfmon(pc) == 1) + supports_monitor_mode = 1; + else + supports_monitor_mode = 0; + if (ndo->ndo_snaplen != 0) { + /* + * A snapshot length was explicitly specified; + * use it. + */ + status = pcap_set_snaplen(pc, ndo->ndo_snaplen); + if (status != 0) + error("%s: Can't set snapshot length: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_promisc(pc, !pflag); + if (status != 0) + error("%s: Can't set promiscuous mode: %s", + device, pcap_statustostr(status)); + if (Iflag) { + status = pcap_set_rfmon(pc, 1); + if (status != 0) + error("%s: Can't set monitor mode: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pc, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + if (Bflag != 0) { + status = pcap_set_buffer_size(pc, 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(pc, jflag); + if (status < 0) + error("%s: Can't set time stamp type: %s", + device, pcap_statustostr(status)); + } +#endif + status = pcap_activate(pc); + if (status < 0) { + /* + * pcap_activate() failed. + */ + cp = pcap_geterr(pc); + if (status == PCAP_ERROR) + error("%s", cp); + else if (status == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * Return an error for our caller to handle. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)", + device, pcap_statustostr(status), cp); + pcap_close(pc); + return (NULL); + } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0') + error("%s: %s\n(%s)", device, + pcap_statustostr(status), cp); +#ifdef __FreeBSD__ + else if (status == PCAP_ERROR_RFMON_NOTSUP && + strncmp(device, "wlan", 4) == 0) { + char parent[8], newdev[8]; + char sysctl[32]; + size_t s = sizeof(parent); + + snprintf(sysctl, sizeof(sysctl), + "net.wlan.%d.%%parent", atoi(device + 4)); + sysctlbyname(sysctl, parent, &s, NULL, 0); + strlcpy(newdev, device, sizeof(newdev)); + /* Suggest a new wlan device. */ + /* FIXME: incrementing the index this way is not going to work well + * when the index is 9 or greater but the only consequence in this + * specific case would be an error message that looks a bit odd. + */ + newdev[strlen(newdev)-1]++; + error("%s is not a monitor mode VAP\n" + "To create a new monitor mode VAP use:\n" + " ifconfig %s create wlandev %s wlanmode monitor\n" + "and use %s as the tcpdump interface", + device, newdev, parent, newdev); + } +#endif + 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(pc); + 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)); + } +#ifdef HAVE_PCAP_SETDIRECTION + if (Qflag != -1) { + status = pcap_setdirection(pc, Qflag); + if (status != 0) + error("%s: pcap_setdirection() failed: %s", + device, pcap_geterr(pc)); + } +#endif /* HAVE_PCAP_SETDIRECTION */ +#else /* HAVE_PCAP_CREATE */ + *ebuf = '\0'; + /* + * If no snapshot length was specified, or a length of 0 was + * specified, default to 256KB. + */ + if (ndo->ndo_snaplen == 0) + ndo->ndo_snaplen = 262144; + pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, 1000, ebuf); + if (pc == NULL) { + /* + * If this failed with "No such device", that means + * the interface doesn't exist; return NULL, so that + * the caller can see whether the device name is + * actually an interface index. + */ + if (strstr(ebuf, "No such device") != NULL) + return (NULL); + error("%s", ebuf); + } + if (*ebuf) + warning("%s", ebuf); +#endif /* HAVE_PCAP_CREATE */ + + return (pc); +} + int main(int argc, char **argv) { register int cnt, op, i; - bpf_u_int32 localnet =0 , netmask = 0; + bpf_u_int32 localnet = 0, netmask = 0; int timezone_offset = 0; register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName; + char *endp; pcap_handler callback; int dlt; const char *dlt_name; struct bpf_program fcode; #ifndef _WIN32 - RETSIGTYPE (*oldhandler)(int); + void (*oldhandler)(int); #endif struct dump_info dumpinfo; u_char *pcap_userdata; @@ -916,8 +1301,8 @@ main(int argc, char **argv) char *ret = NULL; char *end; #ifdef HAVE_PCAP_FINDALLDEVS - pcap_if_t *dev, *devlist; - int devnum; + pcap_if_t *devlist; + long devnum; #endif int status; FILE *VFile; @@ -925,16 +1310,13 @@ main(int argc, char **argv) cap_rights_t rights; int cansandbox; #endif /* HAVE_CAPSICUM */ - int Bflag = 0; /* buffer size */ - int jflag = -1; /* packet time stamp source */ int Oflag = 1; /* run filter code optimizer */ - int pflag = 0; /* don't go promiscuous */ int yflag_dlt = -1; const char *yflag_dlt_name = NULL; + int print = 0; netdissect_options Ndo; netdissect_options *ndo = &Ndo; - int immediate_mode = 0; /* * Initialize the netdissect code. @@ -944,7 +1326,6 @@ main(int argc, char **argv) memset(ndo, 0, sizeof(*ndo)); ndo_set_function_pointers(ndo); - ndo->ndo_snaplen = DEFAULT_SNAPLEN; cnt = -1; device = NULL; @@ -1005,18 +1386,42 @@ main(int argc, char **argv) break; case 'C': - Cflag = atoi(optarg) * 1000000; - if (Cflag <= 0) + errno = 0; +#ifdef HAVE_PCAP_DUMP_FTELL64 + Cflag = strtoint64_t(optarg, &endp, 10); +#else + Cflag = strtol(optarg, &endp, 10); +#endif + if (endp == optarg || *endp != '\0' || errno != 0 + || Cflag <= 0) error("invalid file size %s", optarg); + /* + * Will multiplying it by 1000000 overflow? + */ +#ifdef HAVE_PCAP_DUMP_FTELL64 + if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffff) / 1000000) +#else + if (Cflag > LONG_MAX / 1000000) +#endif + error("file size %s is too large", optarg); + Cflag *= 1000000; break; case 'd': ++dflag; break; +#ifdef HAVE_PCAP_FINDALLDEVS case 'D': Dflag++; break; +#endif + +#ifdef HAVE_PCAP_FINDALLDEVS_EX + case OPTION_LIST_REMOTE_INTERFACES: + remote_interfaces_source = optarg; + break; +#endif case 'L': Lflag++; @@ -1066,42 +1471,6 @@ main(int argc, char **argv) break; case 'i': - if (optarg[0] == '0' && optarg[1] == 0) - error("Invalid adapter index"); - -#ifdef HAVE_PCAP_FINDALLDEVS - /* - * If the argument is a number, treat it as - * an index into the list of adapters, as - * printed by "tcpdump -D". - * - * This should be OK on UNIX systems, as interfaces - * shouldn't have names that begin with digits. - * It can be useful on Windows, where more than - * one interface can have the same name. - */ - devnum = strtol(optarg, &end, 10); - if (optarg != end && *end == '\0') { - if (devnum < 0) - error("Invalid adapter index"); - - if (pcap_findalldevs(&devlist, ebuf) < 0) - error("%s", ebuf); - /* - * Look for the devnum-th entry in the - * list of devices (1-based). - */ - for (i = 0, dev = devlist; - i < devnum-1 && dev != NULL; - i++, dev = dev->next) - ; - if (dev == NULL) - error("Invalid adapter index"); - device = strdup(dev->name); - pcap_freealldevs(devlist); - break; - } -#endif /* HAVE_PCAP_FINDALLDEVS */ device = optarg; break; @@ -1149,16 +1518,14 @@ main(int argc, char **argv) break; case 'm': -#ifdef USE_LIBSMI - if (smiLoadModule(optarg) == 0) { - error("could not load MIB module %s", optarg); + if (nd_have_smi_support()) { + if (nd_load_smi_module(optarg, ebuf, sizeof ebuf) == -1) + error("%s", ebuf); + } else { + (void)fprintf(stderr, "%s: ignoring option `-m %s' ", + program_name, optarg); + (void)fprintf(stderr, "(no libsmi support)\n"); } - ndo->ndo_mflag = 1; -#else - (void)fprintf(stderr, "%s: ignoring option `-m %s' ", - program_name, optarg); - (void)fprintf(stderr, "(no libsmi support)\n"); -#endif break; case 'M': @@ -1212,8 +1579,6 @@ main(int argc, char **argv) if (optarg == end || *end != '\0' || ndo->ndo_snaplen < 0 || ndo->ndo_snaplen > MAXIMUM_SNAPLEN) error("invalid snaplen %s", optarg); - else if (ndo->ndo_snaplen == 0) - ndo->ndo_snaplen = MAXIMUM_SNAPLEN; break; case 'S': @@ -1349,6 +1714,10 @@ main(int argc, char **argv) break; #endif + case OPTION_PRINT: + print = 1; + break; + default: print_usage(); exit_tcpdump(1); @@ -1359,6 +1728,10 @@ main(int argc, char **argv) if (Dflag) show_devices_and_exit(); #endif +#ifdef HAVE_PCAP_FINDALLDEVS_EX + if (remote_interfaces_source != NULL) + show_remote_devices_and_exit(); +#endif switch (ndo->ndo_tflag) { @@ -1387,11 +1760,14 @@ main(int argc, char **argv) #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. + * and the standard output is a terminal, use immediate mode, + * as the user's probably expecting to see packets pop up + * immediately. + * + * XXX - set the timeout to a lower value, instead? If so, + * what value would be appropriate? */ - if (WFileName == NULL && isatty(1)) + if ((WFileName == NULL || print) && isatty(1)) immediate_mode = 1; #endif @@ -1483,150 +1859,77 @@ main(int argc, char **argv) * We're doing a live capture. */ if (device == NULL) { + /* + * No interface was specified. Pick one. + */ #ifdef HAVE_PCAP_FINDALLDEVS - if (pcap_findalldevs(&devlist, ebuf) >= 0 && - devlist != NULL) { - device = strdup(devlist->name); - pcap_freealldevs(devlist); - } + /* + * Find the list of interfaces, and pick + * the first interface. + */ + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); #else /* HAVE_PCAP_FINDALLDEVS */ + /* + * Use whatever interface pcap_lookupdev() + * chooses. + */ device = pcap_lookupdev(ebuf); -#endif if (device == NULL) error("%s", ebuf); - } -#ifdef _WIN32 - /* - * Print a message to the standard error on Windows. - * XXX - why do it here, with a different message? - */ - 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 - { - fprintf(stderr, "%s: listening on %s\n", program_name, device); - } - - 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); -#endif -#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION - status = pcap_set_tstamp_precision(pd, ndo->ndo_tstamp_precision); - if (status != 0) - error("%s: Can't set %ssecond time stamp precision: %s", - device, - tstamp_precision_to_string(ndo->ndo_tstamp_precision), - pcap_statustostr(status)); #endif - -#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE - if (immediate_mode) { - 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? + * Try to open the interface with the specified name. */ - if (pcap_can_set_rfmon(pd) == 1) - supports_monitor_mode = 1; - else - supports_monitor_mode = 0; - status = pcap_set_snaplen(pd, ndo->ndo_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) { + pd = open_interface(device, ndo, ebuf); + if (pd == NULL) { /* - * pcap_activate() failed. + * That failed. If we can get a list of + * interfaces, and the interface name + * is purely numeric, try to use it as + * a 1-based index in the list of + * interfaces. */ - 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) { +#ifdef HAVE_PCAP_FINDALLDEVS + devnum = parse_interface_number(device); + if (devnum == -1) { + /* + * It's not a number; just report + * the open error and fail. + */ + error("%s", ebuf); + } + /* - * pcap_activate() succeeded, but it's warning us - * of a problem it had. + * OK, it's a number; try to find the + * interface with that index, and try + * to open it. + * + * find_interface_by_number() exits if it + * couldn't be found. + */ + device = find_interface_by_number(devnum); + pd = open_interface(device, ndo, ebuf); + if (pd == NULL) + error("%s", ebuf); +#else /* HAVE_PCAP_FINDALLDEVS */ + /* + * We can't get a list of interfaces; just + * fail. */ - 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)); - } -#ifdef HAVE_PCAP_SETDIRECTION - if (Qflag != -1) { - status = pcap_setdirection(pd, Qflag); - if (status != 0) - error("%s: pcap_setdirection() failed: %s", - device, pcap_geterr(pd)); - } -#endif /* HAVE_PCAP_SETDIRECTION */ -#else - *ebuf = '\0'; - pd = pcap_open_live(device, ndo->ndo_snaplen, !pflag, 1000, - ebuf); - if (pd == NULL) error("%s", ebuf); - else if (*ebuf) - warning("%s", ebuf); -#endif /* HAVE_PCAP_CREATE */ +#endif /* HAVE_PCAP_FINDALLDEVS */ + } + /* - * Let user own process after socket has been opened. + * Let user own process after capture device has + * been opened. */ #ifndef _WIN32 if (setgid(getgid()) != 0 || setuid(getuid()) != 0) @@ -1639,7 +1942,7 @@ main(int argc, char **argv) } #endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */ if (Lflag) - show_dlts_and_exit(device); + show_dlts_and_exit(pd, device); if (yflag_dlt >= 0) { #ifdef HAVE_PCAP_SET_DATALINK if (pcap_set_datalink(pd, yflag_dlt) < 0) @@ -1661,7 +1964,11 @@ main(int argc, char **argv) } i = pcap_snapshot(pd); if (ndo->ndo_snaplen < i) { - warning("snaplen raised from %d to %d", ndo->ndo_snaplen, i); + if (ndo->ndo_snaplen != 0) + warning("snaplen raised from %d to %d", ndo->ndo_snaplen, i); + ndo->ndo_snaplen = i; + } else if (ndo->ndo_snaplen > i) { + warning("snaplen lowered from %d to %d", ndo->ndo_snaplen, i); ndo->ndo_snaplen = i; } if(ndo->ndo_fflag != 0) { @@ -1688,13 +1995,19 @@ main(int argc, char **argv) pcap_freecode(&fcode); exit_tcpdump(0); } + +#ifdef HAVE_CASPER + if (!ndo->ndo_nflag) + capdns = capdns_setup(); +#endif /* HAVE_CASPER */ + init_print(ndo, localnet, netmask, timezone_offset); #ifndef _WIN32 (void)setsignal(SIGPIPE, cleanup); (void)setsignal(SIGTERM, cleanup); - (void)setsignal(SIGINT, cleanup); #endif /* _WIN32 */ + (void)setsignal(SIGINT, cleanup); #if defined(HAVE_FORK) || defined(HAVE_VFORK) (void)setsignal(SIGCHLD, child_cleanup); #endif @@ -1728,20 +2041,33 @@ main(int argc, char **argv) /* Initialize capng */ capng_clear(CAPNG_SELECT_BOTH); if (username) { +DIAG_OFF_CLANG(assign-enum) capng_updatev( CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, CAP_SETUID, CAP_SETGID, -1); +DIAG_ON_CLANG(assign-enum) + } + if (chroot_dir) { +DIAG_OFF_CLANG(assign-enum) + capng_update( + CAPNG_ADD, + CAPNG_PERMITTED | CAPNG_EFFECTIVE, + CAP_SYS_CHROOT + ); +DIAG_ON_CLANG(assign-enum) } if (WFileName) { +DIAG_OFF_CLANG(assign-enum) capng_update( CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE ); +DIAG_ON_CLANG(assign-enum) } capng_apply(CAPNG_SELECT_BOTH); #endif /* HAVE_LIBCAP_NG */ @@ -1757,7 +2083,12 @@ main(int argc, char **argv) if (RFileName == NULL && VFileName == NULL) { static const unsigned long cmds[] = { BIOCGSTATS, BIOCROTZBUF }; - cap_rights_init(&rights, CAP_IOCTL, CAP_READ); + /* + * The various libpcap devices use a combination of + * read (bpf), ioctl (bpf, netmap), poll (netmap) + * so we add the relevant access rights. + */ + cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_EVENT); if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 && errno != ENOSYS) { error("unable to limit pcap descriptor"); @@ -1833,8 +2164,18 @@ main(int argc, char **argv) pcap_userdata = (u_char *)&dumpinfo; } else { callback = dump_packet; - pcap_userdata = (u_char *)p; + dumpinfo.WFileName = WFileName; + dumpinfo.pd = pd; + dumpinfo.p = p; + pcap_userdata = (u_char *)&dumpinfo; } + if (print) { + dlt = pcap_datalink(pd); + ndo->ndo_if_printer = get_if_printer(ndo, dlt); + dumpinfo.ndo = ndo; + } else + dumpinfo.ndo = NULL; + #ifdef HAVE_PCAP_DUMP_FLUSH if (Uflag) pcap_dump_flush(p); @@ -1855,23 +2196,23 @@ main(int argc, char **argv) (void)setsignal(SIGNAL_REQ_INFO, requestinfo); #endif - if (ndo->ndo_vflag > 0 && WFileName) { + if (ndo->ndo_vflag > 0 && WFileName && !print) { /* - * When capturing to a file, "-v" means tcpdump should, - * every 10 seconds, "v"erbosely report the number of - * packets captured. + * When capturing to a file, if "--print" wasn't specified, + *"-v" means tcpdump should, once per second, + * "v"erbosely report the number of packets captured. */ -#ifdef USE_WIN32_MM_TIMER +#ifdef _WIN32 /* 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) +#else /* _WIN32 */ + /* UN*X has alarm() */ (void)setsignal(SIGALRM, verbose_stats_dump); alarm(1); -#endif +#endif /* _WIN32 */ } -#ifndef _WIN32 if (RFileName == NULL) { /* * Live capture (if -V was specified, we set RFileName @@ -1896,10 +2237,14 @@ main(int argc, char **argv) } (void)fflush(stderr); } -#endif /* _WIN32 */ #ifdef HAVE_CAPSICUM - cansandbox = (ndo->ndo_nflag && VFileName == NULL && zflag == NULL); + cansandbox = (VFileName == NULL && zflag == NULL); +#ifdef HAVE_CASPER + cansandbox = (cansandbox && (ndo->ndo_nflag || capdns != NULL)); +#else + cansandbox = (cansandbox && ndo->ndo_nflag); +#endif /* HAVE_CASPER */ if (cansandbox && cap_enter() < 0 && errno != ENOSYS) error("unable to enter the capability mode"); #endif /* HAVE_CAPSICUM */ @@ -2024,17 +2369,38 @@ main(int argc, char **argv) exit_tcpdump(status == -1 ? 1 : 0); } +/* + * Catch a signal. + */ +static void +(*setsignal (int sig, void (*func)(int)))(int) +{ +#ifdef _WIN32 + return (signal(sig, func)); +#else + struct sigaction old, new; + + memset(&new, 0, sizeof(new)); + new.sa_handler = func; + if (sig == SIGCHLD) + new.sa_flags = SA_RESTART; + if (sigaction(sig, &new, &old) < 0) + return (SIG_ERR); + return (old.sa_handler); +#endif +} + /* make a clean exit on interrupts */ -static RETSIGTYPE +static void cleanup(int signo _U_) { -#ifdef USE_WIN32_MM_TIMER +#ifdef _WIN32 if (timer_id) timeKillEvent(timer_id); timer_id = 0; -#elif defined(HAVE_ALARM) +#else /* _WIN32 */ alarm(0); -#endif +#endif /* _WIN32 */ #ifdef HAVE_PCAP_BREAKLOOP /* @@ -2070,7 +2436,7 @@ cleanup(int signo _U_) waiting a child processes to die */ #if defined(HAVE_FORK) || defined(HAVE_VFORK) -static RETSIGTYPE +static void child_cleanup(int signo _U_) { wait(NULL); @@ -2234,6 +2600,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) { (void)fprintf(stderr, "Maximum file limit reached: %d\n", Wflag); + info(1); exit_tcpdump(0); /* NOTREACHED */ } @@ -2300,7 +2667,17 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s * file could put it over Cflag. */ if (Cflag != 0) { +#ifdef HAVE_PCAP_DUMP_FTELL64 + int64_t size = pcap_dump_ftell64(dump_info->p); +#else + /* + * XXX - this only handles a Cflag value > 2^31-1 on + * LP64 platforms; to handle ILP32 (32-bit UN*X and + * Windows) or LLP64 (64-bit Windows) would require + * a version of libpcap with pcap_dump_ftell64(). + */ long size = pcap_dump_ftell(dump_info->p); +#endif if (size == -1) error("ftell fails on output file"); @@ -2371,6 +2748,9 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s pcap_dump_flush(dump_info->p); #endif + if (dump_info->ndo != NULL) + pretty_print_packet(dump_info->ndo, h, sp, packets_captured); + --infodelay; if (infoprint) info(0); @@ -2379,16 +2759,23 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s static void dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { + struct dump_info *dump_info; + ++packets_captured; ++infodelay; - pcap_dump(user, h, sp); + dump_info = (struct dump_info *)user; + + pcap_dump((u_char *)dump_info->p, h, sp); #ifdef HAVE_PCAP_DUMP_FLUSH if (Uflag) - pcap_dump_flush((pcap_dumper_t *)user); + pcap_dump_flush(dump_info->p); #endif + if (dump_info->ndo != NULL) + pretty_print_packet(dump_info->ndo, h, sp, packets_captured); + --infodelay; if (infoprint) info(0); @@ -2408,35 +2795,8 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) info(0); } -#ifdef _WIN32 - /* - * XXX - there should really be libpcap calls to get the version - * number as a string (the string would be generated from #defines - * at run time, so that it's not generated from string constants - * in the library, as, on many UNIX systems, those constants would - * be statically linked into the application executable image, and - * would thus reflect the version of libpcap on the system on - * which the application was *linked*, not the system on which it's - * *running*. - * - * That routine should be documented, unlike the "version[]" - * string, so that UNIX vendors providing their own libpcaps - * don't omit it (as a couple of vendors have...). - * - * Packet.dll should perhaps also export a routine to return the - * version number of the Packet.dll code, to supply the - * "Wpcap_version" information on Windows. - */ - char WDversion[]="current-git.tcpdump.org"; -#if !defined(HAVE_GENERATED_VERSION) - char version[]="current-git.tcpdump.org"; -#endif - char pcap_version[]="current-git.tcpdump.org"; - char Wpcap_version[]="3.1"; -#endif - #ifdef SIGNAL_REQ_INFO -RETSIGTYPE requestinfo(int signo _U_) +void requestinfo(int signo _U_) { if (infodelay) ++infoprint; @@ -2445,62 +2805,73 @@ RETSIGTYPE requestinfo(int signo _U_) } #endif +static void +print_packets_captured (void) +{ + static u_int prev_packets_captured, first = 1; + + if (infodelay == 0 && (first || packets_captured != prev_packets_captured)) { + fprintf(stderr, "Got %u\r", packets_captured); + first = 0; + prev_packets_captured = packets_captured; + } +} + /* * Called once each second in verbose mode while dumping to file */ -#ifdef USE_WIN32_MM_TIMER +#ifdef _WIN32 void CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_, DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_) { - if (infodelay == 0) - fprintf(stderr, "Got %u\r", packets_captured); + print_packets_captured(); } -#elif defined(HAVE_ALARM) +#else /* _WIN32 */ static void verbose_stats_dump(int sig _U_) { - if (infodelay == 0) - fprintf(stderr, "Got %u\r", packets_captured); + print_packets_captured(); alarm(1); } -#endif +#endif /* _WIN32 */ USES_APPLE_DEPRECATED_API static void print_version(void) { - extern char version[]; #ifndef HAVE_PCAP_LIB_VERSION -#if defined(_WIN32) || defined(HAVE_PCAP_VERSION) + #ifdef HAVE_PCAP_VERSION extern char pcap_version[]; -#else /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */ + #else /* HAVE_PCAP_VERSION */ static char pcap_version[] = "unknown"; -#endif /* defined(_WIN32) || defined(HAVE_PCAP_VERSION) */ + #endif /* HAVE_PCAP_VERSION */ #endif /* HAVE_PCAP_LIB_VERSION */ + const char *smi_version_string; + (void)fprintf(stderr, "%s version " PACKAGE_VERSION "\n", program_name); #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); -#endif /* _WIN32 */ - (void)fprintf(stderr, "%s\n",pcap_lib_version()); + (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); - (void)fprintf(stderr, "WinPcap version %s, based on libpcap version %s\n",Wpcap_version, pcap_version); -#else /* _WIN32 */ - (void)fprintf(stderr, "%s version %s\n", program_name, version); (void)fprintf(stderr, "libpcap version %s\n", pcap_version); -#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); + smi_version_string = nd_smi_version_string(); + if (smi_version_string != NULL) + (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string); +#ifdef HAVE_DNET_HTOA + (void)fprintf(stderr, "libdnet unknown version\n"); #endif + +#if defined(__SANITIZE_ADDRESS__) + (void)fprintf (stderr, "Compiled with AddressSanitizer/GCC.\n"); +#elif defined(__has_feature) +# if __has_feature(address_sanitizer) + (void)fprintf (stderr, "Compiled with AddressSanitizer/CLang.\n"); +# endif +#endif /* __SANITIZE_ADDRESS__ or __has_feature */ } USES_APPLE_RST @@ -2513,26 +2884,21 @@ print_usage(void) (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 ] [ --number ]\n"); -#ifdef HAVE_PCAP_SETDIRECTION +"\t\t[ -i interface ]" IMMEDIATE_MODE_USAGE j_FLAG_USAGE "\n"); +#ifdef HAVE_PCAP_FINDALLDEVS_EX (void)fprintf(stderr, -"\t\t[ -Q in|out|inout ]\n"); +"\t\t" LIST_REMOTE_INTERFACES_USAGE "\n"); #endif (void)fprintf(stderr, -"\t\t[ -r file ] [ -s snaplen ] "); -#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION - (void)fprintf(stderr, "[ --time-stamp-precision precision ]\n"); +"\t\t[ -M secret ] [ --number ] [ --print ]" Q_FLAG_USAGE "\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"); +"\t\t[ -r file ] [ -s snaplen ]" TIME_STAMP_PRECISION_USAGE "\n"); + (void)fprintf(stderr, +"\t\t[ -T type ] [ --version ] [ -V file ] [ -w file ]\n"); (void)fprintf(stderr, -"\t\t[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ]\n"); +"\t\t[ -W filecount ] [ -y datalinktype ]\n"); (void)fprintf(stderr, -"\t\t[ -Z user ] [ expression ]\n"); +"\t\t[ -z postrotate-command ] [ -Z user ] [ expression ]\n"); } /* * Local Variables: