delete[] state;
delete thread_config;
delete trace_config;
+ delete overlay_trace_config;
delete ha_config;
delete global_dbus;
logging_flags &= ~LOGGING_FLAG__VERBOSE;
}
+void SnortConfig::set_overlay_trace_config(TraceConfig* tc)
+{
+ delete overlay_trace_config;
+ overlay_trace_config = tc;
+}
+
void SnortConfig::set_tunnel_verdicts(const char* args)
{
char* tmp, * tok;
HighAvailabilityConfig* ha_config = nullptr;
TraceConfig* trace_config = nullptr;
+ // TraceConfig instance which used by TraceSwap control channel command
+ TraceConfig* overlay_trace_config = nullptr;
+
//------------------------------------------------------
//Reload inspector related
void set_umask(uint32_t);
void set_utc(bool);
void set_verbose(bool);
+ void set_overlay_trace_config(TraceConfig*);
//------------------------------------------------------
// accessor methods
trace_log_base.h
trace_module.cc
trace_module.h
+ trace_parser.cc
+ trace_parser.h
+ trace_swap.cc
+ trace_swap.h
${INCLUDES}
)
TraceModule ctor should be called after all existed modules due to TraceModule
dynamic params restriction.
+* TraceSwap
+
+ This class extends snort::AnalyzerCommand and represents control channel CLI commands
+ for setting/clearing trace configuration from the shell. Commands parameters are encapsulated in
+ the TraceSwapParams class.
+ Available commands:
+ 1) trace.set({ modules = {}, constraints = {} }) -- set new modules traces and constraints;
+ 2) trace.clear() -- clear modules traces and constraints.
+
+* TraceSwapParams
+
+ This is a helper class for TraceSwap which encapsulates dynamic initialization and storing of
+ snort::Parameter and snort::Command lists based on TraceModule's parameters.
+
+* TraceParser
+
+ This class encapsulates module trace options and packet constraints parsing and setting logic.
+
* TraceApi
TraceApi is a facade API class used to init/reinit/term thread-local trace logger and module's
#include "trace.h"
+#include <algorithm>
+
#include "framework/module.h"
using namespace snort;
mod_name = module.get_name();
const snort::TraceOption* trace_options = module.get_trace_options();
options = ( trace_options->name ) ? trace_options : s_default_trace_options;
-
+
size_t options_size = 0;
trace_options = options;
while ( trace_options->name )
option_levels.resize(options_size, 0);
}
+Trace& Trace::operator=(const Trace& other)
+{
+ if ( this != &other )
+ {
+ option_levels = other.option_levels;
+ options = other.options;
+ }
+ return *this;
+}
+
bool Trace::set(const std::string& trace_option_name, uint8_t trace_level)
{
size_t size = option_levels.size();
module.set_trace(this);
}
+void Trace::clear()
+{ std::fill(option_levels.begin(), option_levels.end(), 0); }
+
#ifdef CATCH_TEST_BUILD
#include "catch/catch.hpp"
{
public:
Trace(const Module& m);
+ Trace& operator=(const Trace&);
bool set(const std::string& option_name, uint8_t option_level);
void set_module_trace() const;
+ void clear();
+
const char* module_name() const
{ return mod_name.c_str(); }
#include "trace_log_base.h"
+using namespace snort;
+
TraceConfig::TraceConfig()
{
- auto modules = snort::ModuleManager::get_all_modules();
+ auto modules = ModuleManager::get_all_modules();
for ( auto* module : modules )
{
if ( module->get_trace_options() )
}
}
+TraceConfig::TraceConfig(const TraceConfig& other)
+ : TraceConfig()
+{
+ traces = other.traces;
+ if ( other.constraints )
+ constraints = new PacketConstraints(*other.constraints);
+}
+
TraceConfig::~TraceConfig()
{
delete logger_factory;
return false;
}
+void TraceConfig::clear_traces()
+{
+ for ( auto& trace : traces )
+ trace.clear();
+}
+
void TraceConfig::setup_module_trace() const
{
for ( const auto& trace : traces )
{
public:
TraceConfig();
+ TraceConfig(const TraceConfig&);
~TraceConfig();
void setup_module_trace() const;
bool set_trace(const std::string& module_name,
const std::string& trace_option_name, uint8_t trace_level);
+ void clear_traces();
+
+public:
snort::TraceLoggerFactory* logger_factory = nullptr;
snort::PacketConstraints* constraints = nullptr;
#include <syslog.h>
-#include "framework/packet_constraints.h"
#include "main/snort_config.h"
#include "managers/module_manager.h"
#include "trace_config.h"
#include "trace_log.h"
+#include "trace_parser.h"
+#include "trace_swap.h"
using namespace snort;
TraceModule::TraceModule() : Module(s_name, trace_help)
{
generate_params();
+ TraceSwapParams::set_params(get_parameters());
}
+TraceModule::~TraceModule()
+{ delete trace_parser; }
+
+const Command* TraceModule::get_commands() const
+{ return TraceSwapParams::get_commands(); }
+
void TraceModule::generate_params()
{
auto modules = snort::ModuleManager::get_all_modules();
const TraceOption* trace_options = module->get_trace_options();
if ( trace_options )
{
- auto& module_trace_options = configured_trace_options[module->get_name()];
std::string module_trace_help(module->get_name());
module_trace_help += " module trace options";
modules_help.emplace_back(module_trace_help);
module_range.emplace_back(DEFAULT_TRACE_OPTION_NAME, Parameter::PT_INT, "0:255", nullptr,
"enable all trace options");
- if ( !trace_options->name )
- module_trace_options[DEFAULT_TRACE_OPTION_NAME] = false;
-
while ( trace_options->name )
{
module_range.emplace_back(trace_options->name,
Parameter::PT_INT, "0:255", nullptr, trace_options->help);
- module_trace_options[trace_options->name] = false;
++trace_options;
}
{
if ( !strcmp(fqn, "trace") )
{
+ trace_parser = new TraceParser(sc->trace_config);
+
// Init default output type based on Snort run-mode
- if ( sc->test_mode() )
- log_output_type = OUTPUT_TYPE_NO_INIT;
- else if ( sc->daemon_mode() or sc->log_syslog() )
+ if ( sc->daemon_mode() or sc->log_syslog() )
log_output_type = OUTPUT_TYPE_SYSLOG;
else
log_output_type = OUTPUT_TYPE_STDOUT;
- reset_configured_trace_options();
}
return true;
}
-void TraceModule::reset_configured_trace_options()
-{
- for ( auto& module_trace_options : configured_trace_options )
- for ( auto& trace_options : module_trace_options.second )
- trace_options.second = false;
-}
-
-bool TraceModule::set(const char* fqn, Value& v, SnortConfig* sc)
+bool TraceModule::set(const char* fqn, Value& v, SnortConfig*)
{
if ( v.is("output") )
{
- if ( sc->test_mode() )
- return true;
-
switch ( v.get_uint8() )
{
case OUTPUT_TYPE_STDOUT:
else if ( strstr(fqn, "trace.modules.") == fqn )
{
std::string module_name = find_module(fqn);
- if ( strcmp(v.get_name(), DEFAULT_TRACE_OPTION_NAME) == 0 )
- {
- const auto& trace_options = configured_trace_options[module_name];
- for ( const auto& trace_option : trace_options )
- if ( !trace_option.second )
- sc->trace_config->set_trace(module_name, trace_option.first, v.get_uint8());
- return true;
- }
- else
- {
- bool res = sc->trace_config->set_trace(module_name, v.get_name(), v.get_uint8());
- configured_trace_options[module_name][v.get_name()] = res;
- return res;
- }
+ return trace_parser->set_traces(module_name, v);
}
else if ( strstr(fqn, "trace.constraints.") == fqn )
- {
- if ( !sc->trace_config->constraints )
- sc->trace_config->constraints = new snort::PacketConstraints;
-
- auto& cs = *sc->trace_config->constraints;
-
- if ( v.is("ip_proto") )
- {
- cs.ip_proto = static_cast<IpProtocol>(v.get_uint8());
- cs.set_bits |= PacketConstraints::SetBits::IP_PROTO;
- }
- else if ( v.is("src_port") )
- {
- cs.src_port = v.get_uint16();
- cs.set_bits |= PacketConstraints::SetBits::SRC_PORT;
- }
- else if ( v.is("dst_port") )
- {
- cs.dst_port = v.get_uint16();
- cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
- }
- else if ( v.is("src_ip") )
- {
- const char* str = v.get_string();
- if ( cs.src_ip.set(str) != SFIP_SUCCESS )
- return false;
-
- cs.set_bits |= PacketConstraints::SetBits::SRC_IP;
- }
- else if ( v.is("dst_ip") )
- {
- const char* str = v.get_string();
- if ( cs.dst_ip.set(str) != SFIP_SUCCESS )
- return false;
-
- cs.set_bits |= PacketConstraints::SetBits::DST_IP;
- }
-
- return true;
- }
+ return trace_parser->set_constraints(v);
return false;
}
{
if ( !strcmp(fqn, "trace") )
{
+ assert(trace_parser);
switch ( log_output_type )
{
case OUTPUT_TYPE_STDOUT:
- sc->trace_config->logger_factory = new StdoutLoggerFactory();
+ trace_parser->get_trace_config()->logger_factory = new StdoutLoggerFactory();
break;
case OUTPUT_TYPE_SYSLOG:
- sc->trace_config->logger_factory = new SyslogLoggerFactory();
+ trace_parser->get_trace_config()->logger_factory = new SyslogLoggerFactory();
break;
- case OUTPUT_TYPE_NO_INIT:
- sc->trace_config->logger_factory = nullptr;
default:
break;
}
local_syslog = true;
openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON);
}
+
+ delete trace_parser;
+ trace_parser = nullptr;
}
return true;
#ifndef TRACE_MODULE_H
#define TRACE_MODULE_H
-#include <map>
-
#include "framework/module.h"
+class TraceParser;
+
class TraceModule : public snort::Module
{
private:
enum OutputType
{
- OUTPUT_TYPE_STDOUT,
+ OUTPUT_TYPE_STDOUT = 0,
OUTPUT_TYPE_SYSLOG,
OUTPUT_TYPE_NO_INIT
};
public:
TraceModule();
+ ~TraceModule() override;
+ const snort::Command* get_commands() const override;
bool begin(const char*, int, snort::SnortConfig*) override;
bool set(const char*, snort::Value&, snort::SnortConfig*) override;
bool end(const char*, int, snort::SnortConfig*) override;
private:
std::string find_module(const char* config_name) const;
void generate_params();
- void reset_configured_trace_options();
private:
OutputType log_output_type = OUTPUT_TYPE_NO_INIT;
bool local_syslog = false;
+
std::vector<snort::Parameter> modules_params;
std::vector<std::vector<snort::Parameter>> module_ranges;
std::vector<std::string> modules_help;
- std::map<std::string, std::map<std::string, bool>> configured_trace_options;
+
+ TraceParser* trace_parser = nullptr;
};
#endif // TRACE_MODULE_H
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+// trace_parser.cc author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "trace_parser.h"
+
+#include "framework/module.h"
+#include "framework/packet_constraints.h"
+#include "managers/module_manager.h"
+
+#include "trace_config.h"
+
+using namespace snort;
+
+std::map<std::string, std::map<std::string, bool>> TraceParser::s_configured_trace_options;
+
+TraceParser::TraceParser(TraceConfig* tc)
+ : trace_config(tc)
+{
+ assert(trace_config);
+
+ // Will be initialized only once when first TraceParser instance created
+ if ( s_configured_trace_options.empty() )
+ init_configured_trace_options();
+ else
+ reset_configured_trace_options();
+}
+
+bool TraceParser::set_traces(const std::string& module_name, const Value& val)
+{
+ if ( !s_configured_trace_options.count(module_name) )
+ return false;
+
+ if ( val.is(DEFAULT_TRACE_OPTION_NAME) )
+ {
+ const auto& trace_options = s_configured_trace_options[module_name];
+ for ( const auto& trace_option : trace_options )
+ {
+ if ( !trace_option.second )
+ trace_config->set_trace(module_name, trace_option.first, val.get_uint8());
+ }
+
+ return true;
+ }
+ else
+ {
+ bool res = trace_config->set_trace(module_name, val.get_name(), val.get_uint8());
+ s_configured_trace_options[module_name][val.get_name()] = res;
+ return res;
+ }
+}
+
+bool TraceParser::set_constraints(const Value& val)
+{
+ if ( !trace_config->constraints )
+ trace_config->constraints = new PacketConstraints;
+
+ auto& cs = *trace_config->constraints;
+
+ if ( val.is("ip_proto") )
+ {
+ cs.ip_proto = static_cast<IpProtocol>(val.get_uint8());
+ cs.set_bits |= PacketConstraints::SetBits::IP_PROTO;
+ }
+ else if ( val.is("src_port") )
+ {
+ cs.src_port = val.get_uint16();
+ cs.set_bits |= PacketConstraints::SetBits::SRC_PORT;
+ }
+ else if ( val.is("dst_port") )
+ {
+ cs.dst_port = val.get_uint16();
+ cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
+ }
+ else if ( val.is("src_ip") )
+ {
+ const char* str = val.get_string();
+ if ( cs.src_ip.set(str) != SFIP_SUCCESS )
+ return false;
+
+ cs.set_bits |= PacketConstraints::SetBits::SRC_IP;
+ }
+ else if ( val.is("dst_ip") )
+ {
+ const char* str = val.get_string();
+ if ( cs.dst_ip.set(str) != SFIP_SUCCESS )
+ return false;
+
+ cs.set_bits |= PacketConstraints::SetBits::DST_IP;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+void TraceParser::clear_traces()
+{ trace_config->clear_traces(); }
+
+void TraceParser::clear_constraints()
+{
+ delete trace_config->constraints;
+ trace_config->constraints = nullptr;
+}
+
+void TraceParser::reset_configured_trace_options()
+{
+ for ( auto& module_trace_options : s_configured_trace_options )
+ {
+ for ( auto& trace_options : module_trace_options.second )
+ trace_options.second = false;
+ }
+}
+
+void TraceParser::init_configured_trace_options()
+{
+ auto trace_modules = ModuleManager::get_all_modules();
+ for ( const auto* module : trace_modules )
+ {
+ const TraceOption* trace_options = module->get_trace_options();
+ if ( trace_options )
+ {
+ auto& module_trace_options = s_configured_trace_options[module->get_name()];
+ if ( !trace_options->name )
+ module_trace_options[DEFAULT_TRACE_OPTION_NAME] = false;
+
+ while ( trace_options->name )
+ {
+ module_trace_options[trace_options->name] = false;
+ ++trace_options;
+ }
+ }
+ }
+}
+
+#ifdef UNIT_TEST
+
+#include <catch/snort_catch.h>
+
+TEST_CASE("packet constraints", "[TraceParser]")
+{
+ TraceConfig tc;
+ TraceParser tp(&tc);
+
+ SECTION("ip_proto")
+ {
+ const Parameter ip_proto_param("ip_proto", Parameter::PT_INT, "0:255", nullptr,
+ "test ip_proto param");
+
+ Value val(false);
+ val.set(&ip_proto_param);
+
+ val.set(6l);
+ CHECK( tp.set_constraints(val) );
+ }
+ SECTION("src_ip")
+ {
+ const Parameter src_ip_param("src_ip", Parameter::PT_STRING, nullptr, nullptr,
+ "test src_ip param");
+
+ Value val(false);
+ val.set(&src_ip_param);
+
+ val.set("10.1.2.3");
+ CHECK( tp.set_constraints(val) );
+
+ val.set("10.1.2.300");
+ CHECK( !tp.set_constraints(val) );
+ }
+ SECTION("src_port")
+ {
+ const Parameter src_port_param("src_port", Parameter::PT_INT, "0:65535", nullptr,
+ "test src_port param");
+
+ Value val(false);
+ val.set(&src_port_param);
+
+ val.set(100l);
+ CHECK( tp.set_constraints(val) );
+ }
+ SECTION("dst_ip")
+ {
+ const Parameter dst_ip_param("dst_ip", Parameter::PT_STRING, nullptr, nullptr,
+ "test dst_ip param");
+
+ Value val(false);
+ val.set(&dst_ip_param);
+
+ val.set("10.3.2.1");
+ CHECK( tp.set_constraints(val) );
+
+ val.set("10.300.2.1");
+ CHECK( !tp.set_constraints(val) );
+ }
+ SECTION("dst_port")
+ {
+ const Parameter dst_port_param("dst_port", Parameter::PT_INT, "0:65535", nullptr,
+ "test dst_port param");
+
+ Value val(false);
+ val.set(&dst_port_param);
+
+ val.set(200l);
+ CHECK( tp.set_constraints(val) );
+ }
+ SECTION("invalid_param")
+ {
+ const Parameter invalid_param("invalid_param", Parameter::PT_INT, "0:8", nullptr,
+ "test invalid param");
+
+ Value val(false);
+ val.set(&invalid_param);
+
+ val.set(5l);
+ CHECK( !tp.set_constraints(val) );
+ }
+}
+
+TEST_CASE("modules traces", "[TraceParser]")
+{
+ TraceConfig tc;
+ TraceParser tp(&tc);
+
+ SECTION("set_option")
+ {
+ const Parameter detection_rule_eval("rule_eval", Parameter::PT_INT, "0:255", nullptr,
+ "test detection_rule_eval param");
+
+ const Parameter detection_detect_engine("detect_engine", Parameter::PT_INT, "0:255", nullptr,
+ "test detection_detect_engine param");
+
+ Value val_opt1(false);
+ Value val_opt2(false);
+ val_opt1.set(&detection_rule_eval);
+ val_opt2.set(&detection_detect_engine);
+
+ val_opt1.set(1l);
+ CHECK( tp.set_traces("detection", val_opt1) );
+
+ val_opt2.set(1l);
+ CHECK( tp.set_traces("detection", val_opt2) );
+ }
+ SECTION("set_all")
+ {
+ const Parameter decode_all(DEFAULT_TRACE_OPTION_NAME, Parameter::PT_INT, "0:255", nullptr,
+ "test decode_all param");
+
+ Value val_all(false);
+ val_all.set(&decode_all);
+
+ val_all.set(1l);
+ CHECK( tp.set_traces("decode", val_all) );
+ CHECK( tp.set_traces("detection", val_all) );
+ }
+ SECTION("set_invalid_option")
+ {
+ const Parameter invalid_param("invalid_opt", Parameter::PT_INT, "0:255", nullptr,
+ "test invalid param");
+
+ Value invalid_val(false);
+ invalid_val.set(&invalid_param);
+
+ invalid_val.set(1l);
+ CHECK( !tp.set_traces("detection", invalid_val) );
+ }
+ SECTION("set_invalid_module")
+ {
+ const Parameter all_param(DEFAULT_TRACE_OPTION_NAME, Parameter::PT_INT, "0:255", nullptr,
+ "test all param");
+
+ Value val(false);
+ val.set(&all_param);
+
+ val.set(1l);
+ CHECK( !tp.set_traces("invalid_module", val) );
+ }
+}
+
+#endif // UNIT_TEST
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+// trace_parser.h author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifndef TRACE_PARSER_H
+#define TRACE_PARSER_H
+
+#include <map>
+#include <string>
+
+namespace snort
+{
+class Module;
+class Value;
+}
+
+class TraceConfig;
+
+class TraceParser
+{
+public:
+ TraceParser(TraceConfig*);
+
+ bool set_traces(const std::string& module_name, const snort::Value& val);
+ bool set_constraints(const snort::Value& val);
+
+ void clear_traces();
+ void clear_constraints();
+
+ void reset_configured_trace_options();
+
+ TraceConfig* get_trace_config() const
+ { return trace_config; }
+
+private:
+ void init_configured_trace_options();
+
+private:
+ TraceConfig* trace_config = nullptr;
+ static std::map<std::string, std::map<std::string, bool>> s_configured_trace_options;
+};
+
+#endif // TRACE_PARSER_H
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+// trace_swap.cc author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "trace_swap.h"
+
+#include <lua.hpp>
+
+#include "framework/module.h"
+#include "log/messages.h"
+#include "main/analyzer_command.h"
+#include "main/snort_config.h"
+
+#include "trace_api.h"
+#include "trace_config.h"
+#include "trace_parser.h"
+
+using namespace snort;
+
+const Command* TraceSwapParams::s_commands = nullptr;
+const Parameter* TraceSwapParams::s_params = nullptr;
+
+static int set(lua_State*);
+static int clear(lua_State*);
+
+void TraceSwapParams::set_params(const Parameter* params)
+{
+ const Parameter* modules_params = Parameter::find(params, "modules");
+ const Parameter* constraints_params = Parameter::find(params, "constraints");
+
+ assert(modules_params);
+ assert(constraints_params);
+
+ static const Parameter trace_params[] =
+ {
+ *modules_params,
+
+ *constraints_params,
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+ };
+
+ static const Command commands[] =
+ {
+ { "set", set, trace_params, "set modules traces and constraints" },
+
+ { "clear", clear, nullptr, "clear modules traces and constraints" },
+
+ { nullptr, nullptr, nullptr, nullptr }
+ };
+
+ s_params = trace_params;
+ s_commands = commands;
+}
+
+const Command* TraceSwapParams::get_commands()
+{ return s_commands; }
+
+const Parameter* TraceSwapParams::get_params()
+{ return s_params; }
+
+class TraceSwap : public AnalyzerCommand
+{
+public:
+ TraceSwap(TraceConfig* tc, bool set_traces = false, bool set_constraints = false)
+ : trace_config(tc),
+ is_set_traces(set_traces),
+ is_set_constraints(set_constraints)
+ { assert(trace_config); }
+ ~TraceSwap() override;
+
+ bool execute(Analyzer&, void**) override;
+ const char* stringify() override
+ { return "TRACE_SWAP"; }
+
+private:
+ void print_msg() const;
+
+private:
+ TraceConfig* trace_config = nullptr;
+ bool is_set_traces;
+ bool is_set_constraints;
+};
+
+TraceSwap::~TraceSwap()
+{
+ // Update configuration for the main thread
+ // and set overlay TraceConfig
+ TraceApi::thread_reinit(trace_config);
+ SnortConfig::get_main_conf()->set_overlay_trace_config(trace_config);
+
+ print_msg();
+}
+
+bool TraceSwap::execute(Analyzer&, void**)
+{
+ // Update configuration for packet threads
+ TraceApi::thread_reinit(trace_config);
+
+ print_msg();
+ return true;
+}
+
+void TraceSwap::print_msg() const
+{
+ if ( is_set_traces and is_set_constraints )
+ LogMessage("== set modules traces and constraints\n");
+ else if ( !is_set_traces and !is_set_constraints )
+ LogMessage("== clear modules traces and constraints\n");
+ else if ( is_set_traces )
+ LogMessage("== set modules traces\n");
+ else if ( is_set_constraints )
+ LogMessage("== set constraints\n");
+}
+
+static int set(lua_State* L)
+{
+ // Create an overlay TraceConfig based on the current configuration
+ // It will be set in a SnortConfig during TraceSwap execution and owned by it after
+ const SnortConfig* sc = SnortConfig::get_conf();
+ TraceConfig* trace_config = new TraceConfig(sc->overlay_trace_config
+ ? *sc->overlay_trace_config : *sc->trace_config);
+
+ TraceParser trace_parser(trace_config);
+
+ const Parameter* params_tree = TraceSwapParams::get_params();
+ bool parse_err = false;
+ bool set_traces = false;
+ bool set_constraints = false;
+
+ // Passed Lua entry check
+ if ( lua_gettop(L) != 1 or !lua_istable(L, 1) )
+ {
+ LogMessage("== invalid Lua entry is provided, %s: %s\n",
+ "use the outer table and pass options inside of it",
+ "{ modules = {}, constraints = {} }");
+
+ delete trace_config;
+ return 0;
+ }
+
+ // Outer table traversal
+ lua_pushnil(L);
+ while ( lua_next(L, 1) )
+ {
+ const char* root_tbl_name = luaL_checkstring(L, -2);
+ const Parameter* root_tbl_param = Parameter::find(params_tree, root_tbl_name);
+
+ if ( !lua_istable(L, -1) or !root_tbl_param )
+ {
+ LogMessage("== invalid table is provided: %s\n", root_tbl_name);
+ parse_err = true;
+ lua_pop(L, 1);
+ continue;
+ }
+
+ // "modules" table traversal
+ if ( !strcmp(root_tbl_name, params_tree[0].name) )
+ {
+ set_traces = true;
+ trace_parser.clear_traces();
+
+ const Parameter* modules_param = (const Parameter*)root_tbl_param->range;
+
+ int modules_tbl_idx = lua_gettop(L);
+ lua_pushnil(L);
+ while ( lua_next(L, modules_tbl_idx) )
+ {
+ const char* module_name = luaL_checkstring(L, -2);
+ const Parameter* module_param = Parameter::find(modules_param, module_name);
+
+ if ( !lua_istable(L, -1) or !module_param )
+ {
+ LogMessage("== invalid table is provided: %s.%s\n", root_tbl_name,
+ module_name);
+
+ parse_err = true;
+ lua_pop(L, 1);
+ continue;
+ }
+
+ // Trace table traversal
+ int module_tbl_idx = lua_gettop(L);
+ lua_pushnil(L);
+ while ( lua_next(L, module_tbl_idx) )
+ {
+ const char* val_name = luaL_checkstring(L, -2);
+ const Parameter* trace_param = Parameter::find(
+ (const Parameter*)module_param->range, val_name);
+
+ Value val(false);
+ val.set(trace_param);
+
+ if ( lua_isnumber(L, -1) )
+ val.set((double)lua_tointeger(L, -1));
+ else
+ val.set(luaL_checkstring(L, -1));
+
+ if ( !trace_param or !trace_param->validate(val) or
+ !trace_parser.set_traces(module_name, val) )
+ {
+ LogMessage("== invalid trace value is provided: %s.%s.%s = %s\n",
+ root_tbl_name, module_name, val_name, val.get_as_string());
+
+ parse_err = true;
+ }
+
+ lua_pop(L, 1);
+ }
+
+ lua_pop(L, 1);
+ }
+ }
+ // "constraints" table traversal
+ else if ( !strcmp(root_tbl_name, params_tree[1].name) )
+ {
+ set_constraints = true;
+ trace_parser.clear_constraints();
+
+ const Parameter* constraints_param = (const Parameter*)root_tbl_param->range;
+
+ int constraints_tbl_idx = lua_gettop(L);
+ lua_pushnil(L);
+ while ( lua_next(L, constraints_tbl_idx) )
+ {
+ const char* val_name = luaL_checkstring(L, -2);
+ const Parameter* filter_param = Parameter::find(constraints_param, val_name);
+ Value val(false);
+ val.set(filter_param);
+
+ if ( lua_isnumber(L, -1) )
+ val.set((double)lua_tointeger(L, -1));
+ else
+ val.set(luaL_checkstring(L, -1));
+
+ if ( !filter_param or !filter_param->validate(val) or
+ !trace_parser.set_constraints(val) )
+ {
+ LogMessage("== invalid constraints value is provided: %s.%s = %s\n",
+ root_tbl_name, val_name, val.get_as_string());
+
+ parse_err = true;
+ }
+
+ lua_pop(L, 1);
+ }
+ }
+
+ lua_pop(L, 1);
+ }
+
+ if ( !parse_err )
+ {
+ if ( !set_traces and !set_constraints )
+ {
+ trace_parser.clear_traces();
+ trace_parser.clear_constraints();
+ }
+
+ main_broadcast_command(new TraceSwap(
+ trace_parser.get_trace_config(), set_traces, set_constraints),
+ true);
+ }
+ else
+ delete trace_config;
+
+ return 0;
+}
+
+static int clear(lua_State*)
+{
+ // Create an empty overlay TraceConfig
+ // It will be set in a SnortConfig during TraceSwap execution and owned by it after
+ main_broadcast_command(new TraceSwap(new TraceConfig()), true);
+ return 0;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+// trace_swap.h author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifndef TRACE_SWAP_H
+#define TRACE_SWAP_H
+
+namespace snort
+{
+struct Command;
+struct Parameter;
+}
+
+class TraceSwapParams
+{
+public:
+ static void set_params(const snort::Parameter* params);
+
+ static const snort::Command* get_commands();
+ static const snort::Parameter* get_params();
+
+private:
+ static const snort::Command* s_commands;
+ static const snort::Parameter* s_params;
+};
+
+#endif // TRACE_SWAP_H
+