diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 8004ecce91..f6b0a7cb4b 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -2871,6 +2871,24 @@ Using this default configuration, Teredo detection will run on UDP port 3544. If the `ports` parameter is missing, or set to `any`, all ports will be inspected for possible presence of Teredo. +Recursion Level +~~~~~~~~~~~~~~~ + +Flow matching via recursion level can be disabled. It is enabled by +default. + +:: + + decoder: + # Depending on packet pickup, incoming and outgoing tunnelled packets + # can be scanned before the kernel has stripped and encapsulated headers, + # respectively, leading to incoming and outgoing flows not being associated. + recursion-level: + use-for-tracking: true + +Using this default setting, flows will be associated only if the compared packet +headers are encapsulated in the same number of headers. + Advanced Options ---------------- diff --git a/src/flow-hash.c b/src/flow-hash.c index c08b6e12c7..21a39b3cfd 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -130,7 +130,10 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) fhk.ports[1] = 0xba98; fhk.proto = (uint8_t)p->proto; - fhk.recur = (uint8_t)p->recursion_level; + /* g_recurlvl_mask sets the recursion_level to 0 if + * decoder.recursion-level.use-for-tracking is disabled. + */ + fhk.recur = (uint8_t)p->recursion_level & g_recurlvl_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; @@ -165,7 +168,7 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) fhk.ports[0] = 0xfedc; fhk.ports[1] = 0xba98; fhk.proto = (uint8_t)p->proto; - fhk.recur = (uint8_t)p->recursion_level; + fhk.recur = (uint8_t)p->recursion_level & g_recurlvl_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; @@ -205,7 +208,10 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.ports[pi] = p->dp; fhk.proto = p->proto; - fhk.recur = p->recursion_level; + /* g_recurlvl_mask sets the recursion_level to 0 if + * decoder.recursion-level.use-for-tracking is disabled. + */ + fhk.recur = p->recursion_level & g_recurlvl_mask; /* 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; @@ -232,7 +238,7 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.ports[pi] = p->l4.vars.icmpv4.emb_dport; fhk.proto = ICMPV4_GET_EMB_PROTO(p); - fhk.recur = p->recursion_level; + fhk.recur = p->recursion_level & g_recurlvl_mask; 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; @@ -249,7 +255,7 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.ports[0] = 0xfeed; fhk.ports[1] = 0xbeef; fhk.proto = p->proto; - fhk.recur = p->recursion_level; + fhk.recur = p->recursion_level & g_recurlvl_mask; 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; @@ -284,7 +290,7 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.ports[1-pi] = p->sp; fhk.ports[pi] = p->dp; fhk.proto = p->proto; - fhk.recur = p->recursion_level; + fhk.recur = p->recursion_level & g_recurlvl_mask; 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; @@ -322,7 +328,7 @@ uint32_t FlowKeyGetHash(FlowKey *fk) fhk.ports[pi] = fk->dp; fhk.proto = fk->proto; - fhk.recur = fk->recursion_level; + fhk.recur = fk->recursion_level & g_recurlvl_mask; 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; @@ -358,7 +364,7 @@ uint32_t FlowKeyGetHash(FlowKey *fk) fhk.ports[1-pi] = fk->sp; fhk.ports[pi] = fk->dp; fhk.proto = fk->proto; - fhk.recur = fk->recursion_level; + fhk.recur = fk->recursion_level & g_recurlvl_mask; 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; @@ -412,7 +418,8 @@ static inline bool CmpFlowPacket(const Flow *f, const Packet *p) 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 && + f->proto == p->proto && + (f->recursion_level == p->recursion_level || g_recurlvl_mask == 0) && CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0); } @@ -423,7 +430,8 @@ static inline bool CmpFlowKey(const Flow *f, const FlowKey *k) 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 && + f->proto == k->proto && + (f->recursion_level == k->recursion_level || g_recurlvl_mask == 0) && CmpVlanIds(f->vlan_id, k->vlan_id) && CmpLiveDevIds(f->livedev, k->livedev_id); } @@ -449,7 +457,8 @@ static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p) 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 && + f->proto == p->proto && + (f->recursion_level == p->recursion_level || g_recurlvl_mask == 0) && CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0); } @@ -472,7 +481,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p))) && (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p))) && f->sp == p->l4.vars.icmpv4.emb_sport && f->dp == p->l4.vars.icmpv4.emb_dport && - f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level && + f->proto == ICMPV4_GET_EMB_PROTO(p) && + (f->recursion_level == p->recursion_level || g_recurlvl_mask == 0) && CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0)) { return 1; @@ -483,7 +493,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p))) && f->dp == p->l4.vars.icmpv4.emb_sport && f->sp == p->l4.vars.icmpv4.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 || g_recurlvl_mask == 0) && + CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0)) { return 1; } @@ -514,8 +525,8 @@ static inline int FlowCompareESP(Flow *f, const Packet *p) const uint32_t *p_dst = p->dst.address.address_un_data32; 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(PacketGetESP(p)) && + (f->recursion_level == p->recursion_level || g_recurlvl_mask == 0) && + CmpVlanIds(f->vlan_id, p->vlan_id) && f->esp.spi == ESP_GET_SPI(PacketGetESP(p)) && (f->livedev == p->livedev || g_livedev_mask == 0); } diff --git a/src/suricata.c b/src/suricata.c index 7c238c48cc..60b67f717b 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -202,6 +202,10 @@ uint16_t g_vlan_mask = 0xffff; * comparing flows */ uint16_t g_livedev_mask = 0xffff; +/** determine (without branching) if we include the recursion levels when hashing or + * comparing flows */ +uint8_t g_recurlvl_mask = 0xff; + /* flag to disable hashing almost globally, to be similar to disabling nss * support */ bool g_disable_hashing = false; @@ -2914,6 +2918,10 @@ void SuricataInit(void) /* Ignore livedev id when comparing flows. */ g_livedev_mask = 0x0000; } + if (ConfGetBool("decoder.recursion-level.use-for-tracking", &tracking) == 1 && !tracking) { + /* Ignore recursion level when comparing flows. */ + g_recurlvl_mask = 0x00; + } SetupUserMode(&suricata); InitRunAs(&suricata); diff --git a/src/suricata.h b/src/suricata.h index 70393541f6..70209f393e 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -173,6 +173,7 @@ extern volatile uint8_t suricata_ctl_flags; extern int g_disable_randomness; extern uint16_t g_vlan_mask; extern uint16_t g_livedev_mask; +extern uint8_t g_recurlvl_mask; /* Flag to disable hashing (almost) globally. */ extern bool g_disable_hashing; diff --git a/suricata.yaml.in b/suricata.yaml.in index 4bc9e87aa2..46c94f0def 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1673,6 +1673,13 @@ decoder: # maximum number of decoder layers for a packet # max-layers: 16 + # This option controls the use of packet recursion level in the flow + # (and defrag) hashing. This is enabled by default and should be + # disabled if packet pickup of tunneled packets occurs before the kernel + # has put the headers on, like when using netmap driver pickup. + recursion-level: + use-for-tracking: true + ## ## Performance tuning and profiling ##