]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1893 in SNORT/snort3 from ~SUNIMUKH/snort3:sgt to master
authorGeorge Koikara (gkoikara) <gkoikara@cisco.com>
Thu, 9 Jan 2020 14:24:03 +0000 (14:24 +0000)
committerGeorge Koikara (gkoikara) <gkoikara@cisco.com>
Thu, 9 Jan 2020 14:24:03 +0000 (14:24 +0000)
Squashed commit of the following:

commit a6367694b7def585aa6471749d916301b6f24ee3
Author: Sunirmal Mukherjee <sunimukh@cisco.com>
Date:   Tue Dec 3 03:53:33 2019 -0500

    sgt-detection: API support to accessing SGT from CiscoMetaData

src/codecs/link/CMakeLists.txt
src/codecs/link/cd_ciscometadata.cc
src/codecs/link/test/CMakeLists.txt [new file with mode: 0644]
src/codecs/link/test/cisco_meta_data_test.cc [new file with mode: 0644]
src/codecs/link/test/dev_notes.txt [new file with mode: 0644]
src/framework/decode_data.h
src/protocols/CMakeLists.txt
src/protocols/cisco_meta_data.h [new file with mode: 0644]
src/protocols/layer.cc
src/protocols/layer.h

index 76a1d54dc6f5968895c365280e47bb352584da77..289bff94fbe69210286b3b7bbd7e66574830dbd7 100644 (file)
@@ -35,3 +35,5 @@ if(STATIC_CODECS)
         ${PLUGIN_SOURCES}
     )
 endif(STATIC_CODECS)
+
+add_subdirectory(test)
index 0fd447c7a67d4b3943daa58f1b7cf97045286860..ca502e6aed7be45920d4f2e8fac78499635dfa3b 100644 (file)
@@ -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<ProtocolId>& v)
@@ -80,66 +73,73 @@ void CiscoMetaDataCodec::get_protocol_ids(std::vector<ProtocolId>& 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<const CiscoMetaDataHdr*>(raw.data);
-    uint32_t cmdh_rem_len = cmdh->length << 3;
+    const cisco_meta_data::CiscoMetaDataHdr* const cmdh =
+        reinterpret_cast<const cisco_meta_data::CiscoMetaDataHdr*>(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<const CiscoMetaDataOpt*>(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<const cisco_meta_data::CiscoMetaDataOpt*>(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<ProtocolId>
         (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 (file)
index 0000000..1ac67d6
--- /dev/null
@@ -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 (file)
index 0000000..53195f9
--- /dev/null
@@ -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 <sunimukh@cisco.com> 
+// 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 <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+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<cisco_meta_data::CiscoMetaDataOpt*>(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 (file)
index 0000000..65051ee
--- /dev/null
@@ -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.
index d04b89e89b8298fd9dc7f1da0d8249c6c4ef9b22..0b5b9eb38c9b79fd621f97d84d732664ec1534cf 100644 (file)
@@ -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 | \
index ac17592a0bc7a058077cd0f811bc1698be7486e4..20390609d51b55142305a6d9a26b471e7d1df5cf 100644 (file)
@@ -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 (file)
index 0000000..79edbc7
--- /dev/null
@@ -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 <sunimukh@cisco.com>
+
+#ifndef PROTOCOLS_CISCO_META_DATA_H
+#define PROTOCOLS_CISCO_META_DATA_H
+
+#include <arpa/inet.h>
+
+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
index d21dbc34994b777b42dfa012a66ca701f57ab8e7..21ecb976b9b520eba4b1b6fe7af7d29e54b5b19e 100644 (file)
@@ -150,6 +150,20 @@ const vlan::VlanTagHdr* get_vlan_layer(const Packet* const p)
     return reinterpret_cast<const vlan::VlanTagHdr*>(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<const snort::cisco_meta_data::CiscoMetaDataOpt*>(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;
index 3bc1bb54cf94671c58230e9f9042f7d6add74d9e..a279c08fc4f2778b53c6b2387ab00d6ae6befc15 100644 (file)
@@ -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