#include "framework/so_rule.h"
#include "hash/hash_key_operations.h"
#include "log/messages.h"
+#include "main/snort_config.h"
#include "managers/so_manager.h"
#include "profiler/profiler.h"
class SoOption : public IpsOption
{
public:
- SoOption(const char*, const char*, bool, SoEvalFunc f, void* v);
+ SoOption(const char*, const char*, bool, SoEvalFunc f, void* v, SnortConfig*);
~SoOption() override;
uint32_t hash() const override;
bool relative_flag;
SoEvalFunc func;
void* data;
+ SoRules* so_rules;
};
SoOption::SoOption(
- const char* id, const char* s, bool r, SoEvalFunc f, void* v)
+ const char* id, const char* s, bool r, SoEvalFunc f, void* v, SnortConfig* sc)
: IpsOption(s_name)
{
soid = id;
relative_flag = r;
func = f;
data = v;
+ so_rules = sc->so_rules;
}
SoOption::~SoOption()
{
- if ( data )
- SoManager::delete_so_data(soid, data);
+ SoManager::delete_so_data(soid, data, so_rules);
}
uint32_t SoOption::hash() const
public:
string name;
bool relative_flag;
+ SnortConfig* cfg;
};
-bool SoModule::begin(const char*, int, SnortConfig*)
+bool SoModule::begin(const char*, int, SnortConfig* sc)
{
name.clear();
relative_flag = false;
+ cfg = sc;
return true;
}
ParseError("no soid before so:%s", name);
return nullptr;
}
- SoEvalFunc func = SoManager::get_so_eval(otn->soid, name, &data);
+ SoEvalFunc func = SoManager::get_so_eval(otn->soid, name, &data, m->cfg);
if ( !func )
{
ParseError("can't link so:%s", name);
return nullptr;
}
- return new SoOption(otn->soid, name, relative_flag, func, data);
+ return new SoOption(otn->soid, name, relative_flag, func, data, m->cfg);
}
static void so_dtor(IpsOption* p)
return 0;
}
const char* fname = nullptr;
+ const char* plugin_path = nullptr;
if ( L )
{
Lua::ManageStack(L, 1);
fname = luaL_checkstring(L, 1);
+ if (lua_gettop(L) > 1)
+ {
+ plugin_path = luaL_checkstring(L, 2);
+ std::ostringstream plugin_path_msg;
+ plugin_path_msg << "-- reload plugin_path: " << plugin_path << "\n";
+ current_request->respond(plugin_path_msg.str().c_str());
+ }
}
current_request->respond(".. reloading configuration\n");
SnortConfig* old = SnortConfig::get_conf();
- SnortConfig* sc = Snort::get_reload_config(fname);
+ SnortConfig* sc = Snort::get_reload_config(fname, plugin_path);
if ( !sc )
{
if ( !tc )
{
+ // FIXIT-L it does not seem a valid check, delete old config if come to it
current_request->respond("== reload failed - bad config\n");
SnortConfig::set_parser_conf(nullptr);
return 0;
}
+ PluginManager::reload_so_plugins_cleanup(sc);
SnortConfig::set_conf(sc);
proc_stats.conf_reloads++;
SnortConfig::set_conf(new SnortConfig);
ScriptManager::load_scripts(sc->script_paths);
PluginManager::load_plugins(sc->plugin_path);
+ PluginManager::load_so_plugins(sc);
ModuleManager::init();
switch ( ht )
ModuleManager::dump_rules(val);
break;
case HT_DDR:
- SoManager::dump_rule_stubs(val);
+ SoManager::dump_rule_stubs(val, sc);
break;
case HT_DFL:
ModuleManager::dump_defaults(val);
* Set the global snort_conf that will be used during run time */
sc->merge(snort_cmd_line_conf);
SnortConfig::set_conf(sc);
-
+ PluginManager::load_so_plugins(sc);
#ifdef PIGLET
if ( !Piglet::piglet_mode() )
#endif
// FIXIT-M refactor this so startup and reload call the same core function to
// instantiate things that can be reloaded
-SnortConfig* Snort::get_reload_config(const char* fname)
+SnortConfig* Snort::get_reload_config(const char* fname, const char* plugin_path)
{
reloading = true;
ModuleManager::reset_errors();
return nullptr;
}
+ PluginManager::reload_so_plugins(plugin_path, sc);
+
sc->setup();
#ifdef SHELL
class Snort
{
public:
- static SnortConfig* get_reload_config(const char* fname);
+ static SnortConfig* get_reload_config(const char* fname, const char* plugin_path = nullptr);
static SnortConfig* get_updated_policy(SnortConfig*, const char* fname, const char* iname);
static SnortConfig* get_updated_module(SnortConfig*, const char* name);
static void setup(int argc, char* argv[]);
#include "managers/ips_manager.h"
#include "managers/module_manager.h"
#include "managers/mpse_manager.h"
+#include "managers/plugin_manager.h"
+#include "managers/so_manager.h"
#include "memory/memory_config.h"
#include "packet_io/sfdaq.h"
#include "packet_io/sfdaq_config.h"
memset(evalOrder, 0, sizeof(evalOrder));
proto_ref = new ProtocolReference(protocol_reference);
flowbits_ginit(this);
+ so_rules = new SoRules;
}
else
{
delete memory;
delete daq_config;
delete proto_ref;
-
+ delete so_rules;
+ if ( plugins )
+ delete plugins;
reload_tuners.clear();
trim_heap();
struct IpsActionsConfig;
struct LatencyConfig;
struct MemoryConfig;
+struct Plugins;
struct PORT_RULE_MAP;
struct RateFilterConfig;
struct ReferenceSystemNode;
struct RuleListNode;
struct RulePortTables;
struct SFDAQConfig;
+struct SoRules;
struct ThresholdConfig;
struct VarNode;
//Reload inspector related
bool cloned = false;
-
+ Plugins* plugins = nullptr;
+ SoRules* so_rules = nullptr;
private:
std::list<ReloadResourceTuner*> reload_tuners;
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
+static const Parameter s_reload_w_path[] =
+{
+ { "filename", Parameter::PT_STRING, "(optional)", nullptr,
+ "[<plugin path>] name of file to load" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
static const Parameter s_delete[] =
{
{ "inspector", Parameter::PT_STRING, nullptr, nullptr,
{ "dump_stats", main_dump_stats, nullptr, "show summary statistics" },
{ "rotate_stats", main_rotate_stats, nullptr, "roll perfmonitor log files" },
- { "reload_config", main_reload_config, s_reload, "load new configuration" },
+ { "reload_config", main_reload_config, s_reload_w_path, "load new configuration" },
{ "reload_policy", main_reload_policy, s_reload, "reload part or all of the default policy" },
{ "reload_module", main_reload_module, s_module, "reload module" },
{ "reload_daq", main_reload_daq, nullptr, "reload daq module" },
#include <dlfcn.h>
#include <iostream>
-#include <map>
#include <sstream>
#include <sys/stat.h>
#include "helpers/directory.h"
#include "helpers/markup.h"
#include "log/messages.h"
+#include "main/snort_config.h"
#ifdef PIGLET
#include "piglet/piglet_api.h"
{
string source;
string key;
-
- const BaseApi* api;
- void* handle;
-
- Plugin()
- { clear(); }
-
- void clear()
- { source.clear(); key.clear(); api = nullptr; handle = nullptr; }
+ const BaseApi* api = nullptr;
+ SoHandlePtr handle;
};
-typedef std::map<string, Plugin> PlugMap;
-static PlugMap plug_map;
-
-struct RefCount
+Plugins::~Plugins()
{
- unsigned count;
-
- RefCount() { count = 0; }
+ plug_map.clear();
+}
- //~RefCount() { assert(!count); }; // FIXIT-L fails on fatal error
-};
+SoHandle::~SoHandle()
+{
+#ifndef REG_TEST
+ if ( handle )
+ dlclose(handle);
+#endif
+}
-typedef std::map<void*, RefCount> RefMap;
-static RefMap ref_map;
+static Plugins s_plugins;
static void set_key(string& key, Symbol* sym, const char* name)
{
return true;
}
+static bool plugin_is_reloadable(const BaseApi* api)
+{
+ if ( api->type == PT_SO_RULE )
+ return true;
+ else
+ return false;
+}
+
static bool register_plugin(
- const BaseApi* api, void* handle, const char* file)
+ const BaseApi* api, SoHandlePtr handle, const char* file, SnortConfig* sc)
{
if ( api->type >= PT_MAX )
return false;
return false;
}
- // validate api ?
+ if ( sc and !plugin_is_reloadable(api) )
+ return false;
string key;
set_key(key, sym, api->name);
- Plugin& p = plug_map[key];
-
+ Plugin& p = ( sc ? sc->plugins->plug_map[key] : s_plugins.plug_map[key] );
if ( p.api )
{
- if ( p.api->version >= api->version)
+ if ( p.api->version > api->version )
return false; // keep the old one
-
- if ( p.handle && !--ref_map[p.handle].count )
- dlclose(p.handle); // drop the old one
}
p.key = key;
p.handle = handle;
p.source = file;
- if ( handle )
- ++ref_map[handle].count;
-
return true;
}
static void load_list(
- const BaseApi** api, void* handle = nullptr, const char* file = "static")
+ const BaseApi** api, void* handle = nullptr, const char* file = "static", SnortConfig* sc = nullptr)
{
- bool keep = false;
+ SoHandlePtr so_file;
+ if ( handle and sc )
+ { // for reload, if the so lib file was previously opened, reuse the shared_ptr
+ for( auto const& i : s_plugins.plug_map )
+ {
+ if ( i.second.api == (*api) and i.second.handle.get()->handle == handle )
+ {
+ so_file = i.second.handle;
+ break;
+ }
+ }
+ }
+ if ( !so_file.get() )
+ so_file = std::make_shared<SoHandle>(handle);
while ( *api )
{
- keep = register_plugin(*api, handle, file) || keep;
- //printf("loaded %s\n", (*api)->name);
+ register_plugin(*api, so_file, file, sc);
++api;
}
- if ( handle && !keep )
- dlclose(handle);
}
-static bool load_lib(const char* file)
+static bool load_lib(const char* file, SnortConfig* sc)
{
struct stat fs;
void* handle;
dlclose(handle);
return false;
}
- load_list(api, handle, file);
+ load_list(api, handle, file, sc);
return true;
}
break;
case PT_SO_RULE:
- SoManager::add_plugin((const SoApi*)p.api);
+ // SO rules are added later
break;
case PT_LOGGER:
}
}
-static void load_plugins(const std::string& paths)
+static void load_plugins(const std::string& paths, SnortConfig* sc = nullptr)
{
struct stat sb;
stringstream paths_stream(paths);
Directory d(path.c_str(), lib_pattern);
while ( const char* f = d.next() )
- load_lib(f);
+ load_lib(f, sc);
}
else
{
if ( path.find("/") == string::npos )
path = "./" + path;
- load_lib(path.c_str());
+ load_lib(path.c_str(), sc);
}
}
}
static void add_plugins()
{
- PlugMap::iterator it;
-
- for ( it = plug_map.begin(); it != plug_map.end(); ++it )
+ for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it )
add_plugin(it->second);
}
static void unload_plugins()
{
- for ( PlugMap::iterator it = plug_map.begin(); it != plug_map.end(); ++it )
- {
- if ( it->second.handle )
- --ref_map[it->second.handle].count;
-
- it->second.clear();
- }
-
-#ifndef REG_TEST
- for ( RefMap::iterator it = ref_map.begin(); it != ref_map.end(); ++it )
- dlclose(it->first);
-#endif
+ s_plugins.plug_map.clear();
}
//-------------------------------------------------------------------------
add_plugins();
}
-void PluginManager::list_plugins()
+void PluginManager::reload_so_plugins(const char* paths, SnortConfig* sc)
+{
+ sc->plugins = new Plugins;
+ sc->plugins->plug_map = s_plugins.plug_map;
+ if ( paths )
+ {
+ // once plugin_path is provided for reload, old so_rules will be dropped
+ for( auto i = sc->plugins->plug_map.begin(); i != sc->plugins->plug_map.end(); ++i )
+ if ( plugin_is_reloadable(i->second.api) )
+ sc->plugins->plug_map.erase(i);
+ ::load_plugins(paths, sc);
+ }
+ load_so_plugins(sc, true);
+}
+
+void PluginManager::reload_so_plugins_cleanup(SnortConfig* sc)
{
- PlugMap::iterator it;
+ if ( !sc->plugins )
+ return;
- for ( it = plug_map.begin(); it != plug_map.end(); ++it )
+ // set the new plugins to current
+ s_plugins.plug_map.clear();
+ s_plugins.plug_map = sc->plugins->plug_map;
+ sc->plugins->plug_map.clear();
+}
+
+void PluginManager::load_so_plugins(SnortConfig* sc, bool is_reload)
+{
+ auto p = is_reload ? sc->plugins->plug_map : s_plugins.plug_map;
+ for ( auto it = p.begin(); it != p.end(); ++it )
+ if ( it->second.api->type == PT_SO_RULE )
+ SoManager::add_plugin((const SoApi*)it->second.api, sc, it->second.handle);
+}
+
+void PluginManager::list_plugins()
+{
+ for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it )
{
Plugin& p = it->second;
cout << Markup::item();
void PluginManager::show_plugins()
{
- PlugMap::iterator it;
-
- for ( it = plug_map.begin(); it != plug_map.end(); ++it )
+ for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it )
{
Plugin& p = it->second;
ActionManager::release_plugins();
InspectorManager::release_plugins();
IpsManager::release_plugins();
- SoManager::release_plugins();
MpseManager::release_plugins();
CodecManager::release_plugins();
ConnectorManager::release_plugins();
string key;
set_key(key, symbols+type, name);
- const PlugMap::iterator it = plug_map.find(key);
+ auto it = s_plugins.plug_map.find(key);
- if ( it != plug_map.end() )
+ if ( it != s_plugins.plug_map.end() )
return it->second.api;
return nullptr;
#ifdef PIGLET
PlugType PluginManager::get_type_from_name(const std::string& name)
{
- for ( auto it = plug_map.begin(); it != plug_map.end(); ++it )
+ for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it )
{
const auto* api = it->second.api;
if ( name == api->name )
{
static std::string s;
s.clear();
-
- for ( auto it = plug_map.begin(); it != plug_map.end(); ++it )
+ for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it )
{
const auto* api = it->second.api;
}
return s.c_str();
}
-
// based on configuration.
//-------------------------------------------------------------------------
+#include <map>
+#include <memory>
#include <string>
#include "framework/base_api.h"
const char* name);
static const char* get_available_plugins(PlugType);
+ static void load_so_plugins(snort::SnortConfig*, bool is_reload = false);
+ static void reload_so_plugins(const char*, snort::SnortConfig*);
+ static void reload_so_plugins_cleanup(snort::SnortConfig*);
};
+struct Plugin;
+struct Plugins
+{
+ std::map<std::string, Plugin> plug_map;
+ ~Plugins();
+};
+
+struct SoHandle
+{
+ void* handle;
+
+ SoHandle(void* h) : handle(h) { }
+ ~SoHandle();
+};
+
+using SoHandlePtr = std::shared_ptr<SoHandle>;
+
#endif
#include <cstring>
#include <iomanip>
#include <iostream>
-#include <list>
#include <sstream>
#include "log/messages.h"
+#include "main/snort_config.h"
#include "parser/parse_so_rule.h"
using namespace snort;
using namespace std;
-static list<const SoApi*> s_rules;
-
//-------------------------------------------------------------------------
// plugins
//-------------------------------------------------------------------------
-
-void SoManager::add_plugin(const SoApi* api)
+SoRules::~SoRules()
{
- s_rules.emplace_back(api);
+ api.clear();
+ handles.clear();
}
-void SoManager::release_plugins()
+void SoManager::add_plugin(const SoApi* api, SnortConfig* sc, SoHandlePtr handle)
{
- s_rules.clear();
+ sc->so_rules->api.emplace_back(api);
+ sc->so_rules->handles.emplace_back(handle);
}
void SoManager::dump_plugins()
{
Dumper d("SO Rules");
- for ( auto* p : s_rules )
+ for ( auto* p : SnortConfig::get_conf()->so_rules->api )
d.dump(p->base.name, p->base.version);
}
//-------------------------------------------------------------------------
-static const SoApi* get_so_api(const char* soid)
+static const SoApi* get_so_api(const char* soid, SoRules* so_rules)
{
- for ( auto* p : s_rules )
+ for ( auto* p : so_rules->api )
if ( !strcmp(p->base.name, soid) )
return p;
return nullptr;
}
-const char* SoManager::get_so_rule(const char* soid)
+const char* SoManager::get_so_rule(const char* soid, SnortConfig* sc)
{
- const SoApi* api = get_so_api(soid);
+ const SoApi* api = get_so_api(soid, sc->so_rules);
if ( !api )
return nullptr;
return rule;
}
-SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data)
+SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data, SnortConfig* sc)
{
- const SoApi* api = get_so_api(soid);
+ const SoApi* api = get_so_api(soid, sc->so_rules);
if ( !api || !api->ctor )
return nullptr;
return api->ctor(so, data);
}
-void SoManager::delete_so_data(const char* soid, void* pv)
+void SoManager::delete_so_data(const char* soid, void* pv, SoRules* so_rules)
{
- const SoApi* api = get_so_api(soid);
+ if (!pv or !so_rules)
+ return;
+ const SoApi* api = get_so_api(soid, so_rules);
if ( api && api->dtor )
api->dtor(pv);
//-------------------------------------------------------------------------
-void SoManager::dump_rule_stubs(const char*)
+void SoManager::dump_rule_stubs(const char*, SnortConfig* sc)
{
unsigned c = 0;
- for ( auto* p : s_rules )
+ for ( auto* p : sc->so_rules->api )
{
const char* rule = revert(p->rule, p->length);
// Factory for shared object rules.
// Runtime is same as for text rules.
-
+#include <list>
#include "framework/so_rule.h"
+#include "managers/plugin_manager.h"
namespace snort
{
struct SnortConfig;
}
-struct SoApi;
//-------------------------------------------------------------------------
+struct SoRules
+{
+ std::list<const SoApi*> api;
+ std::list<SoHandlePtr> handles;
+ ~SoRules();
+};
class SoManager
{
public:
- static void add_plugin(const SoApi*);
+ static void add_plugin(const SoApi*, snort::SnortConfig*, SoHandlePtr);
static void dump_plugins();
- static void release_plugins();
static void instantiate(const SoApi*);
// soid is arg to soid option, so is arg to so option
- static const char* get_so_rule(const char* soid);
- static SoEvalFunc get_so_eval(const char* soid, const char* so, void** data);
- static void delete_so_data(const char* soid, void*);
+ static const char* get_so_rule(const char* soid, snort::SnortConfig* sc = nullptr);
+ static SoEvalFunc get_so_eval(const char* soid, const char* so,
+ void** data, snort::SnortConfig* sc = nullptr);
+ static void delete_so_data(const char* soid, void*, SoRules*);
static void rule_to_hex(const char* file);
static void rule_to_text(const char* file);
- static void dump_rule_stubs(const char*);
+ static void dump_rule_stubs(const char*, snort::SnortConfig*);
};
#endif
if ( rtn.dip )
sfvar_free(rtn.dip);
- const char* rule = SoManager::get_so_rule(otn->soid);
+ const char* rule = SoManager::get_so_rule(otn->soid, sc);
IpsManager::reset_options();
if ( !rule )