]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3142: framework: add a traffic policy and data bus to the network polic...
authorRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 30 Nov 2021 21:39:53 +0000 (21:39 +0000)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 30 Nov 2021 21:39:53 +0000 (21:39 +0000)
Merge in SNORT/snort3 from ~RDEMPSTE/snort3:tenant to master

Squashed commit of the following:

commit c998980c574e3da4fd7fafc79e03fbb538a18a2a
Author: Ron Dempster (rdempste) <rdempste@cisco.com>
Date:   Thu Nov 4 17:34:54 2021 -0400

    framework: add support for multiple tenant

    Add a traffic policy and data bus to the network policy to be able to support
    multiple tenants and add a selector inspector to select a config file for each
    tenant.

73 files changed:
src/CMakeLists.txt
src/decompress/file_olefile.cc
src/detection/regex_offload.h
src/flow/flow.h
src/flow/flow_control.cc
src/flow/test/flow_cache_test.cc
src/flow/test/flow_control_test.cc
src/flow/test/flow_stash_test.cc
src/framework/CMakeLists.txt
src/framework/base_api.h
src/framework/data_bus.cc
src/framework/data_bus.h
src/framework/inspector.cc
src/framework/policy_selector.h [new file with mode: 0644]
src/framework/test/data_bus_test.cc
src/hash/test/ghash_test.cc
src/hash/test/xhash_test.cc
src/hash/test/zhash_test.cc
src/helpers/test/hyper_search_test.cc
src/ips_options/test/ips_regex_test.cc
src/main/analyzer.cc
src/main/policy.cc
src/main/policy.h
src/main/snort.cc
src/main/snort_config.cc
src/main/snort_config.h
src/main/thread_config.cc
src/managers/CMakeLists.txt
src/managers/inspector_manager.cc
src/managers/inspector_manager.h
src/managers/module_manager.cc
src/managers/plugin_manager.cc
src/managers/policy_selector_manager.cc [new file with mode: 0644]
src/managers/policy_selector_manager.h [new file with mode: 0644]
src/network_inspectors/appid/appid_inspector.cc
src/network_inspectors/binder/bind_module.cc
src/network_inspectors/binder/bind_module.h
src/network_inspectors/binder/binder.cc
src/network_inspectors/binder/binding.cc
src/network_inspectors/binder/binding.h
src/network_inspectors/normalize/norm_module.h
src/network_inspectors/perf_monitor/perf_monitor.cc
src/network_inspectors/reputation/reputation_inspect.cc
src/network_inspectors/reputation/reputation_module.h
src/network_inspectors/rna/rna_inspector.cc
src/network_inspectors/rna/test/rna_module_stubs.h
src/payload_injector/test/payload_injector_test.cc
src/policy_selectors/CMakeLists.txt [new file with mode: 0644]
src/policy_selectors/address_space_selector/CMakeLists.txt [new file with mode: 0644]
src/policy_selectors/address_space_selector/address_space_selection.cc [new file with mode: 0644]
src/policy_selectors/address_space_selector/address_space_selection.h [new file with mode: 0644]
src/policy_selectors/address_space_selector/address_space_selector.cc [new file with mode: 0644]
src/policy_selectors/address_space_selector/address_space_selector_module.cc [new file with mode: 0644]
src/policy_selectors/address_space_selector/address_space_selector_module.h [new file with mode: 0644]
src/policy_selectors/address_space_selector/dev_notes.txt [new file with mode: 0644]
src/policy_selectors/dev_notes.txt [new file with mode: 0644]
src/policy_selectors/int_set_to_string.h [new file with mode: 0644]
src/policy_selectors/parse_int_set.h [new file with mode: 0644]
src/policy_selectors/policy_selectors.cc [new file with mode: 0644]
src/policy_selectors/policy_selectors.h [new file with mode: 0644]
src/policy_selectors/tenant_selector/CMakeLists.txt [new file with mode: 0644]
src/policy_selectors/tenant_selector/dev_notes.txt [new file with mode: 0644]
src/policy_selectors/tenant_selector/tenant_selection.cc [new file with mode: 0644]
src/policy_selectors/tenant_selector/tenant_selection.h [new file with mode: 0644]
src/policy_selectors/tenant_selector/tenant_selector.cc [new file with mode: 0644]
src/policy_selectors/tenant_selector/tenant_selector_module.cc [new file with mode: 0644]
src/policy_selectors/tenant_selector/tenant_selector_module.h [new file with mode: 0644]
src/protocols/packet.h
src/search_engines/test/hyperscan_test.cc
src/search_engines/test/search_tool_test.cc
src/service_inspectors/netflow/netflow.cc
src/sfip/sf_ip.h
src/stream/tcp/tcp_reassembler.cc

index b8d26c71e1fb18e2f36adb9e1842091a76e7d41f..e795441ddec915a94a44b64e45f0071ea0fc69ff 100644 (file)
@@ -128,6 +128,7 @@ add_subdirectory(decompress)
 add_subdirectory(ips_options)
 add_subdirectory(loggers)
 add_subdirectory(network_inspectors)
+add_subdirectory(policy_selectors)
 add_subdirectory(search_engines)
 add_subdirectory(side_channel)
 add_subdirectory(connectors)
@@ -165,6 +166,7 @@ add_executable( snort
     $<TARGET_OBJECTS:memory>
     $<TARGET_OBJECTS:mime>
     $<TARGET_OBJECTS:network_inspectors>
+    $<TARGET_OBJECTS:policy_selectors>
     $<TARGET_OBJECTS:packet_io>
     $<TARGET_OBJECTS:parser>
     $<TARGET_OBJECTS:payload_injector>
@@ -195,6 +197,7 @@ add_executable( snort
     ${STATIC_CODEC_PLUGINS}
     ${STATIC_NETWORK_INSPECTOR_PLUGINS}
     ${STATIC_SERVICE_INSPECTOR_PLUGINS}
+    ${STATIC_POLICY_SELECTOR_PLUGINS}
     ${UNIT_TESTS_LIBRARIES}
 )
 
index 146a739723b0f5df0768ef6e1892b3ffe4a42464..be3c62188bcb540708f4dada3b346e50aa9d9cb1 100644 (file)
@@ -271,16 +271,12 @@ uint32_t OleFile :: find_bytes_to_copy(uint32_t byte_offset, uint32_t data_len,
 
     return bytes_to_copy;
 }
-        
+
 void OleFile :: get_file_data(char* file, uint8_t*& file_data, uint32_t& data_len)
 {
-    FileProperty* node;
-    uint16_t sector_size,mini_sector_size;
-    node = dir_list->get_file_node(file);
+    FileProperty* node = dir_list->get_file_node(file);
     data_len = 0;
 
-    sector_size = header->get_sector_size();
-    mini_sector_size = header->get_mini_sector_size();
     if (node)
     {
         int32_t starting_sector;
@@ -299,8 +295,8 @@ void OleFile :: get_file_data(char* file, uint8_t*& file_data, uint32_t& data_le
 
         if (is_fat == FAT_SECTOR)
         {
-            int32_t current_sector;
-            current_sector = starting_sector;
+            int32_t current_sector = starting_sector;
+            uint16_t sector_size = header->get_sector_size();
             while (current_sector > INVALID_SECTOR)
             {
                 byte_offset = get_fat_offset(current_sector);
@@ -309,7 +305,7 @@ void OleFile :: get_file_data(char* file, uint8_t*& file_data, uint32_t& data_le
 
                 bytes_to_copy = find_bytes_to_copy(byte_offset, data_len,
                                     stream_size, sector_size);
-                
+
                 memcpy(temp_data, (file_buf + byte_offset), bytes_to_copy);
                 temp_data += sector_size;
                 data_len += bytes_to_copy;
@@ -320,8 +316,8 @@ void OleFile :: get_file_data(char* file, uint8_t*& file_data, uint32_t& data_le
         }
         else
         {
-            int32_t mini_sector;
-            mini_sector = node->get_starting_sector();
+            int32_t mini_sector = node->get_starting_sector();
+            uint16_t mini_sector_size = header->get_mini_sector_size();
             while (mini_sector > INVALID_SECTOR)
             {
                 byte_offset = get_mini_fat_offset(mini_sector);
@@ -679,13 +675,12 @@ void OleFile :: find_and_extract_vba(uint8_t*& vba_buf, uint32_t& vba_buf_len)
 
     while (it != dir_list->oleentry.end())
     {
-        FileProperty* node;
-        uint8_t* data = nullptr;
-        uint32_t data_len;
-        node = it->second;
+        FileProperty* node = it->second;
         ++it;
         if (node->get_file_type() == STREAM)
         {
+            uint8_t* data = nullptr;
+            uint32_t data_len;
             get_file_data(node->get_name(), data, data_len);
             uint8_t* data1 = data;
             int32_t offset = get_file_offset(data, data_len);
index 3074594f0ffb83096c40cb410b59f08b1ad8db2c..b4a1dc5eb9124c0f241fb8cf4030b24785cfc1b3 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <condition_variable>
 #include <list>
-#include <mutex>
 #include <thread>
 
 namespace snort
index 93b5639774ffcfaa2492034f28045b88f0ad630c..d3103c60362b060f9c42de6b9cf0c40c69ff39da 100644 (file)
@@ -441,11 +441,12 @@ public:  // FIXIT-M privatize if possible
 
     unsigned inspection_policy_id;
     unsigned ips_policy_id;
-    unsigned network_policy_id;
     unsigned reload_id;
 
     uint32_t iplist_monitor_id;
 
+    uint32_t tenant;
+
     uint32_t default_session_timeout;
 
     int32_t client_intf;
index f51858faf88e35c6c094857c0180d72eb689be8b..53e6961de4b64a320dbed3112bfcf6af6b5d6e60 100644 (file)
@@ -323,6 +323,8 @@ static void init_roles(Packet* p, Flow* flow)
         flow->server_group = p->pkth->egress_group;
     }
 
+    flow->tenant = p->get_flow_geneve_vni();
+
     flow->flags.app_direction_swapped = false;
     if ( flow->ssn_state.direction == FROM_CLIENT )
         p->packet_flags |= PKT_FROM_CLIENT;
@@ -448,7 +450,6 @@ unsigned FlowControl::process(Flow* flow, Packet* p)
         const SnortConfig* sc = SnortConfig::get_conf();
         set_inspection_policy(sc, flow->inspection_policy_id);
         set_ips_policy(sc, flow->ips_policy_id);
-        set_network_policy(sc, flow->network_policy_id);
         p->filtering_state = flow->filtering_state;
     }
 
index dc9276aaa1c6f72cfabc640d13600f72d85871a4..2ad995ce89de1740ecac0752cf53f81979dc924a 100644 (file)
@@ -67,6 +67,7 @@ void PacketTracer::unpause() { }
 void Active::set_drop_reason(char const*) { }
 Packet::Packet(bool) { }
 Packet::~Packet() = default;
+uint32_t Packet::get_flow_geneve_vni() const { return 0; }
 Flow::Flow() { memset(this, 0, sizeof(*this)); }
 Flow::~Flow() = default;
 DetectionEngine::DetectionEngine() = default;
index d828b1596f628a23805b58a6f16a0136322010fb..5f3ae5ee05ef0978b0a3d50ac6edaed31b824ad3 100644 (file)
@@ -66,6 +66,7 @@ void PacketTracer::unpause() { }
 void Active::set_drop_reason(char const*) { }
 Packet::Packet(bool) { }
 Packet::~Packet() = default;
+uint32_t Packet::get_flow_geneve_vni() const { return 0; }
 FlowCache::FlowCache(const FlowCacheConfig& cfg) : config(cfg) { }
 FlowCache::~FlowCache() = default;
 Flow::Flow() = default;
index 2262e595d68d384f41ca9a7cb3a9525105d9043e..855c7272b41a2cc92183799e9192d226c1dbfe39 100644 (file)
@@ -104,13 +104,13 @@ void DataBus::subscribe(const char* key, DataHandler* h)
 {
     DB->_subscribe(key, h);
 }
-void DataBus::subscribe_global(const char* key, DataHandler* h, SnortConfig*)
+void DataBus::subscribe_network(const char* key, DataHandler* h)
 {
     DB->_subscribe(key, h);
 }
 
 void DataBus::unsubscribe(const char*, DataHandler*) {}
-void DataBus::unsubscribe_global(const char*, DataHandler*, SnortConfig*) {}
+void DataBus::unsubscribe_network(const char*, DataHandler*) {}
 
 void DataBus::publish(const char* key, DataEvent& e, Flow* f)
 {
@@ -144,7 +144,7 @@ static SnortConfig snort_conf;
 
 namespace snort
 {
-SnortConfig::SnortConfig(const SnortConfig* const) { }
+SnortConfig::SnortConfig(const SnortConfig* const, const char*) { }
 SnortConfig::~SnortConfig() = default;
 const SnortConfig* SnortConfig::get_conf() { return &snort_conf; }
 
index f65de45c670a4c26009745334c64aa7662459f5d..6499cc5225b71d0dcf624026670fc8700939c10e 100644 (file)
@@ -19,6 +19,7 @@ set (FRAMEWORK_INCLUDES
     mpse_batch.h
     packet_constraints.h
     parameter.h
+    policy_selector.h
     range.h
     so_rule.h
     value.h
index d0715f03222322bf4896a1923fefea2ad5106c81..3186b06bac301a89590d8ac0e2e5679a68b22b6f 100644 (file)
@@ -29,7 +29,7 @@
 
 // this is the current version of the base api
 // must be prefixed to subtype version
-#define BASE_API_VERSION 9
+#define BASE_API_VERSION 10
 
 // set options to API_OPTIONS to ensure compatibility
 #ifndef API_OPTIONS
@@ -49,6 +49,7 @@ enum PlugType
     PT_SO_RULE,
     PT_LOGGER,
     PT_CONNECTOR,
+    PT_POLICY_SELECTOR,
 #ifdef PIGLET
     PT_PIGLET,
 #endif
index 3e41b90332daf4099ef9898d7fb182cc7a0d07e4..585019b8890544ef37ecf63b78654839f6551ce4 100644 (file)
@@ -33,6 +33,8 @@ using namespace snort;
 
 static DataBus& get_data_bus()
 { return get_inspection_policy()->dbus; }
+static DataBus& get_network_data_bus()
+{ return get_network_policy()->dbus; }
 
 class BufferEvent : public DataEvent
 {
@@ -100,10 +102,9 @@ void DataBus::subscribe(const char* key, DataHandler* h)
 }
 
 // for subscribers that need to receive events regardless of active inspection policy
-void DataBus::subscribe_global(const char* key, DataHandler* h, SnortConfig* sc)
+void DataBus::subscribe_network(const char* key, DataHandler* h)
 {
-    assert(sc);
-    sc->global_dbus->_subscribe(key, h);
+    get_network_data_bus()._subscribe(key, h);
 }
 
 void DataBus::unsubscribe(const char* key, DataHandler* h)
@@ -111,19 +112,19 @@ void DataBus::unsubscribe(const char* key, DataHandler* h)
     get_data_bus()._unsubscribe(key, h);
 }
 
-void DataBus::unsubscribe_global(const char* key, DataHandler* h, SnortConfig* sc)
+void DataBus::unsubscribe_network(const char* key, DataHandler* h)
 {
-    assert(sc);
-    sc->global_dbus->_unsubscribe(key, h);
+    get_network_data_bus()._unsubscribe(key, h);
 }
 
 // notify subscribers of event
 void DataBus::publish(const char* key, DataEvent& e, Flow* f)
 {
+    NetworkPolicy* ni = get_network_policy();
+    ni->dbus._publish(key, e, f);
+
     InspectionPolicy* pi = get_inspection_policy();
     pi->dbus._publish(key, e, f);
-
-    SnortConfig::get_conf()->global_dbus->_publish(key, e, f);
 }
 
 void DataBus::publish(const char* key, const uint8_t* buf, unsigned len, Flow* f)
index 2593244056fa71ffbf7bc79ad6f7b643ca0a4286..1707fa69a42728a3a7bf94ce15f194875a893519 100644 (file)
@@ -38,7 +38,6 @@ namespace snort
 {
 class Flow;
 struct Packet;
-struct SnortConfig;
 
 class DataEvent
 {
@@ -101,11 +100,11 @@ public:
 
     // FIXIT-L ideally these would not be static or would take an inspection policy*
     static void subscribe(const char* key, DataHandler*);
-    static void subscribe_global(const char* key, DataHandler*, SnortConfig*);
+    static void subscribe_network(const char* key, DataHandler*);
 
     // FIXIT-L these should be called during cleanup
     static void unsubscribe(const char* key, DataHandler*);
-    static void unsubscribe_global(const char* key, DataHandler*, SnortConfig*);
+    static void unsubscribe_network(const char* key, DataHandler*);
 
     // runtime methods
     static void publish(const char* key, DataEvent&, Flow* = nullptr);
index 4c9f0b1143d8ba52f8c1e41177c8c30059ec4b44..636a37330dfd35643b37feee1beb91ae55481d86 100644 (file)
@@ -135,7 +135,7 @@ static const char* InspectorTypeNames[IT_MAX] =
     "network",
     "service",
     "control",
-    "probe"
+    "probe",
 };
 
 const char* InspectApi::get_type(InspectorType type)
diff --git a/src/framework/policy_selector.h b/src/framework/policy_selector.h
new file mode 100644 (file)
index 0000000..1be0b48
--- /dev/null
@@ -0,0 +1,94 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// policy_selector.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef POLICY_SELECTOR_H
+#define POLICY_SELECTOR_H
+
+// Policy selectors provide a method to select the network policy and default inspection
+// and IPS policies for a given packet
+
+#include <string>
+
+#include "framework/base_api.h"
+#include "framework/counts.h"
+#include "main/snort_types.h"
+
+struct _daq_pkt_hdr;
+
+namespace snort
+{
+#define POLICY_SELECTOR_API_VERSION ((BASE_API_VERSION << 16) | 0)
+
+struct Packet;
+class PolicySelector;
+struct PolicySelectorApi;
+struct SnortConfig;
+
+struct PolicySelectStats
+{
+    PegCount packets;
+    PegCount no_match;
+};
+
+struct PolicySelectUse
+{
+    std::string stringify() const
+    { return "file = " + name; }
+
+    std::string name;
+    unsigned network_index;
+    unsigned inspection_index;
+    unsigned ips_index;
+};
+
+typedef PolicySelector* (*SelectorNewFunc)(Module*);
+typedef void (*SelectorDeleteFunc)(PolicySelector*);
+
+struct PolicySelectorApi
+{
+    BaseApi base;
+    SelectorNewFunc ctor;
+    SelectorDeleteFunc dtor;
+};
+
+class SO_PUBLIC PolicySelector
+{
+public:
+    PolicySelector() = delete;
+    PolicySelector(const PolicySelector&) = delete;
+    virtual ~PolicySelector() = default;
+
+    static void free_policy_selector(PolicySelector* ps)
+    {
+        if (ps)
+            ps->get_api()->dtor(ps);
+    }
+    const PolicySelectorApi* get_api()
+    { return api; }
+    virtual bool select_default_policies(const _daq_pkt_hdr*, const SnortConfig*) = 0;
+    virtual void show() const = 0;
+
+protected:
+    explicit PolicySelector(const PolicySelectorApi* api) : api(api)
+    { }
+    const PolicySelectorApi* api;
+};
+}
+#endif
+
index fb97af2c9d36ebed7963a4f33f5efa5f360d728a..c3cda1973e392235077279d01d78603daadfc60f 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <CppUTest/CommandLineTestRunner.h>
 #include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
 
 using namespace snort;
 
@@ -35,27 +36,46 @@ using namespace snort;
 //--------------------------------------------------------------------------
 InspectionPolicy::InspectionPolicy(unsigned int) {}
 InspectionPolicy::~InspectionPolicy() = default;
+NetworkPolicy::NetworkPolicy(unsigned int, unsigned int) {}
+NetworkPolicy::~NetworkPolicy() = default;
 namespace snort
 {
-SnortConfig::SnortConfig(snort::SnortConfig const*)
-{ global_dbus = new DataBus(); }
-
-THREAD_LOCAL const SnortConfig* snort_conf = nullptr;
+SnortConfig::SnortConfig(snort::SnortConfig const*, const char*)
+{ }
 
 const SnortConfig* SnortConfig::get_conf()
-{ return snort_conf; }
+{
+    const SnortConfig* snort_conf =
+        (const SnortConfig*)mock().getData("snort_conf").getObjectPointer();
+    return snort_conf;
+}
 
 SnortConfig* SnortConfig::get_main_conf()
-{ return const_cast<SnortConfig*>(snort_conf); }
+{
+    SnortConfig* snort_conf =
+        (SnortConfig*)mock().getData("snort_conf").getObjectPointer();
+    return snort_conf;
+}
 
 SnortConfig::~SnortConfig()
-{ delete global_dbus; }
+{ }
 
-static  InspectionPolicy* my_inspection_policy = nullptr;
+NetworkPolicy* get_network_policy()
+{
+    NetworkPolicy* my_network_policy =
+        (NetworkPolicy*)mock().getData("my_network_policy").getObjectPointer();
+    return my_network_policy;
+}
 
 InspectionPolicy* get_inspection_policy()
-{ return my_inspection_policy; }
+{
+    InspectionPolicy* my_inspection_policy =
+        (InspectionPolicy*)mock().getData("my_inspection_policy").getObjectPointer();
+    return my_inspection_policy;
 }
+
+}
+
 //--------------------------------------------------------------------------
 class UTestEvent : public DataEvent
 {
@@ -98,24 +118,27 @@ void UTestHandler::handle(DataEvent& event, Flow*)
 
 TEST_GROUP(data_bus)
 {
-   void setup() override
-   {
-        snort_conf = new SnortConfig();
-        my_inspection_policy = new InspectionPolicy();
-   }
-
-   void teardown() override
-   {
-        delete my_inspection_policy;
-        delete snort_conf;
-   }
+    SnortConfig snort_conf;
+    InspectionPolicy my_inspection_policy;
+    NetworkPolicy my_network_policy;
+
+    void setup() override
+    {
+        mock().setDataObject("snort_conf", "SnortConfig", &snort_conf);
+        mock().setDataObject("my_network_policy", "NetworkPolicy", &my_network_policy);
+        mock().setDataObject("my_inspection_policy", "InspectionPolicy", &my_inspection_policy);
+    }
+
+    void teardown() override
+    {
+        mock().clear();
+    }
 };
 
-TEST(data_bus, subscribe_global)
+TEST(data_bus, subscribe_network)
 {
-    SnortConfig* sc = SnortConfig::get_main_conf();
     UTestHandler* h = new UTestHandler();
-    DataBus::subscribe_global(DB_UTEST_EVENT, h, sc);
+    DataBus::subscribe_network(DB_UTEST_EVENT, h);
 
     UTestEvent event(100);
     DataBus::publish(DB_UTEST_EVENT, event);
@@ -125,7 +148,7 @@ TEST(data_bus, subscribe_global)
     DataBus::publish(DB_UTEST_EVENT, event1);
     CHECK(200 == h->evt_msg);
 
-    DataBus::unsubscribe_global(DB_UTEST_EVENT, h, sc);
+    DataBus::unsubscribe_network(DB_UTEST_EVENT, h);
 
     UTestEvent event2(300);
     DataBus::publish(DB_UTEST_EVENT, event2);
index eeebeeb8d9f3ddbc4391a192b9b3e3df95e22a4e..2d13efcaa6258723108d476bd3e3472dd6f4ff15 100644 (file)
@@ -39,7 +39,7 @@ static SnortConfig my_config;
 THREAD_LOCAL SnortConfig* snort_conf = &my_config;
 
 // run_flags is used indirectly from HashFnc class by calling SnortConfig::static_hash()
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 { snort_conf->run_flags = 0;}
 
 SnortConfig::~SnortConfig() = default;
index 7e51ae6e3cbbc960f271136a57d00f35bca0510e..028cc367cc896f65dc2d9c0f251a6f8b0e733a4e 100644 (file)
@@ -39,7 +39,7 @@ static SnortConfig my_config;
 THREAD_LOCAL SnortConfig* snort_conf = &my_config;
 
 // run_flags is used indirectly from HashFnc class by calling SnortConfig::static_hash()
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 { snort_conf->run_flags = 0;}
 
 SnortConfig::~SnortConfig() = default;
index 50fe1e54c5abb71079aa2ed0ffaa08c03fd5b3cf..9cb3654e70833117b65d702be9451f94dfec6c7f 100644 (file)
@@ -64,7 +64,7 @@ static SnortConfig my_config;
 THREAD_LOCAL SnortConfig *snort_conf = &my_config;
 
 // run_flags is used indirectly from HashFnc class by calling SnortConfig::static_hash()
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 { snort_conf->run_flags = 0;}
 
 SnortConfig::~SnortConfig() = default;
index 507148d70d4a07a856305b665e2414ecdb9eb1f4..0e6b77c13b2131696dcda962a8c7907173439b69 100644 (file)
@@ -50,7 +50,7 @@ static ScratchAllocator* scratcher = nullptr;
 
 static unsigned s_parse_errors = 0;
 
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 {
     state = &s_state;
     num_slots = 1;
index 8f901883e28e0585247de95151b564b43adacdae..76e7ef53068952bf540ccc464678dcfd9c8db896 100644 (file)
@@ -56,7 +56,7 @@ THREAD_LOCAL SnortConfig* snort_conf = &s_conf;
 static std::vector<void *> s_state;
 static ScratchAllocator* scratcher = nullptr;
 
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 {
     state = &s_state;
     num_slots = 1;
index 5891e2149f74860e85e66d0092576dabc5b839a8..08b810c6594ce42afd576f908951a241d78d494b 100644 (file)
@@ -194,8 +194,6 @@ static bool process_packet(Packet* p)
 
     PacketTracer::activate(*p);
 
-    // FIXIT-M should not need to set policies here
-    set_default_policy(p->context->conf);
     p->user_inspection_policy_id = get_inspection_policy()->user_policy_id;
     p->user_ips_policy_id = get_ips_policy()->user_policy_id;
     p->user_network_policy_id = get_network_policy()->user_policy_id;
@@ -382,7 +380,7 @@ void Analyzer::process_daq_pkt_msg(DAQ_Msg_h msg, bool retry)
     Packet* p = switcher->get_context()->packet;
     p->context->wire_packet = p;
     p->context->packet_number = get_packet_number();
-    set_default_policy(p->context->conf);
+    select_default_policy(pkthdr, p->context->conf);
 
     DetectionEngine::reset();
     sfthreshold_reset();
@@ -459,7 +457,8 @@ bool Analyzer::inspect_rebuilt(Packet* p)
     return main_hook(p);
 }
 
-bool Analyzer::process_rebuilt_packet(Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt, uint32_t pktlen)
+bool Analyzer::process_rebuilt_packet(Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt,
+    uint32_t pktlen)
 {
     PacketManager::decode(p, pkthdr, pkt, pktlen, true);
 
index 9006261958fc2ef029d945a8cf36099213312b3e..8213f7e007a27f476db73e35b27fd1c1f7e8cd24 100644 (file)
 
 #include "policy.h"
 
+#include "daq_common.h"
+
 #include "actions/actions.h"
 #include "detection/detection_engine.h"
+#include "framework/policy_selector.h"
 #include "log/messages.h"
 #include "managers/inspector_manager.h"
 #include "parser/parse_conf.h"
@@ -41,20 +44,35 @@ using namespace snort;
 // traffic policy
 //-------------------------------------------------------------------------
 
-NetworkPolicy::NetworkPolicy(PolicyId id)
+NetworkPolicy::NetworkPolicy(PolicyId id, PolicyId default_inspection_id)
+    : policy_id(id), default_inspection_policy_id(default_inspection_id)
+{ init(nullptr, nullptr); }
+
+NetworkPolicy::NetworkPolicy(NetworkPolicy* other_network_policy, const char* exclude_name)
+{ init(other_network_policy, exclude_name); }
+
+NetworkPolicy::~NetworkPolicy()
+{ InspectorManager::delete_policy(this, cloned); }
+
+void NetworkPolicy::init(NetworkPolicy* other_network_policy, const char* exclude_name)
 {
-    policy_id = id;
-    user_policy_id = 0;
+    if (other_network_policy)
+    {
+        dbus.clone(other_network_policy->dbus, exclude_name);
+        policy_id = other_network_policy->policy_id;
+        default_inspection_policy_id = other_network_policy->default_inspection_policy_id;
+        user_policy_id = other_network_policy->user_policy_id;
 
-    // minimum possible (allows all but errors to pass by default)
-    min_ttl = 1;
-    new_ttl = 5;
+        min_ttl = other_network_policy->min_ttl;
+        new_ttl = other_network_policy->new_ttl;
 
-    checksum_eval = CHECKSUM_FLAG__ALL | CHECKSUM_FLAG__DEF;
-    checksum_drop = CHECKSUM_FLAG__DEF;
+        checksum_eval = other_network_policy->checksum_eval;
+        checksum_drop = other_network_policy->checksum_drop;
+        normal_mask = other_network_policy->normal_mask;
+    }
+    InspectorManager::new_policy(this, other_network_policy);
 }
 
-
 //-------------------------------------------------------------------------
 // inspection policy
 //-------------------------------------------------------------------------
@@ -143,20 +161,20 @@ IpsPolicy::~IpsPolicy()
 // policy map
 //-------------------------------------------------------------------------
 
-PolicyMap::PolicyMap(PolicyMap* other_map)
+PolicyMap::PolicyMap(PolicyMap* other_map, const char* exclude_name)
 {
     if ( other_map )
-        clone(other_map);
+        clone(other_map, exclude_name);
     else
     {
-        add_shell(new Shell(nullptr, true));
+        add_shell(new Shell(nullptr, true), true);
         empty_ips_policy = new IpsPolicy(ips_policy.size());
         ips_policy.push_back(empty_ips_policy);
     }
 
+    set_network_policy(network_policy[0]);
     set_inspection_policy(inspection_policy[0]);
     set_ips_policy(ips_policy[0]);
-    set_network_policy(network_policy[0]);
 }
 
 PolicyMap::~PolicyMap()
@@ -169,6 +187,12 @@ PolicyMap::~PolicyMap()
             default_policy->cloned = true;
             delete default_policy;
         }
+        if ( !network_policy.empty() )
+        {
+            NetworkPolicy* default_policy = network_policy[0];
+            default_policy->cloned = true;
+            delete default_policy;
+        }
     }
     else
     {
@@ -193,35 +217,49 @@ PolicyMap::~PolicyMap()
     shell_map.clear();
 }
 
-void PolicyMap::clone(PolicyMap *other_map)
+void PolicyMap::clone(PolicyMap *other_map, const char* exclude_name)
 {
     shells = other_map->shells;
     ips_policy = other_map->ips_policy;
-    network_policy = other_map->network_policy;
     empty_ips_policy = other_map->empty_ips_policy;
 
+    for ( unsigned i = 0; i < (other_map->network_policy.size()); i++)
+    {
+        if ( i == 0 )
+            network_policy.emplace_back(new NetworkPolicy(other_map->network_policy[i],
+                exclude_name));
+        else
+            network_policy.emplace_back(other_map->network_policy[i]);
+    }
+
     for ( unsigned i = 0; i < (other_map->inspection_policy.size()); i++)
     {
         if ( i == 0 )
-        {
             inspection_policy.emplace_back(new InspectionPolicy(other_map->inspection_policy[i]));
-        }
         else
             inspection_policy.emplace_back(other_map->inspection_policy[i]);
     }
 
     shell_map = other_map->shell_map;
-
-    // Fix references to inspection_policy[0]
+    // Fix references to network_policy[0] and inspection_policy[0]
     for ( auto p : other_map->shell_map )
     {
+        if ( p.second->network == other_map->network_policy[0] )
+            shell_map[p.first]->network = network_policy[0];
         if ( p.second->inspection == other_map->inspection_policy[0] )
             shell_map[p.first] = std::make_shared<PolicyTuple>(inspection_policy[0], p.second->ips,
                 p.second->network);
     }
 
-    user_inspection = other_map->user_inspection;
+    user_network = other_map->user_network;
+    // Fix references to network_policy[0]
+    for ( auto p : other_map->user_network )
+    {
+        if ( p.second == other_map->network_policy[0] )
+            user_network[p.first] = network_policy[0];
+    }
 
+    user_inspection = other_map->user_inspection;
     // Fix references to inspection_policy[0]
     for ( auto p : other_map->user_inspection )
     {
@@ -230,7 +268,6 @@ void PolicyMap::clone(PolicyMap *other_map)
     }
 
     user_ips = other_map->user_ips;
-    user_network = other_map->user_network;
 }
 
 InspectionPolicy* PolicyMap::add_inspection_shell(Shell* sh)
@@ -257,15 +294,20 @@ IpsPolicy* PolicyMap::add_ips_shell(Shell* sh)
     return p;
 }
 
-std::shared_ptr<PolicyTuple> PolicyMap::add_shell(Shell* sh)
+std::shared_ptr<PolicyTuple> PolicyMap::add_shell(Shell* sh, bool include_network)
 {
     shells.push_back(sh);
     inspection_policy.push_back(new InspectionPolicy(inspection_policy.size()));
+    InspectionPolicy* ip = inspection_policy.back();
+    NetworkPolicy* new_network_policy = nullptr;
+    if (include_network)
+    {
+        new_network_policy = new NetworkPolicy(network_policy.size(), ip->policy_id);
+        network_policy.push_back(new_network_policy);
+    }
     ips_policy.push_back(new IpsPolicy(ips_policy.size()));
-    network_policy.push_back(new NetworkPolicy(network_policy.size()));
-
-    return shell_map[sh] = std::make_shared<PolicyTuple>(inspection_policy.back(),
-        ips_policy.back(), network_policy.back());
+    return shell_map[sh] = std::make_shared<PolicyTuple>(ip,
+        ips_policy.back(), new_network_policy);
 }
 
 std::shared_ptr<PolicyTuple> PolicyMap::get_policies(Shell* sh)
@@ -303,18 +345,19 @@ void set_inspection_policy(InspectionPolicy* p)
 void set_ips_policy(IpsPolicy* p)
 { s_detection_policy = p; }
 
-NetworkPolicy* get_user_network_policy(const SnortConfig* sc, unsigned policy_id)
-{
-    return sc->policy_map->get_user_network(policy_id);
-}
-
 InspectionPolicy* get_user_inspection_policy(const SnortConfig* sc, unsigned policy_id)
 {
     return sc->policy_map->get_user_inspection(policy_id);
 }
 
+NetworkPolicy* get_default_network_policy(const SnortConfig* sc)
+{ return sc->policy_map->get_network_policy(0); }
+
 InspectionPolicy* get_default_inspection_policy(const SnortConfig* sc)
-{ return sc->policy_map->get_inspection_policy(0); }
+{
+    return
+        sc->policy_map->get_inspection_policy(get_network_policy()->default_inspection_policy_id);
+}
 
 IpsPolicy* get_ips_policy(const SnortConfig* sc, unsigned i)
 {
@@ -378,8 +421,15 @@ void set_default_policy(const SnortConfig* sc)
     set_ips_policy(sc->policy_map->get_ips_policy(0));
 }
 
-bool only_network_policy()
-{ return get_network_policy() && !get_ips_policy() && !get_inspection_policy(); }
+void select_default_policy(const _daq_pkt_hdr* pkthdr, const SnortConfig* sc)
+{
+    if (!sc->global_selector || !sc->global_selector->select_default_policies(pkthdr, sc))
+    {
+        set_network_policy(sc->policy_map->get_network_policy(0));
+        set_inspection_policy(sc->policy_map->get_inspection_policy(0));
+        set_ips_policy(sc->policy_map->get_ips_policy(0));
+    }
+}
 
 bool only_inspection_policy()
 { return get_inspection_policy() && !get_ips_policy() && !get_network_policy(); }
@@ -387,14 +437,3 @@ bool only_inspection_policy()
 bool only_ips_policy()
 { return get_ips_policy() && !get_inspection_policy() && !get_network_policy(); }
 
-bool default_inspection_policy()
-{
-    if ( !get_inspection_policy() )
-        return false;
-
-    if ( get_inspection_policy()->policy_id != 0 )
-        return false;
-
-    return true;
-}
-
index 38d57b16af368740865cf1503fba7f7da1635243..38f4b0d20fe31094744a7719e68067d4a296e011 100644 (file)
@@ -43,10 +43,11 @@ typedef unsigned char uuid_t[16];
 namespace snort
 {
 class GHash;
-struct SnortConfig;
 class IpsAction;
+struct SnortConfig;
 }
 
+struct _daq_pkt_hdr;
 struct PortTable;
 struct vartable_t;
 struct sfip_var_t;
@@ -85,10 +86,13 @@ enum DecodeEventFlag
 
 // Snort ac-split creates the nap (network analysis policy)
 // Snort++ breaks the nap into network and inspection
+
 struct NetworkPolicy
 {
 public:
-    NetworkPolicy(PolicyId = 0);
+    NetworkPolicy(PolicyId = 0, PolicyId default_inspection_id = 0);
+    NetworkPolicy(NetworkPolicy*, const char*);
+    ~NetworkPolicy();
 
     bool checksum_drops(uint16_t codec_cksum_err_flag)
     { return (checksum_drop & codec_cksum_err_flag) != 0; }
@@ -106,15 +110,24 @@ public:
     { return (checksum_eval & CHECKSUM_FLAG__ICMP) != 0; }
 
 public:
-    PolicyId policy_id;
+    struct TrafficPolicy* traffic_policy;
+    snort::DataBus dbus;
+
+    PolicyId policy_id = 0;
     uint32_t user_policy_id = 0;
+    PolicyId default_inspection_policy_id = 0;
 
-    uint8_t min_ttl;
-    uint8_t new_ttl;
+    // minimum possible (allows all but errors to pass by default)
+    uint8_t min_ttl = 1;
+    uint8_t new_ttl = 5;
 
-    uint32_t checksum_eval;
-    uint32_t checksum_drop;
-    uint32_t normal_mask;
+    uint32_t checksum_eval = CHECKSUM_FLAG__ALL | CHECKSUM_FLAG__DEF;
+    uint32_t checksum_drop = CHECKSUM_FLAG__DEF;
+    uint32_t normal_mask = 0;
+    bool cloned = false;
+
+private:
+    void init(NetworkPolicy*, const char*);
 };
 
 //-------------------------------------------------------------------------
@@ -211,14 +224,14 @@ struct PolicyTuple
 class PolicyMap
 {
 public:
-    PolicyMap(PolicyMap* old_map = nullptr);
+    PolicyMap(PolicyMap* old_map = nullptr, const char* exclude_name = nullptr);
     ~PolicyMap();
 
     InspectionPolicy* add_inspection_shell(Shell*);
     IpsPolicy* add_ips_shell(Shell*);
-    std::shared_ptr<PolicyTuple> add_shell(Shell*);
+    std::shared_ptr<PolicyTuple> add_shell(Shell*, bool include_network);
     std::shared_ptr<PolicyTuple> get_policies(Shell* sh);
-    void clone(PolicyMap *old_map);
+    void clone(PolicyMap *old_map, const char* exclude_name);
 
     Shell* get_shell(unsigned i = 0)
     { return i < shells.size() ? shells[i] : nullptr; }
@@ -317,7 +330,7 @@ SO_PUBLIC void set_network_policy(NetworkPolicy*);
 SO_PUBLIC void set_inspection_policy(InspectionPolicy*);
 SO_PUBLIC void set_ips_policy(IpsPolicy*);
 
-SO_PUBLIC NetworkPolicy* get_user_network_policy(const snort::SnortConfig*, unsigned policy_id);
+SO_PUBLIC NetworkPolicy* get_default_network_policy(const snort::SnortConfig*);
 SO_PUBLIC InspectionPolicy* get_user_inspection_policy(const snort::SnortConfig*, unsigned policy_id);
 SO_PUBLIC InspectionPolicy* get_default_inspection_policy(const snort::SnortConfig*);
 
@@ -332,11 +345,10 @@ void set_ips_policy(const snort::SnortConfig*, unsigned = 0);
 
 void set_policies(const snort::SnortConfig*, Shell*);
 void set_default_policy(const snort::SnortConfig*);
+void select_default_policy(const _daq_pkt_hdr*, const snort::SnortConfig*);
 
-bool only_network_policy();
 bool only_inspection_policy();
 bool only_ips_policy();
 
-bool default_inspection_policy();
 #endif
 
index ba2493982f1e3c9a540b574ee626a3b29cac14b8..2fdea0fbe89fc9ae70220f24ba50947d6ada4462 100644 (file)
@@ -52,6 +52,7 @@
 #include "managers/module_manager.h"
 #include "managers/mpse_manager.h"
 #include "managers/plugin_manager.h"
+#include "managers/policy_selector_manager.h"
 #include "managers/script_manager.h"
 #include "memory/memory_cap.h"
 #include "network_inspectors/network_inspectors.h"
@@ -60,6 +61,7 @@
 #include "packet_io/trough.h"
 #include "parser/cmd_line.h"
 #include "parser/parser.h"
+#include "policy_selectors/policy_selectors.h"
 #include "profiler/profiler.h"
 #include "search_engines/search_engines.h"
 #include "service_inspectors/service_inspectors.h"
@@ -118,6 +120,7 @@ void Snort::init(int argc, char** argv)
     load_piglets();
 #endif
     load_search_engines();
+    load_policy_selectors();
     load_stream_inspectors();
     load_network_inspectors();
     load_service_inspectors();
@@ -193,6 +196,9 @@ void Snort::init(int argc, char** argv)
     }
     HostAttributesManager::activate(sc);
 
+    if ( SnortConfig::log_verbose() )
+        PolicySelectorManager::print_config(sc);
+
     // Must be after CodecManager::instantiate()
     if ( !InspectorManager::configure(sc) )
         ParseError("can't initialize inspectors");
@@ -481,7 +487,10 @@ SnortConfig* Snort::get_reload_config(const char* fname, const char* plugin_path
     }
 
     if ( SnortConfig::log_verbose() )
+    {
+        PolicySelectorManager::print_config(sc);
         InspectorManager::print_config(sc);
+    }
 
     // FIXIT-L is this still needed?
     /* Transfer any user defined rule type outputs to the new rule list */
@@ -536,8 +545,7 @@ SnortConfig* Snort::get_updated_policy(
     reloading = true;
     reset_parse_errors();
 
-    SnortConfig* sc = new SnortConfig(other_conf);
-    sc->global_dbus->clone(*other_conf->global_dbus, iname);
+    SnortConfig* sc = new SnortConfig(other_conf, iname);
 
     if ( fname )
     {
@@ -600,8 +608,7 @@ SnortConfig* Snort::get_updated_module(SnortConfig* other_conf, const char* name
 {
     reloading = true;
 
-    SnortConfig* sc = new SnortConfig(other_conf);
-    sc->global_dbus->clone(*other_conf->global_dbus, name);
+    SnortConfig* sc = new SnortConfig(other_conf, name);
 
     if ( name )
     {
index 63dc1a2cf6d3a41c55b5ef5bbd760aa449939dde..aab108c3ac562565728062c02291678ba1475a42 100644 (file)
@@ -40,6 +40,7 @@
 #include "filters/sfrf.h"
 #include "filters/sfthreshold.h"
 #include "flow/ha_module.h"
+#include "framework/policy_selector.h"
 #include "hash/xhash.h"
 #include "helpers/process.h"
 #include "latency/latency_config.h"
@@ -151,7 +152,8 @@ static void init_policies(SnortConfig* sc)
     }
 }
 
-void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* protocol_reference)
+void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* protocol_reference,
+    const char* exclude_name)
 {
     homenet.clear();
     obfuscation_net.clear();
@@ -177,7 +179,6 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p
         memory = new MemoryConfig();
         policy_map = new PolicyMap;
         thread_config = new ThreadConfig();
-        global_dbus = new DataBus();
 
         proto_ref = new ProtocolReference(protocol_reference);
         so_rules = new SoRules;
@@ -186,7 +187,7 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p
     else
     {
         clone(other_conf);
-        policy_map = new PolicyMap(other_conf->policy_map);
+        policy_map = new PolicyMap(other_conf->policy_map, exclude_name);
     }
 }
 
@@ -198,22 +199,21 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p
  * but the goal is to minimize config checks at run time when running in
  * IDS mode so we keep things simple and enforce that the only difference
  * among run_modes is how we handle packets via the log_func. */
-SnortConfig::SnortConfig(const SnortConfig* const other_conf)
+SnortConfig::SnortConfig(const SnortConfig* const other_conf, const char* exclude_name)
 {
-    init(other_conf, nullptr);
+    init(other_conf, nullptr, exclude_name);
 }
 
 //  Copy the ProtocolReference data into the new SnortConfig.
 SnortConfig::SnortConfig(ProtocolReference* protocol_reference)
 {
-    init(nullptr, protocol_reference);
+    init(nullptr, protocol_reference, nullptr);
 }
 
 SnortConfig::~SnortConfig()
 {
     if ( cloned )
     {
-        delete global_dbus;
         policy_map->set_cloned(true);
         delete policy_map;
         return;
@@ -264,7 +264,6 @@ SnortConfig::~SnortConfig()
     delete trace_config;
     delete overlay_trace_config;
     delete ha_config;
-    delete global_dbus;
 
     delete profiler;
     delete latency;
@@ -276,6 +275,8 @@ SnortConfig::~SnortConfig()
     if ( plugins )
         delete plugins;
     delete payload_injector_config;
+    InspectorManager::free_flow_tracking(flow_tracking);
+    PolicySelector::free_policy_selector(global_selector);
     clear_reload_resource_tuner_list();
 
     trim_heap();
@@ -332,7 +333,6 @@ void SnortConfig::post_setup()
 void SnortConfig::clone(const SnortConfig* const conf)
 {
     *this = *conf;
-    global_dbus = new DataBus();
     if (conf->homenet.get_family() != 0)
         memcpy(&homenet, &conf->homenet, sizeof(homenet));
 
index 8f7d85681c6a39f09e38cd9a24db83eb4315b72d..8e0bc59d72c043bf823d1ca68288f5816324307a 100644 (file)
@@ -149,6 +149,7 @@ struct IpsActionsConfig;
 struct LatencyConfig;
 struct MemoryConfig;
 struct PayloadInjectorConfig;
+struct PHInstance;
 struct Plugins;
 struct PORT_RULE_MAP;
 struct RateFilterConfig;
@@ -162,6 +163,7 @@ struct ThresholdConfig;
 namespace snort
 {
 class GHash;
+class PolicySelector;
 class ProtocolReference;
 class ThreadConfig;
 class XHash;
@@ -193,10 +195,10 @@ protected:
 struct SnortConfig
 {
 private:
-    void init(const SnortConfig* const, ProtocolReference*);
+    void init(const SnortConfig* const, ProtocolReference*, const char* exclude_name);
 
 public:
-    SnortConfig(const SnortConfig* const other_conf = nullptr);
+    SnortConfig(const SnortConfig* const other_conf = nullptr, const char* exclude_name = nullptr);
     SnortConfig(ProtocolReference* protocol_reference);
     ~SnortConfig();
 
@@ -392,7 +394,9 @@ public:
     PolicyMap* policy_map = nullptr;
     std::string tweaks;
 
-    DataBus* global_dbus = nullptr;
+    PolicySelector* global_selector = nullptr;
+    PHInstance* flow_tracking = nullptr;
+    PHInstance* removed_flow_tracking = nullptr;
 
     uint16_t tunnel_mask = 0;
 
@@ -716,7 +720,7 @@ public:
     { return logging_flags & LOGGING_FLAG__SYSLOG; }
 
     static void set_log_quiet(bool enabled)
-    { 
+    {
         if (enabled)
             logging_flags |= LOGGING_FLAG__QUIET;
         else
index 9e52ab3b59b67435ce52634d523bc709920d29a2..91664bc142e9139577f96c8a1b01e107fbacea33 100644 (file)
@@ -266,7 +266,7 @@ TEST_CASE("Set and check max packet threads", "[ThreadConfig]")
     ThreadConfig::set_instance_max(new_max);
     CHECK(ThreadConfig::get_instance_max() == new_max);
     ThreadConfig::set_instance_max(0);
-    CHECK(ThreadConfig::get_instance_max() == hwloc_bitmap_weight(process_cpuset));
+    CHECK(ThreadConfig::get_instance_max() == (unsigned)hwloc_bitmap_weight(process_cpuset));
 }
 
 TEST_CASE("Set and implement thread affinity", "[ThreadConfig]")
index c5b024b824814a080f6d31fe47d90a858bcb844c..3d502019e1dfdd74558c57ba826a73ba06f5c27f 100644 (file)
@@ -32,6 +32,8 @@ add_library( managers OBJECT
     mpse_manager.h
     plugin_manager.cc
     plugin_manager.h
+    policy_selector_manager.cc
+    policy_selector_manager.h
     script_manager.cc
     script_manager.h
     so_manager.cc
index c02a2586ef15520412f4f34f2fc2654e1a22cd53..613747367463810f2a51b7e59117d9f14368a7d9 100644 (file)
@@ -215,18 +215,70 @@ void PHVector::add_control(PHInstance* p)
     }
 }
 
-struct FrameworkPolicy
+struct InspectorList
 {
+    virtual ~InspectorList() = default;
+
     PHInstanceList ilist;   // List of inspector module instances
     PHInstanceList removed_ilist;   // List of removed inspector module instances
 
+    virtual void handle_new_reenabled(SnortConfig*, bool, bool) = 0;
+    virtual void vectorize(SnortConfig*) = 0;
+};
+
+struct TrafficPolicy : public InspectorList
+{
     PHVector passive;
     PHVector packet;
     PHVector first;
+    PHVector control;
+
+    void handle_new_reenabled(SnortConfig*, bool, bool) override
+    { }
+    void vectorize(SnortConfig*) override;
+};
+
+void TrafficPolicy::vectorize(SnortConfig*)
+{
+    passive.alloc(ilist.size());
+    packet.alloc(ilist.size());
+    first.alloc(ilist.size());
+    control.alloc(ilist.size());
+
+    for ( auto* p : ilist )
+    {
+        switch ( p->pp_class.api.type )
+        {
+        case IT_PASSIVE:
+            passive.add(p);
+            break;
+
+        case IT_PACKET:
+            packet.add(p);
+            break;
+
+        case IT_FIRST:
+            first.add(p);
+            break;
+
+        case IT_CONTROL:
+            control.add_control(p);
+            break;
+
+        default:
+            ParseError("Network policy (context usage) does not handle %s inspector type\n",
+                InspectApi::get_type(p->pp_class.api.type));
+            break;
+        }
+    }
+}
+
+struct FrameworkPolicy : public InspectorList
+{
+    PHVector passive;
+    PHVector packet;
     PHVector network;
-    PHVector session;
     PHVector service;
-    PHVector control;
     PHVector probe;
 
     Inspector* binder;
@@ -237,7 +289,8 @@ struct FrameworkPolicy
 
     bool default_binder;
 
-    void vectorize(SnortConfig*);
+    void handle_new_reenabled(SnortConfig*, bool, bool) override;
+    void vectorize(SnortConfig*) override;
     void add_inspector_to_cache(PHInstance*, SnortConfig*);
     void remove_inspector_from_cache(Inspector*);
 };
@@ -276,15 +329,38 @@ void FrameworkPolicy::remove_inspector_from_cache(Inspector* ins)
     }
 }
 
+static bool get_instance(InspectorList*, const char*,
+    std::vector<PHInstance*>::iterator&);
+
+void FrameworkPolicy::handle_new_reenabled(SnortConfig* sc, bool new_ins, bool reenabled_ins)
+{
+    std::vector<PHInstance*>::iterator old_binder;
+    if ( get_instance(this, bind_id, old_binder) )
+    {
+        if ( new_ins and default_binder )
+        {
+            if ( !((*old_binder)->is_reloaded()) )
+            {
+                (*old_binder)->set_reloaded(RELOAD_TYPE_REENABLED);
+                ilist.erase(old_binder);
+            }
+            default_binder = false;
+        }
+        else if ( reenabled_ins and !((*old_binder)->is_reloaded()) )
+        {
+            (*old_binder)->handler->configure(sc);
+        }
+    }
+}
+
+static void instantiate_default_binder(SnortConfig*, FrameworkPolicy*);
+
 void FrameworkPolicy::vectorize(SnortConfig* sc)
 {
     passive.alloc(ilist.size());
     packet.alloc(ilist.size());
-    first.alloc(ilist.size());
     network.alloc(ilist.size());
-    session.alloc(ilist.size());
     service.alloc(ilist.size());
-    control.alloc(ilist.size());
     probe.alloc(ilist.size());
 
     for ( auto* p : ilist )
@@ -302,17 +378,11 @@ void FrameworkPolicy::vectorize(SnortConfig* sc)
             packet.add(p);
             break;
 
-        case IT_FIRST:
-            first.add(p);
-            break;
-
         case IT_NETWORK:
             network.add(p);
             break;
 
         case IT_STREAM:
-            if ( !p->pp_class.api.ssn )
-                session.add(p);
             break;
 
         case IT_SERVICE:
@@ -323,10 +393,6 @@ void FrameworkPolicy::vectorize(SnortConfig* sc)
             wizard = p->handler;
             break;
 
-        case IT_CONTROL:
-            control.add_control(p);
-            break;
-
         case IT_PROBE:
         {
             // probes always run
@@ -335,10 +401,21 @@ void FrameworkPolicy::vectorize(SnortConfig* sc)
             break;
         }
 
-        case IT_MAX:
+        default:
+            ParseError("Inspection policy does not handle %s inspector type\n",
+                InspectApi::get_type(p->pp_class.api.type));
             break;
         }
     }
+
+    // create cache
+    inspector_cache_by_id.clear();
+    inspector_cache_by_service.clear();
+    for ( auto* p : ilist )
+        add_inspector_to_cache(p, sc);
+
+    if ( !binder and (sc->flow_tracking or wizard) )
+        instantiate_default_binder(sc, this);
 }
 
 //-------------------------------------------------------------------------
@@ -455,10 +532,10 @@ void InspectorManager::empty_trash()
 //-------------------------------------------------------------------------
 
 static bool get_instance(
-    FrameworkPolicy* fp, const char* keyword,
+    InspectorList* il, const char* keyword,
     std::vector<PHInstance*>::iterator& it)
 {
-    for ( it = fp->ilist.begin(); it != fp->ilist.end(); ++it )
+    for ( it = il->ilist.begin(); it != il->ilist.end(); ++it )
     {
         if ( (*it)->name == keyword )
             return true;
@@ -466,25 +543,25 @@ static bool get_instance(
     return false;
 }
 
-static PHInstance* get_instance(FrameworkPolicy* fp, const char* keyword)
+static PHInstance* get_instance(InspectorList* il, const char* keyword)
 {
     std::vector<PHInstance*>::iterator it;
-    return get_instance(fp, keyword, it) ? *it : nullptr;
+    return get_instance(il, keyword, it) ? *it : nullptr;
 }
 
 static PHInstance* get_new(
-    PHClass* ppc, FrameworkPolicy* fp, const char* keyword, Module* mod, SnortConfig* sc)
+    PHClass* ppc, InspectorList* il, const char* keyword, Module* mod, SnortConfig* sc)
 {
     PHInstance* p = nullptr;
     bool reloaded = false;
     std::vector<PHInstance*>::iterator old_it;
 
-    if ( get_instance(fp, keyword, old_it) )
+    if ( get_instance(il, keyword, old_it) )
     {
         if ( Snort::is_reloading() )
         {
             (*old_it)->set_reloaded(RELOAD_TYPE_REENABLED);
-            fp->ilist.erase(old_it);
+            il->ilist.erase(old_it);
             reloaded = true;
         }
         else
@@ -506,7 +583,7 @@ static PHInstance* get_new(
         else
             p->set_reloaded(RELOAD_TYPE_NEW);
     }
-    fp->ilist.emplace_back(p);
+    il->ilist.emplace_back(p);
     return p;
 }
 
@@ -526,6 +603,14 @@ void InspectorManager::new_policy(InspectionPolicy* pi, InspectionPolicy* other_
     pi->framework_policy->wizard = nullptr;
 }
 
+void InspectorManager::new_policy(NetworkPolicy* pi, NetworkPolicy* other_pi)
+{
+    pi->traffic_policy = new TrafficPolicy;
+
+    if ( other_pi )
+        pi->traffic_policy->ilist = other_pi->traffic_policy->ilist;
+}
+
 void InspectorManager::delete_policy(InspectionPolicy* pi, bool cloned)
 {
     for ( auto* p : pi->framework_policy->ilist )
@@ -544,10 +629,31 @@ void InspectorManager::delete_policy(InspectionPolicy* pi, bool cloned)
     pi->framework_policy = nullptr;
 }
 
+void InspectorManager::delete_policy(NetworkPolicy* pi, bool cloned)
+{
+    for ( auto* p : pi->traffic_policy->ilist )
+    {
+        if ( cloned and !(p->is_reloaded()) )
+            continue;
+
+        if ( p->handler->get_api()->type == IT_PASSIVE )
+            s_trash2.emplace_back(p->handler);
+        else
+            s_trash.emplace_back(p->handler);
+
+        delete p;
+    }
+    delete pi->traffic_policy;
+    pi->traffic_policy = nullptr;
+}
+
 void InspectorManager::update_policy(SnortConfig* sc)
 {
-    InspectionPolicy* pi = sc->policy_map->get_inspection_policy();
-    for ( auto* p : pi->framework_policy->ilist )
+    InspectionPolicy* ip = sc->policy_map->get_inspection_policy();
+    for ( auto* p : ip->framework_policy->ilist )
+        p->set_reloaded(RELOAD_TYPE_NONE);
+    NetworkPolicy* np = sc->policy_map->get_network_policy();
+    for ( auto* p : np->traffic_policy->ilist )
         p->set_reloaded(RELOAD_TYPE_NONE);
 }
 
@@ -563,6 +669,15 @@ Binder* InspectorManager::get_binder()
 
 void InspectorManager::clear_removed_inspectors(SnortConfig* sc)
 {
+    if (sc->removed_flow_tracking)
+    {
+        sc->removed_flow_tracking->handler->rem_global_ref();
+        sc->removed_flow_tracking = nullptr;
+    }
+    TrafficPolicy* tp = sc->policy_map->get_network_policy()->traffic_policy;
+    for ( auto* p : tp->removed_ilist )
+        p->handler->rem_global_ref();
+    tp->removed_ilist.clear();
     FrameworkPolicy* fp = sc->policy_map->get_inspection_policy()->framework_policy;
     for ( auto* p : fp->removed_ilist )
         p->handler->rem_global_ref();
@@ -571,9 +686,28 @@ void InspectorManager::clear_removed_inspectors(SnortConfig* sc)
 
 void InspectorManager::tear_down_removed_inspectors(const SnortConfig* old, SnortConfig* sc)
 {
+    if (old->flow_tracking && !sc->flow_tracking)
+    {
+        sc->removed_flow_tracking = old->flow_tracking;
+        sc->removed_flow_tracking->handler->add_global_ref();
+        sc->removed_flow_tracking->handler->tear_down(sc);
+    }
+
+    TrafficPolicy* tp = get_default_network_policy(sc)->traffic_policy;
+    TrafficPolicy* old_tp = get_default_network_policy(old)->traffic_policy;
+    for (auto it = old_tp->ilist.begin(); it != old_tp->ilist.end(); ++it)
+    {
+        PHInstance* instance = get_instance(tp, (*it)->name.c_str());
+        if (!instance)
+        {
+            tp->removed_ilist.emplace_back(*it);
+            (*it)->handler->add_global_ref();
+            (*it)->handler->tear_down(sc);
+        }
+    }
+
     FrameworkPolicy* fp = get_default_inspection_policy(sc)->framework_policy;
-    InspectionPolicy* old_p = get_default_inspection_policy(old);
-    FrameworkPolicy* old_fp = old_p->framework_policy;
+    FrameworkPolicy* old_fp = get_default_inspection_policy(old)->framework_policy;
     for (auto it = old_fp->ilist.begin(); it != old_fp->ilist.end(); ++it)
     {
         PHInstance* instance = get_instance(fp, (*it)->name.c_str());
@@ -590,25 +724,35 @@ void InspectorManager::tear_down_removed_inspectors(const SnortConfig* old, Snor
 Inspector* InspectorManager::get_inspector(const char* key, bool dflt_only, const SnortConfig* sc)
 {
     InspectionPolicy* pi;
+    NetworkPolicy* ni;
 
     if ( dflt_only )
     {
         if ( !sc )
             sc = SnortConfig::get_conf();
         pi = get_default_inspection_policy(sc);
+        ni = get_default_network_policy(sc);
     }
     else
+    {
         pi = get_inspection_policy();
+        ni = get_network_policy();
+    }
 
-    if ( !pi || !pi->framework_policy )
-        return nullptr;
-
-    PHInstance* p = get_instance(pi->framework_policy, key);
-
-    if ( !p )
-        return nullptr;
+    if ( pi && pi->framework_policy )
+    {
+        PHInstance* p = get_instance(pi->framework_policy, key);
+        if ( p )
+            return p->handler;
+    }
 
-    return p->handler;
+    if ( ni && ni->traffic_policy )
+    {
+        PHInstance* p = get_instance(ni->traffic_policy, key);
+        if ( p )
+            return p->handler;
+    }
+    return nullptr;
 }
 
 Inspector* InspectorManager::get_service_inspector_by_service(const char* key)
@@ -660,6 +804,16 @@ void InspectorManager::free_inspector(Inspector* p)
     p->get_api()->dtor(p);
 }
 
+void InspectorManager::free_flow_tracking(PHInstance* pi)
+{
+    if (pi)
+    {
+        Inspector* i = pi->handler;
+        delete pi;
+        free_inspector(i);
+    }
+}
+
 InspectSsnFunc InspectorManager::get_session(uint16_t proto)
 {
     for ( auto* p : s_handlers )
@@ -742,8 +896,17 @@ void InspectorManager::thread_init(const SnortConfig* sc)
 
     // pin->tinit() only called for default policy
     set_default_policy(sc);
-    InspectionPolicy* pi = get_inspection_policy();
+    if (sc->flow_tracking)
+    {
+        PHGlobal& phg = get_thread_local_plugin(sc->flow_tracking->pp_class.api);
+        if ( !phg.instance_initialized )
+        {
+            sc->flow_tracking->handler->tinit();
+            phg.instance_initialized = true;
+        }
+    }
 
+    InspectionPolicy* pi = get_inspection_policy();
     if ( pi && pi->framework_policy )
     {
         for ( auto* p : pi->framework_policy->ilist )
@@ -756,6 +919,21 @@ void InspectorManager::thread_init(const SnortConfig* sc)
             }
         }
     }
+
+    for ( unsigned i = 0; i < sc->policy_map->network_policy_count(); i++)
+    {
+        NetworkPolicy* npi = sc->policy_map->get_network_policy(i);
+        set_network_policy(npi);
+        for ( auto* p : npi->traffic_policy->ilist )
+        {
+            PHGlobal& phg = get_thread_local_plugin(p->pp_class.api);
+            if ( !phg.instance_initialized )
+            {
+                p->handler->tinit();
+                phg.instance_initialized = true;
+            }
+        }
+    }
 }
 
 void InspectorManager::thread_reinit(const SnortConfig* sc)
@@ -772,13 +950,24 @@ void InspectorManager::thread_reinit(const SnortConfig* sc)
         }
     }
 
-    // pin->tinit() only called for default policy
-    InspectionPolicy* pi = get_default_inspection_policy(sc);
+    set_default_policy(sc);
+    if (sc->flow_tracking)
+    {
+        PHGlobal& phg = get_thread_local_plugin(sc->flow_tracking->pp_class.api);
+        if ( !phg.instance_initialized )
+        {
+            if (phg.api.tinit)
+                sc->flow_tracking->handler->tinit();
+            phg.instance_initialized = true;
+        }
+    }
 
-    if ( pi && pi->framework_policy )
+    for ( unsigned i = 0; i < sc->policy_map->network_policy_count(); i++)
     {
-        // Call pin->tinit() for anything that hasn't yet
-        for ( auto* p : pi->framework_policy->ilist )
+        NetworkPolicy* npi = sc->policy_map->get_network_policy(i);
+        set_network_policy(npi);
+
+        for ( auto* p : npi->traffic_policy->ilist )
         {
             PHGlobal& phg = get_thread_local_plugin(p->pp_class.api);
             if ( !phg.instance_initialized )
@@ -787,11 +976,54 @@ void InspectorManager::thread_reinit(const SnortConfig* sc)
                 phg.instance_initialized = true;
             }
         }
+
+        // pin->tinit() only called for default policy
+        InspectionPolicy* pi = get_default_inspection_policy(sc);
+        if ( pi && pi->framework_policy )
+        {
+            // Call pin->tinit() for anything that hasn't yet
+            for ( auto* p : pi->framework_policy->ilist )
+            {
+                PHGlobal& phg = get_thread_local_plugin(p->pp_class.api);
+                if ( !phg.instance_initialized )
+                {
+                    p->handler->tinit();
+                    phg.instance_initialized = true;
+                }
+            }
+        }
     }
 }
 
 void InspectorManager::thread_stop_removed(const SnortConfig* sc)
 {
+    if (sc->removed_flow_tracking)
+    {
+        PHGlobal& phg = get_thread_local_plugin(sc->removed_flow_tracking->pp_class.api);
+        if ( phg.instance_initialized )
+        {
+            sc->removed_flow_tracking->handler->tterm();
+            phg.instance_initialized = false;
+        }
+    }
+
+    // pin->tinit() only called for default policy
+    NetworkPolicy* npi = get_default_network_policy(sc);
+
+    if ( npi && npi->traffic_policy )
+    {
+        // Call pin->tterm() for anything that has been initialized and removed
+        for ( auto* p : npi->traffic_policy->removed_ilist )
+        {
+            PHGlobal& phg = get_thread_local_plugin(p->pp_class.api);
+            if ( phg.instance_initialized )
+            {
+                p->handler->tterm();
+                phg.instance_initialized = false;
+            }
+        }
+    }
+
     // pin->tinit() only called for default policy
     InspectionPolicy* pi = get_default_inspection_policy(sc);
 
@@ -818,8 +1050,17 @@ void InspectorManager::thread_stop(const SnortConfig* sc)
 
     // pin->tterm() only called for default policy
     set_default_policy(sc);
-    InspectionPolicy* pi = get_inspection_policy();
+    if (sc->flow_tracking)
+    {
+        PHGlobal& phg = get_thread_local_plugin(sc->flow_tracking->pp_class.api);
+        if ( phg.instance_initialized )
+        {
+            sc->flow_tracking->handler->tterm();
+            phg.instance_initialized = false;
+        }
+    }
 
+    InspectionPolicy* pi = get_inspection_policy();
     if ( pi && pi->framework_policy )
     {
         for ( auto* p : pi->framework_policy->ilist )
@@ -832,6 +1073,21 @@ void InspectorManager::thread_stop(const SnortConfig* sc)
             }
         }
     }
+
+    for ( unsigned i = 0; i < sc->policy_map->network_policy_count(); i++)
+    {
+        NetworkPolicy* npi = sc->policy_map->get_network_policy(i);
+        set_network_policy(npi);
+        for ( auto* p : npi->traffic_policy->ilist )
+        {
+            PHGlobal& phg = get_thread_local_plugin(p->pp_class.api);
+            if ( phg.instance_initialized )
+            {
+                p->handler->tterm();
+                phg.instance_initialized = false;
+            }
+        }
+    }
 }
 
 void InspectorManager::thread_term()
@@ -860,23 +1116,48 @@ void InspectorManager::instantiate(
 {
     assert(mod);
 
-    FrameworkConfig* fc = sc->framework_config;
-    FrameworkPolicy* fp = get_inspection_policy()->framework_policy;
-
     // FIXIT-L should not need to lookup inspector etc
     // since given api and mod
+    FrameworkConfig* fc = sc->framework_config;
     const char* keyword = api->base.name;
     PHClass* ppc = get_class(keyword, fc);
 
     if ( !ppc )
         ParseError("unknown inspector: '%s'.", keyword);
-
     else
     {
-        if ( name )
-            keyword = name;
+        PHInstance* ppi;
+        if (Module::GLOBAL == mod->get_usage() && IT_STREAM == api->type)
+        {
+            assert(sc);
+            if (sc->flow_tracking)
+            {
+                ParseError("Only one flow tracking inspector may be instantiated\n");
+                return;
+            }
+            ppi = new PHInstance(*ppc, sc, mod);
+            if ( ppi->handler )
+                sc->flow_tracking = ppi;
+            else
+            {
+                delete ppi;
+                ppi = nullptr;
+            }
+        }
+        else
+        {
+            InspectorList* il;
+            if (Module::CONTEXT == mod->get_usage())
+                il = get_network_policy()->traffic_policy;
+            else
+                il = get_inspection_policy()->framework_policy;
+            assert(il);
 
-        PHInstance* ppi = get_new(ppc, fp, keyword, mod, sc);
+            if ( name )
+                keyword = name;
+
+            ppi = get_new(ppc, il, keyword, mod, sc);
+        }
 
         if ( ppi )
             ppi->set_name(keyword);
@@ -944,13 +1225,12 @@ static void instantiate_default_binder(SnortConfig* sc, FrameworkPolicy* fp)
     fp->default_binder = true;
 }
 
-static bool configure(SnortConfig* sc, FrameworkPolicy* fp, bool cloned)
+static bool configure(SnortConfig* sc, InspectorList* il, bool cloned, bool& new_ins,
+    bool& reenabled_ins)
 {
     bool ok = true;
-    bool new_ins = false;
-    bool reenabled_ins = false;
 
-    for ( auto* p : fp->ilist )
+    for ( auto* p : il->ilist )
     {
         ReloadType reload_type = p->get_reload_type();
 
@@ -967,37 +1247,10 @@ static bool configure(SnortConfig* sc, FrameworkPolicy* fp, bool cloned)
     }
 
     if ( new_ins or reenabled_ins )
-    {
-        std::vector<PHInstance*>::iterator old_binder;
-        if ( get_instance(fp, bind_id, old_binder) )
-        {
-            if ( new_ins and fp->default_binder )
-            {
-                if ( !((*old_binder)->is_reloaded()) )
-                {
-                    (*old_binder)->set_reloaded(RELOAD_TYPE_REENABLED);
-                    fp->ilist.erase(old_binder);
-                }
-                fp->default_binder = false;
-            }
-            else if ( reenabled_ins and !((*old_binder)->is_reloaded()) )
-            {
-                (*old_binder)->handler->configure(sc);
-            }
-        }
-    }
+        il->handle_new_reenabled(sc, new_ins, reenabled_ins);
 
-    sort(fp->ilist.begin(), fp->ilist.end(), PHInstance::comp);
-    fp->vectorize(sc);
-
-    // create cache
-    fp->inspector_cache_by_id.clear();
-    fp->inspector_cache_by_service.clear();
-    for ( auto* p : fp->ilist )
-        fp->add_inspector_to_cache(p, sc);
-
-    if ( !fp->binder and (fp->session.num or fp->wizard) )
-        instantiate_default_binder(sc, fp);
+    sort(il->ilist.begin(), il->ilist.end(), PHInstance::comp);
+    il->vectorize(sc);
 
     return ok;
 }
@@ -1031,6 +1284,23 @@ bool InspectorManager::configure(SnortConfig* sc, bool cloned)
 
     SearchTool::set_conf(sc);
 
+    bool new_ins = false;
+    bool reenabled_ins = false;
+    for ( unsigned idx = 0; idx < sc->policy_map->network_policy_count(); ++idx )
+    {
+        if ( cloned and idx )
+            break;
+
+        ::set_network_policy(sc, idx);
+        NetworkPolicy* p = sc->policy_map->get_network_policy(idx);
+        ok = ::configure(sc, p->traffic_policy, cloned, new_ins, reenabled_ins) && ok;
+    }
+    ::set_network_policy(sc);
+
+    if (sc->flow_tracking)
+        ok = sc->flow_tracking->handler->configure(sc) && ok;
+
+    ::set_inspection_policy(sc);
     for ( unsigned idx = 0; idx < sc->policy_map->inspection_policy_count(); ++idx )
     {
         if ( cloned and idx )
@@ -1039,7 +1309,7 @@ bool InspectorManager::configure(SnortConfig* sc, bool cloned)
         ::set_inspection_policy(sc, idx);
         InspectionPolicy* p = sc->policy_map->get_inspection_policy(idx);
         p->configure();
-        ok = ::configure(sc, p->framework_policy, cloned) && ok;
+        ok = ::configure(sc, p->framework_policy, cloned, new_ins, reenabled_ins) && ok;
     }
 
     ::set_inspection_policy(sc);
@@ -1051,55 +1321,86 @@ bool InspectorManager::configure(SnortConfig* sc, bool cloned)
 // remove any disabled controls while retaining order
 void InspectorManager::prepare_controls(SnortConfig* sc)
 {
-    InspectionPolicy* pi = get_default_inspection_policy(sc);
-    assert(pi);
-
-    FrameworkPolicy* fp = pi->framework_policy;
-    assert(fp);
+    for ( unsigned idx = 0; idx < sc->policy_map->network_policy_count(); ++idx )
+    {
+        TrafficPolicy* tp = sc->policy_map->get_network_policy(idx)->traffic_policy;
+        unsigned c = 0;
+        for ( unsigned i = 0; i < tp->control.num; ++i )
+        {
+            if ( !tp->control.vec[i]->handler->disable(sc) )
+                tp->control.vec[c++] = tp->control.vec[i];
+        }
+        tp->control.num = c;
+    }
+}
 
-    unsigned c = 0;
+std::string InspectorManager::generate_inspector_label(const PHInstance* p)
+{
+    std::string name(p->pp_class.api.base.name);
+    if ( p->name != name )
+        name += " (" + p->name + "):";
+    else
+        name += ":";
+    return name;
+}
 
-    for ( unsigned i = 0; i < fp->control.num; ++i )
+void InspectorManager::sort_inspector_list(const InspectorList* il,
+    std::map<const std::string, const PHInstance*>& sorted_ilist)
+{
+    for ( const auto* p : il->ilist )
     {
-        if ( !fp->control.vec[i]->handler->disable(sc) )
-            fp->control.vec[c++] = fp->control.vec[i];
+        std::string name = generate_inspector_label(p);
+        sorted_ilist.emplace(name, p);
     }
-    fp->control.num = c;
 }
 
 void InspectorManager::print_config(SnortConfig* sc)
 {
+    if (sc->flow_tracking)
+    {
+        LogLabel("Flow Tracking");
+        const std::string name = generate_inspector_label(sc->flow_tracking);
+        LogLabel(name.c_str());
+        sc->flow_tracking->handler->show(sc);
+    }
+
     const auto shell_number = sc->policy_map->shells_count();
 
     for ( unsigned shell_id = 0; shell_id < shell_number; shell_id++ )
     {
         const auto shell = sc->policy_map->get_shell(shell_id);
         const auto policies = sc->policy_map->get_policies(shell);
-        const auto inspection = policies->inspection;
 
-        if ( !(inspection and inspection->framework_policy) )
-            continue;
-
-        std::map<const std::string, const PHInstance*> sorted_ilist;
-        for ( const auto* p : inspection->framework_policy->ilist )
+        const auto network = policies->network;
+        if ( network and network->traffic_policy )
         {
-            std::string inspector_name(p->pp_class.api.base.name);
-            if ( p->name != inspector_name )
-                inspector_name += " (" + p->name + "):";
-            else
-                inspector_name += ":";
-            sorted_ilist.emplace(inspector_name, p);
+            const std::string label = "Network Policy : policy id " +
+                std::to_string(network->user_policy_id) + " : " +
+                shell->get_file();
+            LogLabel(label.c_str());
+            std::map<const std::string, const PHInstance*> sorted_ilist;
+            sort_inspector_list(network->traffic_policy, sorted_ilist);
+            for ( const auto& p : sorted_ilist )
+            {
+                LogLabel(p.first.c_str());
+                p.second->handler->show(sc);
+            }
         }
 
-        const std::string label = "Inspection Policy : policy id " +
-            std::to_string(inspection->user_policy_id) + " : " +
-            shell->get_file();
-        LogLabel(label.c_str());
-
-        for ( const auto& p : sorted_ilist )
+        const auto inspection = policies->inspection;
+        if ( inspection and inspection->framework_policy )
         {
-            LogLabel(p.first.c_str());
-            p.second->handler->show(sc);
+            const std::string label = "Inspection Policy : policy id " +
+                std::to_string(inspection->user_policy_id) + " : " +
+                shell->get_file();
+            LogLabel(label.c_str());
+            std::map<const std::string, const PHInstance*> sorted_ilist;
+            sort_inspector_list(inspection->framework_policy, sorted_ilist);
+            for ( const auto& p : sorted_ilist )
+            {
+                LogLabel(p.first.c_str());
+                p.second->handler->show(sc);
+            }
         }
     }
 }
@@ -1110,7 +1411,7 @@ void InspectorManager::print_config(SnortConfig* sc)
 
 template<bool T>
 static inline void execute(
-    Packet* p, PHInstance** prep, unsigned num)
+    Packet* p, PHInstance* const * prep, unsigned num)
 {
     Stopwatch<SnortClock> timer;
     for ( unsigned i = 0; i < num; ++i, ++prep )
@@ -1118,7 +1419,7 @@ static inline void execute(
         if ( p->packet_flags & PKT_PASS_RULE )
             break;
 
-        PHClass& ppc = (*prep)->pp_class;
+        const PHClass& ppc = (*prep)->pp_class;
 
         // FIXIT-P these checks can eventually be optimized
         // but they are required to ensure that session and app
@@ -1230,48 +1531,48 @@ void InspectorManager::internal_execute(Packet* p)
         timer.start();
     }
 
-    FrameworkPolicy* fp = get_inspection_policy()->framework_policy;
-    assert(fp);
+    const SnortConfig* sc = p->context->conf;
+    if ( !p->has_paf_payload() && sc->flow_tracking )
+        ::execute<T>(p, &sc->flow_tracking, 1);
 
-    if ( !p->has_paf_payload() )
-    {
-        // FIXIT-L there is at most one in session; stream_base should
-        // be elevated from inspector to framework component (it is just
-        // a flow control wrapper) and use eval() instead of process()
-        // for stream_*.
-        ::execute<T>(p, fp->session.vec, fp->session.num);
-        fp = get_inspection_policy()->framework_policy;
-    }
     // must check between each ::execute()
     if ( p->disable_inspect )
         return;
 
+    if (!p->flow)
+        DataBus::publish(PKT_WITHOUT_FLOW_EVENT, p);
+
+    FrameworkPolicy* fp = get_inspection_policy()->framework_policy;
+    assert(fp);
+
     if ( !p->is_cooked() )
         ::execute<T>(p, fp->packet.vec, fp->packet.num);
 
     if ( p->disable_inspect )
         return;
 
-    const SnortConfig* sc = p->context->conf;
-    FrameworkPolicy* fp_dft = get_default_inspection_policy(sc)->framework_policy;
+    TrafficPolicy* tp = get_network_policy()->traffic_policy;
+    assert(tp);
+
+    if ( !p->is_cooked() )
+        ::execute<T>(p, tp->packet.vec, tp->packet.num);
+
+    if ( p->disable_inspect )
+        return;
 
     if ( !p->flow )
     {
-        if ( fp_dft != fp )
-            ::execute<T>(p, fp_dft->first.vec, fp_dft->first.num);
-        ::execute<T>(p, fp->first.vec, fp->first.num);
+        ::execute<T>(p, tp->first.vec, tp->first.num);
 
         if ( p->disable_inspect )
             return;
 
-        if (fp_dft != fp)
-            ::execute<T>(p, fp_dft->network.vec, fp_dft->network.num);
         ::execute<T>(p, fp->network.vec, fp->network.num);
 
         if ( p->disable_inspect )
             return;
 
-        ::execute<T>(p, fp_dft->control.vec, fp_dft->control.num);
+        ::execute<T>(p, tp->control.vec, tp->control.num);
     }
     else
     {
@@ -1280,9 +1581,7 @@ void InspectorManager::internal_execute(Packet* p)
 
         if ( p->flow->reload_id != sc->reload_id )
         {
-            if ( fp_dft != fp )
-                ::execute<T>(p, fp_dft->first.vec, fp_dft->first.num);
-            ::execute<T>(p, fp->first.vec, fp->first.num);
+            ::execute<T>(p, tp->first.vec, tp->first.num);
 
             p->flow->reload_id = sc->reload_id;
             if ( p->disable_inspect )
@@ -1290,11 +1589,7 @@ void InspectorManager::internal_execute(Packet* p)
         }
 
         if ( !p->flow->service )
-        {
-            if (fp_dft != fp)
-                ::execute<T>(p, fp_dft->network.vec, fp_dft->network.num);
             ::execute<T>(p, fp->network.vec, fp->network.num);
-        }
 
         if ( p->disable_inspect )
             return;
@@ -1303,7 +1598,7 @@ void InspectorManager::internal_execute(Packet* p)
             full_inspection<T>(p);
 
         if ( !p->disable_inspect and !p->flow->is_inspection_disabled() )
-            ::execute<T>(p, fp_dft->control.vec, fp_dft->control.num);
+            ::execute<T>(p, tp->control.vec, tp->control.num);
     }
 
     if ( T )
index 75150c8afb2b0a6d185f8500ddc9f5da2985a23e..45b684a4947270c9b377fb8613789a535669336e 100644 (file)
 // Factory for Inspectors.
 // Also provides packet evaluation.
 
+#include <map>
+
 #include "framework/inspector.h"
 
 class Binder;
-struct FrameworkPolicy;
+struct InspectorList;
 struct InspectionPolicy;
+struct NetworkPolicy;
+struct PHInstance;
 
 namespace snort
 {
@@ -47,8 +51,12 @@ public:
     static std::vector<const InspectApi*> get_apis();
     static const char* get_inspector_type(const char* name);
 
+    static void new_policy(NetworkPolicy*, NetworkPolicy*);
+    static void delete_policy(NetworkPolicy*, bool cloned);
+
     static void new_policy(InspectionPolicy*, InspectionPolicy*);
     static void delete_policy(InspectionPolicy*, bool cloned);
+
     static void update_policy(SnortConfig* sc);
 
     static void new_config(SnortConfig*);
@@ -59,6 +67,7 @@ public:
 
     static bool delete_inspector(SnortConfig*, const char* iname);
     static void free_inspector(Inspector*);
+    static void free_flow_tracking(PHInstance*);
     static InspectSsnFunc get_session(uint16_t proto);
 
     SO_PUBLIC static Inspector* get_inspector(
@@ -74,6 +83,7 @@ public:
 
     static bool configure(SnortConfig*, bool cloned = false);
     static void prepare_controls(SnortConfig*);
+    static std::string generate_inspector_label(const PHInstance*);
     static void print_config(SnortConfig*);
 
     static void thread_init(const SnortConfig*);
@@ -83,8 +93,6 @@ public:
     static void thread_stop(const SnortConfig*);
     static void thread_term();
 
-    static void release_policy(FrameworkPolicy*);
-
     static void execute(Packet*);
     static void probe(Packet*);
 
@@ -101,6 +109,8 @@ private:
     static void bumble(Packet*);
     template<bool T> static void full_inspection(Packet*);
     template<bool T> static void internal_execute(Packet*);
+    static void sort_inspector_list(const InspectorList* il,
+        std::map<const std::string, const PHInstance*>& sorted_ilist);
 };
 }
 #endif
index f8cc2441942ec9b0b79fa2abea3e9b1b3182ee34..069d3dd4de16b8d9403a78f108b7bf171e1f7ba2 100644 (file)
@@ -612,7 +612,8 @@ static bool end(Module* m, const Parameter* p, const char* s, int idx)
 
 static bool interested(Module* m)
 {
-    if ( m->get_usage() == Module::GLOBAL && !default_inspection_policy() )
+    NetworkPolicy* np = get_network_policy();
+    if ( m->get_usage() == Module::GLOBAL && (!np || np->policy_id) )
         return false;
 
     if ( m->get_usage() != Module::INSPECT && only_inspection_policy() )
@@ -621,7 +622,7 @@ static bool interested(Module* m)
     if ( m->get_usage() != Module::DETECT && only_ips_policy() )
         return false;
 
-    if ( m->get_usage() != Module::CONTEXT && only_network_policy() )
+    if ( m->get_usage() == Module::CONTEXT && !np )
         return false;
 
     return true;
@@ -1011,10 +1012,10 @@ static const char* mod_bind(const Module* m)
 {
     if ( m->is_bindable() )
         return "multiton";
-    else if (
-        (m->get_usage() == Module::GLOBAL) or
-        (m->get_usage() == Module::CONTEXT) )
+    else if (m->get_usage() == Module::GLOBAL)
         return "global";
+    else if (m->get_usage() == Module::CONTEXT)
+        return "network";
 
     return "singleton";
 }
@@ -1046,7 +1047,7 @@ void ModuleManager::show_module(const char* name)
         cout << endl << "Type: "  << mod_type(mh->api) << endl;
         cout << endl << "Usage: "  << mod_use(m->get_usage()) << endl;
 
-        if ( mh->api and (mh->api->type == PT_INSPECTOR) )
+        if ( mh->api and mh->api->type == PT_INSPECTOR )
             cout << endl << "Instance Type: " << mod_bind(m) << endl;
 
         const Parameter* params = m->get_parameters();
@@ -1088,7 +1089,7 @@ void ModuleManager::reload_module(const char* name, SnortConfig* sc)
     // more modules support reload_module.
     const vector<string> supported_modules =
     {
-        "dns_si", "firewall", "identity", "qos", "reputation", "url_si"
+        "dns_si", "firewall", "identity", "qos", "reputation", "url_si", "rt_network"
     };
     auto it = find(supported_modules.begin(), supported_modules.end(), name);
 
@@ -1845,7 +1846,7 @@ void ModuleManager::show_modules_json()
         json.put("help", help);
         json.put("type", type);
         json.put("usage", usage);
-        if ( mh->api and (mh->api->type == PT_INSPECTOR) )
+        if ( mh->api and mh->api->type == PT_INSPECTOR )
             json.put("instance_type", mod_bind(mod));
 
         dump_configs_json(json, mod);
index 5cafa4c046268ff2d0e7cf6fbe70f93986dc62f0..14ae9f28de1f1a0be3669b9a363d9fb59c1e47d7 100644 (file)
@@ -32,6 +32,7 @@
 #include "framework/connector.h"
 #include "framework/logger.h"
 #include "framework/mpse.h"
+#include "framework/policy_selector.h"
 #include "helpers/directory.h"
 #include "helpers/markup.h"
 #include "log/messages.h"
@@ -50,6 +51,7 @@
 #include "ips_manager.h"
 #include "module_manager.h"
 #include "mpse_manager.h"
+#include "policy_selector_manager.h"
 #include "script_manager.h"
 #include "so_manager.h"
 
@@ -77,9 +79,9 @@ static Symbol symbols[PT_MAX] =
     { "search_engine", SEAPI_VERSION, sizeof(MpseApi) },
     { "so_rule", SOAPI_VERSION, sizeof(SoApi) },
     { "logger", LOGAPI_VERSION, sizeof(LogApi) },
-    { "connector", CONNECTOR_API_VERSION, sizeof(ConnectorApi) }
+    { "connector", CONNECTOR_API_VERSION, sizeof(ConnectorApi) },
+    { "policy_selector", POLICY_SELECTOR_API_VERSION, sizeof(PolicySelectorApi) },
 #ifdef PIGLET
-    ,
     { "piglet", PIGLET_API_VERSION, sizeof(Piglet::Api) }
 #endif
 };
@@ -95,7 +97,10 @@ static Symbol symbols[PT_MAX] =
     [PT_IPS_OPTION] = { stringify(PT_IPS_OPTION), IPSAPI_VERSION, sizeof(IpsApi) },
     [PT_SEARCH_ENGINE] = { stringify(PT_SEARCH_ENGINE), SEAPI_VERSION, sizeof(MpseApi) },
     [PT_SO_RULE] = { stringify(PT_SO_RULE), SOAPI_VERSION, sizeof(SoApi) },
-    [PT_LOGGER] = { stringify(PT_LOGGER), LOGAPI_VERSION, sizeof(LogApi) }
+    [PT_LOGGER] = { stringify(PT_LOGGER), LOGAPI_VERSION, sizeof(LogApi) },
+    [PT_CONNECTOR] = { stringify(PT_CONNECTOR), CONNECTOR_API_VERSION, sizeof(ConnectorApi) },
+    [PT_POLICY_SELECTOR] = { stringify(PT_POLICY_SELECTOR), POLICY_SELECTOR_API_VERSION,
+        sizeof(PolicySelectorApi) }
 };
 #endif
 
@@ -330,6 +335,10 @@ static void add_plugin(Plugin& p)
         ConnectorManager::add_plugin((const ConnectorApi*)p.api);
         break;
 
+    case PT_POLICY_SELECTOR:
+        PolicySelectorManager::add_plugin((const PolicySelectorApi*)p.api);
+        break;
+
 #ifdef PIGLET
     case PT_PIGLET:
         Piglet::Manager::add_plugin((const Piglet::Api*)p.api);
@@ -484,6 +493,7 @@ void PluginManager::dump_plugins()
     ActionManager::dump_plugins();
     EventManager::dump_plugins();
     ConnectorManager::dump_plugins();
+    PolicySelectorManager::dump_plugins();
 }
 
 void PluginManager::release_plugins()
@@ -495,6 +505,7 @@ void PluginManager::release_plugins()
     MpseManager::release_plugins();
     CodecManager::release_plugins();
     ConnectorManager::release_plugins();
+    PolicySelectorManager::release_plugins();
 
     unload_plugins();
 }
@@ -560,6 +571,10 @@ void PluginManager::instantiate(
         ConnectorManager::instantiate((const ConnectorApi*)api, mod, sc);
         break;
 
+    case PT_POLICY_SELECTOR:
+        PolicySelectorManager::instantiate((const PolicySelectorApi*)api, mod, sc);
+        break;
+
     case PT_SO_RULE:
         // do not instantiate here; done later
         //IpsManager::instantiate((SoApi*)api, mod, sc);
diff --git a/src/managers/policy_selector_manager.cc b/src/managers/policy_selector_manager.cc
new file mode 100644 (file)
index 0000000..45085e3
--- /dev/null
@@ -0,0 +1,85 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// policy_selector_manager.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "policy_selector_manager.h"
+
+#include <cassert>
+#include <unordered_map>
+
+#include "framework/policy_selector.h"
+#include "framework/module.h"
+#include "main/snort_config.h"
+#include "log/messages.h"
+#include "utils/util.h"
+
+using namespace snort;
+
+static std::unordered_map<std::string, const PolicySelectorApi*> s_selectors;
+
+//-------------------------------------------------------------------------
+
+void PolicySelectorManager::add_plugin(const PolicySelectorApi* api)
+{
+    assert(s_selectors.find(api->base.name) == s_selectors.end());
+
+    s_selectors[api->base.name] = api;
+}
+
+void PolicySelectorManager::dump_plugins()
+{
+    Dumper d("Selectors");
+
+    for (auto& sc : s_selectors)
+        d.dump(sc.second->base.name, sc.second->base.version);
+}
+
+void PolicySelectorManager::release_plugins()
+{
+    s_selectors.clear();
+}
+
+void PolicySelectorManager::instantiate(const PolicySelectorApi* api, Module* mod, SnortConfig* sc)
+{
+    assert(sc);
+    if (sc->global_selector)
+    {
+        ParseError("Only one selector may be instantiated\n");
+        return;
+    }
+    assert(api);
+    sc->global_selector = api->ctor(mod);
+}
+
+void PolicySelectorManager::print_config(const SnortConfig* sc)
+{
+    assert(sc);
+    if (sc->global_selector)
+    {
+        LogLabel("Policy Selector");
+        std::string name = sc->global_selector->get_api()->base.name;
+        name += ":";
+        LogLabel(name.c_str());
+        sc->global_selector->show();
+    }
+}
+
diff --git a/src/managers/policy_selector_manager.h b/src/managers/policy_selector_manager.h
new file mode 100644 (file)
index 0000000..27bc5fd
--- /dev/null
@@ -0,0 +1,48 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// policy_selector_manager.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef POLICY_SELECTOR_MANAGER_H
+#define POLICY_SELECTOR_MANAGER_H
+
+// Policy selectors are used in a multi-tenant configuration to select all policies
+// based on layer 1 criteria. This is the manager for a given policy selector.
+// Only one selector is permitted in the configuration and it must be at the top level.
+
+namespace snort
+{
+struct PolicySelectorApi;
+class Module;
+struct SnortConfig;
+}
+
+//-------------------------------------------------------------------------
+
+class PolicySelectorManager
+{
+public:
+    static void add_plugin(const snort::PolicySelectorApi* api);
+    static void dump_plugins();
+    static void release_plugins();
+
+    static void instantiate(const snort::PolicySelectorApi*, snort::Module*, snort::SnortConfig*);
+    static void print_config(const snort::SnortConfig*);
+};
+
+#endif
+
index 78294cabaa07cc6f89b3a4e4c22f1d91d7a610a3..28bcfa6d3ad83c13b92b4ccfcf9e2c1eb6dec6e9 100644 (file)
@@ -120,24 +120,23 @@ bool AppIdInspector::configure(SnortConfig* sc)
 
     ctxt->init_appid(sc, *this);
 
-    DataBus::subscribe_global(SIP_EVENT_TYPE_SIP_DIALOG_KEY, new SipEventHandler(*this), sc);
+    DataBus::subscribe_network(SIP_EVENT_TYPE_SIP_DIALOG_KEY, new SipEventHandler(*this));
 
-    DataBus::subscribe_global(HTTP_REQUEST_HEADER_EVENT_KEY, new HttpEventHandler(
-        HttpEventHandler::REQUEST_EVENT, *this), sc);
+    DataBus::subscribe_network(HTTP_REQUEST_HEADER_EVENT_KEY, new HttpEventHandler(
+        HttpEventHandler::REQUEST_EVENT, *this));
 
-    DataBus::subscribe_global(HTTP_RESPONSE_HEADER_EVENT_KEY, new HttpEventHandler(
-        HttpEventHandler::RESPONSE_EVENT, *this), sc);
+    DataBus::subscribe_network(HTTP_RESPONSE_HEADER_EVENT_KEY, new HttpEventHandler(
+        HttpEventHandler::RESPONSE_EVENT, *this));
 
-    DataBus::subscribe_global(HTTP2_REQUEST_BODY_EVENT_KEY, new AppIdHttp2ReqBodyEventHandler(),
-        sc);
+    DataBus::subscribe_network(HTTP2_REQUEST_BODY_EVENT_KEY, new AppIdHttp2ReqBodyEventHandler());
 
-    DataBus::subscribe_global(DATA_DECRYPT_EVENT, new DataDecryptEventHandler(), sc);
+    DataBus::subscribe_network(DATA_DECRYPT_EVENT, new DataDecryptEventHandler());
 
-    DataBus::subscribe_global(DCERPC_EXP_SESSION_EVENT_KEY, new DceExpSsnEventHandler(), sc);
+    DataBus::subscribe_network(DCERPC_EXP_SESSION_EVENT_KEY, new DceExpSsnEventHandler());
 
-    DataBus::subscribe_global(OPPORTUNISTIC_TLS_EVENT, new AppIdOpportunisticTlsEventHandler(), sc);
+    DataBus::subscribe_network(OPPORTUNISTIC_TLS_EVENT, new AppIdOpportunisticTlsEventHandler());
 
-    DataBus::subscribe_global(EFP_PROCESS_EVENT, new AppIdEfpProcessEventHandler(), sc);
+    DataBus::subscribe_network(EFP_PROCESS_EVENT, new AppIdEfpProcessEventHandler());
 
     return true;
 }
index 06611dd0d4539f16a4504e3102a873a2d517a5ee..5f51665e4fd0ddce116c8908fda6ae8d929afdc0 100644 (file)
@@ -44,6 +44,7 @@ THREAD_LOCAL BindStats bstats;
 
 static const PegInfo bind_pegs[] =
 {
+    { CountType::SUM, "raw_packets", "raw packets evaluated" },
     { CountType::SUM, "new_flows", "new flows evaluated" },
     { CountType::SUM, "service_changes", "flow service changes evaluated" },
     { CountType::SUM, "assistant_inspectors", "flow assistant inspector requests handled" },
@@ -113,6 +114,9 @@ static const Parameter binder_when_params[] =
     { "addr_spaces", Parameter::PT_STRING, nullptr, nullptr,
       "list of address space IDs" },
 
+    { "tenants", Parameter::PT_STRING, nullptr, nullptr,
+      "list of tenants" },
+
     { "role", Parameter::PT_ENUM, "client | server | any", "any",
       "use the given configuration on one or any end of a session" },
 
@@ -140,6 +144,9 @@ static const Parameter binder_use_params[] =
     { "file", Parameter::PT_STRING, nullptr, nullptr,
       "use configuration in given file" },
 
+    { "network_policy", Parameter::PT_STRING, nullptr, nullptr,
+      "use network policy from given file" },
+
     { "inspection_policy", Parameter::PT_STRING, nullptr, nullptr,
       "use inspection policy from given file" },
 
@@ -170,22 +177,22 @@ static const Parameter s_params[] =
 };
 
 template<typename T>
-static bool parse_int_set(const Value& v, unordered_set<T>& set)
+static bool parse_int_set(const snort::Value& v, std::unordered_set<T>& set)
 {
-    assert(v.get_type() == Value::VT_STR);
+    assert(v.get_type() == snort::Value::VT_STR);
 
     set.clear();
 
-    string pl = v.get_string();
+    std::string pl = v.get_string();
 
-    stringstream ss(pl);
-    ss >> setbase(0);
+    std::stringstream ss(pl);
+    ss >> std::setbase(0);
 
     uint64_t n;
 
     while ( ss >> n )
     {
-        if ( n > numeric_limits<T>::max() )
+        if ( n > static_cast<uint64_t>(std::numeric_limits<T>::max()) )
             return false;
 
         set.insert(n);
@@ -344,6 +351,12 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
             return false;
         binding.when.add_criteria(BindWhen::Criteria::BWC_ADDR_SPACES);
     }
+    else if ( v.is("tenants") )
+    {
+        if (!parse_int_set<uint32_t>(v, binding.when.tenants))
+            return false;
+        binding.when.add_criteria(BindWhen::Criteria::BWC_TENANTS);
+    }
     else if ( v.is("role") )
         binding.when.role = (BindWhen::Role)v.get_uint8();
 
@@ -418,7 +431,7 @@ bool BinderModule::end(const char* fqn, int idx, SnortConfig* sc)
             if ( policy_type == FILE_KEY )
             {
                 Shell* sh = new Shell(policy_filename.c_str());
-                auto policies = sc->policy_map->add_shell(sh);
+                auto policies = sc->policy_map->add_shell(sh, false);
                 binding.use.inspection_index = policies->inspection->policy_id;
                 binding.use.ips_index = policies->ips->policy_id;
             }
index 24642a76cd11187b80bba1d93265bed0217d7fa7..4262262295f9fce9ad038dc2db87d3d69a8a2a07 100644 (file)
@@ -16,7 +16,7 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 
-// bind_module.cc author Russ Combs <rucombs@cisco.com>
+// bind_module.h author Russ Combs <rucombs@cisco.com>
 
 #ifndef BIND_MODULE_H
 #define BIND_MODULE_H
@@ -31,6 +31,7 @@
 
 struct BindStats
 {
+    PegCount raw_packets;
     PegCount new_flows;
     PegCount service_changes;
     PegCount assistant_inspectors;
index c66569c122134620f58327c35fd5f04fb402df9b..e3ba2d87398656e61a915dc317339d162ef698d3 100644 (file)
@@ -25,7 +25,9 @@
 #include "flow/flow.h"
 #include "log/messages.h"
 #include "managers/inspector_manager.h"
+#include "packet_io/active.h"
 #include "profiler/profiler.h"
+#include "protocols/packet.h"
 #include "pub_sub/assistant_gadget_event.h"
 #include "stream/stream.h"
 #include "stream/stream_splitter.h"
@@ -265,6 +267,12 @@ static std::string to_string(const BindWhen& bw)
         when += " addr_spaces = " + addr_spaces + ",";
     }
 
+    if (bw.has_criteria(BindWhen::Criteria::BWC_TENANTS))
+    {
+        auto tenants = to_string<uint32_t>(bw.tenants);
+        when += " tenants = " + tenants + ",";
+    }
+
     if (when.length() > 1)
         when.pop_back();
 
@@ -316,6 +324,7 @@ struct Stuff
 
     bool update(const Binding&);
 
+    void apply_action(Packet*);
     void apply_action(Flow&);
     void apply_session(Flow&);
     void apply_service(Flow&);
@@ -364,6 +373,30 @@ bool Stuff::update(const Binding& pb)
     return false;
 }
 
+void Stuff::apply_action(Packet* p)
+{
+    switch (action)
+    {
+        case BindUse::BA_RESET:
+            // disable all preproc analysis and detection for this packet
+            DetectionEngine::disable_all(p);
+            p->active->reset_session(p, true);
+            break;
+        case BindUse::BA_BLOCK:
+            // disable all preproc analysis and detection for this packet
+            DetectionEngine::disable_all(p);
+            p->active->block_session(p, true);
+            break;
+        case BindUse::BA_ALLOW:
+            p->active->trust_session(p, true);
+            break;
+        case BindUse::BA_INSPECT:
+            break;
+        default:
+            break;
+    }
+}
+
 void Stuff::apply_action(Flow& flow)
 {
     switch (action)
@@ -448,13 +481,16 @@ public:
 
     void eval(Packet*) override { }
 
+    void handle_packet(const Packet*);
     void handle_flow_setup(Flow&, bool standby = false);
     void handle_flow_service_change(Flow&);
     void handle_assistant_gadget(const char* service, Flow&);
 
 private:
     void get_policy_bindings(Flow&, const char* service);
+    void get_policy_bindings(Packet*);
     void get_bindings(Flow&, Stuff&, const char* service = nullptr);
+    void get_bindings(Packet*, Stuff&);
     void apply(Flow&, Stuff&);
     void apply_assistant(Flow&, Stuff&, const char*);
     Inspector* find_gadget(Flow&, Inspector*& data);
@@ -465,6 +501,20 @@ private:
     Inspector* default_ssn_inspectors[to_utype(PktType::MAX)]{};
 };
 
+class NonFlowPacketHandler : public DataHandler
+{
+public:
+    NonFlowPacketHandler() : DataHandler(BIND_NAME)
+    { }
+
+    void handle(DataEvent& e, Flow*) override
+    {
+        Binder* binder = InspectorManager::get_binder();
+        if (binder)
+            binder->handle_packet(e.get_packet());
+    }
+};
+
 class FlowStateSetupHandler : public DataHandler
 {
 public:
@@ -496,7 +546,8 @@ public:
 class StreamHANewFlowHandler : public DataHandler
 {
 public:
-    StreamHANewFlowHandler() : DataHandler(BIND_NAME) { }
+    StreamHANewFlowHandler() : DataHandler(BIND_NAME)
+    { order = 100; }
 
     void handle(DataEvent&, Flow* flow) override
     {
@@ -562,6 +613,7 @@ bool Binder::configure(SnortConfig* sc)
             default_ssn_inspectors[proto] = InspectorManager::get_inspector(name);
     }
 
+    DataBus::subscribe(PKT_WITHOUT_FLOW_EVENT, new NonFlowPacketHandler());
     DataBus::subscribe(FLOW_STATE_SETUP_EVENT, new FlowStateSetupHandler());
     DataBus::subscribe(FLOW_SERVICE_CHANGE_EVENT, new FlowServiceChangeHandler());
     DataBus::subscribe(STREAM_HA_NEW_FLOW_EVENT, new StreamHANewFlowHandler());
@@ -572,11 +624,14 @@ bool Binder::configure(SnortConfig* sc)
 
 void Binder::show(const SnortConfig*) const
 {
-    std::once_flag b_once;
-
+    bool log_header = true;
     for (const Binding& b : bindings)
     {
-        std::call_once(b_once, []{ ConfigLogger::log_option("bindings"); });
+        if (log_header)
+        {
+            ConfigLogger::log_option("bindings");
+            log_header = false;
+        }
 
         auto bind_when = "{ when = " + to_string(b.when) + ",";
         auto bind_use = "use = " + to_string(b.use) + " }";
@@ -584,11 +639,14 @@ void Binder::show(const SnortConfig*) const
         ConfigLogger::log_list("", bind_use.c_str(), "   ", true);
     }
 
-    std::once_flag pb_once;
-
+    log_header = true;
     for (const Binding& b : policy_bindings)
     {
-        std::call_once(pb_once, []{ ConfigLogger::log_option("policy_bindings"); });
+        if (log_header)
+        {
+            ConfigLogger::log_option("policy_bindings");
+            log_header = false;
+        }
 
         auto bind_when = "{ when = " + to_string(b.when) + ",";
         auto bind_use = "use = " + to_string(b.use) + " }";
@@ -615,6 +673,19 @@ void Binder::remove_inspector_binding(SnortConfig*, const char* name)
     }
 }
 
+void Binder::handle_packet(const Packet* pkt)
+{
+    Profile profile(bindPerfStats);
+
+    Stuff stuff;
+    Packet* p = const_cast<Packet*>(pkt);
+    get_bindings(p, stuff);
+    stuff.apply_action(p);
+
+    bstats.raw_packets++;
+    bstats.verdicts[stuff.action]++;
+}
+
 void Binder::handle_flow_setup(Flow& flow, bool standby)
 {
     Profile profile(bindPerfStats);
@@ -784,6 +855,44 @@ void Binder::get_policy_bindings(Flow& flow, const char* service)
     }
 }
 
+void Binder::get_policy_bindings(Packet* p)
+{
+    const SnortConfig* sc = SnortConfig::get_conf();
+    unsigned inspection_index = 0;
+    unsigned ips_index = 0;
+
+    // FIXIT-L This will select the first policy ID of each type that it finds and ignore the rest.
+    //          It gets potentially hairy if people start specifying overlapping policy types in
+    //          overlapping rules.
+    for (const Binding& b : policy_bindings)
+    {
+        // Skip any rules that don't contain an ID for a policy type we haven't set yet.
+        if ((!b.use.inspection_index || inspection_index) && (!b.use.ips_index || ips_index))
+            continue;
+
+        if (!b.check_all(p))
+            continue;
+
+        if (b.use.inspection_index && !inspection_index)
+            inspection_index = b.use.inspection_index;
+
+        if (b.use.ips_index && !ips_index)
+            ips_index = b.use.ips_index;
+    }
+
+    if (inspection_index)
+    {
+        set_inspection_policy(sc, inspection_index);
+        p->user_inspection_policy_id = get_inspection_policy()->user_policy_id;
+    }
+
+    if (ips_index)
+    {
+        set_ips_policy(sc, ips_index);
+        p->user_ips_policy_id = get_ips_policy()->user_policy_id;
+    }
+}
+
 // FIXIT-P this is a simple linear search until functionality is nailed
 // down.  performance should be the focus of the next iteration.
 void Binder::get_bindings(Flow& flow, Stuff& stuff, const char* service)
@@ -817,6 +926,37 @@ void Binder::get_bindings(Flow& flow, Stuff& stuff, const char* service)
     bstats.no_match++;
 }
 
+void Binder::get_bindings(Packet* p, Stuff& stuff)
+{
+    // Evaluate policy ID bindings first
+    get_policy_bindings(p);
+
+    // If policy selection produced a new binder to use, use that instead.
+    Binder* sub = InspectorManager::get_binder();
+    if (sub && sub != this)
+    {
+        sub->get_bindings(p, stuff);
+        return;
+    }
+
+    // If we got here, that means that a sub-policy with a binder was not invoked.
+    // Continue using this binder for the rest of processing.
+
+    // Initialize the session inspector for both client and server to the default for this policy.
+    stuff.client = stuff.server = default_ssn_inspectors[to_utype(p->type())];
+
+    for (const Binding& b : bindings)
+    {
+        if (!b.check_all(p))
+            continue;
+
+        if (stuff.update(b))
+            return;
+    }
+
+    bstats.no_match++;
+}
+
 Inspector* Binder::find_gadget(Flow& flow, Inspector*& data)
 {
     Stuff stuff;
index 665feb04038cd0ec932fe940b6673f8c9532a78d..459e4af0688b8bb6c58ce9a2861dc5d9a8686c50 100644 (file)
@@ -28,6 +28,7 @@
 #include "log/messages.h"
 #include "main/snort_config.h"
 #include "managers/inspector_manager.h"
+#include "protocols/packet.h"
 
 using namespace snort;
 
@@ -139,6 +140,14 @@ inline bool Binding::check_ips_policy(const Flow& flow) const
     return when.ips_id == flow.ips_policy_id;
 }
 
+inline bool Binding::check_ips_policy() const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_IPS_ID))
+        return true;
+
+    return when.ips_id == get_ips_policy()->policy_id;
+}
+
 inline bool Binding::check_vlan(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_VLANS))
@@ -147,6 +156,14 @@ inline bool Binding::check_vlan(const Flow& flow) const
     return when.vlans.test(flow.key->vlan_tag);
 }
 
+inline bool Binding::check_vlan(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_VLANS))
+        return true;
+
+    return when.vlans.test(p->get_flow_vlan_id());
+}
+
 inline bool Binding::check_addr(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_NETS))
@@ -176,6 +193,35 @@ inline bool Binding::check_addr(const Flow& flow) const
     return false;
 }
 
+inline bool Binding::check_addr(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_NETS))
+        return true;
+
+    switch (when.role)
+    {
+        case BindWhen::BR_SERVER:
+            if (sfvar_ip_in(when.src_nets, p->ptrs.ip_api.get_dst()))
+                return true;
+            break;
+
+        case BindWhen::BR_CLIENT:
+            if (sfvar_ip_in(when.src_nets, p->ptrs.ip_api.get_src()))
+                return true;
+            break;
+
+        case BindWhen::BR_EITHER:
+            if (sfvar_ip_in(when.src_nets, p->ptrs.ip_api.get_src()) ||
+                sfvar_ip_in(when.src_nets, p->ptrs.ip_api.get_dst()))
+                return true;
+            break;
+
+        default:
+            break;
+    }
+    return false;
+}
+
 inline bool Binding::check_split_addr(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_NETS))
@@ -190,6 +236,20 @@ inline bool Binding::check_split_addr(const Flow& flow) const
     return true;
 }
 
+inline bool Binding::check_split_addr(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_NETS))
+        return true;
+
+    if (when.src_nets && !sfvar_ip_in(when.src_nets, p->ptrs.ip_api.get_src()))
+        return false;
+
+    if (when.dst_nets && !sfvar_ip_in(when.dst_nets, p->ptrs.ip_api.get_dst()))
+        return false;
+
+    return true;
+}
+
 inline bool Binding::check_proto(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_PROTO))
@@ -199,6 +259,15 @@ inline bool Binding::check_proto(const Flow& flow) const
     return (when.protos & proto_bit) != 0;
 }
 
+inline bool Binding::check_proto(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_PROTO))
+        return true;
+
+    unsigned proto_bit = 1 << ((unsigned)p->type() - 1);
+    return (when.protos & proto_bit) != 0;
+}
+
 inline bool Binding::check_port(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_PORTS))
@@ -231,6 +300,38 @@ inline bool Binding::check_port(const Flow& flow) const
     return false;
 }
 
+inline bool Binding::check_port(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_PORTS))
+        return true;
+
+    if (p->type() != PktType::TCP && p->type() != PktType::UDP)
+        return false;
+
+    switch (when.role)
+    {
+        case BindWhen::BR_SERVER:
+            if (when.src_ports.test(p->ptrs.dp))
+                return true;
+            break;
+
+        case BindWhen::BR_CLIENT:
+            if (when.src_ports.test(p->ptrs.sp))
+                return true;
+            break;
+
+        case BindWhen::BR_EITHER:
+            if (when.src_ports.test(p->ptrs.sp) ||
+                when.src_ports.test(p->ptrs.dp))
+                return true;
+            break;
+
+        default:
+            break;
+    }
+    return false;
+}
+
 inline bool Binding::check_split_port(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_PORTS))
@@ -248,6 +349,23 @@ inline bool Binding::check_split_port(const Flow& flow) const
     return true;
 }
 
+inline bool Binding::check_split_port(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_PORTS))
+        return true;
+
+    if (p->type() != PktType::TCP && p->type() != PktType::UDP)
+        return false;
+
+    if (!when.src_ports.test(p->ptrs.sp))
+        return false;
+
+    if (!when.dst_ports.test(p->ptrs.dp))
+        return false;
+
+    return true;
+}
+
 inline bool Binding::check_intf(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_INTFS))
@@ -278,6 +396,36 @@ inline bool Binding::check_intf(const Flow& flow) const
     return false;
 }
 
+inline bool Binding::check_intf(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_INTFS))
+        return true;
+
+    switch (when.role)
+    {
+        case BindWhen::BR_SERVER:
+            if (when.src_intfs.count(p->pkth->egress_index))
+                return true;
+            break;
+
+        case BindWhen::BR_CLIENT:
+            if (when.src_intfs.count(p->pkth->ingress_index))
+                return true;
+            break;
+
+        case BindWhen::BR_EITHER:
+            if (when.src_intfs.count(p->pkth->ingress_index) ||
+                when.src_intfs.count(p->pkth->egress_index))
+                return true;
+            break;
+
+        default:
+            break;
+    }
+
+    return false;
+}
+
 inline bool Binding::check_split_intf(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_INTFS))
@@ -292,6 +440,20 @@ inline bool Binding::check_split_intf(const Flow& flow) const
     return true;
 }
 
+inline bool Binding::check_split_intf(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_INTFS))
+        return true;
+
+    if (!when.src_intfs.empty() && !when.src_intfs.count(p->pkth->ingress_index))
+        return false;
+
+    if (!when.dst_intfs.empty() && !when.dst_intfs.count(p->pkth->egress_index))
+        return false;
+
+    return true;
+}
+
 inline bool Binding::check_group(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_GROUPS))
@@ -322,6 +484,36 @@ inline bool Binding::check_group(const Flow& flow) const
     return false;
 }
 
+inline bool Binding::check_group(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_GROUPS))
+        return true;
+
+    switch (when.role)
+    {
+        case BindWhen::BR_SERVER:
+            if (when.src_groups.count(p->pkth->egress_group))
+                return true;
+            break;
+
+        case BindWhen::BR_CLIENT:
+            if (when.src_groups.count(p->pkth->ingress_group))
+                return true;
+            break;
+
+        case BindWhen::BR_EITHER:
+            if (when.src_groups.count(p->pkth->ingress_group) ||
+                when.src_groups.count(p->pkth->egress_group))
+                return true;
+            break;
+
+        default:
+            break;
+    }
+
+    return false;
+}
+
 inline bool Binding::check_split_group(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_GROUPS))
@@ -336,6 +528,20 @@ inline bool Binding::check_split_group(const Flow& flow) const
     return true;
 }
 
+inline bool Binding::check_split_group(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_SPLIT_GROUPS))
+        return true;
+
+    if (!when.src_groups.empty() && !when.src_groups.count(p->pkth->ingress_group))
+        return false;
+
+    if (!when.dst_groups.empty() && !when.dst_groups.count(p->pkth->egress_group))
+        return false;
+
+    return true;
+}
+
 inline bool Binding::check_address_space(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_ADDR_SPACES))
@@ -344,6 +550,30 @@ inline bool Binding::check_address_space(const Flow& flow) const
     return when.addr_spaces.count(flow.key->addressSpaceId) != 0;
 }
 
+inline bool Binding::check_address_space(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_ADDR_SPACES))
+        return true;
+
+    return when.addr_spaces.count(p->pkth->address_space_id) != 0;
+}
+
+inline bool Binding::check_tenant(const Flow& flow) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_TENANTS))
+        return true;
+
+    return when.tenants.count(flow.tenant) != 0;
+}
+
+inline bool Binding::check_tenant(const Packet* p) const
+{
+    if (!when.has_criteria(BindWhen::Criteria::BWC_TENANTS))
+        return true;
+
+    return when.tenants.count(p->pkth->address_space_id) != 0;
+}
+
 inline bool Binding::check_service(const Flow& flow) const
 {
     if (!when.has_criteria(BindWhen::Criteria::BWC_SVC))
@@ -365,6 +595,11 @@ inline bool Binding::check_service(const char* service) const
     return when.svc == service;
 }
 
+inline bool Binding::check_service() const
+{
+    return when.has_criteria(BindWhen::Criteria::BWC_SVC) ? false : true;
+}
+
 bool Binding::check_all(const Flow& flow, const char* service) const
 {
     // Do the service check first to optimize service change re-evaluations
@@ -412,6 +647,56 @@ bool Binding::check_all(const Flow& flow, const char* service) const
     if (!check_address_space(flow))
         return false;
 
+    if (!check_tenant(flow))
+        return false;
+
+    return true;
+}
+
+bool Binding::check_all(const Packet* p) const
+{
+    if (!check_service())
+        return false;
+
+    if (!check_ips_policy())
+        return false;
+
+    if (!check_vlan(p))
+        return false;
+
+    if (!check_addr(p))
+        return false;
+
+    if (!check_split_addr(p))
+        return false;
+
+    if (!check_proto(p))
+        return false;
+
+    if (!check_port(p))
+        return false;
+
+    if (!check_split_port(p))
+        return false;
+
+    if (!check_intf(p))
+        return false;
+
+    if (!check_split_intf(p))
+        return false;
+
+    if (!check_group(p))
+        return false;
+
+    if (!check_split_group(p))
+        return false;
+
+    if (!check_address_space(p))
+        return false;
+
+    if (!check_tenant(p))
+        return false;
+
     return true;
 }
 
index 3ff734d0eed8c33c2ec34d35ce9dac9d100b34d9..c9b705ef700b576cde0e952c7e9fd8483ccee95a 100644 (file)
@@ -60,6 +60,8 @@ struct BindWhen
 
     std::unordered_set<uint16_t> addr_spaces;
 
+    std::unordered_set<uint32_t> tenants;
+
     enum Criteria
     {
         BWC_IPS_ID =        0x0001,
@@ -74,7 +76,8 @@ struct BindWhen
         BWC_SPLIT_INTFS =   0x0200,
         BWC_GROUPS =        0x0400,
         BWC_SPLIT_GROUPS =  0x0800,
-        BWC_ADDR_SPACES =   0x1000
+        BWC_ADDR_SPACES =   0x1000,
+        BWC_TENANTS =       0x2000
     };
     uint16_t criteria_flags;
 
@@ -115,20 +118,36 @@ struct Binding
     void configure(const snort::SnortConfig* sc);
 
     bool check_all(const snort::Flow&, const char* = nullptr) const;
+    bool check_all(const snort::Packet*) const;
     bool check_ips_policy(const snort::Flow&) const;
+    bool check_ips_policy() const;
     bool check_vlan(const snort::Flow&) const;
+    bool check_vlan(const snort::Packet*) const;
     bool check_addr(const snort::Flow&) const;
+    bool check_addr(const snort::Packet*) const;
     bool check_split_addr(const snort::Flow&) const;
+    bool check_split_addr(const snort::Packet*) const;
     bool check_proto(const snort::Flow&) const;
+    bool check_proto(const snort::Packet*) const;
     bool check_port(const snort::Flow&) const;
+    bool check_port(const snort::Packet*) const;
     bool check_split_port(const snort::Flow&) const;
+    bool check_split_port(const snort::Packet*) const;
     bool check_intf(const snort::Flow&) const;
+    bool check_intf(const snort::Packet*) const;
     bool check_split_intf(const snort::Flow&) const;
+    bool check_split_intf(const snort::Packet*) const;
     bool check_group(const snort::Flow&) const;
+    bool check_group(const snort::Packet*) const;
     bool check_split_group(const snort::Flow&) const;
-    bool check_address_space(const snort::Flow& flow) const;
+    bool check_split_group(const snort::Packet*) const;
+    bool check_address_space(const snort::Flow&) const;
+    bool check_address_space(const snort::Packet*) const;
+    bool check_tenant(const snort::Flow&) const;
+    bool check_tenant(const snort::Packet*) const;
     bool check_service(const snort::Flow&) const;
     bool check_service(const char* service) const;
+    bool check_service() const;
 };
 
 #endif
index eb4f250a70dbbf8ab27216b0a008904cd02ed0fb..3b08e5e1ecf07b11f53982a72f4c437301a59dec 100644 (file)
@@ -46,7 +46,7 @@ public:
     { return &config; }
 
     Usage get_usage() const override
-    { return INSPECT; }
+    { return CONTEXT; }
 
 private:
     bool set_ip4(const char*, const snort::Value&, snort::SnortConfig*);
index 96268ef675ca0ac6e1458175a52afcd56784383b..e7d75b9927af93fba95a34348a662e710b2797d6 100644 (file)
@@ -60,8 +60,8 @@ static THREAD_LOCAL PerfConstraints* t_constraints;
 class PerfIdleHandler : public DataHandler
 {
 public:
-    PerfIdleHandler(PerfMonitor& p, SnortConfig*& sc) : DataHandler(PERF_NAME), perf_monitor(p)
-    { DataBus::subscribe_global(THREAD_IDLE_EVENT, this, sc); }
+    PerfIdleHandler(PerfMonitor& p) : DataHandler(PERF_NAME), perf_monitor(p)
+    { DataBus::subscribe_network(THREAD_IDLE_EVENT, this); }
 
     void handle(DataEvent&, Flow*) override
     { perf_monitor.eval(nullptr); }
@@ -73,8 +73,8 @@ private:
 class PerfRotateHandler : public DataHandler
 {
 public:
-    PerfRotateHandler(PerfMonitor& p, SnortConfig* sc) : DataHandler(PERF_NAME), perf_monitor(p)
-    { DataBus::subscribe_global(THREAD_ROTATE_EVENT, this, sc); }
+    PerfRotateHandler(PerfMonitor& p) : DataHandler(PERF_NAME), perf_monitor(p)
+    { DataBus::subscribe_network(THREAD_ROTATE_EVENT, this); }
 
     void handle(DataEvent&, Flow*) override
     { perf_monitor.rotate(); }
@@ -86,8 +86,8 @@ private:
 class FlowIPDataHandler : public DataHandler
 {
 public:
-    FlowIPDataHandler(PerfMonitor& p, SnortConfig* sc) : DataHandler(PERF_NAME), perf_monitor(p)
-    { DataBus::subscribe_global(FLOW_STATE_EVENT, this, sc); }
+    FlowIPDataHandler(PerfMonitor& p) : DataHandler(PERF_NAME), perf_monitor(p)
+    { DataBus::subscribe_network(FLOW_STATE_EVENT, this); }
 
     void handle(DataEvent&, Flow* flow) override
     {
@@ -194,11 +194,11 @@ void PerfMonitor::disable_tracker(size_t i)
 // type and version fields immediately after timestamp like seconds, usec,
 // type, version#, data1, data2, ...
 
-bool PerfMonitor::configure(SnortConfig* sc)
+bool PerfMonitor::configure(SnortConfig*)
 {
-    new PerfIdleHandler(*this, sc);
-    new PerfRotateHandler(*this, sc);
-    new FlowIPDataHandler(*this, sc);
+    new PerfIdleHandler(*this);
+    new PerfRotateHandler(*this);
+    new FlowIPDataHandler(*this);
 
     return config->resolve();
 }
index 7e12c6573bda85024d459c965b12164f712e85e9..6561586087402d98b79373eb0b63366656682241 100644 (file)
@@ -560,9 +560,9 @@ void Reputation::eval(Packet* p)
     ++reputationstats.packets;
 }
 
-bool Reputation::configure(SnortConfig* sc)
+bool Reputation::configure(SnortConfig*)
 {
-    DataBus::subscribe_global( AUXILIARY_IP_EVENT, new AuxiliaryIpRepHandler(config), sc );
+    DataBus::subscribe_network( AUXILIARY_IP_EVENT, new AuxiliaryIpRepHandler(config) );
     return true;
 }
 
index 766052d8b2185c9bb0a740f1a1257b64f63b76ef..2e767297e9836bff2777471e0f18d29eca1c6503 100644 (file)
@@ -56,9 +56,6 @@ public:
 
     ReputationConfig* get_data();
 
-    Usage get_usage() const override
-    { return GLOBAL; }
-
 private:
     ReputationConfig* conf;
 };
index 92e1d9322b413a0335a8e9b902d42bfd0c426595..3ee97c10e8fac9c944e13e86211387a032bc8662 100644 (file)
@@ -88,27 +88,27 @@ RnaInspector::~RnaInspector()
 
 bool RnaInspector::configure(SnortConfig* sc)
 {
-    DataBus::subscribe_global( APPID_EVENT_ANY_CHANGE, new RnaAppidEventHandler(*pnd), sc );
-    DataBus::subscribe_global( DHCP_INFO_EVENT, new RnaDHCPInfoEventHandler(*pnd), sc);
-    DataBus::subscribe_global( DHCP_DATA_EVENT, new RnaDHCPDataEventHandler(*pnd), sc);
-    DataBus::subscribe_global( FP_SMB_DATA_EVENT, new RnaFpSMBEventHandler(*pnd), sc);
+    DataBus::subscribe_network( APPID_EVENT_ANY_CHANGE, new RnaAppidEventHandler(*pnd) );
+    DataBus::subscribe_network( DHCP_INFO_EVENT, new RnaDHCPInfoEventHandler(*pnd) );
+    DataBus::subscribe_network( DHCP_DATA_EVENT, new RnaDHCPDataEventHandler(*pnd) );
+    DataBus::subscribe_network( FP_SMB_DATA_EVENT, new RnaFpSMBEventHandler(*pnd) );
 
-    DataBus::subscribe_global( STREAM_ICMP_NEW_FLOW_EVENT, new RnaIcmpNewFlowEventHandler(*pnd), sc );
-    DataBus::subscribe_global( STREAM_ICMP_BIDIRECTIONAL_EVENT, new RnaIcmpBidirectionalEventHandler(*pnd), sc );
+    DataBus::subscribe_network( STREAM_ICMP_NEW_FLOW_EVENT, new RnaIcmpNewFlowEventHandler(*pnd) );
+    DataBus::subscribe_network( STREAM_ICMP_BIDIRECTIONAL_EVENT, new RnaIcmpBidirectionalEventHandler(*pnd) );
 
-    DataBus::subscribe_global( STREAM_IP_NEW_FLOW_EVENT, new RnaIpNewFlowEventHandler(*pnd), sc );
-    DataBus::subscribe_global( STREAM_IP_BIDIRECTIONAL_EVENT, new RnaIpBidirectionalEventHandler(*pnd), sc );
+    DataBus::subscribe_network( STREAM_IP_NEW_FLOW_EVENT, new RnaIpNewFlowEventHandler(*pnd) );
+    DataBus::subscribe_network( STREAM_IP_BIDIRECTIONAL_EVENT, new RnaIpBidirectionalEventHandler(*pnd) );
 
-    DataBus::subscribe_global( STREAM_UDP_NEW_FLOW_EVENT, new RnaUdpNewFlowEventHandler(*pnd), sc );
-    DataBus::subscribe_global( STREAM_UDP_BIDIRECTIONAL_EVENT, new RnaUdpBidirectionalEventHandler(*pnd), sc );
+    DataBus::subscribe_network( STREAM_UDP_NEW_FLOW_EVENT, new RnaUdpNewFlowEventHandler(*pnd) );
+    DataBus::subscribe_network( STREAM_UDP_BIDIRECTIONAL_EVENT, new RnaUdpBidirectionalEventHandler(*pnd) );
 
-    DataBus::subscribe_global( STREAM_TCP_SYN_EVENT, new RnaTcpSynEventHandler(*pnd), sc );
-    DataBus::subscribe_global( STREAM_TCP_SYN_ACK_EVENT, new RnaTcpSynAckEventHandler(*pnd), sc );
-    DataBus::subscribe_global( STREAM_TCP_MIDSTREAM_EVENT, new RnaTcpMidstreamEventHandler(*pnd), sc );
-    DataBus::subscribe_global( CPE_OS_INFO_EVENT, new RnaCPEOSInfoEventHandler(*pnd), sc );
+    DataBus::subscribe_network( STREAM_TCP_SYN_EVENT, new RnaTcpSynEventHandler(*pnd) );
+    DataBus::subscribe_network( STREAM_TCP_SYN_ACK_EVENT, new RnaTcpSynAckEventHandler(*pnd) );
+    DataBus::subscribe_network( STREAM_TCP_MIDSTREAM_EVENT, new RnaTcpMidstreamEventHandler(*pnd) );
+    DataBus::subscribe_network( CPE_OS_INFO_EVENT, new RnaCPEOSInfoEventHandler(*pnd) );
 
     if (rna_conf && rna_conf->log_when_idle)
-        DataBus::subscribe_global( THREAD_IDLE_EVENT, new RnaIdleEventHandler(*pnd), sc );
+        DataBus::subscribe_network( THREAD_IDLE_EVENT, new RnaIdleEventHandler(*pnd) );
 
     // tinit is not called during reload, so pass processor pointers to threads via reload tuner
     if ( Snort::is_reloading() && InspectorManager::get_inspector(RNA_NAME, true) )
index 6c9a7b8b3cc3d718976117b649c44890cb8518cb..7064e8175eb560c94460c482580882c45663f4b7 100644 (file)
@@ -38,7 +38,7 @@ void Module::show_interval_stats(std::vector<unsigned int, std::allocator<unsign
 {}
 void LogMessage(const char*,...) {}
 void WarningMessage(const char*,...) {}
-SnortConfig::SnortConfig(SnortConfig const*) {}
+SnortConfig::SnortConfig(const SnortConfig* const, const char*) {}
 SnortConfig::~SnortConfig() = default;
 time_t packet_time() { return 0; }
 
index e6011a8d6b2840e590ff0061966267db2e5c1b5c..626ccf6449ee36fce06d2c4750524d85edc2a50b 100644 (file)
@@ -63,7 +63,7 @@ Flow::Flow()
 Flow::~Flow() = default;
 IpsContext::IpsContext(unsigned int) { }
 IpsContext::~IpsContext() = default;
-SnortConfig::SnortConfig(snort::SnortConfig const*) { }
+SnortConfig::SnortConfig(snort::SnortConfig const*, const char*) { }
 SnortConfig::~SnortConfig() = default;
 
 IpsContext ips_context;
diff --git a/src/policy_selectors/CMakeLists.txt b/src/policy_selectors/CMakeLists.txt
new file mode 100644 (file)
index 0000000..567343a
--- /dev/null
@@ -0,0 +1,16 @@
+
+add_subdirectory(address_space_selector)
+add_subdirectory(tenant_selector)
+
+set(STATIC_POLICY_SELECTOR_PLUGINS
+    $<TARGET_OBJECTS:address_space_selector>
+    $<TARGET_OBJECTS:tenant_selector>
+    CACHE INTERNAL "STATIC_POLICY_SELECTOR_PLUGINS"
+)
+
+add_library( policy_selectors OBJECT
+    int_set_to_string.h
+    parse_int_set.h
+    policy_selectors.cc
+    policy_selectors.h
+)
diff --git a/src/policy_selectors/address_space_selector/CMakeLists.txt b/src/policy_selectors/address_space_selector/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7ff24bc
--- /dev/null
@@ -0,0 +1,11 @@
+
+set(FILE_LIST
+    address_space_selection.cc
+    address_space_selection.h
+    address_space_selector.cc
+    address_space_selector_module.cc
+    address_space_selector_module.h
+)
+
+add_library(address_space_selector OBJECT ${FILE_LIST})
+
diff --git a/src/policy_selectors/address_space_selector/address_space_selection.cc b/src/policy_selectors/address_space_selector/address_space_selection.cc
new file mode 100644 (file)
index 0000000..b9adce6
--- /dev/null
@@ -0,0 +1,40 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// address_space_selection.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "address_space_selection.h"
+
+using namespace snort;
+
+AddressSpaceSelection::AddressSpaceSelection()
+{ clear(); }
+
+void AddressSpaceSelection::clear()
+{
+    addr_spaces.clear();
+
+    use.name.clear();
+    use.network_index = 0;
+    use.inspection_index = 0;
+    use.ips_index = 0;
+}
+
diff --git a/src/policy_selectors/address_space_selector/address_space_selection.h b/src/policy_selectors/address_space_selector/address_space_selection.h
new file mode 100644 (file)
index 0000000..71a6146
--- /dev/null
@@ -0,0 +1,40 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// address_space_selection.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef ADDRESS_SPACE_SELECTION_H
+#define ADDRESS_SPACE_SELECTION_H
+
+// Evaluation elements for selecting policies based on address space
+
+#include <vector>
+
+#include "framework/policy_selector.h"
+
+struct AddressSpaceSelection
+{
+    std::vector<uint32_t> addr_spaces;
+    snort::PolicySelectUse use;
+
+    AddressSpaceSelection();
+
+    void clear();
+};
+
+#endif
+
diff --git a/src/policy_selectors/address_space_selector/address_space_selector.cc b/src/policy_selectors/address_space_selector/address_space_selector.cc
new file mode 100644 (file)
index 0000000..11a51c6
--- /dev/null
@@ -0,0 +1,177 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// address_space_selector.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <algorithm>
+#include <unordered_map>
+#include <vector>
+
+#include "detection/ips_context.h"
+#include "framework/policy_selector.h"
+#include "log/messages.h"
+#include "policy_selectors/int_set_to_string.h"
+#include "profiler/profiler.h"
+
+#include "address_space_selector_module.h"
+#include "address_space_selection.h"
+
+using namespace snort;
+
+THREAD_LOCAL ProfileStats address_space_selectPerfStats;
+
+//-------------------------------------------------------------------------
+// helpers
+//-------------------------------------------------------------------------
+
+static std::string to_string(const std::vector<uint32_t>& as)
+{
+    std::string when;
+
+    if (!as.empty())
+    {
+        auto addr_spaces = int_set_to_string<uint32_t>(as);
+        when += "addr_spaces = " + addr_spaces;
+    }
+
+    return when;
+}
+
+//-------------------------------------------------------------------------
+// class stuff
+//-------------------------------------------------------------------------
+
+class AddressSpaceSelector : public PolicySelector
+{
+public:
+    AddressSpaceSelector(const PolicySelectorApi*, std::vector<AddressSpaceSelection>&);
+    ~AddressSpaceSelector() override;
+
+    void show() const override;
+
+    bool select_default_policies(const _daq_pkt_hdr*, const SnortConfig*) override;
+
+protected:
+    std::vector<AddressSpaceSelection> policy_selections;
+    std::unordered_map<uint32_t, snort::PolicySelectUse*> policy_map;
+};
+
+AddressSpaceSelector::AddressSpaceSelector(const PolicySelectorApi* api_in,
+    std::vector<AddressSpaceSelection>& psv) : PolicySelector(api_in)
+{
+    policy_selections = std::move(psv);
+    for (auto i = policy_selections.rbegin(); i != policy_selections.rend(); ++i)
+    {
+        std::sort((*i).addr_spaces.begin(), (*i).addr_spaces.end());
+        for(auto j = (*i).addr_spaces.begin(); j != (*i).addr_spaces.end(); ++j)
+            policy_map[*j] = &(*i).use;
+    }
+}
+
+AddressSpaceSelector::~AddressSpaceSelector()
+{
+    for (AddressSpaceSelection& s : policy_selections)
+        s.clear();
+}
+
+void AddressSpaceSelector::show() const
+{
+    bool log_header = true;
+    for (const AddressSpaceSelection& s : policy_selections)
+    {
+        if (log_header)
+        {
+            ConfigLogger::log_option("policy_selections");
+            log_header = false;
+        }
+
+        std::string select;
+        std::string when = to_string(s.addr_spaces);
+        if (when.empty())
+            select = "{ " + s.use.stringify() + " }";
+        else
+            select = "{ " + when + ", " + s.use.stringify() + " }";
+        ConfigLogger::log_list("", select.c_str(), "   ");
+    }
+}
+
+bool AddressSpaceSelector::select_default_policies(const _daq_pkt_hdr* pkthdr, const SnortConfig* sc)
+{
+    Profile profile(address_space_selectPerfStats);
+
+    address_space_select_stats.packets++;
+
+    auto i = policy_map.find(static_cast<uint32_t>(pkthdr->address_space_id));
+    if (i != policy_map.end())
+    {
+        auto use = (*i).second;
+        set_network_policy(sc, use->network_index);
+        set_inspection_policy(sc, use->inspection_index);
+        set_ips_policy(sc, use->ips_index);
+        return true;
+    }
+    address_space_select_stats.no_match++;
+    return false;
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new AddressSpaceSelectorModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static PolicySelector* address_space_select_ctor(Module*);
+static void address_space_select_dtor(PolicySelector*);
+
+static const PolicySelectorApi select_api =
+{
+    {
+        PT_POLICY_SELECTOR,
+        sizeof(PolicySelectorApi),
+        POLICY_SELECTOR_API_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        ADDRESS_SPACE_SELECT_NAME,
+        ADDRESS_SPACE_SELECT_HELP,
+        mod_ctor,
+        mod_dtor
+    },
+    address_space_select_ctor,
+    address_space_select_dtor,
+};
+
+const BaseApi* ps_address_space_selector = &select_api.base;
+
+static PolicySelector* address_space_select_ctor(Module* m)
+{
+    AddressSpaceSelectorModule* mod = static_cast<AddressSpaceSelectorModule*>(m);
+    std::vector<AddressSpaceSelection>& psv = mod->get_policy_selections();
+    return new AddressSpaceSelector(&select_api, psv);
+}
+
+static void address_space_select_dtor(PolicySelector* p)
+{ delete p; }
+
diff --git a/src/policy_selectors/address_space_selector/address_space_selector_module.cc b/src/policy_selectors/address_space_selector/address_space_selector_module.cc
new file mode 100644 (file)
index 0000000..4ff647b
--- /dev/null
@@ -0,0 +1,152 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// address_space_selector_module.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "address_space_selector_module.h"
+
+#include "log/messages.h"
+#include "main/shell.h"
+#include "main/snort_config.h"
+#include "managers/module_manager.h"
+#include "policy_selectors/parse_int_set.h"
+
+using namespace snort;
+using namespace std;
+
+THREAD_LOCAL PolicySelectStats address_space_select_stats;
+
+static const PegInfo select_pegs[] =
+{
+    { CountType::SUM, "packets", "packets evaluated" },
+    { CountType::SUM, "no_match", "selection evaluations that had no matches" },
+    { CountType::END, nullptr, nullptr }
+};
+
+//-------------------------------------------------------------------------
+// selector module
+//-------------------------------------------------------------------------
+
+static const Parameter selector_when_params[] =
+{
+    { "addr_spaces", Parameter::PT_STRING, nullptr, nullptr,
+      "list of address space IDs" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const Parameter selector_use_params[] =
+{
+    { "file", Parameter::PT_STRING, nullptr, nullptr,
+      "use configuration in given file" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const Parameter s_params[] =
+{
+    { "addr_spaces", Parameter::PT_STRING, nullptr, nullptr,
+      "list of address space IDs to match" },
+
+    { "file", Parameter::PT_STRING, nullptr, nullptr,
+      "use configuration in given file" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+AddressSpaceSelectorModule::AddressSpaceSelectorModule() : Module(ADDRESS_SPACE_SELECT_NAME, ADDRESS_SPACE_SELECT_HELP, s_params, true)
+{ }
+
+AddressSpaceSelectorModule::~AddressSpaceSelectorModule()
+{
+    policy_selections.clear();
+    selection.clear();
+}
+
+ProfileStats* AddressSpaceSelectorModule::get_profile() const
+{ return &address_space_selectPerfStats; }
+
+void AddressSpaceSelectorModule::add_policy_file(const char* name)
+{ policy_filename = name; }
+
+bool AddressSpaceSelectorModule::begin(const char* fqn, int idx, SnortConfig*)
+{
+    if ( idx && !strcmp(fqn, ADDRESS_SPACE_SELECT_NAME) )
+    {
+        selection.clear();
+        policy_filename.clear();
+    }
+
+    return true;
+}
+
+bool AddressSpaceSelectorModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("addr_spaces") )
+    {
+        if (!parse_int_set<uint32_t>(v, selection.addr_spaces))
+            return false;
+    }
+
+    // use
+    else if ( v.is("file") )
+        add_policy_file(v.get_string());
+
+    return true;
+}
+
+bool AddressSpaceSelectorModule::end(const char* fqn, int idx, SnortConfig* sc)
+{
+    if ( !strcmp(fqn, ADDRESS_SPACE_SELECT_NAME) && idx )
+    {
+        // Use validation
+        if ( policy_filename.empty() )
+        {
+            ParseError("Missing policy file name");
+            return false;
+        }
+
+        Shell* sh = new Shell(policy_filename.c_str());
+        auto policies = sc->policy_map->add_shell(sh, true);
+        selection.use.network_index = policies->network->policy_id;
+        selection.use.inspection_index = policies->inspection->policy_id;
+        selection.use.ips_index = policies->ips->policy_id;
+
+        // Store the policy filename for verbose output
+        selection.use.name = policy_filename;
+
+        commit_policy_selection();
+    }
+    return true;
+}
+
+void AddressSpaceSelectorModule::commit_policy_selection()
+{ policy_selections.emplace_back(selection); }
+
+vector<AddressSpaceSelection>& AddressSpaceSelectorModule::get_policy_selections()
+{ return policy_selections; }
+
+const PegInfo* AddressSpaceSelectorModule::get_pegs() const
+{ return select_pegs; }
+
+PegCount* AddressSpaceSelectorModule::get_counts() const
+{ return (PegCount*)&address_space_select_stats; }
+
diff --git a/src/policy_selectors/address_space_selector/address_space_selector_module.h b/src/policy_selectors/address_space_selector/address_space_selector_module.h
new file mode 100644 (file)
index 0000000..858fb23
--- /dev/null
@@ -0,0 +1,64 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// address_space_selector_module.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef ADDRESS_SPACE_SELECTOR_MODULE_H
+#define ADDRESS_SPACE_SELECTOR_MODULE_H
+
+// address space selector management interface
+
+#include "framework/module.h"
+#include "framework/policy_selector.h"
+#include "address_space_selection.h"
+
+#define ADDRESS_SPACE_SELECT_NAME "address_space_selector"
+#define ADDRESS_SPACE_SELECT_HELP "configure traffic processing based on address space"
+
+extern THREAD_LOCAL snort::PolicySelectStats address_space_select_stats;
+extern THREAD_LOCAL snort::ProfileStats address_space_selectPerfStats;
+
+class AddressSpaceSelectorModule : public snort::Module
+{
+public:
+    AddressSpaceSelectorModule();
+    ~AddressSpaceSelectorModule() override;
+
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+    const PegInfo* get_pegs() const override;
+    PegCount* get_counts() const override;
+    snort::ProfileStats* get_profile() const override;
+
+    std::vector<AddressSpaceSelection>& get_policy_selections();
+
+    Usage get_usage() const override
+    { return GLOBAL; }
+
+private:
+    AddressSpaceSelection selection;
+    std::vector<AddressSpaceSelection> policy_selections;
+    std::string policy_filename;
+
+    void add_policy_file(const char* name);
+    void commit_policy_selection();
+};
+
+#endif
+
diff --git a/src/policy_selectors/address_space_selector/dev_notes.txt b/src/policy_selectors/address_space_selector/dev_notes.txt
new file mode 100644 (file)
index 0000000..7330e67
--- /dev/null
@@ -0,0 +1,14 @@
+The address space selector maps configuration to a packet based on the address space
+ID in the packet header.
+
+AddressSpaceSelectorModule creates a vector of AddressSpaceSelections from the Lua
+selector table which is moved to the AddressSpaceSelector upon its construction. The
+PolicySelectUse portion of the AddressSpaceSelections is added to a policy map that
+is keyed with the tenant IDs. For each default policy selection, the policy map is
+queried for a match given the address space ID. The match selects the following
+policies:
+
+* network policy
+* inspection policy
+* IPS policy
+
diff --git a/src/policy_selectors/dev_notes.txt b/src/policy_selectors/dev_notes.txt
new file mode 100644 (file)
index 0000000..ed51ac8
--- /dev/null
@@ -0,0 +1,3 @@
+A set of policy selectors to select the default policies in a multi-tenant
+environment. The selectors can only use constraints that are known before
+packet decode, such as address space ID, interfaces, tenants, etc.
diff --git a/src/policy_selectors/int_set_to_string.h b/src/policy_selectors/int_set_to_string.h
new file mode 100644 (file)
index 0000000..e84df20
--- /dev/null
@@ -0,0 +1,48 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// int_set_to_string.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef INT_SET_TO_STRING_H
+#define INT_SET_TO_STRING_H
+
+// used to format configuration for output in show methods
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+template <typename T>
+static std::string int_set_to_string(const std::vector<T>& v)
+{
+    if (v.empty())
+        return "";
+
+    std::stringstream ss;
+    for (auto e : v)
+        ss << e << " ";
+
+    auto str = ss.str();
+    if (!str.empty())
+        str.pop_back();
+
+    return str;
+}
+
+#endif
+
diff --git a/src/policy_selectors/parse_int_set.h b/src/policy_selectors/parse_int_set.h
new file mode 100644 (file)
index 0000000..e976b8a
--- /dev/null
@@ -0,0 +1,62 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// parse_int_set.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef PARSE_INT_SET_H
+#define PARSE_INT_SET_H
+
+// used to parse an int set
+
+#include <cstdint>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "framework/value.h"
+
+template<typename T>
+static bool parse_int_set(const snort::Value& v, std::vector<T>& set)
+{
+    assert(v.get_type() == snort::Value::VT_STR);
+
+    set.clear();
+
+    std::string pl = v.get_string();
+
+    std::stringstream ss(pl);
+    ss >> std::setbase(0);
+
+    int64_t n;
+
+    while ( ss >> n )
+    {
+        if ( n > std::numeric_limits<T>::max() )
+            return false;
+
+        set.emplace_back(n);
+    }
+    if ( !ss.eof() )
+        return false;
+
+    return true;
+}
+
+#endif
+
diff --git a/src/policy_selectors/policy_selectors.cc b/src/policy_selectors/policy_selectors.cc
new file mode 100644 (file)
index 0000000..aebecc3
--- /dev/null
@@ -0,0 +1,43 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+
+#include "policy_selectors.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "managers/plugin_manager.h"
+
+using namespace snort;
+
+extern const BaseApi* ps_address_space_selector;
+extern const BaseApi* ps_tenant_selector;
+
+static const BaseApi* policy_selectors[] =
+{
+    ps_address_space_selector,
+    ps_tenant_selector,
+    nullptr
+};
+
+void load_policy_selectors()
+{
+    PluginManager::load_plugins(policy_selectors);
+}
+
diff --git a/src/policy_selectors/policy_selectors.h b/src/policy_selectors/policy_selectors.h
new file mode 100644 (file)
index 0000000..f4de76a
--- /dev/null
@@ -0,0 +1,25 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+
+#ifndef POLICY_SELECTORS_H
+#define POLICY_SELECTORS_H
+
+void load_policy_selectors();
+
+#endif
+
diff --git a/src/policy_selectors/tenant_selector/CMakeLists.txt b/src/policy_selectors/tenant_selector/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f132021
--- /dev/null
@@ -0,0 +1,11 @@
+
+set(FILE_LIST
+    tenant_selection.cc
+    tenant_selection.h
+    tenant_selector.cc
+    tenant_selector_module.cc
+    tenant_selector_module.h
+)
+
+add_library(tenant_selector OBJECT ${FILE_LIST})
+
diff --git a/src/policy_selectors/tenant_selector/dev_notes.txt b/src/policy_selectors/tenant_selector/dev_notes.txt
new file mode 100644 (file)
index 0000000..561bcfc
--- /dev/null
@@ -0,0 +1,12 @@
+The tenant selector maps configuration to a packet based on the tenant ID in the packet
+header.
+
+TenantSelectorModule creates a vector of TenantSelections from the Lua selector table which
+is moved to the TenantSelector upon its construction. The PolicySelectUse portion of the
+TenantSelections is added to a policy map that is keyed with the tenant IDs. For each
+default policy selection, the policy map is queried for a match given the tenant ID.
+The match selects the following policies:
+
+* network policy
+* inspection policy
+* IPS policy
diff --git a/src/policy_selectors/tenant_selector/tenant_selection.cc b/src/policy_selectors/tenant_selector/tenant_selection.cc
new file mode 100644 (file)
index 0000000..e562d3c
--- /dev/null
@@ -0,0 +1,40 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// tenant_selection.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tenant_selection.h"
+
+using namespace snort;
+
+TenantSelection::TenantSelection()
+{ clear(); }
+
+void TenantSelection::clear()
+{
+    tenants.clear();
+
+    use.name.clear();
+    use.network_index = 0;
+    use.inspection_index = 0;
+    use.ips_index = 0;
+}
+
diff --git a/src/policy_selectors/tenant_selector/tenant_selection.h b/src/policy_selectors/tenant_selector/tenant_selection.h
new file mode 100644 (file)
index 0000000..b1fd635
--- /dev/null
@@ -0,0 +1,40 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// tenant_selection.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef TENANT_SELECTION_H
+#define TENANT_SELECTION_H
+
+// Evaluation elements for selecting policies based on tenant
+
+#include <vector>
+
+#include "framework/policy_selector.h"
+
+struct TenantSelection
+{
+    std::vector<uint32_t> tenants;
+    snort::PolicySelectUse use;
+
+    TenantSelection();
+
+    void clear();
+};
+
+#endif
+
diff --git a/src/policy_selectors/tenant_selector/tenant_selector.cc b/src/policy_selectors/tenant_selector/tenant_selector.cc
new file mode 100644 (file)
index 0000000..643d280
--- /dev/null
@@ -0,0 +1,178 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// selector.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <algorithm>
+#include <unordered_map>
+#include <vector>
+
+#include "detection/ips_context.h"
+#include "framework/policy_selector.h"
+#include "log/messages.h"
+#include "policy_selectors/int_set_to_string.h"
+#include "profiler/profiler.h"
+
+#include "tenant_selector_module.h"
+#include "tenant_selection.h"
+
+using namespace snort;
+
+THREAD_LOCAL ProfileStats tenant_select_perf_stats;
+
+//-------------------------------------------------------------------------
+// helpers
+//-------------------------------------------------------------------------
+
+static std::string to_string(const std::vector<uint32_t>& t)
+{
+    std::string when;
+
+    if (!t.empty())
+    {
+        auto tenants = int_set_to_string<uint32_t>(t);
+        when += "tenants = " + tenants;
+    }
+
+    return when;
+}
+
+//-------------------------------------------------------------------------
+// class stuff
+//-------------------------------------------------------------------------
+
+class TenantSelector : public PolicySelector
+{
+public:
+    TenantSelector(const PolicySelectorApi*, std::vector<TenantSelection>&);
+    ~TenantSelector() override;
+
+    void show() const override;
+
+    bool select_default_policies(const _daq_pkt_hdr*, const SnortConfig*) override;
+
+protected:
+    std::vector<TenantSelection> policy_selections;
+    std::unordered_map<uint32_t, snort::PolicySelectUse*> policy_map;
+};
+
+TenantSelector::TenantSelector(const PolicySelectorApi* api_in, std::vector<TenantSelection>& psv)
+    : PolicySelector(api_in)
+{
+    policy_selections = std::move(psv);
+    for (auto i = policy_selections.rbegin(); i != policy_selections.rend(); ++i)
+    {
+        std::sort((*i).tenants.begin(), (*i).tenants.end());
+        for(auto j = (*i).tenants.begin(); j != (*i).tenants.end(); ++j)
+            policy_map[*j] = &(*i).use;
+    }
+}
+
+TenantSelector::~TenantSelector()
+{
+    for (TenantSelection& s : policy_selections)
+        s.clear();
+}
+
+void TenantSelector::show() const
+{
+    bool log_header = true;
+    for (const TenantSelection& s : policy_selections)
+    {
+        if (log_header)
+        {
+            ConfigLogger::log_option("policy_selections");
+            log_header = false;
+        }
+
+        std::string select;
+        std::string when = to_string(s.tenants);
+        if (when.empty())
+            select = "{ " + s.use.stringify() + " }";
+        else
+            select = "{ " + when + ", " + s.use.stringify() + " }";
+        ConfigLogger::log_list("", select.c_str(), "   ");
+    }
+}
+
+bool TenantSelector::select_default_policies(const _daq_pkt_hdr* pkthdr, const SnortConfig* sc)
+{
+    Profile profile(tenant_select_perf_stats);
+
+    tenant_select_stats.packets++;
+
+    // FIXIT-H replace address_space_id with tenant_id when it is added to the pkthdr
+    auto i = policy_map.find(static_cast<uint32_t>(pkthdr->address_space_id));
+    if (i != policy_map.end())
+    {
+        auto use = (*i).second;
+        set_network_policy(sc, use->network_index);
+        set_inspection_policy(sc, use->inspection_index);
+        set_ips_policy(sc, use->ips_index);
+        return true;
+    }
+    tenant_select_stats.no_match++;
+    return false;
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new TenantSelectorModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static PolicySelector* tenant_select_ctor(Module*);
+
+static void tenant_select_dtor(PolicySelector* p)
+{ delete p; }
+
+
+static const PolicySelectorApi select_api =
+{
+    {
+        PT_POLICY_SELECTOR,
+        sizeof(PolicySelectorApi),
+        POLICY_SELECTOR_API_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        TENANT_SELECT_NAME,
+        TENANT_SELECT_HELP,
+        mod_ctor,
+        mod_dtor
+    },
+    tenant_select_ctor,
+    tenant_select_dtor,
+};
+
+const BaseApi* ps_tenant_selector = &select_api.base;
+
+static PolicySelector* tenant_select_ctor(Module* m)
+{
+    TenantSelectorModule* mod = static_cast<TenantSelectorModule*>(m);
+    std::vector<TenantSelection>& psv = mod->get_policy_selections();
+    return new TenantSelector(&select_api, psv);
+}
+
diff --git a/src/policy_selectors/tenant_selector/tenant_selector_module.cc b/src/policy_selectors/tenant_selector/tenant_selector_module.cc
new file mode 100644 (file)
index 0000000..4a27346
--- /dev/null
@@ -0,0 +1,137 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// selector_module.cc author Ron Dempster <rdempste@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tenant_selector_module.h"
+
+#include "framework/module.h"
+#include "log/messages.h"
+#include "main/shell.h"
+#include "main/snort_config.h"
+#include "policy_selectors/parse_int_set.h"
+
+using namespace snort;
+using namespace std;
+
+THREAD_LOCAL PolicySelectStats tenant_select_stats;
+
+static const PegInfo select_pegs[] =
+{
+    { CountType::SUM, "packets", "packets evaluated" },
+    { CountType::SUM, "no_match", "selection evaluations that had no matches" },
+    { CountType::END, nullptr, nullptr }
+};
+
+//-------------------------------------------------------------------------
+// selector module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+    { "tenants", Parameter::PT_STRING, nullptr, nullptr,
+      "list of tenants to match" },
+
+    { "file", Parameter::PT_STRING, nullptr, nullptr,
+      "use configuration in given file" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+TenantSelectorModule::TenantSelectorModule()
+    : Module(TENANT_SELECT_NAME, TENANT_SELECT_HELP, s_params, true)
+{ }
+
+TenantSelectorModule::~TenantSelectorModule()
+{
+    policy_selections.clear();
+    selection.clear();
+}
+
+ProfileStats* TenantSelectorModule::get_profile() const
+{ return &tenant_select_perf_stats; }
+
+void TenantSelectorModule::add_policy_file(const char* name)
+{ policy_filename = name; }
+
+bool TenantSelectorModule::begin(const char* fqn, int idx, SnortConfig*)
+{
+    if ( idx && !strcmp(fqn, TENANT_SELECT_NAME) )
+    {
+        selection.clear();
+        policy_filename.clear();
+    }
+
+    return true;
+}
+
+bool TenantSelectorModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("tenants") )
+    {
+        if (!parse_int_set<uint32_t>(v, selection.tenants))
+            return false;
+    }
+
+    // use
+    else if ( v.is("file") )
+        add_policy_file(v.get_string());
+
+    return true;
+}
+
+bool TenantSelectorModule::end(const char* fqn, int idx, SnortConfig* sc)
+{
+    if ( !strcmp(fqn, TENANT_SELECT_NAME) && idx )
+    {
+        // Use validation
+        if ( policy_filename.empty() )
+        {
+            ParseError("Missing policy file name");
+            return false;
+        }
+
+        Shell* sh = new Shell(policy_filename.c_str());
+        auto policies = sc->policy_map->add_shell(sh, true);
+        selection.use.network_index = policies->network->policy_id;
+        selection.use.inspection_index = policies->inspection->policy_id;
+        selection.use.ips_index = policies->ips->policy_id;
+
+        // Store the policy filename for verbose output
+        selection.use.name = policy_filename;
+
+        commit_policy_selection();
+    }
+    return true;
+}
+
+void TenantSelectorModule::commit_policy_selection()
+{ policy_selections.emplace_back(selection); }
+
+vector<TenantSelection>& TenantSelectorModule::get_policy_selections()
+{ return policy_selections; }
+
+const PegInfo* TenantSelectorModule::get_pegs() const
+{ return select_pegs; }
+
+PegCount* TenantSelectorModule::get_counts() const
+{ return (PegCount*)&tenant_select_stats; }
+
diff --git a/src/policy_selectors/tenant_selector/tenant_selector_module.h b/src/policy_selectors/tenant_selector/tenant_selector_module.h
new file mode 100644 (file)
index 0000000..4da8796
--- /dev/null
@@ -0,0 +1,66 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// tenant_selector_module.h author Ron Dempster <rdempste@cisco.com>
+
+#ifndef TENANT_SELECTOR_MODULE_H
+#define TENANT_SELECTOR_MODULE_H
+
+// tenant selector management interface
+
+#include <string>
+#include <vector>
+
+#include "framework/module.h"
+#include "tenant_selection.h"
+
+#define TENANT_SELECT_NAME "tenant_selector"
+#define TENANT_SELECT_HELP "configure traffic processing based on tenants"
+
+extern THREAD_LOCAL snort::PolicySelectStats tenant_select_stats;
+extern THREAD_LOCAL snort::ProfileStats tenant_select_perf_stats;
+
+class TenantSelectorModule : public snort::Module
+{
+public:
+    TenantSelectorModule();
+    ~TenantSelectorModule() override;
+
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+    const PegInfo* get_pegs() const override;
+    PegCount* get_counts() const override;
+    snort::ProfileStats* get_profile() const override;
+
+    std::vector<TenantSelection>& get_policy_selections();
+
+    Usage get_usage() const override
+    { return GLOBAL; }
+
+private:
+    TenantSelection selection;
+    std::vector<TenantSelection> policy_selections;
+    std::string policy_filename;
+
+    void add_policy_file(const char* name);
+    void commit_policy_selection();
+};
+
+#endif
+
index 34942e3acbb22f7dab166a783054d28363c40afd..a40ae23a3ead621e357a4a0b85f88e58495502c1 100644 (file)
@@ -27,6 +27,8 @@
 #include "main/snort_types.h"
 #include "target_based/snort_protocols.h"
 
+// Event that is generated when a packet without a flow is processed
+#define PKT_WITHOUT_FLOW_EVENT  "non_flow_pkt"
 
 namespace snort
 {
index cd2582964bbb7e8c67832631155708c64ef10a38..825831089446809dc5f80cf28767be257865d68d 100644 (file)
@@ -101,7 +101,7 @@ THREAD_LOCAL SnortConfig* snort_conf = &s_conf;
 static std::vector<void *> s_state;
 static ScratchAllocator* scratcher = nullptr;
 
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 {
     state = &s_state;
     num_slots = 1;
index c28d64e4fc9de29dafbcab22e20aa293c6b26cc6..d2a477a0f11a547449bd2d0fa58dc7587d6824e1 100644 (file)
@@ -54,7 +54,7 @@ THREAD_LOCAL SnortConfig* snort_conf = &s_conf;
 
 static std::vector<void *> s_state;
 
-SnortConfig::SnortConfig(const SnortConfig* const)
+SnortConfig::SnortConfig(const SnortConfig* const, const char*)
 {
     state = &s_state;
     num_slots = 1;
index d9865ba57e649e83be893e4aca0fed2d2a618887..0ee658f9de1f81c655d2252afe561e640167d88e 100644 (file)
@@ -746,10 +746,14 @@ void NetflowInspector::show(const SnortConfig*) const
 {
     ConfigLogger::log_value("dump_file", config->dump_file);
     ConfigLogger::log_value("update_timeout", config->update_timeout);
-    std::once_flag d_once;
+    bool log_header = true;
     for ( auto const& d : config->device_rule_map )
     {
-        std::call_once(d_once, []{ ConfigLogger::log_option("rules"); });
+        if (log_header)
+        {
+            ConfigLogger::log_option("rules");
+            log_header = false;
+        }
         SfIpString addr_str;
         d.first.ntop(addr_str);
         for( auto const& r : d.second.exclude )
@@ -783,35 +787,36 @@ void NetflowInspector::stringify(std::ofstream& file_stream)
 
     for (auto elem : keys)
     {
+        NetflowSessionRecord& record = cache[elem];
         str = "Netflow Record #";
         str += std::to_string(++i);
         str += "\n";
 
         str += "    Initiator IP (Port): ";
         str += elem.ntop(ip_str);
-        str += " (" + std::to_string(cache[elem].initiator_port) + ")";
+        str += " (" + std::to_string(record.initiator_port) + ")";
 
         str += " -> Responder IP (Port): ";
-        str += cache[elem].responder_ip.ntop(ip_str);
-        str += " (" + std::to_string(cache[elem].responder_port) + ")";
+        str += record.responder_ip.ntop(ip_str);
+        str += " (" + std::to_string(record.responder_port) + ")";
         str += "\n";
 
         str += "    Protocol: ";
-        str += std::to_string(cache[elem].proto);
+        str += std::to_string(record.proto);
 
         str += " Packets: ";
-        str += std::to_string(cache[elem].initiator_pkts);
+        str += std::to_string(record.initiator_pkts);
         str += "\n";
 
         str += "    Source Mask: ";
-        str += std::to_string(cache[elem].nf_src_mask);
+        str += std::to_string(record.nf_src_mask);
 
         str += " Destination Mask: ";
-        str += std::to_string(cache[elem].nf_dst_mask);
+        str += std::to_string(record.nf_dst_mask);
         str += "\n";
 
         str += "    Next Hop IP: ";
-        str += cache[elem].next_hop_ip.ntop(ip_str);
+        str += record.next_hop_ip.ntop(ip_str);
         str += "\n";
 
         str += "------\n";
index 0446932e0ecae347e2cdf29700f68b84b6111d5c..7b9d5f3fe0eb6806d37437ae878b6009c041460d 100644 (file)
@@ -249,26 +249,25 @@ inline bool SfIp::_is_equals(const SfIp& rhs) const
     return false;
 }
 
-// FIXIT-L: when comparing ip4 vs ip6 we have !(ip4 < ip6) and !(ip6 < ip4).
-// This may be OK in some cases, but will not work e.g. on a binary tree
-// (stl::map) with SfIp as keys, whose implementation relies only on "<".
-// This affects SfIp::less_than() and SfIp::greater_than().
 inline bool SfIp::_is_lesser(const SfIp& rhs) const
 {
-    if (is_ip4())
-    {
-        return (rhs.is_ip4() &&
-               (htonl(ip32[3]) < htonl(rhs.ip32[3])));
-    }
-    else if (is_ip6())
-    {
-        return (rhs.is_ip6() &&
-               (htonl(ip32[0]) < htonl(rhs.ip32[0])) &&
-               (htonl(ip32[1]) < htonl(rhs.ip32[1])) &&
-               (htonl(ip32[2]) < htonl(rhs.ip32[2])) &&
-               (htonl(ip32[3]) < htonl(rhs.ip32[3])));
-    }
-    return false;
+    if (is_ip4() && rhs.is_ip4())
+        return ntohl(ip32[3]) < ntohl(rhs.ip32[3]);
+    uint32_t a = ntohl(ip32[0]);
+    uint32_t b = ntohl(rhs.ip32[0]);
+    if (a != b)
+        return a < b;
+    a = ntohl(ip32[1]);
+    b = ntohl(rhs.ip32[1]);
+    if (a != b)
+        return a < b;
+    a = ntohl(ip32[2]);
+    b = ntohl(rhs.ip32[2]);
+    if (a != b)
+        return a < b;
+    a = ntohl(ip32[3]);
+    b = ntohl(rhs.ip32[3]);
+    return a < b;
 }
 
 inline bool SfIp::equals(const SfIp& rhs, bool match_unset) const
index 95899fced2f731309dfdd987a6d764a0086c2e95..0b0d64898c1d8a652899655e1baafd7b2cae93ee 100644 (file)
@@ -756,7 +756,6 @@ static Packet* get_packet(Flow* flow, uint32_t flags, bool c2s)
     const SnortConfig* sc = SnortConfig::get_conf();
     set_inspection_policy(sc, flow->inspection_policy_id);
     set_ips_policy(sc, flow->ips_policy_id);
-    set_network_policy(sc, flow->network_policy_id);
 
     return p;
 }