set (IPS_ACTION_SOURCES
actions.cc
+ actions_module.cc
+ actions_module.h
ips_actions.cc
ips_actions.h
act_alert.cc
${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)
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "protocols/packet.h"
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;
};
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; }
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,
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "packet_io/active.h"
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; }
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; }
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,
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "packet_io/active.h"
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; }
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; }
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,
#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"
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
//-------------------------------------------------------------------------
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;
};
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; }
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,
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "protocols/packet.h"
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;
};
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; }
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,
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "protocols/packet.h"
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;
};
{
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; }
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,
#include <fstream>
#include <string>
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "log/messages.h"
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 \
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
//-------------------------------------------------------------------------
{
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
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" },
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;
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);
0,
API_RESERVED,
API_OPTIONS,
- s_name,
- s_help,
+ action_name,
+ action_help,
mod_ctor,
mod_dtor
},
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "framework/ips_action.h"
#include "framework/module.h"
#include "main/snort_config.h"
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,
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
//-------------------------------------------------------------------------
// 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)
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" },
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;
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;
};
0,
API_RESERVED,
API_OPTIONS,
- s_name,
- s_help,
+ action_name,
+ action_help,
mod_ctor,
mod_dtor
},
#include "config.h"
#endif
+#include "actions/actions_module.h"
#include "detection/detection_engine.h"
#include "framework/ips_action.h"
#include "framework/module.h"
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
//--------------------------------------------------------------------------
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;
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; }
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,
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <stechew@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <algorithm>
+#include <vector>
+
+#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<std::string, std::vector<PegInfo>> ActionsModule::module_peg_info_map { };
+
+std::array<PegInfo, ACTIONS_ARRAY_SIZE> ActionsModule::peg_info_array { {end_peg[0]} };
+
+THREAD_LOCAL std::array<PegCount, ACTIONS_ARRAY_SIZE> ActionsModule::peg_count_array {{0}};
+THREAD_LOCAL std::array<PegCount, ACTIONS_ARRAY_SIZE> ActionsModule::prev_peg_count_array {{0}};
+
+
+void ActionsModule::add_action(std::string module_name, const PegInfo* pegs)
+{
+ std::vector<PegInfo> 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];
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <stechew@cisco.com>
+
+// Aggregates counters from all of the IPS actions.
+
+#ifndef ACTIONS_MODULE_H
+#define ACTIONS_MODULE_H
+
+#include <map>
+#include <vector>
+
+#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<std::string, std::vector<PegInfo>> module_peg_info_map;
+ static std::array<PegInfo, ACTIONS_ARRAY_SIZE> peg_info_array;
+ static THREAD_LOCAL std::array<PegCount, ACTIONS_ARRAY_SIZE> peg_count_array;
+ static THREAD_LOCAL std::array<PegCount, ACTIONS_ARRAY_SIZE> prev_peg_count_array;
+};
+
+#endif
+
// 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
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();
#include <sys/resource.h>
+#include "actions/actions_module.h"
#include "codecs/codec_module.h"
#include "detection/detection_module.h"
#include "detection/fp_config.h"
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
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();
{
for ( ModuleConfig& mod : modules )
{
+ if (mod.ptr->stats_are_aggregated())
+ continue;
+
formatter->register_section(mod.ptr->get_name());
for ( auto const& idx : mod.pegs )
{
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<mutex> lock(ModuleManager::stats_mutex);