From: Michael Altizer (mialtize) Date: Tue, 13 Mar 2018 22:08:01 +0000 (-0400) Subject: Merge pull request #1110 in SNORT/snort3 from packet_trace to master X-Git-Tag: 3.0.0-244~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f136457e004c0dc808be981f8ddede22cf1c1deb;p=thirdparty%2Fsnort3.git Merge pull request #1110 in SNORT/snort3 from packet_trace to master Squashed commit of the following: commit 63889018db28b62c15e7376e4f278e3275d59fa4 Author: Carter Waxman Date: Tue Mar 13 16:15:16 2018 -0400 PacketTracer: added to the snort namespace commit d0d916320e7b59b09ff3c776fb2347ccd4ba9995 Author: Carter Waxman Date: Thu Mar 8 14:33:41 2018 -0500 packet trace: made verdict reasons registerable commit dc5d48340c610b40e7ab8f9194b84d05ec5a9a8a Author: Carter Waxman Date: Tue Feb 13 16:27:13 2018 -0500 packet tracer: added ability to direct logging to file commit b8ae23501922734b0d54a87cde0488165ed7e98a Author: Carter Waxman Date: Tue Feb 13 11:09:11 2018 -0500 packet tracer: fixed function visibility in dynamic modules commit e4314fc0f8e7f2d5736da7d1c942d86df8063e09 Author: Carter Waxman Date: Mon Feb 12 17:28:25 2018 -0500 appid: added mute to packet trace commit df249f0c5650fb138fd9f764f81beafe03160b79 Author: Carter Waxman Date: Mon Feb 12 17:19:26 2018 -0500 packet tracer: unit tested verbosity commit c23843038f4c92f066ffc16b56f4f57895f68e4e Author: Carter Waxman Date: Mon Feb 12 16:41:28 2018 -0500 sfdaq, packet tracer: implemented verdict reason delivery commit 82e78ff2b189a3463282b7441766c71c7317f9b1 Author: Carter Waxman Date: Mon Feb 5 15:39:17 2018 -0500 packet tracer: refactored for clarity and simpler use. added pause/unpause. commit 4049ab28c459b1a9f43eddad2227e806832b5c0b Author: Carter Waxman Date: Mon Feb 5 14:42:42 2018 -0500 packet tracer: refactored unit tests to keep config.h dependencies out of headers commit 98f2b9e9d3e1488c8c07b75b9838bd18e626e309 Author: Carter Waxman Date: Mon Feb 5 13:04:48 2018 -0500 packet tracer: removed unnecessary macro. write logs via LogMessage instead of printf. commit 4ec381cfaa1f537e413a0a07d74b570cdaaa20bc Author: Carter Waxman Date: Fri Feb 2 12:20:59 2018 -0500 packet tracer: added mute groups to prevent spamming commit 3a64876c904c04febbfc2eaa614a582d500b8d40 Author: Carter Waxman Date: Thu Feb 1 14:49:07 2018 -0500 packet tracer: refactored for better integration with external plugins commit 6e9ee483a6f99dc8d00520aabe481f52074c1dff Author: Carter Waxman Date: Fri Feb 2 13:14:19 2018 -0500 packet tracer: fixed CMakeLists.txt not installing header --- diff --git a/src/log/CMakeLists.txt b/src/log/CMakeLists.txt index 06beec1b3..538e4dc86 100644 --- a/src/log/CMakeLists.txt +++ b/src/log/CMakeLists.txt @@ -4,6 +4,7 @@ set (LOG_INCLUDES log_text.h messages.h obfuscator.h + packet_tracer.h text_log.h unified2.h u2_packet.h @@ -16,7 +17,6 @@ add_library ( log OBJECT messages.cc obfuscator.cc packet_tracer.cc - packet_tracer.h text_log.cc u2_packet.cc ) diff --git a/src/log/packet_tracer.cc b/src/log/packet_tracer.cc index 59fde5466..06e7bb9be 100644 --- a/src/log/packet_tracer.cc +++ b/src/log/packet_tracer.cc @@ -25,127 +25,189 @@ #include "packet_tracer.h" #include +#include +#include -#include "log.h" #include "packet_io/sfdaq.h" #include "protocols/eth.h" #include "protocols/ip.h" #include "protocols/packet.h" #include "protocols/tcp.h" +#include "log.h" +#include "messages.h" + #ifdef UNIT_TEST #include "catch/snort_catch.h" #endif using namespace snort; -#define PACKET_TRACER_USER_ENABLED 0x00000001 -#define PACKET_TRACER_DAQ_ENABLED 0x00000002 - +static const uint8_t VERDICT_REASON_NO_BLOCK = 2; /* Not blocking packet; all enum defined after this indicates blocking */ +static std::unordered_map reasons = { {VERDICT_REASON_NO_BLOCK, PacketTracer::PRIORITY_UNSET} }; + +// FIXIT-M refactor the way this is used so all methods are members called against this pointer static THREAD_LOCAL PacketTracer* s_pkt_trace = nullptr; +// so modules can register regardless of when packet trace is activated +static THREAD_LOCAL struct{ unsigned val = 0; } global_mutes; + +static std::string log_file = "-"; + +PacketTracer::PacketTracer() +{ reason = VERDICT_REASON_NO_BLOCK; } + +void PacketTracer::register_verdict_reason(uint8_t reason_code, uint8_t priority) +{ + auto it = reasons.find(reason_code); + assert( it == reasons.end() ); + + reasons[reason_code] = priority; +} + +void PacketTracer::set_log_file(std::string file) +{ log_file = file; } + +void PacketTracer::open_file() +{ + if ( log_file == "-" ) + log_fh = stdout; + else + { + std::string path; + const char* fname = get_instance_file(path, log_file.c_str()); + log_fh = fopen(fname, "a+"); + + if ( log_fh == nullptr ) + { + WarningMessage("Could not open %s for packet trace logging\n", log_file.c_str()); + log_fh = stdout; + } + } +} + +// template needed for unit tests +template void PacketTracer::_thread_init() +{ + if ( s_pkt_trace == nullptr ) + s_pkt_trace = new T(); + + s_pkt_trace->mutes.resize(global_mutes.val, false); + s_pkt_trace->open_file(); +} +template void PacketTracer::_thread_init(); + void PacketTracer::thread_init() +{ _thread_init(); } + +PacketTracer::~PacketTracer() { - if (s_pkt_trace == nullptr) + if ( log_fh && log_fh != stdout ) { - s_pkt_trace = new PacketTracer(); + fclose(log_fh); + log_fh = nullptr; } } void PacketTracer::thread_term() { - if (s_pkt_trace) + if ( s_pkt_trace ) { delete s_pkt_trace; s_pkt_trace = nullptr; } } -bool PacketTracer::get_enable(const uint32_t mask) -{ - if (!s_pkt_trace) - return false; - if (mask) - return (s_pkt_trace->enable_flags & mask); - else - return (s_pkt_trace->enable_flags != 0); -} - -void PacketTracer::enable_user_trace() +void PacketTracer::dump_to_daq(const DAQ_PktHdr_t* pkt_hdr) { - assert(s_pkt_trace); - s_pkt_trace->enable_flags |= PACKET_TRACER_USER_ENABLED; + SFDAQ::get_local_instance()->modify_flow_pkt_trace(pkt_hdr, s_pkt_trace->reason, + (uint8_t *)s_pkt_trace->buffer, s_pkt_trace->buff_len + 1); } -void PacketTracer::enable_daq_trace() +void PacketTracer::reset() { - assert(s_pkt_trace); - s_pkt_trace->enable_flags |= PACKET_TRACER_DAQ_ENABLED; -} + buff_len = 0; + buffer[0] = '\0'; + reason = VERDICT_REASON_NO_BLOCK; -void PacketTracer::disable_daq_trace() -{ - assert(s_pkt_trace); - s_pkt_trace->enable_flags &= ~PACKET_TRACER_DAQ_ENABLED; + for ( unsigned i = 0; i < mutes.size(); i++ ) + mutes[i] = false; } void PacketTracer::dump(char* output_buff, unsigned int len) { - if (!get_enable()) + if (!active()) return; if (output_buff) memcpy(output_buff, s_pkt_trace->buffer, (len < s_pkt_trace->buff_len + 1 ? len : s_pkt_trace->buff_len + 1)); - s_pkt_trace->buff_len = 0; - s_pkt_trace->buffer[0] = '\0'; + s_pkt_trace->reset(); } -void PacketTracer::dump(const DAQ_PktHdr_t* pkthdr, DAQ_Verdict verdict) +void PacketTracer::dump(const DAQ_PktHdr_t* pkt_hdr) { - if (!get_enable()) + if (!active()) return; - if (get_enable(PACKET_TRACER_DAQ_ENABLED)) - { - SFDAQ::get_local_instance()->modify_flow_pkt_trace(pkthdr, verdict, - (uint8_t *)s_pkt_trace->buffer, s_pkt_trace->buff_len + 1); - } + if (s_pkt_trace->daq_enabled) + s_pkt_trace->dump_to_daq(pkt_hdr); - if (get_enable(PACKET_TRACER_USER_ENABLED)) - printf("%s\n", s_pkt_trace->buffer); + if (s_pkt_trace->user_enabled) + LogMessage(s_pkt_trace->log_fh, "%s\n", s_pkt_trace->buffer); - s_pkt_trace->buff_len = 0; - s_pkt_trace->buffer[0] = '\0'; + s_pkt_trace->reset(); } -void PacketTracer::log(const char* format, ...) +void PacketTracer::set_reason(uint8_t reason) { - if (!get_enable()) + if ( !active() ) return; - va_list ap; + if ( reasons[reason] > reasons[s_pkt_trace->reason] ) + s_pkt_trace->reason = reason; +} + +void PacketTracer::log(const char* format, va_list ap) +{ + if ( !active() ) + return; - va_start(ap, format); const int buff_space = max_buff_size - s_pkt_trace->buff_len; const int len = vsnprintf(s_pkt_trace->buffer + s_pkt_trace->buff_len, buff_space, format, ap); - va_end(ap); if (len >= 0 and len < buff_space) - { s_pkt_trace->buff_len += len; - } else - { s_pkt_trace->buff_len = max_buff_size - 1; - } +} + +void PacketTracer::log(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + log(format, ap); + va_end(ap); +} + +void PacketTracer::log(TracerMute mute, const char* format, ...) +{ + if ( s_pkt_trace->mutes[mute] ) + return; // logged under this mute once. don't log again until dump. + + va_list ap; + va_start(ap, format); + log(format, ap); + va_end(ap); + + s_pkt_trace->mutes[mute] = true; } void PacketTracer::add_header_info(Packet* p) { - if (!get_enable()) + if (!active()) return; if ( auto eh = layer::get_eth_layer(p) ) @@ -182,108 +244,322 @@ void PacketTracer::add_header_info(Packet* p) } } -#ifdef UNIT_TEST -char* PacketTracer::get_buff() +bool PacketTracer::active() +{ + if ( !s_pkt_trace ) + return false; + + if ( s_pkt_trace->pause_count ) + return false; + + return s_pkt_trace->user_enabled || s_pkt_trace->daq_enabled; +} + +void PacketTracer::enable_user() +{ s_pkt_trace->user_enabled = true; } + +void PacketTracer::enable_daq() +{ s_pkt_trace->daq_enabled = true; } + +void PacketTracer::disable_daq() +{ s_pkt_trace->daq_enabled = false; } + +void PacketTracer::pause() +{ s_pkt_trace->pause_count++; } + +void PacketTracer::unpause() { - return buffer; + assert(s_pkt_trace->pause_count); + + s_pkt_trace->pause_count--; } -unsigned int PacketTracer::get_buff_len() +PacketTracer::TracerMute PacketTracer::get_mute() { - return buff_len; + global_mutes.val++; + if ( s_pkt_trace == nullptr ) + return global_mutes.val - 1; + + s_pkt_trace->mutes.push_back(false); + return s_pkt_trace->mutes.size() - 1; } -#define MAX_PKT_TRACE_BUFF_SIZE 2048 +#ifdef UNIT_TEST +#include +#include + +class TestPacketTracer : public PacketTracer +{ +public: + uint8_t dump_reason = VERDICT_REASON_NO_BLOCK; + + static void thread_init() + { PacketTracer::_thread_init(); } + + static char* get_buff() + { return ((TestPacketTracer*)s_pkt_trace)->buffer; } + + static unsigned int get_buff_len() + { return ((TestPacketTracer*)s_pkt_trace)->buff_len; } + + static bool is_user_enabled() + { return ((TestPacketTracer*)s_pkt_trace)->user_enabled; } + + static bool is_daq_enabled() + { return ((TestPacketTracer*)s_pkt_trace)->daq_enabled; } + + static bool is_paused() + { return ((TestPacketTracer*)s_pkt_trace)->pause_count; } + + static uint8_t get_reason() + { return ((TestPacketTracer*)s_pkt_trace)->reason; } + + static uint8_t get_dump_reason() + { return ((TestPacketTracer*)s_pkt_trace)->dump_reason; } + + virtual void dump_to_daq(const DAQ_PktHdr_t*) override + { dump_reason = reason; } + + static std::vector get_mutes() + { return ((TestPacketTracer*)s_pkt_trace)->mutes; } + + static FILE* get_log_fh() + { return ((TestPacketTracer*)s_pkt_trace)->log_fh; } +}; TEST_CASE("basic log", "[PacketTracer]") { char test_str[] = "1234567890"; // instantiate a packet tracer - PacketTracer::thread_init(); - PacketTracer::enable_user_trace(); + TestPacketTracer::thread_init(); + TestPacketTracer::enable_user(); // basic logging - PacketTracer::log("%s", test_str); - CHECK(!(strcmp(s_pkt_trace->get_buff(), test_str))); - CHECK((s_pkt_trace->get_buff_len() == 10)); + TestPacketTracer::log("%s", test_str); + CHECK(!(strcmp(TestPacketTracer::get_buff(), test_str))); + CHECK((TestPacketTracer::get_buff_len() == 10)); // continue log will add message to the buffer - PacketTracer::log("%s", "ABCDEFG"); - CHECK((strcmp(s_pkt_trace->get_buff(), "1234567890ABCDEFG") == 0)); - CHECK((s_pkt_trace->get_buff_len() == strlen(s_pkt_trace->get_buff()))); + TestPacketTracer::log("%s", "ABCDEFG"); + CHECK((strcmp(TestPacketTracer::get_buff(), "1234567890ABCDEFG") == 0)); + CHECK((TestPacketTracer::get_buff_len() == strlen(TestPacketTracer::get_buff()))); // log empty string won't change existed buffer - unsigned int curr_len = s_pkt_trace->get_buff_len(); + unsigned int curr_len = TestPacketTracer::get_buff_len(); char empty_str[] = ""; - PacketTracer::log("%s", empty_str); - CHECK((s_pkt_trace->get_buff_len() == curr_len)); + TestPacketTracer::log("%s", empty_str); + CHECK((TestPacketTracer::get_buff_len() == curr_len)); - PacketTracer::thread_term(); + TestPacketTracer::thread_term(); } TEST_CASE("corner cases", "[PacketTracer]") { char test_str[] = "1234567890", empty_str[] = ""; - PacketTracer::thread_init(); - PacketTracer::enable_user_trace(); + TestPacketTracer::thread_init(); + TestPacketTracer::enable_user(); // init length check - CHECK((s_pkt_trace->get_buff_len() == 0)); + CHECK((TestPacketTracer::get_buff_len() == 0)); // logging empty string to start with - PacketTracer::log("%s", empty_str); - CHECK((s_pkt_trace->get_buff_len() == 0)); + TestPacketTracer::log("%s", empty_str); + CHECK((TestPacketTracer::get_buff_len() == 0)); // log messages larger than buffer size for(int i=0; i<1024; i++) - PacketTracer::log("%s", test_str); + TestPacketTracer::log("%s", test_str); // when buffer limit is reached, buffer length will stopped at max_buff_size-1 - CHECK((s_pkt_trace->get_buff_len() == (MAX_PKT_TRACE_BUFF_SIZE-1))); + CHECK((TestPacketTracer::get_buff_len() == (TestPacketTracer::max_buff_size-1))); // continue logging will not change anything - PacketTracer::log("%s", test_str); - CHECK((s_pkt_trace->get_buff_len() == (MAX_PKT_TRACE_BUFF_SIZE-1))); + TestPacketTracer::log("%s", test_str); + CHECK((TestPacketTracer::get_buff_len() == (TestPacketTracer::max_buff_size-1))); - PacketTracer::thread_term(); + TestPacketTracer::thread_term(); } TEST_CASE("dump", "[PacketTracer]") { - char test_string[MAX_PKT_TRACE_BUFF_SIZE]; + char test_string[TestPacketTracer::max_buff_size]; char test_str[] = "ABCD", results[] = "ABCD3=400"; - PacketTracer::thread_init(); - PacketTracer::enable_user_trace(); - PacketTracer::log("%s%d=%d", test_str, 3, 400); - PacketTracer::dump(test_string, MAX_PKT_TRACE_BUFF_SIZE); + TestPacketTracer::thread_init(); + TestPacketTracer::enable_user(); + TestPacketTracer::log("%s%d=%d", test_str, 3, 400); + TestPacketTracer::dump(test_string, TestPacketTracer::max_buff_size); CHECK(!strcmp(test_string, results)); - CHECK((s_pkt_trace->get_buff_len() == 0)); + CHECK((TestPacketTracer::get_buff_len() == 0)); // dump again - PacketTracer::dump(test_string, MAX_PKT_TRACE_BUFF_SIZE); + TestPacketTracer::dump(test_string, TestPacketTracer::max_buff_size); CHECK(!strcmp(test_string, "")); - CHECK((s_pkt_trace->get_buff_len() == 0)); + CHECK((TestPacketTracer::get_buff_len() == 0)); - PacketTracer::thread_term(); + TestPacketTracer::thread_term(); } TEST_CASE("enable", "[PacketTracer]") { - PacketTracer::thread_init(); + TestPacketTracer::thread_init(); // packet tracer is disabled by default - CHECK(!PacketTracer::get_enable()); + CHECK(!TestPacketTracer::active()); // enabled from user - PacketTracer::enable_user_trace(); - CHECK(PacketTracer::get_enable()); - CHECK(PacketTracer::get_enable(PACKET_TRACER_USER_ENABLED)); - CHECK(!PacketTracer::get_enable(PACKET_TRACER_DAQ_ENABLED)); + TestPacketTracer::enable_user(); + CHECK(TestPacketTracer::active()); + CHECK(TestPacketTracer::is_user_enabled()); + CHECK(!TestPacketTracer::is_daq_enabled()); // enabled from DAQ - PacketTracer::enable_daq_trace(); - CHECK(PacketTracer::get_enable()); - CHECK(PacketTracer::get_enable(PACKET_TRACER_DAQ_ENABLED)); + TestPacketTracer::enable_daq(); + CHECK(TestPacketTracer::active()); + CHECK(TestPacketTracer::is_daq_enabled()); // disable DAQ enable - PacketTracer::disable_daq_trace(); - CHECK(!PacketTracer::get_enable(PACKET_TRACER_DAQ_ENABLED)); + TestPacketTracer::disable_daq(); + CHECK(!TestPacketTracer::is_daq_enabled()); // user configuration remain enabled - CHECK(PacketTracer::get_enable()); - CHECK(PacketTracer::get_enable(PACKET_TRACER_USER_ENABLED)); + CHECK(TestPacketTracer::active()); + CHECK(TestPacketTracer::is_user_enabled()); - PacketTracer::thread_term(); + TestPacketTracer::thread_term(); +} + +TEST_CASE("pause", "[PacketTracer]") +{ + char test_str[] = "1234567890"; + + TestPacketTracer::thread_init(); + TestPacketTracer::enable_user(); + TestPacketTracer::pause(); + TestPacketTracer::pause(); + TestPacketTracer::pause(); + + TestPacketTracer::log("%s", test_str); + CHECK( TestPacketTracer::get_buff()[0] == '\0' ); + CHECK( TestPacketTracer::get_buff_len() == 0 ); + + TestPacketTracer::unpause(); + + TestPacketTracer::log("%s", test_str); + CHECK( TestPacketTracer::get_buff()[0] == '\0' ); + CHECK( TestPacketTracer::get_buff_len() == 0 ); + + TestPacketTracer::unpause(); + + TestPacketTracer::log("%s", test_str); + CHECK( TestPacketTracer::get_buff()[0] == '\0' ); + CHECK( TestPacketTracer::get_buff_len() == 0 ); + + TestPacketTracer::unpause(); + + TestPacketTracer::log("%s", test_str); + CHECK( !strcmp(TestPacketTracer::get_buff(), test_str) ); + CHECK( TestPacketTracer::get_buff_len() == 10 ); + + TestPacketTracer::thread_term(); +} + +TEST_CASE("reasons", "[PacketTracer]") +{ + TestPacketTracer::thread_init(); + TestPacketTracer::enable_daq(); + uint8_t low1 = 100, low2 = 101, high = 102; + TestPacketTracer::register_verdict_reason(low1, PacketTracer::PRIORITY_LOW); + TestPacketTracer::register_verdict_reason(low2, PacketTracer::PRIORITY_LOW); + TestPacketTracer::register_verdict_reason(high, PacketTracer::PRIORITY_HIGH); + + // Init + CHECK( TestPacketTracer::get_reason() == VERDICT_REASON_NO_BLOCK ); + + // Update + TestPacketTracer::set_reason(low1); + CHECK( TestPacketTracer::get_reason() == low1 ); + + // Don't update if already set + TestPacketTracer::set_reason(VERDICT_REASON_NO_BLOCK); + CHECK( TestPacketTracer::get_reason() == low1 ); + TestPacketTracer::set_reason(low2); + CHECK( TestPacketTracer::get_reason() == low1 ); + + // Always update for high priority + TestPacketTracer::set_reason(high); + CHECK( TestPacketTracer::get_reason() == high ); + + // Dump resets reason + TestPacketTracer::dump(nullptr); + CHECK( TestPacketTracer::get_reason() == VERDICT_REASON_NO_BLOCK ); + + // Dump delivers reason to daq + CHECK( TestPacketTracer::get_dump_reason() == high ); + + TestPacketTracer::thread_term(); +} + +TEST_CASE("verbosity", "[PacketTracer]") +{ + TestPacketTracer::thread_init(); + TestPacketTracer::enable_user(); + PacketTracer::TracerMute mute_1 = TestPacketTracer::get_mute(); + PacketTracer::TracerMute mute_2 = TestPacketTracer::get_mute(); + + TestPacketTracer::log(mute_1, "this should log\n"); + TestPacketTracer::log(mute_1, "this should not log\n"); + TestPacketTracer::log(mute_1, "this should not log\n"); + TestPacketTracer::log(mute_2, "this should also log\n"); + TestPacketTracer::log(mute_2, "this should not log\n"); + TestPacketTracer::log(mute_2, "this should not log\n"); + + std::string val = TestPacketTracer::get_buff(); + std::string expected = "this should log\nthis should also log\n"; + CHECK( val == expected ); + + // reset mutes + TestPacketTracer::dump(nullptr, 0); + TestPacketTracer::log(mute_1, "this should log\n"); + TestPacketTracer::log(mute_2, "this should also log\n"); + val = TestPacketTracer::get_buff(); + CHECK( val == expected ); + + TestPacketTracer::thread_term(); +} + +TEST_CASE("mute on inactive", "[PacketTracer]") +{ + global_mutes.val = 0; + + CHECK( TestPacketTracer::get_mute() == 0 ); + CHECK( TestPacketTracer::get_mute() == 1 ); + CHECK( TestPacketTracer::get_mute() == 2 ); + + // activation mid-run + TestPacketTracer::thread_init(); + + CHECK( TestPacketTracer::get_mute() == 3 ); + CHECK( TestPacketTracer::get_mute() == 4 ); + CHECK( TestPacketTracer::get_mute() == 5 ); + + std::vector expected = {false, false, false, false, false, false}; + CHECK( TestPacketTracer::get_mutes() == expected ); + + TestPacketTracer::thread_term(); +} + +TEST_CASE("open stdout", "[PacketTracer]") +{ + TestPacketTracer::set_log_file("-"); + TestPacketTracer::thread_init(); + CHECK( log_file == "-" ); + CHECK( TestPacketTracer::get_log_fh() == stdout ); + + TestPacketTracer::thread_term(); +} + +TEST_CASE("open file", "[PacketTracer]") +{ + TestPacketTracer::set_log_file("packet_tracer_tmp"); + TestPacketTracer::thread_init(); + CHECK( log_file == "packet_tracer_tmp" ); + + FILE* fh = TestPacketTracer::get_log_fh(); + CHECK( fh != stdout ); + + TestPacketTracer::thread_term(); + std::string path; + remove(get_instance_file(path, "packet_tracer_tmp")); } #endif diff --git a/src/log/packet_tracer.h b/src/log/packet_tracer.h index 2d4e7ca51..3d82a7f7b 100644 --- a/src/log/packet_tracer.h +++ b/src/log/packet_tracer.h @@ -21,35 +21,77 @@ #ifndef PACKET_TRACER_H #define PACKET_TRACER_H +#include +#include #include +#include +#include + +#include "main/snort_types.h" namespace snort { - struct Packet; -} - +struct Packet; class PacketTracer { public: + enum VerdictPriority : uint8_t + { + PRIORITY_UNSET = 0, + PRIORITY_LOW = 1, + PRIORITY_HIGH = 2 + }; + + PacketTracer(); + virtual ~PacketTracer(); + + typedef uint8_t TracerMute; + + static const int max_buff_size = 2048; + + static void set_log_file(std::string); static void thread_init(); static void thread_term(); - static void log(const char* format, ...) __attribute__((format (printf, 1, 2))); + static void dump(char* output_buff, unsigned int len); - static void dump(const DAQ_PktHdr_t* pkthdr, DAQ_Verdict verdict); - static void add_header_info(snort::Packet* p); - static bool get_enable(const uint32_t mask=0); - static void enable_user_trace(); - static void enable_daq_trace(); - static void disable_daq_trace(); -#ifdef UNIT_TEST - char* get_buff(); - unsigned int get_buff_len(); -#endif -private: - uint32_t enable_flags = 0; - static const int max_buff_size = 2048; + static void dump(const DAQ_PktHdr_t*); + + static void add_header_info(Packet* p); + + static void enable_user(); + static void enable_daq(); + static void disable_daq(); + + static SO_PUBLIC bool active(); + + static SO_PUBLIC void pause(); + static SO_PUBLIC void unpause(); + + static SO_PUBLIC TracerMute get_mute(); + + static SO_PUBLIC void register_verdict_reason(uint8_t reason_code, uint8_t priority); + static SO_PUBLIC void set_reason(uint8_t); + static SO_PUBLIC void log(const char* format, ...) __attribute__((format (printf, 1, 2))); + static SO_PUBLIC void log(TracerMute, const char* format, ...) __attribute__((format (printf, 2, 3))); + +protected: + FILE* log_fh = stdout; + std::vector mutes; char buffer[max_buff_size]; - unsigned int buff_len = 0; + unsigned buff_len = 0; + uint8_t reason; + + unsigned pause_count = 0; + bool user_enabled = false; + bool daq_enabled = false; + + virtual void open_file(); + virtual void dump_to_daq(const DAQ_PktHdr_t*); + virtual void reset(); + + static void log(const char*, va_list); + template static void _thread_init(); }; +} #endif diff --git a/src/main/modules.cc b/src/main/modules.cc index 69d87274c..98a8d4530 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -776,6 +776,9 @@ static const Parameter output_params[] = { "enable_packet_trace", Parameter::PT_BOOL, nullptr, "false", "enable summary output of state that determined packet verdict" }, + { "packet_trace_output", Parameter::PT_ENUM, "console | file", "console", + "select where to send packet trace" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -790,6 +793,12 @@ public: Usage get_usage() const override { return GLOBAL; } + + enum PacketTraceOutput + { + PACKET_TRACE_CONSOLE, + PACKET_TRACE_FILE + }; }; bool OutputModule::set(const char*, Value& v, SnortConfig* sc) @@ -806,6 +815,23 @@ bool OutputModule::set(const char*, Value& v, SnortConfig* sc) else if ( v.is("enable_packet_trace") ) sc->enable_packet_trace = v.get_bool(); + else if ( v.is("packet_trace_output") ) + { + switch ( v.get_long() ) + { + case PACKET_TRACE_CONSOLE: + PacketTracer::set_log_file("-"); + break; + + case PACKET_TRACE_FILE: + PacketTracer::set_log_file("packet_trace.txt"); + break; + + default: + return false; + } + } + else if ( v.is("quiet") ) v.update_mask(sc->logging_flags, LOGGING_FLAG__QUIET); diff --git a/src/main/snort.cc b/src/main/snort.cc index 3f9a519aa..bc371f41d 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -769,7 +769,7 @@ void Snort::thread_init_unprivileged() InspectorManager::thread_init(SnortConfig::get_conf()); PacketTracer::thread_init(); if (SnortConfig::packet_trace_enabled()) - PacketTracer::enable_user_trace(); + PacketTracer::enable_user(); // in case there are HA messages waiting, process them first HighAvailabilityManager::process_receive(); @@ -932,9 +932,9 @@ DAQ_Verdict Snort::packet_callback( void*, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt) { if (pkthdr->flags & DAQ_PKT_FLAG_TRACE_ENABLED) - PacketTracer::enable_daq_trace(); + PacketTracer::enable_daq(); else - PacketTracer::disable_daq_trace(); + PacketTracer::disable_daq(); set_default_policy(); Profile profile(totalPerfStats); @@ -962,7 +962,7 @@ DAQ_Verdict Snort::packet_callback( get_network_policy()->policy_id, get_ips_policy()->policy_id, SFDAQ::verdict_to_string(verdict)); - PacketTracer::dump(pkthdr, verdict); + PacketTracer::dump(pkthdr); HighAvailabilityManager::process_update(s_packet->flow, pkthdr); diff --git a/src/network_inspectors/appid/appid_inspector.cc b/src/network_inspectors/appid/appid_inspector.cc index ab100c65d..8ef38be84 100644 --- a/src/network_inspectors/appid/appid_inspector.cc +++ b/src/network_inspectors/appid/appid_inspector.cc @@ -51,6 +51,7 @@ #include "profiler/profiler.h" using namespace snort; +static THREAD_LOCAL PacketTracer::TracerMute appid_mute; // FIXIT-L - appid cleans up openssl now as it is the primary (only) user... eventually this // should probably be done outside of appid @@ -72,7 +73,8 @@ static void add_appid_to_packet_trace(Flow& flow) payload_app_name = appid_api.get_application_name(payload_id); misc_name = appid_api.get_application_name(misc_id); - PacketTracer::log("AppID: service: %s(%d), client: %s(%d), payload: %s(%d), misc: %s(%d)\n", + PacketTracer::log(appid_mute, + "AppID: service: %s(%d), client: %s(%d), payload: %s(%d), misc: %s(%d)\n", (service_app_name ? service_app_name : ""), service_id, (client_app_name ? client_app_name : ""), client_id, (payload_app_name ? payload_app_name : ""), payload_id, @@ -137,6 +139,8 @@ void AppIdInspector::show(SnortConfig*) void AppIdInspector::tinit() { + appid_mute = PacketTracer::get_mute(); + AppIdStatistics::initialize_manager(*config); HostPortCache::initialize(); AppIdServiceState::initialize(); @@ -177,8 +181,9 @@ void AppIdInspector::eval(Packet* p) if (p->flow) { AppIdDiscovery::do_application_discovery(p, *this); - if (PacketTracer::get_enable()) - add_appid_to_packet_trace(*(p->flow)); + // FIXIT-L tag verdict reason as appid for daq + if (PacketTracer::active()) + add_appid_to_packet_trace(*p->flow); } else AppIdPegCounts::inc_disco_peg(AppIdPegCounts::DiscoveryPegs::IGNORED_PACKETS); diff --git a/src/packet_io/sfdaq.cc b/src/packet_io/sfdaq.cc index 3e73e983f..1f851234a 100644 --- a/src/packet_io/sfdaq.cc +++ b/src/packet_io/sfdaq.cc @@ -632,12 +632,12 @@ int SFDAQInstance::modify_flow_opaque(const DAQ_PktHdr_t* hdr, uint32_t opaque) return daq_modify_flow(daq_mod, daq_hand, hdr, &mod); } -int SFDAQInstance::modify_flow_pkt_trace(const DAQ_PktHdr_t* hdr, DAQ_Verdict verdict, +int SFDAQInstance::modify_flow_pkt_trace(const DAQ_PktHdr_t* hdr, uint8_t verdict_reason, uint8_t* buff, uint32_t buff_len) { DAQ_ModFlow_t mod; DAQ_ModFlowPktTrace_t mod_tr; - mod_tr.vreason = (uint8_t)verdict; + mod_tr.vreason = verdict_reason; mod_tr.pkt_trace_data_len = buff_len; mod_tr.pkt_trace_data = buff; mod.type = DAQ_MODFLOW_TYPE_PKT_TRACE; diff --git a/src/packet_io/sfdaq.h b/src/packet_io/sfdaq.h index 6a8cb9db8..193e79bb8 100644 --- a/src/packet_io/sfdaq.h +++ b/src/packet_io/sfdaq.h @@ -67,7 +67,7 @@ public: SO_PUBLIC int query_flow(const DAQ_PktHdr_t*, DAQ_QueryFlow_t*); SO_PUBLIC int modify_flow_opaque(const DAQ_PktHdr_t*, uint32_t opaque); - int modify_flow_pkt_trace(const DAQ_PktHdr_t*, DAQ_Verdict, + int modify_flow_pkt_trace(const DAQ_PktHdr_t*, uint8_t verdict_reason, uint8_t* buff, uint32_t buff_len); int add_expected(const Packet* ctrlPkt, const SfIp* cliIP, uint16_t cliPort, const SfIp* srvIP, uint16_t srvPort, IpProtocol, unsigned timeout_ms,