From: Russ Combs (rucombs) Date: Tue, 30 Nov 2021 21:39:53 +0000 (+0000) Subject: Pull request #3142: framework: add a traffic policy and data bus to the network polic... X-Git-Tag: 3.1.18.0~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e25b22283d307a8eb43bfee73938458b630f1ce;p=thirdparty%2Fsnort3.git Pull request #3142: framework: 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 Merge in SNORT/snort3 from ~RDEMPSTE/snort3:tenant to master Squashed commit of the following: commit c998980c574e3da4fd7fafc79e03fbb538a18a2a Author: Ron Dempster (rdempste) 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. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8d26c71e..e795441dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 $ $ $ + $ $ $ $ @@ -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} ) diff --git a/src/decompress/file_olefile.cc b/src/decompress/file_olefile.cc index 146a73972..be3c62188 100644 --- a/src/decompress/file_olefile.cc +++ b/src/decompress/file_olefile.cc @@ -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); diff --git a/src/detection/regex_offload.h b/src/detection/regex_offload.h index 3074594f0..b4a1dc5eb 100644 --- a/src/detection/regex_offload.h +++ b/src/detection/regex_offload.h @@ -30,7 +30,6 @@ #include #include -#include #include namespace snort diff --git a/src/flow/flow.h b/src/flow/flow.h index 93b563977..d3103c603 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -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; diff --git a/src/flow/flow_control.cc b/src/flow/flow_control.cc index f51858faf..53e6961de 100644 --- a/src/flow/flow_control.cc +++ b/src/flow/flow_control.cc @@ -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; } diff --git a/src/flow/test/flow_cache_test.cc b/src/flow/test/flow_cache_test.cc index dc9276aaa..2ad995ce8 100644 --- a/src/flow/test/flow_cache_test.cc +++ b/src/flow/test/flow_cache_test.cc @@ -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; diff --git a/src/flow/test/flow_control_test.cc b/src/flow/test/flow_control_test.cc index d828b1596..5f3ae5ee0 100644 --- a/src/flow/test/flow_control_test.cc +++ b/src/flow/test/flow_control_test.cc @@ -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; diff --git a/src/flow/test/flow_stash_test.cc b/src/flow/test/flow_stash_test.cc index 2262e595d..855c7272b 100644 --- a/src/flow/test/flow_stash_test.cc +++ b/src/flow/test/flow_stash_test.cc @@ -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; } diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index f65de45c6..6499cc522 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -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 diff --git a/src/framework/base_api.h b/src/framework/base_api.h index d0715f032..3186b06ba 100644 --- a/src/framework/base_api.h +++ b/src/framework/base_api.h @@ -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 diff --git a/src/framework/data_bus.cc b/src/framework/data_bus.cc index 3e41b9033..585019b88 100644 --- a/src/framework/data_bus.cc +++ b/src/framework/data_bus.cc @@ -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) diff --git a/src/framework/data_bus.h b/src/framework/data_bus.h index 259324405..1707fa69a 100644 --- a/src/framework/data_bus.h +++ b/src/framework/data_bus.h @@ -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); diff --git a/src/framework/inspector.cc b/src/framework/inspector.cc index 4c9f0b114..636a37330 100644 --- a/src/framework/inspector.cc +++ b/src/framework/inspector.cc @@ -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 index 000000000..1be0b480d --- /dev/null +++ b/src/framework/policy_selector.h @@ -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 + +#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 + +#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 + diff --git a/src/framework/test/data_bus_test.cc b/src/framework/test/data_bus_test.cc index fb97af2c9..c3cda1973 100644 --- a/src/framework/test/data_bus_test.cc +++ b/src/framework/test/data_bus_test.cc @@ -27,6 +27,7 @@ #include #include +#include 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(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); diff --git a/src/hash/test/ghash_test.cc b/src/hash/test/ghash_test.cc index eeebeeb8d..2d13efcaa 100644 --- a/src/hash/test/ghash_test.cc +++ b/src/hash/test/ghash_test.cc @@ -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; diff --git a/src/hash/test/xhash_test.cc b/src/hash/test/xhash_test.cc index 7e51ae6e3..028cc367c 100644 --- a/src/hash/test/xhash_test.cc +++ b/src/hash/test/xhash_test.cc @@ -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; diff --git a/src/hash/test/zhash_test.cc b/src/hash/test/zhash_test.cc index 50fe1e54c..9cb3654e7 100644 --- a/src/hash/test/zhash_test.cc +++ b/src/hash/test/zhash_test.cc @@ -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; diff --git a/src/helpers/test/hyper_search_test.cc b/src/helpers/test/hyper_search_test.cc index 507148d70..0e6b77c13 100644 --- a/src/helpers/test/hyper_search_test.cc +++ b/src/helpers/test/hyper_search_test.cc @@ -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; diff --git a/src/ips_options/test/ips_regex_test.cc b/src/ips_options/test/ips_regex_test.cc index 8f901883e..76e7ef530 100644 --- a/src/ips_options/test/ips_regex_test.cc +++ b/src/ips_options/test/ips_regex_test.cc @@ -56,7 +56,7 @@ THREAD_LOCAL SnortConfig* snort_conf = &s_conf; static std::vector s_state; static ScratchAllocator* scratcher = nullptr; -SnortConfig::SnortConfig(const SnortConfig* const) +SnortConfig::SnortConfig(const SnortConfig* const, const char*) { state = &s_state; num_slots = 1; diff --git a/src/main/analyzer.cc b/src/main/analyzer.cc index 5891e2149..08b810c65 100644 --- a/src/main/analyzer.cc +++ b/src/main/analyzer.cc @@ -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); diff --git a/src/main/policy.cc b/src/main/policy.cc index 900626195..8213f7e00 100644 --- a/src/main/policy.cc +++ b/src/main/policy.cc @@ -23,8 +23,11 @@ #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(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 PolicyMap::add_shell(Shell* sh) +std::shared_ptr 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(inspection_policy.back(), - ips_policy.back(), network_policy.back()); + return shell_map[sh] = std::make_shared(ip, + ips_policy.back(), new_network_policy); } std::shared_ptr 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; -} - diff --git a/src/main/policy.h b/src/main/policy.h index 38d57b16a..38f4b0d20 100644 --- a/src/main/policy.h +++ b/src/main/policy.h @@ -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 add_shell(Shell*); + std::shared_ptr add_shell(Shell*, bool include_network); std::shared_ptr 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 diff --git a/src/main/snort.cc b/src/main/snort.cc index ba2493982..2fdea0fbe 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -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 ) { diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 63dc1a2cf..aab108c3a 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -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)); diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 8f7d85681..8e0bc59d7 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -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 diff --git a/src/main/thread_config.cc b/src/main/thread_config.cc index 9e52ab3b5..91664bc14 100644 --- a/src/main/thread_config.cc +++ b/src/main/thread_config.cc @@ -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]") diff --git a/src/managers/CMakeLists.txt b/src/managers/CMakeLists.txt index c5b024b82..3d502019e 100644 --- a/src/managers/CMakeLists.txt +++ b/src/managers/CMakeLists.txt @@ -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 diff --git a/src/managers/inspector_manager.cc b/src/managers/inspector_manager.cc index c02a2586e..613747367 100644 --- a/src/managers/inspector_manager.cc +++ b/src/managers/inspector_manager.cc @@ -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::iterator&); + +void FrameworkPolicy::handle_new_reenabled(SnortConfig* sc, bool new_ins, bool reenabled_ins) +{ + std::vector::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::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::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::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::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& 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 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 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 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 static inline void execute( - Packet* p, PHInstance** prep, unsigned num) + Packet* p, PHInstance* const * prep, unsigned num) { Stopwatch 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(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(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(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(p, tp->packet.vec, tp->packet.num); + + if ( p->disable_inspect ) + return; if ( !p->flow ) { - if ( fp_dft != fp ) - ::execute(p, fp_dft->first.vec, fp_dft->first.num); - ::execute(p, fp->first.vec, fp->first.num); + ::execute(p, tp->first.vec, tp->first.num); if ( p->disable_inspect ) return; - if (fp_dft != fp) - ::execute(p, fp_dft->network.vec, fp_dft->network.num); ::execute(p, fp->network.vec, fp->network.num); if ( p->disable_inspect ) return; - ::execute(p, fp_dft->control.vec, fp_dft->control.num); + ::execute(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(p, fp_dft->first.vec, fp_dft->first.num); - ::execute(p, fp->first.vec, fp->first.num); + ::execute(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(p, fp_dft->network.vec, fp_dft->network.num); ::execute(p, fp->network.vec, fp->network.num); - } if ( p->disable_inspect ) return; @@ -1303,7 +1598,7 @@ void InspectorManager::internal_execute(Packet* p) full_inspection(p); if ( !p->disable_inspect and !p->flow->is_inspection_disabled() ) - ::execute(p, fp_dft->control.vec, fp_dft->control.num); + ::execute(p, tp->control.vec, tp->control.num); } if ( T ) diff --git a/src/managers/inspector_manager.h b/src/managers/inspector_manager.h index 75150c8af..45b684a49 100644 --- a/src/managers/inspector_manager.h +++ b/src/managers/inspector_manager.h @@ -23,11 +23,15 @@ // Factory for Inspectors. // Also provides packet evaluation. +#include + #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 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 static void full_inspection(Packet*); template static void internal_execute(Packet*); + static void sort_inspector_list(const InspectorList* il, + std::map& sorted_ilist); }; } #endif diff --git a/src/managers/module_manager.cc b/src/managers/module_manager.cc index f8cc24419..069d3dd4d 100644 --- a/src/managers/module_manager.cc +++ b/src/managers/module_manager.cc @@ -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 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); diff --git a/src/managers/plugin_manager.cc b/src/managers/plugin_manager.cc index 5cafa4c04..14ae9f28d 100644 --- a/src/managers/plugin_manager.cc +++ b/src/managers/plugin_manager.cc @@ -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 index 000000000..45085e3af --- /dev/null +++ b/src/managers/policy_selector_manager.cc @@ -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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "policy_selector_manager.h" + +#include +#include + +#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 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 index 000000000..27bc5fddc --- /dev/null +++ b/src/managers/policy_selector_manager.h @@ -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 + +#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 + diff --git a/src/network_inspectors/appid/appid_inspector.cc b/src/network_inspectors/appid/appid_inspector.cc index 78294caba..28bcfa6d3 100644 --- a/src/network_inspectors/appid/appid_inspector.cc +++ b/src/network_inspectors/appid/appid_inspector.cc @@ -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; } diff --git a/src/network_inspectors/binder/bind_module.cc b/src/network_inspectors/binder/bind_module.cc index 06611dd0d..5f51665e4 100644 --- a/src/network_inspectors/binder/bind_module.cc +++ b/src/network_inspectors/binder/bind_module.cc @@ -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 -static bool parse_int_set(const Value& v, unordered_set& set) +static bool parse_int_set(const snort::Value& v, std::unordered_set& 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::max() ) + if ( n > static_cast(std::numeric_limits::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(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; } diff --git a/src/network_inspectors/binder/bind_module.h b/src/network_inspectors/binder/bind_module.h index 24642a76c..426226229 100644 --- a/src/network_inspectors/binder/bind_module.h +++ b/src/network_inspectors/binder/bind_module.h @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// bind_module.cc author Russ Combs +// bind_module.h author Russ Combs #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; diff --git a/src/network_inspectors/binder/binder.cc b/src/network_inspectors/binder/binder.cc index c66569c12..e3ba2d873 100644 --- a/src/network_inspectors/binder/binder.cc +++ b/src/network_inspectors/binder/binder.cc @@ -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(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(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; diff --git a/src/network_inspectors/binder/binding.cc b/src/network_inspectors/binder/binding.cc index 665feb040..459e4af06 100644 --- a/src/network_inspectors/binder/binding.cc +++ b/src/network_inspectors/binder/binding.cc @@ -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; } diff --git a/src/network_inspectors/binder/binding.h b/src/network_inspectors/binder/binding.h index 3ff734d0e..c9b705ef7 100644 --- a/src/network_inspectors/binder/binding.h +++ b/src/network_inspectors/binder/binding.h @@ -60,6 +60,8 @@ struct BindWhen std::unordered_set addr_spaces; + std::unordered_set 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 diff --git a/src/network_inspectors/normalize/norm_module.h b/src/network_inspectors/normalize/norm_module.h index eb4f250a7..3b08e5e1e 100644 --- a/src/network_inspectors/normalize/norm_module.h +++ b/src/network_inspectors/normalize/norm_module.h @@ -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*); diff --git a/src/network_inspectors/perf_monitor/perf_monitor.cc b/src/network_inspectors/perf_monitor/perf_monitor.cc index 96268ef67..e7d75b992 100644 --- a/src/network_inspectors/perf_monitor/perf_monitor.cc +++ b/src/network_inspectors/perf_monitor/perf_monitor.cc @@ -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(); } diff --git a/src/network_inspectors/reputation/reputation_inspect.cc b/src/network_inspectors/reputation/reputation_inspect.cc index 7e12c6573..656158608 100644 --- a/src/network_inspectors/reputation/reputation_inspect.cc +++ b/src/network_inspectors/reputation/reputation_inspect.cc @@ -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; } diff --git a/src/network_inspectors/reputation/reputation_module.h b/src/network_inspectors/reputation/reputation_module.h index 766052d8b..2e767297e 100644 --- a/src/network_inspectors/reputation/reputation_module.h +++ b/src/network_inspectors/reputation/reputation_module.h @@ -56,9 +56,6 @@ public: ReputationConfig* get_data(); - Usage get_usage() const override - { return GLOBAL; } - private: ReputationConfig* conf; }; diff --git a/src/network_inspectors/rna/rna_inspector.cc b/src/network_inspectors/rna/rna_inspector.cc index 92e1d9322..3ee97c10e 100644 --- a/src/network_inspectors/rna/rna_inspector.cc +++ b/src/network_inspectors/rna/rna_inspector.cc @@ -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) ) diff --git a/src/network_inspectors/rna/test/rna_module_stubs.h b/src/network_inspectors/rna/test/rna_module_stubs.h index 6c9a7b8b3..7064e8175 100644 --- a/src/network_inspectors/rna/test/rna_module_stubs.h +++ b/src/network_inspectors/rna/test/rna_module_stubs.h @@ -38,7 +38,7 @@ void Module::show_interval_stats(std::vector + $ + 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 index 000000000..7ff24bc71 --- /dev/null +++ b/src/policy_selectors/address_space_selector/CMakeLists.txt @@ -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 index 000000000..b9adce63b --- /dev/null +++ b/src/policy_selectors/address_space_selector/address_space_selection.cc @@ -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 + +#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 index 000000000..71a614669 --- /dev/null +++ b/src/policy_selectors/address_space_selector/address_space_selection.h @@ -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 + +#ifndef ADDRESS_SPACE_SELECTION_H +#define ADDRESS_SPACE_SELECTION_H + +// Evaluation elements for selecting policies based on address space + +#include + +#include "framework/policy_selector.h" + +struct AddressSpaceSelection +{ + std::vector 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 index 000000000..11a51c6be --- /dev/null +++ b/src/policy_selectors/address_space_selector/address_space_selector.cc @@ -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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#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& as) +{ + std::string when; + + if (!as.empty()) + { + auto addr_spaces = int_set_to_string(as); + when += "addr_spaces = " + addr_spaces; + } + + return when; +} + +//------------------------------------------------------------------------- +// class stuff +//------------------------------------------------------------------------- + +class AddressSpaceSelector : public PolicySelector +{ +public: + AddressSpaceSelector(const PolicySelectorApi*, std::vector&); + ~AddressSpaceSelector() override; + + void show() const override; + + bool select_default_policies(const _daq_pkt_hdr*, const SnortConfig*) override; + +protected: + std::vector policy_selections; + std::unordered_map policy_map; +}; + +AddressSpaceSelector::AddressSpaceSelector(const PolicySelectorApi* api_in, + std::vector& 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(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(m); + std::vector& 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 index 000000000..4ff647b01 --- /dev/null +++ b/src/policy_selectors/address_space_selector/address_space_selector_module.cc @@ -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 + +#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(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& 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 index 000000000..858fb2383 --- /dev/null +++ b/src/policy_selectors/address_space_selector/address_space_selector_module.h @@ -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 + +#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& get_policy_selections(); + + Usage get_usage() const override + { return GLOBAL; } + +private: + AddressSpaceSelection selection; + std::vector 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 index 000000000..7330e67b6 --- /dev/null +++ b/src/policy_selectors/address_space_selector/dev_notes.txt @@ -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 index 000000000..ed51ac8c8 --- /dev/null +++ b/src/policy_selectors/dev_notes.txt @@ -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 index 000000000..e84df2039 --- /dev/null +++ b/src/policy_selectors/int_set_to_string.h @@ -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 + +#ifndef INT_SET_TO_STRING_H +#define INT_SET_TO_STRING_H + +// used to format configuration for output in show methods + +#include +#include +#include +#include + +template +static std::string int_set_to_string(const std::vector& 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 index 000000000..e976b8a5a --- /dev/null +++ b/src/policy_selectors/parse_int_set.h @@ -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 + +#ifndef PARSE_INT_SET_H +#define PARSE_INT_SET_H + +// used to parse an int set + +#include +#include +#include +#include +#include +#include + +#include "framework/value.h" + +template +static bool parse_int_set(const snort::Value& v, std::vector& 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::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 index 000000000..aebecc3be --- /dev/null +++ b/src/policy_selectors/policy_selectors.cc @@ -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 index 000000000..f4de76a79 --- /dev/null +++ b/src/policy_selectors/policy_selectors.h @@ -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 index 000000000..f132021a2 --- /dev/null +++ b/src/policy_selectors/tenant_selector/CMakeLists.txt @@ -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 index 000000000..561bcfcc8 --- /dev/null +++ b/src/policy_selectors/tenant_selector/dev_notes.txt @@ -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 index 000000000..e562d3ce5 --- /dev/null +++ b/src/policy_selectors/tenant_selector/tenant_selection.cc @@ -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 + +#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 index 000000000..b1fd6359a --- /dev/null +++ b/src/policy_selectors/tenant_selector/tenant_selection.h @@ -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 + +#ifndef TENANT_SELECTION_H +#define TENANT_SELECTION_H + +// Evaluation elements for selecting policies based on tenant + +#include + +#include "framework/policy_selector.h" + +struct TenantSelection +{ + std::vector 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 index 000000000..643d280fe --- /dev/null +++ b/src/policy_selectors/tenant_selector/tenant_selector.cc @@ -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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#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& t) +{ + std::string when; + + if (!t.empty()) + { + auto tenants = int_set_to_string(t); + when += "tenants = " + tenants; + } + + return when; +} + +//------------------------------------------------------------------------- +// class stuff +//------------------------------------------------------------------------- + +class TenantSelector : public PolicySelector +{ +public: + TenantSelector(const PolicySelectorApi*, std::vector&); + ~TenantSelector() override; + + void show() const override; + + bool select_default_policies(const _daq_pkt_hdr*, const SnortConfig*) override; + +protected: + std::vector policy_selections; + std::unordered_map policy_map; +}; + +TenantSelector::TenantSelector(const PolicySelectorApi* api_in, std::vector& 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(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(m); + std::vector& 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 index 000000000..4a273464d --- /dev/null +++ b/src/policy_selectors/tenant_selector/tenant_selector_module.cc @@ -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 + +#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(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& 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 index 000000000..4da879605 --- /dev/null +++ b/src/policy_selectors/tenant_selector/tenant_selector_module.h @@ -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 + +#ifndef TENANT_SELECTOR_MODULE_H +#define TENANT_SELECTOR_MODULE_H + +// tenant selector management interface + +#include +#include + +#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& get_policy_selections(); + + Usage get_usage() const override + { return GLOBAL; } + +private: + TenantSelection selection; + std::vector policy_selections; + std::string policy_filename; + + void add_policy_file(const char* name); + void commit_policy_selection(); +}; + +#endif + diff --git a/src/protocols/packet.h b/src/protocols/packet.h index 34942e3ac..a40ae23a3 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -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 { diff --git a/src/search_engines/test/hyperscan_test.cc b/src/search_engines/test/hyperscan_test.cc index cd2582964..825831089 100644 --- a/src/search_engines/test/hyperscan_test.cc +++ b/src/search_engines/test/hyperscan_test.cc @@ -101,7 +101,7 @@ THREAD_LOCAL SnortConfig* snort_conf = &s_conf; static std::vector s_state; static ScratchAllocator* scratcher = nullptr; -SnortConfig::SnortConfig(const SnortConfig* const) +SnortConfig::SnortConfig(const SnortConfig* const, const char*) { state = &s_state; num_slots = 1; diff --git a/src/search_engines/test/search_tool_test.cc b/src/search_engines/test/search_tool_test.cc index c28d64e4f..d2a477a0f 100644 --- a/src/search_engines/test/search_tool_test.cc +++ b/src/search_engines/test/search_tool_test.cc @@ -54,7 +54,7 @@ THREAD_LOCAL SnortConfig* snort_conf = &s_conf; static std::vector s_state; -SnortConfig::SnortConfig(const SnortConfig* const) +SnortConfig::SnortConfig(const SnortConfig* const, const char*) { state = &s_state; num_slots = 1; diff --git a/src/service_inspectors/netflow/netflow.cc b/src/service_inspectors/netflow/netflow.cc index d9865ba57..0ee658f9d 100644 --- a/src/service_inspectors/netflow/netflow.cc +++ b/src/service_inspectors/netflow/netflow.cc @@ -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"; diff --git a/src/sfip/sf_ip.h b/src/sfip/sf_ip.h index 0446932e0..7b9d5f3fe 100644 --- a/src/sfip/sf_ip.h +++ b/src/sfip/sf_ip.h @@ -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 diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index 95899fced..0b0d64898 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -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; }