Index | Thread | Search

From:
David Gwynne <david@gwynne.id.au>
Subject:
libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW
To:
tech@openbsd.org
Date:
Thu, 5 Jun 2025 16:00:06 +1000

Download raw body.

Thread
this allows you filter on ip and ip6 packets like you do on other DLTs
by looking at the first nibble.

before this libpcap would just say "yes" if you asked for just ip or
ip6:

xdlg@oak ~$ tcpdump -r erspan.raw.pcap -d ip
(000) ret      #116
xdlg@oak ~$ tcpdump -r erspan.raw.pcap -d ip6
(000) ret      #116

or worse:

xdlg@oak ~$ tcpdump -r erspan.raw.pcap -d mpls 
(000) ldh      [-1]
(001) jeq      #0x8847          jt 2	jf 3
(002) ret      #116
(003) ret      #0
xdlg@oak ~$ tcpdump -r erspan.raw.pcap -d arp  
(000) ldh      [-1]
(001) jeq      #0x806           jt 2	jf 3
(002) ret      #116
(003) ret      #0

with this diff it can match on the packet:

xdlg@pitcher ~$ tcpdump -r erspan.raw.pcap -d ip
(000) ldb      [x + 0]
(001) rsh      #4
(002) jeq      #0x4             jt 3	jf 4
(003) ret      #116
(004) ret      #0
xdlg@pitcher ~$ tcpdump -r erspan.raw.pcap -d ip6
(000) ldb      [x + 0]
(001) rsh      #4
(002) jeq      #0x6             jt 3	jf 4
(003) ret      #116
(004) ret      #0

we also get this:

xdlg@pitcher ~$ tcpdump -r erspan.raw.pcap -d arp 
tcpdump: expression rejects all packets

ok?

Index: gencode.c
===================================================================
RCS file: /cvs/src/lib/libpcap/gencode.c,v
diff -u -p -r1.67 gencode.c
--- gencode.c	15 Sep 2024 07:14:58 -0000	1.67
+++ gencode.c	5 Jun 2025 05:51:30 -0000
@@ -768,12 +768,14 @@ init_linktype(int type)
 		off_nl = 12;
 		return;
 
-	case DLT_USBPCAP:
-		/* FALLTHROUGH */
 	case DLT_RAW:
-		off_linktype = -1;
+		off_linktype = 0;
 		off_nl = 0;
 		return;
+	case DLT_USBPCAP:
+		off_linktype = -1;
+		off_nl = 0;
+		break;
 	}
 	bpf_error("unknown data link type 0x%x", linktype);
 	/* NOTREACHED */
@@ -910,6 +912,38 @@ gen_linktype(int proto)
 		return (gen_cmp(0, BPF_W, (bpf_int32)v));
 		break;
 	}
+	case DLT_RAW: {
+		struct slist *s0, *s1;
+		struct block *b;
+		int v;
+
+		switch (proto) {
+		case ETHERTYPE_IP:
+			v = 4;
+			break;
+		case ETHERTYPE_IPV6:
+			v = 6;
+			break;
+		default:
+			return gen_false();
+		}
+
+		/* A = p[X+off_linktype] */
+		s0 = new_stmt(BPF_LD|BPF_B|BPF_IND);
+		s0->s.k = off_linktype;
+
+		/* A = A >> 4 */
+		s1 = new_stmt(BPF_ALU|BPF_RSH|BPF_K);
+		s1->s.k = 4;
+		sappend(s0, s1);
+
+		b0 = new_block(JMP(BPF_JEQ));
+		b0->stmts = s0;
+		b0->s.k = v;
+
+		return (b0);
+	}
+
 	case DLT_PFLOG:
 		if (proto == ETHERTYPE_IP)
 			return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B,