From: Claudio Jeker Subject: Re: libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW To: David Gwynne Cc: tech@openbsd.org Date: Thu, 5 Jun 2025 08:25:03 +0200 On Thu, Jun 05, 2025 at 04:00:06PM +1000, David Gwynne wrote: > 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; Shouldn't this be a return? > } > 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; I trust you that this is producing the right bpf commands. It kind of makes sense to me. > + > + return (b0); > + } > + > case DLT_PFLOG: > if (proto == ETHERTYPE_IP) > return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, > -- :wq Claudio