Add basic MPLS support in libpcap.

This version simplifies protocol filtering. There is no need to check if we are
in an MPLS packet for each protocol.
With one change, we can check icmp/udp/tcp/host

Index: gencode.c
===================================================================
RCS file: /cvs/src/lib/libpcap/gencode.c,v
retrieving revision 1.51
diff -u -p -r1.51 gencode.c
--- gencode.c   10 Nov 2018 10:17:37 -0000      1.51
+++ gencode.c   14 Nov 2018 12:50:46 -0000
@@ -37,6 +37,8 @@ struct rtentry;
 #include <net/if_pflog.h>
 #include <net/pfvar.h>
 
+#include <netmpls/mpls.h>
+
 #include <net80211/ieee80211.h>
 #include <net80211/ieee80211_radiotap.h>
 
@@ -69,6 +71,7 @@ static pcap_t *bpf_pcap;
 
 /* Hack for updating VLAN offsets. */
 static u_int   orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
+static u_int   mpls_stack = 0;
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -837,11 +840,11 @@ gen_linktype(proto)
        struct block *b0, *b1;
 
        /* If we're not using encapsulation and checking for IP, we're done */
-       if (off_linktype == -1 && proto == ETHERTYPE_IP)
+       if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IP)
                return gen_true();
 #ifdef INET6
        /* this isn't the right thing to do, but sometimes necessary */
-       if (off_linktype == -1 && proto == ETHERTYPE_IPV6)
+       if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IPV6)
                return gen_true();
 #endif
 
@@ -3348,6 +3351,34 @@ gen_acode(eaddr, q)
        }
        bpf_error("ARCnet address used in non-arc expression");
        /* NOTREACHED */
+}
+
+struct block *
+gen_mpls(label)
+       int label;
+{
+       struct block    *b0;
+
+       if (label > MPLS_LABEL_MAX)
+               bpf_error("invalid MPLS label : %d", label);
+
+       if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
+               b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
+       else 
+               b0 = gen_linktype(ETHERTYPE_MPLS);
+
+       if (label >= 0) {
+               struct block *b1;
+
+               b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12),
+                   MPLS_LABEL_MASK);
+               gen_and(b0, b1);
+               b0 = b1;
+       }
+       off_nl += 4;
+       off_linktype += 4;
+       mpls_stack++;
+       return (b0);
 }
 
 /*
Index: gencode.h
===================================================================
RCS file: /cvs/src/lib/libpcap/gencode.h,v
retrieving revision 1.18
diff -u -p -r1.18 gencode.h
--- gencode.h   3 Jun 2018 10:29:28 -0000       1.18
+++ gencode.h   14 Nov 2018 12:50:46 -0000
@@ -179,6 +179,7 @@ struct block *gen_multicast(int);
 struct block *gen_inbound(int);
 
 struct block *gen_vlan(int);
+struct block *gen_mpls(int);
 
 struct block *gen_pf_ifname(char *);
 struct block *gen_pf_rnr(int);
Index: grammar.y
===================================================================
RCS file: /cvs/src/lib/libpcap/grammar.y,v
retrieving revision 1.19
diff -u -p -r1.19 grammar.y
--- grammar.y   27 Oct 2009 23:59:30 -0000      1.19
+++ grammar.y   14 Nov 2018 12:50:46 -0000
@@ -115,7 +115,7 @@ pcap_parse()
 %token LSH RSH
 %token  LEN
 %token  IPV6 ICMPV6 AH ESP
-%token VLAN
+%token VLAN MPLS
 
 %type  <s> ID
 %type  <e> EID
@@ -279,6 +279,8 @@ other:        pqual TK_BROADCAST    { $$ = gen_b
        | OUTBOUND              { $$ = gen_inbound(1); }
        | VLAN pnum             { $$ = gen_vlan($2); }
        | VLAN                  { $$ = gen_vlan(-1); }
+       | MPLS pnum             { $$ = gen_mpls($2); }
+       | MPLS                  { $$ = gen_mpls(-1); }
        | pfvar                 { $$ = $1; }
        | pqual p80211          { $$ = $2; }
        ;
Index: pcap-filter.3
===================================================================
RCS file: /cvs/src/lib/libpcap/pcap-filter.3,v
retrieving revision 1.2
diff -u -p -r1.2 pcap-filter.3
--- pcap-filter.3       19 Feb 2014 04:51:32 -0000      1.2
+++ pcap-filter.3       14 Nov 2018 12:50:46 -0000
@@ -522,6 +522,31 @@ filters on VLAN 200 encapsulated within 
 .in -.5i
 filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
 higher order VLAN.
+.IP "\fBmpls \fI[label]\fR"
+True if the packet is an MPLS (Multi-Protocol Label Switching) packet.
+If \fIlabel\fR is specified, only true if the packet has the specified
+\fIlabel\fR.
+Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
+changes the decoding offsets for the remainder of \fIexpression\fR on
+the assumption that the packet is an MPLS packet.  The \fBmpls
+\fI[label]\fR expression may be used more than once, to filter on MPLS
+labels stack.  Each use of that expression increments the filter offsets
+by 4.
+.IP
+For example:
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12\fR
+.fi
+.in -.5i
+filters on MPLS label 42 on top of MPLS label 12, and
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12 && net 192.0.2.0/24\fR
+.fi
+.in -.5i
+filters network 192.0.2.0/24 transported inside packet with label 42 on
+top of label 12.
 .IP  "\fBtcp\fR, \fBudp\fR, \fBicmp\fR"
 Abbreviations for:
 .in +.5i
Index: scanner.l
===================================================================
RCS file: /cvs/src/lib/libpcap/scanner.l,v
retrieving revision 1.25
diff -u -p -r1.25 scanner.l
--- scanner.l   3 Jun 2018 10:29:28 -0000       1.25
+++ scanner.l   14 Nov 2018 12:50:46 -0000
@@ -224,6 +224,7 @@ inbound             return INBOUND;
 outbound       return OUTBOUND;
 
 vlan           return VLAN;
+mpls           return MPLS;
 
 on|ifname      return PF_IFNAME;
 rset|ruleset   return PF_RSET;

Reply via email to