Download raw body.
libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW
libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW
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
libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW
libpcap: teach gencode how to match ipv6 and ipv4 packets for DLT_RAW