> 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)

Reply via email to