void PacketTracer::reset(bool) { }
void PacketTracer::pause() { }
void PacketTracer::unpause() { }
+bool PacketTracer::is_active() { return false; }
namespace layer
{
// depends on includes installed in framework/snort_api.h
// see framework/plugins.h
-#define BASE_API_VERSION 21
+#define BASE_API_VERSION 22
// set the reserved field to this to be future proof
#define API_RESERVED 0
void PacketTracer::dump(Packet*) { }
void PacketTracer::daq_dump(Packet*) { }
void PacketTracer::activate(const Packet&) { }
+bool PacketTracer::is_active() { return false; }
+bool PacketTracer::is_daq_activated() { return false; }
void TraceApi::thread_init(const TraceConfig*) { }
void TraceApi::thread_term() { }
void TraceApi::thread_reinit(const TraceConfig*) { }
void PacketTracer::daq_log(const char*, ...) { }
uint64_t PacketTracer::get_time() { return 0; }
THREAD_LOCAL PacketTracer* PacketTracer::s_pkt_trace = nullptr;
+bool PacketTracer::is_daq_activated() { return false; }
// Stubs for packet
Packet::Packet(bool) {}
#include "main/snort_config.h"
#include "managers/action_manager.h"
#include "profiler/profiler.h"
+#include "packet_io/packet_tracer.h"
#include "protocols/tcp.h"
#include "pub_sub/active_events.h"
#include "stream/stream.h"
}
//--------------------------------------------------------------------
+static void add_trace_log(EncodeFlags ef, bool direct_inject, bool success,
+ const char* prefix, const char* pkt_type, uint32_t payload_len)
+{
+ if ( not prefix or not pkt_type)
+ return;
+
+ bool forward_direction = ef & ENC_FLAG_FWD;
+ const char *direction = "reverse";
+ const char *inject_type = "injection";
+ const char *status = "failed";
+ if ( forward_direction )
+ direction = "forward";
+
+ if ( success )
+ status = "successful";
+
+ if ( direct_inject )
+ inject_type = "direct injection";
+
+ if ( payload_len )
+ PacketTracer::log("%s: %s %s of %s (length %u) in %s direction\n", prefix, status, inject_type, pkt_type, payload_len, direction);
+ else
+ PacketTracer::log("%s: %s %s of %s in %s direction\n", prefix, status, inject_type, pkt_type, direction);
+}
+
+void Active::add_reset_trace_log(EncodeFlags ef, bool direct_inject, bool success, const char* prefix)
+{
+ add_trace_log(ef, direct_inject, success, prefix, "RST packet", 0);
+}
+void Active::add_fin_trace_log(EncodeFlags ef, bool direct_inject, bool success, const char* prefix)
+{
+ add_trace_log(ef, direct_inject, success, prefix, "FIN packet", 0);
+}
+
+void Active::add_unreach_trace_log(EncodeFlags ef, bool direct_inject, bool success, const char* prefix)
+{
+ add_trace_log(ef, direct_inject, success, prefix, "packet unreachable", 0);
+}
+
+void Active::add_payload_trace_log(EncodeFlags ef, bool direct_inject, bool success, const char* prefix, uint32_t payload_len)
+{
+ add_trace_log(ef, direct_inject, success, prefix, "payload packet", payload_len);
+}
void Active::send_reset(Packet* p, EncodeFlags ef)
{
if ( ret != DAQ_SUCCESS )
{
active_counts.failed_direct_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(ef, true, false, "send_reset");
return;
}
active_counts.direct_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(ef, true, true, "send_reset");
}
else
{
if ( !rej )
{
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(ef, false, false, "send_reset failed to encode");
return;
}
int ret = s_send(p->daq_msg, !(ef & ENC_FLAG_FWD), rej, len);
if ( ret )
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(ef, false, false, "send_reset");
+ }
else
+ {
active_counts.injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(ef, false, true, "send_reset");
+ }
}
}
}
if ( !rej )
{
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_unreach_trace_log(flags, false, false, "send_unreach failed to encode");
return;
}
int ret = s_send(p->daq_msg, 1, rej, len);
if ( ret )
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_unreach_trace_log(flags, false, false, "send_unreach");
+ }
else
+ {
active_counts.injects++;
+ if (PacketTracer::is_active())
+ add_unreach_trace_log(flags, false, true, "send_unreach");
+ }
}
uint32_t Active::send_data(
if ( ret != DAQ_SUCCESS )
{
active_counts.failed_direct_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(tmp_flags, true, false, "send_data to originator");
return 0;
}
active_counts.direct_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(tmp_flags, true, true, "send_data to originator");
}
else
{
{
ret = s_send(p->daq_msg, !(tmp_flags & ENC_FLAG_FWD), seg, plen);
if ( ret )
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(tmp_flags, false, false, "send_data to originator");
+ }
else
+ {
active_counts.injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(tmp_flags, false, true, "send_data to originator");
+ }
}
else
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(tmp_flags, false, false, "send_data to originator failed to encode");
+ }
}
}
flags |= ENC_FLAG_SEQ;
if ( ret != DAQ_SUCCESS )
{
active_counts.failed_direct_injects++;
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, true, false, "send_data", blen);
return 0;
}
sent = blen;
active_counts.direct_injects++;
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, true, true, "send_data", blen);
}
else
{
if (maxPayload)
{
uint32_t toSend;
+ bool success = true;
do
{
plen = 0;
if ( !seg )
{
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, false, false, "send_data failed to encode", blen);
return sent;
}
ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
if ( ret )
+ {
active_counts.failed_injects++;
+ success = false;
+ }
else
active_counts.injects++;
buf += toSend;
}
while (blen -= toSend);
+
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, false, success, "send_data", sent);
}
}
}
if ( !seg )
{
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_fin_trace_log(flags, false, false, "send_data failed to encode");
return sent;
}
ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
if ( ret )
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_fin_trace_log(flags, false, false, "send_data");
+ }
else
+ {
active_counts.injects++;
+ if (PacketTracer::is_active())
+ add_fin_trace_log(flags, false, true, "send_data");
+ }
// Sending a FIN requires that we bump the seq by 1.
sent++;
if ( ret != DAQ_SUCCESS )
{
active_counts.failed_direct_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(flags, true, false, "send_data");
return sent;
}
active_counts.direct_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(flags, true, true, "send_data");
}
else
{
{
ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
if ( ret )
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(flags, false, false, "send_data");
+ }
else
+ {
active_counts.injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(flags, false, true, "send_data");
+ }
}
else
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_reset_trace_log(flags, false, false, "send_data failed to encode");
+ }
}
}
if ( !seg )
{
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, false, false, "inject_data failed to encode", blen);
return;
}
int ret = s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
if ( ret )
+ {
active_counts.failed_injects++;
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, false, false, "inject_data", blen);
+ }
else
+ {
active_counts.injects++;
+ if (PacketTracer::is_active())
+ add_payload_trace_log(flags, false, true, "inject_data", blen);
+ }
}
//--------------------------------------------------------------------
const char* get_drop_reason()
{ return drop_reason; }
+ static void add_reset_trace_log(EncodeFlags, bool direct_inject, bool success, const char* prefix);
+ static void add_fin_trace_log(EncodeFlags, bool direct_inject, bool success, const char* prefix);
+ static void add_unreach_trace_log(EncodeFlags, bool direct_inject, bool success, const char* prefix);
+ static void add_payload_trace_log(EncodeFlags, bool direct_inject, bool success, const char* prefix, uint32_t payload_len);
+
private:
static bool open(const char*);
static void close();
// static functions
// -----------------------------------------------------------------------------
-#ifdef _WIN64
bool PacketTracer::is_active()
{ return s_pkt_trace ? s_pkt_trace->active : false; }
bool PacketTracer::is_daq_activated()
{ return s_pkt_trace ? s_pkt_trace->daq_activated : false; }
-#endif
static std::string stringify_tcp_options(const Packet* const pkt)
{
static SO_PUBLIC void unpause();
static SO_PUBLIC bool is_paused();
-#ifdef _WIN64
static SO_PUBLIC bool is_active();
static SO_PUBLIC bool is_daq_activated();
-#else
- static bool is_active()
- { return s_pkt_trace ? s_pkt_trace->active : false; }
-
- static bool is_daq_activated()
- { return s_pkt_trace ? s_pkt_trace->daq_activated : false; }
-#endif
static SO_PUBLIC TracerMute get_mute();
SOURCES
../sfdaq_module.cc
)
+
+add_cpputest(active_packet_trace_test
+ SOURCES
+)
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2025 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.
+//--------------------------------------------------------------------------
+// distill_verdict_stubs.h author Ron Dempster <rdempste@cisco.com>
+
+#include "detection/context_switcher.h"
+#include "detection/detection_buf.h"
+#include "detection/detection_engine.h"
+#include "detection/ips_context.h"
+#include "detection/tag.h"
+#include "file_api/file_service.h"
+#include "filters/detection_filter.h"
+#include "filters/rate_filter.h"
+#include "filters/sfrf.h"
+#include "filters/sfthreshold.h"
+#include "flow/flow_control.h"
+#include "flow/ha.h"
+#include "framework/data_bus.h"
+#include "latency/packet_latency.h"
+#include "latency/rule_latency.h"
+#include "log/messages.h"
+#include "managers/action_manager.h"
+#include "managers/codec_manager.h"
+#include "managers/connector_manager.h"
+#include "managers/event_manager.h"
+#include "managers/inspector_manager.h"
+#include "managers/ips_manager.h"
+#include "managers/module_manager.h"
+#include "main.h"
+#include "main/analyzer.h"
+#include "main/oops_handler.h"
+#include "main/policy.h"
+#include "main/snort_config.h"
+#include "main/swapper.h"
+#include "main/thread_config.h"
+#include "memory/memory_cap.h"
+#include "packet_io/active.h"
+#include "packet_io/packet_tracer.h"
+#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_instance.h"
+#include "packet_io/sfdaq_module.h"
+#include "profiler/profiler_impl.h"
+#include "profiler/time_profiler_defs.h"
+#include "protocols/packet.h"
+#include "protocols/packet_manager.h"
+#include "side_channel/side_channel.h"
+#include "stream/stream.h"
+#include "target_based/host_attributes.h"
+#include "time/packet_time.h"
+#include "trace/trace_api.h"
+#include "utils/dnet_header.h"
+#include "utils/stats.h"
+
+using namespace snort;
+
+THREAD_LOCAL DAQStats daq_stats;
+THREAD_LOCAL bool RuleContext::enabled = false;
+THREAD_LOCAL bool snort::TimeProfilerStats::enabled;
+THREAD_LOCAL snort::PacketTracer* snort::PacketTracer::s_pkt_trace;
+THREAD_LOCAL class FlowControl* flow_con;
+
+void Flow::trust() { }
+void DeferredTrust::finalize(snort::Active&) { }
+SFDAQInstance* SFDAQ::get_local_instance() { return nullptr; }
+
+void Profiler::start() { }
+void Profiler::stop(uint64_t) { }
+void Profiler::consolidate_stats(snort::ProfilerType) { }
+void Swapper::apply(Analyzer&) { }
+Swapper::~Swapper() = default;
+void OopsHandler::tinit() { }
+void OopsHandler::tterm() { }
+void OopsHandler::set_current_message(DAQ_Msg_h, snort::SFDAQInstance*) { }
+uint16_t get_run_num() { return 0; }
+void set_run_num(uint16_t) { }
+void set_instance_id(unsigned) { }
+void set_thread_type(SThreadType) { }
+void ContextSwitcher::push(snort::IpsContext*) { }
+void ContextSwitcher::stop() { }
+ContextSwitcher::~ContextSwitcher() = default;
+snort::IpsContext* ContextSwitcher::get_context() const { return nullptr; }
+void ContextSwitcher::start() { }
+void InitTag() { }
+void CleanupTag() { }
+void RateFilter_Cleanup() { }
+int sfthreshold_alloc(unsigned int, unsigned int) { return -1; }
+void sfthreshold_reset() { }
+void sfthreshold_free() { }
+void EventTrace_Init() { }
+void EventTrace_Term() { }
+void detection_filter_init(DetectionFilterConfig*) { }
+void detection_filter_term() { }
+void RuleLatency::tterm() { }
+void rule_latency::set_force_enable(bool) { }
+void PacketLatency::tterm() { }
+void packet_latency::set_force_enable(bool) { }
+void ConnectorManager::thread_init() { }
+void ConnectorManager::thread_reinit() { }
+void ConnectorManager::thread_term() { }
+void SideChannelManager::thread_init() { }
+void SideChannelManager::thread_term() { }
+void CodecManager::thread_init() { }
+void CodecManager::thread_term() { }
+void EventManager::open_outputs() { }
+void EventManager::close_outputs() { }
+void EventManager::reload_outputs() { }
+void IpsManager::setup_options(const snort::SnortConfig*) { }
+void IpsManager::clear_options(const snort::SnortConfig*) { }
+void ActionManager::thread_init(const snort::SnortConfig*) { }
+void ActionManager::thread_term() { }
+void ActionManager::thread_reinit(const snort::SnortConfig*) { }
+int SFRF_Alloc(unsigned int) { return -1; }
+void packet_time_update(const struct timeval*) { }
+void main_poke(unsigned) { }
+void set_default_policy(const snort::SnortConfig*) { }
+bool snort_ignore(snort::Packet*) { return false; }
+ip_t* ip_open() { return nullptr; }
+ip_t* ip_close(ip_t*) { return nullptr; }
+ssize_t ip_send(ip_t*, const void*, size_t) { return -1; }
+eth_t* eth_open(const char*) { return nullptr; }
+eth_t* eth_close(eth_t*) { return nullptr; }
+ssize_t eth_send(eth_t*, const void*, size_t) { return -1; }
+void HostAttributesManager::initialize() { }
+
+void select_default_policy(const _daq_pkt_hdr&, const snort::SnortConfig*) { }
+void select_default_policy(const _daq_flow_stats&, const snort::SnortConfig*) { }
+
+namespace snort
+{
+static struct timeval s_packet_time = { 0, 0 };
+THREAD_LOCAL PacketCount pc;
+
+void packet_gettimeofday(struct timeval* tv) { *tv = s_packet_time; }
+MemoryContext::MemoryContext(MemoryTracker&) : saved(nullptr) { }
+MemoryContext::~MemoryContext() = default;
+Packet::Packet(bool)
+{
+ memset((char*) this , 0, sizeof(*this));
+ ip_proto_next = IpProtocol::PROTO_NOT_SET;
+ packet_flags = PKT_FROM_CLIENT;
+}
+Packet::~Packet() = default;
+IpsPolicy* get_ips_policy() { return nullptr; }
+void DataBus::publish(unsigned, unsigned, Packet*, Flow*) { }
+void DataBus::publish(unsigned, unsigned, DataEvent&, Flow*) { }
+void DataBus::publish_to_all_network_policies(unsigned int, unsigned int) { }
+SFDAQInstance::SFDAQInstance(const char*, unsigned, const SFDAQConfig*) { }
+SFDAQInstance::~SFDAQInstance() = default;
+void SFDAQInstance::reload() { }
+bool SFDAQInstance::start() { return false; }
+bool SFDAQInstance::stop() { return false; }
+const char* SFDAQInstance::get_error() { return nullptr; }
+bool SFDAQInstance::interrupt() { return false; }
+int SFDAQInstance::inject(DAQ_Msg_h, int, const uint8_t*, uint32_t) { return -1; }
+DAQ_RecvStatus SFDAQInstance::receive_messages(unsigned) { return DAQ_RSTAT_ERROR; }
+void SFDAQ::set_local_instance(SFDAQInstance*) { }
+const char* SFDAQ::verdict_to_string(DAQ_Verdict) { return nullptr; }
+bool SFDAQ::forwarding_packet(const DAQ_PktHdr_t*) { return false; }
+bool SFDAQ::can_inject() { return false; }
+bool SFDAQ::can_inject_raw() { return false; }
+bool SFDAQ::can_replace() { return false; }
+int SFDAQInstance::set_packet_verdict_reason(DAQ_Msg_h, uint8_t) { return 0; }
+DetectionEngine::DetectionEngine() { context = nullptr; }
+DetectionEngine::~DetectionEngine() = default;
+void DetectionEngine::onload() { }
+void DetectionEngine::thread_init() { }
+void DetectionEngine::thread_term() { }
+void DetectionEngine::idle() { }
+void DetectionEngine::reset() { }
+void DetectionEngine::wait_for_context() { }
+void DetectionEngine::set_file_data(const DataPointer&) { }
+void DetectionEngine::set_file_data(const DataPointer&, uint64_t, bool, bool) { }
+void DetectionEngine::clear_replacement() { }
+void DetectionEngine::disable_all(Packet*) { }
+unsigned get_instance_id() { return 0; }
+const SnortConfig* SnortConfig::get_conf() { return nullptr; }
+void SnortConfig::update_thread_reload_id() { }
+void PacketTracer::thread_init() { }
+void PacketTracer::thread_term() { }
+void PacketTracer::dump(Packet*) { }
+void PacketTracer::daq_dump(Packet*) { }
+void PacketTracer::activate(const Packet&) { }
+void TraceApi::thread_init(const TraceConfig*) { }
+void TraceApi::thread_term() { }
+void TraceApi::thread_reinit(const TraceConfig*) { }
+void PacketManager::thread_init() { }
+void PacketManager::decode(
+ Packet*, const DAQ_PktHdr_t*, const uint8_t*, uint32_t, bool, bool) { }
+void PacketManager::encode_update(Packet*) { }
+void PacketManager::thread_term() { }
+void FileService::thread_init() { }
+void FileService::thread_term() { }
+void ErrorMessage(const char*,...) { }
+void LogMessage(const char*,...) { }
+[[noreturn]] void FatalError(const char*,...) { exit(-1); }
+void ParseWarning(WarningGroup, const char*, ...) { }
+void HighAvailabilityManager::thread_init() { }
+void HighAvailabilityManager::process_receive() { }
+void HighAvailabilityManager::thread_term() { }
+void HighAvailabilityManager::thread_term_beginning() { }
+void HighAvailabilityManager::process_update(Flow*, Packet*) { }
+void InspectorManager::thread_init(const SnortConfig*) { }
+void InspectorManager::thread_term() { }
+void InspectorManager::thread_stop(const SnortConfig*) { }
+void InspectorManager::thread_reinit(const SnortConfig*) { }
+void InspectorManager::thread_stop_removed(const SnortConfig*) { }
+void ModuleManager::accumulate(const char*) { }
+void ModuleManager::accumulate_module(const char*) { }
+void Stream::handle_timeouts(bool) { }
+void Stream::purge_flows() { }
+bool Stream::set_packet_action_to_hold(Packet*) { return false; }
+void Stream::init_active_response(const Packet*, Flow*) { }
+void Stream::drop_flow(const Packet* ) { }
+void Stream::block_flow(const Packet*) { }
+IpsContext::IpsContext(unsigned) { }
+NetworkPolicy* get_network_policy() { return nullptr; }
+InspectionPolicy* get_inspection_policy() { return nullptr; }
+Flow::~Flow() = default;
+bool Flow::handle_allowlist() { return true; }
+void ThreadConfig::implement_thread_affinity(SThreadType, unsigned) { }
+void ThreadConfig::apply_thread_policy(SThreadType , unsigned ) { }
+void ThreadConfig::set_instance_tid(int) { }
+void populate_instance_maps() { }
+void invalidate_instance_maps() { }
+}
+
+bool FlowControl::move_to_allowlist(snort::Flow*) { return true; }
+void memory::MemoryCap::thread_init() { }
+void memory::MemoryCap::thread_term() { }
+void memory::MemoryCap::free_space() { }
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2025-2025 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.
+//--------------------------------------------------------------------------
+// active_packet_trace_test.cc author Steve Chew <stechew@cisco.com>
+
+// -----------------------------------------------------------------------------
+// unit tests
+// -----------------------------------------------------------------------------
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../active.cc"
+#include "active_packet_trace_stubs.h"
+#include "packet_io/active.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+using namespace snort;
+
+const int BUFFER_SIZE = 2048;
+char log_buffer[BUFFER_SIZE] = {};
+bool direct_inject_failed = false;
+bool daq_inject_failed = false;
+bool encode_failed = false;
+bool encode_unreach_failed = false;
+uint8_t encode_buf[BUFFER_SIZE];
+uint16_t max_payload = 0;
+
+void CHECK_STR(const char* str)
+{
+ int failed = strcmp(log_buffer, str);
+ if (failed)
+ {
+ printf("String comparison failed...\n"
+ "Expected: %s"
+ "Actual : %s", str, log_buffer);
+ }
+ log_buffer[0] = '\0'; // Must set to zero-length string before reuse
+
+ CHECK(not failed);
+}
+
+bool snort::PacketTracer::is_active() { return true; }
+uint16_t PacketManager::encode_get_max_payload(const Packet*) { return max_payload; }
+
+// Override log to write to a buffer instead so we can check the result.
+void PacketTracer::log(const char* format, ...)
+{
+ size_t len = strlen(log_buffer);
+
+ va_list args;
+ va_start(args, format);
+ vsnprintf(&log_buffer[len], BUFFER_SIZE, format, args);
+ va_end(args);
+}
+
+int SFDAQInstance::ioctl(DAQ_IoctlCmd, void*, size_t)
+{
+ if (direct_inject_failed)
+ return -1;
+
+ return DAQ_SUCCESS;
+}
+
+int SFDAQ::inject(DAQ_Msg_h, int, const uint8_t*, uint32_t)
+{
+ if (daq_inject_failed)
+ return -1;
+
+ return DAQ_SUCCESS;
+}
+
+const uint8_t* PacketManager::encode_response(TcpResponse, EncodeFlags, const Packet*, uint32_t&,
+ const uint8_t* const, uint32_t)
+{
+ if (encode_failed)
+ return nullptr;
+
+ return encode_buf;
+}
+
+const uint8_t* PacketManager::encode_reject(UnreachResponse, EncodeFlags, const Packet*, uint32_t&)
+{
+ if (encode_unreach_failed)
+ return nullptr;
+
+ return encode_buf;
+}
+
+TEST_GROUP(active_packet_trace)
+{
+ void setup() {
+ direct_inject_failed = false;
+ daq_inject_failed = false;
+ encode_failed = false;
+ encode_unreach_failed = false;
+ max_payload = 0;
+ }
+
+ void teardown() {
+ }
+};
+
+TEST(active_packet_trace, check_send_reset)
+{
+ EncodeFlags ef = ENC_FLAG_FWD;
+ Packet pkt;
+ Flow flow;
+ Active active;
+ pkt.flow = &flow;
+ pkt.active = &active;
+ s_attempts = 1;
+
+ // Direct inject cases.
+ pkt.packet_flags = PKT_USE_DIRECT_INJECT;
+ direct_inject_failed = true;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: failed direct injection of RST packet in forward direction\n");
+
+ ef = 0;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: failed direct injection of RST packet in reverse direction\n");
+
+ direct_inject_failed = false;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: successful direct injection of RST packet in reverse direction\n");
+
+ ef = ENC_FLAG_FWD;
+ direct_inject_failed = false;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: successful direct injection of RST packet in forward direction\n");
+
+
+ // DAQ inject cases
+ pkt.packet_flags &= ~PKT_USE_DIRECT_INJECT;
+
+ daq_inject_failed = true;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: failed injection of RST packet in forward direction\n");
+
+ ef = 0;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: failed injection of RST packet in reverse direction\n");
+
+ daq_inject_failed = false;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: successful injection of RST packet in reverse direction\n");
+
+ ef = ENC_FLAG_FWD;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset: successful injection of RST packet in forward direction\n");
+
+
+ // Encoding failure cases
+ encode_failed = true;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset failed to encode: failed injection of RST packet in forward direction\n");
+
+ ef = 0;
+ pkt.active->send_reset(&pkt, ef);
+ CHECK_STR("send_reset failed to encode: failed injection of RST packet in reverse direction\n");
+}
+
+TEST(active_packet_trace, check_send_unreach)
+{
+ Packet pkt;
+ Flow flow;
+ Active active;
+ pkt.flow = &flow;
+ pkt.active = &active;
+ s_attempts = 1;
+
+ pkt.active->send_unreach(&pkt, snort::UnreachResponse::FWD);
+ CHECK_STR("send_unreach: successful injection of packet unreachable in reverse direction\n");
+
+ daq_inject_failed = true;
+ pkt.active->send_unreach(&pkt, snort::UnreachResponse::FWD);
+ CHECK_STR("send_unreach: failed injection of packet unreachable in reverse direction\n");
+
+ encode_unreach_failed = true;
+ pkt.active->send_unreach(&pkt, snort::UnreachResponse::FWD);
+ CHECK_STR("send_unreach failed to encode: failed injection of packet unreachable in reverse direction\n");
+}
+
+TEST(active_packet_trace, check_send_data)
+{
+ EncodeFlags ef = ENC_FLAG_FWD;
+ Packet pkt;
+ Flow flow;
+ Active active;
+ pkt.flow = &flow;
+ pkt.active = &active;
+ s_attempts = 1;
+
+ // Direct inject cases with no RSTs.
+ pkt.packet_flags = PKT_USE_DIRECT_INJECT;
+ direct_inject_failed = true;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: failed direct injection of payload packet (length 2048) in forward direction\n");
+
+ ef = 0;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: failed direct injection of payload packet (length 2048) in reverse direction\n");
+
+ direct_inject_failed = false;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: successful direct injection of payload packet (length 2048) in reverse direction\n");
+
+ ef = ENC_FLAG_FWD;
+ direct_inject_failed = false;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: successful direct injection of payload packet (length 2048) in forward direction\n");
+
+
+ // Direct inject cases with client and server RSTs
+ ef = ENC_FLAG_FWD | ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+
+ direct_inject_failed = true;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: failed direct injection of RST packet in reverse direction\n");
+
+ ef = ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: failed direct injection of RST packet in forward direction\n");
+
+ direct_inject_failed = false;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: successful direct injection of RST packet in forward direction\n"
+ "send_data: successful direct injection of payload packet (length 2048) in reverse direction\n"
+ "send_data: successful direct injection of RST packet in reverse direction\n"
+ );
+
+ ef = ENC_FLAG_FWD | ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+ direct_inject_failed = false;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: successful direct injection of RST packet in reverse direction\n"
+ "send_data: successful direct injection of payload packet (length 2048) in forward direction\n"
+ "send_data: successful direct injection of RST packet in forward direction\n"
+ );
+
+
+ // DAQ inject cases with no RSTs.
+ pkt.packet_flags &= ~PKT_USE_DIRECT_INJECT;
+ ef = ENC_FLAG_FWD;
+
+ // Testing FIN sends (max_payload = 0)
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: successful injection of FIN packet in forward direction\n");
+
+ ef = 0;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: successful injection of FIN packet in reverse direction\n");
+
+ // Testing FIN sends (max_payload = 1000)
+ max_payload = 1000;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: successful injection of payload packet (length 2048) in reverse direction\n"
+ "send_data: successful injection of FIN packet in reverse direction\n"
+ );
+
+ ef = ENC_FLAG_FWD;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data: successful injection of payload packet (length 2048) in forward direction\n"
+ "send_data: successful injection of FIN packet in forward direction\n"
+ );
+
+ // Testing FIN encoding failure.
+ encode_failed = true;
+ max_payload = 0;
+
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data failed to encode: failed injection of FIN packet in forward direction\n");
+
+ ef = 0;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data failed to encode: failed injection of FIN packet in reverse direction\n");
+
+
+ // Testing server RST encoding failure.
+ ef = ENC_FLAG_RST_SRVR;
+ encode_failed = true;
+
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator failed to encode: failed injection of RST packet in forward direction\n"
+ "send_data failed to encode: failed injection of FIN packet in reverse direction\n"
+ );
+
+ ef = 0;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data failed to encode: failed injection of FIN packet in reverse direction\n");
+
+ // Testing DAQ inject with client and server RSTs.
+ ef = ENC_FLAG_FWD | ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+ encode_failed = false;
+ max_payload = 1000;
+
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: successful injection of RST packet in reverse direction\n"
+ "send_data: successful injection of payload packet (length 2048) in forward direction\n"
+ "send_data: successful injection of FIN packet in forward direction\n"
+ "send_data: successful injection of RST packet in forward direction\n"
+ );
+
+ ef = ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: successful injection of RST packet in forward direction\n"
+ "send_data: successful injection of payload packet (length 2048) in reverse direction\n"
+ "send_data: successful injection of FIN packet in reverse direction\n"
+ "send_data: successful injection of RST packet in reverse direction\n"
+ );
+
+ daq_inject_failed = true;
+ ef = ENC_FLAG_FWD | ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: failed injection of RST packet in reverse direction\n"
+ "send_data: failed injection of payload packet (length 2048) in forward direction\n"
+ "send_data: failed injection of FIN packet in forward direction\n"
+ "send_data: failed injection of RST packet in forward direction\n"
+ );
+
+ daq_inject_failed = true;
+ ef = ENC_FLAG_RST_CLNT | ENC_FLAG_RST_SRVR;
+ pkt.active->send_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("send_data to originator: failed injection of RST packet in forward direction\n"
+ "send_data: failed injection of payload packet (length 2048) in reverse direction\n"
+ "send_data: failed injection of FIN packet in reverse direction\n"
+ "send_data: failed injection of RST packet in reverse direction\n"
+ );
+
+}
+
+TEST(active_packet_trace, check_inject_data)
+{
+ EncodeFlags ef = ENC_FLAG_FWD;
+ Packet pkt;
+ Flow flow;
+ Active active;
+ pkt.flow = &flow;
+ pkt.active = &active;
+ s_attempts = 1;
+
+ pkt.active->inject_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("inject_data: successful injection of payload packet (length 2048) in forward direction\n");
+
+ daq_inject_failed = true;
+ pkt.active->inject_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("inject_data: failed injection of payload packet (length 2048) in forward direction\n");
+
+ encode_failed = true;
+ pkt.active->inject_data(&pkt, ef, encode_buf, BUFFER_SIZE);
+ CHECK_STR("inject_data failed to encode: failed injection of payload packet (length 2048) in forward direction\n");
+}
+
+int main(int argc, char** argv)
+{
+ return CommandLineTestRunner::RunAllTests(argc, argv);
+}