]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1110 in SNORT/snort3 from packet_trace to master
authorMichael Altizer (mialtize) <mialtize@cisco.com>
Tue, 13 Mar 2018 22:08:01 +0000 (18:08 -0400)
committerMichael Altizer (mialtize) <mialtize@cisco.com>
Tue, 13 Mar 2018 22:08:01 +0000 (18:08 -0400)
Squashed commit of the following:

commit 63889018db28b62c15e7376e4f278e3275d59fa4
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Tue Mar 13 16:15:16 2018 -0400

    PacketTracer: added to the snort namespace

commit d0d916320e7b59b09ff3c776fb2347ccd4ba9995
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Thu Mar 8 14:33:41 2018 -0500

    packet trace: made verdict reasons registerable

commit dc5d48340c610b40e7ab8f9194b84d05ec5a9a8a
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Tue Feb 13 16:27:13 2018 -0500

    packet tracer: added ability to direct logging to file

commit b8ae23501922734b0d54a87cde0488165ed7e98a
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Tue Feb 13 11:09:11 2018 -0500

    packet tracer: fixed function visibility in dynamic modules

commit e4314fc0f8e7f2d5736da7d1c942d86df8063e09
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Mon Feb 12 17:28:25 2018 -0500

    appid: added mute to packet trace

commit df249f0c5650fb138fd9f764f81beafe03160b79
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Mon Feb 12 17:19:26 2018 -0500

    packet tracer: unit tested verbosity

commit c23843038f4c92f066ffc16b56f4f57895f68e4e
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Mon Feb 12 16:41:28 2018 -0500

    sfdaq, packet tracer: implemented verdict reason delivery

commit 82e78ff2b189a3463282b7441766c71c7317f9b1
Author: Carter Waxman <cwaxman@cisco.com>
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 <cwaxman@cisco.com>
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 <cwaxman@cisco.com>
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 <cwaxman@cisco.com>
Date:   Fri Feb 2 12:20:59 2018 -0500

    packet tracer: added mute groups to prevent spamming

commit 3a64876c904c04febbfc2eaa614a582d500b8d40
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Thu Feb 1 14:49:07 2018 -0500

    packet tracer: refactored for better integration with external plugins

commit 6e9ee483a6f99dc8d00520aabe481f52074c1dff
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Fri Feb 2 13:14:19 2018 -0500

    packet tracer: fixed CMakeLists.txt not installing header

src/log/CMakeLists.txt
src/log/packet_tracer.cc
src/log/packet_tracer.h
src/main/modules.cc
src/main/snort.cc
src/network_inspectors/appid/appid_inspector.cc
src/packet_io/sfdaq.cc
src/packet_io/sfdaq.h

index 06beec1b31b328a70f9cd1d2c43c096b55199d39..538e4dc86404a83d1f237832579d4fba0d7cacfc 100644 (file)
@@ -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
 )
index 59fde5466f0c3889df2f3a65961aa9129b608d0c..06e7bb9bea3ad768a9d9f4d96c66ed98e86e37cb 100644 (file)
 #include "packet_tracer.h"
 
 #include <cstdarg>
+#include <cstdio>
+#include <unordered_map>
 
-#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<uint8_t, uint8_t> 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<typename T> 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<PacketTracer>();
+
 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 <fcntl.h>
+#include <unistd.h>
+
+class TestPacketTracer : public PacketTracer
+{
+public:
+    uint8_t dump_reason = VERDICT_REASON_NO_BLOCK;
+
+    static void thread_init()
+    { PacketTracer::_thread_init<TestPacketTracer>(); }
+
+    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<bool> 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<bool> 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
index 2d4e7ca511ace507d7ec70af0d93d8ab5e5a16fc..3d82a7f7bd3b3d2ceae191ad048a6eacf40e1829 100644 (file)
 #ifndef PACKET_TRACER_H
 #define PACKET_TRACER_H
 
+#include <cstdarg>
+#include <cstdio>
 #include <daq_common.h>
+#include <string>
+#include <vector>
+
+#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<bool> 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<typename T = PacketTracer> static void _thread_init();
 };
+}
 
 #endif
index 69d87274c3c4c17813706e93dbd118fd50d86a5f..98a8d4530b717251eed10bce38d456bed00fe3b6 100644 (file)
@@ -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);
 
index 3f9a519aabd8575b65246a650a086f787fcd4ec7..bc371f41dd2b1030e3bfc0ebce23b3d4a2782266 100644 (file)
@@ -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);
 
index ab100c65dacef4103174e1bd1781e266f60b2ab8..8ef38be847f41facae64ef54415f7f0d9e42b8f0 100644 (file)
@@ -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);
index 3e73e983fc6dd17aa10bfb35891f74a8775511a3..1f851234a6bfcd69eae0f4504a6d696ebf4e6578 100644 (file)
@@ -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;
index 6a8cb9db8c5f08e51066bca9e46f7f419c0ad77d..193e79bb87497a50271ebbd933774498d604fd2a 100644 (file)
@@ -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,