From: Bhagya Tholpady (bbantwal) Date: Thu, 4 Jun 2020 17:13:03 +0000 (+0000) Subject: Merge pull request #2230 in SNORT/snort3 from ~OSERHIIE/snort3:trace_control_command... X-Git-Tag: 3.0.1-5~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a508faf69d521f249b5ae90ef2ca98596490870;p=thirdparty%2Fsnort3.git Merge pull request #2230 in SNORT/snort3 from ~OSERHIIE/snort3:trace_control_command to master Squashed commit of the following: commit ad8de0f3f4f5499eac67d3e0d9e8ab0391434308 Author: Oleksandr Serhiienko Date: Fri May 29 13:07:54 2020 +0300 trace: fix for trace messages in the test-mode ('-T' option) commit e9e654d6301f4c81c8086d84581380432272299f Author: Oleksandr Serhiienko Date: Fri May 15 11:45:34 2020 +0300 trace: add control channel command --- diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 8e3e1a533..25924d132 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -259,6 +259,7 @@ SnortConfig::~SnortConfig() delete[] state; delete thread_config; delete trace_config; + delete overlay_trace_config; delete ha_config; delete global_dbus; @@ -789,6 +790,12 @@ void SnortConfig::set_verbose(bool enabled) 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; diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 5faf5edef..846bb0cb6 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -414,6 +414,9 @@ public: 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 @@ -472,6 +475,7 @@ public: void set_umask(uint32_t); void set_utc(bool); void set_verbose(bool); + void set_overlay_trace_config(TraceConfig*); //------------------------------------------------------ // accessor methods diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt index da956f98a..23426f4eb 100644 --- a/src/trace/CMakeLists.txt +++ b/src/trace/CMakeLists.txt @@ -13,6 +13,10 @@ set ( TRACE_SOURCES trace_log_base.h trace_module.cc trace_module.h + trace_parser.cc + trace_parser.h + trace_swap.cc + trace_swap.h ${INCLUDES} ) diff --git a/src/trace/dev_notes.txt b/src/trace/dev_notes.txt index 2949148bf..97d9ffcb2 100644 --- a/src/trace/dev_notes.txt +++ b/src/trace/dev_notes.txt @@ -39,6 +39,24 @@ This directory contains the trace logger framework. 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 diff --git a/src/trace/trace.cc b/src/trace/trace.cc index d6ddf07c2..550b31881 100644 --- a/src/trace/trace.cc +++ b/src/trace/trace.cc @@ -23,6 +23,8 @@ #include "trace.h" +#include + #include "framework/module.h" using namespace snort; @@ -39,7 +41,7 @@ Trace::Trace(const Module& m) : module(m) 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 ) @@ -50,6 +52,16 @@ Trace::Trace(const Module& m) : module(m) 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(); @@ -69,6 +81,9 @@ void Trace::set_module_trace() const module.set_trace(this); } +void Trace::clear() +{ std::fill(option_levels.begin(), option_levels.end(), 0); } + #ifdef CATCH_TEST_BUILD #include "catch/catch.hpp" diff --git a/src/trace/trace.h b/src/trace/trace.h index 454d01d11..ff7f6259b 100644 --- a/src/trace/trace.h +++ b/src/trace/trace.h @@ -59,10 +59,13 @@ class Trace { 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(); } diff --git a/src/trace/trace_config.cc b/src/trace/trace_config.cc index 44ec62581..1c9d2db6f 100644 --- a/src/trace/trace_config.cc +++ b/src/trace/trace_config.cc @@ -31,9 +31,11 @@ #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() ) @@ -41,6 +43,14 @@ TraceConfig::TraceConfig() } } +TraceConfig::TraceConfig(const TraceConfig& other) + : TraceConfig() +{ + traces = other.traces; + if ( other.constraints ) + constraints = new PacketConstraints(*other.constraints); +} + TraceConfig::~TraceConfig() { delete logger_factory; @@ -61,6 +71,12 @@ bool TraceConfig::set_trace(const std::string& module_name, const std::string& t return false; } +void TraceConfig::clear_traces() +{ + for ( auto& trace : traces ) + trace.clear(); +} + void TraceConfig::setup_module_trace() const { for ( const auto& trace : traces ) diff --git a/src/trace/trace_config.h b/src/trace/trace_config.h index 7ad3d94bb..e25675541 100644 --- a/src/trace/trace_config.h +++ b/src/trace/trace_config.h @@ -32,12 +32,16 @@ class TraceConfig { 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; diff --git a/src/trace/trace_module.cc b/src/trace/trace_module.cc index 420f3612d..0966b91e4 100644 --- a/src/trace/trace_module.cc +++ b/src/trace/trace_module.cc @@ -25,12 +25,13 @@ #include -#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; @@ -40,8 +41,15 @@ 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(); @@ -50,7 +58,6 @@ void TraceModule::generate_params() 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); @@ -61,15 +68,11 @@ void TraceModule::generate_params() 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; } @@ -122,33 +125,22 @@ bool TraceModule::begin(const char* fqn, int, SnortConfig* sc) { 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: @@ -165,62 +157,10 @@ bool TraceModule::set(const char* fqn, Value& v, SnortConfig* sc) 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(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; } @@ -229,16 +169,15 @@ bool TraceModule::end(const char* fqn, int, SnortConfig* sc) { 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; } @@ -251,6 +190,9 @@ bool TraceModule::end(const char* fqn, int, SnortConfig* sc) local_syslog = true; openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON); } + + delete trace_parser; + trace_parser = nullptr; } return true; diff --git a/src/trace/trace_module.h b/src/trace/trace_module.h index 9c369d3b6..f9d88afa8 100644 --- a/src/trace/trace_module.h +++ b/src/trace/trace_module.h @@ -20,23 +20,25 @@ #ifndef TRACE_MODULE_H #define TRACE_MODULE_H -#include - #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; @@ -47,15 +49,16 @@ public: 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 modules_params; std::vector> module_ranges; std::vector modules_help; - std::map> configured_trace_options; + + TraceParser* trace_parser = nullptr; }; #endif // TRACE_MODULE_H diff --git a/src/trace/trace_parser.cc b/src/trace/trace_parser.cc new file mode 100644 index 000000000..696ecd43c --- /dev/null +++ b/src/trace/trace_parser.cc @@ -0,0 +1,299 @@ +//-------------------------------------------------------------------------- +// 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 + +#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> 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(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 + +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 + diff --git a/src/trace/trace_parser.h b/src/trace/trace_parser.h new file mode 100644 index 000000000..e9a26a9f7 --- /dev/null +++ b/src/trace/trace_parser.h @@ -0,0 +1,59 @@ +//-------------------------------------------------------------------------- +// 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 + +#ifndef TRACE_PARSER_H +#define TRACE_PARSER_H + +#include +#include + +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> s_configured_trace_options; +}; + +#endif // TRACE_PARSER_H + diff --git a/src/trace/trace_swap.cc b/src/trace/trace_swap.cc new file mode 100644 index 000000000..bc2eb778a --- /dev/null +++ b/src/trace/trace_swap.cc @@ -0,0 +1,296 @@ +//-------------------------------------------------------------------------- +// 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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "trace_swap.h" + +#include + +#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; +} + diff --git a/src/trace/trace_swap.h b/src/trace/trace_swap.h new file mode 100644 index 000000000..573f2d812 --- /dev/null +++ b/src/trace/trace_swap.h @@ -0,0 +1,43 @@ +//-------------------------------------------------------------------------- +// 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 + +#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 +