From: Bhagya Tholpady (bbantwal) Date: Thu, 27 Aug 2020 11:56:20 +0000 (+0000) Subject: Merge pull request #2409 in SNORT/snort3 from ~OKHOMIAK/snort3:trace_add_ntuple to... X-Git-Tag: 3.0.2-6~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=169d434e98e45d7425d135ff876e03aa083e332e;p=thirdparty%2Fsnort3.git Merge pull request #2409 in SNORT/snort3 from ~OKHOMIAK/snort3:trace_add_ntuple to master Squashed commit of the following: commit bf8a7d52b3b4f28d90095cb276223a7f2da44f08 Author: Oleksii Khomiakovskyi Date: Tue Aug 18 13:53:49 2020 +0300 trace: update loggers to support extended output with n-tuple packet info --- diff --git a/doc/user/trace.txt b/doc/user/trace.txt index 0e6ae9b96..689c5cc92 100644 --- a/doc/user/trace.txt +++ b/doc/user/trace.txt @@ -14,10 +14,12 @@ following parameters: output - configure the output method for trace messages modules - trace configuration for specific modules constraints - filter traces by the packet constraints + log_ntuple - on/off packet n-tuple info logging The following lines, added in snort.lua, will enable trace messages for detection and codec modules. The messages will be printed to syslog if -the packet filtering constraints match. +the packet filtering constraints match. Messages will be in extended format, +including n-tuple packet info at the beginning of each trace message. trace = { @@ -33,7 +35,8 @@ the packet filtering constraints match. dst_ip = "10.1.1.2", src_port = 100, dst_port = 200 - } + }, + log_ntuple = true } The trace module supports config reloading. Also, it's possible to set or clear @@ -188,11 +191,15 @@ The trace control channel command is a way how to configure module trace options and/or packet filter constraints directly during Snort run and without reloading the entire config. +Control channel also allow adjusting trace output format by setting log_ntuple switcher. + After entering the Snort shell, there are two commands available for the trace module: trace.set({ modules = {...}, constraints = {...} }) - set modules traces and constraints (should pass a valid Lua-entry) + trace.set({ log_ntuple = true/false }) - on/off packet n-tuple info logging + trace.clear() - clear modules traces and constraints Also, it's possible to omit tables in the trace.set() command: @@ -219,6 +226,26 @@ C – main (control) thread P – packet thread O – other thread +Setting the option - *log_ntuple* allows you to change the trace message format, +expanding it with information about the processed packet. + +It will be added at the beginning, right after the thread type and instance ID, +in the following format: + + src_ip src_port -> dst_ip dst_port ip_proto AS=address_space + +Where: + + src_ip - source IP address + src_port - source port + dst_ip - destination IP address + dst_port - destination port + ip_proto - IP protocol ID + address_space - unique ID of the address space + +Those info can be displayed only for IP packets. +Port defaults to zero if a packet doesn't have it. + ==== Example - Debugging rules using detection trace The detection engine is responsible for rule evaluation. Turning on the diff --git a/src/trace/dev_notes.txt b/src/trace/dev_notes.txt index b7e73987e..afb85b2e3 100644 --- a/src/trace/dev_notes.txt +++ b/src/trace/dev_notes.txt @@ -31,6 +31,7 @@ This directory contains the trace logger framework. output - create a concrete logger factory based on the output value (stdout/syslog). constraints - set packet constraints to use for trace filtering. modules - set modules trace level verbosity. + log_ntuple - on/off packet n-tuple info logging. This is a built-in module (from coreinit.lua) @@ -45,7 +46,8 @@ This directory contains the trace logger framework. 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; + 1) trace.set({ modules = {}, constraints = {}, log_ntuple = true/false }) + -- set new modules traces, constraints and log_ntuple option; 2) trace.clear() -- clear modules traces and constraints. * TraceSwapParams diff --git a/src/trace/trace_api.cc b/src/trace/trace_api.cc index c55fb2e60..24b81499b 100644 --- a/src/trace/trace_api.cc +++ b/src/trace/trace_api.cc @@ -52,11 +52,18 @@ static void update_constraints(PacketConstraints* new_cs) g_packet_constraints = new_cs; } +static inline void set_ntuple(bool log_ntuple) +{ + if ( g_trace_logger ) + g_trace_logger->set_ntuple(log_ntuple); +} + void TraceApi::thread_init(const TraceConfig* trace_config) { if ( trace_config->logger_factory ) g_trace_logger = trace_config->logger_factory->instantiate(); + set_ntuple(trace_config->log_ntuple); update_constraints(trace_config->constraints); trace_config->setup_module_trace(); } @@ -71,6 +78,7 @@ void TraceApi::thread_term() void TraceApi::thread_reinit(const TraceConfig* trace_config) { + set_ntuple(trace_config->log_ntuple); update_constraints(trace_config->constraints); trace_config->setup_module_trace(); } diff --git a/src/trace/trace_config.cc b/src/trace/trace_config.cc index b0761afb8..5c9320ce6 100644 --- a/src/trace/trace_config.cc +++ b/src/trace/trace_config.cc @@ -47,6 +47,7 @@ TraceConfig::TraceConfig(const TraceConfig& other) : TraceConfig() { traces = other.traces; + log_ntuple = other.log_ntuple; if ( other.constraints ) constraints = new PacketConstraints(*other.constraints); } diff --git a/src/trace/trace_config.h b/src/trace/trace_config.h index e25675541..320a06e01 100644 --- a/src/trace/trace_config.h +++ b/src/trace/trace_config.h @@ -44,6 +44,7 @@ public: public: snort::TraceLoggerFactory* logger_factory = nullptr; snort::PacketConstraints* constraints = nullptr; + bool log_ntuple = false; private: Traces traces; diff --git a/src/trace/trace_logger.h b/src/trace/trace_logger.h index e9a22d0e3..61aba1f84 100644 --- a/src/trace/trace_logger.h +++ b/src/trace/trace_logger.h @@ -33,6 +33,12 @@ public: virtual void log(const char* log_msg, const char* name, uint8_t log_level, const char* trace_option, const Packet* p) = 0; + + void set_ntuple(bool flag) + { log_ntuple = flag; } + +protected: + bool log_ntuple = false; }; class TraceLoggerFactory diff --git a/src/trace/trace_loggers.cc b/src/trace/trace_loggers.cc index 269953d0b..4c74c3618 100644 --- a/src/trace/trace_loggers.cc +++ b/src/trace/trace_loggers.cc @@ -27,6 +27,7 @@ #include #include "main/thread.h" +#include "protocols/packet.h" using namespace snort; @@ -34,6 +35,33 @@ using namespace snort; // Loggers //----------------------------------------------- +static std::string get_ntuple(bool log_ntuple, const Packet* p) +{ + if ( !log_ntuple or !p or !p->has_ip() ) + return ""; + + SfIpString src_addr; + SfIpString dst_addr; + uint16_t src_port = 0; + uint16_t dst_port = 0; + std::stringstream ss; + + p->ptrs.ip_api.get_src()->ntop(src_addr); + p->ptrs.ip_api.get_dst()->ntop(dst_addr); + + if ( p->proto_bits & (PROTO_BIT__TCP | PROTO_BIT__UDP) ) + { + src_port = p->ptrs.sp; + dst_port = p->ptrs.dp; + } + + ss << src_addr << " " << src_port << " -> " << dst_addr << " " << dst_port << " "; + ss << unsigned(p->get_ip_proto_next()) << " "; + ss << "AS=" << p->pkth->address_space_id << ":"; + + return ss.str(); +} + // Stdout class StdoutTraceLogger : public TraceLogger @@ -68,10 +96,10 @@ StdoutTraceLogger::StdoutTraceLogger() } void StdoutTraceLogger::log(const char* log_msg, const char* name, - uint8_t log_level, const char* trace_option, const Packet*) + uint8_t log_level, const char* trace_option, const Packet* p) { - fprintf(file, "%c%u:%s:%s:%d: %s", thread_type, instance_id, name, - trace_option, log_level, log_msg); + fprintf(file, "%c%u:%s%s:%s:%d: %s", thread_type, instance_id, + get_ntuple(log_ntuple, p).c_str(), name, trace_option, log_level, log_msg); } // Syslog @@ -93,9 +121,10 @@ SyslogTraceLogger::SyslogTraceLogger() { } void SyslogTraceLogger::log(const char* log_msg, const char* name, - uint8_t log_level, const char* trace_option, const Packet*) + uint8_t log_level, const char* trace_option, const Packet* p) { - syslog(priority, "%s:%s:%d: %s", name, trace_option, log_level, log_msg); + syslog(priority, "%s%s:%s:%d: %s", get_ntuple(log_ntuple, p).c_str(), + name, trace_option, log_level, log_msg); } //----------------------------------------------- diff --git a/src/trace/trace_module.cc b/src/trace/trace_module.cc index c99f112a5..b15db5cb5 100644 --- a/src/trace/trace_module.cc +++ b/src/trace/trace_module.cc @@ -117,10 +117,13 @@ void TraceModule::generate_params() { "modules", Parameter::PT_TABLE, modules_params.data(), nullptr, "modules trace option" }, { "constraints", Parameter::PT_TABLE, trace_constraints_params, - nullptr, "trace filtering constraints" }, + nullptr, "trace filtering constraints" }, { "output", Parameter::PT_ENUM, "stdout | syslog", nullptr, - "output method for trace log messages" }, + "output method for trace log messages" }, + + { "log_ntuple", Parameter::PT_BOOL, nullptr, "false", + "use extended trace output with n-tuple packet info" }, { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -161,6 +164,11 @@ bool TraceModule::set(const char* fqn, Value& v, SnortConfig*) } return true; } + else if ( v.is("log_ntuple") ) + { + trace_parser->get_trace_config()->log_ntuple = v.get_bool(); + return true; + } else if ( strstr(fqn, "trace.modules.") == fqn ) { std::string module_name = find_module(fqn); diff --git a/src/trace/trace_swap.cc b/src/trace/trace_swap.cc index 5b1879c88..2acfc0aa9 100644 --- a/src/trace/trace_swap.cc +++ b/src/trace/trace_swap.cc @@ -45,9 +45,11 @@ static int clear(lua_State*); void TraceSwapParams::set_params(const Parameter* params) { + const Parameter* ntuple_params = Parameter::find(params, "log_ntuple"); const Parameter* modules_params = Parameter::find(params, "modules"); const Parameter* constraints_params = Parameter::find(params, "constraints"); + assert(ntuple_params); assert(modules_params); assert(constraints_params); @@ -57,12 +59,14 @@ void TraceSwapParams::set_params(const Parameter* params) *constraints_params, + *ntuple_params, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; static const Command commands[] = { - { "set", set, trace_params, "set modules traces and constraints" }, + { "set", set, trace_params, "set modules traces, constraints and log_ntuple option" }, { "clear", clear, nullptr, "clear modules traces and constraints" }, @@ -82,8 +86,10 @@ const Parameter* TraceSwapParams::get_params() class TraceSwap : public AnalyzerCommand { public: - TraceSwap(TraceConfig* tc, bool set_traces = false, bool set_constraints = false) + TraceSwap(TraceConfig* tc, bool set_traces = false, bool set_constraints = false, + bool set_ntuple = false) : trace_config(tc), + is_set_ntuple(set_ntuple), is_set_traces(set_traces), is_set_constraints(set_constraints) { assert(trace_config); } @@ -98,6 +104,7 @@ private: private: TraceConfig* trace_config = nullptr; + bool is_set_ntuple; bool is_set_traces; bool is_set_constraints; }; @@ -125,12 +132,15 @@ 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 ) + else if ( !is_set_traces and !is_set_constraints and !is_set_ntuple ) 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"); + + if ( is_set_ntuple ) + LogMessage("== set log_ntuple option\n"); } static int set(lua_State* L) @@ -147,6 +157,7 @@ static int set(lua_State* L) bool parse_err = false; bool set_traces = false; bool set_constraints = false; + bool set_ntuple = false; // Passed Lua entry check if ( lua_gettop(L) != 1 or !lua_istable(L, 1) ) @@ -166,6 +177,24 @@ static int set(lua_State* L) const char* root_element_key = luaL_checkstring(L, -2); const Parameter* root_parameter = Parameter::find(params_tree, root_element_key); + // extended output switcher + if ( !strcmp(root_element_key, params_tree[2].name) ) + { + if ( lua_isboolean(L, -1) and root_parameter ) + { + set_ntuple = true; + trace_parser.get_trace_config()->log_ntuple = bool(lua_toboolean(L, -1)); + } + else + { + LogMessage("== invalid value is provided: %s\n", root_element_key); + parse_err = true; + } + + lua_pop(L, 1); + continue; + } + if ( !lua_istable(L, -1) or !root_parameter ) { LogMessage("== invalid table is provided: %s\n", root_element_key); @@ -273,7 +302,7 @@ static int set(lua_State* L) if ( !parse_err ) { - if ( !set_traces and !set_constraints ) + if ( !set_traces and !set_constraints and !set_ntuple ) { trace_parser.clear_traces(); trace_parser.clear_constraints(); @@ -283,7 +312,7 @@ static int set(lua_State* L) trace_parser.finalize_constraints(); main_broadcast_command(new TraceSwap( - trace_parser.get_trace_config(), set_traces, set_constraints), + trace_parser.get_trace_config(), set_traces, set_constraints, set_ntuple), true); } else