1 From 3d8d268320d2381021a409ff8d03533698dd6242 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
3 Date: Mon, 23 Nov 2020 00:38:22 +0100
4 Subject: [PATCH] Add support for B.A.T.M.A.N. Advanced
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 This adds support for the layer 2 mesh routing protocol
10 B.A.T.M.A.N. Advanced. "batadv" can be used to filter on batman-adv
11 packets. It also allows later filters to look at frames inside the
12 tunnel when both "version" and "type" are specified.
14 Documentation for the batman-adv protocol can be found at the following
17 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/batman-adv.rst
18 https://www.open-mesh.org/
20 Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
23 batadv_legacy_packet.h | 77 +++++++++++++++++++
24 batadv_packet.h | 78 ++++++++++++++++++++
26 gencode.c | 164 +++++++++++++++++++++++++++++++++++++++++
28 grammar.y.in | 32 +++++++-
29 nametoaddr.c | 59 +++++++++++++++
30 pcap-filter.manmisc.in | 35 ++++++++-
33 11 files changed, 453 insertions(+), 3 deletions(-)
34 create mode 100644 batadv_legacy_packet.h
35 create mode 100644 batadv_packet.h
39 @@ -134,6 +134,8 @@ PUBHDR = \
43 + batadv_legacy_packet.h \
49 +++ b/batadv_legacy_packet.h
51 +/* SPDX-License-Identifier: BSD-3 */
52 +/* Copyright (C) 2020 Linus Lüssing */
54 +#ifndef _BATADV_LEGACY_PACKET_H_
55 +#define _BATADV_LEGACY_PACKET_H_
57 +enum batadv_legacy_packettype {
58 + BATADV_LEGACY_IV_OGM = 0x01,
59 + BATADV_LEGACY_ICMP = 0x02,
60 + BATADV_LEGACY_UNICAST = 0x03,
61 + BATADV_LEGACY_BCAST = 0x04,
62 + BATADV_LEGACY_VIS = 0x05,
63 + BATADV_LEGACY_UNICAST_FRAG = 0x06,
64 + BATADV_LEGACY_TT_QUERY = 0x07,
65 + BATADV_LEGACY_ROAM_ADV = 0x08,
66 + BATADV_LEGACY_UNICAST_4ADDR = 0x09,
67 + BATADV_LEGACY_CODED = 0x0a,
72 +struct batadv_legacy_unicast_packet {
73 + uint8_t packet_type;
77 + uint8_t dest[ETH_ALEN];
80 +struct batadv_legacy_unicast_4addr_packet {
81 + uint8_t packet_type;
84 + uint8_t src[ETH_ALEN];
89 +struct batadv_legacy_unicast_frag_packet {
90 + uint8_t packet_type;
94 + uint8_t dest[ETH_ALEN];
97 + uint8_t orig[ETH_ALEN];
98 + uint8_t seqno[2]; /* 2-byte integral value */
101 +struct batadv_legacy_bcast_packet {
102 + uint8_t packet_type;
106 + uint8_t seqno[4]; /* 4-byte integral value */
107 + uint8_t orig[ETH_ALEN];
110 +struct batadv_legacy_coded_packet {
111 + uint8_t packet_type;
114 + uint8_t first_ttvn;
115 + uint8_t first_source[ETH_ALEN];
116 + uint8_t first_orig_dest[ETH_ALEN];
117 + uint8_t first_crc[4]; /* 4-byte integral value */
118 + uint8_t second_ttl;
119 + uint8_t second_ttvn;
120 + uint8_t second_dest[ETH_ALEN];
121 + uint8_t second_source[ETH_ALEN];
122 + uint8_t second_orig_dest[ETH_ALEN];
123 + uint8_t second_crc[4]; /* 4-byte integral value */
124 + uint8_t coded_len[2]; /* 2-byte integral value */
127 +#endif /* _BATADV_LEGACY_PACKET_H_ */
129 +++ b/batadv_packet.h
131 +/* SPDX-License-Identifier: BSD-3 */
132 +/* Copyright (C) 2020 Linus Lüssing */
134 +#ifndef _BATADV_PACKET_H_
135 +#define _BATADV_PACKET_H_
137 +/* For the definitive and most recent packet format definition,
138 + * see the batadv_packet.h in the Linux kernel.
141 +enum batadv_packettype {
142 + BATADV_IV_OGM = 0x00,
143 + BATADV_BCAST = 0x01,
144 + BATADV_CODED = 0x02,
146 + BATADV_OGM2 = 0x04,
147 + BATADV_UNICAST = 0x40,
148 + BATADV_UNICAST_FRAG = 0x41,
149 + BATADV_UNICAST_4ADDR = 0x42,
150 + BATADV_ICMP = 0x43,
151 + BATADV_UNICAST_TVLV = 0x44,
156 +struct batadv_unicast_packet {
157 + uint8_t packet_type;
161 + uint8_t dest[ETH_ALEN];
164 +struct batadv_unicast_4addr_packet {
165 + struct batadv_unicast_packet u;
166 + uint8_t src[ETH_ALEN];
171 +struct batadv_frag_packet {
172 + uint8_t packet_type;
175 + uint8_t num_pri; /* number and priority */
176 + uint8_t dest[ETH_ALEN];
177 + uint8_t orig[ETH_ALEN];
178 + uint8_t seqno[2]; /* 2-byte integral value */
179 + uint8_t total_size[2]; /* 2-byte integral value */
182 +struct batadv_bcast_packet {
183 + uint8_t packet_type;
187 + uint8_t seqno[4]; /* 4-byte integral value */
188 + uint8_t orig[ETH_ALEN];
191 +struct batadv_coded_packet {
192 + uint8_t packet_type;
195 + uint8_t first_ttvn;
196 + uint8_t first_source[ETH_ALEN];
197 + uint8_t first_orig_dest[ETH_ALEN];
198 + uint8_t first_crc[4]; /* 4-byte integral value */
199 + uint8_t second_ttl;
200 + uint8_t second_ttvn;
201 + uint8_t second_dest[ETH_ALEN];
202 + uint8_t second_source[ETH_ALEN];
203 + uint8_t second_orig_dest[ETH_ALEN];
204 + uint8_t second_crc[4]; /* 4-byte integral value */
205 + uint8_t coded_len[2]; /* 2-byte integral value */
208 +#endif /* _BATADV_PACKET_H_ */
212 #ifndef ETHERTYPE_TRAIL
213 #define ETHERTYPE_TRAIL 0x1000
215 +#ifndef ETHERTYPE_BATMAN
216 +#define ETHERTYPE_BATMAN 0x4305 /* B.A.T.M.A.N. Advanced */
218 #ifndef ETHERTYPE_MOPDL
219 #define ETHERTYPE_MOPDL 0x6001
224 #include "sunatmpos.h"
227 +#include "batadv_packet.h"
228 +#include "batadv_legacy_packet.h"
229 #include "pcap/sll.h"
230 #include "pcap/ipnet.h"
232 @@ -9436,6 +9438,168 @@ gen_geneve(compiler_state_t *cstate, bpf
236 +static struct block *
237 +gen_batadv_check_version(compiler_state_t *cstate, struct block *b0, bpf_u_int32 version)
241 + if (version > UINT8_MAX)
243 + "batman-adv compatibility version number %u unsupported",
246 + b1 = gen_cmp(cstate, OR_LINKPL, 1, BPF_B, version);
252 +static struct block *
253 +gen_batadv_check_type(compiler_state_t *cstate, struct block *b0,
254 + bpf_u_int32 version, bpf_u_int32 type)
261 + if (type > UINT8_MAX)
263 + "batman-adv packet type %u unsupported for compatibility version %u",
266 + b1 = gen_cmp(cstate, OR_LINKPL, 0, BPF_B, type);
273 + "batman-adv compatibility version number %u unsupported",
281 +static void gen_batadv_push_offset(compiler_state_t *cstate, u_int offset)
283 + PUSH_LINKHDR(cstate, DLT_EN10MB, cstate->off_linkpl.is_variable,
284 + cstate->off_linkpl.constant_part + cstate->off_nl + offset,
285 + cstate->off_linkpl.reg);
287 + cstate->off_linktype.constant_part += cstate->off_linkhdr.constant_part;
288 + cstate->off_linkpl.constant_part += cstate->off_linkhdr.constant_part;
290 + cstate->off_nl = 0;
291 + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */
295 +gen_batadv_offsets_v14(compiler_state_t *cstate, bpf_u_int32 type)
300 + case BATADV_LEGACY_UNICAST: /* 0x03 */
301 + offset = sizeof(struct batadv_legacy_unicast_packet);
303 + case BATADV_LEGACY_BCAST: /* 0x04 */
304 + offset = sizeof(struct batadv_legacy_bcast_packet);
306 + case BATADV_LEGACY_UNICAST_FRAG: /* 0x06 */
307 + offset = sizeof(struct batadv_legacy_unicast_frag_packet);
309 + case BATADV_LEGACY_UNICAST_4ADDR: /* 0x09 */
310 + offset = sizeof(struct batadv_legacy_unicast_4addr_packet);
312 + case BATADV_LEGACY_CODED: /* 0x0a */
313 + offset = sizeof(struct batadv_legacy_coded_packet);
320 + gen_batadv_push_offset(cstate, (u_int)offset);
324 +gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
329 + case BATADV_BCAST: /* 0x01 */
330 + offset = sizeof(struct batadv_bcast_packet);
332 + case BATADV_CODED: /* 0x02 */
333 + offset = sizeof(struct batadv_coded_packet);
335 + case BATADV_UNICAST: /* 0x40 */
336 + offset = sizeof(struct batadv_unicast_packet);
338 + case BATADV_UNICAST_FRAG: /* 0x41 */
339 + offset = sizeof(struct batadv_frag_packet);
341 + case BATADV_UNICAST_4ADDR: /* 0x42 */
342 + offset = sizeof(struct batadv_unicast_4addr_packet);
344 + case BATADV_UNICAST_TVLV:
345 + /* unsupported for now, needs variable offset to
346 + * take tvlv_len into account
354 + gen_batadv_push_offset(cstate, (u_int)offset);
358 +gen_batadv_offsets(compiler_state_t *cstate, bpf_u_int32 version, bpf_u_int32 type)
362 + gen_batadv_offsets_v14(cstate, type);
365 + gen_batadv_offsets_v15(cstate, type);
373 +gen_batadv(compiler_state_t *cstate, bpf_u_int32 version, int has_version,
374 + bpf_u_int32 type, int has_type)
379 + * Catch errors reported by us and routines below us, and return NULL
382 + if (setjmp(cstate->top_ctx))
385 + b0 = gen_linktype(cstate, ETHERTYPE_BATMAN);
388 + b0 = gen_batadv_check_version(cstate, b0, version);
391 + b0 = gen_batadv_check_type(cstate, b0, version, type);
392 + gen_batadv_offsets(cstate, version, type);
398 /* Check that the encapsulated frame has a link layer header
399 * for Ethernet filters. */
400 static struct block *
403 @@ -358,6 +358,9 @@ struct block *gen_pppoes(compiler_state_
405 struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int);
407 +struct block *gen_batadv(compiler_state_t *, bpf_u_int32, int,
410 struct block *gen_atmfield_code(compiler_state_t *, int, bpf_u_int32,
412 struct block *gen_atmtype_abbrev(compiler_state_t *, int);
415 @@ -375,6 +375,7 @@ DIAG_OFF_BISON_BYACC
417 %type <blk> mtp3field
418 %type <blk> mtp3fieldvalue mtp3value mtp3listvalue
419 +%type <rblk> pbatadv
422 %token DST SRC HOST GATEWAY
423 @@ -393,7 +394,7 @@ DIAG_OFF_BISON_BYACC
425 %token IPV6 ICMPV6 AH ESP
427 -%token PPPOED PPPOES GENEVE
428 +%token PPPOED PPPOES GENEVE BATADV
429 %token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP
432 @@ -620,11 +621,40 @@ other: pqual TK_BROADCAST { CHECK_PTR_
433 | PPPOES { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); }
434 | GENEVE pnum { CHECK_PTR_VAL(($$ = gen_geneve(cstate, $2, 1))); }
435 | GENEVE { CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); }
436 + | BATADV pbatadv { $$ = $2; }
438 | pqual p80211 { $$ = $2; }
442 +pbatadv: { CHECK_PTR_VAL(($$ = gen_batadv(cstate, 0, 0, 0, 0))); }
443 + | pnum { CHECK_PTR_VAL(($$ = gen_batadv(cstate, $1, 1, 0, 0))); }
444 + | pnum pnum { CHECK_PTR_VAL(($$ = gen_batadv(cstate, $1, 1, $2, 1))); }
451 + type = pcap_nametobatadvtype_v14($2);
454 + type = pcap_nametobatadvtype_v15($2);
457 + bpf_set_error(cstate, "batman-adv compatibility version number %u unsupported", $1);
461 + if (type == PROTO_UNDEF) {
462 + bpf_set_error(cstate, "invalid batman-adv packet type value \"%s\"", $2);
466 + CHECK_PTR_VAL(($$ = gen_batadv(cstate, $1, 1, type, 1)));
470 pfvar: PF_IFNAME ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ifname(cstate, $2))); }
471 | PF_RSET ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ruleset(cstate, $2))); }
472 | PF_RNR NUM { CHECK_PTR_VAL(($$ = gen_pf_rnr(cstate, $2))); }
477 #include "diag-control.h"
479 +#include "batadv_packet.h"
480 +#include "batadv_legacy_packet.h"
483 #include <pcap/namedb.h>
485 #include "nametoaddr.h"
487 #ifdef HAVE_OS_PROTO_H
488 @@ -604,6 +608,7 @@ PCAP_API_DEF struct eproto eproto_db[] =
489 { "moprc", ETHERTYPE_MOPRC },
490 { "rarp", ETHERTYPE_REVARP },
491 { "sca", ETHERTYPE_SCA },
492 + { "batadv", ETHERTYPE_BATMAN },
496 @@ -638,6 +643,60 @@ pcap_nametollc(const char *s)
499 if (strcmp(p->s, s) == 0)
503 + return PROTO_UNDEF;
506 +/* Static data base of batman-adv v14 packet type values. */
507 +static struct eproto batadv_type_db_v14[] = {
508 + { "iv_ogm", BATADV_LEGACY_IV_OGM },
509 + { "icmp", BATADV_LEGACY_ICMP },
510 + { "unicast", BATADV_LEGACY_UNICAST },
511 + { "bcast", BATADV_LEGACY_BCAST },
512 + { "vis", BATADV_LEGACY_VIS },
513 + { "unicast_frag", BATADV_LEGACY_UNICAST_FRAG },
514 + { "tt_query", BATADV_LEGACY_TT_QUERY },
515 + { "roam_adv", BATADV_LEGACY_ROAM_ADV },
516 + { "unicast_4addr", BATADV_LEGACY_UNICAST_4ADDR },
517 + { "coded", BATADV_LEGACY_CODED },
521 +int pcap_nametobatadvtype_v14(const char *s)
523 + struct eproto *p = batadv_type_db_v14;
525 + while (p->s != 0) {
526 + if (strcmp(p->s, s) == 0)
530 + return PROTO_UNDEF;
533 +/* Static data base of batman-adv v15 packet type values. */
534 +static struct eproto batadv_type_db_v15[] = {
535 + { "iv_ogm", BATADV_IV_OGM },
536 + { "bcast", BATADV_BCAST },
537 + { "coded", BATADV_CODED },
538 + { "elp", BATADV_ELP },
539 + { "ogm2", BATADV_OGM2 },
540 + { "unicast", BATADV_UNICAST },
541 + { "unicast_frag", BATADV_UNICAST_FRAG },
542 + { "unicast_4addr", BATADV_UNICAST_4ADDR },
543 + { "icmp", BATADV_ICMP },
544 + { "unicast_tvlv", BATADV_UNICAST_TVLV },
548 +int pcap_nametobatadvtype_v15(const char *s)
550 + struct eproto *p = batadv_type_db_v15;
552 + while (p->s != 0) {
553 + if (strcmp(p->s, s) == 0)
557 --- a/pcap-filter.manmisc.in
558 +++ b/pcap-filter.manmisc.in
559 @@ -98,6 +98,7 @@ protocols are:
567 @@ -400,7 +401,7 @@ True if the packet is an IPv6 multicast
568 .IP "\fBether proto \fIprotocol\fR"
569 True if the packet is of ether type \fIprotocol\fR.
570 \fIProtocol\fP can be a number or one of the names
571 -\fBaarp\fP, \fBarp\fP, \fBatalk\fP, \fBdecnet\fP, \fBip\fP, \fBip6\fP,
572 +\fBaarp\fP, \fBarp\fP, \fBatalk\fP, \fBbatadv\fP, \fBdecnet\fP, \fBip\fP, \fBip6\fP,
573 \fBipx\fP, \fBiso\fP, \fBlat\fP, \fBloopback\fP, \fBmopdl\fP, \fBmoprc\fP, \fBnetbeui\fP,
574 \fBrarp\fP, \fBsca\fP or \fBstp\fP.
575 Note these identifiers (except \fBloopback\fP) are also keywords
576 @@ -454,7 +455,7 @@ the filter checks for the IPX etype in a
577 DSAP in the LLC header, the 802.3-with-no-LLC-header encapsulation of
578 IPX, and the IPX etype in a SNAP frame.
580 -.IP "\fBip\fR, \fBip6\fR, \fBarp\fR, \fBrarp\fR, \fBatalk\fR, \fBaarp\fR, \fBdecnet\fR, \fBiso\fR, \fBstp\fR, \fBipx\fR, \fBnetbeui\fP"
581 +.IP "\fBip\fR, \fBip6\fR, \fBarp\fR, \fBrarp\fR, \fBatalk\fR, \fBaarp\fR, \fBdecnet\fR, \fBiso\fR, \fBstp\fR, \fBipx\fR, \fBnetbeui\fP, \fBbatadv\fP"
585 @@ -792,6 +793,36 @@ For example:
586 filters IPv4 protocol encapsulated in Geneve with VNI 0xb. This will
587 match both IPv4 directly encapsulated in Geneve as well as IPv4 contained
588 inside an Ethernet frame.
589 +.IP "\fBbatadv \fI[version] \fI[type]\fR"
590 +True if the packet is a B.A.T.M.A.N. Advanced packet (Ethernet type 0x4305).
591 +If the optional \fIversion\fR is specified, only true if the packet has the
592 +specified batman-adv compatibility \fIversion\fR. If the optional \fIversion\fR
593 +and \fItype\fR are specified, only true if the packet has both the specified
594 +batman-adv compatibility \fIversion\fR and batman-adv packet \fItype\fR.
596 +\fIversion\fR may be a number from 0 to 255, though only compatibility version
597 +14 and 15 were actually deployed in the wild. Version 15 is the current version,
598 +14 is considered deprecated.
600 +\fItype\fR is currently only defined for compatibility \fIversion\fR 14 and 15.
601 +\fItype\fR may be a number from 0 to 255 for compatibility \fIversion\fR 14 and 15.
603 +The following packet \fItype\fR aliases are available for compat \fIversion\fR 14:
604 +\fBiv_ogm\fP, \fBicmp\fP, \fBunicast\fP, \fBbcast\fP, \fBvis\fP, \fBunicast-frag\fP,
605 +\fBtt_query\fP, \fBroam_adv\fP, \fBunicast_4addr\fP, \fPcoded\fP.
607 +The following packet \fItype\fR aliases are available for compat \fIversion\fR 15:
608 +\fBiv_ogm\fP, \fBbcast\fP, \fBcoded\fP, \fBelp\fP, \fBogm2\fP, \fBunicast\fP,
609 +\fBunicast_frag\fP, \fBunicast_4addr\fP, \fBicmp\fP, \fPunicast_tvlv\fP.
611 +Note that when the \fBbatadv\fR keyword is encountered in an expression and
612 +a batman-adv packet \fItype\fR is provided which specifies an encapsulating
613 +packet type then it changes the decoding offsets for the remainder of the
614 +expression on the assumption that the packet is a batman-adv packet. For compat
615 +\fIversion\fR 14 these are packet \fItype\fRs \fBunicast\fP, \fBbcast\fP,
616 +\fBunicast_frag\fP, \fBunicast_4addr\fP and \fBcoded\fP. For compat \fIversion\fR
617 +15 these are currently packet \fItype\fRs \fBbcast\fP, \fBcoded\fP, \fBunicast\fP,
618 +\fBunicast_frag\fP and \fBunicast_4addr\fP.
619 .IP "\fBiso proto \fIprotocol\fR"
620 True if the packet is an OSI packet of protocol type \fIprotocol\fP.
621 \fIProtocol\fP can be a number or one of the names
624 @@ -70,6 +70,8 @@ PCAP_API int pcap_nametoportrange(const
625 PCAP_API int pcap_nametoproto(const char *);
626 PCAP_API int pcap_nametoeproto(const char *);
627 PCAP_API int pcap_nametollc(const char *);
628 +PCAP_API int pcap_nametobatadvtype_v14(const char *);
629 +PCAP_API int pcap_nametobatadvtype_v15(const char *);
631 * If a protocol is unknown, PROTO_UNDEF is returned.
632 * Also, pcap_nametoport() returns the protocol along with the port number.
635 @@ -347,6 +347,7 @@ mpls return MPLS;
636 pppoed return PPPOED;
637 pppoes return PPPOES;
638 geneve return GENEVE;
639 +batadv return BATADV;