From 2414d8b9d22c6e977fa1babd40cc6b596d0ba8c1 Mon Sep 17 00:00:00 2001 From: "Michael Altizer (mialtize)" Date: Fri, 26 Mar 2021 19:20:37 +0000 Subject: [PATCH] Merge pull request #2800 in SNORT/snort3 from ~BBANTWAL/snort3:ips_actions to master Squashed commit of the following: commit 9ea4a671998c7c5270d91ca26ee1cca8228030ff Author: Bhagya Tholpady Date: Fri Mar 26 12:08:39 2021 -0400 actions: dynamically construct the default eval order for all the loaded ips actions commit 39c59c2dd92c4ad3b1ed1d3ac4914c511b5a7edf Author: Bhagya Tholpady Date: Sun Mar 21 13:07:52 2021 -0400 detection: Update the rtn's listHead to reflect the new action set in the rule state commit 628648057da9d38fc7c212a209427623700efaa3 Author: Bhagya Tholpady Date: Thu Mar 25 09:48:18 2021 -0400 rate_filter: Get the available ips actions dynamically to configure the new_action commit 15c13d82d360fc37aa83ebf30dea71b2877b5a14 Author: Bhagya Tholpady Date: Wed Mar 17 12:13:06 2021 -0400 snort_config: Remove is_active_enabled and set_active_enabled functions commit fce81b9ed016b3aa118371fec104cc3d62c5109b Author: Bhagya Tholpady Date: Tue Mar 16 14:26:49 2021 -0400 snort2lua: delete conversion of disable_replace option commit 13ad5f9b33620576f11483058425fc8b43031acc Author: Bhagya Tholpady Date: Tue Mar 9 11:33:31 2021 -0500 actions: Make all IPS actions pluggable * All actions, including the previously "built-in" actions, have been refactored into a set of equal IPS action plugins. Each IPS action has an immediate effect and may or may not contain an active response to be carried out as a delayed action. * The reset and reject IPS actions have been merged into a single reject IPS action. The reject IPS action can no longer be built as a dynamic plugin. * All IPS actions will be instantiated in a default state in each IPS policy where they have not been otherwise explicitly configured via a module. * The rewrite IPS action is no longer configurable and has lost its module. Its active response priority has been corrected to AP_MODIFY. * Rate filter thresholding has been corrected to apply to any IPS action that drops traffic. * Rule evaluation action ordering has been expanded to include all IPS actions, static and dynamic. Dynamic actions will currently default to the lowest priority. --- doc/user/active.txt | 14 +- lua/snort.lua | 2 - src/actions/CMakeLists.txt | 8 +- src/actions/act_alert.cc | 88 ++++++++++++ src/actions/act_block.cc | 92 ++++++++++++ src/actions/act_drop.cc | 92 ++++++++++++ src/actions/act_log.cc | 88 ++++++++++++ src/actions/act_pass.cc | 91 ++++++++++++ src/actions/act_react.cc | 133 ++++++++++++------ src/actions/act_reject.cc | 78 +++++++--- src/actions/act_replace.cc | 88 ++++-------- src/actions/actions.cc | 114 +++------------ src/actions/actions.h | 24 ++-- src/actions/dev_notes.txt | 47 ++++--- src/actions/ips_actions.cc | 14 +- src/detection/detection_engine.cc | 3 +- src/detection/detection_engine.h | 3 +- src/detection/detection_util.cc | 7 +- src/detection/detection_util.h | 3 +- src/detection/fp_detect.cc | 46 +++--- src/detection/rules.cc | 11 +- src/detection/rules.h | 7 +- src/detection/signature.cc | 7 +- src/detection/treenodes.h | 2 +- src/events/event_queue.h | 2 - src/file_api/file_module.cc | 6 +- src/filters/sfrf.cc | 11 +- src/filters/sfrf.h | 2 +- src/filters/sfrf_test.cc | 4 +- src/framework/ips_action.h | 36 ++++- src/main/modules.cc | 24 ++-- src/main/policy.cc | 2 +- src/main/policy.h | 7 +- src/main/snort.cc | 2 +- src/main/snort_config.cc | 7 +- src/main/snort_config.h | 11 +- src/managers/action_manager.cc | 103 ++++++++++++-- src/managers/action_manager.h | 12 +- src/packet_io/active.cc | 25 ++-- src/packet_io/active_action.h | 22 +-- src/parser/parse_conf.cc | 26 +--- src/parser/parse_conf.h | 1 - src/parser/parse_rule.cc | 13 +- src/parser/parser.cc | 19 +-- src/parser/parser.h | 3 +- .../test/payload_injector_test.cc | 2 +- src/piglet_plugins/pp_inspector_iface.cc | 2 +- src/piglet_plugins/pp_ips_action_iface.cc | 2 +- .../test/http2_hpack_int_decode_test.cc | 2 +- .../test/http2_hpack_string_decode_test.cc | 2 +- .../http_inspect/test/http_module_test.cc | 2 +- .../test/http_transaction_test.cc | 2 +- .../http_inspect/test/http_uri_norm_test.cc | 2 +- src/service_inspectors/smtp/smtp_module.cc | 5 +- .../snort2lua/config_states/config_deleted.cc | 14 ++ .../config_states/config_no_option.cc | 14 -- tools/snort2lua/rule_states/rule_replace.cc | 4 - 57 files changed, 975 insertions(+), 478 deletions(-) create mode 100644 src/actions/act_alert.cc create mode 100644 src/actions/act_block.cc create mode 100644 src/actions/act_drop.cc create mode 100644 src/actions/act_log.cc create mode 100644 src/actions/act_pass.cc diff --git a/doc/user/active.txt b/doc/user/active.txt index 5ea2d0475..2acaf189b 100644 --- a/doc/user/active.txt +++ b/doc/user/active.txt @@ -24,7 +24,9 @@ plugins: react = { } reject = { } - rewrite = { } + +When these active responses are not configured the default configuration +is used. Active responses will be performed for reject, react or rewrite IPS rule actions, and response packets are encoded based on the triggering packet. @@ -164,7 +166,6 @@ option in the rules. For example: - rewrite = { } local_rules = [[ rewrite tcp 10.1.1.87 any -> 10.1.1.0/24 80 @@ -183,12 +184,3 @@ For example: this rule replaces "index.php" with "indax.php", and rewrite action updates that packet. - -to enable rewrite action: - - rewrite = { } - -the replace operation can be disabled by changing the configuration: - - rewrite = { disable_replace = true } - diff --git a/lua/snort.lua b/lua/snort.lua index dc9df2c8a..e0b5a3d3d 100644 --- a/lua/snort.lua +++ b/lua/snort.lua @@ -178,8 +178,6 @@ ips = variables = default_variables } -rewrite = { } - -- use these to configure additional rule actions -- react = { } -- reject = { } diff --git a/src/actions/CMakeLists.txt b/src/actions/CMakeLists.txt index f12a5a84e..acb3102ce 100644 --- a/src/actions/CMakeLists.txt +++ b/src/actions/CMakeLists.txt @@ -7,12 +7,17 @@ set (IPS_ACTION_SOURCES actions.cc ips_actions.cc ips_actions.h + act_alert.cc + act_block.cc + act_drop.cc + act_log.cc + act_pass.cc + act_reject.cc act_replace.cc ) set( PLUGIN_LIST act_react.cc - act_reject.cc ) if (STATIC_IPS_ACTIONS) @@ -28,7 +33,6 @@ else (STATIC_IPS_ACTIONS) ) add_dynamic_module(act_react ips_actions act_react.cc) - add_dynamic_module(act_reject ips_actions act_reject.cc) endif (STATIC_IPS_ACTIONS) diff --git a/src/actions/act_alert.cc b/src/actions/act_alert.cc new file mode 100644 index 000000000..a2b4e9e20 --- /dev/null +++ b/src/actions/act_alert.cc @@ -0,0 +1,88 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// act_alert.cc author Bhagya Tholpady + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "framework/ips_action.h" +#include "framework/module.h" +#include "protocols/packet.h" + +#include "actions.h" + +using namespace snort; + +#define s_name "alert" + +#define s_help \ + "generate alert on the current packet" + +//------------------------------------------------------------------------- +class AlertAction : public IpsAction +{ +public: + AlertAction() : IpsAction(s_name, nullptr) { } + + void exec(Packet*, const OptTreeNode* otn) override; +}; + +void AlertAction::exec(Packet* p, const OptTreeNode* otn) +{ + if ( otn ) + Actions::alert(p, otn); +} + +//------------------------------------------------------------------------- + +static IpsAction* alert_ctor(Module*) +{ return new AlertAction; } + +static void alert_dtor(IpsAction* p) +{ delete p; } + +static ActionApi alert_api +{ + { + PT_IPS_ACTION, + sizeof(ActionApi), + ACTAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + nullptr, // mod_ctor + nullptr, // mod_dtor + }, + IpsAction::IAP_ALERT, + nullptr, + nullptr, + nullptr, + nullptr, + alert_ctor, + alert_dtor +}; + +const BaseApi* act_alert[] = +{ + &alert_api.base, + nullptr +}; + diff --git a/src/actions/act_block.cc b/src/actions/act_block.cc new file mode 100644 index 000000000..7a910c308 --- /dev/null +++ b/src/actions/act_block.cc @@ -0,0 +1,92 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// act_block.cc author Bhagya Tholpady + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "framework/ips_action.h" +#include "framework/module.h" +#include "packet_io/active.h" +#include "protocols/packet.h" + +#include "actions.h" + +using namespace snort; + +#define s_name "block" + +#define s_help \ + "block current packet and all the subsequent packets in this flow" + +//------------------------------------------------------------------------- +class BlockAction : public IpsAction +{ +public: + BlockAction() : IpsAction(s_name, nullptr) { } + + void exec(Packet*, const OptTreeNode* otn) override; + bool drops_traffic() override { return true; } +}; + +void BlockAction::exec(Packet* p, const OptTreeNode* otn) +{ + p->active->block_session(p); + p->active->set_drop_reason("ips"); + if ( otn ) + Actions::alert(p, otn); +} + +//------------------------------------------------------------------------- + +static IpsAction* block_ctor(Module*) +{ return new BlockAction; } + +static void block_dtor(IpsAction* p) +{ delete p; } + +static ActionApi block_api +{ + { + PT_IPS_ACTION, + sizeof(ActionApi), + ACTAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + nullptr, // mod_ctor + nullptr, // mod_dtor + }, + IpsAction::IAP_BLOCK, + nullptr, + nullptr, + nullptr, + nullptr, + block_ctor, + block_dtor +}; + +const BaseApi* act_block[] = +{ + &block_api.base, + nullptr +}; + diff --git a/src/actions/act_drop.cc b/src/actions/act_drop.cc new file mode 100644 index 000000000..444720457 --- /dev/null +++ b/src/actions/act_drop.cc @@ -0,0 +1,92 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// act_drop.cc author Bhagya Tholpady + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "framework/ips_action.h" +#include "framework/module.h" +#include "packet_io/active.h" +#include "protocols/packet.h" + +#include "actions.h" + +using namespace snort; + +#define s_name "drop" + +#define s_help \ + "drop the current packet" + +//------------------------------------------------------------------------- +class DropAction : public IpsAction +{ +public: + DropAction() : IpsAction(s_name, nullptr) { } + + void exec(Packet*, const OptTreeNode* otn) override; + bool drops_traffic() override { return true; } +}; + +void DropAction::exec(Packet* p, const OptTreeNode* otn) +{ + p->active->drop_packet(p); + p->active->set_drop_reason("ips"); + if ( otn ) + Actions::alert(p, otn); +} + +//------------------------------------------------------------------------- + +static IpsAction* drop_ctor(Module*) +{ return new DropAction; } + +static void drop_dtor(IpsAction* p) +{ delete p; } + +static ActionApi drop_api +{ + { + PT_IPS_ACTION, + sizeof(ActionApi), + ACTAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + nullptr, // mod_ctor + nullptr, // mod_dtor + }, + IpsAction::IAP_DROP, + nullptr, + nullptr, + nullptr, + nullptr, + drop_ctor, + drop_dtor +}; + +const BaseApi* act_drop[] = +{ + &drop_api.base, + nullptr +}; + diff --git a/src/actions/act_log.cc b/src/actions/act_log.cc new file mode 100644 index 000000000..b230d6683 --- /dev/null +++ b/src/actions/act_log.cc @@ -0,0 +1,88 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// act_log.cc author Bhagya Tholpady + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "framework/ips_action.h" +#include "framework/module.h" +#include "protocols/packet.h" + +#include "actions.h" + +using namespace snort; + +#define s_name "log" + +#define s_help \ + "log the current packet" + +//------------------------------------------------------------------------- +class LogAction : public IpsAction +{ +public: + LogAction() : IpsAction(s_name, nullptr) { } + + void exec(Packet*, const OptTreeNode* otn) override; +}; + +void LogAction::exec(Packet* p, const OptTreeNode* otn) +{ + if ( otn ) + Actions::log(p, otn); +} + +//------------------------------------------------------------------------- + +static IpsAction* log_ctor(Module*) +{ return new LogAction; } + +static void log_dtor(IpsAction* p) +{ delete p; } + +static ActionApi log_api +{ + { + PT_IPS_ACTION, + sizeof(ActionApi), + ACTAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + nullptr, // mod_ctor + nullptr, // mod_dtor + }, + IpsAction::IAP_LOG, + nullptr, + nullptr, + nullptr, + nullptr, + log_ctor, + log_dtor +}; + +const BaseApi* act_log[] = +{ + &log_api.base, + nullptr +}; + diff --git a/src/actions/act_pass.cc b/src/actions/act_pass.cc new file mode 100644 index 000000000..6a86561d0 --- /dev/null +++ b/src/actions/act_pass.cc @@ -0,0 +1,91 @@ +//-------------------------------------------------------------------------- +// 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. +//-------------------------------------------------------------------------- +// act_pass.cc author Bhagya Tholpady + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "framework/ips_action.h" +#include "framework/module.h" +#include "protocols/packet.h" + +#include "actions.h" + +using namespace snort; + +#define s_name "pass" + +#define s_help \ + "mark the current packet as passed" + +//------------------------------------------------------------------------- +class PassAction : public IpsAction +{ +public: + PassAction() : IpsAction(s_name, nullptr) { } + + void exec(Packet*, const OptTreeNode*) override; +}; + +void PassAction::exec(Packet* p, const OptTreeNode* otn) +{ + if ( otn ) + { + Actions::pass(); + p->packet_flags |= PKT_PASS_RULE; + } +} + +//------------------------------------------------------------------------- + +static IpsAction* pass_ctor(Module*) +{ return new PassAction; } + +static void pass_dtor(IpsAction* p) +{ delete p; } + +static ActionApi pass_api +{ + { + PT_IPS_ACTION, + sizeof(ActionApi), + ACTAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + nullptr, // mod_ctor + nullptr, // mod_dtor + }, + IpsAction::IAP_PASS, + nullptr, + nullptr, + nullptr, + nullptr, + pass_ctor, + pass_dtor +}; + +const BaseApi* act_pass[] = +{ + &pass_api.base, + nullptr +}; + diff --git a/src/actions/act_react.cc b/src/actions/act_react.cc index 2a12018a9..64c862ec2 100644 --- a/src/actions/act_react.cc +++ b/src/actions/act_react.cc @@ -61,6 +61,8 @@ #include "utils/util.h" #include "utils/util_cstring.h" +#include "actions.h" + using namespace snort; using namespace HttpCommon; using namespace Http2Enums; @@ -93,7 +95,7 @@ static THREAD_LOCAL ProfileStats reactPerfStats; "\r\n" \ "\r\n" -THREAD_LOCAL const snort::Trace* react_trace = nullptr; +THREAD_LOCAL const Trace* react_trace = nullptr; class ReactData { @@ -127,57 +129,90 @@ private: std::string resp_buf; // response to send }; -class ReactAction : public snort::IpsAction +//------------------------------------------------------------------------- +// active action +//------------------------------------------------------------------------- + +class ReactActiveAction : public ActiveAction { public: - ReactAction(ReactData* c) - : IpsAction(s_name, ActionType::ACT_PROXY), config(c) + ReactActiveAction(ReactData* c) + : ActiveAction( ActionPriority::AP_PROXY ), config(c) { } - ~ReactAction() override - { delete config; } + void delayed_exec(Packet* p) override; - void exec(snort::Packet* p) override - { - Profile profile(reactPerfStats); +private: + void send(Packet* p); + ReactData* config; +}; - if ( p->active->is_reset_candidate(p) ) - send(p); - } +void ReactActiveAction::delayed_exec(Packet* p) +{ + Profile profile(reactPerfStats); -private: - void send(snort::Packet* p) + if ( p->active->is_reset_candidate(p) ) + send(p); +} + +void ReactActiveAction::send(Packet* p) +{ + InjectionControl control; + control.http_page = (const uint8_t*)config->get_resp_buf(); + control.http_page_len = config->get_buf_len(); + if (p->flow && p->flow->gadget && + (strcmp(p->flow->gadget->get_name(), "http2_inspect") == 0)) { - InjectionControl control; - control.http_page = (const uint8_t*)config->get_resp_buf(); - control.http_page_len = config->get_buf_len(); - if (p->flow && p->flow->gadget && - (strcmp(p->flow->gadget->get_name(), "http2_inspect") == 0)) + Http2FlowData* const session_data = + (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id); + assert(session_data != nullptr); + const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER; + if (session_data != nullptr) { - Http2FlowData* const session_data = - (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id); - assert(session_data != nullptr); - const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER; - if (session_data != nullptr) - { - control.stream_id = session_data->get_current_stream_id(source_id); - assert(control.stream_id != NO_STREAM_ID); - } + control.stream_id = session_data->get_current_stream_id(source_id); + assert(control.stream_id != NO_STREAM_ID); } - InjectionReturnStatus status = PayloadInjector::inject_http_payload(p, control); + } + InjectionReturnStatus status = PayloadInjector::inject_http_payload(p, control); #ifdef DEBUG_MSGS - if (status != INJECTION_SUCCESS) - debug_logf(react_trace, p, "Injection error: %s\n", - PayloadInjector::get_err_string(status)); + if (status != INJECTION_SUCCESS) + debug_logf(react_trace, p, "Injection error: %s\n", + PayloadInjector::get_err_string(status)); #else - UNUSED(status); + UNUSED(status); #endif - } +} + +//------------------------------------------------------------------------- +// ips action +//------------------------------------------------------------------------- + +class ReactAction : public IpsAction +{ +public: + ReactAction(ReactData* c) + : IpsAction(s_name, &react_act_action), config(c), react_act_action(c) + { } + + ~ReactAction() override + { delete config; } + + void exec(Packet*, const OptTreeNode* otn) override; + bool drops_traffic() override { return true; } private: ReactData* config; + ReactActiveAction react_act_action; }; +void ReactAction::exec(Packet* p, const OptTreeNode* otn) +{ + p->active->drop_packet(p); + p->active->set_drop_reason("ips"); + if ( otn ) + Actions::alert(p, otn); +} + //------------------------------------------------------------------------- // module //------------------------------------------------------------------------- @@ -205,19 +240,19 @@ public: Usage get_usage() const override { return DETECT; } - void set_trace(const snort::Trace* trace) const override + void set_trace(const Trace* trace) const override { react_trace = trace; } - const snort::TraceOption* get_trace_options() const override + const TraceOption* get_trace_options() const override { static const TraceOption react_trace_options(nullptr, 0, nullptr); return &react_trace_options; } -public: - std::string page; + std::string get_data(); private: + std::string page; bool getpage(const char* file); }; @@ -234,10 +269,9 @@ bool ReactModule::getpage(const char* file) return true; } -bool ReactModule::begin(const char*, int, SnortConfig* sc) +bool ReactModule::begin(const char*, int, SnortConfig*) { page.clear(); - sc->set_active_enabled(); return true; } @@ -249,6 +283,13 @@ bool ReactModule::set(const char*, Value& v, SnortConfig*) return true; } +std::string ReactModule::get_data() +{ + std::string tmp = page; + page.clear(); + return tmp; +} + //------------------------------------------------------------------------- // api methods //------------------------------------------------------------------------- @@ -261,10 +302,14 @@ static void mod_dtor(Module* m) static IpsAction* react_ctor(Module* p) { - ReactModule* m = (ReactModule*)p; - ReactData* rd = new ReactData(m->page); + std::string react_page; + if ( p ) + { + ReactModule* m = (ReactModule*)p; + react_page = m->get_data(); + } - return new ReactAction(rd); + return new ReactAction(new ReactData(react_page)); } static void react_dtor(IpsAction* p) @@ -284,7 +329,7 @@ static const ActionApi react_api = mod_ctor, mod_dtor }, - Actions::DROP, + IpsAction::IpsActionPriority(IpsAction::IAP_DROP + 1), nullptr, // pinit nullptr, // pterm nullptr, // tinit diff --git a/src/actions/act_reject.cc b/src/actions/act_reject.cc index f9eb2e315..69a56087b 100644 --- a/src/actions/act_reject.cc +++ b/src/actions/act_reject.cc @@ -54,6 +54,8 @@ #include "packet_io/active.h" #include "profiler/profiler.h" +#include "actions.h" + using namespace snort; #define s_name "reject" @@ -76,25 +78,21 @@ enum THREAD_LOCAL ProfileStats rejPerfStats; -class RejectAction : public snort::IpsAction +//------------------------------------------------------------------------- +// active action +//------------------------------------------------------------------------- + +class RejectActiveAction : public ActiveAction { public: - RejectAction(uint32_t f); - void exec(snort::Packet*) override; + RejectActiveAction(uint32_t f) : ActiveAction (ActionPriority::AP_RESET) , mask(f) { } + void delayed_exec(Packet*) override; private: uint32_t mask; }; -//------------------------------------------------------------------------- -// class methods -//------------------------------------------------------------------------- - -RejectAction::RejectAction(uint32_t f) : IpsAction(s_name, ActionType::ACT_RESET), mask(f) -{ } - - -void RejectAction::exec(Packet* p) +void RejectActiveAction::delayed_exec(Packet* p) { if ( !p->ptrs.ip_api.is_ip() ) return; @@ -148,6 +146,35 @@ void RejectAction::exec(Packet* p) act->send_unreach(p, UnreachResponse::PORT); } +//------------------------------------------------------------------------- +// ips action +//------------------------------------------------------------------------- + +class RejectAction : public IpsAction +{ +public: + RejectAction(uint32_t f = REJ_RST_BOTH); + + void exec(Packet*, const OptTreeNode* otn) override; + +private: + RejectActiveAction rej_act_action; +}; + +//------------------------------------------------------------------------- +// class methods +//------------------------------------------------------------------------- + +RejectAction::RejectAction(uint32_t f) : IpsAction(s_name, &rej_act_action) , rej_act_action(f) +{ } + +void RejectAction::exec(Packet* p, const OptTreeNode* otn) +{ + p->active->reset_session(p, get_active_action()); + if ( otn ) + Actions::alert(p, otn); +} + //------------------------------------------------------------------------- // module //------------------------------------------------------------------------- @@ -177,14 +204,15 @@ public: Usage get_usage() const override { return DETECT; } -public: + uint32_t get_data(); + +private: uint32_t flags; }; -bool RejectModule::begin(const char*, int, SnortConfig* sc) +bool RejectModule::begin(const char*, int, SnortConfig*) { flags = 0; - sc->set_active_enabled(); return true; } @@ -226,6 +254,11 @@ bool RejectModule::set(const char*, Value& v, SnortConfig*) return true; } +uint32_t RejectModule::get_data() +{ + return flags; +} + //------------------------------------------------------------------------- // api methods //------------------------------------------------------------------------- @@ -242,8 +275,13 @@ static void mod_dtor(Module* m) static IpsAction* rej_ctor(Module* p) { - RejectModule* m = (RejectModule*)p; - return new RejectAction(m->flags); + if ( p ) + { + RejectModule* m = (RejectModule*)p; + return new RejectAction(m->get_data()); + } + else + return new RejectAction(); } static void rej_dtor(IpsAction* p) @@ -265,7 +303,7 @@ static const ActionApi rej_api = mod_ctor, mod_dtor }, - Actions::RESET, + IpsAction::IAP_REJECT, nullptr, nullptr, nullptr, @@ -274,11 +312,7 @@ static const ActionApi rej_api = rej_dtor }; -#ifdef BUILDING_SO -SO_PUBLIC const BaseApi* snort_plugins[] = -#else const BaseApi* act_reject[] = -#endif { &rej_api.base, nullptr diff --git a/src/actions/act_replace.cc b/src/actions/act_replace.cc index 1ad01da12..05f1feddd 100644 --- a/src/actions/act_replace.cc +++ b/src/actions/act_replace.cc @@ -24,10 +24,11 @@ #include "detection/detection_engine.h" #include "framework/ips_action.h" #include "framework/module.h" -#include "main/snort_config.h" #include "packet_io/active.h" #include "protocols/packet.h" +#include "actions.h" + using namespace snort; #define s_name "rewrite" @@ -72,83 +73,46 @@ static void Replace_ModifyPacket(Packet* p) } //------------------------------------------------------------------------- -// replace module +// active action //------------------------------------------------------------------------- - -static const Parameter s_params[] = -{ - { "disable_replace", Parameter::PT_BOOL, nullptr, "false", - "disable replace of packet contents with rewrite rules" }, - - { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } -}; - -class ReplaceModule : public Module +class ReplaceActiveAction : public ActiveAction { public: - ReplaceModule() : Module(s_name, s_help, s_params) { } - bool set(const char*, Value&, SnortConfig*) override; - bool begin(const char*, int, SnortConfig*) override; - - Usage get_usage() const override - { return DETECT; } - -public: - bool disable_replace; + ReplaceActiveAction() : ActiveAction(ActionPriority::AP_MODIFY) { } + void delayed_exec(Packet*) override; }; -bool ReplaceModule::set(const char*, Value& v, SnortConfig*) +void ReplaceActiveAction::delayed_exec(Packet* p) { - if ( v.is("disable_replace") ) - disable_replace = v.get_bool(); - else - return false; - - return true; -} + if ( p->is_rebuilt() ) + return; -bool ReplaceModule::begin(const char*, int, SnortConfig* sc) -{ - disable_replace = false; - sc->set_active_enabled(); - return true; + Replace_ModifyPacket(p); } //------------------------------------------------------------------------- -class ReplaceAction : public snort::IpsAction +// ips action +//------------------------------------------------------------------------- +class ReplaceAction : public IpsAction { public: - ReplaceAction(bool disable_replace); + ReplaceAction() : IpsAction(s_name, &rep_act_action) { } + + void exec(Packet*, const OptTreeNode* otn) override; - void exec(snort::Packet*) override; private: - bool disable_replace = false; + ReplaceActiveAction rep_act_action; }; -ReplaceAction::ReplaceAction(bool dr) : - IpsAction(s_name, ACT_RESET) +void ReplaceAction::exec(Packet* p, const OptTreeNode* otn) { - disable_replace = dr; -} - -void ReplaceAction::exec(Packet* p) -{ - if ( p->is_rebuilt() || disable_replace ) - return; - - Replace_ModifyPacket(p); + Actions::alert(p, otn); } //------------------------------------------------------------------------- -static Module* mod_ctor() -{ return new ReplaceModule; } - -static void mod_dtor(Module* m) -{ delete m; } - -static IpsAction* rep_ctor(Module* m) -{ return new ReplaceAction( ((ReplaceModule*)m)->disable_replace); } +static IpsAction* rep_ctor(Module*) +{ return new ReplaceAction; } static void rep_dtor(IpsAction* p) { delete p; } @@ -164,10 +128,10 @@ static ActionApi rep_api API_OPTIONS, s_name, s_help, - mod_ctor, - mod_dtor + nullptr, // mod_ctor + nullptr, // mod_dtor }, - Actions::ALERT, + IpsAction::IAP_REWRITE, nullptr, nullptr, nullptr, @@ -176,11 +140,7 @@ static ActionApi rep_api rep_dtor }; -#ifdef BUILDING_SO -SO_PUBLIC const BaseApi* snort_plugins[] = -#else const BaseApi* act_replace[] = -#endif { &rep_api.base, nullptr diff --git a/src/actions/actions.cc b/src/actions/actions.cc index 2f28c9aea..a8c685267 100644 --- a/src/actions/actions.cc +++ b/src/actions/actions.cc @@ -23,26 +23,24 @@ #include "actions.h" #include "detection/detect.h" -#include "detection/tag.h" -#include "packet_io/active.h" -#include "packet_io/active_action.h" +#include "managers/action_manager.h" #include "parser/parser.h" #include "utils/stats.h" using namespace snort; -static void pass() +void Actions::pass() { pc.pass_pkts++; } -static void log(Packet* p, const OptTreeNode* otn) +void Actions::log(Packet* p, const OptTreeNode* otn) { RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn); CallLogFuncs(p, otn, rtn->listhead); } -static void alert(Packet* p, const OptTreeNode* otn) +void Actions::alert(Packet* p, const OptTreeNode* otn) { RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn); @@ -60,108 +58,30 @@ static void alert(Packet* p, const OptTreeNode* otn) CallLogFuncs(p, otn, rtn->listhead); } -static const char* const type[Actions::MAX] = +std::string Actions::get_string(Actions::Type action) { - "none", "log", "pass", "alert", "drop", "block", "reset" -}; - -const char* Actions::get_string(Actions::Type action) -{ - if ( action < Actions::MAX ) - return type[action]; - - return "ERROR"; + return ActionManager::get_action_string(action); } Actions::Type Actions::get_type(const char* s) { - if ( !s ) - return Actions::NONE; - - else if ( !strcasecmp(s, Actions::get_string(Actions::LOG)) ) - return Actions::LOG; - - else if ( !strcasecmp(s, Actions::get_string(Actions::PASS)) ) - return Actions::PASS; - - else if ( !strcasecmp(s, Actions::get_string(Actions::ALERT)) ) - return Actions::ALERT; - - else if ( !strcasecmp(s, Actions::get_string(Actions::DROP)) ) - return Actions::DROP; - - else if ( !strcasecmp(s, Actions::get_string(Actions::BLOCK)) ) - return Actions::BLOCK; - - else if ( !strcasecmp(s, Actions::get_string(Actions::RESET)) ) - return Actions::RESET; - - return Actions::NONE; + return ActionManager::get_action_type(s); } -void Actions::execute(Actions::Type action, Packet* p, const OptTreeNode* otn, - uint16_t event_id) +Actions::Type Actions::get_max_types() { - switch (action) - { - case Actions::PASS: - pass(); - SetTags(p, otn, event_id); - break; - - case Actions::ALERT: - alert(p, otn); - SetTags(p, otn, event_id); - break; - - case Actions::LOG: - log(p, otn); - SetTags(p, otn, event_id); - break; - - case Actions::DROP: - p->active->drop_packet(p); - p->active->set_drop_reason("ips"); - alert(p, otn); - SetTags(p, otn, event_id); - break; - - case Actions::BLOCK: - p->active->block_session(p); - p->active->set_drop_reason("ips"); - alert(p, otn); - SetTags(p, otn, event_id); - break; - - case Actions::RESET: - p->active->reset_session(p, get_ips_policy()->action[action]); - alert(p, otn); - SetTags(p, otn, event_id); - break; - - default: - break; - } + return ActionManager::get_max_action_types(); } -void Actions::apply(Actions::Type action, Packet* p) +bool Actions::is_valid_action(Actions::Type action) { - switch ( action ) - { - case Actions::DROP: - p->active->drop_packet(p); - break; - - case Actions::BLOCK: - p->active->block_session(p); - break; - - case Actions::RESET: - p->active->reset_session(p, get_ips_policy()->action[action]); - break; + if ( action < get_max_types() ) + return true; - default: - break; - } + return false; } +std::string Actions::get_default_priorities(bool alert_before_pass) +{ + return ActionManager::get_action_priorities(alert_before_pass); +} diff --git a/src/actions/actions.h b/src/actions/actions.h index e3badba00..be6ac3eea 100644 --- a/src/actions/actions.h +++ b/src/actions/actions.h @@ -22,6 +22,7 @@ // Define action types and provide hooks to apply a given action to a packet #include +#include #include "main/snort_types.h" @@ -30,25 +31,22 @@ struct OptTreeNode; namespace snort { struct Packet; +} class SO_PUBLIC Actions { public: - // FIXIT-L if Type is changed, RateFilterModule and type in actions.cc must be updated - enum Type : uint8_t - { NONE = 0, LOG, PASS, ALERT, DROP, BLOCK, RESET, MAX }; - - static const char* get_string(Type); + using Type = uint8_t; +public: + static std::string get_string(Type); static Type get_type(const char*); + static Type get_max_types(); + static bool is_valid_action(Type); + static std::string get_default_priorities(bool alert_before_pass = false); - static void execute(Type, struct Packet*, const struct OptTreeNode*, - uint16_t event_id); - - static void apply(Type, struct Packet*); - - static inline bool is_pass(Type a) - { return ( a == PASS ); } + static void pass(); + static void log(snort::Packet*, const OptTreeNode*); + static void alert(snort::Packet*, const OptTreeNode*); }; -} #endif diff --git a/src/actions/dev_notes.txt b/src/actions/dev_notes.txt index 90b114dd7..a8f7026bc 100644 --- a/src/actions/dev_notes.txt +++ b/src/actions/dev_notes.txt @@ -1,31 +1,34 @@ -IPS actions allow you to execute custom responses to events. -Unlike loggers, these are invoked before thresholding and can be used to -control external agents (including loggers). +IPS actions allow you to execute custom responses to events. Unlike loggers, +these are invoked before thresholding and can be used to control external agents +(including loggers). IPS rules have an associated type that determines what kind of action they trigger. The rule types defined in this module are: -* log -* pass -* alert -* drop -* block -* reset - -There is also a "none" rule type, which is a no-op. +* log pass alert drop block It also defines 3 active responses: -* react -* reject -* rewrite +* react reject rewrite + +Reject performs active response to shutdown hostile network session by injecting +TCP resets (TCP connections) or ICMP unreachable packets. + +React sends an HTML page to the client, a RST to the server and blocks the flow. +It is using payload_injector utilty. payload_injector should be configured when +react is used. + +Rewrite enables overwrite packet contents based on "replace" option in the +rules. -Reject performs active response to shutdown hostile network -session by injecting TCP resets (TCP connections) or ICMP unreachable -packets. +Ips actions are all pluggable and implemented as subclasses of IpsAction action. +Each ips action instance has an instance of the active action that is used to +perform the active response. -React sends an HTML page to the client, a RST to the server -and blocks the flow. It is using payload_injector utilty. -payload_injector should be configured when react is used. +IpsAction::exec represents the action taken by the ips actions after rule +evaluation during packet processing. This may include logging, alerting marking +the packet as passed, etc. IpsActions::exec when called without the otn will do +the active action such as drop/block/reset without alerting/logging or marking +the packet as passed. -Rewrite enables overwrite packet contents based on "replace" -option in the rules. +ActiveAction::delayed_exec is called during the post processing of a packet to +send active responses. diff --git a/src/actions/ips_actions.cc b/src/actions/ips_actions.cc index 0e4a13c21..90e2d4aea 100644 --- a/src/actions/ips_actions.cc +++ b/src/actions/ips_actions.cc @@ -29,16 +29,26 @@ using namespace snort; #ifdef STATIC_IPS_ACTIONS extern const BaseApi* act_react[]; -extern const BaseApi* act_reject[]; #endif +extern const BaseApi* act_alert[]; +extern const BaseApi* act_block[]; +extern const BaseApi* act_drop[]; +extern const BaseApi* act_log[]; +extern const BaseApi* act_pass[]; +extern const BaseApi* act_reject[]; extern const BaseApi* act_replace[]; void load_actions() { #ifdef STATIC_IPS_ACTIONS PluginManager::load_plugins(act_react); - PluginManager::load_plugins(act_reject); #endif + PluginManager::load_plugins(act_alert); + PluginManager::load_plugins(act_block); + PluginManager::load_plugins(act_drop); + PluginManager::load_plugins(act_log); + PluginManager::load_plugins(act_pass); + PluginManager::load_plugins(act_reject); PluginManager::load_plugins(act_replace); } diff --git a/src/detection/detection_engine.cc b/src/detection/detection_engine.cc index 13094254d..f708dbb8f 100644 --- a/src/detection/detection_engine.cc +++ b/src/detection/detection_engine.cc @@ -649,7 +649,7 @@ int DetectionEngine::queue_event(const OptTreeNode* otn) return 0; } -int DetectionEngine::queue_event(unsigned gid, unsigned sid, Actions::Type type) +int DetectionEngine::queue_event(unsigned gid, unsigned sid) { OptTreeNode* otn = GetOTN(gid, sid); @@ -664,7 +664,6 @@ int DetectionEngine::queue_event(unsigned gid, unsigned sid, Actions::Type type) en->otn = otn; en->rtn = nullptr; // lookup later after ips policy selection - en->type = type; if ( sfeventq_add(pq, en) ) return -1; diff --git a/src/detection/detection_engine.h b/src/detection/detection_engine.h index aa77a2471..919d4a952 100644 --- a/src/detection/detection_engine.h +++ b/src/detection/detection_engine.h @@ -25,7 +25,6 @@ // packet (PDU), first call set_next_packet(). If rebuild is successful, // then instantiate a new DetectionEngine to detect that packet. -#include "actions/actions.h" #include "detection/detection_util.h" #include "detection/ips_context.h" #include "main/snort_types.h" @@ -87,7 +86,7 @@ public: static bool inspect(Packet*); static int queue_event(const struct OptTreeNode*); - static int queue_event(unsigned gid, unsigned sid, Actions::Type = Actions::NONE); + static int queue_event(unsigned gid, unsigned sid); static void disable_all(Packet*); static bool all_disabled(Packet*); diff --git a/src/detection/detection_util.cc b/src/detection/detection_util.cc index 8cd9f3ef2..a8be6e144 100644 --- a/src/detection/detection_util.cc +++ b/src/detection/detection_util.cc @@ -24,6 +24,7 @@ #include "detection_util.h" +#include "actions/actions.h" #include "events/event.h" #include "log/text_log.h" #include "protocols/packet.h" @@ -74,16 +75,16 @@ static void LogBuffer(const char* s, const uint8_t* p, unsigned n) } } -void EventTrace_Log(const Packet* p, const OptTreeNode* otn, int action) +void EventTrace_Log(const Packet* p, const OptTreeNode* otn, Actions::Type action) { - const char* acts = Actions::get_string((Actions::Type)action); + std::string acts = Actions::get_string(action); if ( !tlog ) return; TextLog_Print(tlog, "\nEvt=%u, Gid=%u, Sid=%u, Rev=%u, Act=%s\n", - event_id, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, acts); + event_id, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, acts.c_str()); TextLog_Print(tlog, "Pkt=" STDu64 ", Sec=%lu.%6lu, Len=%u, Cap=%u\n", diff --git a/src/detection/detection_util.h b/src/detection/detection_util.h index 123492e0e..13484f877 100644 --- a/src/detection/detection_util.h +++ b/src/detection/detection_util.h @@ -24,6 +24,7 @@ // this is a legacy junk-drawer file that needs to be refactored // it provides file and alt data and event trace foo. +#include "actions/actions.h" #include "main/snort_config.h" #define DECODE_BLEN 65535 @@ -44,7 +45,7 @@ struct DataBuffer void EventTrace_Init(); void EventTrace_Term(); -void EventTrace_Log(const snort::Packet*, const OptTreeNode*, int action); +void EventTrace_Log(const snort::Packet*, const OptTreeNode*, Actions::Type action); inline int EventTrace_IsEnabled(const snort::SnortConfig* sc) { diff --git a/src/detection/fp_detect.cc b/src/detection/fp_detect.cc index cc1c72252..a3ba32a02 100644 --- a/src/detection/fp_detect.cc +++ b/src/detection/fp_detect.cc @@ -41,6 +41,7 @@ #include +#include "actions/actions.h" #include "events/event.h" #include "filters/rate_filter.h" #include "filters/sfthreshold.h" @@ -107,29 +108,26 @@ static inline void init_match_info(const IpsContext* c) // called by fpLogEvent(), which does the filtering etc. // this handles the non-rule-actions (responses). static inline void fpLogOther( - Packet* p, const RuleTreeNode* rtn, const OptTreeNode* otn, int action) + Packet* p, const RuleTreeNode* rtn, const OptTreeNode* otn, Actions::Type action) { if ( EventTrace_IsEnabled(p->context->conf) ) EventTrace_Log(p, otn, action); if ( PacketTracer::is_active() ) { + std::string act = Actions::get_string(action); PacketTracer::log("Event: %u:%u:%u, Action %s\n", otn->sigInfo.gid, otn->sigInfo.sid, - otn->sigInfo.rev, Actions::get_string((Actions::Type)action)); + otn->sigInfo.rev, act.c_str()); } // rule option actions are queued here (eg replace) otn_trigger_actions(otn, p); - // rule actions are queued here (eg reject) - if ( rtn->listhead->is_plugin_action ) - { - Actions::Type idx = rtn->listhead->ruleListNode->mode; - ActiveAction * act = get_ips_policy()->action[idx]; - if ( act ) - Active::queue(act, p); - } + IpsAction* act = get_ips_policy()->action[rtn->action]; + ActiveAction* active_act = act->get_active_action(); + if ( active_act ) + Active::queue(act->get_active_action(), p); } /* @@ -143,9 +141,6 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p) int action = -1, rateAction = -1; int override, filterEvent = 0; - if ( Actions::is_pass(rtn->action) ) - p->packet_flags |= PKT_PASS_RULE; - if ( otn->stateless() ) { /* Stateless rule, set the stateless bit */ @@ -166,16 +161,17 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p) { // We still want to drop packets that are drop rules. // We just don't want to see the alert. - Actions::apply(rtn->action, p); + IpsAction * act = get_ips_policy()->action[rtn->action]; + act->exec(p); fpLogOther(p, rtn, otn, rtn->action); return 1; } // perform rate filtering tests - impacts action taken rateAction = RateFilter_Test(otn, p); - override = ( rateAction >= Actions::MAX ); + override = ( rateAction >= Actions::get_max_types() ); if ( override ) - rateAction -= Actions::MAX; + rateAction -= Actions::get_max_types(); // internal events are no-ops if ( (rateAction < 0) && EventIsInternal(otn->sigInfo.gid) ) @@ -209,7 +205,8 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p) ** If InlineMode is on, then we still want to drop packets ** that are drop rules. We just don't want to see the alert. */ - Actions::apply((Actions::Type)action, p); + IpsAction * act = get_ips_policy()->action[action]; + act->exec(p); fpLogOther(p, rtn, otn, action); pc.event_limit++; return 1; @@ -222,7 +219,7 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p) const SnortConfig* sc = p->context->conf; if ( (p->packet_flags & PKT_PASS_RULE) && - (sc->get_eval_index(rtn->action) > sc->get_eval_index(Actions::PASS)) ) + (sc->get_eval_index(rtn->action) > sc->get_eval_index(Actions::get_type("pass"))) ) { fpLogOther(p, rtn, otn, rtn->action); return 1; @@ -231,7 +228,11 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p) otn->state[get_instance_id()].alerts++; event_id++; - Actions::execute((Actions::Type)action, p, otn, event_id); + + IpsAction * act = get_ips_policy()->action[action]; + act->exec(p, otn); + SetTags(p, otn, event_id); + fpLogOther(p, rtn, otn, action); return 0; @@ -639,7 +640,7 @@ static inline int fpFinalSelectEvent(OtnxMatchData* omd, Packet* p) const OptTreeNode* otn = omd->matchInfo[i].MatchArray[j]; RuleTreeNode* rtn = getRtnFromOtn(otn); - if ( otn && rtn && Actions::is_pass(rtn->action) ) + if ( otn && rtn && ( p->packet_flags & PKT_PASS_RULE ) ) { /* Already acted on rules, so just don't act on anymore */ if ( tcnt > 0 ) @@ -680,11 +681,8 @@ static inline int fpFinalSelectEvent(OtnxMatchData* omd, Packet* p) } /* only log/count one pass */ - if ( otn && rtn && Actions::is_pass(rtn->action) ) - { - p->packet_flags |= PKT_PASS_RULE; + if ( otn && rtn && ( p->packet_flags & PKT_PASS_RULE ) ) return 1; - } } } } diff --git a/src/detection/rules.cc b/src/detection/rules.cc index 6c09fcf67..c45122a4e 100644 --- a/src/detection/rules.cc +++ b/src/detection/rules.cc @@ -101,7 +101,8 @@ void RuleStateMap::apply( policy->rules_shared++; RuleTreeNode* t_rtn = dup_rtn(sc, otn, b_rtn, policy); - update_rtn(t_rtn, s); + update_rtn(sc, t_rtn, s); + addRtnToOtn(sc, otn, t_rtn, ips_num); } @@ -156,7 +157,7 @@ RuleTreeNode* RuleStateMap::dup_rtn( return ret; } -void RuleStateMap::update_rtn(RuleTreeNode* rtn, const RuleState& s) +void RuleStateMap::update_rtn(SnortConfig* sc, RuleTreeNode* rtn, const RuleState& s) { switch ( s.enable ) { @@ -164,6 +165,12 @@ void RuleStateMap::update_rtn(RuleTreeNode* rtn, const RuleState& s) case IpsPolicy::ENABLED: rtn->set_enabled(); break; case IpsPolicy::INHERIT_ENABLE: break; } + + ListHead* new_listhead = get_rule_list(sc, s.rule_action.c_str()); + + if ( new_listhead and ( rtn->listhead != new_listhead ) ) + rtn->listhead = new_listhead; + rtn->action = s.action; if ( rtn->header ) diff --git a/src/detection/rules.h b/src/detection/rules.h index 69b0629ca..0905f6cac 100644 --- a/src/detection/rules.h +++ b/src/detection/rules.h @@ -58,14 +58,13 @@ struct ListHead OutputSet* LogList; OutputSet* AlertList; struct RuleListNode* ruleListNode; - bool is_plugin_action = false; }; // for top-level rule lists by type (alert, drop, etc.) struct RuleListNode { ListHead* RuleList; /* The rule list associated with this node */ - snort::Actions::Type mode; /* the rule mode */ + Actions::Type mode; /* the rule mode */ unsigned evalIndex; /* eval index for this rule set */ char* name; /* name of this rule list */ RuleListNode* next; /* the next RuleListNode */ @@ -83,7 +82,7 @@ struct RuleKey struct RuleState { std::string rule_action; - snort::Actions::Type action; + uint8_t action; IpsPolicy::Enable enable; }; @@ -97,7 +96,7 @@ public: private: RuleTreeNode* dup_rtn(snort::SnortConfig*, OptTreeNode*, RuleTreeNode*, IpsPolicy*); - void update_rtn(RuleTreeNode*, const RuleState&); + void update_rtn(snort::SnortConfig*, RuleTreeNode*, const RuleState&); void apply(snort::SnortConfig*, OptTreeNode*, unsigned ips_num, const RuleState&); private: diff --git a/src/detection/signature.cc b/src/detection/signature.cc index 978672e6b..b106f2504 100644 --- a/src/detection/signature.cc +++ b/src/detection/signature.cc @@ -28,6 +28,7 @@ #include "signature.h" +#include "actions/actions.h" #include "framework/decode_data.h" #include "hash/hash_defs.h" #include "hash/ghash.h" @@ -476,10 +477,10 @@ void dump_rule_state(const SnortConfig* sc) auto pid = snort::get_ips_policy(sc, i)->user_policy_id; json.put("policy", pid); - const char* s = Actions::get_string(rtn->action); - json.put("action", s); + std::string action = Actions::get_string(rtn->action); + json.put("action", action.c_str()); - s = rtn->enabled() ? "enabled" : "disabled"; + const char* s = rtn->enabled() ? "enabled" : "disabled"; json.put("state", s); json.close(); diff --git a/src/detection/treenodes.h b/src/detection/treenodes.h index f7f90927f..1a268f80b 100644 --- a/src/detection/treenodes.h +++ b/src/detection/treenodes.h @@ -133,7 +133,7 @@ struct RuleTreeNode // Multiple OTNs can reference this RTN with the same policy. unsigned int otnRefCount = 0; // FIXIT-L shared_ptr? - snort::Actions::Type action = snort::Actions::Type::NONE; + Actions::Type action = 0; uint8_t flags = 0; diff --git a/src/events/event_queue.h b/src/events/event_queue.h index c1d74b587..97b722c55 100644 --- a/src/events/event_queue.h +++ b/src/events/event_queue.h @@ -20,7 +20,6 @@ #ifndef EVENT_QUEUE_H #define EVENT_QUEUE_H -#include "actions/actions.h" #include "main/snort_types.h" #define SNORT_EVENTQ_PRIORITY 1 @@ -38,7 +37,6 @@ struct EventNode { const struct OptTreeNode* otn; const struct RuleTreeNode* rtn; - snort::Actions::Type type; }; EventQueueConfig* EventQueueConfigNew(); diff --git a/src/file_api/file_module.cc b/src/file_api/file_module.cc index fa5e1606b..7fcd4f4a8 100644 --- a/src/file_api/file_module.cc +++ b/src/file_api/file_module.cc @@ -464,14 +464,10 @@ bool FileIdModule::begin(const char* fqn, int idx, SnortConfig*) return true; } -bool FileIdModule::end(const char* fqn, int idx, SnortConfig* sc) +bool FileIdModule::end(const char* fqn, int idx, SnortConfig*) { if (!idx) - { - if ( need_active ) - sc->set_active_enabled(); return true; - } if ( !strcmp(fqn, "file_id.file_rules") ) { diff --git a/src/filters/sfrf.cc b/src/filters/sfrf.cc index 6e47a7ef5..0ff10ac5e 100644 --- a/src/filters/sfrf.cc +++ b/src/filters/sfrf.cc @@ -28,6 +28,7 @@ #include "main/thread.h" #include "detection/rules.h" +#include "framework/ips_action.h" #include "hash/ghash.h" #include "hash/hash_defs.h" #include "hash/xhash.h" @@ -402,9 +403,13 @@ static int SFRF_TestObject( // but the decrement will never come so we "fix" it here // if the count were not incremented in such cases, the // threshold would never be exceeded. - if ( !cfgNode->seconds && dynNode->count > cfgNode->count ) - if ( cfgNode->newAction == Actions::DROP ) + if ( !cfgNode->seconds && (dynNode->count > cfgNode->count) + && Actions::is_valid_action(cfgNode->newAction) ) + { + IpsAction* act = get_ips_policy()->action[cfgNode->newAction]; + if ( act->drops_traffic() ) dynNode->count--; + } #ifdef SFRF_DEBUG printf("--SFRF_DEBUG: %d-%u-%u: %u Packet IP %s, op: %d, count %u, action %d\n", @@ -742,7 +747,7 @@ static int _checkThreshold( fflush(stdout); #endif - return Actions::MAX + cfgNode->newAction; + return Actions::get_max_types() + cfgNode->newAction; } static void _updateDependentThresholds( diff --git a/src/filters/sfrf.h b/src/filters/sfrf.h index e58aa33b0..d28887fd8 100644 --- a/src/filters/sfrf.h +++ b/src/filters/sfrf.h @@ -95,7 +95,7 @@ struct tSFRFConfigNode unsigned seconds; // Action that replaces original rule action on reaching threshold - snort::Actions::Type newAction; + Actions::Type newAction; // Threshold action duration in seconds before reverting to original rule action unsigned timeout; diff --git a/src/filters/sfrf_test.cc b/src/filters/sfrf_test.cc index ccc8c27b9..43028a253 100644 --- a/src/filters/sfrf_test.cc +++ b/src/filters/sfrf_test.cc @@ -952,8 +952,8 @@ static int EventTest(EventData* p) status = SFRF_TestThreshold( rfc, p->gid, p->sid, &sip, &dip, curtime, op); - if ( status >= Actions::MAX ) - status -= Actions::MAX; + if ( status >= Actions::get_max_types() ) + status -= Actions::get_max_types(); return status; } diff --git a/src/framework/ips_action.h b/src/framework/ips_action.h index 3338589e1..c69e6c54e 100644 --- a/src/framework/ips_action.h +++ b/src/framework/ips_action.h @@ -25,34 +25,55 @@ // These can be used to execute external controls like updating an external // firewall. -#include "actions/actions.h" #include "framework/base_api.h" #include "main/snort_types.h" #include "packet_io/active_action.h" // this is the current version of the api -#define ACTAPI_VERSION ((BASE_API_VERSION << 16) | 0) +#define ACTAPI_VERSION ((BASE_API_VERSION << 16) | 1) //------------------------------------------------------------------------- // api for class //------------------------------------------------------------------------- +struct OptTreeNode; namespace snort { struct Packet; -class SO_PUBLIC IpsAction : public ActiveAction +class SO_PUBLIC IpsAction { public: - void exec(Packet*) override = 0; + enum IpsActionPriority : uint16_t + { + IAP_LOG = 10, + IAP_ALERT = 20, + IAP_REWRITE = 30, + IAP_DROP = 40, + IAP_BLOCK = 50, + IAP_REJECT = 60, + IAP_PASS = 70, + IAP_MAX = IAP_PASS + }; + +public: + virtual ~IpsAction() = default; const char* get_name() const { return name; } + ActiveAction* get_active_action() const { return active_action; } + + virtual void exec(Packet*, const OptTreeNode* otn = nullptr) = 0; + virtual bool drops_traffic() { return false; } protected: - IpsAction(const char* s, ActionType a) : ActiveAction(a) - { name = s; } + IpsAction(const char* s, ActiveAction* a) + { + active_action = a; + name = s; + } private: const char* name; + ActiveAction* active_action; }; typedef void (* IpsActFunc)(); @@ -62,7 +83,8 @@ typedef void (* ActDelFunc)(IpsAction*); struct ActionApi { BaseApi base; - Actions::Type type; + + IpsAction::IpsActionPriority priority; IpsActFunc pinit; IpsActFunc pterm; diff --git a/src/main/modules.cc b/src/main/modules.cc index db0f0c82e..7739c139b 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -611,7 +611,6 @@ bool ReferencesModule::set(const char*, Value& v, SnortConfig*) //------------------------------------------------------------------------- // alerts module //------------------------------------------------------------------------- - static const Parameter alerts_params[] = { { "alert_with_interface_name", Parameter::PT_BOOL, nullptr, "false", @@ -626,7 +625,7 @@ static const Parameter alerts_params[] = { "log_references", Parameter::PT_BOOL, nullptr, "false", "include rule references in alert info (full only)" }, - { "order", Parameter::PT_STRING, nullptr, "pass reset block drop alert log", + { "order", Parameter::PT_STRING, nullptr, nullptr, "change the order of rule action application" }, { "rate_filter_memcap", Parameter::PT_INT, "0:max32", "1048576", @@ -873,13 +872,8 @@ bool ActiveModule::set(const char*, Value& v, SnortConfig* sc) sc->set_dst_mac(v.get_string()); else if ( v.is("max_responses") ) - { sc->max_responses = v.get_uint8(); - if ( sc->max_responses ) - sc->set_active_enabled(); - } - else if ( v.is("min_interval") ) sc->min_interval = v.get_uint8(); @@ -1711,6 +1705,9 @@ bool EventFilterModule::end(const char*, int idx, SnortConfig* sc) // rate_filter module //------------------------------------------------------------------------- +function get_action_types = []() +{ return PluginManager::get_available_plugins(PT_IPS_ACTION); }; + static const Parameter rate_filter_params[] = { { "gid", Parameter::PT_INT, "0:max32", "1", @@ -1728,10 +1725,7 @@ static const Parameter rate_filter_params[] = { "seconds", Parameter::PT_INT, "0:max32", "1", "count interval" }, - { "new_action", Parameter::PT_ENUM, - // FIXIT-L new_action options must match Actions::Type and - // should include pluggable actions as well - "log | pass | alert | drop | block | reset", "alert", + { "new_action", Parameter::PT_DYNAMIC, (void*)&get_action_types, "alert", "take this action on future hits until timeout" }, { "timeout", Parameter::PT_INT, "0:max32", "1", @@ -1811,7 +1805,13 @@ bool RateFilterModule::set(const char*, Value& v, SnortConfig*) thdx.applyTo = sfip_var_from_string(v.get_string(), "rate_filter"); else if ( v.is("new_action") ) - thdx.newAction = (Actions::Type)(v.get_uint8() + 1); + { + thdx.newAction = Actions::get_type(v.get_string()); + + if ( !Actions::is_valid_action(thdx.newAction) ) + ParseError("unknown new_action type rate_filter configuration %s", + v.get_string()); + } else return false; diff --git a/src/main/policy.cc b/src/main/policy.cc index 19df09fc7..9842b0c4b 100644 --- a/src/main/policy.cc +++ b/src/main/policy.cc @@ -107,7 +107,7 @@ void InspectionPolicy::configure() // detection policy //------------------------------------------------------------------------- -IpsPolicy::IpsPolicy(PolicyId id) : action(Actions::Type::MAX, nullptr) +IpsPolicy::IpsPolicy(PolicyId id) : action(Actions::get_max_types(), nullptr) { policy_id = id; user_policy_id = 0; diff --git a/src/main/policy.h b/src/main/policy.h index 89681ad71..7ed989580 100644 --- a/src/main/policy.h +++ b/src/main/policy.h @@ -43,7 +43,7 @@ namespace snort { class GHash; struct SnortConfig; -class ActiveAction; +class IpsAction; } struct PortTable; @@ -184,9 +184,8 @@ public: bool obfuscate_pii; - // Holds plugin actions associated with this policy (e.g. reject, react, etc.) - // Indexed by Actions::Type. - std::vector action; + // Holds all plugin actions associated with this policy + std::vector action; }; //------------------------------------------------------------------------- diff --git a/src/main/snort.cc b/src/main/snort.cc index 679aa4ec7..93002e791 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -182,7 +182,7 @@ void Snort::init(int argc, char** argv) ModuleManager::reset_stats(sc); if (sc->alert_before_pass()) - sc->rule_order = "reset block drop alert pass log"; + sc->rule_order = Actions::get_default_priorities(true); sc->setup(); diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index d0e6a76d2..fc51f6ed5 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -27,6 +27,7 @@ #include #include +#include "actions/ips_actions.h" #include "detection/detect.h" #include "detection/detection_engine.h" #include "detection/fp_config.h" @@ -178,7 +179,6 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p thread_config = new ThreadConfig(); global_dbus = new DataBus(); - memset(evalOrder, 0, sizeof(evalOrder)); proto_ref = new ProtocolReference(protocol_reference); so_rules = new SoRules; trace_config = new TraceConfig; @@ -271,6 +271,7 @@ SnortConfig::~SnortConfig() delete memory; delete daq_config; delete proto_ref; + delete[] evalOrder; delete so_rules; if ( plugins ) delete plugins; @@ -290,6 +291,10 @@ void SnortConfig::setup() init_policies(this); ParseRules(this); + + // Allocate evalOrder before calling the OrderRuleLists + evalOrder = new int[Actions::get_max_types()](); + OrderRuleLists(this); if ( rule_states ) diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 24a2a9e70..94c753ec9 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -29,6 +29,7 @@ #include #include +#include "actions/actions.h" #include "events/event_queue.h" #include "framework/bits.h" #include "helpers/scratch_allocator.h" @@ -356,7 +357,7 @@ public: unsigned num_rule_types = 0; RuleListNode* rule_lists = nullptr; - int evalOrder[Actions::MAX + 1]; + int* evalOrder = nullptr; IpsActionsConfig* ips_actions_config = nullptr; FrameworkConfig* framework_config = nullptr; @@ -427,7 +428,6 @@ public: DumpConfigType dump_config_type = DUMP_CONFIG_NONE; private: - bool active_enabled = false; std::list reload_tuners; public: @@ -604,13 +604,6 @@ public: bool assure_established() const { return run_flags & RUN_FLAG__ASSURE_EST; } - // active stuff - void set_active_enabled() - { active_enabled = true; } - - bool is_active_enabled() const - { return active_enabled; } - // other stuff uint8_t min_ttl() const { return get_network_policy()->min_ttl; } diff --git a/src/managers/action_manager.cc b/src/managers/action_manager.cc index 1d7401a83..6c8470428 100644 --- a/src/managers/action_manager.cc +++ b/src/managers/action_manager.cc @@ -27,6 +27,8 @@ #include "log/messages.h" #include "main/snort_config.h" +#include "managers/module_manager.h" +#include "managers/plugin_manager.h" #include "packet_io/active.h" #include "parser/parser.h" @@ -57,8 +59,13 @@ struct IpsActionsConfig }; using ACList = vector; +using ACTypeList = unordered_map; +using ACPriorityList = map>; static ACList s_actors; +static ACTypeList s_act_types; +static ACPriorityList s_act_priorities; +static Actions::Type s_act_index = 0; static THREAD_LOCAL ACList* s_tl_actors = nullptr; @@ -70,16 +77,67 @@ static THREAD_LOCAL ACList* s_tl_actors = nullptr; void ActionManager::add_plugin(const ActionApi* api) { s_actors.emplace_back(api); + s_act_types.emplace(api->base.name, s_act_index++); + s_act_priorities.emplace(api->priority, api->base.name); +} + +std::string ActionManager::get_action_string(Actions::Type action) +{ + if ( action < s_act_index ) + { + for ( const auto& type : s_act_types ) + { + if ( type.second == action ) + return type.first; + } + } + + return "ERROR"; } Actions::Type ActionManager::get_action_type(const char* s) { - for ( auto& p : s_actors ) + auto type = s_act_types.find(s); + + if (type != s_act_types.end()) + return type->second; + + return get_max_action_types(); +} + +Actions::Type ActionManager::get_max_action_types() +{ + return s_act_index; +} + +std::string ActionManager::get_action_priorities(bool alert_before_pass) +{ + std::string priorities; + + for (auto iter = s_act_priorities.begin(); iter != s_act_priorities.end(); ) { - if ( !strcmp(p.api->base.name, s) ) - return p.api->type; + if ( alert_before_pass ) + { + if ( iter->second == "pass" ) + { + iter++; + continue; + } + else if ( iter->second == "alert" ) + { + priorities += "alert pass "; + iter++; + continue; + } + } + + priorities += iter->second; + + if ( ++iter != s_act_priorities.end() ) + priorities += " "; } - return Actions::NONE; + + return priorities; } void ActionManager::dump_plugins() @@ -144,26 +202,49 @@ void ActionManager::delete_config(SnortConfig* sc) sc->ips_actions_config = nullptr; } -void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc) +void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc, IpsPolicy* ips) { ActionClass* cls = get_action_class(api, sc->ips_actions_config); + assert(cls != nullptr); IpsAction* act = cls->api->ctor(mod); if ( act ) { - // Add this instance to the list of those created for this config - sc->ips_actions_config->clist.emplace_back(*cls, act); - RuleListNode* rln = CreateRuleType(sc, api->base.name, api->type, true); + RuleListNode* rln = CreateRuleType(sc, api->base.name, get_action_type(api->base.name)); // The plugin actions (e.g. reject, react, etc.) are per policy, per mode. // At logging time, they have to be retrieved the way we store them here. - IpsPolicy* ips = get_ips_policy(); + if ( !ips ) + ips = get_ips_policy(); + Actions::Type idx = rln->mode; - assert(ips->action[idx] == nullptr); - ips->action[idx] = act; + if (ips->action[idx] == nullptr) + { + ips->action[idx] = act; + // Add this instance to the list of those created for this config + sc->ips_actions_config->clist.emplace_back(*cls, act); + } + else + { + cls->api->dtor(act); + } + } +} + +void ActionManager::initialize_policies(SnortConfig* sc) +{ + for (unsigned i = 0; i < sc->policy_map->ips_policy_count(); i++) + { + auto policy = sc->policy_map->get_ips_policy(i); + + if ( !policy ) + continue; + + for ( auto actor : s_actors ) + ActionManager::instantiate(actor.api, nullptr, sc, policy); } } diff --git a/src/managers/action_manager.h b/src/managers/action_manager.h index bfb95fad5..b3dd0c931 100644 --- a/src/managers/action_manager.h +++ b/src/managers/action_manager.h @@ -36,6 +36,8 @@ struct SnortConfig; struct Packet; } +struct IpsPolicy; + //------------------------------------------------------------------------- #ifdef PIGLET @@ -63,10 +65,16 @@ public: static void dump_plugins(); static void new_config(snort::SnortConfig*); - static snort::Actions::Type get_action_type(const char*); static void delete_config(snort::SnortConfig*); - static void instantiate(const snort::ActionApi*, snort::Module*, snort::SnortConfig*); + static void instantiate(const snort::ActionApi*, snort::Module*, + snort::SnortConfig*, IpsPolicy* ips = nullptr ); + static void initialize_policies(snort::SnortConfig*); + + static std::string get_action_string(Actions::Type); + static Actions::Type get_action_type(const char*); + static Actions::Type get_max_action_types(void); + static std::string get_action_priorities(bool); static void thread_init(const snort::SnortConfig*); static void thread_reinit(const snort::SnortConfig*); diff --git a/src/packet_io/active.cc b/src/packet_io/active.cc index 4165775a5..313b6a4d7 100644 --- a/src/packet_io/active.cc +++ b/src/packet_io/active.cc @@ -47,9 +47,9 @@ using namespace snort; class ResetAction : public snort::ActiveAction { public: - ResetAction() : ActiveAction(ActionType::ACT_RESET) { } + ResetAction() : ActiveAction(ActionPriority::AP_RESET) { } - void exec(snort::Packet* p) override + void delayed_exec(snort::Packet* p) override { p->active->kill_session(p, ENC_FLAG_FWD); } @@ -183,10 +183,10 @@ bool Active::thread_init(const SnortConfig* sc) if ( s_attempts > MAX_ATTEMPTS ) s_attempts = MAX_ATTEMPTS; - if ( sc->is_active_enabled() && !s_attempts ) + if ( !s_attempts ) s_attempts = 1; - if ( sc->is_active_enabled() && (!SFDAQ::can_inject() || !sc->respond_device.empty()) ) + if ( !SFDAQ::can_inject() || !sc->respond_device.empty() ) { if ( sc->read_mode() || !open(sc->respond_device.empty() ? nullptr : sc->respond_device.c_str()) ) @@ -695,16 +695,13 @@ void Active::reset_session(Packet* p, ActiveAction* reject, bool force) if ( force or (p->context->conf->inline_mode() and SFDAQ::forwarding_packet(p->pkth))) Stream::drop_flow(p); - if ( p->context->conf->is_active_enabled() ) - { - if (reject) - Active::queue(reject, p); + if (reject) + Active::queue(reject, p); - if ( p->flow ) - { - Stream::init_active_response(p, p->flow); - p->flow->set_state(Flow::FlowState::RESET); - } + if ( p->flow ) + { + Stream::init_active_response(p, p->flow); + p->flow->set_state(Flow::FlowState::RESET); } p->disable_inspect = true; @@ -818,7 +815,7 @@ void Active::execute(Packet* p) { if ( *p->action ) { - (*p->action)->exec(p); + (*p->action)->delayed_exec(p); *p->action = nullptr; } diff --git a/src/packet_io/active_action.h b/src/packet_io/active_action.h index 88f5ff000..485d976bb 100644 --- a/src/packet_io/active_action.h +++ b/src/packet_io/active_action.h @@ -27,14 +27,14 @@ namespace snort { struct Packet; -enum ActionType +enum ActionPriority { - ACT_LOCAL, - ACT_MODIFY, - ACT_PROXY, - ACT_RESET, - ACT_REMOTE, - ACT_MAX + AP_LOCAL, + AP_MODIFY, + AP_PROXY, + AP_RESET, + AP_REMOTE, + AP_MAX }; // These are injection actions (e.g. send a RST packet, or respond to a query @@ -45,15 +45,15 @@ enum ActionType class SO_PUBLIC ActiveAction { public: - ActiveAction(ActionType a = ActionType::ACT_MAX) : action(a) {} + ActiveAction(ActionPriority a = ActionPriority::AP_MAX) : action(a) {} virtual ~ActiveAction() = default; - virtual void exec(Packet*) = 0; + virtual void delayed_exec(Packet* ) { } - ActionType get_action() const { return action; } + ActionPriority get_action() const { return action; } protected: - ActionType action; + ActionPriority action; }; diff --git a/src/parser/parse_conf.cc b/src/parser/parse_conf.cc index e646c9b68..ce60702b1 100644 --- a/src/parser/parse_conf.cc +++ b/src/parser/parse_conf.cc @@ -28,13 +28,13 @@ #include #include +#include #include #include #include #include "log/messages.h" #include "main/snort_config.h" -#include "managers/action_manager.h" #include "managers/module_manager.h" #include "sfip/sf_vartable.h" #include "target_based/snort_protocols.h" @@ -265,30 +265,6 @@ void add_service_to_otn(SnortConfig* sc, OptTreeNode* otn, const char* svc_name) otn->sigInfo.services.emplace_back(si); } -Actions::Type get_rule_type(const char* s) -{ - Actions::Type rt = Actions::get_type(s); - - if ( rt == Actions::NONE ) - rt = ActionManager::get_action_type(s); - - switch ( rt ) - { - case Actions::DROP: - case Actions::BLOCK: - case Actions::RESET: - return rt; - - case Actions::NONE: - ParseError("unknown rule type '%s'", s); - break; - - default: - break; - } - return rt; -} - ListHead* get_rule_list(SnortConfig* sc, const char* s) { const RuleListNode* p = sc->rule_lists; diff --git a/src/parser/parse_conf.h b/src/parser/parse_conf.h index 7f320f1b4..3baa5d1c6 100644 --- a/src/parser/parse_conf.h +++ b/src/parser/parse_conf.h @@ -46,7 +46,6 @@ void parse_include(snort::SnortConfig*, const char*); void add_service_to_otn(snort::SnortConfig*, OptTreeNode*, const char*); -snort::Actions::Type get_rule_type(const char*); ListHead* get_rule_list(snort::SnortConfig*, const char*); #endif diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index 7069343a9..d287a563e 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -23,6 +23,7 @@ #include "parse_rule.h" +#include "actions/actions.h" #include "detection/detect.h" #include "detection/fp_config.h" #include "detection/fp_utils.h" @@ -955,13 +956,17 @@ void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn) if ( s_so_rule ) return; - rtn.action = get_rule_type(s); + assert(s); - if ( rtn.action == Actions::NONE ) + rtn.action = Actions::get_type(s); + + if ( !Actions::is_valid_action(rtn.action) ) { s_ignore = true; + ParseError("unknown rule action '%s'", s); return; } + if ( sc->dump_rule_meta() ) rtn.header = new RuleHeader(s); @@ -972,11 +977,9 @@ void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn) CreateRuleType(sc, s, rtn.action); rtn.listhead = get_rule_list(sc, s); } + if ( sc->get_default_rule_state() ) rtn.set_enabled(); - - if ( !rtn.listhead ) - ParseError("unconfigured rule action '%s'", s); } void parse_rule_proto(SnortConfig* sc, const char* s, RuleTreeNode& rtn, bool elided) diff --git a/src/parser/parser.cc b/src/parser/parser.cc index 71c5ea18b..e9b0b1ee0 100644 --- a/src/parser/parser.cc +++ b/src/parser/parser.cc @@ -45,6 +45,7 @@ #include "main/modules.h" #include "main/shell.h" #include "main/snort_config.h" +#include "managers/action_manager.h" #include "managers/event_manager.h" #include "managers/module_manager.h" #include "ports/port_object.h" @@ -289,6 +290,7 @@ static bool parse_file(SnortConfig* sc, Shell* sh, bool is_fatal, bool is_root) return false; bool success = sh->configure(sc, is_fatal, is_root); + return success; } @@ -379,6 +381,8 @@ SnortConfig* ParseSnortConf(const SnortConfig* cmd_line_conf, const char* fname, // Merge in any overrides from the command line sc->merge(cmd_line_conf); + ActionManager::initialize_policies(sc); + return sc; } @@ -551,10 +555,9 @@ void ShowPolicyStats(const SnortConfig* sc) * Returns: the ListHead for the rule type * ***************************************************************************/ -RuleListNode* CreateRuleType(SnortConfig* sc, const char* name, Actions::Type mode, bool is_plugin_action) +RuleListNode* CreateRuleType(SnortConfig* sc, const char* name, Actions::Type mode) { RuleListNode* node; - unsigned evalIndex = 0; if (sc == nullptr) return nullptr; @@ -580,7 +583,6 @@ RuleListNode* CreateRuleType(SnortConfig* sc, const char* name, Actions::Type mo return tmp; } - evalIndex++; last = tmp; tmp = tmp->next; } @@ -591,12 +593,9 @@ RuleListNode* CreateRuleType(SnortConfig* sc, const char* name, Actions::Type mo node->RuleList = (ListHead*)snort_calloc(sizeof(ListHead)); node->RuleList->ruleListNode = node; - node->RuleList->is_plugin_action = is_plugin_action; node->mode = mode; node->name = snort_strdup(name); - node->evalIndex = evalIndex; - sc->evalOrder[node->mode] = evalIndex; sc->num_rule_types++; return node; @@ -629,10 +628,14 @@ void OrderRuleLists(SnortConfig* sc) { int evalIndex = 0; RuleListNode* ordered_list = nullptr; + std::string default_priorities; const char* order = sc->rule_order.c_str(); if ( !*order ) - order = "pass drop alert log"; // FIXIT-M apply builtin module defaults + { + default_priorities = Actions::get_default_priorities(); // FIXIT-M apply builtin module defaults + order = default_priorities.c_str(); + } std::stringstream ss(order); std::string tok; @@ -670,7 +673,7 @@ void OrderRuleLists(SnortConfig* sc) RuleListNode* node = sc->rule_lists; sc->rule_lists = node->next; ordered_list = addNodeToOrderedList(ordered_list, node, evalIndex++); - sc->evalOrder[node->mode] = evalIndex; + sc->evalOrder[node->mode] = evalIndex; } sc->rule_lists = ordered_list; diff --git a/src/parser/parser.h b/src/parser/parser.h index 5b4821c91..79be6d14c 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -86,8 +86,7 @@ inline RuleTreeNode* getRuntimeRtnFromOtn(const struct OptTreeNode* otn) return getRtnFromOtn(otn); } -RuleListNode* CreateRuleType(snort::SnortConfig* sc, const char* name, - snort::Actions::Type, bool is_plugin_action = false); +RuleListNode* CreateRuleType(snort::SnortConfig* sc, const char* name, Actions::Type action_type); void FreeRuleTreeNode(RuleTreeNode*); void DestroyRuleTreeNode(RuleTreeNode*); diff --git a/src/payload_injector/test/payload_injector_test.cc b/src/payload_injector/test/payload_injector_test.cc index 01f5ec80a..c6646506b 100644 --- a/src/payload_injector/test/payload_injector_test.cc +++ b/src/payload_injector/test/payload_injector_test.cc @@ -81,7 +81,7 @@ static void set_not_configured() { conf.payload_injector_config = nullptr; } static void set_configured() { conf.payload_injector_config = &pi_conf; } Packet::~Packet() = default; -int DetectionEngine::queue_event(unsigned int, unsigned int, snort::Actions::Type) { return 0; } +int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } FlowData::~FlowData() = default; FlowData::FlowData(unsigned int, snort::Inspector*) { } diff --git a/src/piglet_plugins/pp_inspector_iface.cc b/src/piglet_plugins/pp_inspector_iface.cc index d3475d0fc..c1e9b1a13 100644 --- a/src/piglet_plugins/pp_inspector_iface.cc +++ b/src/piglet_plugins/pp_inspector_iface.cc @@ -36,7 +36,7 @@ using namespace snort; // FIXIT-M needs to be updated for addition of get_fp_buf() template static inline bool get_buf( - Inspector& i, T v, Packet& p, std::string& rb) + Inspector& i, T v, snort::Packet& p, std::string& rb) { struct InspectionBuffer ib; bool result = i.get_buf(v, &p, ib); diff --git a/src/piglet_plugins/pp_ips_action_iface.cc b/src/piglet_plugins/pp_ips_action_iface.cc index 52df4a8c1..0e18f5978 100644 --- a/src/piglet_plugins/pp_ips_action_iface.cc +++ b/src/piglet_plugins/pp_ips_action_iface.cc @@ -38,7 +38,7 @@ static const luaL_Reg methods[] = auto& p = PacketIface.get(L); auto& self = IpsActionIface.get(L); - self.exec(&p); + self.exec(&p, nullptr); return 0; } diff --git a/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc b/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc index 8eec00d41..7680e3197 100644 --- a/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc +++ b/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc @@ -32,7 +32,7 @@ namespace snort { // Stubs whose sole purpose is to make the test code link -int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; } +int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } } using namespace Http2Enums; diff --git a/src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc b/src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc index 6e69ae2c0..2baf159a2 100644 --- a/src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc +++ b/src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc @@ -35,7 +35,7 @@ namespace snort { // Stubs whose sole purpose is to make the test code link -int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; } +int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } } using namespace Http2Enums; diff --git a/src/service_inspectors/http_inspect/test/http_module_test.cc b/src/service_inspectors/http_inspect/test/http_module_test.cc index ec5d19029..47f3676b0 100755 --- a/src/service_inspectors/http_inspect/test/http_module_test.cc +++ b/src/service_inspectors/http_inspect/test/http_module_test.cc @@ -48,7 +48,7 @@ void Value::get_bits(std::bitset<256ul>&) const {} void Value::set_first_token() {} bool Value::get_next_token(std::string& ) { return false; } -int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; } +int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } LiteralSearch::Handle* LiteralSearch::setup() { return nullptr; } void LiteralSearch::cleanup(LiteralSearch::Handle*) {} LiteralSearch* LiteralSearch::instantiate(LiteralSearch::Handle*, const uint8_t*, unsigned, bool, diff --git a/src/service_inspectors/http_inspect/test/http_transaction_test.cc b/src/service_inspectors/http_inspect/test/http_transaction_test.cc index fd88bb220..f1c68448e 100644 --- a/src/service_inspectors/http_inspect/test/http_transaction_test.cc +++ b/src/service_inspectors/http_inspect/test/http_transaction_test.cc @@ -43,7 +43,7 @@ namespace snort unsigned FlowData::flow_data_id = 0; FlowData::FlowData(unsigned, Inspector*) {} FlowData::~FlowData() = default; -int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; } +int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } fd_status_t File_Decomp_StopFree(fd_session_t*) { return File_Decomp_OK; } uint32_t str_to_hash(const uint8_t *, size_t) { return 0; } void FlowData::update_allocations(size_t) {} diff --git a/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc b/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc index 83a2041ef..5621c58af 100755 --- a/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc +++ b/src/service_inspectors/http_inspect/test/http_uri_norm_test.cc @@ -43,7 +43,7 @@ void ParseError(const char*, ...) {} void Value::get_bits(std::bitset<256ul>&) const {} void Value::set_first_token() {} bool Value::get_next_token(std::string& ) { return false; } -int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; } +int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; } LiteralSearch::Handle* LiteralSearch::setup() { return nullptr; } void LiteralSearch::cleanup(LiteralSearch::Handle*) {} LiteralSearch* LiteralSearch::instantiate(LiteralSearch::Handle*, const uint8_t*, unsigned, bool, diff --git a/src/service_inspectors/smtp/smtp_module.cc b/src/service_inspectors/smtp/smtp_module.cc index 690407957..4b0c0c1df 100644 --- a/src/service_inspectors/smtp/smtp_module.cc +++ b/src/service_inspectors/smtp/smtp_module.cc @@ -364,11 +364,8 @@ bool SmtpModule::begin(const char*, int, SnortConfig*) return true; } -bool SmtpModule::end(const char* fqn, int idx, SnortConfig* sc) +bool SmtpModule::end(const char* fqn, int idx, SnortConfig*) { - if ( !strcmp(fqn, "smtp") and config->xlink2state ) - sc->set_active_enabled(); - if ( !idx ) return true; diff --git a/tools/snort2lua/config_states/config_deleted.cc b/tools/snort2lua/config_states/config_deleted.cc index 2ca66c579..9d2da5e4a 100644 --- a/tools/snort2lua/config_states/config_deleted.cc +++ b/tools/snort2lua/config_states/config_deleted.cc @@ -134,6 +134,20 @@ static const ConvertMap disable_ipopt_drops_api = const ConvertMap* disable_ipopt_drops_map = &disable_ipopt_drops_api; +/************************************************* + **************** disable_replace *************** + *************************************************/ + +static const std::string disable_replace = "disable_replace"; +static const ConvertMap disable_replace_api = +{ + disable_replace, + deleted_ctor<& disable_replace>, +}; + +const ConvertMap* disable_replace_map = &disable_replace_api; + + /************************************************* ************ disable_tcpopt_alerts ************ *************************************************/ diff --git a/tools/snort2lua/config_states/config_no_option.cc b/tools/snort2lua/config_states/config_no_option.cc index e73dd1aec..8383ca11f 100644 --- a/tools/snort2lua/config_states/config_no_option.cc +++ b/tools/snort2lua/config_states/config_no_option.cc @@ -110,7 +110,6 @@ static const std::string ips = "ips"; static const std::string packets = "packets"; static const std::string process = "process"; static const std::string output = "output"; -static const std::string rewrite = "rewrite"; /************************************************* ********** addressspace_agnostic ********** @@ -181,19 +180,6 @@ static const ConvertMap dirty_pig_api = const ConvertMap* dirty_pig_map = &dirty_pig_api; -/************************************************* - ***** disable rewrite rules with replace ******* - *************************************************/ - -static const std::string disable_replace = "disable_replace"; -static const ConvertMap disable_replace_api = -{ - disable_replace, - config_true_no_opt_ctor<& disable_replace, & rewrite>, -}; - -const ConvertMap* disable_replace_map = &disable_replace_api; - /************************************************* *************** dump_chars_only *************** *************************************************/ diff --git a/tools/snort2lua/rule_states/rule_replace.cc b/tools/snort2lua/rule_states/rule_replace.cc index 261f55569..91759d6ec 100644 --- a/tools/snort2lua/rule_states/rule_replace.cc +++ b/tools/snort2lua/rule_states/rule_replace.cc @@ -74,10 +74,6 @@ static ConversionState* ctor(Converter& c) "Changing ruletype '" + old_action + "' to 'rewrite' " "because the rule has 'replace' option."); - // include a rewrite plugin - c.get_table_api().open_table("rewrite"); - c.get_table_api().close_table(); - // update the rule type c.get_rule_api().update_rule_action("rewrite"); -- 2.47.3