static u_int packets_captured;
struct printer {
- if_printer f;
- int type;
-};
-
-
-struct ndo_printer {
- if_ndo_printer f;
+ if_printer f;
int type;
};
static const struct printer printers[] = {
- { NULL, 0 },
-};
-
-static const struct ndo_printer ndo_printers[] = {
{ ether_if_print, DLT_EN10MB },
#ifdef DLT_IPNET
{ ipnet_if_print, DLT_IPNET },
if (type == p->type)
return p->f;
- return NULL;
- /* NOTREACHED */
-}
-
-if_ndo_printer
-lookup_ndo_printer(int type)
-{
- const struct ndo_printer *p;
-
- for (p = ndo_printers; p->f; ++p)
- if (type == p->type)
- return p->f;
-
#if defined(DLT_USER2) && defined(DLT_PKTAP)
/*
* Apple incorrectly chose to use DLT_USER2 for their PKTAP
* that.
*/
if (type == DLT_USER2) {
- for (p = ndo_printers; p->f; ++p)
+ for (p = printers; p->f; ++p)
if (DLT_PKTAP == p->type)
return p->f;
}
struct print_info {
netdissect_options *ndo;
- union {
- if_printer printer;
- if_ndo_printer ndo_printer;
- } p;
- int ndo_type;
+ if_printer printer;
};
struct dump_info {
/*
* OK, does tcpdump handle that type?
*/
- if (lookup_printer(dlts[n_dlts]) == NULL
- && lookup_ndo_printer(dlts[n_dlts]) == NULL)
+ if (lookup_printer(dlts[n_dlts]) == NULL)
(void) fprintf(stderr, " (printing not supported)");
fprintf(stderr, "\n");
} else {
*
* OS X tcpdump uses -P to indicate that -w should write pcap-ng rather
* than pcap files.
+ *
+ * OS X tcpdump also uses -Q to specify expressions that match packet
+ * metadata, including but not limited to the packet direction.
+ * The expression syntax is different from a simple "in|out|inout",
+ * and those expressions aren't accepted by OS X tcpdump, but the
+ * equivalents would be "in" = "dir=in", "out" = "dir=out", and
+ * "inout" = "dir=in or dir=out", and the parser could conceivably
+ * special-case "in", "out", and "inout" as expressions for backwards
+ * compatibility, so all is not (yet) lost.
*/
/*
#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:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#"
+
/*
* Long options.
*
{
struct print_info printinfo;
- printinfo.ndo_type = 1;
printinfo.ndo = gndo;
- printinfo.p.ndo_printer = lookup_ndo_printer(type);
- if (printinfo.p.ndo_printer == NULL) {
- printinfo.p.printer = lookup_printer(type);
- printinfo.ndo_type = 0;
- if (printinfo.p.printer == NULL) {
- gndo->ndo_dltname = pcap_datalink_val_to_name(type);
- if (gndo->ndo_dltname != NULL)
- error("packet printing is not supported for link type %s: use -w",
- gndo->ndo_dltname);
- else
- error("packet printing is not supported for link type %d: use -w", type);
- }
+ printinfo.printer = lookup_printer(type);
+ if (printinfo.printer == NULL) {
+ gndo->ndo_dltname = pcap_datalink_val_to_name(type);
+ if (gndo->ndo_dltname != NULL)
+ error("packet printing is not supported for link type %s: use -w",
+ gndo->ndo_dltname);
+ else
+ error("packet printing is not supported for link type %d: use -w", type);
}
return (printinfo);
}
}
#endif
+#ifdef HAVE_CAPSICUM
+/*
+ * Ensure that, on a dump file's descriptor, we have all the rights
+ * necessary to make the standard I/O library work with an fdopen()ed
+ * FILE * from that descriptor.
+ *
+ * A long time ago, in a galaxy far far away, AT&T decided that, instead
+ * of providing separate APIs for getting and setting the FD_ flags on a
+ * descriptor, getting and setting the O_ flags on a descriptor, and
+ * locking files, they'd throw them all into a kitchen-sink fcntl() call
+ * along the lines of ioctl(), the fact that ioctl() operations are
+ * largely specific to particular character devices but fcntl() operations
+ * are either generic to all descriptors or generic to all descriptors for
+ * regular files nonwithstanding.
+ *
+ * The Capsicum people decided that fine-grained control of descriptor
+ * operations was required, so that you need to grant permission for
+ * reading, writing, seeking, and fcntl-ing. The latter, courtesy of
+ * AT&T's decision, means that "fcntl-ing" isn't a thing, but a motley
+ * collection of things, so there are *individual* fcntls for which
+ * permission needs to be granted.
+ *
+ * The FreeBSD standard I/O people implemented some optimizations that
+ * requires that the standard I/O routines be able to determine whether
+ * the descriptor for the FILE * is open append-only or not; as that
+ * descriptor could have come from an open() rather than an fopen(),
+ * that requires that it be able to do an F_GETFL fcntl() to read
+ * the O_ flags.
+ *
+ * Tcpdump uses ftell() to determine how much data has been written
+ * to a file in order to, when used with -C, determine when it's time
+ * to rotate capture files. ftell() therefore needs to do an lseek()
+ * to find out the file offset and must, thanks to the aforementioned
+ * optimization, also know whether the descriptor is open append-only
+ * or not.
+ *
+ * The net result of all the above is that we need to grant CAP_SEEK,
+ * CAP_WRITE, and CAP_FCNTL with the CAP_FCNTL_GETFL subcapability.
+ *
+ * Perhaps this is the universe's way of saying that either
+ *
+ * 1) there needs to be an fopenat() call and a pcap_dump_openat() call
+ * using it, so that Capsicum-capable tcpdump wouldn't need to do
+ * an fdopen()
+ *
+ * or
+ *
+ * 2) there needs to be a cap_fdopen() call in the FreeBSD standard
+ * I/O library that knows what rights are needed by the standard
+ * I/O library, based on the open mode, and assigns them, perhaps
+ * with an additional argument indicating, for example, whether
+ * seeking should be allowed, so that tcpdump doesn't need to know
+ * what the standard I/O library happens to require this week.
+ */
+static void
+set_dumper_capsicum_rights(pcap_dumper_t *p)
+{
+ int fd = fileno(pcap_dump_file(p));
+ cap_rights_t rights;
+
+ cap_rights_init(&rights, CAP_SEEK, CAP_WRITE, CAP_FCNTL);
+ if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) {
+ error("unable to limit dump descriptor");
+ }
+ if (cap_fcntls_limit(fd, CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) {
+ error("unable to limit dump descriptor fcntls");
+ }
+}
+#endif
+
int
main(int argc, char **argv)
{
#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, SHORTOPTS, longopts, NULL)) != -1)
switch (op) {
case 'a':
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");
- }
+ set_dumper_capsicum_rights(p);
#endif
if (Cflag != 0 || Gflag != 0) {
#ifdef HAVE_CAPSICUM
errno != ENOSYS) {
error("unable to limit directory rights");
}
+ if (cap_fcntls_limit(dumpinfo.dirfd, CAP_FCNTL_GETFL) < 0 &&
+ errno != ENOSYS) {
+ error("unable to limit dump descriptor fcntls");
+ }
#else /* !HAVE_CAPSICUM */
dumpinfo.WFileName = WFileName;
#endif
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 (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");
- }
+ set_dumper_capsicum_rights(dump_info->p);
#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");
- }
+ set_dumper_capsicum_rights(dump_info->p);
#endif
}
}
*/
ndo->ndo_snapend = sp + h->caplen;
- if(print_info->ndo_type) {
- hdrlen = (*print_info->p.ndo_printer)(print_info->ndo, h, sp);
- } else {
- hdrlen = (*print_info->p.printer)(h, sp);
- }
+ hdrlen = (*print_info->printer)(print_info->ndo, h, sp);
/*
* Restore the original snapend, as a printer might have