From: Vitalii Tron -X (vtron - SOFTSERVE INC at Cisco) Date: Wed, 8 May 2024 01:34:48 +0000 (+0000) Subject: Pull request #4201: actions: Add action counters and aggregate them under ips_actions. X-Git-Tag: 3.2.1.0~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f776915d156c7eb148801337de777ff93ab1300a;p=thirdparty%2Fsnort3.git Pull request #4201: actions: Add action counters and aggregate them under ips_actions. Merge in SNORT/snort3 from ~VTRON/snort3:action_counter_logs to master Squashed commit of the following: commit 0430f3a6f7250523fdb8029ed1a195a813736de5 Author: Steve Chew Date: Wed Jan 31 13:03:00 2024 -0500 actions: Add action counters and aggregate them under ips_actions. --- diff --git a/src/actions/CMakeLists.txt b/src/actions/CMakeLists.txt index 2ec6f48c7..7dde1c9f4 100644 --- a/src/actions/CMakeLists.txt +++ b/src/actions/CMakeLists.txt @@ -5,6 +5,8 @@ set ( ACTIONS_INCLUDES set (IPS_ACTION_SOURCES actions.cc + actions_module.cc + actions_module.h ips_actions.cc ips_actions.h act_alert.cc @@ -33,7 +35,7 @@ else (STATIC_IPS_ACTIONS) ${IPS_ACTION_SOURCES} ) - add_dynamic_module(act_react ips_actions act_react.cc) + add_dynamic_module(act_react ips_actions act_react.cc actions_module.cc) endif (STATIC_IPS_ACTIONS) diff --git a/src/actions/act_alert.cc b/src/actions/act_alert.cc index 72a181f8e..d46302d85 100644 --- a/src/actions/act_alert.cc +++ b/src/actions/act_alert.cc @@ -21,6 +21,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "protocols/packet.h" @@ -29,16 +30,30 @@ using namespace snort; -#define s_name "alert" - -#define s_help \ +#define action_name "alert" +#define action_help \ "generate alert on the current packet" +#define module_name "alert" +#define module_help \ + "manage the counters for the alert action" + +static THREAD_LOCAL struct AlertStats +{ + PegCount alert; +} alert_stats; + +const PegInfo alert_pegs[] = +{ + { CountType::SUM, "alert", "number of packets that matched an IPS alert rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- class AlertAction : public IpsAction { public: - AlertAction() : IpsAction(s_name, nullptr) { } + AlertAction() : IpsAction(action_name, nullptr) { } void exec(Packet*, const OptTreeNode* otn) override; }; @@ -46,9 +61,35 @@ public: void AlertAction::exec(Packet* p, const OptTreeNode* otn) { Actions::alert(p, otn); + ++alert_stats.alert; } //------------------------------------------------------------------------- +class AlertActionModule : public Module +{ +public: + AlertActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, alert_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return alert_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&alert_stats; } +}; + +//------------------------------------------------------------------------- +static Module* mod_ctor() +{ return new AlertActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } static IpsAction* alert_ctor(Module*) { return new AlertAction; } @@ -65,10 +106,10 @@ static ActionApi alert_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_ALERT, nullptr, diff --git a/src/actions/act_block.cc b/src/actions/act_block.cc index 244a0739b..7e9e0d5df 100644 --- a/src/actions/act_block.cc +++ b/src/actions/act_block.cc @@ -21,6 +21,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "packet_io/active.h" @@ -30,16 +31,30 @@ using namespace snort; -#define s_name "block" - -#define s_help \ +#define action_name "block" +#define action_help \ "block current packet and all the subsequent packets in this flow" +#define module_name "block" +#define module_help \ + "manage the counters for the block action" + +static THREAD_LOCAL struct BlockStats +{ + PegCount block; +} block_stats; + +const PegInfo block_pegs[] = +{ + { CountType::SUM, "block", "number of packets that matched an IPS block rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- class BlockAction : public IpsAction { public: - BlockAction() : IpsAction(s_name, nullptr) { } + BlockAction() : IpsAction(action_name, nullptr) { } void exec(Packet*, const OptTreeNode* otn) override; bool drops_traffic() override { return true; } @@ -51,9 +66,35 @@ void BlockAction::exec(Packet* p, const OptTreeNode* otn) p->active->set_drop_reason("ips"); Actions::alert(p, otn); + ++block_stats.block; } //------------------------------------------------------------------------- +class BlockActionModule : public Module +{ +public: + BlockActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, block_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return block_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&block_stats; } +}; + +//------------------------------------------------------------------------- +static Module* mod_ctor() +{ return new BlockActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } static IpsAction* block_ctor(Module*) { return new BlockAction; } @@ -70,10 +111,10 @@ static ActionApi block_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_BLOCK, nullptr, diff --git a/src/actions/act_drop.cc b/src/actions/act_drop.cc index 2e112ae6b..ae69f6e3e 100644 --- a/src/actions/act_drop.cc +++ b/src/actions/act_drop.cc @@ -21,6 +21,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "packet_io/active.h" @@ -30,16 +31,30 @@ using namespace snort; -#define s_name "drop" - -#define s_help \ +#define action_name "drop" +#define action_help \ "drop the current packet" +#define module_name "drop" +#define module_help \ + "manage the counters for the drop action" + +static THREAD_LOCAL struct DropStats +{ + PegCount drop; +} drop_stats; + +const PegInfo drop_pegs[] = +{ + { CountType::SUM, "drop", "number of packets that matched an IPS drop rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- class DropAction : public IpsAction { public: - DropAction() : IpsAction(s_name, nullptr) { } + DropAction() : IpsAction(action_name, nullptr) { } void exec(Packet*, const OptTreeNode* otn) override; bool drops_traffic() override { return true; } @@ -51,9 +66,36 @@ void DropAction::exec(Packet* p, const OptTreeNode* otn) p->active->set_drop_reason("ips"); Actions::alert(p, otn); + ++drop_stats.drop; } //------------------------------------------------------------------------- +class DropActionModule : public Module +{ +public: + DropActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, drop_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return drop_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&drop_stats; } +}; + +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ return new DropActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } static IpsAction* drop_ctor(Module*) { return new DropAction; } @@ -70,10 +112,10 @@ static ActionApi drop_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_DROP, nullptr, diff --git a/src/actions/act_file_id.cc b/src/actions/act_file_id.cc index fb5af763f..70386fbee 100644 --- a/src/actions/act_file_id.cc +++ b/src/actions/act_file_id.cc @@ -22,6 +22,7 @@ #endif #include "actions.h" +#include "actions/actions_module.h" #include "detection/detect.h" #include "file_api/file_flows.h" #include "file_api/file_identifier.h" @@ -31,11 +32,25 @@ using namespace snort; -#define s_name "file_id" - -#define s_help \ +#define action_name "file_id" +#define action_help \ "file_id file type id" +#define module_name "file_id_action" +#define module_help \ + "manage the counters for the file_id action" + +static THREAD_LOCAL struct File_IdStats +{ + PegCount file_id; +} file_id_stats; + +const PegInfo file_id_pegs[] = +{ + { CountType::SUM, "file_id", "number of packets that matched an IPS file_id rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- // ips action //------------------------------------------------------------------------- @@ -43,7 +58,7 @@ using namespace snort; class File_IdAction : public IpsAction { public: - File_IdAction() : IpsAction(s_name, nullptr) { } + File_IdAction() : IpsAction(action_name, nullptr) { } void exec(Packet*, const OptTreeNode* otn) override; }; @@ -58,10 +73,38 @@ void File_IdAction::exec(Packet* p, const OptTreeNode* otn) if (!file) return; file->set_file_type(otn->sigInfo.file_id); + + ++file_id_stats.file_id; } //------------------------------------------------------------------------- +class File_IdActionModule : public Module +{ +public: + File_IdActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, file_id_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return file_id_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&file_id_stats; } +}; + +//------------------------------------------------------------------------- +static Module* mod_ctor() +{ return new File_IdActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } + static IpsAction* file_id_ctor(Module*) { return new File_IdAction; } @@ -77,10 +120,10 @@ static ActionApi file_id_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_OTHER, nullptr, diff --git a/src/actions/act_log.cc b/src/actions/act_log.cc index 5293e6d15..8b6689c75 100644 --- a/src/actions/act_log.cc +++ b/src/actions/act_log.cc @@ -21,6 +21,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "protocols/packet.h" @@ -29,16 +30,30 @@ using namespace snort; -#define s_name "log" - -#define s_help \ +#define action_name "log" +#define action_help \ "log the current packet" +#define module_name "log" +#define module_help \ + "manage the counters for the log action" + +static THREAD_LOCAL struct LogStats +{ + PegCount log; +} log_stats; + +const PegInfo log_pegs[] = +{ + { CountType::SUM, "log", "number of packets that matched an IPS log rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- class LogAction : public IpsAction { public: - LogAction() : IpsAction(s_name, nullptr) { } + LogAction() : IpsAction(action_name, nullptr) { } void exec(Packet*, const OptTreeNode* otn) override; }; @@ -46,11 +61,40 @@ public: void LogAction::exec(Packet* p, const OptTreeNode* otn) { if ( otn ) + { Actions::log(p, otn); + ++log_stats.log; + } } //------------------------------------------------------------------------- +class LogActionModule : public Module +{ +public: + LogActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, log_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return log_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&log_stats; } +}; + +//------------------------------------------------------------------------- +static Module* mod_ctor() +{ return new LogActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } + static IpsAction* log_ctor(Module*) { return new LogAction; } @@ -66,10 +110,10 @@ static ActionApi log_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_LOG, nullptr, diff --git a/src/actions/act_pass.cc b/src/actions/act_pass.cc index 420887ee3..15987dbce 100644 --- a/src/actions/act_pass.cc +++ b/src/actions/act_pass.cc @@ -21,6 +21,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "protocols/packet.h" @@ -29,16 +30,30 @@ using namespace snort; -#define s_name "pass" - -#define s_help \ +#define action_name "pass" +#define action_help \ "mark the current packet as passed" +#define module_name "pass" +#define module_help \ + "manage the counters for the pass action" + +static THREAD_LOCAL struct PassStats +{ + PegCount pass; +} pass_stats; + +const PegInfo pass_pegs[] = +{ + { CountType::SUM, "pass", "number of packets that matched an IPS pass rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- class PassAction : public IpsAction { public: - PassAction() : IpsAction(s_name, nullptr) { } + PassAction() : IpsAction(action_name, nullptr) { } void exec(Packet*, const OptTreeNode*) override; }; @@ -49,11 +64,38 @@ void PassAction::exec(Packet* p, const OptTreeNode* otn) { Actions::pass(); p->packet_flags |= PKT_PASS_RULE; + ++pass_stats.pass; } } //------------------------------------------------------------------------- +class PassActionModule : public Module +{ +public: + PassActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, pass_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return pass_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&pass_stats; } +}; + +//------------------------------------------------------------------------- +static Module* mod_ctor() +{ return new PassActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } + static IpsAction* pass_ctor(Module*) { return new PassAction; } @@ -69,10 +111,10 @@ static ActionApi pass_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_PASS, nullptr, diff --git a/src/actions/act_react.cc b/src/actions/act_react.cc index 091c91788..14ed536ce 100644 --- a/src/actions/act_react.cc +++ b/src/actions/act_react.cc @@ -48,6 +48,7 @@ #include #include +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "log/messages.h" @@ -67,11 +68,14 @@ using namespace snort; using namespace HttpCommon; using namespace Http2Enums; -#define s_name "react" - -#define s_help \ +#define action_name "react" +#define action_help \ "send response to client and terminate session" +#define module_name "react" +#define module_help \ + "manage the data and the counters for the react action" + static THREAD_LOCAL ProfileStats reactPerfStats; #define DEFAULT_HTTP \ @@ -129,6 +133,18 @@ private: std::string resp_buf; // response to send }; +static THREAD_LOCAL struct ReactStats +{ + PegCount react; +} react_stats; + +const PegInfo react_pegs[] = +{ + { CountType::SUM, "react", "number of packets that matched an IPS react rule" }, + { CountType::END, nullptr, nullptr } +}; + + //------------------------------------------------------------------------- // active action //------------------------------------------------------------------------- @@ -192,7 +208,7 @@ class ReactAction : public IpsAction { public: ReactAction(ReactData* c) - : IpsAction(s_name, &react_act_action), config(c), react_act_action(c) + : IpsAction(action_name, &react_act_action), config(c), react_act_action(c) { } ~ReactAction() override @@ -212,13 +228,14 @@ void ReactAction::exec(Packet* p, const OptTreeNode* otn) p->active->set_drop_reason("ips"); Actions::alert(p, otn); + ++react_stats.react; } //------------------------------------------------------------------------- // module //------------------------------------------------------------------------- -static const Parameter s_params[] = +static const Parameter module_params[] = { { "page", Parameter::PT_STRING, nullptr, nullptr, "file containing HTTP response body" }, @@ -229,8 +246,8 @@ static const Parameter s_params[] = class ReactModule : public Module { public: - ReactModule() : Module(s_name, s_help, s_params) - { } + ReactModule() : Module(module_name, module_help, module_params) + { ActionsModule::add_action(module_name, react_pegs); } bool begin(const char*, int, SnortConfig*) override; bool set(const char*, Value&, SnortConfig*) override; @@ -256,6 +273,18 @@ public: std::string get_data(); + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return react_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&react_stats; } + private: std::string page; bool getpage(const char* file); @@ -327,8 +356,8 @@ static const ActionApi react_api = 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, + action_name, + action_help, mod_ctor, mod_dtor }, diff --git a/src/actions/act_reject.cc b/src/actions/act_reject.cc index 1a6844c56..28bc7d805 100644 --- a/src/actions/act_reject.cc +++ b/src/actions/act_reject.cc @@ -48,6 +48,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "framework/ips_action.h" #include "framework/module.h" #include "main/snort_config.h" @@ -58,11 +59,14 @@ using namespace snort; -#define s_name "reject" - -#define s_help \ +#define action_name "reject" +#define action_help \ "terminate session with TCP reset or ICMP unreachable" +#define module_name "reject" +#define module_help \ + "manage the data and the counters for the reject action" + enum { REJ_NONE = 0x00, @@ -78,6 +82,17 @@ enum THREAD_LOCAL ProfileStats rejPerfStats; +static THREAD_LOCAL struct RejectStats +{ + PegCount reject; +} reject_stats; + +const PegInfo reject_pegs[] = +{ + { CountType::SUM, "reject", "number of packets that matched an IPS reject rule" }, + { CountType::END, nullptr, nullptr } +}; + //------------------------------------------------------------------------- // active action //------------------------------------------------------------------------- @@ -165,7 +180,7 @@ private: // class methods //------------------------------------------------------------------------- -RejectAction::RejectAction(uint32_t f) : IpsAction(s_name, &rej_act_action) , rej_act_action(f) +RejectAction::RejectAction(uint32_t f) : IpsAction(action_name, &rej_act_action) , rej_act_action(f) { } void RejectAction::exec(Packet* p, const OptTreeNode* otn) @@ -176,13 +191,14 @@ void RejectAction::exec(Packet* p, const OptTreeNode* otn) p->active->update_status(p); Actions::alert(p, otn); + ++reject_stats.reject; } //------------------------------------------------------------------------- // module //------------------------------------------------------------------------- -static const Parameter s_params[] = +static const Parameter module_params[] = { { "reset", Parameter::PT_ENUM, "none|source|dest|both", "both", "send TCP reset to one or both ends" }, @@ -196,7 +212,8 @@ static const Parameter s_params[] = class RejectModule : public Module { public: - RejectModule() : Module(s_name, s_help, s_params) { } + RejectModule() : Module(module_name, module_help, module_params) + { ActionsModule::add_action(module_name, reject_pegs); } bool begin(const char*, int, SnortConfig*) override; bool set(const char*, Value&, SnortConfig*) override; @@ -209,6 +226,18 @@ public: uint32_t get_data(); + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return reject_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&reject_stats; } + private: uint32_t flags = 0; }; @@ -298,8 +327,8 @@ static const ActionApi rej_api = 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, + action_name, + action_help, mod_ctor, mod_dtor }, diff --git a/src/actions/act_replace.cc b/src/actions/act_replace.cc index 0cb023bdd..14c24fa4d 100644 --- a/src/actions/act_replace.cc +++ b/src/actions/act_replace.cc @@ -21,6 +21,7 @@ #include "config.h" #endif +#include "actions/actions_module.h" #include "detection/detection_engine.h" #include "framework/ips_action.h" #include "framework/module.h" @@ -31,11 +32,25 @@ using namespace snort; -#define s_name "rewrite" - -#define s_help \ +#define action_name "rewrite" +#define action_help \ "overwrite packet contents with the \"replace\" option content" +#define module_name "rewrite" +#define module_help \ + "manage the counters for the rewrite action" + +static THREAD_LOCAL struct ReplaceStats +{ + PegCount replace; +} replace_stats; + +const PegInfo replace_pegs[] = +{ + { CountType::SUM, "rewrite", "number of packets that matched an IPS rewrite rule" }, + { CountType::END, nullptr, nullptr } +}; + //-------------------------------------------------------------------------- // queue foo //-------------------------------------------------------------------------- @@ -96,7 +111,7 @@ void ReplaceActiveAction::delayed_exec(Packet* p) class ReplaceAction : public IpsAction { public: - ReplaceAction() : IpsAction(s_name, &rep_act_action) { } + ReplaceAction() : IpsAction(action_name, &rep_act_action) { } void exec(Packet*, const OptTreeNode* otn) override; @@ -109,10 +124,37 @@ void ReplaceAction::exec(Packet* p, const OptTreeNode* otn) p->active->rewrite_packet(p); Actions::alert(p, otn); + ++replace_stats.replace; } //------------------------------------------------------------------------- +class ReplaceActionModule : public Module +{ +public: + ReplaceActionModule() : Module(module_name, module_help) + { ActionsModule::add_action(module_name, replace_pegs); } + + bool stats_are_aggregated() const override + { return true; } + + void show_stats() override + { /* These stats are shown by ActionsModule. */ } + + const PegInfo* get_pegs() const override + { return replace_pegs; } + + PegCount* get_counts() const override + { return (PegCount*)&replace_stats; } +}; + +//------------------------------------------------------------------------- +static Module* mod_ctor() +{ return new ReplaceActionModule; } + +static void mod_dtor(Module* m) +{ delete m; } + static IpsAction* rep_ctor(Module*) { return new ReplaceAction; } @@ -128,10 +170,10 @@ static ActionApi rep_api 0, API_RESERVED, API_OPTIONS, - s_name, - s_help, - nullptr, // mod_ctor - nullptr, // mod_dtor + action_name, + action_help, + mod_ctor, + mod_dtor, }, IpsAction::IAP_REWRITE, nullptr, diff --git a/src/actions/actions_module.cc b/src/actions/actions_module.cc new file mode 100644 index 000000000..ddeb0e4e9 --- /dev/null +++ b/src/actions/actions_module.cc @@ -0,0 +1,129 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2024-2024 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. +//-------------------------------------------------------------------------- + +// actions_module.cc author Steve Chew + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "actions_module.h" +#include "actions/actions.h" +#include "log/messages.h" +#include "managers/action_manager.h" +#include "managers/module_manager.h" + +const PegInfo end_peg[] = +{ + { CountType::END, nullptr, nullptr } +}; + +std::map> ActionsModule::module_peg_info_map { }; + +std::array ActionsModule::peg_info_array { {end_peg[0]} }; + +THREAD_LOCAL std::array ActionsModule::peg_count_array {{0}}; +THREAD_LOCAL std::array ActionsModule::prev_peg_count_array {{0}}; + + +void ActionsModule::add_action(std::string module_name, const PegInfo* pegs) +{ + std::vector aggregated_pegs; + for (int i = 0; pegs[i].type != CountType::END; i++) + aggregated_pegs.push_back(pegs[i]); + + module_peg_info_map.emplace(module_name, aggregated_pegs); + + // FIXIT-M: Probably not needed unless things change on a reload? + std::fill(std::begin(peg_info_array), std::end(peg_info_array), end_peg[0]); + + // Go through the module names alphabetically and add their pegs. + int i = 0; + for (const auto& kv : module_peg_info_map) + { + for (const auto& peg_info : kv.second) + { + peg_info_array[i++] = peg_info; + + // FIXIT-L: Limited by array size. + assert(i < MAX_ACTIONS); + if (i >= MAX_ACTIONS) + { + snort::WarningMessage("Exceeded max action pegs limit (%u). Ignoring remaining action pegs.\n", MAX_ACTIONS); + return; + } + } + } + + // Peg info array must terminate with CountType::END. + peg_info_array[i] = end_peg[0]; +} + +void ActionsModule::prep_counts(bool dump_stats) +{ + int peg_count = 0; + for (auto& kv : module_peg_info_map) + { + Module* mod = snort::ModuleManager::get_module(kv.first.c_str()); + const PegInfo* pegs = mod->get_pegs(); + const PegCount* counts = mod->get_counts(); + + for (int i=0; pegs[i].type != CountType::END; i++) + { + for (const auto& peg_info : kv.second) + { + if (0 == strcmp(peg_info.name, pegs[i].name)) + { + if (dump_stats) + { + // For dumping stats + peg_count_array[peg_count++] = counts[i]; + } + else + { + // For perf monitor + peg_count_array[peg_count] = counts[i] - prev_peg_count_array[peg_count]; + prev_peg_count_array[peg_count] = counts[i]; + + ++peg_count; + } + + // FIXIT-L: Limited by array size. + assert(peg_count < MAX_ACTIONS); + if (peg_count >= MAX_ACTIONS) + return; + break; + } + } + } + } +} + +PegCount* ActionsModule::get_counts() const +{ + return (PegCount*)&peg_count_array[0]; +} + +const PegInfo* ActionsModule::get_pegs() const +{ + return (PegInfo*)&peg_info_array[0]; +} + diff --git a/src/actions/actions_module.h b/src/actions/actions_module.h new file mode 100644 index 000000000..703b8ce3b --- /dev/null +++ b/src/actions/actions_module.h @@ -0,0 +1,62 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2024-2024 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. +//-------------------------------------------------------------------------- + +// actions_module.h author Steve Chew + +// Aggregates counters from all of the IPS actions. + +#ifndef ACTIONS_MODULE_H +#define ACTIONS_MODULE_H + +#include +#include + +#include "framework/module.h" + +#define ACTIONS_ARRAY_SIZE UINT8_MAX +#define MAX_ACTIONS (ACTIONS_ARRAY_SIZE-1) + +class ActionsModule : public snort::Module +{ +public: + ActionsModule() : snort::Module("ips_actions", "aggregate action counters") + { } + + Usage get_usage() const override + { return GLOBAL; } + + static void add_action(std::string module_name, const PegInfo* pegs); + void prep_counts(bool) override; + PegCount* get_counts() const override; + const PegInfo* get_pegs() const override; + + bool counts_need_prep() const override + { return true; } + + bool is_aggregator() const override + { return true; } + +private: + static std::map> module_peg_info_map; + static std::array peg_info_array; + static THREAD_LOCAL std::array peg_count_array; + static THREAD_LOCAL std::array prev_peg_count_array; +}; + +#endif + diff --git a/src/framework/base_api.h b/src/framework/base_api.h index 421b320e1..49bbfdf09 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 16 +#define BASE_API_VERSION 17 // set options to API_OPTIONS to ensure compatibility #ifndef API_OPTIONS diff --git a/src/framework/module.h b/src/framework/module.h index 24b87b537..f2f97bfab 100644 --- a/src/framework/module.h +++ b/src/framework/module.h @@ -171,6 +171,16 @@ public: virtual bool global_stats() const { return false; } + // Return true only if all of the module's stats are aggregated into + // another module. + virtual bool stats_are_aggregated() const + { return false; } + + // Return true only if all of the module's stats are aggregated from + // other modules. + virtual bool is_aggregator() const + { return false; } + virtual void sum_stats(bool dump_stats); virtual void show_interval_stats(IndexVec&, FILE*); virtual void show_stats(); diff --git a/src/main/modules.cc b/src/main/modules.cc index 59ee55975..e6db41f74 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -26,6 +26,7 @@ #include +#include "actions/actions_module.h" #include "codecs/codec_module.h" #include "detection/detection_module.h" #include "detection/fp_config.h" @@ -1968,6 +1969,7 @@ void module_init() ModuleManager::add_module(new SearchEngineModule); ModuleManager::add_module(new SFDAQModule); ModuleManager::add_module(new PayloadInjectorModule); + ModuleManager::add_module(new ActionsModule); // these could but probably shouldn't be policy specific // or should be broken into policy and non-policy parts diff --git a/src/managers/module_manager.cc b/src/managers/module_manager.cc index f28d832f4..32747e352 100644 --- a/src/managers/module_manager.cc +++ b/src/managers/module_manager.cc @@ -1332,7 +1332,7 @@ void ModuleManager::show_pegs(const char* pfx, bool exact) const Module* m = mh->mod; assert(m); - if ( !selected(m, pfx, exact) ) + if ( !selected(m, pfx, exact) || m->stats_are_aggregated()) continue; const PegInfo* pegs = m->get_pegs(); diff --git a/src/network_inspectors/perf_monitor/base_tracker.cc b/src/network_inspectors/perf_monitor/base_tracker.cc index ced852c50..d89bcdf61 100644 --- a/src/network_inspectors/perf_monitor/base_tracker.cc +++ b/src/network_inspectors/perf_monitor/base_tracker.cc @@ -39,6 +39,9 @@ BaseTracker::BaseTracker(PerfConfig* perf) : PerfTracker(perf, PERF_NAME "_base" { for ( ModuleConfig& mod : modules ) { + if (mod.ptr->stats_are_aggregated()) + continue; + formatter->register_section(mod.ptr->get_name()); for ( auto const& idx : mod.pegs ) @@ -58,6 +61,9 @@ void BaseTracker::process(bool summary) { for ( const ModuleConfig& mod : modules ) { + if (mod.ptr->is_aggregator()) + continue; + if (strstr(ModuleManager::dynamic_stats_modules, mod.ptr->get_name()) || mod.ptr->global_stats()) { lock_guard lock(ModuleManager::stats_mutex);