]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
decoder/vxlan: initial implementation of decoder
authorHenrik Lund Kramshoej <hlk@kramse.org>
Tue, 17 Jul 2018 05:37:12 +0000 (07:37 +0200)
committerVictor Julien <victor@inliniac.net>
Thu, 27 Jun 2019 05:18:30 +0000 (07:18 +0200)
src/Makefile.am
src/decode-udp.c
src/decode-vxlan.c [new file with mode: 0644]
src/decode-vxlan.h [new file with mode: 0644]
src/decode.c
src/decode.h
src/runmode-unittests.c

index 875f9b8441b6257d6b73a4c7ceb4a38fe78b4a03..2d4a8d1f05876e32352aa8e2d5d760a79a699a29 100644 (file)
@@ -76,6 +76,7 @@ decode-tcp.c decode-tcp.h \
 decode-teredo.c decode-teredo.h \
 decode-udp.c decode-udp.h \
 decode-vlan.c decode-vlan.h \
+decode-vxlan.c decode-vxlan.h \
 decode-mpls.c decode-mpls.h \
 decode-template.c decode-template.h \
 defrag-config.c defrag-config.h \
index d84f969192069c53c015015c3e250234de5b0ee2..5585034037b9e108c02c78f34187959dd51e6de8 100644 (file)
@@ -34,6 +34,7 @@
 #include "decode.h"
 #include "decode-udp.h"
 #include "decode-teredo.h"
+#include "decode-vxlan.h"
 #include "decode-events.h"
 #include "util-unittest.h"
 #include "util-debug.h"
@@ -88,6 +89,13 @@ int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui
         FlowSetupPacket(p);
         return TM_ECODE_OK;
     }
+    /* TODO hardcoded port 4789 - to avoid spending time on non-VXLAN */
+    if (UDP_GET_DST_PORT(p) == 4789 && unlikely(DecodeVXLAN(tv, dtv, p, pkt,len, pq) == TM_ECODE_OK)) {
+        /* Here we have a VXLAN packet and don't need to handle app
+         * layer */
+        FlowSetupPacket(p);
+        return TM_ECODE_OK;
+    }
 
     FlowSetupPacket(p);
 
diff --git a/src/decode-vxlan.c b/src/decode-vxlan.c
new file mode 100644 (file)
index 0000000..ff6e4cb
--- /dev/null
@@ -0,0 +1,180 @@
+/* Copyright (C) 2014 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
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Henrik Kramshoej <hlk@kramse.org>
+ *
+ * VXLAN decoder.
+ */
+
+#include "suricata-common.h"
+#include "decode.h"
+#include "decode-vxlan.h"
+#include "decode-events.h"
+#include "decode-udp.h"
+
+#include "decode-ethernet.h"
+
+#include "flow.h"
+
+#include "util-unittest.h"
+#include "util-debug.h"
+
+#include "pkt-var.h"
+#include "util-profiling.h"
+#include "host.h"
+
+#define VXLAN_HEADER_LEN         8
+
+static bool g_vxlan_enabled = true;
+
+void DecodeVXLANConfig(void)
+{
+    int enabled = 0;
+    if (ConfGetBool("decoder.vxlan.enabled", &enabled) == 1) {
+        if (enabled) {
+            g_vxlan_enabled = true;
+        } else {
+            g_vxlan_enabled = false;
+        }
+    }
+}
+
+static int DecodeVXLANPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len)
+{
+    if (unlikely(len < UDP_HEADER_LEN)) {
+        ENGINE_SET_INVALID_EVENT(p, UDP_HLEN_TOO_SMALL);
+        return -1;
+    }
+
+    p->udph = (UDPHdr *)pkt;
+
+    SET_UDP_SRC_PORT(p,&p->sp);
+    SET_UDP_DST_PORT(p,&p->dp);
+
+    p->payload = pkt + UDP_HEADER_LEN;
+    p->payload_len = len - UDP_HEADER_LEN;
+    p->proto = IPPROTO_UDP;
+
+    return 0;
+}
+
+int DecodeVXLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt,
+        uint32_t len, PacketQueue *pq)
+{
+    if (!g_vxlan_enabled)
+        return TM_ECODE_FAILED;
+
+    /* Is this packet to short to contain an IPv4/IPv6 packet ? */
+    if (len < IPV4_HEADER_LEN)
+        return TM_ECODE_FAILED;
+
+    int event = 0;
+
+    if (unlikely(DecodeVXLANPacket(tv, p,pkt,len) < 0)) {
+        p->udph = NULL;
+        return TM_ECODE_FAILED;
+    }
+    StatsIncr(tv, dtv->counter_vxlan);
+
+    SCLogDebug("VXLAN UDP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 "",
+            UDP_GET_SRC_PORT(p), UDP_GET_DST_PORT(p), UDP_HEADER_LEN, p->payload_len);
+
+    /* VXLAN encapsulate Layer 2 in UDP, most likely IPv4 and IPv6  */
+
+    p->ethh = (EthernetHdr *)(pkt + UDP_HEADER_LEN + VXLAN_HEADER_LEN);
+    SCLogDebug("VXLAN Ethertype 0x%04x", SCNtohs(p->ethh->eth_type));
+    /* Best guess at inner packet. */
+    switch (SCNtohs(p->ethh->eth_type)) {
+        case ETHERNET_TYPE_ARP:
+            SCLogDebug("VXLAN found ARP");
+            break;
+        case ETHERNET_TYPE_IP:
+            SCLogDebug("VXLAN found IPv4");
+            /* DecodeIPV4(tv, dtv, p, pkt, len, pq); */
+            break;
+        case ETHERNET_TYPE_IPV6:
+            SCLogDebug("VXLAN found IPv6");
+            /* DecodeIPV6(tv, dtv, p, pkt, len, pq); */
+            break;
+        default:
+            SCLogDebug("VXLAN found no known Ethertype - only checks for IPv4, IPv6, ARP");
+            /* ENGINE_SET_INVALID_EVENT(p, VXLAN_UNKNOWN_PAYLOAD_TYPE);*/
+            /* return TM_ECODE_OK; */
+    }
+
+    SCLogDebug("VXLAN trying to decode with Ethernet");
+    DecodeEthernet(tv, dtv, p, pkt + UDP_HEADER_LEN + VXLAN_HEADER_LEN,
+      len - UDP_HEADER_LEN - VXLAN_HEADER_LEN, pq);
+
+    if (event) {
+        ENGINE_SET_EVENT(p, event);
+    }
+    return TM_ECODE_OK;
+}
+
+#ifdef UNITTESTS
+
+/**
+ * \test DecodeVXLANTest01 test a good vxlan header.
+ * Contains a DNS request packet
+ *
+ *  \retval 1 on success
+ *  \retval 0 on failure
+ */
+static int DecodeVXLANtest01 (void)
+{
+    uint8_t raw_vxlan[] = {
+        0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */
+        0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, /* VXLAN header */
+        0x10, 0x00, 0x00, 0x0c, 0x01, 0x00, /* inner destination MAC */
+        0x00, 0x51, 0x52, 0xb3, 0x54, 0xe5, /* inner source MAC */
+        0x08, 0x00, /* wot another IPv4 0x0800 */
+        0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
+        0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06,  /* IPv4 hdr */
+        0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */
+    };
+    Packet *p = PacketGetFromAlloc();
+    FAIL_IF_NULL(p);
+    ThreadVars tv;
+    DecodeThreadVars dtv;
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(p, 0, SIZE_OF_PACKET);
+    memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+    FlowInitConfig(FLOW_QUIET);
+    DecodeVXLAN(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan), NULL);
+
+    FAIL_IF(p->udph == NULL);
+
+    PACKET_RECYCLE(p);
+    FlowShutdown();
+    SCFree(p);
+    PASS;
+}
+#endif /* UNITTESTS */
+
+void DecodeVXLANRegisterTests(void)
+{
+#ifdef UNITTESTS
+    UtRegisterTest("DecodeVXLANtest01",
+                   DecodeVXLANtest01);
+#endif /* UNITTESTS */
+}
diff --git a/src/decode-vxlan.h b/src/decode-vxlan.h
new file mode 100644 (file)
index 0000000..747f2af
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2018 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
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Henrik Kramshoej <hlk@kramse.org>
+ *
+ * VXLAN decoder.
+ */
+
+#ifndef __DECODE_VXLAN_H__
+#define __DECODE_VXLAN_H__
+
+void DecodeVXLANRegisterTests(void);
+void DecodeVXLANConfig(void);
+
+#endif /* !__DECODE_VXLAN_H__ */
index 2c914d2e3a0f516de9c3e47c16b18e19b7bd22b1..6b295a8e67a669351f02b2f17854221cb950cfb0 100644 (file)
@@ -484,6 +484,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_vxlan = StatsRegisterCounter("decoder.vxlan", tv);
     dtv->counter_ieee8021ah = StatsRegisterCounter("decoder.ieee8021ah", tv);
     dtv->counter_teredo = StatsRegisterCounter("decoder.teredo", tv);
     dtv->counter_ipv4inipv6 = StatsRegisterCounter("decoder.ipv4_in_ipv6", tv);
index ba07c771cc27d2eed08b500ef304275c40876f67..c4c4a51a42b2774e9bb0431bc1323e85870e8212 100644 (file)
@@ -86,6 +86,7 @@ enum PktSrcEnum {
 #include "decode-raw.h"
 #include "decode-null.h"
 #include "decode-vlan.h"
+#include "decode-vxlan.h"
 #include "decode-mpls.h"
 
 #include "detect-reference.h"
@@ -660,6 +661,7 @@ typedef struct DecodeThreadVars_
     uint16_t counter_gre;
     uint16_t counter_vlan;
     uint16_t counter_vlan_qinq;
+    uint16_t counter_vxlan;
     uint16_t counter_ieee8021ah;
     uint16_t counter_pppoe;
     uint16_t counter_teredo;
@@ -942,6 +944,7 @@ int DecodeUDP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, P
 int DecodeSCTP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *);
 int DecodeGRE(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint32_t, PacketQueue *);
 int DecodeVLAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint32_t, PacketQueue *);
+int DecodeVXLAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint32_t, PacketQueue *);
 int DecodeMPLS(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint32_t, PacketQueue *);
 int DecodeERSPAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint32_t, PacketQueue *);
 int DecodeTEMPLATE(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *);
@@ -1165,4 +1168,3 @@ static inline bool VerdictTunnelPacket(Packet *p)
 }
 
 #endif /* __DECODE_H__ */
-
index 39f4ad64fe83bf1516b3fe078074e5fc155c6160..9ca42eb1f75f2eb96f4523b81caddab458955180 100644 (file)
@@ -148,6 +148,7 @@ static void RegisterUnittests(void)
     DecodeEthernetRegisterTests();
     DecodePPPRegisterTests();
     DecodeVLANRegisterTests();
+    DecodeVXLANRegisterTests();
     DecodeRawRegisterTests();
     DecodePPPOERegisterTests();
     DecodeICMPV4RegisterTests();
@@ -309,4 +310,3 @@ void RunUnittests(int list_unittests, const char *regex_arg)
     exit(EXIT_FAILURE);
 #endif /* UNITTESTS */
 }
-