diff --git a/etc/schema.json b/etc/schema.json index 7223e0d75541..81024cf6b49b 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -4204,6 +4204,9 @@ "vlan_qinq": { "type": "integer" }, + "vlan_qinqinq": { + "type": "integer" + }, "vntag": { "type": "integer" }, diff --git a/src/decode-erspan.c b/src/decode-erspan.c index e9ffac180d7d..ccdf64aeaef9 100644 --- a/src/decode-erspan.c +++ b/src/decode-erspan.c @@ -99,7 +99,7 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t } if (vlan_id > 0) { - if (p->vlan_idx >= 2) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { ENGINE_SET_EVENT(p,ERSPAN_TOO_MANY_VLAN_LAYERS); return TM_ECODE_FAILED; } diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 61059201eb85..2ec8e2ad9706 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -62,6 +62,8 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, StatsIncr(tv, dtv->counter_vlan); else if (p->vlan_idx == 1) StatsIncr(tv, dtv->counter_vlan_qinq); + else if (p->vlan_idx == 2) + StatsIncr(tv, dtv->counter_vlan_qinqinq); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); @@ -70,7 +72,7 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, if (!PacketIncreaseCheckLayers(p)) { return TM_ECODE_FAILED; } - if (p->vlan_idx >= 2) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); return TM_ECODE_FAILED; } @@ -93,16 +95,6 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return TM_ECODE_OK; } -uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer) -{ - if (unlikely(layer > 1)) - return 0; - if (p->vlan_idx > layer) { - return p->vlan_id[layer]; - } - return 0; -} - typedef struct IEEE8021ahHdr_ { uint32_t flags; uint8_t c_destination[6]; diff --git a/src/decode-vlan.h b/src/decode-vlan.h index bdc0c0cc1c6a..809038dbe6fc 100644 --- a/src/decode-vlan.h +++ b/src/decode-vlan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -36,10 +36,6 @@ uint16_t DecodeVLANGetId(const struct Packet_ *, uint8_t layer); #define GET_VLAN_ID(vlanh) ((uint16_t)(SCNtohs((vlanh)->vlan_cfi) & 0x0FFF)) #define GET_VLAN_PROTO(vlanh) ((SCNtohs((vlanh)->protocol))) -/* return vlan id in host byte order */ -#define VLAN_GET_ID1(p) DecodeVLANGetId((p), 0) -#define VLAN_GET_ID2(p) DecodeVLANGetId((p), 1) - /** Vlan header struct */ typedef struct VLANHdr_ { uint16_t vlan_cfi; @@ -51,5 +47,9 @@ typedef struct VLANHdr_ { void DecodeVLANRegisterTests(void); +/** VLAN max encapsulation layer count/index */ +#define VLAN_MAX_LAYERS 3 +#define VLAN_MAX_LAYER_IDX (VLAN_MAX_LAYERS - 1) + #endif /* __DECODE_VLAN_H__ */ diff --git a/src/decode.c b/src/decode.c index 6a064cfd4199..303459e086bc 100644 --- a/src/decode.c +++ b/src/decode.c @@ -412,8 +412,7 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u p->tenant_id = parent->tenant_id; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); - p->vlan_id[0] = parent->vlan_id[0]; - p->vlan_id[1] = parent->vlan_id[1]; + memcpy(&p->vlan_id[0], &parent->vlan_id[0], sizeof(p->vlan_id)); p->vlan_idx = parent->vlan_idx; p->livedev = parent->livedev; @@ -555,6 +554,7 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) dtv->counter_gre = StatsRegisterCounter("decoder.gre", tv); dtv->counter_vlan = StatsRegisterCounter("decoder.vlan", tv); dtv->counter_vlan_qinq = StatsRegisterCounter("decoder.vlan_qinq", tv); + dtv->counter_vlan_qinqinq = StatsRegisterCounter("decoder.vlan_qinqinq", tv); dtv->counter_vxlan = StatsRegisterCounter("decoder.vxlan", tv); dtv->counter_vntag = StatsRegisterCounter("decoder.vntag", tv); dtv->counter_ieee8021ah = StatsRegisterCounter("decoder.ieee8021ah", tv); diff --git a/src/decode.h b/src/decode.h index 2646e0824194..b39502f54523 100644 --- a/src/decode.h +++ b/src/decode.h @@ -225,7 +225,6 @@ typedef struct Address_ { (p)->pktlen = (len); \ } while (0) - /* Port is just a uint16_t */ typedef uint16_t Port; #define SET_PORT(v, p) ((p) = (v)) @@ -453,7 +452,7 @@ typedef struct Packet_ * has the exact same tuple as the lower levels */ uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; uint8_t vlan_idx; /* flow */ @@ -700,6 +699,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_gre; uint16_t counter_vlan; uint16_t counter_vlan_qinq; + uint16_t counter_vlan_qinqinq; uint16_t counter_vxlan; uint16_t counter_vntag; uint16_t counter_ieee8021ah; @@ -1185,7 +1185,7 @@ static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv, case ETHERNET_TYPE_VLAN: case ETHERNET_TYPE_8021AD: case ETHERNET_TYPE_8021QINQ: - if (p->vlan_idx >= 2) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); } else { DecodeVLAN(tv, dtv, p, data, len); diff --git a/src/defrag-hash.c b/src/defrag-hash.c index dda23016429b..2f19ce28ee13 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -137,8 +137,7 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p) dt->af = AF_INET6; } dt->proto = IP_GET_IPPROTO(p); - dt->vlan_id[0] = p->vlan_id[0]; - dt->vlan_id[1] = p->vlan_id[1]; + memcpy(&dt->vlan_id[0], &p->vlan_id[0], sizeof(dt->vlan_id)); dt->policy = DefragGetOsPolicy(p); dt->host_timeout = DefragPolicyGetHostTimeout(p); dt->remove = 0; @@ -361,9 +360,10 @@ typedef struct DefragHashKey4_ { struct { uint32_t src, dst; uint32_t id; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - uint32_t u32[4]; + uint32_t u32[5]; }; } DefragHashKey4; @@ -372,9 +372,10 @@ typedef struct DefragHashKey6_ { struct { uint32_t src[4], dst[4]; uint32_t id; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - uint32_t u32[10]; + uint32_t u32[11]; }; } DefragHashKey6; @@ -392,7 +393,7 @@ static inline uint32_t DefragHashGetKey(Packet *p) uint32_t key; if (p->ip4h != NULL) { - DefragHashKey4 dhk; + DefragHashKey4 dhk = { .pad[0] = 0 }; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { dhk.src = p->src.addr_data32[0]; dhk.dst = p->dst.addr_data32[0]; @@ -401,13 +402,13 @@ static inline uint32_t DefragHashGetKey(Packet *p) dhk.dst = p->src.addr_data32[0]; } dhk.id = (uint32_t)IPV4_GET_IPID(p); - dhk.vlan_id[0] = p->vlan_id[0]; - dhk.vlan_id[1] = p->vlan_id[1]; + memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id)); - uint32_t hash = hashword(dhk.u32, 4, defrag_config.hash_rand); + uint32_t hash = + hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand); key = hash % defrag_config.hash_size; } else if (p->ip6h != NULL) { - DefragHashKey6 dhk; + DefragHashKey6 dhk = { .pad[0] = 0 }; if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { dhk.src[0] = p->src.addr_data32[0]; dhk.src[1] = p->src.addr_data32[1]; @@ -428,10 +429,10 @@ static inline uint32_t DefragHashGetKey(Packet *p) dhk.dst[3] = p->src.addr_data32[3]; } dhk.id = IPV6_EXTHDR_GET_FH_ID(p); - dhk.vlan_id[0] = p->vlan_id[0]; - dhk.vlan_id[1] = p->vlan_id[1]; + memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id)); - uint32_t hash = hashword(dhk.u32, 10, defrag_config.hash_rand); + uint32_t hash = + hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand); key = hash % defrag_config.hash_size; } else key = 0; @@ -441,15 +442,12 @@ static inline uint32_t DefragHashGetKey(Packet *p) /* Since two or more trackers can have the same hash key, we need to compare * the tracker with the current tracker key. */ -#define CMP_DEFRAGTRACKER(d1,d2,id) \ - (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && \ - CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ - (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \ - CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ - (d1)->proto == IP_GET_IPPROTO(d2) && \ - (d1)->id == (id) && \ - (d1)->vlan_id[0] == (d2)->vlan_id[0] && \ - (d1)->vlan_id[1] == (d2)->vlan_id[1]) +#define CMP_DEFRAGTRACKER(d1, d2, id) \ + (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ + (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ + (d1)->proto == IP_GET_IPPROTO(d2) && (d1)->id == (id) && \ + (d1)->vlan_id[0] == (d2)->vlan_id[0] && (d1)->vlan_id[1] == (d2)->vlan_id[1] && \ + (d1)->vlan_id[2] == (d2)->vlan_id[2]) static inline int DefragTrackerCompare(DefragTracker *t, Packet *p) { @@ -469,7 +467,7 @@ static inline int DefragTrackerCompare(DefragTracker *t, Packet *p) * Get a new defrag tracker. We're checking memcap first and will try to make room * if the memcap is reached. * - * \retval dt *LOCKED* tracker on succes, NULL on error. + * \retval dt *LOCKED* tracker on success, NULL on error. */ static DefragTracker *DefragTrackerGetNew(Packet *p) { diff --git a/src/defrag.c b/src/defrag.c index 989b39cb3389..a4c307834f08 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -2259,6 +2259,41 @@ static int DefragVlanQinQTest(void) PASS; } +/** + * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID. + */ +static int DefragVlanQinQinQTest(void) +{ + Packet *r = NULL; + + DefragInit(); + + Packet *p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + Packet *p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); + FAIL_IF_NULL(p2); + + /* With no VLAN IDs set, packets should re-assemble. */ + FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL); + SCFree(r); + + /* With mismatched VLANs, packets should not re-assemble. */ + p1->vlan_id[0] = 1; + p2->vlan_id[0] = 1; + p1->vlan_id[1] = 2; + p2->vlan_id[1] = 2; + p1->vlan_id[2] = 3; + p2->vlan_id[2] = 4; + FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL); + + PacketFree(p1); + PacketFree(p2); + DefragDestroy(); + + PASS; +} static int DefragTrackerReuseTest(void) { int id = 1; @@ -2508,6 +2543,7 @@ void DefragRegisterTests(void) UtRegisterTest("DefragVlanTest", DefragVlanTest); UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest); + UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest); UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest); UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest); UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test); diff --git a/src/defrag.h b/src/defrag.h index 016aa3ea5cd5..11e6a619b2f1 100644 --- a/src/defrag.h +++ b/src/defrag.h @@ -87,7 +87,7 @@ typedef struct DefragTracker_ { SCMutex lock; /**< Mutex for locking list operations on * this tracker. */ - uint16_t vlan_id[2]; /**< VLAN ID tracker applies to. */ + uint16_t vlan_id[VLAN_MAX_LAYERS]; /**< VLAN ID tracker applies to. */ uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16 * for IPv4. */ diff --git a/src/flow-hash.c b/src/flow-hash.c index 387adf0d6c23..9edd6d1daed5 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,11 +88,13 @@ 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 */ - uint16_t vlan_id[2]; + 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]; }; - const uint32_t u32[5]; + const uint32_t u32[6]; }; } FlowHashKey4; @@ -100,11 +103,13 @@ 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 */ - uint16_t vlan_id[2]; + 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]; }; - const uint32_t u32[11]; + const uint32_t u32[12]; }; } FlowHashKey6; @@ -112,7 +117,9 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) { uint32_t hash = 0; if (p->ip4h != NULL) { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { + .pad[0] = 0, + }; int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); fhk.addrs[1 - ai] = p->src.addr_data32[0]; @@ -121,16 +128,19 @@ 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; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else if (p->ip6h != NULL) { - FlowHashKey6 fhk; + FlowHashKey6 fhk = { + .pad[0] = 0, + }; if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { fhk.src[0] = p->src.addr_data32[0]; fhk.src[1] = p->src.addr_data32[1]; @@ -153,12 +163,13 @@ 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; - hash = hashword(fhk.u32, 11, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } return hash; } @@ -182,7 +193,7 @@ static inline uint32_t FlowGetHash(const Packet *p) if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { .pad[0] = 0 }; int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); fhk.addrs[1-ai] = p->src.addr_data32[0]; @@ -192,19 +203,24 @@ 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; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)); - FlowHashKey4 fhk; + FlowHashKey4 fhk = { .pad[0] = 0 }; const int ai = (psrc > pdst); fhk.addrs[1-ai] = psrc; @@ -214,29 +230,35 @@ 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; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { .pad[0] = 0 }; const int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); fhk.addrs[1-ai] = p->src.addr_data32[0]; 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; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } } else if (p->ip6h != NULL) { - FlowHashKey6 fhk; + FlowHashKey6 fhk = { .pad[0] = 0 }; if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { fhk.src[0] = p->src.addr_data32[0]; fhk.src[1] = p->src.addr_data32[1]; @@ -260,12 +282,15 @@ 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; - hash = hashword(fhk.u32, 11, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } return hash; @@ -284,7 +309,9 @@ uint32_t FlowKeyGetHash(FlowKey *fk) uint32_t hash = 0; if (fk->src.family == AF_INET) { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { + .pad[0] = 0, + }; int ai = (fk->src.address.address_un_data32[0] > fk->dst.address.address_un_data32[0]); fhk.addrs[1-ai] = fk->src.address.address_un_data32[0]; fhk.addrs[ai] = fk->dst.address.address_un_data32[0]; @@ -293,14 +320,18 @@ 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; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else { - FlowHashKey6 fhk; + FlowHashKey6 fhk = { + .pad[0] = 0, + }; if (FlowHashRawAddressIPv6GtU32(fk->src.address.address_un_data32, fk->dst.address.address_un_data32)) { fhk.src[0] = fk->src.address.address_un_data32[0]; @@ -325,12 +356,14 @@ 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; - hash = hashword(fhk.u32, 11, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } return hash; } @@ -355,10 +388,18 @@ static inline bool CmpAddrsAndPorts(const uint32_t src1[4], src_port1 == dst_port2 && dst_port1 == src_port2); } -static inline bool CmpVlanIds(const uint16_t vlan_id1[2], const uint16_t vlan_id2[2]) +static inline bool CmpVlanIds( + const uint16_t vlan_id1[VLAN_MAX_LAYERS], const uint16_t vlan_id2[VLAN_MAX_LAYERS]) { return ((vlan_id1[0] ^ vlan_id2[0]) & g_vlan_mask) == 0 && - ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0; + ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0 && + ((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 @@ -369,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) @@ -381,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], @@ -407,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); } /** @@ -433,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 @@ -442,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; } @@ -473,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) @@ -614,7 +655,7 @@ static inline void NoFlowHandleIPS(Packet *p) * \param tv thread vars * \param fls lookup support vars * - * \retval f *LOCKED* flow on succes, NULL on error. + * \retval f *LOCKED* flow on success, NULL on error. */ static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, Packet *p) { @@ -964,6 +1005,61 @@ Flow *FlowGetExistingFlowFromFlowId(int64_t flow_id) return f; } +/** \brief Look for existing Flow using a FlowKey + * + * Hash retrieval function for flows. Looks up the hash bucket containing the + * flow pointer. Then compares the packet with the found flow to see if it is + * the flow we need. If it isn't, walk the list until the right flow is found. + * + * + * \param key Pointer to FlowKey build using flow to look for + * \param hash Value of the flow hash + * \retval f *LOCKED* flow or NULL + */ +static Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash) +{ + /* get our hash bucket and lock it */ + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; + FBLOCK_LOCK(fb); + + SCLogDebug("fb %p fb->head %p", fb, fb->head); + + /* return if the bucket don't have a flow */ + if (fb->head == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + + /* ok, we have a flow in the bucket. Let's find out if it is our flow */ + Flow *f = fb->head; + + /* see if this is the flow we are looking for */ + if (FlowCompareKey(f, key) == 0) { + while (f) { + f = f->next; + + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + + if (FlowCompareKey(f, key) != 0) { + /* found our flow, lock & return */ + FLOWLOCK_WRLOCK(f); + + FBLOCK_UNLOCK(fb); + return f; + } + } + } + + /* lock & return */ + FLOWLOCK_WRLOCK(f); + + FBLOCK_UNLOCK(fb); + return f; +} + /** \brief Get or create a Flow using a FlowKey * * Hash retrieval function for flows. Looks up the hash bucket containing the @@ -993,8 +1089,8 @@ Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t ha return NULL; } f->proto = key->proto; - f->vlan_id[0] = key->vlan_id[0]; - f->vlan_id[1] = key->vlan_id[1]; + memcpy(&f->vlan_id[0], &key->vlan_id[0], sizeof(f->vlan_id)); + ; f->src.addr_data32[0] = key->src.addr_data32[0]; f->src.addr_data32[1] = key->src.addr_data32[1]; f->src.addr_data32[2] = key->src.addr_data32[2]; @@ -1006,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; @@ -1028,61 +1125,6 @@ Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t ha return f; } -/** \brief Look for existing Flow using a FlowKey - * - * Hash retrieval function for flows. Looks up the hash bucket containing the - * flow pointer. Then compares the packet with the found flow to see if it is - * the flow we need. If it isn't, walk the list until the right flow is found. - * - * - * \param key Pointer to FlowKey build using flow to look for - * \param hash Value of the flow hash - * \retval f *LOCKED* flow or NULL - */ -Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash) -{ - /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; - FBLOCK_LOCK(fb); - - SCLogDebug("fb %p fb->head %p", fb, fb->head); - - /* return if the bucket don't have a flow */ - if (fb->head == NULL) { - FBLOCK_UNLOCK(fb); - return NULL; - } - - /* ok, we have a flow in the bucket. Let's find out if it is our flow */ - Flow *f = fb->head; - - /* see if this is the flow we are looking for */ - if (FlowCompareKey(f, key) == 0) { - while (f) { - f = f->next; - - if (f == NULL) { - FBLOCK_UNLOCK(fb); - return NULL; - } - - if (FlowCompareKey(f, key) != 0) { - /* found our flow, lock & return */ - FLOWLOCK_WRLOCK(f); - - FBLOCK_UNLOCK(fb); - return f; - } - } - } - - /* lock & return */ - FLOWLOCK_WRLOCK(f); - - FBLOCK_UNLOCK(fb); - return f; -} - #define FLOW_GET_NEW_TRIES 5 /* inline locking wrappers to make profiling easier */ diff --git a/src/flow-hash.h b/src/flow-hash.h index a8c27f2ea4dd..201eb6414543 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -82,7 +82,6 @@ typedef struct FlowBucket_ { Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *tctx, Packet *, Flow **); Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash); -Flow *FlowGetExistingFlowFromHash(FlowKey * key, uint32_t hash); Flow *FlowGetExistingFlowFromFlowId(int64_t flow_id); uint32_t FlowKeyGetHash(FlowKey *flow_key); uint32_t FlowGetIpPairProtoHash(const Packet *p); diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 9196c22dbef0..91dd872375e4 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -90,8 +90,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->flags |= PKT_STREAM_EOF; p->flags |= PKT_HAS_FLOW; p->flags |= PKT_PSEUDO_STREAM_END; - p->vlan_id[0] = f->vlan_id[0]; - p->vlan_id[1] = f->vlan_id[1]; + memcpy(&p->vlan_id[0], &f->vlan_id[0], sizeof(p->vlan_id)); p->vlan_idx = f->vlan_idx; p->livedev = (struct LiveDevice_ *)f->livedev; diff --git a/src/flow-util.c b/src/flow-util.c index 324f9be87840..3572c0823f4e 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -150,8 +150,7 @@ void FlowInit(Flow *f, const Packet *p) f->proto = p->proto; f->recursion_level = p->recursion_level; - f->vlan_id[0] = p->vlan_id[0]; - f->vlan_id[1] = p->vlan_id[1]; + memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id)); f->vlan_idx = p->vlan_idx; f->livedev = p->livedev; diff --git a/src/flow.h b/src/flow.h index 6ec901c00972..f6c2eb47fda9 100644 --- a/src/flow.h +++ b/src/flow.h @@ -301,7 +301,8 @@ typedef struct FlowKey_ Port sp, dp; uint8_t proto; uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t livedev_id; + uint16_t vlan_id[VLAN_MAX_LAYERS]; } FlowKey; typedef struct FlowAddress_ { @@ -364,7 +365,7 @@ typedef struct Flow_ }; uint8_t proto; uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; uint8_t vlan_idx; diff --git a/src/output-json-flow.c b/src/output-json-flow.c index a52e20eb28b3..07bcd954f2f5 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -113,6 +113,9 @@ static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) if (f->vlan_idx > 1) { jb_append_uint(jb, f->vlan_id[1]); } + if (f->vlan_idx > 2) { + jb_append_uint(jb, f->vlan_id[2]); + } jb_close(jb); } diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index de9dbdb4ec84..2ac6995cfad6 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -117,6 +117,9 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) if (f->vlan_idx > 1) { jb_append_uint(js, f->vlan_id[1]); } + if (f->vlan_idx > 2) { + jb_append_uint(js, f->vlan_id[2]); + } jb_close(js); } diff --git a/src/output-json.c b/src/output-json.c index 09128403a9dc..95a6e5ef4c25 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -836,6 +836,9 @@ JsonBuilder *CreateEveHeader(const Packet *p, enum OutputJsonLogDirection dir, if (p->vlan_idx > 1) { jb_append_uint(js, p->vlan_id[1]); } + if (p->vlan_idx > 2) { + jb_append_uint(js, p->vlan_id[2]); + } jb_close(js); } diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 89f8c2e80319..0c50ed219aa6 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -2209,6 +2209,7 @@ static int AFPBypassCallback(Packet *p) keys[0]->port16[1] = GET_TCP_DST_PORT(p); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV4_GET_IPPROTO(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; @@ -2234,6 +2235,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->port16[1] = GET_TCP_SRC_PORT(p); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], @@ -2269,6 +2271,7 @@ static int AFPBypassCallback(Packet *p) keys[0]->port16[1] = GET_TCP_DST_PORT(p); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV6_GET_NH(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; @@ -2296,6 +2299,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->port16[1] = GET_TCP_SRC_PORT(p); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], @@ -2363,6 +2367,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[0]->port16[1] = htons(p->dp); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV4_GET_IPPROTO(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; } else { @@ -2387,6 +2392,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->port16[1] = htons(p->sp); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { @@ -2420,6 +2426,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[0]->port16[1] = htons(GET_TCP_DST_PORT(p)); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV6_GET_NH(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; } else { @@ -2446,6 +2453,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->port16[1] = htons(GET_TCP_SRC_PORT(p)); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 5c355ee72324..e58043fbac99 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -6506,8 +6506,7 @@ static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, np->flags |= PKT_HAS_FLOW; np->flags |= PKT_IGNORE_CHECKSUM; np->flags |= PKT_PSEUDO_DETECTLOG_FLUSH; - np->vlan_id[0] = f->vlan_id[0]; - np->vlan_id[1] = f->vlan_id[1]; + memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id)); np->vlan_idx = f->vlan_idx; np->livedev = (struct LiveDevice_ *)f->livedev; diff --git a/src/suricata.c b/src/suricata.c index 007ca7b329e0..7172a49dba40 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 f4ce718f7eb3..fb9a7534c6f3 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-device.c b/src/util-device.c index 5eed6abdb5da..74a51c9f1069 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -132,6 +132,12 @@ int LiveRegisterDevice(const char *dev) return -1; } + int id = LiveGetDeviceCount(); + if (id > UINT16_MAX) { + SCFree(pd); + return -1; + } + pd->dev = SCStrdup(dev); if (unlikely(pd->dev == NULL)) { SCFree(pd); @@ -143,7 +149,7 @@ int LiveRegisterDevice(const char *dev) SC_ATOMIC_INIT(pd->pkts); SC_ATOMIC_INIT(pd->drop); SC_ATOMIC_INIT(pd->invalid_checksums); - pd->id = LiveGetDeviceCount(); + pd->id = (uint16_t)id; TAILQ_INSERT_TAIL(&live_devices, pd, next); SCLogDebug("Device \"%s\" registered and created.", dev); diff --git a/src/util-device.h b/src/util-device.h index ae9ec97c08b5..51ddf7d5257a 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -51,7 +51,7 @@ typedef struct LiveDevice_ { char dev_short[MAX_DEVNAME + 1]; bool tenant_id_set; - int id; + uint16_t id; SC_ATOMIC_DECLARE(uint64_t, pkts); SC_ATOMIC_DECLARE(uint64_t, drop); diff --git a/src/util-ebpf.c b/src/util-ebpf.c index af99dca227a7..13eaea828d9b 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -751,12 +751,14 @@ static int EBPFForEachFlowV4Table(ThreadVars *th_v, LiveDevice *dev, const char flow_key.dst.addr_data32[3] = 0; flow_key.vlan_id[0] = next_key.vlan0; flow_key.vlan_id[1] = next_key.vlan1; + flow_key.vlan_id[2] = next_key.vlan2; if (next_key.ip_proto == 1) { flow_key.proto = IPPROTO_TCP; } else { 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); @@ -868,12 +870,14 @@ static int EBPFForEachFlowV6Table(ThreadVars *th_v, } flow_key.vlan_id[0] = next_key.vlan0; flow_key.vlan_id[1] = next_key.vlan1; + flow_key.vlan_id[2] = next_key.vlan2; if (next_key.ip_proto == 1) { flow_key.proto = IPPROTO_TCP; } else { 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/src/util-ebpf.h b/src/util-ebpf.h index fa77ad2c9e02..bf1768a69da7 100644 --- a/src/util-ebpf.h +++ b/src/util-ebpf.h @@ -44,6 +44,7 @@ struct flowv4_keys { __u8 ip_proto:1; __u16 vlan0:15; __u16 vlan1; + __u16 vlan2; }; struct flowv6_keys { @@ -56,6 +57,7 @@ struct flowv6_keys { __u8 ip_proto:1; __u16 vlan0:15; __u16 vlan1; + __u16 vlan2; }; struct pair { diff --git a/suricata.yaml.in b/suricata.yaml.in index 947a68268228..b7d9943692e6 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