]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
ebpf: tls encrypted bypass in xdp_filter
authorEric Leblond <eric@regit.org>
Sat, 11 May 2019 09:14:23 +0000 (11:14 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 18 Jun 2019 05:07:02 +0000 (07:07 +0200)
Tests have shown that when we bypass encrypted traffic a non
neglicteable amount of encrypted  packets of the session are already in the
capture ring buffer. Result is that Suricata is doing unnecessary
work on these packets.

These packets can be identified via the first bytes of their payloads
so we can bypass them directly in the XDP code. This is done here
for application data packets on port 443 and for TLS 1.2.

ebpf/xdp_filter.c

index 8ffa412762fff8bb669473408b386c19ef005fff..f84cecd4357843483207fd2f523c885c731ebcd0 100644 (file)
 /* Increase CPUMAP_MAX_CPUS if ever you have more than 64 CPUs */
 #define CPUMAP_MAX_CPUS     64
 
+/* Set to 1 to bypass encrypted packets of TLS sessions. Suricata will
+ * be blind to these packets or forged packets looking alike. */
+#define ENCRYPTED_TLS_BYPASS    0
+
 /* Set it to 0 if for example you plan to use the XDP filter in a
  * network card that don't support per CPU value (like netronome) */
 #define USE_PERCPU_HASH     1
@@ -107,6 +111,20 @@ struct bpf_map_def SEC("maps") flow_table_v6 = {
     .max_entries = 32768,
 };
 
+
+#if ENCRYPTED_TLS_BYPASS
+struct bpf_map_def SEC("maps") tls_bypass_count = {
+#if USE_PERCPU_HASH
+    .type              = BPF_MAP_TYPE_PERCPU_ARRAY,
+#else
+    .type              = BPF_MAP_TYPE_ARRAY,
+#endif
+    .key_size  = sizeof(__u32),
+    .value_size        = sizeof(__u64),
+    .max_entries       = 1,
+};
+#endif
+
 #if BUILD_CPUMAP
 /* Special map type that can XDP_REDIRECT frames to another CPU */
 struct bpf_map_def SEC("maps") cpu_map = {
@@ -219,6 +237,10 @@ static int __always_inline filter_ipv4(struct xdp_md *ctx, void *data, __u64 nh_
 #if BUILD_CPUMAP || GOT_TX_PEER
     __u32 key0 = 0;
 #endif
+#if ENCRYPTED_TLS_BYPASS
+    __u32 key1 = 0;
+    __u32 *tls_count = NULL;
+#endif
 #if BUILD_CPUMAP
     __u32 cpu_dest;
     __u32 *cpu_max = bpf_map_lookup_elem(&cpus_count, &key0);
@@ -287,6 +309,38 @@ static int __always_inline filter_ipv4(struct xdp_md *ctx, void *data, __u64 nh_
 #endif
     }
 
+#if ENCRYPTED_TLS_BYPASS
+    if ((dport == __constant_ntohs(443)) || (sport == __constant_ntohs(443))) {
+        __u8 *app_data;
+        /* drop application data for tls 1.2 */
+        /* FIXME better parsing */
+        nh_off += sizeof(struct iphdr) + sizeof(struct tcphdr);
+        if (data_end > data + nh_off + 4) {
+            app_data = data + nh_off;
+            if (app_data[0] == 0x17 && app_data[1] == 0x3 && app_data[2] == 0x3) {
+                tls_count = bpf_map_lookup_elem(&tls_bypass_count, &key1);
+                if (tls_count) {
+#if USE_PERCPU_HASH
+                    tls_count++;
+#else
+                    __sync_fetch_and_add(tls_count, 1);
+#endif
+                }
+#if GOT_TX_PEER
+                iface_peer = bpf_map_lookup_elem(&tx_peer_int, &key0);
+                if (!iface_peer) {
+                    return XDP_DROP;
+                } else {
+                    return bpf_redirect_map(&tx_peer, tx_port, 0);
+                }
+#else
+                return XDP_DROP;
+#endif
+            }
+        }
+    }
+#endif
+
 #if BUILD_CPUMAP
     /* IP-pairs + protocol (UDP/TCP/ICMP) hit same CPU */
     cpu_hash = tuple.src + tuple.dst;