]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
ebpf: complete vlan support for ebpf bypass filter
authorEric Leblond <eric@regit.org>
Fri, 17 May 2019 17:55:39 +0000 (19:55 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 18 Jun 2019 05:07:02 +0000 (07:07 +0200)
ebpf/bypass_filter.c

index 0e858eed2f78270c6907e72f99f2d379cd4d1d7d..162a313f7c7a6aa3cc52918fd67b8ef54f5ec32d 100644 (file)
@@ -27,6 +27,9 @@
 
 #include "bpf_helpers.h"
 
+/* vlan tracking: set it to 0 if you don't use VLAN for flow tracking */
+#define VLAN_TRACKING    1
+
 #define LINUX_VERSION_CODE 263682
 
 struct flowv4_keys {
@@ -71,18 +74,22 @@ struct bpf_map_def SEC("maps") flow_table_v6 = {
     .max_entries = 32768,
 };
 
+struct vlan_hdr {
+    __u16      h_vlan_TCI;
+    __u16      h_vlan_encapsulated_proto;
+};
+
 /**
  * IPv4 filter
  *
  * \return 0 to drop packet out and -1 to accept it
  */
-static __always_inline int ipv4_filter(struct __sk_buff *skb)
+static __always_inline int ipv4_filter(struct __sk_buff *skb, __u16 vlan0, __u16 vlan1)
 {
     __u32 nhoff, verlen;
     struct flowv4_keys tuple;
     struct pair *value;
     __u16 port;
-    __u16 vlan_id = skb->vlan_tci & 0x0fff;
 
     nhoff = skb->cb[0];
 
@@ -105,9 +112,8 @@ static __always_inline int ipv4_filter(struct __sk_buff *skb)
     port = tuple.port16[1];
     tuple.port16[1] = tuple.port16[0];
     tuple.port16[0] = port;
-    tuple.vlan_id[0] = vlan_id;
-    /* FIXME add second vlan layer */
-    tuple.vlan_id[1] = 0;
+    tuple.vlan_id[0] = vlan0;
+    tuple.vlan_id[1] = vlan1;
 
 #if 0
     if ((tuple.port16[0] == 22) || (tuple.port16[1] == 22))
@@ -141,14 +147,13 @@ static __always_inline int ipv4_filter(struct __sk_buff *skb)
  *
  * \return 0 to drop packet out and -1 to accept it
  */
-static __always_inline int ipv6_filter(struct __sk_buff *skb)
+static __always_inline int ipv6_filter(struct __sk_buff *skb, __u16 vlan0, __u16 vlan1)
 {
     __u32 nhoff;
     __u8 nhdr;
     struct flowv6_keys tuple;
     struct pair *value;
     __u16 port;
-    __u16 vlan_id = skb->vlan_tci & 0x0fff;
 
     nhoff = skb->cb[0];
 
@@ -180,9 +185,8 @@ static __always_inline int ipv6_filter(struct __sk_buff *skb)
     tuple.port16[0] = port;
     tuple.ip_proto = nhdr;
 
-    tuple.vlan_id[0] = vlan_id;
-    /* FIXME add second vlan layer */
-    tuple.vlan_id[1] = 0;
+    tuple.vlan_id[0] = vlan0;
+    tuple.vlan_id[1] = vlan1;
 
     //char fmt[] = "Now Got IPv6 port %u and %u\n";
     //bpf_trace_printk(fmt, sizeof(fmt), tuple.port16[0], tuple.port16[1]);
@@ -209,12 +213,39 @@ static __always_inline int ipv6_filter(struct __sk_buff *skb)
 int SEC("filter") hashfilter(struct __sk_buff *skb) {
     __u32 nhoff = ETH_HLEN;
 
+    void *data = (void *)(long)skb->data;
+    void *data_end = (void *)(long)skb->data_end;
+    __u64 proto = load_half(skb, 12);
+    __u16 vlan0 = 0;
+    __u16 vlan1 = 0;
+
+    if (proto == ETH_P_8021AD) {
+        proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
+                    h_vlan_encapsulated_proto));
+#if VLAN_TRACKING
+        if (data + nhoff <= data_end) {
+            vlan0 = ((struct vlan_hdr *)(data + nhoff))->h_vlan_TCI & 0x0fff;
+        }
+#endif
+        nhoff += sizeof(struct vlan_hdr);
+    }
+
+    if (proto == ETH_P_8021Q) {
+        proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
+                    h_vlan_encapsulated_proto));
+#if VLAN_TRACKING
+        if (data + nhoff <= data_end) {
+            vlan1 = ((struct vlan_hdr *)(data + nhoff))->h_vlan_TCI & 0x0fff;
+        }
+#endif
+        nhoff += sizeof(struct vlan_hdr);
+    }
     skb->cb[0] = nhoff;
     switch (skb->protocol) {
         case __constant_htons(ETH_P_IP):
-            return ipv4_filter(skb);
+            return ipv4_filter(skb, vlan0, vlan1);
         case __constant_htons(ETH_P_IPV6):
-            return ipv6_filter(skb);
+            return ipv6_filter(skb, vlan0, vlan1);
         default:
 #if 0
             {