> This mail contains changes required to the kernel, subsequent ones have the > (most complicated) tcpdump(8) bit and (untested) pcap(3) bit.
tcpdump(8) change follows: Index: usr.sbin/tcpdump/privsep.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/privsep.c,v retrieving revision 1.30 diff -u -p -r1.30 privsep.c --- usr.sbin/tcpdump/privsep.c 22 Sep 2011 09:12:30 -0000 1.30 +++ usr.sbin/tcpdump/privsep.c 19 Mar 2013 15:09:52 -0000 @@ -18,6 +18,7 @@ */ #include <sys/types.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/wait.h> @@ -125,6 +126,41 @@ static void impl_getlines(int); static void test_state(int, int); static void logmsg(int, const char *, ...); + +static u_int32_t +find_queue(const char *device, const char *queue) +{ + int fd; + u_int32_t q, total; + struct pfioc_altq pa; + + if ((fd = open("/dev/pf", O_RDONLY)) == -1) + err(2, "can't open pf to get queue ID"); + + memset(&pa, 0, sizeof pa); + if (ioctl(fd, DIOCGETALTQS, &pa)) + err(2, "DIOCGETALTQS"); + + total = pa.nr; + for (q = 0; q < total; ++q) { + pa.nr = q; + if (ioctl(fd, DIOCGETALTQ, &pa)) + err(2, "DIOCGETALTQ, number %u", q); + if (pa.altq.qid == 0) + continue; + if (strncmp(pa.altq.ifname, device, sizeof pa.altq.ifname)) + continue; + if (strncmp(pa.altq.qname, queue, sizeof pa.altq.qname)) + continue; + break; + } + close(fd); + if (q == total) + warnx("WARNING: no queue %s on interface %s, choosing all", + queue, device); + return (q == total ? 0 : pa.altq.qid); +} + int priv_init(int argc, char **argv) { @@ -200,7 +236,7 @@ priv_init(int argc, char **argv) /* parse the arguments for required options */ opterr = 0; while ((i = getopt(argc, argv, - "ac:D:deE:fF:i:lLnNOopqr:s:StT:vw:xXy:Y")) != -1) { + "ac:D:deE:fF:i:lLnNOopQ:qr:s:StT:vw:xXy:Y")) != -1) { switch (i) { case 'n': nflag++; @@ -320,8 +356,9 @@ impl_open_bpf(int fd, int *bpfd) { int snaplen, promisc, err; u_int dlt, dirfilt; - char device[IFNAMSIZ]; - size_t iflen; + u_int32_t qid = 0; + char device[IFNAMSIZ], queue[PF_QNAME_SIZE]; + size_t iflen, qlen; logmsg(LOG_DEBUG, "[priv]: msg PRIV_OPEN_BPF received"); @@ -332,7 +369,10 @@ impl_open_bpf(int fd, int *bpfd) iflen = read_string(fd, device, sizeof(device), __func__); if (iflen == 0) errx(1, "Invalid interface size specified"); - *bpfd = pcap_live(device, snaplen, promisc, dlt, dirfilt); + qlen = read_string(fd, queue, sizeof queue, __func__); + if (qlen > 1) + qid = find_queue(device, queue); + *bpfd = pcap_live(device, snaplen, promisc, dlt, dirfilt, qid); err = errno; if (*bpfd < 0) logmsg(LOG_DEBUG, Index: usr.sbin/tcpdump/privsep.h =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/privsep.h,v retrieving revision 1.7 diff -u -p -r1.7 privsep.h --- usr.sbin/tcpdump/privsep.h 25 Aug 2009 06:59:17 -0000 1.7 +++ usr.sbin/tcpdump/privsep.h 19 Mar 2013 15:09:52 -0000 @@ -47,11 +47,11 @@ int priv_init(int, char **); void priv_init_done(void); int setfilter(int, int, char *); -int pcap_live(const char *, int, int, u_int, u_int); +int pcap_live(const char *, int, int, u_int, u_int, u_int32_t); struct bpf_program *priv_pcap_setfilter(pcap_t *, int, u_int32_t); pcap_t *priv_pcap_live(const char *, int, int, int, char *, u_int, - u_int); + u_int, const char *); pcap_t *priv_pcap_offline(const char *, char *); size_t priv_gethostbyaddr(char *, size_t, int, char *, size_t); Index: usr.sbin/tcpdump/privsep_pcap.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/privsep_pcap.c,v retrieving revision 1.17 diff -u -p -r1.17 privsep_pcap.c --- usr.sbin/tcpdump/privsep_pcap.c 14 Nov 2012 03:33:04 -0000 1.17 +++ usr.sbin/tcpdump/privsep_pcap.c 19 Mar 2013 15:09:52 -0000 @@ -173,7 +173,7 @@ priv_pcap_setfilter(pcap_t *hpcap, int o /* privileged part of priv_pcap_live */ int pcap_live(const char *device, int snaplen, int promisc, u_int dlt, - u_int dirfilt) + u_int dirfilt, u_int32_t qid) { char bpf[sizeof "/dev/bpf0000000000"]; int fd, n = 0; @@ -206,6 +206,8 @@ pcap_live(const char *device, int snaple ioctl(fd, BIOCPROMISC, NULL); if (ioctl(fd, BIOCSDIRFILT, &dirfilt) < 0) goto error; + if (qid && ioctl(fd, BIOCSQUEUE, &qid) < 0) + goto error; /* lock the descriptor */ if (ioctl(fd, BIOCLOCK, NULL) < 0) @@ -224,7 +226,7 @@ pcap_live(const char *device, int snaple */ pcap_t * priv_pcap_live(const char *dev, int slen, int prom, int to_ms, - char *ebuf, u_int dlt, u_int dirfilt) + char *ebuf, u_int dlt, u_int dirfilt, const char *queue) { int fd, err; struct bpf_version bv; @@ -254,6 +256,7 @@ priv_pcap_live(const char *dev, int slen must_write(priv_fd, &dlt, sizeof(u_int)); must_write(priv_fd, &dirfilt, sizeof(u_int)); write_string(priv_fd, dev); + write_string(priv_fd, queue); fd = receive_fd(priv_fd); must_read(priv_fd, &err, sizeof(int)); Index: usr.sbin/tcpdump/tcpdump.8 =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.8,v retrieving revision 1.79 diff -u -p -r1.79 tcpdump.8 --- usr.sbin/tcpdump/tcpdump.8 26 Sep 2012 16:19:45 -0000 1.79 +++ usr.sbin/tcpdump/tcpdump.8 19 Mar 2013 15:09:52 -0000 @@ -35,6 +35,7 @@ .Ar espkey Oc .Op Fl F Ar file .Op Fl i Ar interface +.Op Fl Q Ar queue .Op Fl r Ar file .Op Fl s Ar snaplen .Op Fl T Ar type @@ -176,6 +177,14 @@ cannot be used as an abbreviation for .Dq ether host \&"{local-hw-addr}\&" or .Dq ether broadcast . +.It Fl Q Ar queue +Display only traffic going out of this queue (see +.Xr altq 9 +or +.Xr pf 4 +for reference). +If no such queue exists on the selected interface, a warning is displayed. +Note that queueing applies only to outbound traffic. .It Fl q Quick .Pq quiet? Index: usr.sbin/tcpdump/tcpdump.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.c,v retrieving revision 1.65 diff -u -p -r1.65 tcpdump.c --- usr.sbin/tcpdump/tcpdump.c 11 Jul 2012 10:37:38 -0000 1.65 +++ usr.sbin/tcpdump/tcpdump.c 19 Mar 2013 15:09:52 -0000 @@ -82,6 +82,7 @@ int packettype; char *program_name; char *device = NULL; +char *queue = NULL, noqueue[1] = ""; int32_t thiszone; /* seconds offset from gmt to local time */ @@ -229,7 +230,7 @@ main(int argc, char **argv) opterr = 0; while ((op = getopt(argc, argv, - "Aac:D:deE:fF:i:IlLnNOopqr:s:StT:vw:xXy:Y")) != -1) + "Aac:D:deE:fF:i:IlLnNOopQ:qr:s:StT:vw:xXy:Y")) != -1) switch (op) { case 'A': @@ -309,6 +310,10 @@ main(int argc, char **argv) ++pflag; break; + case 'Q': + queue = optarg; + break; + case 'q': ++qflag; break; @@ -432,8 +437,12 @@ main(int argc, char **argv) if (device == NULL) error("%s", ebuf); } + if (queue == NULL) + queue = noqueue; + else if (dirfilt == BPF_DIRECTION_OUT) + error("queueing happens on -D way OUT!"); pd = priv_pcap_live(device, snaplen, !pflag, 1000, ebuf, - dlt, dirfilt); + dlt, dirfilt, queue); if (pd == NULL) error("%s", ebuf); @@ -487,10 +496,12 @@ main(int argc, char **argv) /* state: STATE_RUN */ } if (RFileName == NULL) { - (void)fprintf(stderr, "%s: listening on %s, link-type ", - program_name, device); + fprintf(stderr, "%s: listening on %s", program_name, device); + if (queue && queue != noqueue) + fprintf(stderr, ", queue %s", queue); + fprintf(stderr, ", link-type "); pcap_print_linktype(pd->linktype); - (void)fflush(stderr); + fflush(stderr); } if (oflag)