extern const BaseApi* cd_udp[];
extern const BaseApi* cd_user[];
extern const BaseApi* cd_vlan[];
+extern const BaseApi* cd_vxlan[];
#endif
void load_codecs()
PluginManager::load_plugins(cd_udp);
PluginManager::load_plugins(cd_user);
PluginManager::load_plugins(cd_vlan);
+ PluginManager::load_plugins(cd_vxlan);
#endif
}
#include "codecs/codec_module.h"
#include "framework/codec.h"
+#include "log/messages.h"
#include "log/text_log.h"
#include "main/snort_config.h"
#include "protocols/teredo.h"
{ "deep_teredo_inspection", Parameter::PT_BOOL, nullptr, "false",
"look for Teredo on all UDP ports (default is only 3544)" },
- { "enable_gtp", Parameter::PT_BOOL, nullptr, "false",
- "decode GTP encapsulations" },
-
{ "gtp_ports", Parameter::PT_BIT_LIST, "65535",
"2152 3386", "set GTP ports" },
+ { "vxlan_ports", Parameter::PT_BIT_LIST, "65535",
+ "4789", "set VXLAN ports" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
constexpr uint16_t GTP_U_PORT = 2152;
constexpr uint16_t GTP_U_PORT_V0 = 3386;
+constexpr uint16_t VXLAN_U_PORT = 4789;
+
+class UdpCodecConfig
+{
+public:
+ UdpCodecConfig()
+ {
+ gtp_ports.set(GTP_U_PORT);
+ gtp_ports.set(GTP_U_PORT_V0);
+ vxlan_ports.set(VXLAN_U_PORT);
+ }
+
+ bool deep_teredo_inspection()
+ { return enable_teredo; }
+
+ void set_teredo_inspection(bool val)
+ { enable_teredo = val; }
+
+ bool gtp_decoding()
+ { return gtp_decode; }
+
+ bool is_gtp_port(uint16_t port)
+ { return gtp_ports.test(port); }
+
+ bool vxlan_decoding()
+ { return vxlan_decode; }
+
+ bool is_vxlan_port(uint16_t port)
+ { return vxlan_ports.test(port); }
+
+ void set_gtp_ports(PortBitSet ports)
+ {
+ gtp_ports = ports;
+ gtp_decode = ports.any();
+ }
+
+ void set_vxlan_ports(PortBitSet ports)
+ {
+ vxlan_ports = ports;
+ vxlan_decode = ports.any();
+ }
+
+private:
+ bool enable_teredo = false;
+ PortBitSet gtp_ports;
+ PortBitSet vxlan_ports;
+ bool gtp_decode = true;
+ bool vxlan_decode = true;
+};
class UdpModule : public CodecModule
{
public:
- UdpModule() : CodecModule(CD_UDP_NAME, CD_UDP_HELP, udp_params) { }
+ UdpModule() : CodecModule(CD_UDP_NAME, CD_UDP_HELP, udp_params)
+ {
+ config = nullptr;
+ }
+
+ ~UdpModule() override
+ {
+ if ( config )
+ {
+ delete config;
+ config = nullptr;
+ }
+ }
+
+ bool set(const char*, Value&, SnortConfig*) override;
+ bool begin(const char*, int, SnortConfig*) override;
const RuleMap* get_rules() const override
{ return udp_rules; }
PegCount* get_counts() const override
{ return (PegCount*)&stats; }
- bool set(const char*, Value& v, SnortConfig* sc) override
+ UdpCodecConfig* get_data()
{
- if ( v.is("deep_teredo_inspection") )
- {
- sc->enable_teredo = v.get_bool();
- }
- else if ( v.is("gtp_ports") )
- {
- if ( !sc->gtp_ports )
- sc->gtp_ports = new PortBitSet;
+ UdpCodecConfig* tmp = config;
+ config = nullptr;
+ return tmp;
+ }
+private:
+ UdpCodecConfig* config;
+};
- v.get_bits(*(sc->gtp_ports));
- }
- else if ( v.is("enable_gtp") )
- {
- if ( v.get_bool() )
- {
- if ( !sc->gtp_ports )
- {
- sc->gtp_ports = new PortBitSet;
- sc->gtp_ports->set(GTP_U_PORT);
- sc->gtp_ports->set(GTP_U_PORT_V0);
- }
- }
- }
- else
- {
- return false;
- }
+bool UdpModule::set(const char*, Value& v, SnortConfig*)
+{
+ PortBitSet ports;
- return true;
+ if ( v.is("deep_teredo_inspection") )
+ {
+ config->set_teredo_inspection(v.get_bool());
}
-};
+ else if ( v.is("gtp_ports") )
+ {
+ v.get_bits(ports);
+ config->set_gtp_ports(ports);
+ }
+ else if ( v.is("vxlan_ports") )
+ {
+ v.get_bits(ports);
+ config->set_vxlan_ports(ports);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+bool UdpModule::begin(const char*, int, SnortConfig*)
+{
+ assert(!config);
+ config = new UdpCodecConfig;
+ return true;
+}
+
class UdpCodec : public Codec
{
public:
- UdpCodec() : Codec(CD_UDP_NAME) { }
+ UdpCodec(UdpCodecConfig* c) : Codec(CD_UDP_NAME) { config = c; }
+ ~UdpCodec() override { delete config; }
void get_protocol_ids(std::vector<ProtocolId>& v) override;
bool decode(const RawData&, CodecData&, DecodeData&) override;
bool valid_checksum6(const RawData&, const CodecData&, const DecodeData&);
void UDPMiscTests(const DecodeData&, const CodecData&, uint32_t pay_len);
+ UdpCodecConfig* config;
};
} // anonymous namespace
// set in packet manager
UDPMiscTests(snort, codec, uhlen - udp::UDP_HEADER_LEN);
- if (SnortConfig::gtp_decoding() &&
- (SnortConfig::is_gtp_port(src_port) || SnortConfig::is_gtp_port(dst_port)))
+ if (config->gtp_decoding() and
+ (config->is_gtp_port(src_port) || config->is_gtp_port(dst_port)))
{
if ( !(snort.decode_flags & DECODE_FRAG) )
codec.next_prot_id = ProtocolId::GTP;
}
else if (teredo::is_teredo_port(src_port) ||
teredo::is_teredo_port(dst_port) ||
- SnortConfig::deep_teredo_inspection())
+ (config->deep_teredo_inspection()))
{
codec.next_prot_id = ProtocolId::TEREDO;
}
+ else if (config->vxlan_decoding() and
+ (config->is_vxlan_port(src_port) || config->is_vxlan_port(dst_port)))
+ {
+ codec.next_prot_id = ProtocolId::VXLAN;
+ }
+
+ if (codec.next_prot_id != ProtocolId::FINISHED_DECODE)
+ codec.proto_bits |= PROTO_BIT__UDP_TUNNELED;
return true;
}
static void mod_dtor(Module* m)
{ delete m; }
-static Codec* ctor(Module*)
-{ return new UdpCodec(); }
+static Codec* ctor(Module* m)
+{
+ UdpModule* mod = (UdpModule*)m;
+ // Codecs can be instantiated without modules. In which case use
+ // the snort defaults for config.
+ UdpCodecConfig* cfg = mod ? (mod->get_data()) : (new UdpCodecConfig());
+ return new UdpCodec(cfg);
+}
static void dtor(Codec* cd)
{ delete cd; }
cd_llc.cc
cd_teredo.cc
cd_user.cc
+ cd_vxlan.cc
)
else(STATIC_CODECS)
add_dynamic_module(cd_llc codecs cd_llc.cc)
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)
endif(STATIC_CODECS)
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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_vxlan.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/codec.h"
+#include "log/text_log.h"
+#include "main/snort_config.h"
+#include "packet_io/active.h"
+
+using namespace snort;
+
+#define CD_VXLAN_NAME "vxlan"
+#define CD_VXLAN_HELP "support for Virtual Extensible LAN"
+
+namespace
+{
+class VxlanCodec : public Codec
+{
+public:
+ VxlanCodec() : Codec(CD_VXLAN_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;
+};
+
+struct VXLANHdr
+{
+ uint8_t flags;
+ uint8_t reserved_1[3];
+ uint8_t vni[3]; //VXLAN network id
+ uint8_t reserved_2;
+};
+constexpr uint16_t VXLAN_MIN_HDR_LEN = 8;
+} // anonymous namespace
+
+void VxlanCodec::get_protocol_ids(std::vector<ProtocolId>& v)
+{
+ v.push_back(ProtocolId::VXLAN);
+}
+
+bool VxlanCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
+{
+ if ( raw.len < VXLAN_MIN_HDR_LEN )
+ return false;
+
+ const VXLANHdr* const hdr = reinterpret_cast<const VXLANHdr*>(raw.data);
+
+ if ( hdr->flags != 0x08 )
+ return false;
+
+ if ( SnortConfig::tunnel_bypass_enabled(TUNNEL_VXLAN) )
+ codec.tunnel_bypass = true;
+
+ codec.lyr_len = VXLAN_MIN_HDR_LEN;
+ codec.proto_bits |= PROTO_BIT__VXLAN;
+ codec.next_prot_id = ProtocolId::ETHERNET_802_3;
+ codec.codec_flags |= CODEC_NON_IP_TUNNEL;
+
+ return true;
+}
+
+void VxlanCodec::log(TextLog* const text_log, const uint8_t* raw_pkt,
+ const uint16_t /*lyr_len*/)
+{
+ const VXLANHdr* const hdr = reinterpret_cast<const VXLANHdr*>(raw_pkt);
+ uint32_t vni = ( hdr->vni[0] << 16 ) | ( hdr->vni[1] << 8 ) | hdr->vni[2];
+ TextLog_Print(text_log, "network identifier: %u", vni);
+}
+
+//-------------------------------------------------------------------------
+// api
+//-------------------------------------------------------------------------
+
+static Codec* ctor(Module*)
+{ return new VxlanCodec(); }
+
+static void dtor(Codec* cd)
+{ delete cd; }
+
+static const CodecApi vxlan_api =
+{
+ {
+ PT_CODEC,
+ sizeof(CodecApi),
+ CDAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ CD_VXLAN_NAME,
+ CD_VXLAN_HELP,
+ nullptr,
+ nullptr
+ },
+ 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_vxlan[] =
+#endif
+{
+ &vxlan_api.base,
+ nullptr
+};
+
{
if ( !last_check.flowbit_failed &&
!(p->packet_flags & PKT_IP_RULE_2ND) &&
- !(p->proto_bits & (PROTO_BIT__TEREDO|PROTO_BIT__GTP)) )
+ !p->is_udp_tunneled() )
{
trace_log(detection, TRACE_RULE_EVAL,
"Was evaluated before, returning last check result\n");
// FIXIT-P Batch outer UDP payload searches for teredo set and the outer header
// during any signature evaluation
- if ( p->ptrs.udph && (p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
+ if ( p->is_udp_tunneled() )
{
fp_immediate(so, p, buf, len);
}
{
/* Run UDP rules against the UDP header of Teredo packets */
// FIXIT-L udph is always inner; need to check for outer
- if ( p->ptrs.udph && (p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
+ if ( p->is_udp_tunneled() )
fpEvalPacketUdp(p, task);
if ( p->get_snort_protocol_id() != UNKNOWN_PROTOCOL_ID and fpEvalHeaderSvc(p, task) )
// the first several of these bits must map to PktType
// eg PROTO_BIT__IP == BIT(PktType::IP), etc.
-#define PROTO_BIT__NONE 0x00000
-#define PROTO_BIT__IP 0x00001
-#define PROTO_BIT__TCP 0x00002
-#define PROTO_BIT__UDP 0x00004
-#define PROTO_BIT__ICMP 0x00008
-#define PROTO_BIT__PDU 0x00010
-#define PROTO_BIT__FILE 0x00020
-#define PROTO_BIT__ARP 0x00040
-#define PROTO_BIT__TEREDO 0x00080
-#define PROTO_BIT__GTP 0x00100
-#define PROTO_BIT__MPLS 0x00200
-#define PROTO_BIT__VLAN 0x00400
-#define PROTO_BIT__ETH 0x00800
-#define PROTO_BIT__TCP_EMBED_ICMP 0x01000
-#define PROTO_BIT__UDP_EMBED_ICMP 0x02000
-#define PROTO_BIT__ICMP_EMBED_ICMP 0x04000
-#define PROTO_BIT__ICMP_EMBED_OTHER 0x08000
-#define PROTO_BIT__IP6_EXT 0x10000
-#define PROTO_BIT__CISCO_META_DATA 0x20000
-#define PROTO_BIT__OTHER 0x40000
-#define PROTO_BIT__ALL 0x7FFFF
+#define PROTO_BIT__NONE 0x000000
+#define PROTO_BIT__IP 0x000001
+#define PROTO_BIT__TCP 0x000002
+#define PROTO_BIT__UDP 0x000004
+#define PROTO_BIT__ICMP 0x000008
+#define PROTO_BIT__PDU 0x000010
+#define PROTO_BIT__FILE 0x000020
+#define PROTO_BIT__ARP 0x000040
+#define PROTO_BIT__TEREDO 0x000080
+#define PROTO_BIT__GTP 0x000100
+#define PROTO_BIT__MPLS 0x000200
+#define PROTO_BIT__VLAN 0x000400
+#define PROTO_BIT__ETH 0x000800
+#define PROTO_BIT__TCP_EMBED_ICMP 0x001000
+#define PROTO_BIT__UDP_EMBED_ICMP 0x002000
+#define PROTO_BIT__ICMP_EMBED_ICMP 0x004000
+#define PROTO_BIT__ICMP_EMBED_OTHER 0x008000
+#define PROTO_BIT__IP6_EXT 0x010000
+#define PROTO_BIT__CISCO_META_DATA 0x020000
+#define PROTO_BIT__VXLAN 0x040000
+#define PROTO_BIT__UDP_TUNNELED 0x080000
+#define PROTO_BIT__OTHER 0x100000
+#define PROTO_BIT__ALL 0x1FFFFF
#define PROTO_BIT__ICMP_EMBED \
(PROTO_BIT__TCP_EMBED_ICMP | PROTO_BIT__UDP_EMBED_ICMP | \
Active* act = p->active;
// First Pass
- if ( act->session_was_blocked() )
+ if ( act->session_was_blocked() ||
+ (p->flow && (p->flow->flow_state == Flow::FlowState::BLOCK)) )
{
if ( !act->can_block() )
verdict = DAQ_VERDICT_PASS;
}
else if ( p->ptrs.decode_flags & DECODE_PKT_TRUST )
{
- if (p->flow)
+ if ( p->flow )
p->flow->set_ignore_direction(SSN_DIR_BOTH);
verdict = DAQ_VERDICT_WHITELIST;
}
"don't alert w/o established session (note: rule action still taken)" },
{ "tunnel_verdicts", Parameter::PT_STRING, nullptr, nullptr,
- "let DAQ handle non-allow verdicts for gtp|teredo|6in4|4in6|4in4|6in6|gre|mpls traffic" },
+ "let DAQ handle non-allow verdicts for gtp|teredo|6in4|4in6|4in4|6in6|gre|mpls|vxlan traffic" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
delete ha_config;
delete global_dbus;
- if (gtp_ports)
- delete gtp_ports;
-
delete profiler;
delete latency;
delete memory;
else if (!strcasecmp(tok, "teredo"))
tunnel_mask |= TUNNEL_TEREDO;
+ else if (!strcasecmp(tok, "vxlan"))
+ tunnel_mask |= TUNNEL_VXLAN;
+
else if (!strcasecmp(tok, "6in4"))
tunnel_mask |= TUNNEL_6IN4;
syslog_configured = true;
}
-bool SnortConfig::tunnel_bypass_enabled(uint8_t proto)
+bool SnortConfig::tunnel_bypass_enabled(uint16_t proto)
{
return (!((get_conf()->tunnel_mask & proto) or SFDAQ::get_tunnel_bypass(proto)));
}
TUNNEL_4IN4 = 0x10,
TUNNEL_6IN6 = 0x20,
TUNNEL_GRE = 0x40,
- TUNNEL_MPLS = 0x80
+ TUNNEL_MPLS = 0x80,
+ TUNNEL_VXLAN = 0x100
};
class FastPatternConfig;
//------------------------------------------------------
// decode module stuff
- PortBitSet* gtp_ports = nullptr;
-
int mpls_stack_depth = 0;
uint8_t mpls_payload_type = 0;
uint8_t max_ip6_extensions = 0;
uint8_t max_ip_layers = 0;
- bool enable_teredo = false;
bool enable_esp = false;
bool address_anomaly_check_enabled = false;
DataBus* global_dbus = nullptr;
- uint8_t tunnel_mask = 0;
+ uint16_t tunnel_mask = 0;
// FIXIT-L this is temporary for legacy paf_max required only for HI;
// it is not appropriate for multiple stream_tcp with different
static bool mpls_multicast()
{ return get_conf()->run_flags & RUN_FLAG__MPLS_MULTICAST; }
- static bool deep_teredo_inspection()
- { return get_conf()->enable_teredo; }
-
- static bool gtp_decoding()
- { return get_conf()->gtp_ports; }
-
- static bool is_gtp_port(uint16_t port)
- { return get_conf()->gtp_ports->test(port); }
-
static bool esp_decoding()
{ return get_conf()->enable_esp; }
return true;
}
- SO_PUBLIC static bool tunnel_bypass_enabled(uint8_t proto);
+ SO_PUBLIC static bool tunnel_bypass_enabled(uint16_t proto);
// checksum stuff
static bool checksum_drop(uint16_t codec_cksum_err_flag)
return local_instance && local_instance->can_replace();
}
-bool SFDAQ::get_tunnel_bypass(uint8_t proto)
+bool SFDAQ::get_tunnel_bypass(uint16_t proto)
{
return local_instance && local_instance->get_tunnel_bypass(proto);
}
static bool can_inject_raw();
static bool can_replace();
static bool can_run_unprivileged();
- SO_PUBLIC static bool get_tunnel_bypass(uint8_t proto);
+ SO_PUBLIC static bool get_tunnel_bypass(uint16_t proto);
// FIXIT-M X Temporary thread-local instance helpers to be removed when no longer needed
static void set_local_instance(SFDAQInstance*);
daq_tunnel_mask |= TUNNEL_GTP;
if (caps & DAQ_CAPA_DECODE_TEREDO)
daq_tunnel_mask |= TUNNEL_TEREDO;
+ if (caps & DAQ_CAPA_DECODE_VXLAN)
+ daq_tunnel_mask |= TUNNEL_VXLAN;
if (caps & DAQ_CAPA_DECODE_GRE)
daq_tunnel_mask |= TUNNEL_GRE;
if (caps & DAQ_CAPA_DECODE_4IN4)
}
}
-bool SFDAQInstance::get_tunnel_bypass(uint8_t proto)
+bool SFDAQInstance::get_tunnel_bypass(uint16_t proto)
{
return (daq_tunnel_mask & proto) != 0;
}
int add_expected(const Packet* ctrlPkt, const SfIp* cliIP, uint16_t cliPort,
const SfIp* srvIP, uint16_t srvPort, IpProtocol, unsigned timeout_ms,
unsigned /* flags */);
- bool get_tunnel_bypass(uint8_t proto);
+ bool get_tunnel_bypass(uint16_t proto);
private:
void get_tunnel_capabilities();
uint32_t pool_available = 0;
int dlt = -1;
DAQ_Stats_t daq_instance_stats = { };
- uint8_t daq_tunnel_mask = 0;
+ uint16_t daq_tunnel_mask = 0;
};
}
#endif
inline bool is_fragment() const
{ return ptrs.decode_flags & DECODE_FRAG; }
+ inline bool is_udp_tunneled() const
+ {
+ if (proto_bits & PROTO_BIT__UDP_TUNNELED)
+ {
+ assert(ptrs.udph);
+ return true;
+ }
+
+ return false;
+ }
+
inline bool has_tcp_data() const
{ return (proto_bits & PROTO_BIT__TCP) and data and dsize; }
ETHERNET_802_3 = 0x0105,
ETHERNET_802_11 = 0x0106,
ETHERNET_LLC = 0x0107,
+ VXLAN = 0x0108,
/*
* Below is a partial list of ethertypes.
extern const ConvertMap* enable_decode_oversized_alerts_map;
extern const ConvertMap* enable_decode_oversized_drops_map;
extern const ConvertMap* enable_deep_teredo_inspection_map;
-extern const ConvertMap* enable_ipopt_drops_map;
extern const ConvertMap* enable_gtp_map;
+extern const ConvertMap* enable_ipopt_drops_map;
extern const ConvertMap* enable_mpls_multicast_map;
extern const ConvertMap* enable_mpls_overlapping_ip_map;
extern const ConvertMap* enable_tcpopt_drops_map;
enable_decode_oversized_alerts_map,
enable_decode_oversized_drops_map,
enable_deep_teredo_inspection_map,
- enable_ipopt_drops_map,
enable_gtp_map,
+ enable_ipopt_drops_map,
enable_mpls_multicast_map,
enable_mpls_overlapping_ip_map,
enable_tcpopt_drops_map,
const ConvertMap* enable_decode_oversized_drops_map = &enable_decode_oversized_drops_api;
+/*************************************************
+ ****************** enable_gtp ******************
+ *************************************************/
+
+static const std::string enable_gtp = "enable_gtp";
+static const ConvertMap enable_gtp_api =
+{
+ enable_gtp,
+ deleted_ctor<& enable_gtp>
+};
+
+const ConvertMap* enable_gtp_map = &enable_gtp_api;
+
/*************************************************
************** enable_ipopt_drops *************
*************************************************/
const ConvertMap* enable_deep_teredo_inspection_map = &enable_deep_teredo_inspection_api;
-/*************************************************
- ****************** enable_gtp ******************
- *************************************************/
-
-static const std::string enable_gtp = "enable_gtp";
-static const ConvertMap enable_gtp_api =
-{
- enable_gtp,
- config_true_no_opt_ctor<& enable_gtp, & udp>
-};
-
-const ConvertMap* enable_gtp_map = &enable_gtp_api;
-
/*************************************************
********** enable_mpls_overlapping_ip **********
*************************************************/