]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
decode/vlan: Decode upto 3 layers of VLAN
authorJeff Lucovsky <jeff.lucovsky@corelight.com>
Sun, 7 Aug 2022 19:53:21 +0000 (15:53 -0400)
committerVictor Julien <vjulien@oisf.net>
Mon, 5 Jun 2023 09:08:21 +0000 (11:08 +0200)
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.

19 files changed:
src/decode-erspan.c
src/decode-vlan.c
src/decode-vlan.h
src/decode.c
src/decode.h
src/defrag-hash.c
src/defrag.c
src/defrag.h
src/flow-hash.c
src/flow-timeout.c
src/flow-util.c
src/flow.h
src/output-json-flow.c
src/output-json-netflow.c
src/output-json.c
src/source-af-packet.c
src/stream-tcp.c
src/util-ebpf.c
src/util-ebpf.h

index e9ffac180d7d31b51f43bff0764ad079609a0910..ccdf64aeaef98db064a6703b90f1ec291fcef63f 100644 (file)
@@ -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;
         }
index 61059201eb8599e0d44e92532c06f2b44f2785ca..b4683a1d626eae09d3e8f16a33e36e14eba2649f 100644 (file)
@@ -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];
index bdc0c0cc1c6a1c8eafa9c219a0f6766a143c4f2a..a70517c709d44badc5be3309c58f87e250395cec 100644 (file)
@@ -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__ */
 
index 6a064cfd4199a5f1307bfe6559e59e093c844ad4..303459e086bcd54a5296d7c3abbd2c18aadcde67 100644 (file)
@@ -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);
index 2646e0824194762e7a5b14d3161751f1881dcb41..b39502f54523ce6a245437eb8fed1d83e31fb3ae 100644 (file)
@@ -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);
index dda23016429b36af54e6ca93ef926a640b69e213..b812c171e2e361540e050db9d1e8912d8ce836df 100644 (file)
@@ -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)
 {
index 989b39cb33896a83d388d18d1749c727a11a8ce7..a4c307834f08240257b12ec553bddb7c7c35dc6a 100644 (file)
@@ -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);
index 016aa3ea5cd5eff1502345f1942fef289d20be25..11e6a619b2f1fadbff068b775f0e8405f9bd0a04 100644 (file)
@@ -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. */
index 387adf0d6c232481850647bca6469f4eefb59246..38d419c1359a7a08544c6bccd3db901368f4a45e 100644 (file)
@@ -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];
index 9196c22dbef0fa3ac9f6e78be2d58129d15a3651..91dd872375e447522ae009fc0d242c7c27498e0b 100644 (file)
@@ -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;
 
index 324f9be8784029a5c8ad9ca3e32f0173608c260a..3572c0823f4e4ab941e0d1b474c60d57be32d332 100644 (file)
@@ -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;
 
index 6ec901c0097219802d558a8774473364aecbd15f..d08c6a4be080b7f7b460b43bbabb8043e1883a90 100644 (file)
@@ -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;
 
index a52e20eb28b363b2d86f42ea02024389993e3024..07bcd954f2f51d046855695d49349bb832ba8ca8 100644 (file)
@@ -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);
     }
 
index de9dbdb4ec84a01210ad021e615dac3f542aec46..2ac6995cfad6a3492be73bf1a2fe7ae52ed88354 100644 (file)
@@ -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);
     }
 
index 09128403a9dc21af133cb96d2677d4a6a8a286a2..95a6e5ef4c251651495d1b2300e5e31e8e1e0497 100644 (file)
@@ -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);
     }
 
index 89f8c2e80319616c1e54f602ed99aa476629a41e..0c50ed219aa661c0c3478ed75e48b3ca53472307 100644 (file)
@@ -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) {
index ec87745c3b1ba27b1af4c591ac3628c67f80a8b2..d30bb39a48b70eec8ae51f8d5eb01d0931f465f1 100644 (file)
@@ -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;
 
index af99dca227a7bac4be4074a9363eee119bf7ca22..1afedbd859cffd08bd0c24553bae01bbe705f9e8 100644 (file)
@@ -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 {
index fa77ad2c9e023381926c7e694efe21bcd854a66d..bf1768a69da71d175ebb998034b42957974ecbd8 100644 (file)
@@ -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 {