* combined efforts of Van, Steve McCanne and Craig Leres of LBL.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
/*
- * Some older versions of Mac OS X may ship pcap.h from libpcap 0.6 with a
+ * Some older versions of Mac OS X 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().
#include <sys/stat.h>
-#ifdef HAVE_FCNTL_H
#include <fcntl.h>
-#endif
#ifdef HAVE_LIBCRYPTO
#include <openssl/crypto.h>
#endif
/* Capsicum-specific code requires macros from <net/bpf.h>, which will fail
* to compile if <pcap.h> has already been included; including the headers
- * in the opposite order works fine.
+ * in the opposite order works fine. For the most part anyway, because in
+ * FreeBSD <pcap/pcap.h> declares bpf_dump() instead of <net/bpf.h>. Thus
+ * interface.h takes care of it later to avoid a compiler warning.
*/
#ifdef HAVE_CAPSICUM
#include <sys/capsicum.h>
#include <grp.h>
#endif /* _WIN32 */
+/*
+ * Pathname separator.
+ * Use this in pathnames, but do *not* use it in URLs.
+ */
+#ifdef _WIN32
+#define PATH_SEPARATOR '\\'
+#else
+#define PATH_SEPARATOR '/'
+#endif
+
/* 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.
#include <sys/sysctl.h>
#endif /* __FreeBSD__ */
+#include "netdissect-stdinc.h"
#include "netdissect.h"
#include "interface.h"
#include "addrtoname.h"
#include "print.h"
+#include "diag-control.h"
+
+#include "fptype.h"
+
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
static int Jflag; /* list available time stamp types */
static int jflag = -1; /* packet time stamp source */
#endif
+static int lflag; /* line-buffered output */
static int pflag; /* don't go promiscuous */
#ifdef HAVE_PCAP_SETDIRECTION
static int Qflag = -1; /* restrict captured packet by send/receive direction */
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 timeout = 1000; /* default timeout = 1000 ms = 1 s */
#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
static int immediate_mode;
#endif
+static int count_mode;
static int infodelay;
static int infoprint;
char *program_name;
-#ifdef HAVE_CASPER
-cap_channel_t *capdns;
-#endif
-
/* Forwards */
static NORETURN void error(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2);
static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2);
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 print_version(FILE *);
+static void print_usage(FILE *);
#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
static NORETURN void show_tstamp_types_and_exit(pcap_t *, const char *device);
#endif
device);
exit_tcpdump(S_SUCCESS);
}
- fprintf(stderr, "Time stamp types for %s (use option -j to set):\n",
+ fprintf(stdout, "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,
+ (void) fprintf(stdout, " %s (%s)\n", tstamp_type_name,
pcap_tstamp_type_val_to_description(tstamp_types[i]));
} else {
- (void) fprintf(stderr, " %d\n", tstamp_types[i]);
+ (void) fprintf(stdout, " %d\n", tstamp_types[i]);
}
}
pcap_free_tstamp_types(tstamp_types);
* monitor mode might be different from the ones available when
* not in monitor mode).
*/
+ (void) fprintf(stdout, "Data link types for ");
if (supports_monitor_mode)
- (void) fprintf(stderr, "Data link types for %s %s (use option -y to set):\n",
+ (void) fprintf(stdout, "%s %s",
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",
+ (void) fprintf(stdout, "%s",
device);
+ (void) fprintf(stdout, " (use option -y to set):\n");
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,
+ (void) fprintf(stdout, " %s (%s)", dlt_name,
pcap_datalink_val_to_description(dlts[i]));
/*
* OK, does tcpdump handle that type?
*/
if (!has_printer(dlts[i]))
- (void) fprintf(stderr, " (printing not supported)");
- fprintf(stderr, "\n");
+ (void) fprintf(stdout, " (printing not supported)");
+ fprintf(stdout, "\n");
} else {
- (void) fprintf(stderr, " DLT %d (printing not supported)\n",
+ (void) fprintf(stdout, " DLT %d (printing not supported)\n",
dlts[i]);
}
}
#define OPTION_LIST_REMOTE_INTERFACES 132
#define OPTION_TSTAMP_MICRO 133
#define OPTION_TSTAMP_NANO 134
+#define OPTION_FP_TYPE 135
+#define OPTION_COUNT 136
+#define OPTION_TIME_T_SIZE 139
static const struct option longopts[] = {
#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
{ "debug-filter-parser", no_argument, NULL, 'Y' },
#endif
{ "relinquish-privileges", required_argument, NULL, 'Z' },
+ { "count", no_argument, NULL, OPTION_COUNT },
+ { "fp-type", no_argument, NULL, OPTION_FP_TYPE },
{ "number", no_argument, NULL, '#' },
{ "print", no_argument, NULL, OPTION_PRINT },
+ { "time-t-size", no_argument, NULL, OPTION_TIME_T_SIZE },
{ "version", no_argument, NULL, OPTION_VERSION },
{ NULL, 0, NULL, 0 }
};
} else
error("Couldn't find user '%.32s'", username);
#ifdef HAVE_LIBCAP_NG
- /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */
-DIAG_OFF_CLANG(assign-enum)
+ /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT anymore. */
+DIAG_OFF_ASSIGN_ENUM
capng_updatev(
CAPNG_DROP,
CAPNG_EFFECTIVE | CAPNG_PERMITTED,
CAP_SETGID,
CAP_SYS_CHROOT,
-1);
-DIAG_ON_CLANG(assign-enum)
+DIAG_ON_ASSIGN_ENUM
capng_apply(CAPNG_SELECT_BOTH);
#endif /* HAVE_LIBCAP_NG */
{
char *filename = malloc(PATH_MAX + 1);
if (filename == NULL)
- error("Makefilename: malloc");
+ error("%s: malloc", __func__);
+ if (strlen(orig_name) == 0)
+ error("an empty string is not a valid file name");
/* Process with strftime if Gflag is set. */
if (Gflag != 0) {
/* Convert Gflag_time to a usable format */
if ((local_tm = localtime(&Gflag_time)) == NULL) {
- error("MakeTimedFilename: localtime");
+ error("%s: localtime", __func__);
}
/* There's no good way to detect an error in strftime since a return
- * value of 0 isn't necessarily failure.
+ * value of 0 isn't necessarily failure; if orig_name is an empty
+ * string, the formatted string will be empty.
+ *
+ * However, the C90 standard says that, if there *is* a
+ * buffer overflow, the content of the buffer is undefined,
+ * so we must check for a buffer overflow.
+ *
+ * So we check above for an empty orig_name, and only call
+ * strftime() if it's non-empty, in which case the return
+ * value will only be 0 if the formatted date doesn't fit
+ * in the buffer.
+ *
+ * (We check above because, even if we don't use -G, we
+ * want a better error message than "tcpdump: : No such
+ * file or directory" for this case.)
*/
- strftime(filename, PATH_MAX, orig_name, local_tm);
+ if (strftime(filename, PATH_MAX, orig_name, local_tm) == 0) {
+ error("%s: strftime", __func__);
+ }
} else {
strncpy(filename, orig_name, PATH_MAX);
}
* 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
+ * 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.
+ * regular files notwithstanding.
*
* The Capsicum people decided that fine-grained control of descriptor
* operations was required, so that you need to grant permission for
buf = (char *)malloc(len);
if (buf == NULL)
- error("copy_argv: malloc");
+ error("%s: malloc", __func__);
p = argv;
dst = buf;
int i, fd;
ssize_t cc;
char *cp;
- struct stat buf;
+ our_statb buf;
fd = open(fname, O_RDONLY|O_BINARY);
if (fd < 0)
error("can't open %s: %s", fname, pcap_strerror(errno));
- if (fstat(fd, &buf) < 0)
+ if (our_fstat(fd, &buf) < 0)
error("can't stat %s: %s", fname, pcap_strerror(errno));
+ /*
+ * Reject files whose size doesn't fit into an int; a filter
+ * *that* large will probably be too big.
+ */
+ if (buf.st_size > INT_MAX)
+ error("%s is too large", fname);
+
cp = malloc((u_int)buf.st_size + 1);
if (cp == NULL)
error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
if (cc < 0)
error("read %s: %s", fname, pcap_strerror(errno));
if (cc != buf.st_size)
- error("short read %s (%zd != %d)", fname, cc, (int)buf.st_size);
+ error("short read %s (%d != %d)", fname, (int) cc,
+ (int)buf.st_size);
close(fd);
/* replace "# comment" with spaces */
/*
* No, it's not an ordinal.
*/
- error("Invalid adapter index");
+ error("Invalid adapter index %s", device);
}
return (devnum);
} else {
for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
i++, dev = dev->next)
;
- if (dev == NULL)
- error("Invalid adapter index");
+ if (dev == NULL) {
+ pcap_freealldevs(devlist);
+ error("Invalid adapter index %ld: only %ld interfaces found",
+ devnum, i);
+ }
device = strdup(dev->name);
pcap_freealldevs(devlist);
return (device);
*/
*ebuf = '\0';
pc = pcap_open(device, ndo->ndo_snaplen,
- pflag ? 0 : PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL,
+ pflag ? 0 : PCAP_OPENFLAG_PROMISCUOUS, timeout, NULL,
ebuf);
if (pc == NULL) {
/*
error("%s: Can't set monitor mode: %s",
device, pcap_statustostr(status));
}
- status = pcap_set_timeout(pc, 1000);
+ status = pcap_set_timeout(pc, timeout);
if (status != 0)
error("%s: pcap_set_timeout failed: %s",
device, pcap_statustostr(status));
*/
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);
else
error("%s: %s", device,
pcap_statustostr(status));
+ pcap_close(pc);
+ return (NULL);
} else if (status > 0) {
/*
* pcap_activate() succeeded, but it's warning us
*/
if (ndo->ndo_snaplen == 0)
ndo->ndo_snaplen = MAXIMUM_SNAPLEN;
- pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, 1000, ebuf);
+ pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, timeout, ebuf);
if (pc == NULL) {
/*
* If this failed with "No such device", that means
netdissect_options Ndo;
netdissect_options *ndo = &Ndo;
+#ifdef _WIN32
+ /*
+ * We need to look for wpcap.dll in \Windows\System32\Npcap first,
+ * as either:
+ *
+ * 1) WinPcap isn't installed and Npcap isn't installed in "WinPcap
+ * API-compatible Mode", so there's no wpcap.dll in
+ * \Windows\System32, only in \Windows\System32\Npcap;
+ *
+ * 2) WinPcap is installed and Npcap isn't installed in "WinPcap
+ * API-compatible Mode", so the wpcap.dll in \Windows\System32
+ * is a WinPcap DLL, but we'd prefer an Npcap DLL (we should
+ * work with either one if we're configured against WinPcap,
+ * and we'll probably require Npcap if we're configured againt
+ * it), and that's in \Windows\System32\Npcap;
+ *
+ * 3) Npcap is installed in "WinPcap API-compatible Mode", so both
+ * \Windows\System32 and \Windows\System32\Npcap have an Npcap
+ * wpcap.dll.
+ *
+ * Unfortunately, Windows has no notion of an rpath, so we can't
+ * set the rpath to include \Windows\System32\Npcap at link time;
+ * what we need to do is to link wpcap as a delay-load DLL and
+ * add \Windows\System32\Npcap to the DLL search path early in
+ * main() with a call to SetDllDirectory().
+ *
+ * The same applies to packet.dll.
+ *
+ * We add \Windows\System32\Npcap here.
+ *
+ * See https://npcap.com/guide/npcap-devguide.html#npcap-feature-native-dll-implicitly
+ */
+ WCHAR *dll_directory = NULL;
+ size_t dll_directory_buf_len = 0; /* units of bytes */
+ UINT system_directory_buf_len = 0; /* units of WCHARs */
+ UINT system_directory_len; /* units of WCHARs */
+ static const WCHAR npcap[] = L"\\Npcap";
+
+ /*
+ * Get the system directory path, in UTF-16, into a buffer that's
+ * large enough for that directory path plus "\Npcap".
+ *
+ * String manipulation in C, plus fetching a variable-length
+ * string into a buffer whose size is fixed at the time of
+ * the call, with an oddball return value (see below), is just
+ * a huge bag of fun.
+ *
+ * And it's even more fun when dealing with UTF-16, so that the
+ * buffer sizes used in GetSystemDirectoryW() are in different
+ * units from the buffer sizes used in realloc()! We maintain
+ * all sizes/length in units of bytes, not WCHARs, so that our
+ * heads don't explode.
+ */
+ for (;;) {
+ /*
+ * Try to fetch the system directory.
+ *
+ * GetSystemDirectoryW() expects a buffer size in units
+ * of WCHARs, not bytes, and returns a directory path
+ * length in units of WCHARs, not bytes.
+ *
+ * For extra fun, if GetSystemDirectoryW() succeeds,
+ * the return value is the length of the directory
+ * path in units of WCHARs, *not* including the
+ * terminating '\0', but if it fails because the
+ * path string wouldn't fit, the return value is
+ * the length of the directory path in units of WCHARs,
+ * *including* the terminating '\0'.
+ */
+ system_directory_len = GetSystemDirectoryW(dll_directory,
+ system_directory_buf_len);
+ if (system_directory_len == 0)
+ error("GetSystemDirectoryW() failed");
+
+ /*
+ * Did the directory path fit in the buffer?
+ *
+ * As per the above, this means that the return value
+ * *plus 1*, so that the terminating '\0' is counted,
+ * is <= the buffer size.
+ *
+ * (If the directory path, complete with the terminating
+ * '\0', fits *exactly*, the return value would be the
+ * size of the buffer minus 1, as it doesn't count the
+ * terminating '\0', so the test below would succeed.
+ *
+ * If everything *but* the terminating '\0' fits,
+ * the return value would be the size of the buffer + 1,
+ * i.e., the size that the string in question would
+ * have required.
+ *
+ * The astute reader will note that returning the
+ * size of the buffer is not one of the two cases
+ * above, and should never happen.)
+ */
+ if ((system_directory_len + 1) <= system_directory_buf_len) {
+ /*
+ * No. We have a buffer that's large enough
+ * for our purposes.
+ */
+ break;
+ }
+
+ /*
+ * Yes. Grow the buffer.
+ *
+ * The space we'll need in the buffer for the system
+ * directory, in units of WCHARs, is system_directory_len,
+ * as that's the length of the system directory path
+ * including the terminating '\0'.
+ */
+ system_directory_buf_len = system_directory_len;
+
+ /*
+ * The size of the DLL directory buffer, in *bytes*, must
+ * be the number of WCHARs taken by the system directory,
+ * *minus* the terminating '\0' (as we'll overwrite that
+ * with the "\" of the "\Npcap" string), multiplied by
+ * sizeof(WCHAR) to convert it to the number of bytes,
+ * plus the size of the "\Npcap" string, in bytes (which
+ * will include the terminating '\0', as that will become
+ * the DLL path's terminating '\0').
+ */
+ dll_directory_buf_len =
+ ((system_directory_len - 1)*sizeof(WCHAR)) + sizeof npcap;
+ dll_directory = realloc(dll_directory, dll_directory_buf_len);
+ if (dll_directory == NULL)
+ error("Can't allocate string for Npcap directory");
+ }
+
+ /*
+ * OK, that worked.
+ *
+ * Now append \Npcap. We add the length of the system directory path,
+ * in WCHARs, *not* including the terminating '\0' (which, since
+ * GetSystemDirectoryW() succeeded, is the return value of
+ * GetSystemDirectoryW(), as per the above), to the pointer to the
+ * beginning of the path, to go past the end of the system directory
+ * to point to the terminating '\0'.
+ */
+ memcpy(dll_directory + system_directory_len, npcap, sizeof npcap);
+
+ /*
+ * Now add that as a system DLL directory.
+ */
+ if (!SetDllDirectoryW(dll_directory))
+ error("SetDllDirectory failed");
+
+ free(dll_directory);
+#endif
+
/*
* Initialize the netdissect code.
*/
VFile = NULL;
WFileName = NULL;
dlt = -1;
- if ((cp = strrchr(argv[0], '/')) != NULL)
+ if ((cp = strrchr(argv[0], PATH_SEPARATOR)) != NULL)
ndo->program_name = program_name = cp + 1;
else
ndo->program_name = program_name = argv[0];
if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0)
error("%s", ebuf);
+ /*
+ * An explicit tzset() call is usually not needed as it happens
+ * implicitly the first time we call localtime() or mktime(),
+ * but in some cases (sandboxing, chroot) this may be too late.
+ */
+ tzset();
+
while (
(op = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != -1)
switch (op) {
/* 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));
+ error("%s: can't get current time: %s",
+ __func__, pcap_strerror(errno));
}
break;
case 'h':
- print_usage();
+ print_usage(stdout);
exit_tcpdump(S_SUCCESS);
break;
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
#endif /* _WIN32 */
+ lflag = 1;
break;
case 'K':
if (nd_load_smi_module(optarg, ebuf, sizeof(ebuf)) == -1)
error("%s", ebuf);
} else {
- (void)fprintf(stderr, "%s: ignoring option `-m %s' ",
+ (void)fprintf(stderr, "%s: ignoring option '-m %s' ",
program_name, optarg);
(void)fprintf(stderr, "(no libsmi support)\n");
}
else if (ascii_strcasecmp(optarg, "inout") == 0)
Qflag = PCAP_D_INOUT;
else
- error("unknown capture direction `%s'", optarg);
+ error("unknown capture direction '%s'", optarg);
break;
#endif /* HAVE_PCAP_SETDIRECTION */
ndo->ndo_packettype = PT_LMP;
else if (ascii_strcasecmp(optarg, "resp") == 0)
ndo->ndo_packettype = PT_RESP;
+ else if (ascii_strcasecmp(optarg, "ptp") == 0)
+ ndo->ndo_packettype = PT_PTP;
+ else if (ascii_strcasecmp(optarg, "someip") == 0)
+ ndo->ndo_packettype = PT_SOMEIP;
+ else if (ascii_strcasecmp(optarg, "domain") == 0)
+ ndo->ndo_packettype = PT_DOMAIN;
else
- error("unknown packet type `%s'", optarg);
+ error("unknown packet type '%s'", optarg);
break;
case 'u':
ndo->ndo_packet_number = 1;
break;
+ case OPTION_TIME_T_SIZE:
+ printf("%zu\n", sizeof(time_t) * 8);
+ return 0;
+
case OPTION_VERSION:
- print_version();
+ print_version(stdout);
exit_tcpdump(S_SUCCESS);
break;
break;
#endif
+ case OPTION_FP_TYPE:
+ /*
+ * Print out the type of floating-point arithmetic
+ * we're doing; it's probably IEEE, unless somebody
+ * tries to run this on a VAX, but the precision
+ * may differ (e.g., it might be 32-bit, 64-bit,
+ * or 80-bit).
+ */
+ float_type_check(0x4e93312d);
+ return 0;
+
+ case OPTION_COUNT:
+ count_mode = 1;
+ break;
+
default:
- print_usage();
+ print_usage(stderr);
exit_tcpdump(S_ERR_HOST_PROGRAM);
/* NOTREACHED */
}
+ if (ndo->ndo_Aflag && ndo->ndo_xflag)
+ warning("-A and -x[x] are mutually exclusive. -A ignored.");
+ if (ndo->ndo_Aflag && ndo->ndo_Xflag)
+ warning("-A and -X[X] are mutually exclusive. -A ignored.");
+ if (ndo->ndo_xflag && ndo->ndo_Xflag)
+ warning("-x[x] and -X[X] are mutually exclusive. -x[x] ignored.");
+
#ifdef HAVE_PCAP_FINDALLDEVS
if (Dflag)
show_devices_and_exit();
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
- * and the standard output is a terminal, use immediate mode,
- * as the user's probably expecting to see packets pop up
- * immediately.
+ * If we're printing dissected packets to the standard output,
+ * and either the standard output is a terminal or we're doing
+ * "line" buffering, set the capture timeout to .1 second rather
+ * than 1 second, as the user's probably expecting to see packets
+ * pop up immediately shortly after they arrive.
*
- * XXX - set the timeout to a lower value, instead? If so,
- * what value would be appropriate?
+ * XXX - would there be some value appropriate for all cases,
+ * based on, say, the buffer size and packet input rate?
*/
- if ((WFileName == NULL || print) && isatty(1))
- immediate_mode = 1;
-#endif
+ if ((WFileName == NULL || print) && (isatty(1) || lflag))
+ timeout = 100;
#ifdef WITH_CHROOT
/* if run as root, prepare for chrooting */
/* Run with '-Z root' to restore old behaviour */
if (!username)
username = WITH_USER;
+ else if (strcmp(username, "root") == 0)
+ username = NULL;
}
#endif
if (dlt == DLT_LINUX_SLL2)
fprintf(stderr, "Warning: interface names might be incorrect\n");
#endif
+ } else if (dflag && !device) {
+ int dump_dlt = DLT_EN10MB;
+ /*
+ * We're dumping the compiled code without an explicit
+ * device specification. (If a device is specified, we
+ * definitely want to open it to use the DLT of that device.)
+ * Either default to DLT_EN10MB with a warning, or use
+ * the user-specified value if supplied.
+ */
+ /*
+ * If no snapshot length was specified, or a length of 0 was
+ * specified, default to 256KB.
+ */
+ if (ndo->ndo_snaplen == 0)
+ ndo->ndo_snaplen = MAXIMUM_SNAPLEN;
+ /*
+ * If a DLT was specified with the -y flag, use that instead.
+ */
+ if (yflag_dlt != -1)
+ dump_dlt = yflag_dlt;
+ else
+ fprintf(stderr, "Warning: assuming Ethernet\n");
+ pd = pcap_open_dead(dump_dlt, ndo->ndo_snaplen);
} else {
/*
* We're doing a live capture.
}
#endif
(void)fprintf(stderr, "%s: data link type %s\n",
- program_name, yflag_dlt_name);
+ program_name,
+ pcap_datalink_val_to_name(yflag_dlt));
(void)fflush(stderr);
}
+#if defined(DLT_LINUX_SLL2) && defined(HAVE_PCAP_SET_DATALINK)
+ else {
+ /*
+ * Attempt to set default linktype to
+ * DLT_LINUX_SLL2 when capturing on the
+ * "any" device.
+ *
+ * If the attempt fails, just quietly drive
+ * on; this may be a non-Linux "any" device
+ * that doesn't support DLT_LINUX_SLL2.
+ */
+ if (strcmp(device, "any") == 0) {
+DIAG_OFF_WARN_UNUSED_RESULT
+ (void) pcap_set_datalink(pd, DLT_LINUX_SLL2);
+DIAG_ON_WARN_UNUSED_RESULT
+ }
+ }
+#endif
i = pcap_snapshot(pd);
if (ndo->ndo_snaplen < i) {
if (ndo->ndo_snaplen != 0)
#endif
/* Cooperate with nohup(1) */
#ifndef _WIN32
+ /*
+ * In illumos /usr/include/sys/iso/signal_iso.h causes Clang to
+ * generate a -Wstrict-prototypes warning here, see [1]. The
+ * __illumos__ macro is available since at least GCC 11 and Clang 13,
+ * see [2].
+ * 1: https://www.illumos.org/issues/16344
+ * 2: https://www.illumos.org/issues/13726
+ */
+#ifdef __illumos__
+ DIAG_OFF_STRICT_PROTOTYPES
+#endif /* __illumos__ */
if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
+#ifdef __illumos__
+ DIAG_ON_STRICT_PROTOTYPES
+#endif /* __illumos__ */
(void)setsignal(SIGHUP, oldhandler);
#endif /* _WIN32 */
/* Initialize capng */
capng_clear(CAPNG_SELECT_BOTH);
if (username) {
-DIAG_OFF_CLANG(assign-enum)
+DIAG_OFF_ASSIGN_ENUM
capng_updatev(
CAPNG_ADD,
CAPNG_PERMITTED | CAPNG_EFFECTIVE,
CAP_SETUID,
CAP_SETGID,
-1);
-DIAG_ON_CLANG(assign-enum)
+DIAG_ON_ASSIGN_ENUM
}
if (chroot_dir) {
-DIAG_OFF_CLANG(assign-enum)
+DIAG_OFF_ASSIGN_ENUM
capng_update(
CAPNG_ADD,
CAPNG_PERMITTED | CAPNG_EFFECTIVE,
CAP_SYS_CHROOT
);
-DIAG_ON_CLANG(assign-enum)
+DIAG_ON_ASSIGN_ENUM
}
if (WFileName) {
-DIAG_OFF_CLANG(assign-enum)
+DIAG_OFF_ASSIGN_ENUM
capng_update(
CAPNG_ADD,
CAPNG_PERMITTED | CAPNG_EFFECTIVE,
CAP_DAC_OVERRIDE
);
-DIAG_ON_CLANG(assign-enum)
+DIAG_ON_ASSIGN_ENUM
}
capng_apply(CAPNG_SELECT_BOTH);
#endif /* HAVE_LIBCAP_NG */
#endif
if (Cflag != 0 || Gflag != 0) {
#ifdef HAVE_CAPSICUM
- dumpinfo.WFileName = strdup(basename(WFileName));
+ /*
+ * basename() and dirname() may modify their input buffer
+ * and they do since FreeBSD 12.0, but they didn't before.
+ * Hence use the return value only, but always assume the
+ * input buffer has been modified and would need to be
+ * reset before the next use.
+ */
+ char *WFileName_copy;
+
+ if ((WFileName_copy = strdup(WFileName)) == NULL) {
+ error("Unable to allocate memory for file %s",
+ WFileName);
+ }
+ DIAG_OFF_C11_EXTENSIONS
+ dumpinfo.WFileName = strdup(basename(WFileName_copy));
+ DIAG_ON_C11_EXTENSIONS
if (dumpinfo.WFileName == NULL) {
error("Unable to allocate memory for file %s",
WFileName);
}
- dumpinfo.dirfd = open(dirname(WFileName),
+ free(WFileName_copy);
+
+ if ((WFileName_copy = strdup(WFileName)) == NULL) {
+ error("Unable to allocate memory for file %s",
+ WFileName);
+ }
+ DIAG_OFF_C11_EXTENSIONS
+ char *WFileName_dirname = dirname(WFileName_copy);
+ DIAG_ON_C11_EXTENSIONS
+ dumpinfo.dirfd = open(WFileName_dirname,
O_DIRECTORY | O_RDONLY);
if (dumpinfo.dirfd < 0) {
error("unable to open directory %s",
- dirname(WFileName));
+ WFileName_dirname);
}
+ free(WFileName_dirname);
+ free(WFileName_copy);
+
cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL,
CAP_FTRUNCATE, CAP_LOOKUP, CAP_SEEK, CAP_WRITE);
if (cap_rights_limit(dumpinfo.dirfd, &rights) < 0 &&
}
if (print) {
dlt = pcap_datalink(pd);
- ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+ ndo->ndo_if_printer = get_if_printer(dlt);
dumpinfo.ndo = ndo;
} else
dumpinfo.ndo = NULL;
#endif
} else {
dlt = pcap_datalink(pd);
- ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+ ndo->ndo_if_printer = get_if_printer(dlt);
callback = print_packet;
pcap_userdata = (u_char *)ndo;
}
(void)setsignal(SIGNAL_FLUSH_PCAP, flushpcap);
#endif
- if (ndo->ndo_vflag > 0 && WFileName && !print) {
+ if (ndo->ndo_vflag > 0 && WFileName && RFileName == NULL && !print) {
/*
* 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.
+ * Except when reading from a file, because -r, -w and -v
+ * together used to make a corner case, in which pcap_loop()
+ * errored due to EINTR (see GH #155 for details).
*/
#ifdef _WIN32
/*
*/
if (!ndo->ndo_vflag && !WFileName) {
(void)fprintf(stderr,
- "%s: verbose output suppressed, use -v or -vv for full protocol decode\n",
+ "%s: verbose output suppressed, use -v[v]... for full protocol decode\n",
program_name);
} else
(void)fprintf(stderr, "%s: ", program_name);
#else
cansandbox = (cansandbox && ndo->ndo_nflag);
#endif /* HAVE_CASPER */
+ cansandbox = (cansandbox && (pcap_fileno(pd) != -1 ||
+ RFileName != NULL));
+
if (cansandbox && cap_enter() < 0 && errno != ENOSYS)
error("unable to enter the capability mode");
#endif /* HAVE_CAPSICUM */
* the new DLT.
*/
dlt = new_dlt;
- ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+ ndo->ndo_if_printer = get_if_printer(dlt);
+ /* Free the old filter */
+ pcap_freecode(&fcode);
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
error("%s", pcap_geterr(pd));
}
}
while (ret != NULL);
+ if (count_mode && RFileName != NULL)
+ fprintf(stdout, "%u packet%s\n", packets_captured,
+ PLURAL_SUFFIX(packets_captured));
+
free(cmdbuf);
pcap_freecode(&fcode);
- exit_tcpdump(status == -1 ? 1 : 0);
+ exit_tcpdump(status == -1 ? S_ERR_HOST_PROGRAM : S_SUCCESS);
}
/*
memset(&new, 0, sizeof(new));
new.sa_handler = func;
- if (sig == SIGCHLD)
+ if ((sig == SIGCHLD)
+# ifdef SIGNAL_REQ_INFO
+ || (sig == SIGNAL_REQ_INFO)
+# endif
+# ifdef SIGNAL_FLUSH_PCAP
+ || (sig == SIGNAL_FLUSH_PCAP)
+# endif
+ )
new.sa_flags = SA_RESTART;
if (sigaction(sig, &new, &old) < 0)
+ /* The same workaround as for SIG_DFL above. */
+#ifdef __illumos__
+ DIAG_OFF_STRICT_PROTOTYPES
+#endif /* __illumos__ */
return (SIG_ERR);
+#ifdef __illumos__
+ DIAG_ON_STRICT_PROTOTYPES
+#endif /* __illumos__ */
return (old.sa_handler);
#endif
}
static void
child_cleanup(int signo _U_)
{
- wait(NULL);
+ while (waitpid(-1, NULL, WNOHANG) >= 0);
}
#endif /* HAVE_FORK && HAVE_VFORK */
/* 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));
+ error("%s: can't get current_time: %s",
+ __func__, pcap_strerror(errno));
}
free(dump_info->CurrentFileName);
dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1);
if (dump_info->CurrentFileName == NULL)
- error("dump_packet_and_trunc: malloc");
+ error("%s: malloc", __func__);
MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
#ifdef HAVE_LIBCAP_NG
capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
++infodelay;
- pretty_print_packet((netdissect_options *)user, h, sp, packets_captured);
+ if (!count_mode)
+ pretty_print_packet((netdissect_options *)user, h, sp, packets_captured);
--infodelay;
if (infoprint)
}
#endif /* _WIN32 */
-USES_APPLE_DEPRECATED_API
+DIAG_OFF_DEPRECATION
static void
-print_version(void)
+print_version(FILE *f)
{
#ifndef HAVE_PCAP_LIB_VERSION
#ifdef HAVE_PCAP_VERSION
#endif /* HAVE_PCAP_LIB_VERSION */
const char *smi_version_string;
- (void)fprintf(stderr, "%s version " PACKAGE_VERSION "\n", program_name);
+ (void)fprintf(f, "%s version " PACKAGE_VERSION "\n", program_name);
#ifdef HAVE_PCAP_LIB_VERSION
- (void)fprintf(stderr, "%s\n", pcap_lib_version());
+ (void)fprintf(f, "%s\n", pcap_lib_version());
#else /* HAVE_PCAP_LIB_VERSION */
- (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
+ (void)fprintf(f, "libpcap version %s\n", pcap_version);
#endif /* HAVE_PCAP_LIB_VERSION */
#if defined(HAVE_LIBCRYPTO) && defined(SSLEAY_VERSION)
- (void)fprintf (stderr, "%s\n", SSLeay_version(SSLEAY_VERSION));
+ (void)fprintf (f, "%s\n", SSLeay_version(SSLEAY_VERSION));
#endif
smi_version_string = nd_smi_version_string();
if (smi_version_string != NULL)
- (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string);
+ (void)fprintf (f, "SMI-library: %s\n", smi_version_string);
#if defined(__SANITIZE_ADDRESS__)
- (void)fprintf (stderr, "Compiled with AddressSanitizer/GCC.\n");
+ (void)fprintf (f, "Compiled with AddressSanitizer/GCC.\n");
#elif defined(__has_feature)
# if __has_feature(address_sanitizer)
- (void)fprintf (stderr, "Compiled with AddressSanitizer/CLang.\n");
+ (void)fprintf (f, "Compiled with AddressSanitizer/Clang.\n");
+# elif __has_feature(memory_sanitizer)
+ (void)fprintf (f, "Compiled with MemorySanitizer/Clang.\n");
# endif
#endif /* __SANITIZE_ADDRESS__ or __has_feature */
+ (void)fprintf (f, "%zu-bit build, %zu-bit time_t\n",
+ sizeof(void *) * 8, sizeof(time_t) * 8);
}
-USES_APPLE_RST
+DIAG_ON_DEPRECATION
static void
-print_usage(void)
+print_usage(FILE *f)
{
- print_version();
- (void)fprintf(stderr,
-"Usage: %s [-aAbd" D_FLAG "efhH" I_FLAG J_FLAG "KlLnNOpqStu" U_FLAG "vxX#]" B_FLAG_USAGE " [ -c count ]\n", program_name);
- (void)fprintf(stderr,
+ print_version(f);
+ (void)fprintf(f,
+"Usage: %s [-Abd" D_FLAG "efhH" I_FLAG J_FLAG "KlLnNOpqStu" U_FLAG "vxX#]" B_FLAG_USAGE " [ -c count ] [--count]\n", program_name);
+ (void)fprintf(f,
"\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t[ -i interface ]" IMMEDIATE_MODE_USAGE j_FLAG_USAGE "\n");
#ifdef HAVE_PCAP_FINDALLDEVS_EX
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t" LIST_REMOTE_INTERFACES_USAGE "\n");
#endif
#ifdef USE_LIBSMI
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t" m_FLAG_USAGE "\n");
#endif
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t[ -M secret ] [ --number ] [ --print ]" Q_FLAG_USAGE "\n");
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ --version ]\n");
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t[ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ]\n");
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t[ --time-stamp-precision precision ] [ --micro ] [ --nano ]\n");
#endif
- (void)fprintf(stderr,
+ (void)fprintf(f,
"\t\t[ -z postrotate-command ] [ -Z user ] [ expression ]\n");
}