From: George Koikara (gkoikara) Date: Thu, 9 Jan 2020 14:24:03 +0000 (+0000) Subject: Merge pull request #1893 in SNORT/snort3 from ~SUNIMUKH/snort3:sgt to master X-Git-Tag: 3.0.0-268~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82b4d983ce97f503f06b20ec16d9b892bc6d901f;p=thirdparty%2Fsnort3.git Merge pull request #1893 in SNORT/snort3 from ~SUNIMUKH/snort3:sgt to master Squashed commit of the following: commit a6367694b7def585aa6471749d916301b6f24ee3 Author: Sunirmal Mukherjee Date: Tue Dec 3 03:53:33 2019 -0500 sgt-detection: API support to accessing SGT from CiscoMetaData --- diff --git a/src/codecs/link/CMakeLists.txt b/src/codecs/link/CMakeLists.txt index 76a1d54dc..289bff94f 100644 --- a/src/codecs/link/CMakeLists.txt +++ b/src/codecs/link/CMakeLists.txt @@ -35,3 +35,5 @@ if(STATIC_CODECS) ${PLUGIN_SOURCES} ) endif(STATIC_CODECS) + +add_subdirectory(test) diff --git a/src/codecs/link/cd_ciscometadata.cc b/src/codecs/link/cd_ciscometadata.cc index 0fd447c7a..ca502e6ae 100644 --- a/src/codecs/link/cd_ciscometadata.cc +++ b/src/codecs/link/cd_ciscometadata.cc @@ -23,6 +23,9 @@ #include "codecs/codec_module.h" #include "framework/codec.h" +#include "log/messages.h" +#include "protocols/cisco_meta_data.h" +#include "protocols/layer.h" using namespace snort; @@ -58,21 +61,11 @@ public: bool decode(const RawData&, CodecData&, DecodeData&) override; }; -struct CiscoMetaDataHdr -{ - uint8_t version; // This must be 1 - uint8_t length; //This is the header size in bytes / 8 -}; - -struct CiscoMetaDataOpt -{ - uint16_t opt_len_type; // 3-bit length + 13-bit type. Length of 0 = 4. Type must be 1. - uint16_t sgt; // Can be any value except 0xFFFF -}; - constexpr uint8_t CISCO_META_OPT_LEN_SHIFT = 4; constexpr uint16_t CISCO_META_OPT_TYPE_SGT = 1; constexpr uint16_t CISCO_META_OPT_TYPE_MASK = 0x1FFF; //mask opt_len_type to get option type +// Currently we only support one CiscoMetaDataHdr which is size of 1 byte. +constexpr uint8_t SUPPORTED_HDR_LEN = 1; } // namespace void CiscoMetaDataCodec::get_protocol_ids(std::vector& v) @@ -80,66 +73,73 @@ void CiscoMetaDataCodec::get_protocol_ids(std::vector& v) bool CiscoMetaDataCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) { - if (raw.len < sizeof(CiscoMetaDataHdr)) + uint16_t len; + uint16_t type; + + /* 2 octets for ethertype + 2 octets for CiscoMetaDataHdr + * + 4 octets for CiscoMetaDataOpt + */ + uint32_t total_len = (sizeof(uint16_t) + + sizeof(cisco_meta_data::CiscoMetaDataHdr) + + sizeof(cisco_meta_data::CiscoMetaDataOpt)); + + if (raw.len < total_len) { codec_event(codec, DECODE_CISCO_META_HDR_TRUNC); return false; } - const CiscoMetaDataHdr* const cmdh = - reinterpret_cast(raw.data); - uint32_t cmdh_rem_len = cmdh->length << 3; + const cisco_meta_data::CiscoMetaDataHdr* const cmdh = + reinterpret_cast(raw.data); - if ( (raw.len < cmdh_rem_len) || (cmdh_rem_len == 0) ) + if (SUPPORTED_HDR_LEN != cmdh->length) { codec_event(codec, DECODE_CISCO_META_HDR_TRUNC); return false; } - const CiscoMetaDataOpt* cmd_options = - reinterpret_cast(raw.data + sizeof(CiscoMetaDataHdr)); - // validate options, lengths, and SGTs - cmdh_rem_len -= sizeof(CiscoMetaDataHdr) + sizeof(uint16_t); //2 octets for ethertype - if(cmdh_rem_len == 0) - cmd_options = nullptr; + const cisco_meta_data::CiscoMetaDataOpt* cmd_option = + reinterpret_cast(raw.data + + sizeof(cisco_meta_data::CiscoMetaDataHdr)); + + // Top 3 bits (length) must be equal to 0 + // Bottom 13 bits (type) must be 1 to indicate SGT + len = ntohs(cmd_option->opt_len_type) >> CISCO_META_OPT_LEN_SHIFT; + type = ntohs(cmd_option->opt_len_type) & CISCO_META_OPT_TYPE_MASK; - for(int i = 0; cmdh_rem_len > 0; i++) + // 0 indicates 4 octets which is sizeof(CiscoMetaDataOpt) + if (len != 0) { - // Top 3 bits (length) must be equal to 0 or 4 - // Bottom 13 bits (type) must be 1 to indicate SGT - const CiscoMetaDataOpt* opt = &cmd_options[i]; - uint16_t len = ntohs(opt->opt_len_type) >> CISCO_META_OPT_LEN_SHIFT; - uint16_t type = ntohs(opt->opt_len_type) & CISCO_META_OPT_TYPE_MASK; - - // 0 indicates 4 octets - if(len != 0 && len != 4) - { - codec_event(codec, DECODE_CISCO_META_HDR_OPT_LEN); - return false; - } - - if(type != CISCO_META_OPT_TYPE_SGT) - { - codec_event(codec, DECODE_CISCO_META_HDR_OPT_TYPE); - return false; - } - - /* Tag value 0xFFFF is invalid */ - if(opt->sgt == 0xFFFF) - { - codec_event(codec, DECODE_CISCO_META_HDR_SGT); - return false; - } - cmdh_rem_len -= sizeof(CiscoMetaDataOpt); + codec_event(codec, DECODE_CISCO_META_HDR_OPT_LEN); + return false; } - codec.lyr_len = cmdh->length << 3; + if (type != CISCO_META_OPT_TYPE_SGT) + { + codec_event(codec, DECODE_CISCO_META_HDR_OPT_TYPE); + return false; + } + + /* Tag value 0xFFFF is invalid */ + if (cmd_option->sgt == 0xFFFF) + { + codec_event(codec, DECODE_CISCO_META_HDR_SGT); + return false; + } + +#ifdef REG_TEST + LogMessage("Value of sgt %d\n", ntohs(cmd_option->sgt)); +#endif + + codec.lyr_len = total_len; //The last 2 octets of the header will be the real ethtype codec.next_prot_id = static_cast (ntohs(*((const uint16_t*)(raw.data + codec.lyr_len - sizeof(uint16_t))))); codec.codec_flags |= CODEC_ETHER_NEXT; + codec.proto_bits |= PROTO_BIT__CISCO_META_DATA; + return true; } diff --git a/src/codecs/link/test/CMakeLists.txt b/src/codecs/link/test/CMakeLists.txt new file mode 100644 index 000000000..1ac67d6eb --- /dev/null +++ b/src/codecs/link/test/CMakeLists.txt @@ -0,0 +1,4 @@ +add_cpputest( cisco_meta_data_test + SOURCES + ../../../protocols/layer.cc +) diff --git a/src/codecs/link/test/cisco_meta_data_test.cc b/src/codecs/link/test/cisco_meta_data_test.cc new file mode 100644 index 000000000..53195f910 --- /dev/null +++ b/src/codecs/link/test/cisco_meta_data_test.cc @@ -0,0 +1,112 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2019-2019 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. +//-------------------------------------------------------------------------- + +// cisco_meta_data_test.cc author Sunirmal Mukherjee +// unit test main + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "protocols/cisco_meta_data.h" +#include "protocols/ip.h" +#include "protocols/layer.h" +#include "protocols/packet.h" + +#include +#include + +using namespace snort; + +//------------------------------------------------------------------------- +// tests +//------------------------------------------------------------------------- + +Packet::Packet(bool) { } +Packet::~Packet() = default; + +namespace snort +{ +void ip::IpApi::set(ip::IP4Hdr const* iph) +{ + return; +} + +void ip::IpApi::set(ip::IP6Hdr const* iph) +{ + return; +} + +void ip::IpApi::reset() +{ + return; +} + +const uint8_t* ip::IpApi::ip_data() const +{ + return nullptr; +} +} + +static inline void push_layer(Packet* p, + ProtocolId prot_id, + const uint8_t* hdr_start, + uint32_t len) +{ + Layer& lyr = p->layers[p->num_layers++]; + lyr.prot_id = prot_id; + lyr.start = hdr_start; + lyr.length = (uint16_t)len; +} + +TEST_GROUP(cisco_meta_data_test) +{ +}; + +TEST(cisco_meta_data_test, cisco_meta_data_class_test) +{ + Packet pkt(false); + Layer layers; + uint8_t * cmd_data; + int len; + int sgt; + + pkt.num_layers = 0; + pkt.layers = &layers; + + cmd_data = new uint8_t[sizeof(cisco_meta_data::CiscoMetaDataHdr) + sizeof(cisco_meta_data::CiscoMetaDataOpt)]; + + cisco_meta_data::CiscoMetaDataOpt* cmd_options = + reinterpret_cast(cmd_data + sizeof(cisco_meta_data::CiscoMetaDataHdr)); + cmd_options->sgt = 512; + + len = (sizeof(cisco_meta_data::CiscoMetaDataHdr) + sizeof(cisco_meta_data::CiscoMetaDataOpt)); + pkt.proto_bits |= PROTO_BIT__CISCO_META_DATA; + push_layer(&pkt, ProtocolId::ETHERTYPE_CISCO_META, cmd_data, len); + sgt = htons(layer::get_cisco_meta_data_layer(&pkt)->sgt_val()); + CHECK(sgt == cmd_options->sgt); + + delete[] cmd_data; +} + +int main(int argc, char** argv) +{ + return CommandLineTestRunner::RunAllTests(argc, argv); +} + diff --git a/src/codecs/link/test/dev_notes.txt b/src/codecs/link/test/dev_notes.txt new file mode 100644 index 000000000..65051eeaf --- /dev/null +++ b/src/codecs/link/test/dev_notes.txt @@ -0,0 +1,8 @@ +This is the test case to parse SGT(Security Group Tag/Trustsec) from CiscoMetaData. + +CiscoMetaData - A proprietary header in ethernet layer, called CiscoMetaDataHdr. + After CiscoMetaDataHdr, packet contains CiscoMetaDataOpt which carries + SGT data. + +Here created a dummy packet which has CiscoMetaDataHdr integrated and pushing it to layer stack. +To validate the sgt data, parsing it from layer and comparing with the expected. diff --git a/src/framework/decode_data.h b/src/framework/decode_data.h index d04b89e89..0b5b9eb38 100644 --- a/src/framework/decode_data.h +++ b/src/framework/decode_data.h @@ -67,8 +67,9 @@ enum class PktType : std::uint8_t #define PROTO_BIT__ICMP_EMBED_ICMP 0x04000 #define PROTO_BIT__ICMP_EMBED_OTHER 0x08000 #define PROTO_BIT__IP6_EXT 0x10000 -#define PROTO_BIT__OTHER 0x20000 -#define PROTO_BIT__ALL 0x3FFFF +#define PROTO_BIT__CISCO_META_DATA 0x20000 +#define PROTO_BIT__OTHER 0x40000 +#define PROTO_BIT__ALL 0x7FFFF #define PROTO_BIT__ICMP_EMBED \ (PROTO_BIT__TCP_EMBED_ICMP | PROTO_BIT__UDP_EMBED_ICMP | \ diff --git a/src/protocols/CMakeLists.txt b/src/protocols/CMakeLists.txt index ac17592a0..20390609d 100644 --- a/src/protocols/CMakeLists.txt +++ b/src/protocols/CMakeLists.txt @@ -1,6 +1,7 @@ set (PROTOCOL_HEADERS arp.h + cisco_meta_data.h eapol.h eth.h icmp4.h diff --git a/src/protocols/cisco_meta_data.h b/src/protocols/cisco_meta_data.h new file mode 100644 index 000000000..79edbc719 --- /dev/null +++ b/src/protocols/cisco_meta_data.h @@ -0,0 +1,46 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// cisco_meta_data.h author Sunirmal Mukherjee + +#ifndef PROTOCOLS_CISCO_META_DATA_H +#define PROTOCOLS_CISCO_META_DATA_H + +#include + +namespace snort +{ +namespace cisco_meta_data +{ +struct CiscoMetaDataHdr +{ + uint8_t version; // This must be 1 + uint8_t length; //This is the header size in bytes / 8 +}; + +struct CiscoMetaDataOpt +{ + uint16_t opt_len_type; // 3-bit length + 13-bit type. Type must be 1 + uint16_t sgt; // Can be any value except 0xFFFF + + inline uint16_t sgt_val() const + { return ntohs(sgt); } +}; +} +} + +#endif diff --git a/src/protocols/layer.cc b/src/protocols/layer.cc index d21dbc349..21ecb976b 100644 --- a/src/protocols/layer.cc +++ b/src/protocols/layer.cc @@ -150,6 +150,20 @@ const vlan::VlanTagHdr* get_vlan_layer(const Packet* const p) return reinterpret_cast(lyr->start); } +const cisco_meta_data::CiscoMetaDataOpt* get_cisco_meta_data_layer(const Packet* const p) +{ + assert( p->proto_bits & PROTO_BIT__CISCO_META_DATA ); + uint8_t num_layers = p->num_layers; + const Layer* lyr = p->layers; + const Layer* cmd_lyr; + + cmd_lyr = find_layer(lyr, num_layers, ProtocolId::ETHERTYPE_CISCO_META, + ProtocolId::ETHERTYPE_CISCO_META); + + return reinterpret_cast(cmd_lyr->start + + sizeof(snort::cisco_meta_data::CiscoMetaDataHdr)); +} + const eth::EtherHdr* get_eth_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 3bc1bb54c..a279c08fc 100644 --- a/src/protocols/layer.h +++ b/src/protocols/layer.h @@ -21,6 +21,7 @@ #define PROTOCOLS_LAYER_H #include "main/snort_types.h" +#include "protocols/cisco_meta_data.h" #include "protocols/protocol_ids.h" namespace snort @@ -180,6 +181,9 @@ SO_PUBLIC bool set_inner_ip_api(const Packet* const, ip::IpApi&, SO_PUBLIC bool set_outer_ip_api(const Packet* const, ip::IpApi&, int8_t& curr_layer); SO_PUBLIC bool set_outer_ip_api(const Packet* const, ip::IpApi&, IpProtocol& next_ip_proto, int8_t& curr_layer); + +/* This is the api to get CiscoMetaData layer to fetch SGT value from it */ +SO_PUBLIC const cisco_meta_data::CiscoMetaDataOpt* get_cisco_meta_data_layer(const Packet* const p); } // namespace layer } // namespace snort #endif