]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
flow: optionally use livedev for hash
authorPhilippe Antoine <contact@catenacyber.fr>
Thu, 28 Apr 2022 07:49:38 +0000 (09:49 +0200)
committerVictor Julien <vjulien@oisf.net>
Mon, 5 Jun 2023 09:08:21 +0000 (11:08 +0200)
So that in a setup with different interfaces capturing different
networks, flows do not get mixed up

Ticket: #5270

src/flow-hash.c
src/flow.h
src/suricata.c
src/suricata.h
src/util-ebpf.c
suricata.yaml.in

index 26c7b1c60e1928e94ddd27ef8e8d184645cf08df..9edd6d1daed5296a317400e65d04ae4765b5c48d 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "util-time.h"
 #include "util-debug.h"
+#include "util-device.h"
 
 #include "util-hash-lookup3.h"
 
@@ -87,8 +88,9 @@ typedef struct FlowHashKey4_ {
         struct {
             uint32_t addrs[2];
             uint16_t ports[2];
-            uint16_t proto; /**< u16 so proto and recur add up to u32 */
-            uint16_t recur; /**< u16 so proto and recur add up to u32 */
+            uint8_t proto; /**< u8 so proto and recur and livedev add up to u32 */
+            uint8_t recur;
+            uint16_t livedev;
             uint16_t vlan_id[VLAN_MAX_LAYERS];
             uint16_t pad[1];
         };
@@ -101,8 +103,9 @@ typedef struct FlowHashKey6_ {
         struct {
             uint32_t src[4], dst[4];
             uint16_t ports[2];
-            uint16_t proto; /**< u16 so proto and recur add up to u32 */
-            uint16_t recur; /**< u16 so proto and recur add up to u32 */
+            uint8_t proto; /**< u8 so proto and recur and livedev add up to u32 */
+            uint8_t recur;
+            uint16_t livedev;
             uint16_t vlan_id[VLAN_MAX_LAYERS];
             uint16_t pad[1];
         };
@@ -125,8 +128,8 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p)
         fhk.ports[0] = 0xfedc;
         fhk.ports[1] = 0xba98;
 
-        fhk.proto = (uint16_t)p->proto;
-        fhk.recur = (uint16_t)p->recursion_level;
+        fhk.proto = (uint8_t)p->proto;
+        fhk.recur = (uint8_t)p->recursion_level;
         /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
          * is disabled. */
         fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
@@ -160,8 +163,8 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p)
 
         fhk.ports[0] = 0xfedc;
         fhk.ports[1] = 0xba98;
-        fhk.proto = (uint16_t)p->proto;
-        fhk.recur = (uint16_t)p->recursion_level;
+        fhk.proto = (uint8_t)p->proto;
+        fhk.recur = (uint8_t)p->recursion_level;
         fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
         fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
         fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
@@ -200,8 +203,12 @@ static inline uint32_t FlowGetHash(const Packet *p)
             fhk.ports[1-pi] = p->sp;
             fhk.ports[pi] = p->dp;
 
-            fhk.proto = (uint16_t)p->proto;
-            fhk.recur = (uint16_t)p->recursion_level;
+            fhk.proto = p->proto;
+            fhk.recur = p->recursion_level;
+            /* g_livedev_mask sets the livedev ids to 0 if livedev.use-for-tracking
+             * is disabled. */
+            uint16_t devid = p->livedev ? p->livedev->id : 0;
+            fhk.livedev = devid & g_livedev_mask;
             /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
              * is disabled. */
             fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
@@ -223,8 +230,10 @@ static inline uint32_t FlowGetHash(const Packet *p)
             fhk.ports[1-pi] = p->icmpv4vars.emb_sport;
             fhk.ports[pi] = p->icmpv4vars.emb_dport;
 
-            fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p);
-            fhk.recur = (uint16_t)p->recursion_level;
+            fhk.proto = ICMPV4_GET_EMB_PROTO(p);
+            fhk.recur = p->recursion_level;
+            uint16_t devid = p->livedev ? p->livedev->id : 0;
+            fhk.livedev = devid & g_livedev_mask;
             fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
             fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
             fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
@@ -238,8 +247,10 @@ static inline uint32_t FlowGetHash(const Packet *p)
             fhk.addrs[ai] = p->dst.addr_data32[0];
             fhk.ports[0] = 0xfeed;
             fhk.ports[1] = 0xbeef;
-            fhk.proto = (uint16_t)p->proto;
-            fhk.recur = (uint16_t)p->recursion_level;
+            fhk.proto = p->proto;
+            fhk.recur = p->recursion_level;
+            uint16_t devid = p->livedev ? p->livedev->id : 0;
+            fhk.livedev = devid & g_livedev_mask;
             fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
             fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
             fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
@@ -271,8 +282,10 @@ static inline uint32_t FlowGetHash(const Packet *p)
         const int pi = (p->sp > p->dp);
         fhk.ports[1-pi] = p->sp;
         fhk.ports[pi] = p->dp;
-        fhk.proto = (uint16_t)p->proto;
-        fhk.recur = (uint16_t)p->recursion_level;
+        fhk.proto = p->proto;
+        fhk.recur = p->recursion_level;
+        uint16_t devid = p->livedev ? p->livedev->id : 0;
+        fhk.livedev = devid & g_livedev_mask;
         fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
         fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
         fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask;
@@ -307,8 +320,9 @@ uint32_t FlowKeyGetHash(FlowKey *fk)
         fhk.ports[1-pi] = fk->sp;
         fhk.ports[pi] = fk->dp;
 
-        fhk.proto = (uint16_t)fk->proto;
-        fhk.recur = (uint16_t)fk->recursion_level;
+        fhk.proto = fk->proto;
+        fhk.recur = fk->recursion_level;
+        fhk.livedev = fk->livedev_id & g_livedev_mask;
         fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
         fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
         fhk.vlan_id[2] = fk->vlan_id[2] & g_vlan_mask;
@@ -342,8 +356,9 @@ uint32_t FlowKeyGetHash(FlowKey *fk)
         const int pi = (fk->sp > fk->dp);
         fhk.ports[1-pi] = fk->sp;
         fhk.ports[pi] = fk->dp;
-        fhk.proto = (uint16_t)fk->proto;
-        fhk.recur = (uint16_t)fk->recursion_level;
+        fhk.proto = fk->proto;
+        fhk.recur = fk->recursion_level;
+        fhk.livedev = fk->livedev_id & g_livedev_mask;
         fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
         fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
         fhk.vlan_id[2] = fk->vlan_id[2] & g_vlan_mask;
@@ -381,6 +396,12 @@ static inline bool CmpVlanIds(
            ((vlan_id1[2] ^ vlan_id2[2]) & g_vlan_mask) == 0;
 }
 
+static inline bool CmpLiveDevIds(const LiveDevice *livedev, const uint16_t id)
+{
+    uint16_t devid = livedev ? livedev->id : 0;
+    return (((devid ^ id) & g_livedev_mask) == 0);
+}
+
 /* Since two or more flows can have the same hash key, we need to compare
  * the flow with the current packet or flow key. */
 static inline bool CmpFlowPacket(const Flow *f, const Packet *p)
@@ -389,10 +410,9 @@ static inline bool CmpFlowPacket(const Flow *f, const Packet *p)
     const uint32_t *f_dst = f->dst.address.address_un_data32;
     const uint32_t *p_src = p->src.address.address_un_data32;
     const uint32_t *p_dst = p->dst.address.address_un_data32;
-    return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp,
-                            p->dp) && f->proto == p->proto &&
-            f->recursion_level == p->recursion_level &&
-            CmpVlanIds(f->vlan_id, p->vlan_id);
+    return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp, p->dp) &&
+           f->proto == p->proto && f->recursion_level == p->recursion_level &&
+           CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0);
 }
 
 static inline bool CmpFlowKey(const Flow *f, const FlowKey *k)
@@ -401,10 +421,9 @@ static inline bool CmpFlowKey(const Flow *f, const FlowKey *k)
     const uint32_t *f_dst = f->dst.address.address_un_data32;
     const uint32_t *k_src = k->src.address.address_un_data32;
     const uint32_t *k_dst = k->dst.address.address_un_data32;
-    return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp,
-                            k->dp) && f->proto == k->proto &&
-            f->recursion_level == k->recursion_level &&
-            CmpVlanIds(f->vlan_id, k->vlan_id);
+    return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp, k->dp) &&
+           f->proto == k->proto && f->recursion_level == k->recursion_level &&
+           CmpVlanIds(f->vlan_id, k->vlan_id) && CmpLiveDevIds(f->livedev, k->livedev_id);
 }
 
 static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4],
@@ -427,10 +446,10 @@ static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p)
     const uint32_t *f_dst = f->dst.address.address_un_data32;
     const uint32_t *p_src = p->src.address.address_un_data32;
     const uint32_t *p_dst = p->dst.address.address_un_data32;
-    return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type,
-                f->icmp_d.type, p_src, p_dst, p->icmp_s.type, p->icmp_d.type) &&
-            f->proto == p->proto && f->recursion_level == p->recursion_level &&
-            CmpVlanIds(f->vlan_id, p->vlan_id);
+    return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type, f->icmp_d.type, p_src, p_dst,
+                   p->icmp_s.type, p->icmp_d.type) &&
+           f->proto == p->proto && f->recursion_level == p->recursion_level &&
+           CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0);
 }
 
 /**
@@ -453,7 +472,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p)
                 (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) &&
                 f->sp == p->icmpv4vars.emb_sport && f->dp == p->icmpv4vars.emb_dport &&
                 f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level &&
-                CmpVlanIds(f->vlan_id, p->vlan_id)) {
+                CmpVlanIds(f->vlan_id, p->vlan_id) &&
+                (f->livedev == p->livedev || g_livedev_mask == 0)) {
             return 1;
 
         /* check the less likely case where the ICMP error was a response to
@@ -462,7 +482,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p)
                    (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) &&
                    f->dp == p->icmpv4vars.emb_sport && f->sp == p->icmpv4vars.emb_dport &&
                    f->proto == ICMPV4_GET_EMB_PROTO(p) &&
-                   f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id)) {
+                   f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id) &&
+                   (f->livedev == p->livedev || g_livedev_mask == 0)) {
             return 1;
         }
 
@@ -493,7 +514,7 @@ static inline int FlowCompareESP(Flow *f, const Packet *p)
 
     return CmpAddrs(f_src, p_src) && CmpAddrs(f_dst, p_dst) && f->proto == p->proto &&
            f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id) &&
-           f->esp.spi == ESP_GET_SPI(p);
+           f->esp.spi == ESP_GET_SPI(p) && (f->livedev == p->livedev || g_livedev_mask == 0);
 }
 
 void FlowSetupPacket(Packet *p)
@@ -1081,6 +1102,7 @@ Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t ha
     f->sp = key->sp;
     f->dp = key->dp;
     f->recursion_level = 0;
+    // f->livedev is set by caller EBPFCreateFlowForKey
     f->flow_hash = hash;
     if (key->src.family == AF_INET) {
         f->flags |= FLOW_IPV4;
index d08c6a4be080b7f7b460b43bbabb8043e1883a90..f6c2eb47fda9896efe8915ade136396d905295f8 100644 (file)
@@ -301,6 +301,7 @@ typedef struct FlowKey_
     Port sp, dp;
     uint8_t proto;
     uint8_t recursion_level;
+    uint16_t livedev_id;
     uint16_t vlan_id[VLAN_MAX_LAYERS];
 } FlowKey;
 
index 007ca7b329e074d8ecbda795eb60155985e58e8c..7172a49dba40d37d0525a6e741a4fcf0190ca69e 100644 (file)
@@ -202,6 +202,10 @@ int g_disable_randomness = 1;
   * comparing flows */
 uint16_t g_vlan_mask = 0xffff;
 
+/** determine (without branching) if we include the livedev ids when hashing or
+ * comparing flows */
+uint16_t g_livedev_mask = 0xffff;
+
 /* flag to disable hashing almost globally, to be similar to disabling nss
  * support */
 bool g_disable_hashing = false;
@@ -2933,13 +2937,16 @@ int SuricataMain(int argc, char **argv)
         exit(EXIT_SUCCESS);
     }
 
-    int vlan_tracking = 1;
-    if (ConfGetBool("vlan.use-for-tracking", &vlan_tracking) == 1 && !vlan_tracking) {
+    int tracking = 1;
+    if (ConfGetBool("vlan.use-for-tracking", &tracking) == 1 && !tracking) {
         /* Ignore vlan_ids when comparing flows. */
         g_vlan_mask = 0x0000;
     }
-    SCLogDebug("vlan tracking is %s", vlan_tracking == 1 ? "enabled" : "disabled");
-
+    SCLogDebug("vlan tracking is %s", tracking == 1 ? "enabled" : "disabled");
+    if (ConfGetBool("livedev.use-for-tracking", &tracking) == 1 && !tracking) {
+        /* Ignore livedev id when comparing flows. */
+        g_livedev_mask = 0x0000;
+    }
     SetupUserMode(&suricata);
     InitRunAs(&suricata);
 
index 82b049f583e24320fa2e26de5c6abcd11436b2d1..957134b92c068fd0a481d8437c431e15005a2f69 100644 (file)
@@ -172,6 +172,7 @@ void GlobalsInitPreConfig(void);
 extern volatile uint8_t suricata_ctl_flags;
 extern int g_disable_randomness;
 extern uint16_t g_vlan_mask;
+extern uint16_t g_livedev_mask;
 
 /* Flag to disable hashing (almost) globally. */
 extern bool g_disable_hashing;
index 1afedbd859cffd08bd0c24553bae01bbe705f9e8..13eaea828d9ba36ad02816e38e5894c9f51556ba 100644 (file)
@@ -758,6 +758,7 @@ static int EBPFForEachFlowV4Table(ThreadVars *th_v, LiveDevice *dev, const char
             flow_key.proto = IPPROTO_UDP;
         }
         flow_key.recursion_level = 0;
+        flow_key.livedev_id = dev->id;
         dead_flow = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key,
                                      ctime, pkts_cnt, bytes_cnt,
                                      mapfd, tcfg->cpus_count);
@@ -876,6 +877,7 @@ static int EBPFForEachFlowV6Table(ThreadVars *th_v,
             flow_key.proto = IPPROTO_UDP;
         }
         flow_key.recursion_level = 0;
+        flow_key.livedev_id = dev->id;
         pkts_cnt = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key,
                                     ctime, pkts_cnt, bytes_cnt,
                                     mapfd, tcfg->cpus_count);
index 96d3bc4ad71428b6a1a067cff7c6830685560f23..f9a575d726274aafe8d547615acfde28fa95f844 100644 (file)
@@ -1414,6 +1414,12 @@ flow:
 vlan:
   use-for-tracking: true
 
+# This option controls the use of livedev ids in the flow (and defrag)
+# hashing. This is enabled by default and should be disabled if
+# multiple live devices are used to capture traffic from the same network
+livedev:
+  use-for-tracking: true
+
 # Specific timeouts for flows. Here you can specify the timeouts that the
 # active flows will wait to transit from the current state to another, on each
 # protocol. The value of "new" determines the seconds to wait after a handshake or