From: Steve Chew (stechew) Date: Mon, 2 Mar 2020 15:39:36 +0000 (+0000) Subject: Merge pull request #2020 in SNORT/snort3 from ~SBAIGAL/snort3:so_reload_2 to master X-Git-Tag: 3.0.0-269~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8272a522fb45cd2ebce058850bf1616d9c54c856;p=thirdparty%2Fsnort3.git Merge pull request #2020 in SNORT/snort3 from ~SBAIGAL/snort3:so_reload_2 to master Squashed commit of the following: commit 0ffe1aa821d7d4e092a64173900e9a264f999dde Author: Steven Baigal (sbaigal) Date: Wed Feb 19 11:01:43 2020 -0500 plugin_manager: add support for reload so_rule plugins --- diff --git a/src/ips_options/ips_so.cc b/src/ips_options/ips_so.cc index ce7b452a3..f94702210 100644 --- a/src/ips_options/ips_so.cc +++ b/src/ips_options/ips_so.cc @@ -27,6 +27,7 @@ #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" @@ -40,7 +41,7 @@ static THREAD_LOCAL ProfileStats soPerfStats; 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; @@ -57,10 +58,11 @@ private: 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; @@ -68,12 +70,12 @@ SoOption::SoOption( 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 @@ -142,12 +144,14 @@ public: 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; } @@ -191,14 +195,14 @@ static IpsOption* so_ctor(Module* p, OptTreeNode* otn) 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) diff --git a/src/main.cc b/src/main.cc index 1b0ae01ed..f95e191b5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -329,16 +329,24 @@ int main_reload_config(lua_State* L) 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 ) { @@ -361,10 +369,12 @@ int main_reload_config(lua_State* L) 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++; diff --git a/src/main/help.cc b/src/main/help.cc index 1599a62b1..fa9e689a4 100644 --- a/src/main/help.cc +++ b/src/main/help.cc @@ -155,6 +155,7 @@ enum HelpType 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 ) @@ -172,7 +173,7 @@ enum HelpType 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); diff --git a/src/main/snort.cc b/src/main/snort.cc index 22ddc02e3..45c4548fc 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -155,7 +155,7 @@ void Snort::init(int argc, char** argv) * 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 @@ -428,7 +428,7 @@ void Snort::reload_failure_cleanup(SnortConfig* sc) // 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(); @@ -445,6 +445,8 @@ SnortConfig* Snort::get_reload_config(const char* fname) return nullptr; } + PluginManager::reload_so_plugins(plugin_path, sc); + sc->setup(); #ifdef SHELL diff --git a/src/main/snort.h b/src/main/snort.h index efe5a9e75..3efeb7fc4 100644 --- a/src/main/snort.h +++ b/src/main/snort.h @@ -38,7 +38,7 @@ struct SnortConfig; 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[]); diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 6a736a2c9..3fb2de0cf 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -47,6 +47,8 @@ #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" @@ -209,6 +211,7 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p memset(evalOrder, 0, sizeof(evalOrder)); proto_ref = new ProtocolReference(protocol_reference); flowbits_ginit(this); + so_rules = new SoRules; } else { @@ -304,7 +307,9 @@ SnortConfig::~SnortConfig() delete memory; delete daq_config; delete proto_ref; - + delete so_rules; + if ( plugins ) + delete plugins; reload_tuners.clear(); trim_heap(); diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 4c5dcdc1b..ce428f451 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -136,12 +136,14 @@ struct HighAvailabilityConfig; 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; @@ -413,7 +415,8 @@ public: //Reload inspector related bool cloned = false; - + Plugins* plugins = nullptr; + SoRules* so_rules = nullptr; private: std::list reload_tuners; diff --git a/src/main/snort_module.cc b/src/main/snort_module.cc index a6d5f750f..17cd9c3c0 100644 --- a/src/main/snort_module.cc +++ b/src/main/snort_module.cc @@ -65,6 +65,14 @@ static const Parameter s_reload[] = { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; +static const Parameter s_reload_w_path[] = +{ + { "filename", Parameter::PT_STRING, "(optional)", nullptr, + "[] name of file to load" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + static const Parameter s_delete[] = { { "inspector", Parameter::PT_STRING, nullptr, nullptr, @@ -98,7 +106,7 @@ static const Command snort_cmds[] = { "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" }, diff --git a/src/managers/plugin_manager.cc b/src/managers/plugin_manager.cc index a0ea0c35d..63fc5a3f1 100644 --- a/src/managers/plugin_manager.cc +++ b/src/managers/plugin_manager.cc @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -36,6 +35,7 @@ #include "helpers/directory.h" #include "helpers/markup.h" #include "log/messages.h" +#include "main/snort_config.h" #ifdef PIGLET #include "piglet/piglet_api.h" @@ -125,31 +125,24 @@ struct Plugin { 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 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 RefMap; -static RefMap ref_map; +static Plugins s_plugins; static void set_key(string& key, Symbol* sym, const char* name) { @@ -178,8 +171,16 @@ static bool compatible_builds(const char* plug_opts) 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; @@ -206,20 +207,17 @@ static bool register_plugin( 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; @@ -227,28 +225,35 @@ static bool register_plugin( 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(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; @@ -272,7 +277,7 @@ static bool load_lib(const char* file) dlclose(handle); return false; } - load_list(api, handle, file); + load_list(api, handle, file, sc); return true; } @@ -314,7 +319,7 @@ static void add_plugin(Plugin& p) break; case PT_SO_RULE: - SoManager::add_plugin((const SoApi*)p.api); + // SO rules are added later break; case PT_LOGGER: @@ -337,7 +342,7 @@ static void add_plugin(Plugin& p) } } -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); @@ -358,40 +363,27 @@ static void load_plugins(const std::string& 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(); } //------------------------------------------------------------------------- @@ -417,11 +409,43 @@ void PluginManager::load_plugins(const std::string& paths) 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(); @@ -434,9 +458,7 @@ void PluginManager::list_plugins() 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; @@ -464,7 +486,6 @@ void PluginManager::release_plugins() ActionManager::release_plugins(); InspectorManager::release_plugins(); IpsManager::release_plugins(); - SoManager::release_plugins(); MpseManager::release_plugins(); CodecManager::release_plugins(); ConnectorManager::release_plugins(); @@ -480,9 +501,9 @@ const BaseApi* PluginManager::get_api(PlugType type, const char* name) 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; @@ -491,7 +512,7 @@ const BaseApi* PluginManager::get_api(PlugType type, const char* name) #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 ) @@ -562,8 +583,7 @@ const char* PluginManager::get_available_plugins(PlugType t) { 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; @@ -577,4 +597,3 @@ const char* PluginManager::get_available_plugins(PlugType t) } return s.c_str(); } - diff --git a/src/managers/plugin_manager.h b/src/managers/plugin_manager.h index a8a13d52f..48b8f4a83 100644 --- a/src/managers/plugin_manager.h +++ b/src/managers/plugin_manager.h @@ -31,6 +31,8 @@ // based on configuration. //------------------------------------------------------------------------- +#include +#include #include #include "framework/base_api.h" @@ -67,7 +69,27 @@ public: 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 plug_map; + ~Plugins(); +}; + +struct SoHandle +{ + void* handle; + + SoHandle(void* h) : handle(h) { } + ~SoHandle(); +}; + +using SoHandlePtr = std::shared_ptr; + #endif diff --git a/src/managers/so_manager.cc b/src/managers/so_manager.cc index 1bf2b3437..8c8c8b046 100644 --- a/src/managers/so_manager.cc +++ b/src/managers/so_manager.cc @@ -30,36 +30,35 @@ #include #include #include -#include #include #include "log/messages.h" +#include "main/snort_config.h" #include "parser/parse_so_rule.h" using namespace snort; using namespace std; -static list 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); } @@ -186,18 +185,18 @@ static const char* revert(const uint8_t* data, unsigned len) //------------------------------------------------------------------------- -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; @@ -207,9 +206,9 @@ const char* SoManager::get_so_rule(const char* soid) 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; @@ -217,9 +216,11 @@ SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data) 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); @@ -227,11 +228,11 @@ void SoManager::delete_so_data(const char* soid, void* 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); diff --git a/src/managers/so_manager.h b/src/managers/so_manager.h index ae30f0a7d..bbcc89e19 100644 --- a/src/managers/so_manager.h +++ b/src/managers/so_manager.h @@ -22,34 +22,40 @@ // Factory for shared object rules. // Runtime is same as for text rules. - +#include #include "framework/so_rule.h" +#include "managers/plugin_manager.h" namespace snort { struct SnortConfig; } -struct SoApi; //------------------------------------------------------------------------- +struct SoRules +{ + std::list api; + std::list 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 diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index fae711f51..e23a5d342 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -1147,7 +1147,7 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn) 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 )