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 =
{
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
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:
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
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)
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
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();
}
void TraceApi::thread_reinit(const TraceConfig* trace_config)
{
+ set_ntuple(trace_config->log_ntuple);
update_constraints(trace_config->constraints);
trace_config->setup_module_trace();
}
: TraceConfig()
{
traces = other.traces;
+ log_ntuple = other.log_ntuple;
if ( other.constraints )
constraints = new PacketConstraints(*other.constraints);
}
public:
snort::TraceLoggerFactory* logger_factory = nullptr;
snort::PacketConstraints* constraints = nullptr;
+ bool log_ntuple = false;
private:
Traces traces;
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
#include <syslog.h>
#include "main/thread.h"
+#include "protocols/packet.h"
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
}
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
{ }
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);
}
//-----------------------------------------------
{ "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 }
};
}
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);
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);
*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" },
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); }
private:
TraceConfig* trace_config = nullptr;
+ bool is_set_ntuple;
bool is_set_traces;
bool is_set_constraints;
};
{
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)
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) )
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);
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();
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