]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2409 in SNORT/snort3 from ~OKHOMIAK/snort3:trace_add_ntuple to...
authorBhagya Tholpady (bbantwal) <bbantwal@cisco.com>
Thu, 27 Aug 2020 11:56:20 +0000 (11:56 +0000)
committerBhagya Tholpady (bbantwal) <bbantwal@cisco.com>
Thu, 27 Aug 2020 11:56:20 +0000 (11:56 +0000)
Squashed commit of the following:

commit bf8a7d52b3b4f28d90095cb276223a7f2da44f08
Author: Oleksii Khomiakovskyi <okhomiak@cisco.com>
Date:   Tue Aug 18 13:53:49 2020 +0300

    trace: update loggers to support extended output with n-tuple packet info

doc/user/trace.txt
src/trace/dev_notes.txt
src/trace/trace_api.cc
src/trace/trace_config.cc
src/trace/trace_config.h
src/trace/trace_logger.h
src/trace/trace_loggers.cc
src/trace/trace_module.cc
src/trace/trace_swap.cc

index 0e6ae9b9688b9246d1f58b90561cf31ac139b3f7..689c5cc92f3f0e16f608c60f768b85bb0afb735c 100644 (file)
@@ -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
index b7e73987e2d65860bdd9bb3b955b9cf596fc127b..afb85b2e35913a104a456abc82cc2c30342ddc36 100644 (file)
@@ -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
index c55fb2e604e32887a946d4fcebde7139ab9c0569..24b81499b79503b3d446143a77e6c8ea72b2903d 100644 (file)
@@ -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();
 }
index b0761afb8280c136eb22429bc66cab8304d02501..5c9320ce603a30615cc711bd9c4a62bdba2d13ea 100644 (file)
@@ -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);
 }
index e25675541fa5665db147a828efb89a9a2ad7bc59..320a06e010cd4c55d6cecb1730bcf76217bbf81e 100644 (file)
@@ -44,6 +44,7 @@ public:
 public:
     snort::TraceLoggerFactory* logger_factory = nullptr;
     snort::PacketConstraints* constraints = nullptr;
+    bool log_ntuple = false;
 
 private:
     Traces traces;
index e9a22d0e38b299d20a5a9b570cd5ed20f6da9b9d..61aba1f84f1a3c2906a751955a1880c3ed547e7a 100644 (file)
@@ -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
index 269953d0ba0e7ebf2022f5377973ce007a9e4442..4c74c36182a15e7bcfe5ce5c03e5154d41d1766a 100644 (file)
@@ -27,6 +27,7 @@
 #include <syslog.h>
 
 #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);
 }
 
 //-----------------------------------------------
index c99f112a515a4a4e8d3e1f69cf7e8131d0ea4370..b15db5cb50698cb6a049fc4a8d56584c1e8327cc 100644 (file)
@@ -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);
index 5b1879c880e642c45ffe54a395e0213ace37fa29..2acfc0aa9b6484e382ee19dfa27e2dfb87fc0267 100644 (file)
@@ -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