[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    tcpdump(8) USB support
From:       Martin Pieuchot <mpi () openbsd ! org>
Date:       2018-01-25 18:00:43
Message-ID: 20180125180043.GA28671 () oliva ! grenadille ! net
[Download RAW message or body]

Diff below adds support for dumping USB transfers via bpf(4), including
the tcpdump(8) bits.

I'd like special review of the new bpf_tap(9) function I'm introducing:
  - is there a way to pass the header as a different buffer?
  - is _bpf_tap() the best way to share code with bpf_mtap(9)?

Concerning the kernel/userland interface, in looked at the existing
DLT_USB*, namely:
	- DLT_USB_FREEBSD (a.k.a DLT_USB)
	- DLT_USB_LINUX
	- DLT_USB_LINUX_MMAPPED
	- DLT_USBPCAP
	- DLT_USB_DARWIN

I decided to follow DLT_USBPCAP which is the most generic one beside
being originated from Windows.  Wireshark has some support for it
(currently untested) so it is a nice fit.
The current implementation is small and I'd like to continue developing
it in tree.

Here's an excerpt of what's happening when plugging a USB key: 

     # tcpdump -xXi usb0
     tcpdump: listening on usb0, link-type USBPCAP
     [...]
     18:56:26.261293 bus 0 > addr 5: ep0 ctrl 0
     
     18:56:26.261409 bus 0 < addr 5: ep0 ctrl 20
       0000: 1403 5300 6c00 6900 6d00 2000 4c00 6900  ..S.l.i.m. .L.i.
       0010: 6e00 6500                                n.e.
     
     18:56:26.261418 bus 0 > addr 5: ep0 ctrl 0
     
     18:56:26.261547 bus 0 < addr 5: ep0 ctrl 2
       0000: 2203                                     ".
     
     18:56:26.261552 bus 0 > addr 5: ep0 ctrl 0
     
     18:56:26.261746 bus 0 < addr 5: ep0 ctrl 34
       0000: 2203 3000 3700 3100 3000 3500 3900 3600  ".0.7.1.0.5.9.6.
       0010: 3100 4100 3400 3800 4400 3600 4100 3900  1.A.4.8.D.6.A.9.
       0020: 3500                                     5.
     
     18:56:26.261761 bus 0 > addr 5: ep2 bulk 31
       0000: 5553 4243 4c00 0000 0000 0000 0000 0600  USBCL...........
       0010: 0000 0000 0000 0000 0000 0000 0000 00    ...............

Ok to put it in tree?

Index: sys/net/bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.166
diff -u -p -r1.166 bpf.c
--- sys/net/bpf.c	24 Jan 2018 00:25:17 -0000	1.166
+++ sys/net/bpf.c	25 Jan 2018 14:02:58 -0000
@@ -1226,35 +1226,24 @@ bpf_mcopy(const void *src_arg, void *dst
 	}
 }
 
-/*
- * like bpf_mtap, but copy fn can be given. used by various bpf_mtap*
- */
 int
-_bpf_mtap(caddr_t arg, const struct mbuf *m, u_int direction,
-    void (*cpfn)(const void *, void *, size_t))
+_bpf_tap(caddr_t arg, u_char *pkt, size_t pktlen, u_int direction,
+    void (*cpfn)(const void *, void *, size_t), int mfilter)
 {
 	struct bpf_if *bp = (struct bpf_if *)arg;
 	struct srp_ref sr;
 	struct bpf_d *d;
-	size_t pktlen, slen;
-	const struct mbuf *m0;
+	size_t slen;
 	struct timeval tv;
 	int gottime = 0;
 	int drop = 0;
 
-	if (m == NULL)
+	if (pkt == NULL)
 		return (0);
 
-	if (cpfn == NULL)
-		cpfn = bpf_mcopy;
-
 	if (bp == NULL)
 		return (0);
 
-	pktlen = 0;
-	for (m0 = m; m0 != NULL; m0 = m0->m_next)
-		pktlen += m0->m_len;
-
 	SRPL_FOREACH(d, &sr, &bp->bif_dlist, bd_next) {
 		atomic_inc_long(&d->bd_rcount);
 
@@ -1268,7 +1257,11 @@ _bpf_mtap(caddr_t arg, const struct mbuf
 			bf = srp_enter(&bsr, &d->bd_rfilter);
 			if (bf != NULL)
 				fcode = bf->bf_insns;
-			slen = bpf_mfilter(fcode, m, pktlen);
+			if (mfilter) {
+				const struct mbuf *m = (const struct mbuf *)pkt;
+				slen = bpf_mfilter(fcode, m, pktlen);
+			} else
+				slen = bpf_filter(fcode, pkt, pktlen, pktlen);
 			srp_leave(&bsr);
 		}
 
@@ -1277,8 +1270,7 @@ _bpf_mtap(caddr_t arg, const struct mbuf
 				microtime(&tv);
 
 			mtx_enter(&d->bd_mtx);
-			bpf_catchpacket(d, (u_char *)m, pktlen, slen, cpfn,
-			    &tv);
+			bpf_catchpacket(d, pkt, pktlen, slen, cpfn, &tv);
 			mtx_leave(&d->bd_mtx);
 
 			if (d->bd_fildrop)
@@ -1290,6 +1282,35 @@ _bpf_mtap(caddr_t arg, const struct mbuf
 	return (drop);
 }
 
+int
+bpf_tap(caddr_t arg, u_char *pkt, size_t pktlen, u_int direction)
+{
+	return _bpf_tap(arg, pkt, pktlen, direction, bcopy, 0);
+}
+
+/*
+ * like bpf_mtap, but copy fn can be given. used by various bpf_mtap*
+ */
+int
+_bpf_mtap(caddr_t arg, const struct mbuf *m, u_int direction,
+    void (*cpfn)(const void *, void *, size_t))
+{
+	const struct mbuf *m0;
+	size_t pktlen;
+
+	if (m == NULL)
+		return (0);
+
+	if (cpfn == NULL)
+		cpfn = bpf_mcopy;
+
+	pktlen = 0;
+	for (m0 = m; m0 != NULL; m0 = m0->m_next)
+		pktlen += m0->m_len;
+
+	return _bpf_tap(arg, (u_char *)m, pktlen, direction, cpfn, 1);
+}
+
 /*
  * Incoming linkage from device drivers, when packet is in an mbuf chain.
  */
@@ -1790,7 +1811,7 @@ bpf_mbuf_copy(const struct mbuf *m, u_in
 
 	for (;;) {
 		count = min(m->m_len - off, len);
-		
+
 		memcpy(cp, m->m_data + off, count);
 		len -= count;
 
Index: sys/net/bpf.h
===================================================================
RCS file: /cvs/src/sys/net/bpf.h,v
retrieving revision 1.63
diff -u -p -r1.63 bpf.h
--- sys/net/bpf.h	24 Jan 2018 00:25:17 -0000	1.63
+++ sys/net/bpf.h	25 Jan 2018 16:06:35 -0000
@@ -201,6 +201,7 @@ struct bpf_hdr {
 #define DLT_USER13		160	/* Reserved for private use */
 #define DLT_USER14		161	/* Reserved for private use */
 #define DLT_USER15		162	/* Reserved for private use */
+#define DLT_USBPCAP		249	/* USBPcap */
 #define DLT_MPLS		219	/* MPLS Provider Edge header */
 #define DLT_OPENFLOW		267	/* in-kernel OpenFlow, by pcap */
 
@@ -306,6 +307,7 @@ struct ifnet;
 struct mbuf;
 
 int	 bpf_validate(struct bpf_insn *, int);
+int	 bpf_tap(caddr_t arg, u_char *, size_t, u_int);
 int	 bpf_mtap(caddr_t, const struct mbuf *, u_int);
 int	 bpf_mtap_hdr(caddr_t, caddr_t, u_int, const struct mbuf *, u_int,
 	    void (*)(const void *, void *, size_t));
Index: usr.sbin/tcpdump/Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/Makefile,v
retrieving revision 1.62
diff -u -p -r1.62 Makefile
--- usr.sbin/tcpdump/Makefile	30 Oct 2017 10:07:44 -0000	1.62
+++ usr.sbin/tcpdump/Makefile	25 Jan 2018 17:10:15 -0000
@@ -49,7 +49,7 @@ SRCS=	tcpdump.c addrtoname.c privsep.c p
 	print-etherip.c print-lwres.c print-lldp.c print-cdp.c print-pflog.c \
 	print-pfsync.c pf_print_state.c print-ofp.c ofp_map.c \
 	print-udpencap.c print-carp.c \
-	print-802_11.c print-iapp.c print-mpls.c print-slow.c \
+	print-802_11.c print-iapp.c print-mpls.c print-slow.c print-usbpcap.c \
 	gmt2local.c savestr.c setsignal.c in_cksum.c
 
 # TCP OS Fingerprinting
Index: usr.sbin/tcpdump/interface.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v
retrieving revision 1.69
diff -u -p -r1.69 interface.h
--- usr.sbin/tcpdump/interface.h	16 Nov 2016 13:47:27 -0000	1.69
+++ usr.sbin/tcpdump/interface.h	25 Jan 2018 17:13:09 -0000
@@ -276,6 +276,8 @@ extern void slow_print(const u_char *, u
 extern void gtp_print(const u_char *, u_int, u_short, u_short);
 extern void ofp_print(const u_char *, u_int);
 extern void ofp_if_print(u_char *, const struct pcap_pkthdr *, const u_char *);
+extern void usbpcap_if_print(u_char *, const struct pcap_pkthdr *,
+    const u_char *);
 
 #ifdef INET6
 extern void ip6_print(const u_char *, u_int);
Index: usr.sbin/tcpdump/tcpdump.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.c,v
retrieving revision 1.81
diff -u -p -r1.81 tcpdump.c
--- usr.sbin/tcpdump/tcpdump.c	8 Dec 2017 17:04:15 -0000	1.81
+++ usr.sbin/tcpdump/tcpdump.c	25 Jan 2018 17:10:08 -0000
@@ -127,6 +127,7 @@ static struct printer printers[] = {
 	{ ieee802_11_if_print,		DLT_IEEE802_11 },
 	{ ieee802_11_radio_if_print,	DLT_IEEE802_11_RADIO },
 	{ ofp_if_print,			DLT_OPENFLOW },
+	{ usbpcap_if_print,		DLT_USBPCAP },
 	{ NULL,				0 },
 };
 
Index: lib/libpcap/gencode.c
===================================================================
RCS file: /cvs/src/lib/libpcap/gencode.c,v
retrieving revision 1.46
diff -u -p -r1.46 gencode.c
--- lib/libpcap/gencode.c	20 Nov 2016 12:45:26 -0000	1.46
+++ lib/libpcap/gencode.c	25 Jan 2018 17:09:17 -0000
@@ -787,6 +787,8 @@ init_linktype(type)
 		off_nl = 12;
 		return;
 
+	case DLT_USBPCAP:
+		/* FALLTHROUGH */
 	case DLT_RAW:
 		off_linktype = -1;
 		off_nl = 0;
Index: lib/libpcap/pcap.c
===================================================================
RCS file: /cvs/src/lib/libpcap/pcap.c,v
retrieving revision 1.20
diff -u -p -r1.20 pcap.c
--- lib/libpcap/pcap.c	16 Nov 2016 13:47:27 -0000	1.20
+++ lib/libpcap/pcap.c	25 Jan 2018 17:09:23 -0000
@@ -326,6 +326,7 @@ DLT_CHOICE(DLT_IEEE802_11, "IEEE 802.11 
 DLT_CHOICE(DLT_PFLOG, "Packet filter logging, by pcap people"),
 DLT_CHOICE(DLT_IEEE802_11_RADIO, "IEEE 802.11 plus WLAN header"),
 DLT_CHOICE(DLT_OPENFLOW, "OpenFlow"),
+DLT_CHOICE(DLT_USBPCAP, "USB"),
 #undef DLT_CHOICE
 	{ NULL, NULL, -1}
 };
Index: sys/dev/usb/usb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.114
diff -u -p -r1.114 usb.c
--- sys/dev/usb/usb.c	29 Jul 2017 18:26:14 -0000	1.114
+++ sys/dev/usb/usb.c	25 Jan 2018 17:41:40 -0000
@@ -63,6 +63,8 @@
 #include <machine/bus.h>
 
 #include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+#include <dev/usb/usbpcap.h>
 
 #ifdef USB_DEBUG
 #define DPRINTF(x)	do { if (usbdebug) printf x; } while (0)
@@ -183,6 +185,11 @@ usb_attach(struct device *parent, struct
 	}
 	printf("\n");
 
+#if NBPFILTER > 0
+	bpfsattach(&sc->sc_bus->bpf, sc->sc_dev.dv_xname, DLT_USBPCAP,
+	    sizeof(struct usbpcap_hdr));
+#endif
+
 	/* Make sure not to use tsleep() if we are cold booting. */
 	if (cold)
 		sc->sc_bus->use_polling++;
@@ -973,5 +980,75 @@ usb_detach(struct device *self, int flag
 		sc->sc_bus->soft = NULL;
 	}
 
+#if NBPFILTER > 0
+	bpfsdetach(&sc->sc_bus->bpf);
+#endif
 	return (0);
+}
+
+void
+usb_tap(struct usbd_bus *bus, struct usbd_xfer *xfer, uint8_t dir)
+{
+#if NBPFILTER > 0
+	struct usb_softc *sc = (struct usb_softc *)bus->usbctl;
+	usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
+	struct usbpcap_hdr *uph;
+	unsigned int bpfdir;
+	uint32_t len, dlen;
+	uint8_t *buf, info = 0;
+
+	if (dir == USBTAP_DIR_OUT) {
+		bpfdir = BPF_DIRECTION_OUT;
+		if (usbd_xfer_isread(xfer))
+			dlen = 0;
+		else
+			dlen = xfer->length;
+	} else { /* USBTAP_DIR_IN */
+		info = USBPCAP_INFO_PDO_TO_FDO;
+		bpfdir = BPF_DIRECTION_IN;
+		if (usbd_xfer_isread(xfer))
+			dlen = xfer->actlen;
+		else
+			dlen = 0;
+	}
+
+	len = sizeof(*uph) + dlen;
+
+	buf = malloc(len, M_TEMP, M_NOWAIT);
+	if (buf == NULL)
+		return;
+
+	uph = (struct usbpcap_hdr *)buf;
+	uph->hlen = htole32(sizeof(*uph));
+	uph->id = 0; /* not yet used */
+	uph->status = htole32(xfer->status);
+	uph->function = 0; /* not yet used */
+	uph->info = info;
+	uph->bus = htole32(sc->sc_dev.dv_unit);
+	uph->devaddr = htole16(xfer->device->address);
+	uph->epaddr = ed->bEndpointAddress;
+
+	switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
+	case UE_CONTROL:
+		uph->xfertype = USBPCAP_TRANSFER_CONTROL;
+		break;
+	case UE_ISOCHRONOUS:
+		uph->xfertype = USBPCAP_TRANSFER_ISOCHRONOUS;
+		break;
+	case UE_BULK:
+		uph->xfertype = USBPCAP_TRANSFER_BULK;
+		break;
+	case UE_INTERRUPT:
+		uph->xfertype = USBPCAP_TRANSFER_INTERRUPT;
+		break;
+	}
+
+	uph->dlen = dlen;
+	if (dlen)
+		memcpy(buf + sizeof(*uph), KERNADDR(&xfer->dmabuf, 0), dlen);
+
+	bpf_tap(bus->bpf, buf, len, bpfdir);
+
+	free(buf, M_TEMP, len);
+#endif
 }
Index: sys/dev/usb/usbdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.96
diff -u -p -r1.96 usbdi.c
--- sys/dev/usb/usbdi.c	21 Sep 2017 07:44:06 -0000	1.96
+++ sys/dev/usb/usbdi.c	25 Jan 2018 16:59:55 -0000
@@ -320,6 +320,8 @@ usbd_transfer(struct usbd_xfer *xfer)
 		usb_syncmem(&xfer->dmabuf, 0, xfer->length,
 		    BUS_DMASYNC_PREREAD);
 
+	usb_tap(bus, xfer, USBTAP_DIR_OUT);
+
 	err = pipe->methods->transfer(xfer);
 
 	if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
@@ -715,7 +717,8 @@ void
 usb_transfer_complete(struct usbd_xfer *xfer)
 {
 	struct usbd_pipe *pipe = xfer->pipe;
-	int polling = pipe->device->bus->use_polling;
+	struct usbd_bus *bus = pipe->device->bus;
+	int polling = bus->use_polling;
 	int status, flags;
 
 #if 0
@@ -759,7 +762,7 @@ usb_transfer_complete(struct usbd_xfer *
 	/* if we allocated the buffer in usbd_transfer() we free it here. */
 	if (xfer->rqflags & URQ_AUTO_DMABUF) {
 		if (!pipe->repeat) {
-			usb_freemem(pipe->device->bus, &xfer->dmabuf);
+			usb_freemem(bus, &xfer->dmabuf);
 			xfer->rqflags &= ~URQ_AUTO_DMABUF;
 		}
 	}
@@ -778,7 +781,7 @@ usb_transfer_complete(struct usbd_xfer *
 	    pipe->repeat, SIMPLEQ_FIRST(&pipe->queue)));
 
 	/* Count completed transfers. */
-	++pipe->device->bus->stats.uds_requests
+	++bus->stats.uds_requests
 		[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
 
 	xfer->done = 1;
@@ -788,6 +791,8 @@ usb_transfer_complete(struct usbd_xfer *
 		    xfer->actlen, xfer->length));
 		xfer->status = USBD_SHORT_XFER;
 	}
+
+	usb_tap(bus, xfer, USBTAP_DIR_IN);
 
 	/*
 	 * We cannot dereference ``xfer'' after calling the callback as
Index: sys/dev/usb/usbdivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.72
diff -u -p -r1.72 usbdivar.h
--- sys/dev/usb/usbdivar.h	8 Apr 2017 02:57:25 -0000	1.72
+++ sys/dev/usb/usbdivar.h	25 Jan 2018 17:02:27 -0000
@@ -35,6 +35,11 @@
 #ifndef _USBDIVAR_H_
 #define _USBDIVAR_H_
 
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
 #include <sys/timeout.h>
 
 /* From usb_mem.h */
@@ -100,6 +105,9 @@ struct usbd_bus {
 	/* Filled by HC driver */
 	struct device		bdev; /* base device, host adapter */
 	struct usbd_bus_methods	*methods;
+#if NBPFILTER > 0
+	caddr_t			bpf;
+#endif
 	u_int32_t		pipe_size; /* size of a pipe struct */
 	/* Filled by usb driver */
 	struct usbd_device     *root_hub;
@@ -253,6 +261,10 @@ int		usbd_detach(struct usbd_device *, s
 void		usb_needs_explore(struct usbd_device *, int);
 void		usb_needs_reattach(struct usbd_device *);
 void		usb_schedsoftintr(struct usbd_bus *);
+void		usb_tap(struct usbd_bus *, struct usbd_xfer *, uint8_t);
+
+#define USBTAP_DIR_OUT	0
+#define USBTAP_DIR_IN	1
 
 #define	UHUB_UNK_CONFIGURATION	-1
 #define	UHUB_UNK_INTERFACE	-1
Index: sys/dev/usb/usbpcap.h
===================================================================
RCS file: sys/dev/usb/usbpcap.h
diff -N sys/dev/usb/usbpcap.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/dev/usb/usbpcap.h	25 Jan 2018 17:05:08 -0000
@@ -0,0 +1,45 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2018 Martin Pieuchot
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _USBCAP_H_
+#define _USBCAP_H_
+
+/*
+ * DLT_USBPCAP header.
+ */
+struct usbpcap_hdr {
+	uint16_t	hlen;		/* header length */
+	uint64_t	id;		/* request ID */
+	uint32_t	status;		/* USB status code */
+	uint16_t	function;	/* stack function ID */
+	uint8_t		info;		/* info flags */
+#define USBPCAP_INFO_PDO_TO_FDO  (1 << 0)
+
+	uint16_t	bus;		/* bus number */
+	uint16_t	devaddr;	/* device address */
+	uint8_t		epaddr;		/* endpoint's `bEndpointAddress' */
+	uint8_t		xfertype;	/* transfer type */
+#define USBPCAP_TRANSFER_ISOCHRONOUS 0
+#define USBPCAP_TRANSFER_INTERRUPT   1
+#define USBPCAP_TRANSFER_CONTROL     2
+#define USBPCAP_TRANSFER_BULK        3
+
+	uint32_t	dlen;		/* data length */
+} __attribute__((packed));
+
+#endif /* _USBCAP_H_ */

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic