*/
#include <config.h>
+#ifndef TCPDUMP_CONFIG_H_
+#error "The included config.h header is not from the tcpdump build."
+#endif
#include "netdissect-stdinc.h"
#include <sys/sysctl.h>
#endif /* __FreeBSD__ */
-#include "netdissect-stdinc.h"
#include "netdissect.h"
#include "interface.h"
#include "addrtoname.h"
-#include "pcap-missing.h"
#include "ascii_strcasecmp.h"
#include "print.h"
#endif
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 */
static int Dflag; /* list available devices and exit */
#ifdef HAVE_PCAP_FINDALLDEVS_EX
static int Uflag; /* "unbuffered" output of dump files */
static int Wflag; /* recycle output files after this number of files */
static int WflagChars;
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
static char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */
+#endif
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 u_int packets_skipped;
+static u_int packets_to_skip;
static int infodelay;
static int infoprint;
char *program_name;
/* Forwards */
+static int parse_int(const char *argname, const char *string, char **endp,
+ int minval, int maxval, int base);
+static u_int parse_u_int(const char *argname, const char *string, char **endp,
+ u_int minval, u_int maxval, int base);
+static int64_t parse_int64(const char *argname, const char *string,
+ char **endp, int64_t minval, int64_t maxval, int base);
static void (*setsignal (int sig, void (*func)(int)))(int);
static void cleanup(int);
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
static void child_cleanup(int);
+#endif
static void print_version(FILE *);
static void print_usage(FILE *);
}
#define HAVE_PCAP_SET_PARSER_DEBUG
-#endif
+#endif // HAVE_PCAP_SET_PARSER_DEBUG, HAVE_PCAP_DEBUG, HAVE_YYDEBUG
#if defined(HAVE_PCAP_SET_OPTIMIZER_DEBUG)
/*
extern
#endif /* _WIN32 */
void pcap_set_optimizer_debug(int);
-#endif
+#endif // HAVE_PCAP_SET_OPTIMIZER_DEBUG
static void NORETURN
exit_tcpdump(const int status)
pcap_free_tstamp_types(tstamp_types);
exit_tcpdump(S_SUCCESS);
}
-#endif
+#endif // HAVE_PCAP_SET_TSTAMP_TYPE
static void NORETURN
show_dlts_and_exit(pcap_t *pc, const char *device)
break;
}
}
-#endif
+#endif // PCAP_IF_WIRELESS
printf("]");
}
printf("\n");
#define m_FLAG_USAGE "[ -m module ] ..."
#endif
-#define SHORTOPTS "aAbB:c:C:dDeE:fF:G:hHi:I" j_FLAG J_FLAG "KlLm:M:nNOpqQ:r:s:StT:uUvV:w:W:xXy:Yz:Z:#"
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
+#define z_FLAG "z:"
+#define z_FLAG_USAGE "[ -z postrotate-command ] "
+#else
+#define z_FLAG
+#define z_FLAG_USAGE
+#endif
+
+#ifdef HAVE_LIBCRYPTO
+#define E_FLAG "E:"
+#define E_FLAG_USAGE "[ -E algo:secret ] "
+#define M_FLAG "M:"
+#define M_FLAG_USAGE "[ -M secret ] "
+#else
+#define E_FLAG
+#define E_FLAG_USAGE
+#define M_FLAG
+#define M_FLAG_USAGE
+#endif
+
+#define SHORTOPTS "aAbB:c:C:dDe" E_FLAG "fF:G:hHi:I" j_FLAG J_FLAG "KlLm:" M_FLAG "nNOpqQ:r:s:StT:uUvV:w:W:xXy:Y" z_FLAG "Z:#"
/*
* Long options.
{
int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG);
if (ret < 0)
- error("capng_change_id(): return %d\n", ret);
+ error("capng_change_id(): return %d", ret);
else
fprintf(stderr, "dropped privs to %s\n", username);
}
return "unknown";
}
}
-#endif
+#endif // HAVE_PCAP_SET_TSTAMP_PRECISION
#ifdef HAVE_CAPSICUM
/*
error("unable to limit dump descriptor fcntls");
}
}
-#endif
+#endif // HAVE_CAPSICUM
/*
* Copy arg vector into a new buffer, concatenating arguments with spaces.
status = pcap_findalldevs_ex(host_url, NULL, &devlist, ebuf);
free(host_url);
} else
-#endif
+#endif // HAVE_PCAP_FINDALLDEVS_EX
status = pcap_findalldevs(&devlist, ebuf);
if (status < 0)
error("%s", ebuf);
} else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
error("%s: %s\n(%s)", device,
pcap_statustostr(status), cp);
+#ifdef PCAP_ERROR_CAPTURE_NOTSUP
+ else if (status == PCAP_ERROR_CAPTURE_NOTSUP && *cp != '\0')
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+#endif
#ifdef __FreeBSD__
else if (status == PCAP_ERROR_RFMON_NOTSUP &&
strncmp(device, "wlan", 4) == 0) {
* 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"
+ error("%s is not a monitor mode VAP"
"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
+#endif // __FreeBSD__
else
error("%s: %s", device,
pcap_statustostr(status));
const char *chroot_dir = NULL;
#endif
char *ret = NULL;
- char *end;
pcap_if_t *devlist;
long devnum;
int status;
error("SetDllDirectory failed");
free(dll_directory);
-#endif
+#endif // _WIN32
/*
* Initialize the netdissect code.
break;
case 'B':
- Bflag = atoi(optarg)*1024;
- if (Bflag <= 0)
- error("invalid packet buffer size %s", optarg);
+ Bflag = parse_int("packet buffer size", optarg, NULL, 1,
+ INT_MAX, 10);
+ /*
+ * Will multiplying it by 1024 overflow?
+ */
+ if (Bflag > INT_MAX / 1024)
+ error("packet buffer size %s is too large", optarg);
+ Bflag *= 1024;
break;
case 'c':
- cnt = atoi(optarg);
- if (cnt <= 0)
- error("invalid packet count %s", optarg);
+ cnt = parse_int("packet count", optarg, NULL, 1,
+ INT_MAX, 10);
break;
case 'C':
- errno = 0;
-#ifdef HAVE_PCAP_DUMP_FTELL64
- Cflag = strtoint64_t(optarg, &endp, 10);
-#else
- Cflag = strtol(optarg, &endp, 10);
-#endif
- if (endp == optarg || errno != 0 || Cflag <= 0)
- error("invalid file size %s", optarg);
+ Cflag = parse_int64("file size", optarg, &endp, 1,
+ INT64_MAX, 10);
if (*endp == '\0') {
/*
break;
default:
- error("invalid file size %s", optarg);
+ error("invalid file size %s (invalid units)", optarg);
}
/*
endp++;
if (*endp != '\0') {
/* Yes - error */
- error("invalid file size %s", optarg);
+ error("invalid file size %s (invalid units)", optarg);
}
}
* Will multiplying it by multiplier overflow?
*/
#ifdef HAVE_PCAP_DUMP_FTELL64
- if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffff) / Cflagmult)
+ if (Cflag > INT64_MAX / Cflagmult)
#else
if (Cflag > LONG_MAX / Cflagmult)
#endif
++ndo->ndo_eflag;
break;
+#ifdef HAVE_LIBCRYPTO
case 'E':
-#ifndef HAVE_LIBCRYPTO
- warning("crypto code not compiled in");
-#endif
ndo->ndo_espsecret = optarg;
break;
+#endif
case 'f':
++ndo->ndo_fflag;
break;
case 'G':
- Gflag = atoi(optarg);
- if (Gflag < 0)
- error("invalid number of seconds %s", optarg);
+ Gflag = parse_int("number of seconds", optarg, NULL, 0,
+ INT_MAX, 10);
/* We will create one file initially. */
Gflag_count = 0;
}
break;
+#ifdef HAVE_LIBCRYPTO
case 'M':
/* TCP-MD5 shared secret */
-#ifndef HAVE_LIBCRYPTO
- warning("crypto code not compiled in");
-#endif
ndo->ndo_sigsecret = optarg;
break;
+#endif
case 'n':
++ndo->ndo_nflag;
break;
case 's':
- ndo->ndo_snaplen = (int)strtol(optarg, &end, 0);
- if (optarg == end || *end != '\0'
- || ndo->ndo_snaplen < 0 || ndo->ndo_snaplen > MAXIMUM_SNAPLEN)
- error("invalid snaplen %s (must be >= 0 and <= %d)",
- optarg, MAXIMUM_SNAPLEN);
+ ndo->ndo_snaplen = parse_int("snaplen", optarg, NULL,
+ 0, MAXIMUM_SNAPLEN, 0);
break;
case 'S':
break;
case 'W':
- Wflag = atoi(optarg);
- if (Wflag <= 0)
- error("invalid number of output files %s", optarg);
+ Wflag = parse_int("number of output files", optarg,
+ NULL, 1, INT_MAX, 10);
WflagChars = getWflagChars(Wflag);
break;
}
break;
#endif
+
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
case 'z':
zflag = optarg;
break;
+#endif
case 'Z':
username = optarg;
case OPTION_PRINT_SAMPLING:
print = 1;
++ndo->ndo_Sflag;
- ndo->ndo_print_sampling = atoi(optarg);
- if (ndo->ndo_print_sampling <= 0)
- error("invalid print sampling %s", optarg);
+ ndo->ndo_print_sampling = parse_int("print sampling",
+ optarg, NULL, 1, INT_MAX, 10);
break;
case OPTION_SKIP:
- errno = 0;
- packets_skipped = (u_int)strtoul(optarg, &end, 0);
- if (optarg[0] == '-' || optarg == end || *end != '\0' ||
- errno != 0)
- error("invalid packet skipped %s", optarg);
+ packets_to_skip = parse_u_int("packet skip count",
+ optarg, NULL, 0, INT_MAX, 0);
break;
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
/* NOTREACHED */
}
+ if (ndo->ndo_Aflag && ndo->ndo_xflag)
+ error("-A and -x[x] are mutually exclusive.");
+ if (ndo->ndo_Aflag && ndo->ndo_Xflag)
+ error("-A and -X[X] are mutually exclusive.");
+ if (ndo->ndo_xflag && ndo->ndo_Xflag)
+ error("-x[x] and -X[X] are mutually exclusive.");
+ if (Cflag != 0 && WFileName == NULL)
+ error("-C cannot be used without -w.");
+ if (Gflag != 0 && WFileName == NULL)
+ error("-G cannot be used without -w.");
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
+ if (zflag != NULL && (WFileName == NULL || (Cflag == 0 && Gflag == 0)))
+ error("-z cannot be used without -w and (-C or -G).");
+#endif
+
+ if (cnt != -1)
+ if ((int)packets_to_skip > (INT_MAX - cnt))
+ // cnt + (int)packets_to_skip used in pcap_loop() call
+ error("Overflow (-c count) %d + (--skip count) %d", cnt,
+ (int)packets_to_skip);
+
if (Dflag)
show_devices_and_exit();
#ifdef HAVE_PCAP_FINDALLDEVS_EX
}
if (ndo->ndo_fflag != 0 && (VFileName != NULL || RFileName != NULL))
- error("-f can not be used with -V or -r");
+ error("-f cannot be used with -V or -r.");
if (VFileName != NULL && RFileName != NULL)
error("-V and -r are mutually exclusive.");
VFile = fopen(VFileName, "r");
if (VFile == NULL)
- error("Unable to open file: %s\n", pcap_strerror(errno));
+ error("Unable to open file: %s", pcap_strerror(errno));
ret = get_next_file(VFile, VFileLine);
if (!ret)
- error("Nothing in %s\n", VFileName);
+ error("Nothing in %s", VFileName);
RFileName = VFileLine;
}
#ifdef HAVE_PCAP_SET_OPTIMIZER_DEBUG
pcap_set_optimizer_debug(dflag);
#endif
- if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+ /*
+ * netmask is in network byte order, pcap_compile() takes it
+ * in host byte order.
+ */
+ if (pcap_compile(pd, &fcode, cmdbuf, Oflag, ntohl(netmask)) < 0)
error("%s", pcap_geterr(pd));
if (dflag) {
bpf_dump(&fcode, dflag);
capdns = capdns_setup();
#endif /* HAVE_CASPER */
+ // Both localnet and netmask are in network byte order.
init_print(ndo, localnet, netmask);
#ifndef _WIN32
do {
status = pcap_loop(pd,
- cnt + (cnt == -1 ? 0 : packets_skipped),
+ (cnt == -1 ? -1 : cnt + (int)packets_to_skip),
callback, pcap_userdata);
if (WFileName == NULL) {
/*
ndo->ndo_if_printer = get_if_printer(dlt);
/* Free the old filter */
pcap_freecode(&fcode);
- if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+ /*
+ * netmask is in network byte order, pcap_compile() takes it
+ * in host byte order.
+ */
+ if (pcap_compile(pd, &fcode, cmdbuf, Oflag, ntohl(netmask)) < 0)
error("%s", pcap_geterr(pd));
}
exit_tcpdump(status == -1 ? S_ERR_HOST_PROGRAM : S_SUCCESS);
}
+/*
+ * Routines to parse numerical command-line arguments and check for
+ * errors, including "too large for that type".
+ */
+static int
+parse_int(const char *argname, const char *string, char **endpp,
+ int minval, int maxval, int base)
+{
+ long val;
+ char *endp;
+
+ errno = 0;
+ val = strtol(string, &endp, base);
+
+ /*
+ * Did it either not parse any of the string, find extra stuff
+ * at the end that the caller isn't interested in, or get
+ * another parsing error?
+ */
+ if (string == endp || (endpp == NULL && *endp != '\0') ||
+ (val == 0 && errno == EINVAL)) {
+ error("invalid %s \"%s\" (not a valid number)", argname,
+ string);
+ }
+
+ /*
+ * Did it get a value that's out of range?
+ */
+ if (((val == LONG_MAX || val == LONG_MIN) && errno == ERANGE) ||
+ val < minval || val > maxval) {
+ error("invalid %s %s (must be >= %d and <= %d)",
+ argname, string, minval, maxval);
+ }
+
+ /*
+ * OK, it passes all the tests.
+ */
+ if (endpp != NULL)
+ *endpp = endp;
+ return ((int)val);
+}
+
+static u_int
+parse_u_int(const char *argname, const char *string, char **endpp,
+ u_int minval, u_int maxval, int base)
+{
+ unsigned long val;
+ char *endp;
+
+ errno = 0;
+
+ /*
+ * strtoul() does *NOT* report an error if the string
+ * begins with a minus sign. We do.
+ */
+ if (*string == '-') {
+ error("invalid %s \"%s\" (not a valid unsigned number)",
+ argname, string);
+ }
+
+ val = strtoul(string, &endp, base);
+
+ /*
+ * Did it either not parse any of the string, find extra stuff
+ * at the end that the caller isn't interested in, or get
+ * another parsing error?
+ */
+ if (string == endp || (endpp == NULL && *endp != '\0') ||
+ (val == 0 && errno == EINVAL)) {
+ error("invalid %s \"%s\" (not a valid unsigned number)",
+ argname, string);
+ }
+
+ /*
+ * Did it get a value that's out of range?
+ */
+ if ((val == ULONG_MAX && errno == ERANGE) ||
+ val < minval || val > maxval) {
+ error("invalid %s %s (must be >= %u and <= %u)",
+ argname, string, minval, maxval);
+ }
+
+ /*
+ * OK, it passes all the tests.
+ */
+ if (endpp != NULL)
+ *endpp = endp;
+ return ((u_int)val);
+}
+
+static int64_t
+parse_int64(const char *argname, const char *string, char **endpp,
+ int64_t minval, int64_t maxval, int base)
+{
+ intmax_t val;
+ char *endp;
+
+ errno = 0;
+ val = strtoimax(string, &endp, base);
+
+ /*
+ * Did it either not parse any of the string, find extra stuff
+ * at the end that the caller isn't interested in, or get
+ * another parsing error?
+ */
+ if (string == endp || (endpp == NULL && *endp != '\0') ||
+ (val == 0 && errno == EINVAL)) {
+ error("invalid %s \"%s\" (not a valid number)", argname,
+ string);
+ }
+
+ /*
+ * Did it get a value that's out of range?
+ */
+ if (((val == INTMAX_MAX || val == INTMAX_MIN) && errno == ERANGE) ||
+ val < minval || val > maxval) {
+ error("invalid %s %s (must be >= %" PRId64 " and <= %" PRId64 ")",
+ argname, string, minval, maxval);
+ }
+
+ /*
+ * OK, it passes all the tests.
+ */
+ if (endpp != NULL)
+ *endpp = endp;
+ return ((int64_t)val);
+}
+
/*
* Catch a signal.
*/
child = fork_subprocess();
if (child == -1) {
fprintf(stderr,
- "compress_savefile: fork failed: %s\n",
- pcap_strerror(errno));
+ "%s: fork failed: %s\n",
+ __func__, pcap_strerror(errno));
return;
}
if (child != 0) {
#endif
if (execlp(zflag, zflag, filename, (char *)NULL) == -1)
fprintf(stderr,
- "compress_savefile: execlp(%s, %s) failed: %s\n",
- zflag,
- filename,
- pcap_strerror(errno));
+ "%s: execlp(%s, %s) failed: %s\n",
+ __func__, zflag, filename, pcap_strerror(errno));
#ifdef HAVE_FORK
exit(S_ERR_HOST_PROGRAM);
#else
_exit(S_ERR_HOST_PROGRAM);
#endif
}
-#else /* HAVE_FORK && HAVE_VFORK */
-static void
-compress_savefile(const char *filename)
-{
- fprintf(stderr,
- "compress_savefile failed. Functionality not implemented under your system\n");
-}
-#endif /* HAVE_FORK && HAVE_VFORK */
+#endif /* HAVE_FORK || HAVE_VFORK */
static void
close_old_dump_file(struct dump_info *dump_info)
*/
pcap_dump_close(dump_info->pdd);
+#if defined(HAVE_FORK) || defined(HAVE_VFORK)
/*
* Compress the file we just closed, if the user asked for it.
*/
if (zflag != NULL)
compress_savefile(dump_info->CurrentFileName);
+#endif
}
static void
dump_info = (struct dump_info *)user;
- if (packets_captured <= packets_skipped)
+ if (packets_captured <= packets_to_skip)
return;
/*
dump_info = (struct dump_info *)user;
- if (packets_captured <= packets_skipped)
+ if (packets_captured <= packets_to_skip)
return;
pcap_dump((u_char *)dump_info->pdd, h, sp);
++infodelay;
- if (!count_mode && packets_captured > packets_skipped)
+ if (!count_mode && packets_captured > packets_to_skip)
pretty_print_packet((netdissect_options *)user, h, sp, packets_captured);
--infodelay;
(void)fprintf(f,
"Usage: %s [-AbdDefhHI" J_FLAG "KlLnNOpqStuUvxX#] [ -B size ] [ -c count ] [--count]\n", program_name);
(void)fprintf(f,
-"\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
+"\t\t[ -C file_size ] " E_FLAG_USAGE "[ -F file ] [ -G seconds ]\n");
(void)fprintf(f,
"\t\t[ -i interface ]" IMMEDIATE_MODE_USAGE j_FLAG_USAGE "\n");
(void)fprintf(f,
"\t\t" m_FLAG_USAGE "\n");
#endif
(void)fprintf(f,
-"\t\t[ -M secret ] [ --number ] [ --print ]\n");
+"\t\t" M_FLAG_USAGE "[ --number ] [ --print ]\n");
(void)fprintf(f,
"\t\t[ --print-sampling nth ] [ -Q in|out|inout ] [ -r file ]\n");
(void)fprintf(f,
-"\t\t[ -s snaplen ] [ -T type ] [ --version ]\n");
+"\t\t[ -s snaplen ] [ --skip count ] [ -T type ] [ --version ]\n");
(void)fprintf(f,
"\t\t[ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ]\n");
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
"\t\t[ --time-stamp-precision precision ] [ --micro ] [ --nano ]\n");
#endif
(void)fprintf(f,
-"\t\t[ -z postrotate-command ] [ -Z user ] [ expression ]\n");
+"\t\t" z_FLAG_USAGE "[ -Z user ] [ expression ]\n");
}