From: David Gwynne Subject: Re: libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW To: tech@openbsd.org Date: Thu, 5 Jun 2025 16:43:51 +1000 On Thu, Jun 05, 2025 at 08:25:03AM +0200, Claudio Jeker wrote: > 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? yep. > > + /* 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. i shouldn't be using indirect loads here. 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 06:41:41 -0000 @@ -768,9 +768,11 @@ init_linktype(int type) off_nl = 12; return; - case DLT_USBPCAP: - /* FALLTHROUGH */ case DLT_RAW: + off_linktype = 0; + off_nl = 0; + return; + case DLT_USBPCAP: off_linktype = -1; off_nl = 0; return; @@ -910,6 +912,37 @@ gen_linktype(int proto) return (gen_cmp(0, BPF_W, (bpf_int32)v)); break; } + case DLT_RAW: { + struct slist *s0, *s1; + int ipv; + + switch (proto) { + case ETHERTYPE_IP: + ipv = 4; + break; + case ETHERTYPE_IPV6: + ipv = 6; + break; + default: + return gen_false(); + } + + /* A = p[X+off_linktype] */ + s0 = new_stmt(BPF_LD|BPF_ABS|BPF_B); + 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 = ipv; + + return (b0); + } + case DLT_PFLOG: if (proto == ETHERTYPE_IP) return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B,