From: Philippe Antoine Date: Thu, 28 Apr 2022 07:49:38 +0000 (+0200) Subject: flow: optionally use livedev for hash X-Git-Tag: suricata-7.0.0-rc2~76 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7e725c650d7d73814c1572ac8db48814b1c89333;p=thirdparty%2Fsuricata.git flow: optionally use livedev for hash So that in a setup with different interfaces capturing different networks, flows do not get mixed up Ticket: #5270 --- diff --git a/src/flow-hash.c b/src/flow-hash.c index 26c7b1c60e..9edd6d1dae 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -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; diff --git a/src/flow.h b/src/flow.h index d08c6a4be0..f6c2eb47fd 100644 --- a/src/flow.h +++ b/src/flow.h @@ -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; diff --git a/src/suricata.c b/src/suricata.c index 007ca7b329..7172a49dba 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -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); diff --git a/src/suricata.h b/src/suricata.h index 82b049f583..957134b92c 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -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; diff --git a/src/util-ebpf.c b/src/util-ebpf.c index 1afedbd859..13eaea828d 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -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); diff --git a/suricata.yaml.in b/suricata.yaml.in index 96d3bc4ad7..f9a575d726 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -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