Skip to content

Add support for filtering VNTag frames #1480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ethertype.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
73 changes: 73 additions & 0 deletions gencode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
1 change: 1 addition & 0 deletions gencode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion grammar.y.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))); }
Expand Down
24 changes: 22 additions & 2 deletions pcap-filter.manmisc.in
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
48 changes: 48 additions & 0 deletions testprogs/TESTrun
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
Binary file added tests/filter/vntag-novntag-mixed.pcap
Binary file not shown.