]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2911 in SNORT/snort3 from ~RAMANKS/snort3:geneve to master
authorSteve Chew (stechew) <stechew@cisco.com>
Mon, 14 Jun 2021 21:38:26 +0000 (21:38 +0000)
committerSteve Chew (stechew) <stechew@cisco.com>
Mon, 14 Jun 2021 21:38:26 +0000 (21:38 +0000)
Squashed commit of the following:

commit f0c32fd35d5763b7e32f1c04b03f5fa457d3552f
Author: Raman Krishnan <ramanks@cisco.com>
Date:   Fri Jun 11 19:52:06 2021 -0700

    codecs: geneve: incorporate review comments

commit abf8a20f05b7a2be16af0472b0d98b4cddded7be
Author: Raman Krishnan <ramanks@cisco.com>
Date:   Sat Jun 5 23:09:27 2021 -0700

    codecs: geneve: add vni to alert_csv and alert_json

commit fb516639ed8f29972df650b782fb5c721c946e60
Author: Raman Krishnan <ramanks@cisco.com>
Date:   Tue Apr 13 15:13:59 2021 -0700

    codecs: geneve: Support for Geneve encapsulation

17 files changed:
src/codecs/codec_api.cc
src/codecs/codec_module.h
src/codecs/ip/cd_udp.cc
src/codecs/misc/CMakeLists.txt
src/codecs/misc/cd_geneve.cc [new file with mode: 0644]
src/framework/decode_data.h
src/loggers/alert_csv.cc
src/loggers/alert_json.cc
src/main/snort_config.cc
src/main/snort_config.h
src/protocols/CMakeLists.txt
src/protocols/geneve.h [new file with mode: 0644]
src/protocols/layer.cc
src/protocols/layer.h
src/protocols/packet.cc
src/protocols/packet.h
src/protocols/protocol_ids.h

index 961723c5c493988a8ded81ed6d591495771fb755..2079d118b88ac54874a188af38e2e5eb40320fef 100644 (file)
@@ -46,6 +46,7 @@ extern const BaseApi* cd_esp[];
 extern const BaseApi* cd_eth[];
 extern const BaseApi* cd_fabricpath[];
 extern const BaseApi* cd_frag[];
+extern const BaseApi* cd_geneve[];
 extern const BaseApi* cd_gre[];
 extern const BaseApi* cd_gtp[];
 extern const BaseApi* cd_icmp4[];
@@ -89,6 +90,7 @@ void load_codecs()
     PluginManager::load_plugins(cd_eth);
     PluginManager::load_plugins(cd_fabricpath);
     PluginManager::load_plugins(cd_frag);
+    PluginManager::load_plugins(cd_geneve);
     PluginManager::load_plugins(cd_gre);
     PluginManager::load_plugins(cd_gtp);
     PluginManager::load_plugins(cd_icmp4);
index b0987756fc51bb6f38eb1d94a8efb3bfffc46df0..e09069996ec91ce8f83bcb25d847564db98348a3 100644 (file)
@@ -105,6 +105,12 @@ enum CodecSid : uint32_t
     DECODE_MPLS_RESERVED_LABEL = 175,
     DECODE_MPLS_LABEL_STACK = 176,
 
+    DECODE_GENEVE_DGRAM_LT_GENEVE_HDR = 180,
+    DECODE_GENEVE_INVALID_VERSION,
+    DECODE_GENEVE_INVALID_HEADER,
+    DECODE_GENEVE_INVALID_FLAGS,
+    DECODE_GENEVE_INVALID_OPTIONS,
+
     DECODE_ICMP_ORIG_IP_TRUNCATED = 250,
     DECODE_ICMP_ORIG_IP_VER_MISMATCH = 251,
     DECODE_ICMP_ORIG_DGRAM_LT_ORIG_IP = 252,
index f61133ab1e4c5202c10034c5a4bd52792474e2bb..b6668f1eae7a95183bbd67cfa6a5fb632214f31f 100644 (file)
@@ -70,6 +70,9 @@ static const Parameter udp_params[] =
     { "vxlan_ports", Parameter::PT_BIT_LIST, "65535",
       "4789", "set VXLAN ports" },
 
+    { "geneve_ports", Parameter::PT_BIT_LIST, "65535",
+      "6081", "set Geneve ports" },
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -88,6 +91,7 @@ static const RuleMap udp_rules[] =
 constexpr uint16_t GTP_U_PORT = 2152;
 constexpr uint16_t GTP_U_PORT_V0 = 3386;
 constexpr uint16_t VXLAN_U_PORT = 4789;
+constexpr uint16_t GENEVE_U_PORT = 6081;
 
 class UdpCodecConfig
 {
@@ -97,6 +101,7 @@ public:
         gtp_ports.set(GTP_U_PORT);
         gtp_ports.set(GTP_U_PORT_V0);
         vxlan_ports.set(VXLAN_U_PORT);
+        geneve_ports.set(GENEVE_U_PORT);
     }
 
     bool deep_teredo_inspection()
@@ -114,9 +119,15 @@ public:
     bool vxlan_decoding()
     { return vxlan_decode; }
 
+    bool geneve_decoding()
+    { return geneve_decode; }
+
     bool is_vxlan_port(uint16_t port)
     { return vxlan_ports.test(port); }
 
+    bool is_geneve_port(uint16_t port)
+    { return geneve_ports.test(port); }
+
     void set_gtp_ports(const PortBitSet& ports)
     {
         gtp_ports = ports;
@@ -129,12 +140,20 @@ public:
         vxlan_decode = ports.any();
     }
 
+    void set_geneve_ports(const PortBitSet& ports)
+    {
+        geneve_ports = ports;
+        geneve_decode = ports.any();
+    }
+
 private:
     bool enable_teredo = false;
     PortBitSet gtp_ports;
     PortBitSet vxlan_ports;
+    PortBitSet geneve_ports;
     bool gtp_decode = true;
     bool vxlan_decode = true;
+    bool geneve_decode = true;
 };
 
 class UdpModule : public BaseCodecModule
@@ -195,6 +214,11 @@ bool UdpModule::set(const char*, Value& v, SnortConfig*)
         v.get_bits(ports);
         config->set_vxlan_ports(ports);
     }
+    else if ( v.is("geneve_ports") )
+    {
+        v.get_bits(ports);
+        config->set_geneve_ports(ports);
+    }
     else
         return false;
 
@@ -431,6 +455,11 @@ bool UdpCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
     {
         codec.next_prot_id = ProtocolId::VXLAN;
     }
+    else if (config->geneve_decoding() and
+        (config->is_geneve_port(src_port) || config->is_geneve_port(dst_port)))
+    {
+        codec.next_prot_id = ProtocolId::GENEVE;
+    }
 
     if (codec.next_prot_id != ProtocolId::FINISHED_DECODE)
         codec.proto_bits |= PROTO_BIT__UDP_TUNNELED;
index d55d60ae0720cd09037fa73e91894623e1ecb4a4..d8ccd8a8f2d97d5ab1031e85c56a61ccf0824b29 100644 (file)
@@ -8,6 +8,7 @@ if(STATIC_CODECS)
         cd_teredo.cc
         cd_user.cc
         cd_vxlan.cc
+        cd_geneve.cc
     )
 
 else(STATIC_CODECS)
@@ -18,6 +19,7 @@ else(STATIC_CODECS)
     add_dynamic_module(cd_teredo codecs cd_teredo.cc)
     add_dynamic_module(cd_user codecs cd_user.cc)
     add_dynamic_module(cd_vxlan codecs cd_vxlan.cc)
+    add_dynamic_module(cd_geneve codecs cd_geneve.cc)
 
 endif(STATIC_CODECS)
 
diff --git a/src/codecs/misc/cd_geneve.cc b/src/codecs/misc/cd_geneve.cc
new file mode 100644 (file)
index 0000000..00db4e6
--- /dev/null
@@ -0,0 +1,305 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// cd_geneve.cc author Raman S. Krishnan <ramanks@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "codecs/codec_module.h"
+#include "framework/codec.h"
+#include "log/text_log.h"
+#include "main/snort_config.h"
+#include "packet_io/active.h"
+#include "protocols/geneve.h"
+
+using namespace snort;
+
+#define CD_GENEVE_NAME "geneve"
+#define CD_GENEVE_HELP "support for Geneve: Generic Network Virtualization Encapsulation"
+
+#define RFC_8926_GENEVE_VERSION     0
+#define GENEVE_ETH_TYPE             0x6558
+
+#define GENEVE_FLAG_O               0x80
+#define GENEVE_FLAG_C               0x40
+
+#define GENEVE_OPT_TYPE_C           0x80
+
+namespace
+{
+struct GeneveOpt
+{
+    uint16_t g_class;
+    uint8_t  g_type;
+    uint8_t  g_len;
+
+    uint16_t optclass() const
+    { return (ntohs(g_class)); }
+
+    bool is_set(uint16_t which) const
+    { return (g_type & which); }
+
+    uint8_t type() const
+    { return (g_type); }
+
+    uint8_t olen() const
+    { return (sizeof(GeneveOpt) + (g_len * 4)); }
+
+    uint8_t len() const
+    { return (g_len * 4); }
+};
+
+static const RuleMap geneve_rules[] =
+{
+    { DECODE_GENEVE_DGRAM_LT_GENEVE_HDR, "insufficient room for geneve header" },
+    { DECODE_GENEVE_INVALID_VERSION, "invalid version" },
+    { DECODE_GENEVE_INVALID_HEADER, "invalid header" },
+    { DECODE_GENEVE_INVALID_FLAGS, "invalid flags" },
+    { DECODE_GENEVE_INVALID_OPTIONS, "invalid options" },
+    { 0, nullptr }
+};
+
+class GeneveModule : public BaseCodecModule
+{
+public:
+    GeneveModule() : BaseCodecModule(CD_GENEVE_NAME, CD_GENEVE_HELP) { }
+
+    const RuleMap* get_rules() const override
+    { return geneve_rules; }
+};
+
+class GeneveCodec : public Codec
+{
+public:
+    GeneveCodec() : Codec(CD_GENEVE_NAME) { }
+
+    void get_protocol_ids(std::vector<ProtocolId>& v) override;
+    bool decode(const RawData&, CodecData&, DecodeData&) override;
+    void log(TextLog* const, const uint8_t* pkt, const uint16_t len) override;
+    bool encode(const uint8_t* const raw_in, const uint16_t raw_len,
+        EncState&, Buffer&, Flow*) override;
+
+private:
+
+    void log_opts(TextLog* const, const uint8_t*, const uint16_t len);
+    bool validate_options(const uint8_t* rptr, uint16_t optlen, CodecData& codec);
+};
+
+} // namespace
+
+void GeneveCodec::get_protocol_ids(std::vector<ProtocolId>& v)
+{
+    v.push_back(ProtocolId::GENEVE);
+}
+
+bool GeneveCodec::validate_options(const uint8_t* rptr, uint16_t hdrlen, CodecData& codec)
+{
+    const geneve::GeneveHdr* const hdr = reinterpret_cast<const geneve::GeneveHdr*>(rptr);
+    uint16_t offset = sizeof(geneve::GeneveHdr);
+    uint16_t copts = 0;
+
+    /* Skip past tunnel header */
+    rptr += sizeof(geneve::GeneveHdr);
+
+    while (offset < hdrlen)
+    {
+        const GeneveOpt* const opt = reinterpret_cast<const GeneveOpt*>(rptr);
+        uint8_t olen = opt->olen();
+
+        if ((offset + olen) > hdrlen)
+        {
+            codec_event(codec, DECODE_GENEVE_INVALID_OPTIONS);
+            return false;
+        }
+
+        if (opt->is_set(GENEVE_OPT_TYPE_C))
+            copts++;
+
+        rptr += olen;
+        offset += olen;
+    }
+
+    /*
+     * Generate event if
+     *   C flag is clear but critical options are present
+     *   C flag is set   but critical options are absent
+     */
+    if ((!copts && hdr->is_set(GENEVE_FLAG_C)) || (copts && !hdr->is_set(GENEVE_FLAG_C)))
+    {
+        codec_event(codec, DECODE_GENEVE_INVALID_FLAGS);
+        return false;
+    }
+
+    return true;
+}
+
+bool GeneveCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
+{
+    if ( raw.len < sizeof(geneve::GeneveHdr) )
+    {
+        codec_event(codec, DECODE_GENEVE_DGRAM_LT_GENEVE_HDR);
+        return false;
+    }
+
+    const geneve::GeneveHdr* const hdr = reinterpret_cast<const geneve::GeneveHdr*>(raw.data);
+
+    if (hdr->version() != RFC_8926_GENEVE_VERSION)
+    {
+        codec_event(codec, DECODE_GENEVE_INVALID_VERSION);
+        return false;
+    }
+
+    const uint16_t optlen = hdr->optlen();
+    const uint32_t hdrlen = hdr->hlen();
+    if (raw.len <  hdrlen)
+    {
+        codec_event(codec, DECODE_GENEVE_INVALID_HEADER);
+        return false;
+    }
+
+    /* If critical header present bit is set, optlen cannot be 0 */
+    if (hdr->is_set(GENEVE_FLAG_C) && (optlen == 0))
+    {
+        codec_event(codec, DECODE_GENEVE_INVALID_FLAGS);
+        return false;
+    }
+
+    if (!validate_options(raw.data, hdrlen, codec))
+    {
+        return false;
+    }
+
+    if ( codec.conf->tunnel_bypass_enabled(TUNNEL_GENEVE) )
+        codec.tunnel_bypass = true;
+
+    uint16_t next = hdr->proto();
+    ProtocolId proto = (next == GENEVE_ETH_TYPE) ? ProtocolId::ETHERNET_802_3 : (ProtocolId) next;
+
+    codec.lyr_len = hdrlen;
+    codec.proto_bits |= PROTO_BIT__GENEVE;
+    codec.next_prot_id = proto;
+    codec.codec_flags |= CODEC_NON_IP_TUNNEL;
+
+    return true;
+}
+
+void GeneveCodec::log_opts(TextLog* const text_log, const uint8_t *rptr, uint16_t optlen)
+{
+    uint16_t offset = 0;
+
+    while (offset < optlen)
+    {
+        const GeneveOpt* const opt = reinterpret_cast<const GeneveOpt*>(rptr);
+        uint8_t olen = opt->olen();
+
+        TextLog_Print(text_log, "\n\tclass 0x%04x, type 0x%02x%s, len %3u%s", opt->optclass(),
+            opt->type(), (opt->is_set(GENEVE_OPT_TYPE_C) ? " (C)" : ""), olen, (olen ? " value " : ""));
+
+        rptr += sizeof(GeneveOpt);
+
+        for (int idx=0; idx < opt->len(); idx++)
+            TextLog_Print(text_log, "%02x ", *rptr++);
+
+        offset += olen;
+    }
+}
+
+void GeneveCodec::log(TextLog* const text_log, const uint8_t* raw_pkt,
+    const uint16_t /*lyr_len*/)
+{
+    const uint8_t* rptr = raw_pkt;
+    const geneve::GeneveHdr* const hdr = reinterpret_cast<const geneve::GeneveHdr*>(rptr);
+    rptr += sizeof(geneve::GeneveHdr);
+
+    std::string flags = "";
+
+    if (hdr->is_set(GENEVE_FLAG_O))
+        flags += "O";
+
+    if (hdr->is_set(GENEVE_FLAG_C))
+        flags += "C";
+
+    if (flags == "")
+        flags = "none";
+
+    TextLog_Print(text_log, "version %u, optlen %u flags [%s]", hdr->version(), hdr->optlen(), flags.c_str());
+    TextLog_Print(text_log, " network id %u, next protocol: 0x%04x", hdr->vni(), hdr->proto());
+
+    log_opts(text_log, rptr, hdr->optlen());
+}
+
+bool GeneveCodec::encode(const uint8_t* const raw_in, const uint16_t raw_len,
+    EncState&, Buffer& buf, Flow*)
+{
+    if (!buf.allocate(raw_len))
+        return false;
+
+    geneve::GeneveHdr* const hdr = reinterpret_cast<geneve::GeneveHdr*>(buf.data());
+    memcpy(hdr, raw_in, raw_len);
+    return true;
+}
+
+//-------------------------------------------------------------------------
+// api
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new GeneveModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Codec* ctor(Module*)
+{ return new GeneveCodec(); }
+
+static void dtor(Codec* cd)
+{ delete cd; }
+
+static const CodecApi geneve_api =
+{
+    {
+        PT_CODEC,
+        sizeof(CodecApi),
+        CDAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        CD_GENEVE_NAME,
+        CD_GENEVE_HELP,
+        mod_ctor,
+        mod_dtor
+    },
+    nullptr, // pinit
+    nullptr, // pterm
+    nullptr, // tinit
+    nullptr, // tterm
+    ctor, // ctor
+    dtor, // dtor
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* cd_geneve[] =
+#endif
+{
+    &geneve_api.base,
+    nullptr
+};
+
index 0051a7cf34286d7e0f5c34dc1feed033851afca1..98ba2484691551c93375ed91549d009b8c8ef926 100644 (file)
@@ -71,7 +71,8 @@ enum class PktType : std::uint8_t
 #define PROTO_BIT__VXLAN            0x040000
 #define PROTO_BIT__UDP_TUNNELED     0x080000
 #define PROTO_BIT__OTHER            0x100000
-#define PROTO_BIT__ALL              0x1FFFFF
+#define PROTO_BIT__GENEVE           0x200000
+#define PROTO_BIT__ALL              0x3FFFFF
 
 #define PROTO_BIT__ICMP_EMBED \
     (PROTO_BIT__TCP_EMBED_ICMP | PROTO_BIT__UDP_EMBED_ICMP | \
index 92dec83374afba3b9affb0d9698e13880233dd70..6ac046a7b35a57bae37d24e6fdc9e8b3af021811 100644 (file)
@@ -47,6 +47,7 @@
 #include "protocols/tcp.h"
 #include "protocols/udp.h"
 #include "protocols/vlan.h"
+#include "protocols/geneve.h"
 #include "utils/stats.h"
 
 using namespace snort;
@@ -210,6 +211,12 @@ static void ff_flowstart_time(const Args& a)
         TextLog_Print(csv_log, "%ld", a.pkt->flow->flowstats.start_time.tv_sec);
 }
 
+static void ff_geneve_vni(const Args& a)
+{
+    if (a.pkt->proto_bits & PROTO_BIT__GENEVE)
+        TextLog_Print(csv_log, "%u", a.pkt->get_flow_geneve_vni());
+}
+
 static void ff_gid(const Args& a)
 {
     TextLog_Print(csv_log, "%u",  a.event.sig_info->gid);
@@ -472,7 +479,7 @@ static const CsvFunc csv_func[] =
 {
     ff_action, ff_class, ff_b64_data, ff_client_bytes, ff_client_pkts, ff_dir,
     ff_dst_addr, ff_dst_ap, ff_dst_port, ff_eth_dst, ff_eth_len, ff_eth_src,
-    ff_eth_type, ff_flowstart_time, ff_gid, ff_icmp_code, ff_icmp_id, ff_icmp_seq,
+    ff_eth_type, ff_flowstart_time, ff_geneve_vni, ff_gid, ff_icmp_code, ff_icmp_id, ff_icmp_seq,
     ff_icmp_type, ff_iface, ff_ip_id, ff_ip_len, ff_msg, ff_mpls, ff_pkt_gen, ff_pkt_len,
     ff_pkt_num, ff_priority, ff_proto, ff_rev, ff_rule, ff_seconds, ff_server_bytes,
     ff_server_pkts, ff_service, ff_sgt, ff_sid, ff_src_addr, ff_src_ap, ff_src_port,
@@ -483,7 +490,7 @@ static const CsvFunc csv_func[] =
 #define csv_range \
     "action | class | b64_data | client_bytes | client_pkts | dir | " \
     "dst_addr | dst_ap | dst_port | eth_dst | eth_len | eth_src | " \
-    "eth_type | flowstart_time | gid | icmp_code | icmp_id | icmp_seq | " \
+    "eth_type | flowstart_time | geneve_vni | gid | icmp_code | icmp_id | icmp_seq | " \
     "icmp_type | iface | ip_id | ip_len | msg | mpls | pkt_gen | pkt_len | " \
     "pkt_num | priority | proto | rev | rule | seconds | server_bytes | " \
     "server_pkts | service | sgt| sid | src_addr | src_ap | src_port | " \
index 6614b7ad84e2925da0a7d5ef59a8b0ed93f40d56..283a2e581e9a204b167471f76f786c6936c1da3b 100644 (file)
@@ -268,6 +268,16 @@ static bool ff_flowstart_time(const Args& a)
     return false;
 }
 
+static bool ff_geneve_vni(const Args& a)
+{
+    if (a.pkt->proto_bits & PROTO_BIT__GENEVE)
+    {
+        print_label(a, "geneve_vni");
+        TextLog_Print(json_log, "%u", a.pkt->get_flow_geneve_vni());
+    }
+    return true;
+}
+
 static bool ff_gid(const Args& a)
 {
     print_label(a, "gid");
@@ -664,7 +674,7 @@ static const JsonFunc json_func[] =
 {
     ff_action, ff_class, ff_b64_data, ff_client_bytes, ff_client_pkts, ff_dir,
     ff_dst_addr, ff_dst_ap, ff_dst_port, ff_eth_dst, ff_eth_len, ff_eth_src,
-    ff_eth_type, ff_flowstart_time, ff_gid, ff_icmp_code, ff_icmp_id, ff_icmp_seq,
+    ff_eth_type, ff_flowstart_time, ff_geneve_vni, ff_gid, ff_icmp_code, ff_icmp_id, ff_icmp_seq,
     ff_icmp_type, ff_iface, ff_ip_id, ff_ip_len, ff_msg, ff_mpls, ff_pkt_gen, ff_pkt_len,
     ff_pkt_num, ff_priority, ff_proto, ff_rev, ff_rule, ff_seconds, ff_server_bytes,
     ff_server_pkts, ff_service, ff_sgt, ff_sid, ff_src_addr, ff_src_ap, ff_src_port,
@@ -675,7 +685,7 @@ static const JsonFunc json_func[] =
 #define json_range \
     "action | class | b64_data | client_bytes | client_pkts | dir | " \
     "dst_addr | dst_ap | dst_port | eth_dst | eth_len | eth_src | " \
-    "eth_type | flowstart_time | gid | icmp_code | icmp_id | icmp_seq | " \
+    "eth_type | flowstart_time | geneve_vni | gid | icmp_code | icmp_id | icmp_seq | " \
     "icmp_type | iface | ip_id | ip_len | msg | mpls | pkt_gen | pkt_len | " \
     "pkt_num | priority | proto | rev | rule | seconds | server_bytes | " \
     "server_pkts | service | sgt| sid | src_addr | src_ap | src_port | " \
index 2f6298a9395e5028a6f9f0d655ae539b47b912fd..d30fa382d322c07664fdbd7f66a7672355154b85 100644 (file)
@@ -798,6 +798,9 @@ void SnortConfig::set_tunnel_verdicts(const char* args)
         else if (!strcasecmp(tok, "mpls"))
             tunnel_mask |= TUNNEL_MPLS;
 
+        else if (!strcasecmp(tok, "geneve"))
+            tunnel_mask |= TUNNEL_GENEVE;
+
         else
         {
             ParseError("unknown tunnel bypass protocol");
index 7f471735241a77d5d33993f174a9a3e55527b85a..683f7fcc7f57219e6c0c2f11bb075812b8bb5f99 100644 (file)
@@ -119,7 +119,8 @@ enum TunnelFlags
     TUNNEL_6IN6   = 0x20,
     TUNNEL_GRE    = 0x40,
     TUNNEL_MPLS   = 0x80,
-    TUNNEL_VXLAN  = 0x100
+    TUNNEL_VXLAN  = 0x100,
+    TUNNEL_GENEVE = 0x200
 };
 
 enum DumpConfigType
index 0fdf263af7e01b397f75d456802c2a7043faa3f7..09c4bd97abff7dd1d82f1e9701cc02df2462ba12 100644 (file)
@@ -12,6 +12,7 @@ set (PROTOCOL_HEADERS
     ipv4.h
     ipv4_options.h
     ipv6.h
+    geneve.h
     gre.h
     layer.h
     linux_sll.h
diff --git a/src/protocols/geneve.h b/src/protocols/geneve.h
new file mode 100644 (file)
index 0000000..6118473
--- /dev/null
@@ -0,0 +1,57 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// geneve.h author Raman S. Krishnan <ramanks@cisco.com>
+
+#ifndef PROTOCOLS_GENEVE_H
+#define PROTOCOLS_GENEVE_H
+
+namespace snort
+{
+namespace geneve
+{
+struct GeneveHdr
+{
+    uint8_t g_vl;
+    uint8_t g_flags;
+    uint16_t g_proto;
+    uint8_t g_vni[ 3 ];
+    uint8_t g_rsvd;
+
+    uint16_t hlen() const
+    { return (sizeof(GeneveHdr) + ((g_vl & 0x3f) * 4)); }
+
+    uint8_t version() const
+    { return (g_vl >> 6); }
+
+    uint8_t optlen() const
+    { return ((g_vl & 0x3f) * 4); }
+
+    bool is_set(uint16_t which) const
+    { return (g_flags & which); }
+
+    uint16_t proto() const
+    { return (ntohs(g_proto)); }
+
+    uint32_t vni() const
+    { return ((g_vni[0] << 16) | (g_vni[1] << 8) | g_vni[2]); }
+};
+
+} // namespace geneve
+} // namespace snort
+
+#endif
index 9d4235d6b3951bd6ecee26e85b4d933a19c1e82c..6a5c303b3fd6bcff8d1ba489f47bfbbfb9584d73 100644 (file)
@@ -115,6 +115,15 @@ const arp::EtherARP* get_arp_layer(const Packet* const p)
             ProtocolId::ETHERTYPE_REVARP));
 }
 
+const geneve::GeneveHdr* get_geneve_layer(const Packet* const p)
+{
+    uint8_t num_layers = p->num_layers;
+    const Layer* lyr = p->layers;
+
+    return reinterpret_cast<const geneve::GeneveHdr*>(
+        find_inner_layer(lyr, num_layers, ProtocolId::GENEVE));
+}
+
 const gre::GREHdr* get_gre_layer(const Packet* const p)
 {
     uint8_t num_layers = p->num_layers;
index 3d31ca84aecb62c3304bfee96d9a52b4655bb243..e944e99923d6a9dbb51883fd1c8c663841716aca 100644 (file)
@@ -55,6 +55,11 @@ namespace eth
 struct EtherHdr;
 }
 
+namespace geneve
+{
+struct GeneveHdr;
+}
+
 namespace gre
 {
 struct GREHdr;
@@ -107,6 +112,7 @@ SO_PUBLIC const arp::EtherARP* get_arp_layer(const Packet*);
 SO_PUBLIC const cisco_meta_data::CiscoMetaDataHdr* get_cisco_meta_data_layer(const Packet* const);
 SO_PUBLIC const eapol::EtherEapol* get_eapol_layer(const Packet*);
 SO_PUBLIC const eth::EtherHdr* get_eth_layer(const Packet*);
+SO_PUBLIC const geneve::GeneveHdr* get_geneve_layer(const Packet*);
 SO_PUBLIC const gre::GREHdr* get_gre_layer(const Packet*);
 SO_PUBLIC const vlan::VlanTagHdr* get_vlan_layer(const Packet*);
 SO_PUBLIC const wlan::WifiHdr* get_wifi_layer(const Packet*);
index 4227781a9e9cbd57351d34e1a343d2f066696be9..21885a4e31a9a4182e6b52ae3ab12eea8152f755 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "packet_manager.h"
 #include "vlan.h"
+#include "geneve.h"
 
 namespace snort
 {
@@ -264,6 +265,16 @@ uint16_t Packet::get_flow_vlan_id() const
     return vid;
 }
 
+uint32_t Packet::get_flow_geneve_vni() const
+{
+    uint32_t vni = 0;
+
+    if (proto_bits & PROTO_BIT__GENEVE)
+        vni = layer::get_geneve_layer(this)->vni();
+
+    return vni;
+}
+
 bool Packet::is_from_application_client() const
 {
     if (flow)
index 8a4ce05631bfef60da72d9ec9d0be42fbe27d5ab..af1dcaf752098fbdb34d39e39eae41d6eb30bf0e 100644 (file)
@@ -339,6 +339,7 @@ struct SO_PUBLIC Packet
     }
 
     uint16_t get_flow_vlan_id() const;
+    uint32_t get_flow_geneve_vni() const;
 
     int16_t get_ingress_group() const
     {
index f7113055f4ba16407124a5ad58b855da415b9f4a..8ba5b66b5209c7640ca25674455fc8f04ad82c10 100644 (file)
@@ -133,6 +133,7 @@ enum class ProtocolId : std::uint16_t
     ETHERNET_802_11 = 0x0106,
     ETHERNET_LLC = 0x0107,
     VXLAN = 0x0108,
+    GENEVE = 0x0109,
 
     /*
      * Below is a partial list of ethertypes.