From: Michael Altizer (mialtize) Date: Fri, 10 Apr 2020 23:27:02 +0000 (+0000) Subject: Merge pull request #2113 in SNORT/snort3 from ~OSERHIIE/snort3:trace_logger to master X-Git-Tag: 3.0.1-2~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb23b9bb30e8fb8f18bdc6327b438ef5a3c17d9f;p=thirdparty%2Fsnort3.git Merge pull request #2113 in SNORT/snort3 from ~OSERHIIE/snort3:trace_logger to master Squashed commit of the following: commit 5ae02e42ad00e7b23dea2ca7432f54f06c7debf5 Author: Oleksandr Serhiienko Date: Fri Mar 13 17:05:30 2020 +0200 trace: refactor stdout/syslog logging of trace into logger framework --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9455b3c0..0e5012d33 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,6 +109,7 @@ add_subdirectory(host_tracker) add_subdirectory(pub_sub) add_subdirectory(time) add_subdirectory(profiler) +add_subdirectory(trace) add_subdirectory(utils) add_subdirectory(helpers) add_subdirectory(lua) @@ -175,6 +176,7 @@ add_executable( snort $ $ $ + $ $ ${PIGLET_LIBRARIES} ${STATIC_CODEC_PLUGINS} diff --git a/src/main/analyzer.cc b/src/main/analyzer.cc index 1e2020b60..6a337c266 100644 --- a/src/main/analyzer.cc +++ b/src/main/analyzer.cc @@ -63,6 +63,7 @@ #include "side_channel/side_channel.h" #include "stream/stream.h" #include "time/packet_time.h" +#include "trace/trace_log_api.h" #include "utils/stats.h" #include "analyzer_command.h" @@ -590,6 +591,10 @@ void Analyzer::init_unprivileged() switcher->push(new IpsContext); SnortConfig* sc = SnortConfig::get_conf(); + + // This should be called as soon as possible + // to handle all trace log messages + TraceLogApi::thread_init(sc); CodecManager::thread_init(sc); // this depends on instantiated daq capabilities @@ -676,6 +681,8 @@ void Analyzer::term() sfthreshold_free(); RateFilter_Cleanup(); + + TraceLogApi::thread_term(); } Analyzer::Analyzer(SFDAQInstance* instance, unsigned i, const char* s, uint64_t msg_cnt) diff --git a/src/main/modules.cc b/src/main/modules.cc index 8b9ce42ea..81861f332 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -58,6 +58,7 @@ #include "stream/stream.h" #include "target_based/sftarget_data.h" #include "target_based/snort_protocols.h" +#include "trace/trace_module.h" #include "snort_config.h" #include "snort_module.h" @@ -1957,6 +1958,7 @@ void module_init() ModuleManager::add_module(new RuleStateModule); ModuleManager::add_module(new SearchEngineModule); ModuleManager::add_module(new SFDAQModule); + ModuleManager::add_module(new TraceModule); // these could but prolly shouldn't be policy specific // or should be broken into policy and non-policy parts diff --git a/src/main/snort.cc b/src/main/snort.cc index 9d2e50340..0b6a7150e 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -67,6 +67,7 @@ #include "stream/stream_inspectors.h" #include "target_based/sftarget_reader.h" #include "time/periodic.h" +#include "trace/trace_log_api.h" #include "utils/util.h" #ifdef PIGLET @@ -155,6 +156,11 @@ 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); + + // This call must be immediately after "SnortConfig::set_conf(sc)" + // since the first trace call may happen somewhere after this point + TraceLogApi::thread_init(sc); + PluginManager::load_so_plugins(sc); #ifdef PIGLET if ( !Piglet::piglet_mode() ) @@ -331,6 +337,10 @@ void Snort::term() LogMessage("%s Snort exiting\n", get_prompt()); + // This call must be before SnortConfig cleanup + // since the "TraceLogApi::thread_term()" uses SnortConfig + TraceLogApi::thread_term(); + /* free allocated memory */ if (SnortConfig::get_conf() == snort_cmd_line_conf) { diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 935a8fad6..c3edd8c74 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -59,6 +59,7 @@ #include "sfip/sf_ip.h" #include "target_based/sftarget_reader.h" #include "target_based/snort_protocols.h" +#include "trace/trace_config.h" #include "utils/dnet_header.h" #include "utils/util.h" #include "utils/util_cstring.h" @@ -264,6 +265,8 @@ SnortConfig::~SnortConfig() delete ha_config; delete global_dbus; + delete trace_config; + delete profiler; delete latency; delete memory; diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 5c2c18bdd..b52c15b52 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -128,6 +128,7 @@ enum TunnelFlags class FastPatternConfig; class RuleStateMap; class ThreadConfig; +class TraceConfig; struct srmm_table_t; struct sopg_table_t; @@ -412,6 +413,10 @@ public: ThreadConfig* thread_config; HighAvailabilityConfig* ha_config = nullptr; + //------------------------------------------------------ + + TraceConfig* trace_config = nullptr; + //------------------------------------------------------ //Reload inspector related diff --git a/src/main/snort_debug.cc b/src/main/snort_debug.cc index 57b03e8fa..90169bbc5 100644 --- a/src/main/snort_debug.cc +++ b/src/main/snort_debug.cc @@ -24,49 +24,29 @@ #include "snort_debug.h" -#include - #include -#include "log/messages.h" +#include "trace/trace_log_api.h" #include "utils/safec.h" -#include "snort_config.h" +#define STD_BUF_SIZE 1024 namespace snort { -template -static inline void trace_vprintf(const char* name, TraceLevel log_level, +template +void trace_vprintf(const char* name, TraceLevel log_level, const char* trace_option, const char* fmt, va_list ap) { - char buf[STD_BUF]; - int buf_len = sizeof(buf); - char* buf_ptr = buf; - - if ( name ) - { - int size = snprintf(buf, buf_len, "%s:%s:%d: ", name, trace_option, log_level); - if ( size >= buf_len ) - size = buf_len - 1; - if ( size > 0 ) - { - buf_ptr += size; - buf_len -= size; - } - } - - vsnprintf(buf_ptr, buf_len, fmt, ap); + char buf[STD_BUF_SIZE]; + vsnprintf(buf, sizeof(buf), fmt, ap); - if ( SnortConfig::get_conf() and SnortConfig::log_syslog() ) - syslog(LOG_DAEMON | LOG_DEBUG, "%s", buf); - else - output(buf, stdout); + log_func(buf, name, log_level, trace_option); } void trace_vprintf(const char* name, TraceLevel log_level, const char* trace_option, const char* fmt, va_list ap) { - trace_vprintf(name, log_level, trace_option, fmt, ap); + trace_vprintf(name, log_level, trace_option, fmt, ap); } } @@ -89,12 +69,13 @@ struct TestCase const char* expected; }; -static char testing_dump[STD_BUF]; -static int test_fputs(const char* str, FILE*) -{ - memcpy_s(testing_dump, STD_BUF, str, STD_BUF); +static char testing_dump[STD_BUF_SIZE]; - return 0; +void test_log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) +{ + snprintf(testing_dump, sizeof(testing_dump), "%s:%s:%d: %s", + name, trace_option, log_level, log_msg); } TEST_CASE("macros", "[trace]") @@ -129,10 +110,10 @@ TEST_CASE("macros", "[trace]") #undef trace_printf //These templates expand to replace the default expansion of trace_vprintf. -//This custom expansion replaces output (expands to fputs in snort_debug.h macros) -//with test_fputs for capturing what would be passed to the console. -#define trace_print trace_print> -#define trace_printf trace_printf> +//This custom expansion replaces log_func (expands to TraceLogApi::log()) +//with test_log for capturing what would be passed to the console. +#define trace_print trace_print> +#define trace_printf trace_printf> enum { @@ -152,189 +133,191 @@ const TraceOptionString test_trace_values[] = { "option5", TEST_TRACE_OPTION5 }, }; -TEST_CASE("trace all=0", "[trace]") +TEST_CASE("Trace logging", "[trace]") { - Trace test("test"); + SECTION("trace all=0") + { + Trace test("test"); - Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module"); - Value trace_val((double)0); - trace_val.set(&p); + Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module"); + Value trace_val((double)0); + trace_val.set(&p); - test.set(trace_val); + test.set(trace_val); - testing_dump[0] = '\0'; - debug_log(test, "my message"); - CHECK( testing_dump[0] == '\0' ); -} - -TEST_CASE("debug_log", "[trace]") -{ - Trace test("test"); + testing_dump[0] = '\0'; + debug_log(test, "my message"); + CHECK( testing_dump[0] == '\0' ); + } + SECTION("debug_log") + { + Trace test("test"); - Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module"); - Value trace_val((double)1); - trace_val.set(&p); + Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module"); + Value trace_val((double)1); + trace_val.set(&p); - test.set(trace_val); + test.set(trace_val); - testing_dump[0] = '\0'; - debug_log(test, "my message"); - CHECK( !strcmp(testing_dump, "test:all:1: my message") ); + testing_dump[0] = '\0'; + debug_log(test, "my message"); + CHECK( !strcmp(testing_dump, "test:all:1: my message") ); - Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all"); - Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1"); - Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2"); - Value trace_val1("trace"); + Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all"); + Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1"); + Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2"); + Value trace_val1("trace"); - Trace testing_opt("testing_opt", test_trace_values, - (sizeof(test_trace_values) / sizeof(TraceOptionString))); + Trace testing_opt("testing_opt", test_trace_values, + (sizeof(test_trace_values) / sizeof(TraceOptionString))); - // set log_level = 1 for TEST_TRACE_OPTION1 - trace_val1.set(&p1); - trace_val1.set_enum(1); - testing_opt.set(trace_val1); + // set log_level = 1 for TEST_TRACE_OPTION1 + trace_val1.set(&p1); + trace_val1.set_enum(1); + testing_opt.set(trace_val1); - // set log_level = 5 for TEST_TRACE_OPTION3 - trace_val1.set(&p2); - trace_val1.set_enum(5); - testing_opt.set(trace_val1); + // set log_level = 5 for TEST_TRACE_OPTION3 + trace_val1.set(&p2); + trace_val1.set_enum(5); + testing_opt.set(trace_val1); - // set log_level = 2 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5 - trace_val1.set(&p_all); - trace_val1.set_enum(2); - testing_opt.set(trace_val1); + // set log_level = 2 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5 + trace_val1.set(&p_all); + trace_val1.set_enum(2); + testing_opt.set(trace_val1); - testing_dump[0] = '\0'; - debug_log(testing_opt, TEST_TRACE_OPTION1, "my other masked message"); - CHECK( !strcmp(testing_dump, "testing_opt:option1:1: my other masked message") ); + testing_dump[0] = '\0'; + debug_log(testing_opt, TEST_TRACE_OPTION1, "my other masked message"); + CHECK( !strcmp(testing_dump, "testing_opt:option1:1: my other masked message") ); - testing_dump[0] = '\0'; - debug_log(3, testing_opt, TEST_TRACE_OPTION2, "log option2 message"); - CHECK( testing_dump[0] == '\0' ); + testing_dump[0] = '\0'; + debug_log(3, testing_opt, TEST_TRACE_OPTION2, "log option2 message"); + CHECK( testing_dump[0] == '\0' ); - testing_dump[0] = '\0'; - debug_log(testing_opt, TEST_TRACE_OPTION2, "log option2 message"); - CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") ); + testing_dump[0] = '\0'; + debug_log(testing_opt, TEST_TRACE_OPTION2, "log option2 message"); + CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") ); - testing_dump[0] = '\0'; - debug_log(6, testing_opt, TEST_TRACE_OPTION3, "log option3 message"); - CHECK( testing_dump[0] == '\0' ); + testing_dump[0] = '\0'; + debug_log(6, testing_opt, TEST_TRACE_OPTION3, "log option3 message"); + CHECK( testing_dump[0] == '\0' ); - testing_dump[0] = '\0'; - debug_log(3, testing_opt, TEST_TRACE_OPTION3, "log option3 message"); - CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") ); + testing_dump[0] = '\0'; + debug_log(3, testing_opt, TEST_TRACE_OPTION3, "log option3 message"); + CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") ); - testing_dump[0] = '\0'; - debug_log(2, testing_opt, TEST_TRACE_OPTION4, "log option4 message"); - CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") ); + testing_dump[0] = '\0'; + debug_log(2, testing_opt, TEST_TRACE_OPTION4, "log option4 message"); + CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") ); - testing_dump[0] = '\0'; - debug_log(4, testing_opt, TEST_TRACE_OPTION5, "log option5 message"); - CHECK( testing_dump[0] == '\0' ); -} + testing_dump[0] = '\0'; + debug_log(4, testing_opt, TEST_TRACE_OPTION5, "log option5 message"); + CHECK( testing_dump[0] == '\0' ); + } + SECTION("debug_logf") + { + Trace test("test"); + + Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module"); + Value trace_val((double)1); + trace_val.set(&p); + test.set(trace_val); + + testing_dump[0] = '\0'; + debug_logf(test, "%s %s", "my", "message"); + CHECK( !strcmp(testing_dump, "test:all:1: my message") ); + + Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all"); + Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1"); + Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2"); + Value trace_val1("trace"); + + Trace testing_opt("testing_opt", test_trace_values, + (sizeof(test_trace_values) / sizeof(TraceOptionString))); + + // set log_level = 1 for TEST_TRACE_OPTION1 + trace_val1.set(&p1); + trace_val1.set_enum(1); + testing_opt.set(trace_val1); + + // set log_level = 5 for TEST_TRACE_OPTION3 + trace_val1.set(&p2); + trace_val1.set_enum(5); + testing_opt.set(trace_val1); + + // set log_level = 3 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5 + trace_val1.set(&p_all); + trace_val1.set_enum(3); + testing_opt.set(trace_val1); + + testing_dump[0] = '\0'; + debug_logf(testing_opt, TEST_TRACE_OPTION1, "%s %s %s", "log", "option1", "message"); + CHECK( !strcmp(testing_dump, "testing_opt:option1:1: log option1 message") ); + + testing_dump[0] = '\0'; + debug_logf(testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message"); + CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") ); + + testing_dump[0] = '\0'; + debug_logf(4, testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message"); + CHECK( testing_dump[0] == '\0' ); + + testing_dump[0] = '\0'; + debug_logf(3, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message"); + CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") ); + + testing_dump[0] = '\0'; + debug_logf(6, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message"); + CHECK( testing_dump[0] == '\0' ); + + testing_dump[0] = '\0'; + debug_logf(2, testing_opt, TEST_TRACE_OPTION4, "%s %s %s", "log", "option4", "message"); + CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") ); + + testing_dump[0] = '\0'; + debug_logf(4, testing_opt, TEST_TRACE_OPTION5, "%s %s %s", "log", "option5", "message"); + CHECK( testing_dump[0] == '\0' ); + } + SECTION("safety") + { + Trace test("test"); -TEST_CASE("debug_logf", "[trace]") -{ - Trace test("test"); - - Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module"); - Value trace_val((double)1); - trace_val.set(&p); - test.set(trace_val); - - testing_dump[0] = '\0'; - debug_logf(test, "%s %s", "my", "message"); - CHECK( !strcmp(testing_dump, "test:all:1: my message") ); - - Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all"); - Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1"); - Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2"); - Value trace_val1("trace"); - - Trace testing_opt("testing_opt", test_trace_values, - (sizeof(test_trace_values) / sizeof(TraceOptionString))); - - // set log_level = 1 for TEST_TRACE_OPTION1 - trace_val1.set(&p1); - trace_val1.set_enum(1); - testing_opt.set(trace_val1); - - // set log_level = 5 for TEST_TRACE_OPTION3 - trace_val1.set(&p2); - trace_val1.set_enum(5); - testing_opt.set(trace_val1); - - // set log_level = 3 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5 - trace_val1.set(&p_all); - trace_val1.set_enum(3); - testing_opt.set(trace_val1); - - testing_dump[0] = '\0'; - debug_logf(testing_opt, TEST_TRACE_OPTION1, "%s %s %s", "log", "option1", "message"); - CHECK( !strcmp(testing_dump, "testing_opt:option1:1: log option1 message") ); - - testing_dump[0] = '\0'; - debug_logf(testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message"); - CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") ); - - testing_dump[0] = '\0'; - debug_logf(4, testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message"); - CHECK( testing_dump[0] == '\0' ); - - testing_dump[0] = '\0'; - debug_logf(3, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message"); - CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") ); - - testing_dump[0] = '\0'; - debug_logf(6, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message"); - CHECK( testing_dump[0] == '\0' ); - - testing_dump[0] = '\0'; - debug_logf(2, testing_opt, TEST_TRACE_OPTION4, "%s %s %s", "log", "option4", "message"); - CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") ); - - testing_dump[0] = '\0'; - debug_logf(4, testing_opt, TEST_TRACE_OPTION5, "%s %s %s", "log", "option5", "message"); - CHECK( testing_dump[0] == '\0' ); -} + Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module"); + Value trace_val((double)1); + trace_val.set(&p); -TEST_CASE("safety", "[trace]") -{ - Trace test("test"); + test.set(trace_val); - Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module"); - Value trace_val((double)1); - trace_val.set(&p); + char message[STD_BUF_SIZE + 1]; - test.set(trace_val); + for( int i = 0; i < STD_BUF_SIZE; i++ ) + message[i] = 'A'; + message[STD_BUF_SIZE] = '\0'; - char message[STD_BUF + 1]; + testing_dump[0] = '\0'; + debug_log(test, message); + CHECK( (strlen(testing_dump) == STD_BUF_SIZE - 1) ); - for( int i = 0; i < STD_BUF; i++ ) - message[i] = 'A'; - message[STD_BUF] = '\0'; + Trace testing_opt("testing_opt", test_trace_values, + (sizeof(test_trace_values) / sizeof(TraceOptionString))); - testing_dump[0] = '\0'; - debug_log(test, message); - CHECK( (strlen(testing_dump) == STD_BUF - 1) ); + Parameter p1("option3", Parameter::PT_INT, "0:255", "0", "p1"); + Value trace_val1("trace"); + trace_val1.set(&p1); + trace_val1.set_enum(5); + testing_opt.set(trace_val1); - Trace testing_opt("testing_opt", test_trace_values, - (sizeof(test_trace_values) / sizeof(TraceOptionString))); + testing_dump[0] = '\0'; + debug_log(3, testing_opt, TEST_TRACE_OPTION3, message); + CHECK( (strlen(testing_dump) == STD_BUF_SIZE - 1) ); - Parameter p1("option3", Parameter::PT_INT, "0:255", "0", "p1"); - Value trace_val1("trace"); - trace_val1.set(&p1); - trace_val1.set_enum(5); - testing_opt.set(trace_val1); + testing_dump[0] = '\0'; + debug_log(6, testing_opt, TEST_TRACE_OPTION3, message); + CHECK( (strlen(testing_dump) == 0) ); + } +} - testing_dump[0] = '\0'; - debug_log(3, testing_opt, TEST_TRACE_OPTION3, message); - CHECK( (strlen(testing_dump) == STD_BUF - 1) ); +#endif // DEBUG_MSGS - testing_dump[0] = '\0'; - debug_log(6, testing_opt, TEST_TRACE_OPTION3, message); - CHECK( (strlen(testing_dump) == 0) ); -} -#endif +#endif // UNIT_TEST -#endif diff --git a/src/managers/coreinit.lua b/src/managers/coreinit.lua index 7f607870d..bf02b77ea 100644 --- a/src/managers/coreinit.lua +++ b/src/managers/coreinit.lua @@ -39,6 +39,7 @@ packets = { } process = { } search_engine = { } so_proxy = { } +trace = { } -- exceptions: diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt new file mode 100644 index 000000000..adbb81c21 --- /dev/null +++ b/src/trace/CMakeLists.txt @@ -0,0 +1,16 @@ + +set ( TRACE_SOURCES + trace_config.cc + trace_config.h + trace_log.cc + trace_log.h + trace_log_api.cc + trace_log_api.h + trace_log_base.h + trace_module.cc + trace_module.h +) + +add_library ( trace OBJECT + ${TRACE_SOURCES} +) diff --git a/src/trace/dev_notes.txt b/src/trace/dev_notes.txt new file mode 100644 index 000000000..962fdfa57 --- /dev/null +++ b/src/trace/dev_notes.txt @@ -0,0 +1,66 @@ +This directory contains the trace logger framework. + +* TraceLogger + + The TraceLogger encapsulates the logging method for traces. A particular thread-local logger + is created per each packet thread and one for the main thread. The logging configuration + happens in the module. The logger factory is used to init/cleanup loggers. + + Include "trace_log_base.h" to get TraceLogger base class. + Derived loggers placed into "trace_log.h/trace_log.cc". + +* TraceLoggerFactory + + The base TraceLoggerFactory is used to create a particular TraceLogger instance per each + thread. One factory instance exists which used to init/cleanup loggers and placed + into TraceConfig. The factory object instantiates in the module due to configuration. + + Include "trace_log_base.h" to get TraceLoggerFactory base class and template function + to create particular objects. Derived factories placed into "trace_log.h/trace_log.cc". + +* TraceConfig + + This is a class that handles a pointer to TraceLoggerFactory and used by TraceLogApi as + a global access point. Pointer to TraceConfig is placed into SnortConfig. It will be + overwritten during reloading and new TraceLoggerFactory pointer will be used by TraceLogApi + since that point. + + TraceConfig placed into "trace_config.h". + +* TraceModule + + This module provides configuration for trace logs. The main goal of TraceModule + is to create a concrete logger factory based on the configuration, init/reload TraceConfig + pointer and move it into SnortConfig. + + This is a built-in module (from coreinit.lua) + + The module placed into "trace_module.h/trace_module.cc". + +* TraceLogApi + + TraceLogApi is a facade API class used to init/term trace logger framework and make logs + per each thread. TraceLogger is encapsulated in TraceLogApi. This, in a couple with + the TraceConfig, is a single common entry point to trace logger framework. + + TraceLogApi placed into "trace_log_api.h/trace_log_api.cc" + +* Configuration override + + By default, the factory will be initialized based on Snort run mode (stdout or syslog). + But this can be explicitly overwritten in TraceModule's configuration to specify which + kind of logger to use. + + Changes will be applied in case of reloading too. + +* External dependencies + + Include TraceLogApi header somewhere in the code where it needs to make trace logs. + Make sure that TraceLogApi::thread_init()/thread_term() are provided for thread where + TraceLogApi::log() is going used. + + TraceConfig should be configured and moved into SnortConfig before TraceLogApi init. + + To create specific TraceLogger/TraceLoggerFactory pair just inherit base classes placed + into "trace_log_base.h" and init TraceConfig with a new factory during configuration. + diff --git a/src/trace/trace_config.cc b/src/trace/trace_config.cc new file mode 100644 index 000000000..f280607f3 --- /dev/null +++ b/src/trace/trace_config.cc @@ -0,0 +1,32 @@ +//-------------------------------------------------------------------------- +// 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_config.cc author Oleksandr Serhiienko + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "trace_config.h" + +#include "trace_log_base.h" + +using namespace snort; + +TraceConfig::~TraceConfig() +{ delete logger_factory; } + diff --git a/src/trace/trace_config.h b/src/trace/trace_config.h new file mode 100644 index 000000000..ea8be458f --- /dev/null +++ b/src/trace/trace_config.h @@ -0,0 +1,38 @@ +//-------------------------------------------------------------------------- +// 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_config.h author Oleksandr Serhiienko + +#ifndef TRACE_CONFIG_H +#define TRACE_CONFIG_H + +namespace snort +{ +class TraceLoggerFactory; +} + +class TraceConfig +{ +public: + TraceConfig() = default; + ~TraceConfig(); + + snort::TraceLoggerFactory* logger_factory = nullptr; +}; + +#endif // TRACE_CONFIG_H + diff --git a/src/trace/trace_log.cc b/src/trace/trace_log.cc new file mode 100644 index 000000000..fe43ceb19 --- /dev/null +++ b/src/trace/trace_log.cc @@ -0,0 +1,100 @@ +//-------------------------------------------------------------------------- +// 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_log.cc author Oleksandr Serhiienko + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "trace_log.h" + +#include +#include + +using namespace snort; + +//----------------------------------------------- +// Loggers +//----------------------------------------------- + +// Stdout + +class StdoutTraceLogger : public TraceLogger +{ +public: + StdoutTraceLogger(); + + void log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) override; + +private: + FILE* file; +}; + +StdoutTraceLogger::StdoutTraceLogger() + : file(stdout) +{ } + +void StdoutTraceLogger::log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) +{ + fprintf(file, "%s:%s:%d: %s", name, trace_option, log_level, log_msg); +} + +// Syslog + +class SyslogTraceLogger : public TraceLogger +{ +public: + SyslogTraceLogger(); + + void log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) override; + +private: + int priority; +}; + +SyslogTraceLogger::SyslogTraceLogger() + : priority(LOG_DAEMON | LOG_DEBUG) +{ } + +void SyslogTraceLogger::log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) +{ + syslog(priority, "%s:%s:%d: %s", name, trace_option, log_level, log_msg); +} + +//----------------------------------------------- +// Logger factories +//----------------------------------------------- + +// Stdout + +TraceLogger* StdoutLoggerFactory::instantiate() +{ + return new StdoutTraceLogger(); +} + +// Syslog + +TraceLogger* SyslogLoggerFactory::instantiate() +{ + return new SyslogTraceLogger(); +} + diff --git a/src/trace/trace_log.h b/src/trace/trace_log.h new file mode 100644 index 000000000..34096ee0c --- /dev/null +++ b/src/trace/trace_log.h @@ -0,0 +1,50 @@ +//-------------------------------------------------------------------------- +// 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_log.h author Oleksandr Serhiienko + +#ifndef TRACE_LOG_H +#define TRACE_LOG_H + +#include "trace_log_base.h" + +//----------------------------------------------- +// Logger factories +//----------------------------------------------- + +class StdoutLoggerFactory : public snort::TraceLoggerFactory +{ +public: + StdoutLoggerFactory() = default; + StdoutLoggerFactory(const StdoutLoggerFactory&) = delete; + StdoutLoggerFactory& operator=(const StdoutLoggerFactory&) = delete; + + snort::TraceLogger* instantiate() override; +}; + +class SyslogLoggerFactory : public snort::TraceLoggerFactory +{ +public: + SyslogLoggerFactory() = default; + SyslogLoggerFactory(const SyslogLoggerFactory&) = delete; + SyslogLoggerFactory& operator=(const SyslogLoggerFactory&) = delete; + + snort::TraceLogger* instantiate() override; +}; + +#endif // TRACE_LOG_H + diff --git a/src/trace/trace_log_api.cc b/src/trace/trace_log_api.cc new file mode 100644 index 000000000..b3023c4b5 --- /dev/null +++ b/src/trace/trace_log_api.cc @@ -0,0 +1,54 @@ +//-------------------------------------------------------------------------- +// 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_log_api.cc author Oleksandr Serhiienko + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "trace_log_api.h" + +#include "main/snort_config.h" +#include "main/thread.h" + +#include "trace_config.h" +#include "trace_log_base.h" + +using namespace snort; + +static THREAD_LOCAL TraceLogger* g_trace_logger = nullptr; + +void TraceLogApi::thread_init(SnortConfig* sc) +{ + if ( sc->trace_config and sc->trace_config->logger_factory ) + g_trace_logger = sc->trace_config->logger_factory->instantiate(); +} + +void TraceLogApi::thread_term() +{ + delete g_trace_logger; + g_trace_logger = nullptr; +} + +void TraceLogApi::log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) +{ + if ( g_trace_logger ) + g_trace_logger->log(log_msg, name, log_level, trace_option); +} + diff --git a/src/trace/trace_log_api.h b/src/trace/trace_log_api.h new file mode 100644 index 000000000..afde50873 --- /dev/null +++ b/src/trace/trace_log_api.h @@ -0,0 +1,41 @@ +//-------------------------------------------------------------------------- +// 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_log_api.h author Oleksandr Serhiienko + +#ifndef TRACE_LOG_API_H +#define TRACE_LOG_API_H + +#include + +namespace snort +{ +struct SnortConfig; + +class TraceLogApi +{ +public: + static void thread_init(SnortConfig* sc); + static void thread_term(); + + static void log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option); +}; +} + +#endif // TRACE_LOG_API_H + diff --git a/src/trace/trace_log_base.h b/src/trace/trace_log_base.h new file mode 100644 index 000000000..61dff1311 --- /dev/null +++ b/src/trace/trace_log_base.h @@ -0,0 +1,46 @@ +//-------------------------------------------------------------------------- +// 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_log_base.h author Oleksandr Serhiienko + +#ifndef TRACE_LOG_BASE_H +#define TRACE_LOG_BASE_H + +#include + +namespace snort +{ +class TraceLogger +{ +public: + virtual ~TraceLogger() = default; + + virtual void log(const char* log_msg, const char* name, + uint8_t log_level, const char* trace_option) = 0; +}; + +class TraceLoggerFactory +{ +public: + virtual ~TraceLoggerFactory() = default; + + virtual TraceLogger* instantiate() = 0; +}; +} + +#endif // TRACE_LOG_BASE_H + diff --git a/src/trace/trace_module.cc b/src/trace/trace_module.cc new file mode 100644 index 000000000..ef7c23e1b --- /dev/null +++ b/src/trace/trace_module.cc @@ -0,0 +1,132 @@ +//-------------------------------------------------------------------------- +// 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_module.cc author Serhii Vlasiuk + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "trace_module.h" + +#include + +#include "main/snort_config.h" + +#include "trace_config.h" +#include "trace_log.h" + +using namespace snort; + +static const Parameter trace_params[] = +{ + { "output", Parameter::PT_ENUM, "stdout | syslog", nullptr, + "output method for trace log messages" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#define trace_help \ + "configure trace log messages" + +TraceModule::TraceModule() : Module("trace", trace_help, trace_params, false) +{ } + +TraceModule::~TraceModule() +{ + delete t_config; +} + +bool TraceModule::begin(const char* fqn, int, SnortConfig* sc) +{ + if ( !strcmp(fqn, "trace") ) + { + assert(!t_config); + t_config = new TraceConfig(); + + // 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() ) + log_output_type = OUTPUT_TYPE_SYSLOG; + else + log_output_type = OUTPUT_TYPE_STDOUT; + } + + return true; +} + +bool TraceModule::set(const char*, Value& v, SnortConfig* sc) +{ + if ( v.is("output") ) + { + if ( sc->test_mode() ) + return true; + + switch ( v.get_uint8() ) + { + case OUTPUT_TYPE_STDOUT: + log_output_type = OUTPUT_TYPE_STDOUT; + break; + case OUTPUT_TYPE_SYSLOG: + log_output_type = OUTPUT_TYPE_SYSLOG; + break; + default: + return false; + } + + return true; + } + + return false; +} + +bool TraceModule::end(const char* fqn, int, SnortConfig* sc) +{ + if ( !strcmp(fqn, "trace") ) + { + switch ( log_output_type ) + { + case OUTPUT_TYPE_STDOUT: + t_config->logger_factory = new StdoutLoggerFactory(); + break; + case OUTPUT_TYPE_SYSLOG: + t_config->logger_factory = new SyslogLoggerFactory(); + break; + case OUTPUT_TYPE_NO_INIT: + t_config->logger_factory = nullptr; + break; + } + + delete sc->trace_config; + + sc->trace_config = t_config; + t_config = nullptr; + + // "output=syslog" config override case + // do not closelog() here since it will be closed in Snort::clean_exit() + if ( !sc->log_syslog() and log_output_type == OUTPUT_TYPE_SYSLOG + and !local_syslog ) + { + local_syslog = true; + openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON); + } + } + + return true; +} + diff --git a/src/trace/trace_module.h b/src/trace/trace_module.h new file mode 100644 index 000000000..0dca7da9b --- /dev/null +++ b/src/trace/trace_module.h @@ -0,0 +1,55 @@ +//-------------------------------------------------------------------------- +// 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_module.h author Serhii Vlasiuk + +#ifndef TRACE_MODULE_H +#define TRACE_MODULE_H + +#include "framework/module.h" + +class TraceConfig; + +class TraceModule : public snort::Module +{ +private: + enum OutputType + { + OUTPUT_TYPE_STDOUT, + OUTPUT_TYPE_SYSLOG, + OUTPUT_TYPE_NO_INIT + }; + +public: + TraceModule(); + ~TraceModule() 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; + + Usage get_usage() const override + { return GLOBAL; } + +private: + OutputType log_output_type = OUTPUT_TYPE_NO_INIT; + TraceConfig* t_config = nullptr; + bool local_syslog = false; +}; + +#endif // TRACE_MODULE_H +