#define uint UINT
#endif /* WIN32 */
-#ifdef HAVE_SMI_H
+#ifdef USE_LIBSMI
#include <smi.h>
#endif
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/crypto.h>
+#endif
+
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#ifdef HAVE_CAPSICUM
+#include <sys/capability.h>
+#include <sys/ioccom.h>
+#include <net/bpf.h>
+#include <fcntl.h>
+#include <libgen.h>
+#endif /* HAVE_CAPSICUM */
#ifndef WIN32
#include <sys/wait.h>
#include <sys/resource.h>
/* 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 *);
char *CurrentFileName;
pcap_t *pd;
pcap_dumper_t *p;
+#ifdef HAVE_CAPSICUM
+ int dirfd;
+#endif
};
#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
* doesn't make sense; it should be --verbosity={N} or something such
* as that.
*
- * We do not currently have long options with no corresponding short
- * options; for those, we should 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.
+ * 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.
*/
-static struct option longopts[] = {
+#define OPTION_VERSION 128
+#define OPTION_TSTAMP_PRECISION 129
+
+static const struct option longopts[] = {
#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
{ "buffer-size", required_argument, NULL, 'B' },
#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' },
{ "debug-filter-parser", no_argument, NULL, 'Y' },
#endif
{ "relinquish-privileges", required_argument, NULL, 'Z' },
- { "number", no_argument, NULL, 'z' + 1},
+ { "number", no_argument, NULL, '#' },
+ { "version", no_argument, NULL, OPTION_VERSION },
{ NULL, 0, NULL, 0 }
};
#ifdef HAVE_CAP_NG_H
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 {
+ printf("dropped privs to %s\n", username);
}
/* We don't need CAP_SETUID and CAP_SETGID */
capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID);
pcap_strerror(errno));
exit(1);
}
+ else {
+ printf("dropped privs to %s\n", username);
+ }
#endif /* HAVE_CAP_NG_H */
}
else {
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
+
int
main(int argc, char **argv)
{
#endif
int status;
FILE *VFile;
+#ifdef HAVE_CAPSICUM
+ cap_rights_t rights;
+ int cansandbox;
+#endif /* HAVE_CAPSICUM */
+
#ifdef WIN32
if(wsockinit() != 0) return 1;
#endif /* WIN32 */
if (abort_on_misalignment(ebuf, sizeof(ebuf)) < 0)
error("%s", ebuf);
-#ifdef LIBSMI
+#ifdef USE_LIBSMI
smiInit("tcpdump");
#endif
while (
- (op = getopt_long(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:", longopts, NULL)) != -1)
+ (op = getopt_long(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:#", longopts, NULL)) != -1)
switch (op) {
case 'a':
break;
case 'h':
- usage();
+ print_usage();
+ exit(0);
break;
case 'H':
break;
case 'm':
-#ifdef LIBSMI
+#ifdef USE_LIBSMI
if (smiLoadModule(optarg) == 0) {
error("could not load MIB module %s", optarg);
}
username = strdup(optarg);
break;
- case 'z' + 1:
+ 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
+
default:
- usage();
+ print_usage();
+ exit(1);
/* NOTREACHED */
}
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) {
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
+
/*
* Is this an interface that supports monitor mode?
*/
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. */
#endif
if (p == NULL)
error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+ cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(pcap_dump_file(p)), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("unable to limit dump descriptor");
+ }
+#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");
+ }
+#else /* !HAVE_CAPSICUM */
dumpinfo.WFileName = WFileName;
+#endif
+ callback = dump_packet_and_trunc;
dumpinfo.pd = pd;
dumpinfo.p = p;
pcap_userdata = (u_char *)&dumpinfo;
(void)fflush(stderr);
}
#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) {
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);
dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
{
struct dump_info *dump_info;
+#ifdef HAVE_CAPSICUM
+ cap_rights_t rights;
+#endif
++packets_captured;
/* 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 */
capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
capng_apply(CAPNG_EFFECTIVE);
#endif /* HAVE_CAP_NG_H */
+#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_CAP_NG_H
capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
capng_apply(CAPNG_EFFECTIVE);
#endif /* HAVE_CAP_NG_H */
if (dump_info->p == NULL)
error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+ cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
+ &rights) < 0 && errno != ENOSYS) {
+ error("unable to limit dump descriptor");
+ }
+#endif
}
}
* file could put it over Cflag.
*/
if (Cflag != 0 && pcap_dump_ftell(dump_info->p) > Cflag) {
+#ifdef HAVE_CAPSICUM
+ FILE *fp;
+ int fd;
+#endif
+
/*
* Close the current file and open a new one.
*/
if (dump_info->CurrentFileName == NULL)
error("dump_packet_and_trunc: malloc");
MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
+#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
if (dump_info->p == NULL)
error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+ cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
+ &rights) < 0 && errno != ENOSYS) {
+ error("unable to limit dump descriptor");
+ }
+#endif
}
pcap_dump((u_char *)dump_info->p, h, sp);
/*
* 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;
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.
}
#endif
+USES_APPLE_DEPRECATED_API
static void
-usage(void)
+print_version(void)
{
extern char version[];
#ifndef HAVE_PCAP_LIB_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);
+#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[ -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[ -W filecount ] [ -y datalinktype ] [ -z command ]\n");
+"\t\t");
+#endif
+ (void)fprintf(stderr, "[ -T type ] [ --version ] [ -V file ]\n");
+ (void)fprintf(stderr,
+"\t\t[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z command ]\n");
(void)fprintf(stderr,
"\t\t[ -Z user ] [ expression ]\n");
- exit(1);
}