From: Steve Chew (stechew) Date: Mon, 14 Jun 2021 21:38:26 +0000 (+0000) Subject: Merge pull request #2911 in SNORT/snort3 from ~RAMANKS/snort3:geneve to master X-Git-Tag: 3.1.6.0~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b07dcc18f1eefd962e54345d76c39460e3b07bc0;p=thirdparty%2Fsnort3.git Merge pull request #2911 in SNORT/snort3 from ~RAMANKS/snort3:geneve to master Squashed commit of the following: commit f0c32fd35d5763b7e32f1c04b03f5fa457d3552f Author: Raman Krishnan Date: Fri Jun 11 19:52:06 2021 -0700 codecs: geneve: incorporate review comments commit abf8a20f05b7a2be16af0472b0d98b4cddded7be Author: Raman Krishnan Date: Sat Jun 5 23:09:27 2021 -0700 codecs: geneve: add vni to alert_csv and alert_json commit fb516639ed8f29972df650b782fb5c721c946e60 Author: Raman Krishnan Date: Tue Apr 13 15:13:59 2021 -0700 codecs: geneve: Support for Geneve encapsulation --- diff --git a/src/codecs/codec_api.cc b/src/codecs/codec_api.cc index 961723c5c..2079d118b 100644 --- a/src/codecs/codec_api.cc +++ b/src/codecs/codec_api.cc @@ -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); diff --git a/src/codecs/codec_module.h b/src/codecs/codec_module.h index b0987756f..e09069996 100644 --- a/src/codecs/codec_module.h +++ b/src/codecs/codec_module.h @@ -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, diff --git a/src/codecs/ip/cd_udp.cc b/src/codecs/ip/cd_udp.cc index f61133ab1..b6668f1ea 100644 --- a/src/codecs/ip/cd_udp.cc +++ b/src/codecs/ip/cd_udp.cc @@ -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; diff --git a/src/codecs/misc/CMakeLists.txt b/src/codecs/misc/CMakeLists.txt index d55d60ae0..d8ccd8a8f 100644 --- a/src/codecs/misc/CMakeLists.txt +++ b/src/codecs/misc/CMakeLists.txt @@ -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 index 000000000..00db4e67d --- /dev/null +++ b/src/codecs/misc/cd_geneve.cc @@ -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 + +#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& 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& 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(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(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(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(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(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(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 +}; + diff --git a/src/framework/decode_data.h b/src/framework/decode_data.h index 0051a7cf3..98ba24846 100644 --- a/src/framework/decode_data.h +++ b/src/framework/decode_data.h @@ -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 | \ diff --git a/src/loggers/alert_csv.cc b/src/loggers/alert_csv.cc index 92dec8337..6ac046a7b 100644 --- a/src/loggers/alert_csv.cc +++ b/src/loggers/alert_csv.cc @@ -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 | " \ diff --git a/src/loggers/alert_json.cc b/src/loggers/alert_json.cc index 6614b7ad8..283a2e581 100644 --- a/src/loggers/alert_json.cc +++ b/src/loggers/alert_json.cc @@ -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 | " \ diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 2f6298a93..d30fa382d 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -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"); diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 7f4717352..683f7fcc7 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -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 diff --git a/src/protocols/CMakeLists.txt b/src/protocols/CMakeLists.txt index 0fdf263af..09c4bd97a 100644 --- a/src/protocols/CMakeLists.txt +++ b/src/protocols/CMakeLists.txt @@ -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 index 000000000..6118473ed --- /dev/null +++ b/src/protocols/geneve.h @@ -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 + +#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 diff --git a/src/protocols/layer.cc b/src/protocols/layer.cc index 9d4235d6b..6a5c303b3 100644 --- a/src/protocols/layer.cc +++ b/src/protocols/layer.cc @@ -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( + 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; diff --git a/src/protocols/layer.h b/src/protocols/layer.h index 3d31ca84a..e944e9992 100644 --- a/src/protocols/layer.h +++ b/src/protocols/layer.h @@ -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*); diff --git a/src/protocols/packet.cc b/src/protocols/packet.cc index 4227781a9..21885a4e3 100644 --- a/src/protocols/packet.cc +++ b/src/protocols/packet.cc @@ -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) diff --git a/src/protocols/packet.h b/src/protocols/packet.h index 8a4ce0563..af1dcaf75 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -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 { diff --git a/src/protocols/protocol_ids.h b/src/protocols/protocol_ids.h index f7113055f..8ba5b66b5 100644 --- a/src/protocols/protocol_ids.h +++ b/src/protocols/protocol_ids.h @@ -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.