Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flow: optionally use pkt recursion for hash #11913

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions doc/userguide/configuration/suricata-yaml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2780,6 +2780,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
----------------

Expand Down
41 changes: 26 additions & 15 deletions src/flow-hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,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;
Expand Down Expand Up @@ -164,7 +167,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;
Expand Down Expand Up @@ -204,7 +207,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;
Expand All @@ -231,7 +237,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;
Expand All @@ -248,7 +254,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;
Expand Down Expand Up @@ -283,7 +289,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;
Expand Down Expand Up @@ -321,7 +327,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;
Expand Down Expand Up @@ -357,7 +363,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;
Expand Down Expand Up @@ -411,7 +417,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);
}

Expand All @@ -422,7 +429,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);
}

Expand All @@ -448,7 +456,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);
}

Expand All @@ -471,7 +480,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;
Expand All @@ -482,7 +492,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;
}
Expand Down Expand Up @@ -513,8 +524,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);
}

Expand Down
8 changes: 8 additions & 0 deletions src/suricata.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,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;
Expand Down Expand Up @@ -2919,6 +2923,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);

Expand Down
1 change: 1 addition & 0 deletions src/suricata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,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
##
Expand Down
Loading