#include "action_manager.h"
-#include <list>
+#include <vector>
#include "actions/act_replace.h"
#include "log/messages.h"
+#include "main/snort_config.h"
#include "packet_io/active.h"
#include "parser/parser.h"
using namespace snort;
using namespace std;
-struct Actor
+struct ActionClass
{
const ActionApi* api;
+ bool initialized = false; // In the context of the main thread, this means that api.pinit()
+ // has been called. In the packet thread, it means that api.tinit()
+ // has been called.
+
+ ActionClass(const ActionApi* p) : api(p) { }
+};
+
+struct ActionInst
+{
+ ActionClass& cls;
IpsAction* act;
- Actor(const ActionApi* p)
- { api = p; act = nullptr; }
+ ActionInst(ActionClass& cls, IpsAction* act) : cls(cls), act(act) { }
};
-typedef list<Actor> AList;
-static AList s_actors;
+struct IpsActionsConfig
+{
+ vector<ActionInst> clist;
+ IpsAction* reject = nullptr;
+};
+
+typedef vector<ActionClass> ACList;
-static IpsAction* s_reject = nullptr;
-static THREAD_LOCAL IpsAction* s_action = nullptr;
+static ACList s_actors;
+
+static THREAD_LOCAL ACList* s_tl_actors = nullptr;
+static THREAD_LOCAL IpsAction* s_tl_action = nullptr;
//-------------------------------------------------------------------------
-// action plugins
+// Main thread operations
//-------------------------------------------------------------------------
+// Plugin/Class operations
void ActionManager::add_plugin(const ActionApi* api)
{
- Actor a(api);
-
- if ( api->pinit )
- api->pinit();
-
- s_actors.emplace_back(a);
+ s_actors.emplace_back(api);
}
-void ActionManager::release_plugins()
+Actions::Type ActionManager::get_action_type(const char* s)
{
for ( auto& p : s_actors )
{
- p.api->dtor(p.act);
-
- if ( p.api->pterm )
- p.api->pterm();
+ if ( !strcmp(p.api->base.name, s) )
+ return p.api->type;
}
- s_actors.clear();
+ return Actions::NONE;
}
void ActionManager::dump_plugins()
d.dump(p.api->base.name, p.api->base.version);
}
-static void store(const ActionApi* api, IpsAction* act)
+void ActionManager::release_plugins()
{
for ( auto& p : s_actors )
- if ( p.api == api )
+ {
+ if ( p.api->pterm )
+ p.api->pterm();
+ }
+ s_actors.clear();
+}
+
+static ActionClass* get_action_class(const ActionApi* api, IpsActionsConfig* iac)
+{
+ for ( auto& ai : iac->clist )
+ {
+ if ( ai.cls.api == api )
+ return &ai.cls;
+ }
+
+ for ( auto& ac : s_actors )
+ {
+ if ( ac.api == api )
{
- //assert(!p.act); FIXIT-RC memory leak on reload; move to SnortConfig?
- p.act = act;
- break;
+ if ( !ac.initialized )
+ {
+ if ( ac.api->pinit )
+ ac.api->pinit();
+ ac.initialized = true;
+ }
+ return ∾
}
+ }
+
+ return nullptr;
}
-//-------------------------------------------------------------------------
+// Config operations
+void ActionManager::new_config(SnortConfig* sc)
+{
+ sc->ips_actions_config = new IpsActionsConfig;
+}
-Actions::Type ActionManager::get_action_type(const char* s)
+void ActionManager::delete_config(SnortConfig* sc)
{
- for ( auto& p : s_actors )
- {
- if ( !strcmp(p.api->base.name, s) )
- return p.api->type;
- }
- return Actions::NONE;
+ if (!sc->ips_actions_config)
+ return;
+
+ // Delete all IPS action instances that were created as part of this configuration
+ for (auto& ia : sc->ips_actions_config->clist)
+ ia.cls.api->dtor(ia.act);
+
+ delete sc->ips_actions_config;
+ sc->ips_actions_config = nullptr;
}
-void ActionManager::instantiate(
- const ActionApi* api, Module* m, SnortConfig* sc)
+void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc)
{
- IpsAction* act = api->ctor(m);
+ ActionClass* cls = get_action_class(api, sc->ips_actions_config);
+ assert(cls != nullptr);
+
+ IpsAction* act = cls->api->ctor(mod);
if ( act )
{
- if ( !s_reject && !strcmp(act->get_name(), "reject") )
- s_reject = act;
+ // Add this instance to the list of those created for this config
+ sc->ips_actions_config->clist.emplace_back(*cls, act);
+
+ // FIXIT-M Either you are static or you're not, make a choice.
+ // Anyway, if we happen to instantiate an action called reject, cache that for use later.
+ if ( !sc->ips_actions_config->reject && !strcmp(act->get_name(), "reject") )
+ sc->ips_actions_config->reject = act;
ListHead* lh = CreateRuleType(sc, api->base.name, api->type);
assert(lh);
lh->action = act;
+ }
+}
- store(api, act);
+//-------------------------------------------------------------------------
+// Packet thread operations
+//-------------------------------------------------------------------------
+static ActionClass& get_thread_local_action_class(const ActionApi* api)
+{
+ for ( ActionClass& p : *s_tl_actors )
+ {
+ if ( p.api == api )
+ return p;
}
+ s_tl_actors->emplace_back(api);
+ return s_tl_actors->back();
}
-void ActionManager::thread_init(SnortConfig*)
+void ActionManager::thread_init(SnortConfig* sc)
{
- for ( auto& p : s_actors )
- if ( p.api->tinit )
- p.api->tinit();
+ // Initial build out of this thread's configured plugin registry
+ s_tl_actors = new ACList;
+ for ( auto& p : sc->ips_actions_config->clist )
+ {
+ ActionClass& tlac = get_thread_local_action_class(p.cls.api);
+ if ( tlac.api->tinit )
+ tlac.api->tinit();
+ tlac.initialized = true;
+ }
+}
+
+void ActionManager::thread_reinit(SnortConfig* sc)
+{
+ // Update this thread's configured plugin registry with any newly configured inspectors
+ for ( auto& p : sc->ips_actions_config->clist )
+ {
+ ActionClass& tlac = get_thread_local_action_class(p.cls.api);
+ if (!tlac.initialized)
+ {
+ if ( tlac.api->tinit )
+ tlac.api->tinit();
+ tlac.initialized = true;
+ }
+ }
+ Active::thread_init(sc);
}
void ActionManager::thread_term(SnortConfig*)
{
- for ( auto& p : s_actors )
+ // Call tterm for every IPS action plugin ever configured during the lifetime of this thread
+ for ( auto& p : *s_tl_actors )
+ {
if ( p.api->tterm )
p.api->tterm();
+ }
+ delete s_tl_actors;
+ s_tl_actors = nullptr;
}
void ActionManager::execute(Packet* p)
{
- if ( s_action )
+ if ( s_tl_action )
{
- s_action->exec(p);
- s_action = nullptr;
+ s_tl_action->exec(p);
+ s_tl_action = nullptr;
}
}
void ActionManager::queue(IpsAction* a)
{
- if ( !s_action || a->get_action() > s_action->get_action() )
- s_action = a;
+ if ( !s_tl_action || a->get_action() > s_tl_action->get_action() )
+ s_tl_action = a;
}
-void ActionManager::queue_reject()
+void ActionManager::queue_reject(SnortConfig* sc)
{
- if ( s_reject )
- queue(s_reject);
+ if ( sc->ips_actions_config->reject )
+ queue(sc->ips_actions_config->reject);
}
void ActionManager::reset_queue()
{
- s_action = nullptr;
+ s_tl_action = nullptr;
Replace_ResetQueue();
}