From 0d2268ddfcc65462a53fc7f27dcc68ae87c8ecf8 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Sun, 7 Aug 2022 15:53:21 -0400 Subject: [PATCH] decode/vlan: Decode upto 3 layers of VLAN Issue: 2816 This commit increase the number of VLAN layers supported by Suricata from 2 to 3. 3-layers are dubbed "Q-in-Q-in-Q". Note that 3 layers are not compliant with any existing standard but are often seen in larger deployments. --- src/decode-erspan.c | 2 +- src/decode-vlan.c | 6 ++-- src/decode-vlan.h | 5 +++ src/decode.c | 4 +-- src/decode.h | 6 ++-- src/defrag-hash.c | 46 +++++++++++++------------- src/defrag.c | 38 +++++++++++++++++++++- src/defrag.h | 2 +- src/flow-hash.c | 68 +++++++++++++++++++++++++-------------- src/flow-timeout.c | 3 +- src/flow-util.c | 3 +- src/flow.h | 4 +-- src/output-json-flow.c | 3 ++ src/output-json-netflow.c | 3 ++ src/output-json.c | 3 ++ src/source-af-packet.c | 8 +++++ src/stream-tcp.c | 3 +- src/util-ebpf.c | 2 ++ src/util-ebpf.h | 2 ++ 19 files changed, 145 insertions(+), 66 deletions(-) diff --git a/src/decode-erspan.c b/src/decode-erspan.c index e9ffac180d..ccdf64aeae 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 61059201eb..b4683a1d62 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -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; } @@ -95,7 +97,7 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer) { - if (unlikely(layer > 1)) + if (unlikely(layer > 2)) return 0; if (p->vlan_idx > layer) { return p->vlan_id[layer]; diff --git a/src/decode-vlan.h b/src/decode-vlan.h index bdc0c0cc1c..a70517c709 100644 --- a/src/decode-vlan.h +++ b/src/decode-vlan.h @@ -39,6 +39,7 @@ uint16_t DecodeVLANGetId(const struct Packet_ *, uint8_t layer); /* return vlan id in host byte order */ #define VLAN_GET_ID1(p) DecodeVLANGetId((p), 0) #define VLAN_GET_ID2(p) DecodeVLANGetId((p), 1) +#define VLAN_GET_ID3(p) DecodeVLANGetId((p), 2) /** Vlan header struct */ typedef struct VLANHdr_ { @@ -51,5 +52,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 6a064cfd41..303459e086 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 2646e08241..b39502f545 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 dda2301642..b812c171e2 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) { diff --git a/src/defrag.c b/src/defrag.c index 989b39cb33..a4c307834f 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 016aa3ea5c..11e6a619b2 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 387adf0d6c..38d419c135 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -89,9 +89,10 @@ typedef struct FlowHashKey4_ { 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]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - const uint32_t u32[5]; + const uint32_t u32[6]; }; } FlowHashKey4; @@ -102,9 +103,10 @@ typedef struct FlowHashKey6_ { 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]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - const uint32_t u32[11]; + const uint32_t u32[12]; }; } FlowHashKey6; @@ -112,7 +114,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]; @@ -127,10 +131,13 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) * 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]; @@ -157,8 +164,9 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) fhk.recur = (uint16_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 +190,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]; @@ -198,13 +206,14 @@ static inline uint32_t FlowGetHash(const Packet *p) * 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; @@ -218,11 +227,12 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.recur = (uint16_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, 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]; @@ -232,11 +242,12 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.recur = (uint16_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, 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]; @@ -264,8 +275,9 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.recur = (uint16_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; @@ -284,7 +296,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]; @@ -297,10 +311,13 @@ uint32_t FlowKeyGetHash(FlowKey *fk) fhk.recur = (uint16_t)fk->recursion_level; 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]; @@ -329,8 +346,9 @@ uint32_t FlowKeyGetHash(FlowKey *fk) fhk.recur = (uint16_t)fk->recursion_level; 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 +373,12 @@ 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; } /* Since two or more flows can have the same hash key, we need to compare @@ -993,8 +1013,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]; diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 9196c22dbe..91dd872375 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 324f9be878..3572c0823f 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 6ec901c009..d08c6a4be0 100644 --- a/src/flow.h +++ b/src/flow.h @@ -301,7 +301,7 @@ typedef struct FlowKey_ Port sp, dp; uint8_t proto; uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; } FlowKey; typedef struct FlowAddress_ { @@ -364,7 +364,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 a52e20eb28..07bcd954f2 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 de9dbdb4ec..2ac6995cfa 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 09128403a9..95a6e5ef4c 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 89f8c2e803..0c50ed219a 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 ec87745c3b..d30bb39a48 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -6504,8 +6504,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/util-ebpf.c b/src/util-ebpf.c index af99dca227..1afedbd859 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -751,6 +751,7 @@ 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 { @@ -868,6 +869,7 @@ 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 { diff --git a/src/util-ebpf.h b/src/util-ebpf.h index fa77ad2c9e..bf1768a69d 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 {