]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1180 in SNORT/snort3 from pkt_trace_command to master
authorMichael Altizer (mialtize) <mialtize@cisco.com>
Tue, 24 Apr 2018 17:36:30 +0000 (13:36 -0400)
committerMichael Altizer (mialtize) <mialtize@cisco.com>
Tue, 24 Apr 2018 17:36:30 +0000 (13:36 -0400)
Squashed commit of the following:

commit 4517f65d5f7c91db3200bce544d74f5de1673821
Author: shaslad <shaslad@cisco.com>
Date:   Thu Mar 29 16:31:29 2018 -0400

    packet_tracer: Modularize and add constraint-based shell enablement

12 files changed:
src/detection/fp_detect.cc
src/log/CMakeLists.txt
src/main/modules.cc
src/main/snort.cc
src/main/snort_config.h
src/network_inspectors/CMakeLists.txt
src/network_inspectors/appid/appid_inspector.cc
src/network_inspectors/packet_tracer/CMakeLists.txt [new file with mode: 0644]
src/network_inspectors/packet_tracer/packet_tracer.cc [moved from src/log/packet_tracer.cc with 63% similarity]
src/network_inspectors/packet_tracer/packet_tracer.h [moved from src/log/packet_tracer.h with 51% similarity]
src/network_inspectors/packet_tracer/packet_tracer_module.cc [new file with mode: 0644]
src/network_inspectors/packet_tracer/packet_tracer_module.h [new file with mode: 0644]

index 5e25059fb6313b018685facf3075e4905986f06c..78f8a7502754d85080c3715ebc44431891a0c929 100644 (file)
 #include "latency/packet_latency.h"
 #include "latency/rule_latency.h"
 #include "log/messages.h"
-#include "log/packet_tracer.h"
 #include "main/modules.h"
 #include "main/snort.h"
 #include "main/snort_config.h"
 #include "main/snort_debug.h"
 #include "managers/action_manager.h"
+#include "packet_tracer/packet_tracer.h"
 #include "parser/parser.h"
 #include "profiler/profiler_defs.h"
 #include "protocols/icmp4.h"
@@ -107,10 +107,13 @@ static inline void fpLogOther(
     if ( EventTrace_IsEnabled() )
         EventTrace_Log(p, otn, action);
 
-    PacketTracer::log("Event: %u:%u:%u, Action %s\n",
-        otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev,
-        Actions::get_string((Actions::Type)action));
-
+    if ( PacketTracer::is_active() )
+    {
+        PacketTracer::log("Event: %u:%u:%u, Action %s\n",
+            otn->sigInfo.gid, otn->sigInfo.sid,
+            otn->sigInfo.rev, Actions::get_string((Actions::Type)action));
+    }
+    
     // rule option actions are queued here (eg replace)
     otn_trigger_actions(otn, p);
 
index 538e4dc86404a83d1f237832579d4fba0d7cacfc..6a6209355254cf1e8a8b6d356ad892ae29480bfc 100644 (file)
@@ -4,7 +4,6 @@ set (LOG_INCLUDES
     log_text.h
     messages.h
     obfuscator.h
-    packet_tracer.h
     text_log.h
     unified2.h
     u2_packet.h
@@ -16,7 +15,6 @@ add_library ( log OBJECT
     log_text.cc
     messages.cc
     obfuscator.cc
-    packet_tracer.cc
     text_log.cc
     u2_packet.cc
 )
index b6c9a8af54d9112893dc88a191ede1ca6ce26440..5374d076bcda2d1442dca5c7bae404c8d887edc3 100644 (file)
 #include "host_tracker/host_cache_module.h"
 #include "latency/latency_module.h"
 #include "log/messages.h"
-#include "log/packet_tracer.h"
 #include "managers/module_manager.h"
 #include "managers/plugin_manager.h"
 #include "memory/memory_module.h"
 #include "packet_io/sfdaq_module.h"
+#include "packet_tracer/packet_tracer_module.h"
 #include "parser/config_file.h"
 #include "parser/parse_conf.h"
 #include "parser/parse_ip.h"
@@ -773,12 +773,6 @@ static const Parameter output_params[] =
 #endif
       "output 20 bytes per lines instead of 16 when dumping buffers" },
 
-    { "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 }
 };
 
@@ -793,12 +787,6 @@ 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)
@@ -812,26 +800,6 @@ bool OutputModule::set(const char*, Value& v, SnortConfig* sc)
     else if ( v.is("dump_payload_verbose") )
         v.update_mask(sc->output_flags, OUTPUT_FLAG__VERBOSE_DUMP);
 
-    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);
 
@@ -1904,6 +1872,7 @@ void module_init()
     ModuleManager::add_module(new CodecModule);
     ModuleManager::add_module(new DetectionModule);
     ModuleManager::add_module(new MemoryModule);
+    ModuleManager::add_module(new PacketTracerModule);
     ModuleManager::add_module(new PacketsModule);
     ModuleManager::add_module(new ProcessModule);
     ModuleManager::add_module(new ProfilerModule);
index eef5834b1ba2ef5a9b5e36e7853ebf2ef827192b..865dae8f3485668490cabaf7c6cd989d48f3581d 100644 (file)
@@ -54,7 +54,6 @@
 #include "latency/rule_latency.h"
 #include "log/log.h"
 #include "log/messages.h"
-#include "log/packet_tracer.h"
 #include "loggers/loggers.h"
 #include "main.h"
 #include "main/shell.h"
@@ -73,6 +72,7 @@
 #include "packet_io/active.h"
 #include "packet_io/sfdaq.h"
 #include "packet_io/trough.h"
+#include "packet_tracer/packet_tracer.h"
 #include "parser/cmd_line.h"
 #include "parser/parser.h"
 #include "profiler/profiler.h"
@@ -769,9 +769,7 @@ void Snort::thread_init_unprivileged()
     HighAvailabilityManager::thread_init(); // must be before InspectorManager::thread_init();
     InspectorManager::thread_init(SnortConfig::get_conf());
     PacketTracer::thread_init();
-    if (SnortConfig::packet_trace_enabled())
-        PacketTracer::enable_user();
-
+    
     // in case there are HA messages waiting, process them first
     HighAvailabilityManager::process_receive();
     PacketManager::thread_init();
@@ -840,7 +838,7 @@ DAQ_Verdict Snort::process_packet(
     PacketManager::decode(p, pkthdr, pkt, is_frag);
     assert(p->pkth && p->pkt);
 
-    PacketTracer::add_header_info(p);
+    PacketTracer::activate(*p);
 
     if (is_frag)
     {
@@ -935,11 +933,6 @@ static DAQ_Verdict update_verdict(Packet* p, DAQ_Verdict verdict, int& inject)
 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();
-    else
-        PacketTracer::disable_daq();
-
     set_default_policy();
     Profile profile(totalPerfStats);
 
@@ -962,11 +955,14 @@ DAQ_Verdict Snort::packet_callback(
     int inject = 0;
     verdict = update_verdict(s_packet, verdict, inject);
 
-    PacketTracer::log("NAP id %u, IPS id %u, Verdict %s\n",
-        get_network_policy()->policy_id, get_ips_policy()->policy_id,
-        SFDAQ::verdict_to_string(verdict));
+    if (PacketTracer::is_active())
+    {
+        PacketTracer::log("NAP id %u, IPS id %u, Verdict %s\n",
+            get_network_policy()->policy_id, get_ips_policy()->policy_id,
+            SFDAQ::verdict_to_string(verdict));
 
-    PacketTracer::dump(pkthdr);
+        PacketTracer::dump(pkthdr);
+    }
 
     HighAvailabilityManager::process_update(s_packet->flow, pkthdr);
 
index 31c4f33aea4dfa2f8c55666122dc45d7a7bc2c57..3d9ce8602bfa090f757141829b6e70e3a02e999d 100644 (file)
@@ -203,7 +203,6 @@ public:
 
     uint16_t event_trace_max = 0;
     long int tagged_packet_limit = 256;
-    bool enable_packet_trace = false;
 
     std::string log_dir;
 
@@ -646,11 +645,6 @@ public:
             !get_conf()->chroot_dir.empty();
     }
 
-    static bool packet_trace_enabled()
-    {
-        return get_conf()->enable_packet_trace;
-    }
-
     bool track_on_syn() const
     { return (run_flags & RUN_FLAG__TRACK_ON_SYN) != 0; }
 
index 95b846878c702065067aa6df0ca32f100391cf8f..a0c32f93deea38bb8e2a1f5c71910839748e90a5 100644 (file)
@@ -4,6 +4,7 @@ add_subdirectory(arp_spoof)
 add_subdirectory(binder)
 add_subdirectory(normalize)
 add_subdirectory(packet_capture)
+add_subdirectory(packet_tracer)
 add_subdirectory(perf_monitor)
 add_subdirectory(port_scan)
 add_subdirectory(reputation)
@@ -20,6 +21,7 @@ set(STATIC_NETWORK_INSPECTOR_PLUGINS
     $<TARGET_OBJECTS:appid>
     $<TARGET_OBJECTS:binder>
     $<TARGET_OBJECTS:normalize>
+    $<TARGET_OBJECTS:packet_tracer>
     $<TARGET_OBJECTS:port_scan>
     $<TARGET_OBJECTS:reputation>
     ${STATIC_INSPECTOR_OBJS}
index f56832372cd07569255d6b2c5911b6136d754905..f8ea11912a1c117b169da423ae40338fb76edc5e 100644 (file)
@@ -29,9 +29,9 @@
 
 #include "flow/flow.h"
 #include "log/messages.h"
-#include "log/packet_tracer.h"
 #include "managers/inspector_manager.h"
 #include "managers/module_manager.h"
+#include "packet_tracer/packet_tracer.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
@@ -75,12 +75,15 @@ 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_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,
-            (misc_name ? misc_name : ""), misc_id);
+        if (PacketTracer::is_active())
+        {
+            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,
+                    (misc_name ? misc_name : ""), misc_id);
+        }
     }
 }
 
@@ -182,13 +185,13 @@ void AppIdInspector::tterm()
 void AppIdInspector::eval(Packet* p)
 {
     Profile profile(appidPerfStats);
-
     appid_stats.packets++;
+    
     if (p->flow)
     {
         AppIdDiscovery::do_application_discovery(p, *this);
         // FIXIT-L tag verdict reason as appid for daq
-        if (PacketTracer::active())
+        if (PacketTracer::is_active())
             add_appid_to_packet_trace(*p->flow);
     }
     else
diff --git a/src/network_inspectors/packet_tracer/CMakeLists.txt b/src/network_inspectors/packet_tracer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4bcc19
--- /dev/null
@@ -0,0 +1,14 @@
+set (PACKET_TRACER_INCLUDES
+    packet_tracer.h
+)
+
+add_library ( packet_tracer OBJECT
+    ${PACKET_TRACER_INCLUDES}
+    packet_tracer.cc
+    packet_tracer_module.h
+    packet_tracer_module.cc
+)
+
+install(FILES ${PACKET_TRACER_INCLUDES}
+    DESTINATION "${INCLUDE_INSTALL_PATH}/network_inspectors/packet_tracer"
+)
\ No newline at end of file
similarity index 63%
rename from src/log/packet_tracer.cc
rename to src/network_inspectors/packet_tracer/packet_tracer.cc
index 9e2acd42e26158deaf74994a63bf29890fccf257..80c67dbcb440c55060e7d5dc8ca788811646831e 100644 (file)
 #include <cstdio>
 #include <unordered_map>
 
+#include "log/log.h"
+#include "log/messages.h"
 #include "packet_io/sfdaq.h"
 #include "protocols/eth.h"
+#include "protocols/icmp4.h"
 #include "protocols/ip.h"
 #include "protocols/packet.h"
 #include "protocols/tcp.h"
-
-#include "log.h"
-#include "messages.h"
+#include "utils/util.h"
 
 #ifdef UNIT_TEST
 #include "catch/snort_catch.h"
 
 using namespace snort;
 
+// -----------------------------------------------------------------------------
+// static variables
+// -----------------------------------------------------------------------------
+
 static const uint8_t VERDICT_REASON_NO_BLOCK = 2; /* Not blocking packet; all enum defined after this indicates blocking */
+
+// FIXIT-M currently non-threadsafe accesses being done in packet threads against this
 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;
+THREAD_LOCAL PacketTracer* snort::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 = "-";
+static bool config_status = false;
 
-PacketTracer::PacketTracer()
-{ reason = VERDICT_REASON_NO_BLOCK; }
+// -----------------------------------------------------------------------------
+// static functions
+// -----------------------------------------------------------------------------
 
 void PacketTracer::register_verdict_reason(uint8_t reason_code, uint8_t priority)
 {
     assert(reasons.find(reason_code) == 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()
 {
@@ -93,21 +83,13 @@ template<typename T> void PacketTracer::_thread_init()
 
     s_pkt_trace->mutes.resize(global_mutes.val, false);
     s_pkt_trace->open_file();
+    s_pkt_trace->user_enabled = config_status;
 }
 template void PacketTracer::_thread_init<PacketTracer>();
 
 void PacketTracer::thread_init()
 { _thread_init(); }
 
-PacketTracer::~PacketTracer()
-{
-    if ( log_fh && log_fh != stdout )
-    {
-        fclose(log_fh);
-        log_fh = nullptr;
-    }
-}
-
 void PacketTracer::thread_term()
 {
     if ( s_pkt_trace )
@@ -117,25 +99,9 @@ void PacketTracer::thread_term()
     }
 }
 
-void PacketTracer::dump_to_daq(const DAQ_PktHdr_t* pkt_hdr)
-{
-    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::reset()
-{
-    buff_len = 0;
-    buffer[0] = '\0';
-    reason = VERDICT_REASON_NO_BLOCK;
-
-    for ( unsigned i = 0; i < mutes.size(); i++ )
-        mutes[i] = false;
-}
-
 void PacketTracer::dump(char* output_buff, unsigned int len)
 {
-    if (!active())
+    if (is_paused())
         return;
 
     if (output_buff)
@@ -147,13 +113,13 @@ void PacketTracer::dump(char* output_buff, unsigned int len)
 
 void PacketTracer::dump(const DAQ_PktHdr_t* pkt_hdr)
 {
-    if (!active())
+    if (is_paused())
         return;
 
-    if (s_pkt_trace->daq_enabled)
+    if (s_pkt_trace->daq_activated)
         s_pkt_trace->dump_to_daq(pkt_hdr);
 
-    if (s_pkt_trace->user_enabled)
+    if (s_pkt_trace->user_enabled or s_pkt_trace->shell_enabled)
         LogMessage(s_pkt_trace->log_fh, "%s\n", s_pkt_trace->buffer);
 
     s_pkt_trace->reset();
@@ -161,33 +127,18 @@ void PacketTracer::dump(const DAQ_PktHdr_t* pkt_hdr)
 
 void PacketTracer::set_reason(uint8_t reason)
 {
-    if ( !active() )
-        return;
-
     if ( reasons[reason] > reasons[s_pkt_trace->reason] )
         s_pkt_trace->reason = reason;
 }
 
-void PacketTracer::log(const char* format, va_list ap)
+void PacketTracer::log(const char* format, ...)
 {
-    if ( !active() )
+    if (is_paused())
         return;
 
-    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);
-
-    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);
+    s_pkt_trace->log(format, ap);
     va_end(ap);
 }
 
@@ -198,78 +149,46 @@ void PacketTracer::log(TracerMute mute, const char* format, ...)
 
     va_list ap;
     va_start(ap, format);
-    log(format, ap);
+    s_pkt_trace->log(format, ap);
     va_end(ap);
 
     s_pkt_trace->mutes[mute] = true;
 }
 
-void PacketTracer::add_header_info(Packet* p)
+bool PacketTracer::is_paused()
+{
+    if ( s_pkt_trace and s_pkt_trace->pause_count )
+        return true;
+    return false;
+}
+
+void PacketTracer::set_constraints(const PTSessionConstraints* constraints)
 {
-    if (!active())
+    if (!s_pkt_trace)
         return;
 
-    if ( auto eh = layer::get_eth_layer(p) )
+    if (!constraints)
     {
-        // MAC layer
-        log("%02X:%02X:%02X:%02X:%02X:%02X -> ", eh->ether_src[0],
-            eh->ether_src[1], eh->ether_src[2], eh->ether_src[3],
-            eh->ether_src[4], eh->ether_src[5]);
-        log("%02X:%02X:%02X:%02X:%02X:%02X ", eh->ether_dst[0],
-            eh->ether_dst[1], eh->ether_dst[2], eh->ether_dst[3],
-            eh->ether_dst[4], eh->ether_dst[5]);
-        // protocol and pkt size
-        log("%04X\n", (uint16_t)eh->ethertype());
-    }
-
-    if (p->ptrs.ip_api.get_src() and p->ptrs.ip_api.get_dst())
-    {
-        char sipstr[INET6_ADDRSTRLEN], dipstr[INET6_ADDRSTRLEN];
-
-        p->ptrs.ip_api.get_src()->ntop(sipstr, sizeof(sipstr));
-        p->ptrs.ip_api.get_dst()->ntop(dipstr, sizeof(dipstr));
-
-        log("%s:%hu -> %s:%hu proto %u\n",
-            sipstr, p->ptrs.sp, dipstr, p->ptrs.dp, (unsigned)p->ptrs.ip_api.proto());
-        log("Packet: %s", p->get_type());
-        if (p->type() == PktType::TCP)
-        {
-            char tcpFlags[10];
-            CreateTCPFlagString(p->ptrs.tcph, tcpFlags);
-            log( " %s, seq %u, ack %u", tcpFlags,
-                p->ptrs.tcph->seq(), p->ptrs.tcph->ack());
-        }
-        log("\n");
+        LogMessage("Debugging packet tracer disabled\n");
+        s_pkt_trace->shell_enabled = false;
     }
+    else 
+        s_pkt_trace->update_constraints(constraints);
 }
 
-bool PacketTracer::active()
+void PacketTracer::configure(bool status, const std::string& file_name)
 {
-    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;
+    log_file = file_name;
+    config_status = status;
 }
 
-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()
 {
     assert(s_pkt_trace->pause_count);
-
     s_pkt_trace->pause_count--;
 }
 
@@ -283,6 +202,232 @@ PacketTracer::TracerMute PacketTracer::get_mute()
     return s_pkt_trace->mutes.size() - 1;
 }
 
+void PacketTracer::activate(const Packet& p)
+{
+    if (!s_pkt_trace)
+        return;
+
+    if ( p.pkth->flags &  DAQ_PKT_FLAG_TRACE_ENABLED )
+        s_pkt_trace->daq_activated = true;
+    else 
+        s_pkt_trace->daq_activated = false;
+
+    if (s_pkt_trace->daq_activated or s_pkt_trace->user_enabled or s_pkt_trace->shell_enabled)
+    {
+        if (!p.ptrs.ip_api.is_ip())
+        {
+            s_pkt_trace->add_eth_header_info(p);
+            s_pkt_trace->add_packet_type_info(p);
+        }
+        else
+        {
+            if (s_pkt_trace->shell_enabled)
+            {
+                uint16_t sport = p.ptrs.sp;
+                uint16_t dport = p.ptrs.dp;
+
+                const SfIp *actual_sip = p.ptrs.ip_api.get_src();
+                const SfIp *actual_dip = p.ptrs.ip_api.get_dst();
+
+                const uint32_t *sip_ptr = actual_sip->get_ip6_ptr();
+                const uint32_t *dip_ptr = actual_dip->get_ip6_ptr();
+
+                IpProtocol proto = p.get_ip_proto_next();
+
+                if (!(s_pkt_trace->info.proto_match(proto) and
+                        ((s_pkt_trace->info.port_match(sport, dport) and s_pkt_trace->info.ip_match(sip_ptr, dip_ptr)) or
+                        (s_pkt_trace->info.port_match(dport, sport) and s_pkt_trace->info.ip_match(dip_ptr, sip_ptr)))))
+                {
+                    s_pkt_trace->active = false;
+                    return;
+                }
+            }
+            s_pkt_trace->active = true;
+            s_pkt_trace->add_ip_header_info(p);
+        }
+    }
+    else
+        s_pkt_trace->active = false;
+}
+
+// -----------------------------------------------------------------------------
+// non-static functions
+// -----------------------------------------------------------------------------
+
+// constructor
+PacketTracer::PacketTracer()
+{ reason = VERDICT_REASON_NO_BLOCK; }
+
+// destructor
+PacketTracer::~PacketTracer()
+{
+    if ( log_fh && log_fh != stdout )
+    {
+        fclose(log_fh);
+        log_fh = nullptr;
+    }
+}
+
+void PacketTracer::log(const char* format, va_list ap)
+{       
+    // FIXIT-L Need to find way to add 'PktTracerDbg' string as part of format string.
+    std::string dbg_str;
+    if (shell_enabled) // only add debug string during shell execution
+    {
+        dbg_str = "PktTracerDbg "; 
+        if (strcmp(format, "\n") != 0)
+            dbg_str += get_debug_session();
+        dbg_str += format;
+        format = dbg_str.c_str();
+    }
+
+    const int buff_space = max_buff_size - buff_len;
+    const int len = vsnprintf(buffer + buff_len, buff_space, format, ap);
+
+    if (len >= 0 and len < buff_space)
+        buff_len += len;
+    else
+        buff_len = max_buff_size - 1;
+}
+
+void PacketTracer::add_ip_header_info(const Packet& p)
+{
+    SfIpString sipstr;
+    SfIpString dipstr;
+
+    uint16_t sport = p.ptrs.sp;
+    uint16_t dport = p.ptrs.dp;
+
+    const SfIp* actual_sip = p.ptrs.ip_api.get_src();
+    const SfIp* actual_dip = p.ptrs.ip_api.get_dst();
+    
+    IpProtocol proto = p.get_ip_proto_next();
+
+    actual_sip->ntop(sipstr, sizeof(sipstr));
+    actual_dip->ntop(dipstr, sizeof(dipstr));
+
+    if (shell_enabled)
+    {
+        PacketTracer::log("\n");
+        snprintf(debug_session, sizeof(debug_session), "%s %hu -> %s %hu %hhu AS=%hu ID=%u ",
+            sipstr, sport, dipstr, dport, static_cast<uint8_t>(proto),
+            p.pkth->address_space_id, get_instance_id());
+    }
+    else
+    {
+        add_eth_header_info(p);
+        PacketTracer::log("%s:%hu -> %s:%hu proto %u AS=%hu ID=%u\n",
+            sipstr, sport, dipstr, dport, static_cast<uint8_t>(proto),
+            p.pkth->address_space_id, get_instance_id());
+    }
+    add_packet_type_info(p);
+}
+
+void PacketTracer::add_packet_type_info(const Packet& p)
+{
+    bool is_v6 = p.ptrs.ip_api.is_ip6();
+    char timestamp[TIMEBUF_SIZE];
+    ts_print((const struct timeval*)&p.pkth->ts, timestamp);
+
+    switch (p.type())
+    {
+        case PktType::TCP:
+        {
+            char tcpFlags[10];
+            CreateTCPFlagString(p.ptrs.tcph, tcpFlags);
+
+            if (p.ptrs.tcph->th_flags & TH_ACK)
+                PacketTracer::log("Packet: TCP %s, %s, seq %u, ack %u\n", tcpFlags, timestamp,
+                    p.ptrs.tcph->seq(), p.ptrs.tcph->ack());
+            else
+                PacketTracer::log("Packet: TCP %s, %s, seq %u\n", tcpFlags, timestamp, p.ptrs.tcph->seq());
+            break;
+        }
+
+        case PktType::ICMP:
+        {
+            const char* icmp_str = is_v6 ? "ICMPv6" : "ICMP";
+
+            PacketTracer::log("Packet: %s, %s, Type: %u  Code: %u \n", icmp_str, timestamp,
+                p.ptrs.icmph->type, p.ptrs.icmph->code);
+            break;
+        }
+
+        default:
+            PacketTracer::log("Packet: %s, %s\n", p.get_type(), timestamp);
+            break;
+    }
+}
+
+void PacketTracer::add_eth_header_info(const Packet& p)
+{
+    auto eh = layer::get_eth_layer(&p);
+    if (!(shell_enabled) && eh )
+    {
+        // MAC layer
+        PacketTracer::log("%02X:%02X:%02X:%02X:%02X:%02X -> %02X:%02X:%02X:%02X:%02X:%02X %04X\n",
+            eh->ether_src[0], eh->ether_src[1], eh->ether_src[2],
+            eh->ether_src[3], eh->ether_src[4], eh->ether_src[5],
+            eh->ether_dst[0], eh->ether_dst[1], eh->ether_dst[2],
+            eh->ether_dst[3], eh->ether_dst[4], eh->ether_dst[5],
+            (uint16_t)eh->ethertype());
+    }
+}
+
+void PacketTracer::update_constraints(const PTSessionConstraints* constraints)
+{
+
+    char sipstr[INET6_ADDRSTRLEN];
+    char dipstr[INET6_ADDRSTRLEN];
+
+    info.set(*constraints);
+    info.sip.ntop(sipstr, sizeof(sipstr));
+    info.dip.ntop(dipstr, sizeof(dipstr));
+    LogMessage("Debugging packet tracer with %s-%hu and %s-%hu %hhu\n",
+               sipstr, info.sport, dipstr, info.dport, static_cast<uint8_t>(info.protocol));
+
+    shell_enabled = true;
+
+}
+
+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;
+        }
+    }
+}
+
+void PacketTracer::dump_to_daq(const DAQ_PktHdr_t* pkt_hdr)
+{
+    SFDAQ::get_local_instance()->modify_flow_pkt_trace(pkt_hdr, reason,
+        (uint8_t *)buffer, buff_len + 1);
+}
+
+void PacketTracer::reset()
+{
+    buff_len = 0;
+    buffer[0] = '\0';
+    reason = VERDICT_REASON_NO_BLOCK;
+
+    for ( unsigned i = 0; i < mutes.size(); i++ )
+        mutes[i] = false;
+}
+
+// --------------------------------------------------------------------------
+// unit tests
+// --------------------------------------------------------------------------
+
 #ifdef UNIT_TEST
 #include <fcntl.h>
 #include <unistd.h>
@@ -301,11 +446,17 @@ public:
     static unsigned int get_buff_len()
     { return ((TestPacketTracer*)s_pkt_trace)->buff_len; }
 
+    static void set_user_enable(bool status)
+    { ((TestPacketTracer*)s_pkt_trace)->user_enabled = status; }
+
     static bool is_user_enabled()
     { return ((TestPacketTracer*)s_pkt_trace)->user_enabled; }
 
+    static void set_daq_enable(bool status)
+    { ((TestPacketTracer*)s_pkt_trace)->daq_activated = status; }
+
     static bool is_daq_enabled()
-    { return ((TestPacketTracer*)s_pkt_trace)->daq_enabled; }
+    { return ((TestPacketTracer*)s_pkt_trace)->daq_activated; }
 
     static bool is_paused()
     { return ((TestPacketTracer*)s_pkt_trace)->pause_count; }
@@ -331,7 +482,7 @@ TEST_CASE("basic log", "[PacketTracer]")
     char test_str[] = "1234567890";
     // instantiate a packet tracer
     TestPacketTracer::thread_init();
-    TestPacketTracer::enable_user();
+    TestPacketTracer::set_user_enable(true);
     // basic logging
     TestPacketTracer::log("%s", test_str);
     CHECK(!(strcmp(TestPacketTracer::get_buff(), test_str)));
@@ -353,7 +504,7 @@ TEST_CASE("corner cases", "[PacketTracer]")
 {
     char test_str[] = "1234567890", empty_str[] = "";
     TestPacketTracer::thread_init();
-    TestPacketTracer::enable_user();
+    TestPacketTracer::set_user_enable(true);
     // init length check
     CHECK((TestPacketTracer::get_buff_len() == 0));
     // logging empty string to start with
@@ -379,7 +530,7 @@ TEST_CASE("dump", "[PacketTracer]")
     char test_str[] = "ABCD", results[] = "ABCD3=400";
 
     TestPacketTracer::thread_init();
-    TestPacketTracer::enable_user();
+    TestPacketTracer::set_user_enable(true);
     TestPacketTracer::log("%s%d=%d", test_str, 3, 400);
     TestPacketTracer::dump(test_string, TestPacketTracer::max_buff_size);
     CHECK(!strcmp(test_string, results));
@@ -397,21 +548,18 @@ TEST_CASE("enable", "[PacketTracer]")
 {
     TestPacketTracer::thread_init();
     // packet tracer is disabled by default
-    CHECK(!TestPacketTracer::active());
+    CHECK(!TestPacketTracer::is_active());
     // enabled from user
-    TestPacketTracer::enable_user();
-    CHECK(TestPacketTracer::active());
+    TestPacketTracer::set_user_enable(true);
     CHECK(TestPacketTracer::is_user_enabled());
     CHECK(!TestPacketTracer::is_daq_enabled());
     // enabled from DAQ
-    TestPacketTracer::enable_daq();
-    CHECK(TestPacketTracer::active());
+    TestPacketTracer::set_daq_enable(true);
     CHECK(TestPacketTracer::is_daq_enabled());
     // disable DAQ enable
-    TestPacketTracer::disable_daq();
+    TestPacketTracer::set_daq_enable(false);
     CHECK(!TestPacketTracer::is_daq_enabled());
     // user configuration remain enabled
-    CHECK(TestPacketTracer::active());
     CHECK(TestPacketTracer::is_user_enabled());
     
     TestPacketTracer::thread_term();
@@ -422,7 +570,7 @@ TEST_CASE("pause", "[PacketTracer]")
     char test_str[] = "1234567890";
 
     TestPacketTracer::thread_init();
-    TestPacketTracer::enable_user();
+    TestPacketTracer::set_user_enable(true);
     TestPacketTracer::pause();
     TestPacketTracer::pause();
     TestPacketTracer::pause();
@@ -455,7 +603,7 @@ TEST_CASE("pause", "[PacketTracer]")
 TEST_CASE("reasons", "[PacketTracer]")
 {
     TestPacketTracer::thread_init();
-    TestPacketTracer::enable_daq();
+    TestPacketTracer::set_daq_enable(true);
     uint8_t low1 = 100, low2 = 101, high = 102;
     TestPacketTracer::register_verdict_reason(low1, PacketTracer::PRIORITY_LOW);
     TestPacketTracer::register_verdict_reason(low2, PacketTracer::PRIORITY_LOW);
@@ -491,7 +639,7 @@ TEST_CASE("reasons", "[PacketTracer]")
 TEST_CASE("verbosity", "[PacketTracer]")
 {
     TestPacketTracer::thread_init();
-    TestPacketTracer::enable_user();
+    TestPacketTracer::set_user_enable(true);
     PacketTracer::TracerMute mute_1 = TestPacketTracer::get_mute();
     PacketTracer::TracerMute mute_2 = TestPacketTracer::get_mute();
 
similarity index 51%
rename from src/log/packet_tracer.h
rename to src/network_inspectors/packet_tracer/packet_tracer.h
index 3d82a7f7bd3b3d2ceae191ad048a6eacf40e1829..28bec20d5bab358f0bb543fbd45a6fe53408b65b 100644 (file)
 
 #include <cstdarg>
 #include <cstdio>
+#include <cstring>
 #include <daq_common.h>
-#include <string>
 #include <vector>
 
 #include "main/snort_types.h"
+#include "main/thread.h"
+#include "protocols/ipv6.h"
+#include "protocols/protocol_ids.h"
+#include "sfip/sf_ip.h"
+
+// %s %u -> %s %u %u AS=%u ID=%u
+// IPv6 Port -> IPv6 Port Proto AS=ASNum ID=InstanceNum
+#define PT_DEBUG_SESSION_ID_SIZE ((39+1+5+1+2+1+39+1+5+1+3+1+2+1+10+1+2+1+10)+1)
+
+struct PTSessionConstraints
+{
+    snort::SfIp sip;
+    int sip_flag = 0;
+    snort::SfIp dip;
+    int dip_flag = 0;
+    uint16_t sport;
+    uint16_t dport;
+    IpProtocol protocol = IpProtocol::PROTO_NOT_SET;
+
+    bool proto_match(IpProtocol& proto)
+    {
+        return (protocol == IpProtocol::PROTO_NOT_SET or protocol == proto);
+    }
+    bool port_match(uint16_t p1, uint16_t p2)
+    {
+        return (!sport or sport == p1) and (!dport or dport == p2);
+    }
+    bool ip_match(const uint32_t* ip1, const uint32_t* ip2)
+    {
+        return
+            ((!sip_flag or !memcmp(sip.get_ip6_ptr(), ip1, sizeof(snort::ip::snort_in6_addr))) and
+             (!dip_flag or !memcmp(dip.get_ip6_ptr(), ip2, sizeof(snort::ip::snort_in6_addr))));
+    }
+
+    void set(const PTSessionConstraints& src);
+};
+
+inline void PTSessionConstraints::set(const PTSessionConstraints& src)
+{
+    if ((sip_flag = src.sip_flag))
+        sip.set(src.sip);
+    if ((dip_flag = src.dip_flag))
+        dip.set(src.dip);
+    sport = src.sport;
+    dport = src.dport;
+    protocol = src.protocol;
+}
 
 namespace snort
 {
 struct Packet;
+
 class PacketTracer
 {
 public:
@@ -46,9 +94,9 @@ public:
     virtual ~PacketTracer();
 
     typedef uint8_t TracerMute;
-
     static const int max_buff_size = 2048;
 
+    // static functions 
     static void set_log_file(std::string);
     static void thread_init();
     static void thread_term();
@@ -56,17 +104,15 @@ public:
     static void dump(char* output_buff, unsigned int len);
     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 void configure(bool status, const std::string& file_name);
+    static void set_constraints(const PTSessionConstraints* constraints);
+    static void activate(const snort::Packet&);
+    
     static SO_PUBLIC void pause();
     static SO_PUBLIC void unpause();
-
+    static SO_PUBLIC bool is_paused();
+    static SO_PUBLIC bool is_active();
+    
     static SO_PUBLIC TracerMute get_mute();
 
     static SO_PUBLIC void register_verdict_reason(uint8_t reason_code, uint8_t priority);
@@ -75,6 +121,9 @@ public:
     static SO_PUBLIC void log(TracerMute, const char* format, ...) __attribute__((format (printf, 2, 3)));
 
 protected:
+
+
+    // non-static variable
     FILE* log_fh = stdout;
     std::vector<bool> mutes;
     char buffer[max_buff_size];
@@ -83,15 +132,35 @@ protected:
 
     unsigned pause_count = 0;
     bool user_enabled = false;
-    bool daq_enabled = false;
+    bool daq_activated = false;
+    bool shell_enabled = false;
+    bool active = false;
+
+    char debug_session[PT_DEBUG_SESSION_ID_SIZE];
+    PTSessionConstraints info;
+    
+    // static functions
+    template<typename T = PacketTracer> static void _thread_init();
+
+    // non-static functions
+    void log(const char*, va_list);
+    void add_ip_header_info(const snort::Packet&);
+    void add_eth_header_info(const snort::Packet&);
+    void add_packet_type_info(const snort::Packet&);
+    void update_constraints(const PTSessionConstraints* constraints);
+    const char *get_debug_session() { return debug_session; }
 
     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();
 };
-}
 
+SO_PUBLIC extern THREAD_LOCAL PacketTracer* s_pkt_trace;
+
+inline bool PacketTracer::is_active() 
+{ return s_pkt_trace ? s_pkt_trace->active : false; }
+
+}
+  
 #endif
diff --git a/src/network_inspectors/packet_tracer/packet_tracer_module.cc b/src/network_inspectors/packet_tracer/packet_tracer_module.cc
new file mode 100644 (file)
index 0000000..74bb97e
--- /dev/null
@@ -0,0 +1,203 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2018-2018 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// packet_tracer_module.cc author Shashikant Lad <shaslad@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <lua.hpp>
+
+#include "packet_tracer_module.h"
+
+#include "main/snort_config.h"
+#include "profiler/profiler.h"
+#include "main/analyzer_command.h"
+#include "log/messages.h"
+#include "sfip/sf_ip.h"
+
+#include "packet_tracer.h"
+
+using namespace snort;
+
+static int enable(lua_State*);
+static int disable(lua_State*);
+
+static const Parameter s_params[] =
+{
+    {"enable", Parameter::PT_BOOL, nullptr, "false",
+    "enable summary output of state that determined packet verdict"},
+
+    {"output", Parameter::PT_ENUM, "console | file", "console",
+    "select where to send packet trace"},
+
+    {nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr}
+};
+
+static const Parameter enable_packet_tracer_params[] =
+{
+    {"proto", Parameter::PT_INT, nullptr, nullptr, "numerical IP protocol ID filter"},
+    {"src_ip", Parameter::PT_STRING, nullptr, nullptr, "source IP address filter"},
+    {"src_port", Parameter::PT_INT, nullptr, nullptr, "source port filter"},
+    {"dst_ip", Parameter::PT_STRING, nullptr, nullptr, "destination IP address filter"},
+    {"dst_port", Parameter::PT_INT, nullptr, nullptr, "destination port filter"},
+    {nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr}
+};
+
+static const Command packet_tracer_cmds[] =
+{
+    {"enable", enable, enable_packet_tracer_params, "enable packet tracer debugging"},
+    {"disable", disable, nullptr, "disable packet tracer"},
+    {nullptr, nullptr, nullptr, nullptr}
+};
+
+class PacketTracerDebug : public AnalyzerCommand
+{
+  public:
+    PacketTracerDebug(PTSessionConstraints *cs);
+    void execute(Analyzer &) override;
+    const char *stringify() override { return "PACKET_TRACER_DEBUG"; }
+
+  private:
+    PTSessionConstraints constraints = {};
+    bool enable = false;
+};
+
+PacketTracerDebug::PacketTracerDebug(PTSessionConstraints *cs)
+{
+    if (cs)
+    {
+        memcpy(&constraints, cs, sizeof(constraints));
+        enable = true;
+    }
+}
+
+void PacketTracerDebug::execute(Analyzer &)
+{
+    if (enable)
+        PacketTracer::set_constraints(&constraints);
+    else 
+        PacketTracer::set_constraints(nullptr);
+}
+
+static int enable(lua_State* L)
+{
+    int proto = luaL_optint(L, 1, 0);
+    const char *sipstr = luaL_optstring(L, 2, nullptr);
+    int sport = luaL_optint(L, 3, 0);
+    const char *dipstr = luaL_optstring(L, 4, nullptr);
+    int dport = luaL_optint(L, 5, 0);
+
+    SfIp sip, dip;
+    if (sipstr)
+    {
+        if (sip.set(sipstr) != SFIP_SUCCESS)
+            LogMessage("Invalid source IP address provided: %s\n", sipstr);
+    }
+
+    if (dipstr)
+    {
+        if (dip.set(dipstr) != SFIP_SUCCESS)
+            LogMessage("Invalid destination IP address provided: %s\n", dipstr);
+    }
+
+    PTSessionConstraints constraints = {};
+
+    if (proto)
+        constraints.protocol = (IpProtocol)proto;
+
+    if (sip.is_set())
+    {
+        memcpy(&constraints.sip, sip.get_ip6_ptr(), sizeof(constraints.sip));
+        constraints.sip_flag = true;
+    }
+
+    if (dip.is_set())
+    {
+        memcpy(&constraints.dip, dip.get_ip6_ptr(), sizeof(constraints.dip));
+        constraints.dip_flag = true;
+    }
+
+    constraints.sport = sport;
+    constraints.dport = dport;
+
+    main_broadcast_command(new PacketTracerDebug(&constraints));
+    return 0;
+}
+
+static int disable(lua_State*)
+{
+    main_broadcast_command(new PacketTracerDebug(nullptr));
+    return 0;
+}
+
+PacketTracerModule::PacketTracerModule() :
+    Module(PACKET_TRACER_NAME, PACKET_TRACER_HELP, s_params)
+{
+}
+
+
+bool PacketTracerModule::set(const char *, Value &v, SnortConfig*)
+{
+    if ( v.is("enable") )
+        config->enabled = v.get_bool();
+
+    else if ( v.is("output") )
+    {
+        switch ( v.get_long() )
+        {
+            case PACKET_TRACE_CONSOLE:
+                config->file = "-";
+                break;
+
+            case PACKET_TRACE_FILE:
+                config->file = "packet_trace.txt";
+                break;
+
+            default:
+                return false;
+        }
+    }
+    else
+        return false;
+
+    return true;
+}
+
+const Command *PacketTracerModule::get_commands() const
+{
+    return packet_tracer_cmds;
+}
+
+bool PacketTracerModule::begin(const char*, int, SnortConfig*)
+{
+    assert(!config);
+    config = new PacketTracerConfig;
+    return true;
+}
+bool PacketTracerModule::end(const char*, int, SnortConfig*)
+{
+    if (config != nullptr) 
+    {
+        PacketTracer::configure(config->enabled, config->file);
+        delete config;
+        config = nullptr;
+    }
+    return true;
+}
diff --git a/src/network_inspectors/packet_tracer/packet_tracer_module.h b/src/network_inspectors/packet_tracer/packet_tracer_module.h
new file mode 100644 (file)
index 0000000..fec5ca2
--- /dev/null
@@ -0,0 +1,59 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2018-2018 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// packet_tracer_module.h author Shashikant Lad <shaslad@cisco.com>
+
+#ifndef PACKET_TRACER_MODULE_H
+#define PACKET_TRACER_MODULE_H
+
+#include "framework/module.h"
+
+#define PACKET_TRACER_NAME "packet_tracer"
+#define PACKET_TRACER_HELP "generate debug trace messages for packets"
+
+struct PacketTracerConfig
+{
+    bool enabled;
+    std::string file;
+};
+
+class PacketTracerModule : public snort::Module
+{
+public:
+    PacketTracerModule();
+
+
+    enum PacketTraceOutput
+    {
+        PACKET_TRACE_CONSOLE,
+        PACKET_TRACE_FILE
+    };
+
+    const snort::Command* get_commands() const override;
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+    Usage get_usage() const override
+    { return GLOBAL; }
+
+private:
+    PacketTracerConfig* config = nullptr;
+};
+
+#endif