]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4230: trace: Add tenants filtering and logging
authorVitalii Tron -X (vtron - SOFTSERVE INC at Cisco) <vtron@cisco.com>
Tue, 5 Mar 2024 17:21:04 +0000 (17:21 +0000)
committerSteve Chew (stechew) <stechew@cisco.com>
Tue, 5 Mar 2024 17:21:04 +0000 (17:21 +0000)
Merge in SNORT/snort3 from ~VTRON/snort3:trace_module_tenant to master

Squashed commit of the following:

commit ae746511828751a36b744c3056da353cdfecf00e
Author: Vitalii Tron <vtron@cisco.com>
Date:   Tue Feb 27 11:38:40 2024 -0500

    trace: add tenants logging

src/framework/dev_notes.txt
src/framework/packet_constraints.cc
src/framework/packet_constraints.h
src/network_inspectors/packet_tracer/packet_tracer_module.cc
src/trace/trace_loggers.cc
src/trace/trace_module.cc
src/trace/trace_parser.cc

index 7fd55e68cfa719e327457463efff43d58443f653..bb733cc82b88a96f52d031d85ae924b5730ea09c 100644 (file)
@@ -10,6 +10,6 @@ attached to configuration with one element per packet thread, however those
 cases are rare and should only be needed by the framework code, not the
 plugins.
 
-PacketConstraints allow you to match packets and flows against a 5-tuple.
-( ip_proto; src_ip; dst_ip; src_port; dst_port)
+PacketConstraints allow you to match packets and flows against a 6-tuple.
+( ip_proto; src_ip; dst_ip; src_port; dst_port; tenant)
 
index 939a287d150b3819193bb87f7dff02b292824efa..67ccdad999d92c47e65f77b7a5b1955642039973 100644 (file)
@@ -40,7 +40,7 @@ inline bool match_constraints(const snort::PacketConstraints& cs,
         (!(cs.set_bits & SetBits::SRC_IP) or (sip == cs.src_ip)) and
         (!(cs.set_bits & SetBits::DST_IP) or (dip == cs.dst_ip));
 
-    if (res && tenant_id && !cs.tenants.empty())
+    if (res and (cs.set_bits & SetBits::TENANT) and tenant_id and !cs.tenants.empty())
     {
         auto it = std::find_if(cs.tenants.cbegin(), cs.tenants.cend(),
             [tenant_id](uint32_t t){ return t == tenant_id; });
@@ -87,7 +87,7 @@ bool PacketConstraints::operator==(const PacketConstraints& other) const
         and ( !(set_bits & DST_PORT) or dst_port == other.dst_port )
         and ( !(set_bits & SRC_IP) or src_ip == other.src_ip )
         and ( !(set_bits & DST_IP) or dst_ip == other.dst_ip )
-        and ( tenants == other.tenants );
+        and ( !(set_bits & TENANT) or tenants == other.tenants );
 }
 
 bool PacketConstraints::packet_match(const Packet& p) const
@@ -110,9 +110,10 @@ bool PacketConstraints::packet_match(const Packet& p) const
     const auto& dip = *p.ptrs.ip_api.get_dst();
     const auto sp = p.ptrs.sp;
     const auto dp = p.ptrs.dp;
+    const auto tenant = p.pkth->tenant_id;
 
-    return match_constraints(*this, sip, dip, sp, dp, p.pkth->tenant_id) or
-        match_constraints(*this, dip, sip, dp, sp, p.pkth->tenant_id);
+    return match_constraints(*this, sip, dip, sp, dp, tenant) or
+        match_constraints(*this, dip, sip, dp, sp, tenant);
 }
 
 bool PacketConstraints::flow_match(const Flow& f) const
@@ -181,11 +182,9 @@ TEST_CASE("Packet constraints comparison", "[framework]")
         const uint32_t ip1 = 0x01010101;
         const uint32_t ip2 = 0x02020202;
         PacketConstraints exp = PacketConstraints(IpProtocol::PROTO_NOT_SET, 0, 0,
-            SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1, true);
-        exp.tenants = tenants1;
+            SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1, true, tenants1);
         PacketConstraints act = PacketConstraints(IpProtocol::PROTO_NOT_SET, 0, 0,
-            SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1, true);
-        act.tenants = tenants2;
+            SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1, true, tenants2);
         CHECK( exp == act );
     }
 }
@@ -209,6 +208,7 @@ TEST_CASE("Packet constraints matching", "[framework]")
         cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
         cs.set_bits |= PacketConstraints::SetBits::SRC_IP;
         cs.set_bits |= PacketConstraints::SetBits::DST_IP;
+        cs.set_bits |= PacketConstraints::SetBits::TENANT;
 
         cs.ip_proto = proto;
         cs.src_port = sport;
index ffe6c03bce1218bed01dddcf5226ab4c1ad49e5b..093a61ae7960c16a3ec04c60f9dee4a34eabf0cd 100644 (file)
@@ -39,13 +39,15 @@ struct PacketConstraints
         DST_IP   = 1 << 2,
         SRC_PORT = 1 << 3,
         DST_PORT = 1 << 4,
+        TENANT   = 1 << 5,
     };
 
     PacketConstraints() = default;
     PacketConstraints(IpProtocol ip_proto, uint16_t src_port, uint16_t dst_port,
-        const snort::SfIp& src_ip, const snort::SfIp& dst_ip, uint8_t set_bits, bool match) :
+        const snort::SfIp& src_ip, const snort::SfIp& dst_ip, uint8_t set_bits, bool match,
+        const std::vector<uint32_t>& tenants = std::vector<uint32_t>()) :
         ip_proto(ip_proto), src_port(src_port), dst_port(dst_port),
-        src_ip(src_ip), dst_ip(dst_ip), set_bits(set_bits), match(match)
+        src_ip(src_ip), dst_ip(dst_ip), set_bits(set_bits), match(match), tenants(tenants)
     {}
     PacketConstraints(const PacketConstraints&);
     PacketConstraints& operator=(const PacketConstraints& other);
index f714aa1b0f0a1bc8d174847c07fd795874ab51ca..df9f43d30bba723d141f23e0cef9230527524865 100644 (file)
@@ -130,7 +130,10 @@ static int enable(lua_State* L)
     PacketConstraints constraints = {};
 
     if (tenantsstr)
+    {
         StrToIntVector(tenantsstr, ',', constraints.tenants);
+        constraints.set_bits |= PacketConstraints::SetBits::TENANT;
+    }
 
     if (proto and (IpProtocol)proto < IpProtocol::PROTO_NOT_SET)
     {
index 2025bdeaa1fa48ddb5ad2ac095dc87d84fea022b..fb4402218922d416a0e98e298d75f95e21c55370 100644 (file)
@@ -60,6 +60,13 @@ static std::string get_ntuple(bool ntuple, const Packet* p)
     ss << unsigned(p->get_ip_proto_next()) << " ";
     ss << "AS=" << p->pkth->address_space_id << ":";
 
+    if (p->pkth->tenant_id)
+        ss << "TN=" << p->pkth->tenant_id<< ":";
+
+    const auto vni = p->get_flow_geneve_vni();
+    if (vni)
+        ss << "VNI=" << vni<< ":";
+
     return ss.str();
 }
 
index ea04a64efbb20ed2d417cb52473f0fdb10a6e4c0..018b26181474efe2fbab6fcb7239f754cbaa82f0 100644 (file)
@@ -133,6 +133,9 @@ void TraceModule::generate_params()
 
         { "match", Parameter::PT_BOOL, nullptr, "true",
           "use constraints to filter traces" },
+        
+        { "tenants", Parameter::PT_STRING, nullptr, nullptr,
+          "tenants filter" },
 
         { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
     };
index 5b132cfe4c2fe309eb804cd5d88c1da2f7c63fc2..8822a4bc4a782e28c3679f98b67e6428e5db3ed1 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "framework/module.h"
 #include "managers/module_manager.h"
+#include "utils/util.h"
 
 #include "trace_config.h"
 
@@ -36,7 +37,7 @@ TraceParser::TraceParser(TraceConfig& tc)
     : trace_config(tc)
 {
     // Will be initialized only once when first TraceParser instance created
-    if ( s_configured_trace_options.empty() )
+    if (s_configured_trace_options.empty())
         init_configured_trace_options();
     else
         reset_configured_trace_options();
@@ -44,20 +45,20 @@ TraceParser::TraceParser(TraceConfig& tc)
 
 bool TraceParser::set_traces(const std::string& module_name, const Value& val)
 {
-    if ( !s_configured_trace_options.count(module_name)
-        and module_name != DEFAULT_TRACE_OPTION_NAME )
+    if (!s_configured_trace_options.count(module_name) 
+        and module_name != DEFAULT_TRACE_OPTION_NAME)
         return false;
 
-    if ( module_name == DEFAULT_TRACE_OPTION_NAME )
+    if (module_name == DEFAULT_TRACE_OPTION_NAME)
     {
-        for ( const auto& trace_options : s_configured_trace_options )
+        for (const auto& trace_options : s_configured_trace_options)
         {
-            if ( trace_options.second.at(DEFAULT_TRACE_OPTION_NAME) )
+            if (trace_options.second.at(DEFAULT_TRACE_OPTION_NAME))
                 continue;
 
-            for ( const auto& trace_option : trace_options.second )
+            for (const auto& trace_option : trace_options.second)
             {
-                if ( !trace_option.second )
+                if (!trace_option.second)
                     trace_config.set_trace(trace_options.first, trace_option.first,
                         val.get_uint8());
             }
@@ -65,12 +66,12 @@ bool TraceParser::set_traces(const std::string& module_name, const Value& val)
 
         return true;
     }
-    else if ( val.is(DEFAULT_TRACE_OPTION_NAME) )
+    else if (val.is(DEFAULT_TRACE_OPTION_NAME))
     {
         auto& trace_options = s_configured_trace_options[module_name];
-        for ( const auto& trace_option : trace_options )
+        for (const auto& trace_option : trace_options)
         {
-            if ( !trace_option.second )
+            if (!trace_option.second)
                 trace_config.set_trace(module_name, trace_option.first, val.get_uint8());
         }
         trace_options[DEFAULT_TRACE_OPTION_NAME] = true;
@@ -87,39 +88,48 @@ bool TraceParser::set_traces(const std::string& module_name, const Value& val)
 
 bool TraceParser::set_constraints(const Value& val)
 {
-    if ( val.is("ip_proto") )
+    if (val.is("ip_proto"))
     {
         parsed_constraints.ip_proto = static_cast<IpProtocol>(val.get_uint8());
         parsed_constraints.set_bits |= PacketConstraints::SetBits::IP_PROTO;
     }
-    else if ( val.is("src_port") )
+    else if (val.is("src_port"))
     {
         parsed_constraints.src_port = val.get_uint16();
         parsed_constraints.set_bits |= PacketConstraints::SetBits::SRC_PORT;
     }
-    else if ( val.is("dst_port") )
+    else if (val.is("dst_port"))
     {
         parsed_constraints.dst_port = val.get_uint16();
         parsed_constraints.set_bits |= PacketConstraints::SetBits::DST_PORT;
     }
-    else if ( val.is("src_ip") )
+    else if (val.is("src_ip"))
     {
         const char* str = val.get_string();
-        if ( parsed_constraints.src_ip.set(str) != SFIP_SUCCESS )
+        if (parsed_constraints.src_ip.set(str) != SFIP_SUCCESS)
             return false;
 
         parsed_constraints.set_bits |= PacketConstraints::SetBits::SRC_IP;
     }
-    else if ( val.is("dst_ip") )
+    else if (val.is("dst_ip"))
     {
         const char* str = val.get_string();
-        if ( parsed_constraints.dst_ip.set(str) != SFIP_SUCCESS )
+        if (parsed_constraints.dst_ip.set(str) != SFIP_SUCCESS)
             return false;
 
         parsed_constraints.set_bits |= PacketConstraints::SetBits::DST_IP;
     }
-    else if ( val.is("match") )
+    else if (val.is("match"))
         parsed_constraints.match = val.get_bool();
+    else if (val.is("tenants"))
+    {
+        const char* tenants_str = val.get_string();
+        if (!tenants_str)
+            return false;
+
+        StrToIntVector(tenants_str, ',', parsed_constraints.tenants);
+        parsed_constraints.set_bits |= PacketConstraints::SetBits::TENANT;
+    }
     else
         return false;
 
@@ -128,7 +138,7 @@ bool TraceParser::set_constraints(const Value& val)
 
 void TraceParser::finalize_constraints()
 {
-    if ( !parsed_constraints.match or parsed_constraints.set_bits )
+    if (!parsed_constraints.match or parsed_constraints.set_bits)
         trace_config.constraints = new PacketConstraints(parsed_constraints);
 }
 
@@ -143,9 +153,9 @@ void TraceParser::clear_constraints()
 
 void TraceParser::reset_configured_trace_options()
 {
-    for ( auto& module_trace_options : s_configured_trace_options )
+    for (auto& module_trace_options : s_configured_trace_options)
     {
-        for ( auto& trace_options : module_trace_options.second )
+        for (auto& trace_options : module_trace_options.second)
             trace_options.second = false;
     }
 }
@@ -153,16 +163,16 @@ void TraceParser::reset_configured_trace_options()
 void TraceParser::init_configured_trace_options()
 {
     auto trace_modules = ModuleManager::get_all_modules();
-    for ( const auto* module : trace_modules )
+    for (const auto* module : trace_modules)
     {
         const TraceOption* trace_options = module->get_trace_options();
-        if ( !trace_options )
+        if (!trace_options)
             continue;
 
         auto& module_trace_options = s_configured_trace_options[module->get_name()];
 
         module_trace_options[DEFAULT_TRACE_OPTION_NAME] = false;
-        while ( trace_options->name )
+        while (trace_options->name)
         {
             module_trace_options[trace_options->name] = false;
             ++trace_options;
@@ -195,6 +205,9 @@ void TraceParser::init_configured_trace_options()
 #define PORT_OPTION(name, value) \
     CONFIG_OPTION(name, (uint64_t)value, Parameter::PT_INT, "0:65535")
 
+#define TENANT_OPTION(name, value) \
+    CONFIG_OPTION(name, value, Parameter::PT_STRING, nullptr)
+
 enum { OPT_1, OPT_2 };
 
 static const TraceOption s_trace_options[] =
@@ -449,6 +462,21 @@ TEST_CASE("packet constraints", "[TraceParser]")
         CONFIG_OPTION(invalid_option, (uint64_t)5, Parameter::PT_INT, "0:8");
         CHECK(false == tp.set_constraints(invalid_option));
     }
+
+    SECTION("tenants")
+    {
+        TENANT_OPTION(tenants, "11,12");
+        const auto expected_tenants = std::vector<uint32_t>{ 11, 12 };
+        
+        const PacketConstraints expected_constraints = PacketConstraints(IpProtocol::PROTO_NOT_SET, 0, 0,
+            SfIp(), SfIp(), PacketConstraints::TENANT, true, expected_tenants);
+
+        CHECK(true == tp.set_constraints(tenants));
+        tp.finalize_constraints();
+
+        REQUIRE(tc.constraints != nullptr);
+        CHECK(*tc.constraints == expected_constraints);
+    }
 }
 
 #endif // UNIT_TEST