running Pig. The inspector manager is called to empty trash if the main
loop is not otherwise busy.
+Reload policy is implemented by cloning the thread local config and
+overwriting the policy map and the inspection policy in the main thread.
+The inspector list from the old config's inspection policy is copied
+into the inspection policy of the new config. After the config pointer
+is cloned, the new inspection policy elements (reloadable) such as
+inspectors, binder, wizard etc are read and instantiated.
+The inspector list of the new config is updated by swapping out the
+old inspectors, binder etc. with the newly instantiated elements. The
+reloaded inspectors, binders and other inspection policy elements are
+marked for deletion. After the new inspection policy is loaded, the
+thread local config pointer is swapped with the new cloned config
+by running Pig. This happens in the packet thread. The inspector manager
+ is then called to delete any reloaded policy elements and empty trash.
// Stubs whose sole purpose is to make the test code link
SnortConfig my_config;
THREAD_LOCAL SnortConfig *snort_conf = &my_config;
-SnortConfig::SnortConfig() { snort_conf->run_flags = 0;} // run_flags is used indirectly from SFHASHFCN class by calling SnortConfig::static_hash()
+SnortConfig::SnortConfig(SnortConfig*)
+{ snort_conf->run_flags = 0;} // run_flags is used indirectly from SFHASHFCN class by calling SnortConfig::static_hash()
SnortConfig::~SnortConfig() {}
// implement functions for virtual
FileVerdict FilePolicy::type_lookup(Flow* , FileContext* ) { return FILE_VERDICT_UNKNOWN;}
static SnortState s_state;
-SnortConfig::SnortConfig()
+SnortConfig::SnortConfig(SnortConfig*)
{
state = &s_state;
memset(state, 0, sizeof(*state));
return 0;
}
+int main_reload_policy(lua_State* L)
+{
+ if ( Swapper::get_reload_in_progress() )
+ {
+ current_request->respond("== reload pending; retry\n");
+ return 0;
+ }
+ const char* fname = nullptr;
+
+ if ( L )
+ {
+ Lua::ManageStack(L, 1);
+ fname = luaL_checkstring(L, 1);
+ }
+
+ if ( fname and *fname )
+ current_request->respond(".. reloading policy\n");
+ else
+ {
+ current_request->respond("== filename required\n");
+ return 0;
+ }
+
+ SnortConfig* old = snort_conf;
+ SnortConfig* sc = Snort::get_reloaded_policy(old, fname);
+
+ if ( !sc )
+ {
+ current_request->respond("== reload failed\n");
+ return 0;
+ }
+ snort_conf = sc;
+ proc_stats.policy_reloads++;
+
+ bool from_shell = ( L != nullptr );
+ current_request->respond(".. swapping policy\n", from_shell);
+ broadcast(get_command(new ACSwap(new Swapper(old, sc)), from_shell));
+
+ return 0;
+}
+
int main_reload_daq(lua_State* L)
{
bool from_shell = ( L != nullptr );
int main_dump_stats(lua_State* = nullptr);
int main_rotate_stats(lua_State* = nullptr);
int main_reload_config(lua_State* = nullptr);
+int main_reload_policy(lua_State* = nullptr);
int main_reload_daq(lua_State* = nullptr);
int main_reload_hosts(lua_State* = nullptr);
int main_process(lua_State* = nullptr);
{ DetectionEngine::detect((Packet*)e.get_packet()); } // FIXIT-L not const!
};
-InspectionPolicy::InspectionPolicy()
+InspectionPolicy::InspectionPolicy(InspectionPolicy* other_inspection_policy)
{
framework_policy = nullptr;
+ cloned = false;
- InspectorManager::new_policy(this);
+ InspectorManager::new_policy(this, other_inspection_policy);
}
InspectionPolicy::~InspectionPolicy()
{
- InspectorManager::delete_policy(this);
+ InspectorManager::delete_policy(this, cloned);
}
void InspectionPolicy::configure()
// policy map
//-------------------------------------------------------------------------
-PolicyMap::PolicyMap()
+PolicyMap::PolicyMap(PolicyMap* other_map)
{
- add_shell(new Shell);
+ if ( other_map )
+ clone(other_map);
+ else
+ add_shell(new Shell);
set_inspection_policy(inspection_policy[0]);
set_ips_policy(ips_policy[0]);
PolicyMap::~PolicyMap()
{
- for ( auto p : shells )
- delete p;
+ if ( cloned )
+ {
+ if ( inspection_policy.size() )
+ {
+ InspectionPolicy* default_policy = inspection_policy[0];
+ default_policy->cloned = true;
+ delete default_policy;
+ }
+ }
+ else
+ {
+ for ( auto p : shells )
+ delete p;
- for ( auto p : inspection_policy )
- delete p;
+ for ( auto p : inspection_policy )
+ delete p;
- for ( auto p : ips_policy )
- delete p;
+ for ( auto p : ips_policy )
+ delete p;
- for ( auto p : network_policy )
- delete p;
+ for ( auto p : network_policy )
+ delete p;
+ }
shells.clear();
inspection_policy.clear();
network_policy.clear();
}
+void PolicyMap::clone(PolicyMap *other_map)
+{
+ shells = other_map->shells;
+ ips_policy = other_map->ips_policy;
+ network_policy = other_map->network_policy;
+
+ for ( unsigned i = 0; i < (other_map->inspection_policy.size()); i++)
+ {
+ if ( i == 0 )
+ {
+ inspection_policy.push_back(new InspectionPolicy(other_map->inspection_policy[i]));
+ }
+ else
+ inspection_policy.push_back(other_map->inspection_policy[i]);
+ }
+}
+
unsigned PolicyMap::add_shell(Shell* sh)
{
unsigned idx = shells.size();
struct InspectionPolicy
{
public:
- InspectionPolicy();
+ InspectionPolicy(InspectionPolicy* old_inspection_policy = nullptr);
~InspectionPolicy();
void configure();
public:
struct FrameworkPolicy* framework_policy;
DataBus dbus;
+ bool cloned;
};
//-------------------------------------------------------------------------
class PolicyMap
{
public:
- PolicyMap();
+ PolicyMap(PolicyMap* old_map = nullptr);
~PolicyMap();
unsigned add_shell(Shell*);
+ void clone(PolicyMap *old_map);
Shell* get_shell(unsigned i = 0)
{ return i < shells.size() ? shells[i] : nullptr; }
std::vector<InspectionPolicy*> inspection_policy;
std::vector<IpsPolicy*> ips_policy;
std::vector<NetworkPolicy*> network_policy;
+ bool cloned = false;
};
//-------------------------------------------------------------------------
#include "log/packet_tracer.h"
#include "loggers/loggers.h"
#include "main.h"
+#include "main/shell.h"
#include "managers/action_manager.h"
#include "managers/codec_manager.h"
#include "managers/inspector_manager.h"
return sc;
}
+SnortConfig* Snort::get_reloaded_policy(SnortConfig* other_conf, const char* fname)
+{
+ reloading = true;
+
+ SnortConfig* sc = new SnortConfig(other_conf);
+ Shell sh = Shell(fname);
+ sh.configure(sc);
+
+ if ( ModuleManager::get_errors() || !sc->verify() )
+ {
+ sc->cloned = true;
+ InspectorManager::update_policy(other_conf);
+ delete sc;
+ set_policies(other_conf);
+ reloading = false;
+ return nullptr;
+ }
+
+ if ( !InspectorManager::configure(sc, true) )
+ {
+ sc->cloned = true;
+ InspectorManager::update_policy(other_conf);
+ delete sc;
+ set_policies(other_conf);
+ reloading = false;
+ return nullptr;
+ }
+
+ other_conf->cloned = true;
+
+ InspectorManager::update_policy(sc);
+ reloading = false;
+ return sc;
+}
+
void Snort::capture_packet()
{
if ( snort_main_thread_pid == gettid() )
{
public:
static SnortConfig* get_reload_config(const char* fname);
+ static SnortConfig* get_reloaded_policy(SnortConfig*, const char* fname);
static void setup(int argc, char* argv[]);
static bool drop_privileges();
static void do_pidfile();
* but the goal is to minimize config checks at run time when running in
* IDS mode so we keep things simple and enforce that the only difference
* among run_modes is how we handle packets via the log_func. */
-SnortConfig::SnortConfig()
+SnortConfig::SnortConfig(SnortConfig* other_conf)
{
- num_layers = DEFAULT_LAYERMAX;
+ homenet.clear();
+ obfuscation_net.clear();
- max_attribute_hosts = DEFAULT_MAX_ATTRIBUTE_HOSTS;
- max_attribute_services_per_host = DEFAULT_MAX_ATTRIBUTE_SERVICES_PER_HOST;
+ if ( !other_conf )
+ {
+ num_layers = DEFAULT_LAYERMAX;
- max_metadata_services = DEFAULT_MAX_METADATA_SERVICES;
- mpls_stack_depth = DEFAULT_LABELCHAIN_LENGTH;
+ max_attribute_hosts = DEFAULT_MAX_ATTRIBUTE_HOSTS;
+ max_attribute_services_per_host = DEFAULT_MAX_ATTRIBUTE_SERVICES_PER_HOST;
- daq_config = new SFDAQConfig();
- InspectorManager::new_config(this);
+ max_metadata_services = DEFAULT_MAX_METADATA_SERVICES;
+ mpls_stack_depth = DEFAULT_LABELCHAIN_LENGTH;
- num_slots = ThreadConfig::get_instance_max();
- state = (SnortState*)snort_calloc(num_slots, sizeof(SnortState));
+ daq_config = new SFDAQConfig();
+ InspectorManager::new_config(this);
- profiler = new ProfilerConfig;
- latency = new LatencyConfig();
- memory = new MemoryConfig();
- policy_map = new PolicyMap;
- thread_config = new ThreadConfig();
+ num_slots = ThreadConfig::get_instance_max();
+ state = (SnortState*)snort_calloc(num_slots, sizeof(SnortState));
- homenet.clear();
- obfuscation_net.clear();
+ profiler = new ProfilerConfig;
+ latency = new LatencyConfig();
+ memory = new MemoryConfig();
+ policy_map = new PolicyMap;
+ thread_config = new ThreadConfig();
- memset(evalOrder, 0, sizeof(evalOrder));
- proto_ref = new ProtocolReference;
+ memset(evalOrder, 0, sizeof(evalOrder));
+ proto_ref = new ProtocolReference;
+ }
+ else
+ {
+ clone(other_conf);
+ policy_map = new PolicyMap(other_conf->policy_map);
+ }
+
+ set_inspection_policy(get_inspection_policy());
+ set_ips_policy(get_ips_policy());
+ set_network_policy(get_network_policy());
}
SnortConfig::~SnortConfig()
{
+ if ( cloned )
+ {
+ policy_map->cloned = true;
+ delete policy_map;
+ return;
+ }
+
free_rule_state_list();
FreeClassifications(classifications);
FreeReferences(references);
#endif
}
+void SnortConfig::clone(SnortConfig* conf)
+{
+ *this = *conf;
+ if (conf->homenet.get_family() != 0)
+ memcpy(&homenet, &conf->homenet, sizeof(homenet));
+
+ if (conf->obfuscation_net.get_family() != 0)
+ memcpy(&obfuscation_net, &conf->obfuscation_net, sizeof(obfuscation_net));
+
+}
+
// merge in everything from the command line config
void SnortConfig::merge(SnortConfig* cmd_line)
{
struct SnortConfig
{
public:
- SnortConfig();
+ SnortConfig(SnortConfig* other_conf = nullptr );
~SnortConfig();
void setup();
bool verify();
void merge(SnortConfig*);
+ void clone(SnortConfig*);
public:
//------------------------------------------------------
ThreadConfig* thread_config;
+ //------------------------------------------------------
+ //Reload inspector related
+
+ bool cloned = false;
+
//------------------------------------------------------
// policy access
InspectionPolicy* get_inspection_policy()
{ "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_policy", main_reload_policy, s_reload, "reload part or all of the default policy" },
{ "reload_daq", main_reload_daq, nullptr, "reload daq module" },
{ "reload_hosts", main_reload_hosts, s_reload, "load a new hosts table" },
#include "flow/flow.h"
#include "flow/session.h"
#include "log/messages.h"
+#include "main/snort.h"
#include "main/snort_config.h"
#include "main/thread_config.h"
#include "protocols/packet.h"
{ return ( a->api.type < b->api.type ); }
};
+enum ReloadType {
+ RELOAD_TYPE_NONE = 0,
+ RELOAD_TYPE_REENABLED,
+ RELOAD_TYPE_NEW,
+ RELOAD_TYPE_MAX
+};
+
struct PHInstance
{
PHClass& pp_class;
Inspector* handler;
string name;
+ ReloadType reload_type;
PHInstance(PHClass&, SnortConfig*, Module* = nullptr);
~PHInstance();
void set_name(const char* s)
{ name = s; }
+
+ void set_reloaded(ReloadType val)
+ { reload_type = val; }
+
+ bool is_reloaded()
+ { return ((reload_type == RELOAD_TYPE_REENABLED) or
+ (reload_type == RELOAD_TYPE_NEW)); }
+
+ ReloadType get_reload_type()
+ { return reload_type; }
};
PHInstance::PHInstance(PHClass& p, SnortConfig* sc, Module* mod) : pp_class(p)
{
+ reload_type = RELOAD_TYPE_NONE;
handler = p.api.ctor(mod);
if ( handler )
Inspector* binder;
Inspector* wizard;
+ bool default_binder;
+
void vectorize();
};
// policy stuff
//-------------------------------------------------------------------------
-void InspectorManager::new_policy(InspectionPolicy* pi)
-{
- pi->framework_policy = new FrameworkPolicy;
-
- pi->framework_policy->binder = nullptr;
- pi->framework_policy->wizard = nullptr;
-}
-
-void InspectorManager::delete_policy(InspectionPolicy* pi)
-{
- for ( auto* p : pi->framework_policy->ilist )
- {
- if ( p->handler->get_api()->type == IT_PASSIVE )
- s_trash2.push_back(p->handler);
- else
- s_trash.push_back(p->handler);
- delete p;
- }
- delete pi->framework_policy;
- pi->framework_policy = nullptr;
-}
-
// FIXIT-L allowing lookup by name or type or key is kinda hinky
// would be helpful to have specific lookups
-static PHInstance* get_instance(
- FrameworkPolicy* fp, const char* keyword, bool dflt_only = false)
+static bool get_instance(
+ FrameworkPolicy* fp, const char* keyword, bool dflt_only, std::vector<PHInstance*>::iterator& it)
{
- for ( auto* p : fp->ilist )
+ for ( it = fp->ilist.begin(); it != fp->ilist.end(); ++it )
{
+ PHInstance* p = *it;
if ( p->name.size() && p->name == keyword )
- return p;
+ return true;
else if ( !strcmp(p->pp_class.api.base.name, keyword) )
- return (!p->name.size() || !dflt_only) ? p : nullptr;
+ return (!p->name.size() || !dflt_only) ? true : false;
else if ( p->pp_class.api.service && !strcmp(p->pp_class.api.service, keyword) )
- return p;
+ return true;
}
- return nullptr;
+ return false;
+}
+
+static PHInstance* get_instance(
+ FrameworkPolicy* fp, const char* keyword, bool dflt_only = false)
+{
+ std::vector<PHInstance*>::iterator it;
+ return get_instance(fp, keyword, dflt_only, it)? *it : nullptr;
}
static PHInstance* get_new(
PHClass* ppc, FrameworkPolicy* fp, const char* keyword, Module* mod, SnortConfig* sc)
{
- PHInstance* p = get_instance(fp, keyword);
+ PHInstance* p = nullptr;
+ bool reloaded = false;
+ std::vector<PHInstance*>::iterator old_it;
- if ( p )
- return p;
+ if ( get_instance(fp, keyword, false, old_it) )
+ {
+ if ( Snort::is_reloading() )
+ {
+ (*old_it)->set_reloaded(RELOAD_TYPE_REENABLED);
+ fp->ilist.erase(old_it);
+ reloaded = true;
+ }
+ else
+ return *old_it;
+ }
p = new PHInstance(*ppc, sc, mod);
return NULL;
}
+ if ( Snort::is_reloading() )
+ {
+ if ( reloaded )
+ p->set_reloaded(RELOAD_TYPE_REENABLED);
+ else
+ p->set_reloaded(RELOAD_TYPE_NEW);
+ }
fp->ilist.push_back(p);
return p;
}
+void InspectorManager::new_policy(InspectionPolicy* pi, InspectionPolicy* other_pi)
+{
+ pi->framework_policy = new FrameworkPolicy;
+ bool default_binder = false;
+
+ if ( other_pi )
+ {
+ pi->framework_policy->ilist = other_pi->framework_policy->ilist;
+ default_binder = other_pi->framework_policy->default_binder;
+ }
+
+ pi->framework_policy->default_binder = default_binder;
+ pi->framework_policy->binder = nullptr;
+ pi->framework_policy->wizard = nullptr;
+}
+
+void InspectorManager::delete_policy(InspectionPolicy* pi, bool cloned)
+{
+ for ( auto* p : pi->framework_policy->ilist )
+ {
+ if ( cloned and !(p->is_reloaded()) )
+ continue;
+
+ if ( p->handler->get_api()->type == IT_PASSIVE )
+ s_trash2.push_back(p->handler);
+ else
+ s_trash.push_back(p->handler);
+ delete p;
+ }
+ delete pi->framework_policy;
+ pi->framework_policy = nullptr;
+}
+
+void InspectorManager::update_policy(SnortConfig* sc)
+{
+ if ( sc->policy_map->inspection_policy.size() )
+ {
+ InspectionPolicy* pi = sc->policy_map->inspection_policy[0];
+ for ( auto* p : pi->framework_policy->ilist )
+ p->set_reloaded(RELOAD_TYPE_NONE);
+ }
+}
// FIXIT-M create a separate list for meta handlers? is there really more than one?
void InspectorManager::dispatch_meta(FrameworkPolicy* fp, int type, const uint8_t* data)
{
InspectorManager::instantiate(api, m, sc);
fp->binder = get_instance(fp, bind_id)->handler;
fp->binder->configure(sc);
+ fp->default_binder = true;
}
-static bool configure(SnortConfig* sc, FrameworkPolicy* fp)
+static bool configure(SnortConfig* sc, FrameworkPolicy* fp, bool cloned)
{
bool ok = true;
+ bool new_ins = false;
+ bool reenabled_ins = false;
for ( auto* p : fp->ilist )
+ {
+ ReloadType reload_type = p->get_reload_type();
+
+ if ( cloned )
+ {
+ if ( reload_type == RELOAD_TYPE_NEW )
+ new_ins = true;
+ else if ( reload_type == RELOAD_TYPE_REENABLED )
+ reenabled_ins = true;
+ else
+ continue;
+ }
ok = p->handler->configure(sc) && ok;
+ }
+
+ if ( new_ins or reenabled_ins )
+ {
+ std::vector<PHInstance*>::iterator old_binder;
+ if ( get_instance(fp, "binder", false, old_binder) )
+ {
+ if ( new_ins and fp->default_binder )
+ {
+ if ( !((*old_binder)->is_reloaded()) )
+ {
+ (*old_binder)->set_reloaded(RELOAD_TYPE_REENABLED);
+ fp->ilist.erase(old_binder);
+ }
+ fp->default_binder = false;
+ }
+ else if ( reenabled_ins and !((*old_binder)->is_reloaded()) )
+ {
+ (*old_binder)->handler->configure(sc);
+ }
+ }
+ }
sort(fp->ilist.begin(), fp->ilist.end(), PHInstance::comp);
fp->vectorize();
pi->rem_ref();
}
-bool InspectorManager::configure(SnortConfig* sc)
+bool InspectorManager::configure(SnortConfig* sc, bool cloned)
{
if ( !s_sorted )
{
for ( unsigned idx = 0; idx < sc->policy_map->inspection_policy.size(); ++idx )
{
+ if ( cloned and idx )
+ break;
+
set_policies(sc, idx);
InspectionPolicy* p = sc->policy_map->inspection_policy[idx];
p->configure();
- ok = ::configure(sc, p->framework_policy) && ok;
+ ok = ::configure(sc, p->framework_policy, cloned) && ok;
}
set_policies(sc);
static void dump_buffers();
static void release_plugins();
- static void new_policy(InspectionPolicy*);
- static void delete_policy(InspectionPolicy*);
+ static void new_policy(InspectionPolicy*, InspectionPolicy*);
+ static void delete_policy(InspectionPolicy*, bool cloned);
+ static void update_policy(SnortConfig* sc);
static void new_config(SnortConfig*);
static void delete_config(SnortConfig*);
SO_PUBLIC static Inspector* acquire(const char* key, SnortConfig*);
SO_PUBLIC static void release(Inspector*);
- static bool configure(SnortConfig*);
+ static bool configure(SnortConfig*, bool cloned = false);
static void print_config(SnortConfig*);
static void thread_init(SnortConfig*);
return false;
// FIXIT-M only basic modules and inspectors can be reloaded at present
- if ( Snort::is_reloading() and h->api and h->api->type != PT_INSPECTOR )
+ if ( ( Snort::is_reloading() )
+ and h->api and h->api->type != PT_INSPECTOR )
return false;
Module* m = h->mod;
static SnortState s_state;
-SnortConfig::SnortConfig()
+SnortConfig::SnortConfig(SnortConfig*)
{
state = &s_state;
memset(state, 0, sizeof(*state));
static SnortState s_state;
-SnortConfig::SnortConfig()
+SnortConfig::SnortConfig(SnortConfig*)
{
state = &s_state;
memset(state, 0, sizeof(*state));
{ "remote_commands", "total remote commands processed" },
{ "signals", "total signals processed" },
{ "conf_reloads", "number of times configuration was reloaded" },
+ { "policy_reloads", "number of times policies were reloaded" },
{ "daq_reloads", "number of times daq configuration was reloaded" },
{ "attribute_table_reloads", "number of times hosts table was reloaded" },
{ "attribute_table_hosts", "total number of hosts in table" },
PegCount remote_commands;
PegCount signals;
PegCount conf_reloads;
+ PegCount policy_reloads;
PegCount daq_reloads;
PegCount attribute_table_reloads;
PegCount attribute_table_hosts;