diff --git a/CHANGES b/CHANGES index 2518354f49..25bc566b22 100644 --- a/CHANGES +++ b/CHANGES @@ -51,6 +51,7 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group Require a live capture for all Linux BPF extensions. Have "outbound" mean Tx only for DLT_SLIP. Filter Linux SocketCAN frames in userland if necessary. + Add support for filtering VNTag frames (pull request #1480) rpcap: Support user names and passwords in rpcap:// and rpcaps:// URLs. Add a -t flag to rpcapd to specify the data channel port; from diff --git a/ethertype.h b/ethertype.h index e34e07b98d..82158b8145 100644 --- a/ethertype.h +++ b/ethertype.h @@ -115,6 +115,9 @@ #ifndef ETHERTYPE_8021AD #define ETHERTYPE_8021AD 0x88a8 #endif +#ifndef ETHERTYPE_VNTAG +#define ETHERTYPE_VNTAG 0x8926 +#endif #ifndef ETHERTYPE_LOOPBACK #define ETHERTYPE_LOOPBACK 0x9000 #endif diff --git a/gencode.c b/gencode.c index a9e431649e..af1a937dc6 100644 --- a/gencode.c +++ b/gencode.c @@ -10710,3 +10710,76 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type) } return b1; } + +/* + * support VNTag (proposed as IEEE 802.1Qbh but never accepted) over Ethernet + * VNTag headers look like this on their own: + * 0 1 2 3 4 5 + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * | | | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | EtherType |D|P| vif_list_id/dvif_id |L|R|ver| svif_id | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * In context that looks like this: + * 0 1 2 3 4 5 + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * | | | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | VNTag | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | EtherType | Payload... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct block * +gen_vntag(compiler_state_t *cstate) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Check for a VNTag packet, and then change the offsets to point + * to the type and data fields within the VLAN after the VNTag packet. + * VNTag always requires VLAN afterwards, and that likely won't be + * offloaded so handle it just like inline VLAN. Apply the same rules + * and restrictions as VLAN, too. + */ + if (cstate->label_stack_depth > 0) + bpf_error(cstate, "no VNTag match after MPLS"); + + /* Assume any of the EtherTypes that can have VLAN can also have + * VNTag as well. With VNTag not being accepted as 802.1Qbh but + * being replaced in the standads by 802.1Qbr there's not much to go on + * other than a few vendor proprietary implementations. + */ + switch (cstate->linktype) { + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + /* Make sure we have a VNTag frame, then jump over it. */ + b0 = gen_linktype(cstate, ETHERTYPE_VNTAG); + cstate->off_linkpl.constant_part += 6; + cstate->off_linktype.constant_part += 6; + break; + default: + bpf_error(cstate, "no VNTag support for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ + } + + return (b0); +} diff --git a/gencode.h b/gencode.h index 22752ed1aa..608daa24d3 100644 --- a/gencode.h +++ b/gencode.h @@ -352,6 +352,7 @@ struct block *gen_llc_u_subtype(compiler_state_t *, bpf_u_int32); struct block *gen_vlan(compiler_state_t *, bpf_u_int32, int); struct block *gen_mpls(compiler_state_t *, bpf_u_int32, int); +struct block *gen_vntag(compiler_state_t *); struct block *gen_pppoed(compiler_state_t *); struct block *gen_pppoes(compiler_state_t *, bpf_u_int32, int); diff --git a/grammar.y.in b/grammar.y.in index 4df433960e..0c0e3b5ecd 100644 --- a/grammar.y.in +++ b/grammar.y.in @@ -389,7 +389,7 @@ DIAG_OFF_BISON_BYACC %token LSH RSH %token LEN %token IPV6 ICMPV6 AH ESP -%token VLAN MPLS +%token VLAN MPLS VNTAG %token PPPOED PPPOES GENEVE VXLAN %token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP %token STP @@ -682,6 +682,7 @@ other: pqual TK_BROADCAST { CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); } | VLAN { CHECK_PTR_VAL(($$ = gen_vlan(cstate, 0, 0))); } | MPLS pnum { CHECK_PTR_VAL(($$ = gen_mpls(cstate, $2, 1))); } | MPLS { CHECK_PTR_VAL(($$ = gen_mpls(cstate, 0, 0))); } + | VNTAG { CHECK_PTR_VAL(($$ = gen_vntag(cstate))); } | PPPOED { CHECK_PTR_VAL(($$ = gen_pppoed(cstate))); } | PPPOES pnum { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, $2, 1))); } | PPPOES { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); } diff --git a/pcap-filter.manmisc.in b/pcap-filter.manmisc.in index 7864cf03ab..eaa21c7b69 100644 --- a/pcap-filter.manmisc.in +++ b/pcap-filter.manmisc.in @@ -1011,6 +1011,24 @@ filters packets with an outer label of 100000 and an inner label of .in -.5i filters packets to or from 192.9.200.1 with an inner label of 1024 and any outer label. +.IP "\fBvntag\fR" +True if the packet is a VNTag packet (identified by EtherType 0x8926). +Each use of that keyword increments the filter link header and payload offsets by 6. +.IP +For example: +.in +.5i +.nf +\fBvntag\fR +.fi +.in -.5i +filters on VNTag as the next EtherType and skips the VNTag header +.in +.5i +.nf +\fBvntag\fR and \fBvlan\fR and \fBip src host\fR 192.0.2.0 +.fi +.in -.5i +filters on VNTag followed by any VLAN followed by an IPv4 packet from 192.0.2.0 +skipping over the VNTag header, then VLAN header, to allow finding the IPv4 .IP \fBpppoed\fP True if the packet is a PPP-over-Ethernet Discovery packet (Ethernet type 0x8863). @@ -1636,8 +1654,10 @@ The keyword became available in libpcap 1.10.0. .PP The -.B vxlan -keyword became available in libpcap 1.11.0. +.BR vxlan +and +.B vntag +keywords became available in libpcap 1.11.0. .SH SEE ALSO .BR pcap (3PCAP) .SH BUGS diff --git a/scanner.l b/scanner.l index 0fa8f40724..07a842b158 100644 --- a/scanner.l +++ b/scanner.l @@ -339,6 +339,7 @@ pppoed return PPPOED; pppoes return PPPOES; geneve return GENEVE; vxlan return VXLAN; +vntag return VNTAG; lane return LANE; llc return LLC; diff --git a/testprogs/TESTrun b/testprogs/TESTrun index 33d9f42915..47e1a9fa52 100755 --- a/testprogs/TESTrun +++ b/testprogs/TESTrun @@ -9657,6 +9657,34 @@ my %accept_blocks = ( (020) ret #0 ', }, # dst_portrange_degenerate + vntag_eth => { + DLT => 'EN10MB', + aliases => ['vntag'], + opt => ' + (000) ldh [12] + (001) jeq #0x8926 jt 2 jf 3 + (002) ret #262144 + (003) ret #0 + ', + }, # vntag_eth + vntag_eth_vlan_vntag_vlan => { + DLT => 'EN10MB', + aliases => ['vlan and vntag and vlan'], + opt => ' + (000) ldh [12] + (001) jeq #0x8100 jt 4 jf 2 + (002) jeq #0x88a8 jt 4 jf 3 + (003) jeq #0x9100 jt 4 jf 11 + (004) ldh [16] + (005) jeq #0x8926 jt 6 jf 11 + (006) ldh [22] + (007) jeq #0x8100 jt 10 jf 8 + (008) jeq #0x88a8 jt 10 jf 9 + (009) jeq #0x9100 jt 10 jf 11 + (010) ret #262144 + (011) ret #0 + ', + }, # vntag_eth ); # In apply_blocks the top-level keys are test block names. Each test block @@ -10067,6 +10095,21 @@ my %apply_blocks = ( expr => 'outbound', results => [46], }, + vntag => { + savefile => 'vntag-novntag-mixed.pcap', + expr => 'vntag', + results => [262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, + vntag_vlan_ip => { + savefile => 'vntag-novntag-mixed.pcap', + expr => 'vntag and vlan 100 and ip', + results => [262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 262144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, + vntag_vlan_dest_ip => { + savefile => 'vntag-novntag-mixed.pcap', + expr => 'vntag and vlan 100 and ip dst 192.168.20.102', + results => [0, 262144, 0, 0, 262144, 262144, 0, 0, 262144, 262144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, ); # * DLT, expr, netmask and skip: same as in accept_blocks above @@ -10699,6 +10742,11 @@ my %reject_tests = ( expr => 'gateway $af', errstr => 'aid supported only on ARCnet', }, + vntag_not_supported => { + DLT => 'RAW', + expr => 'vntag', + errstr => 'no VNTag support', + }, ); sub accept_test_label { diff --git a/tests/filter/vntag-novntag-mixed.pcap b/tests/filter/vntag-novntag-mixed.pcap new file mode 100644 index 0000000000..763b38acf9 Binary files /dev/null and b/tests/filter/vntag-novntag-mixed.pcap differ