From: Steve Chew (stechew) Date: Fri, 9 May 2025 00:26:40 +0000 (+0000) Subject: Pull request #4683: packet_io: add trace logs when injecting packets. X-Git-Tag: 3.8.1.0~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ce0356c4d5fb1d95a496244409ef39d3d8071b5;p=thirdparty%2Fsnort3.git Pull request #4683: packet_io: add trace logs when injecting packets. Merge in SNORT/snort3 from ~STECHEW/snort3:inject_trace_logs to master Squashed commit of the following: commit 4aee3268aab234a62231870a3ff8764b463b7948 Author: Steve Chew Date: Wed Apr 2 00:50:04 2025 -0400 packet_io: add trace logs when injecting packets. --- diff --git a/src/flow/test/flow_stubs.h b/src/flow/test/flow_stubs.h index f873d8369..d929409c3 100644 --- a/src/flow/test/flow_stubs.h +++ b/src/flow/test/flow_stubs.h @@ -57,6 +57,7 @@ void PacketTracer::dump_to_daq(Packet*) { } void PacketTracer::reset(bool) { } void PacketTracer::pause() { } void PacketTracer::unpause() { } +bool PacketTracer::is_active() { return false; } namespace layer { diff --git a/src/framework/base_api.h b/src/framework/base_api.h index 4306687da..c2d0b94c8 100644 --- a/src/framework/base_api.h +++ b/src/framework/base_api.h @@ -38,7 +38,7 @@ // 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 diff --git a/src/main/test/distill_verdict_stubs.h b/src/main/test/distill_verdict_stubs.h index 23fa6d349..81a1a4469 100644 --- a/src/main/test/distill_verdict_stubs.h +++ b/src/main/test/distill_verdict_stubs.h @@ -191,6 +191,8 @@ void PacketTracer::log(const char*, ...) { } 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*) { } diff --git a/src/network_inspectors/appid/test/appid_discovery_test.cc b/src/network_inspectors/appid/test/appid_discovery_test.cc index 9ec2591a3..7ef011511 100644 --- a/src/network_inspectors/appid/test/appid_discovery_test.cc +++ b/src/network_inspectors/appid/test/appid_discovery_test.cc @@ -55,6 +55,7 @@ const char* AppIdApi::get_application_name(AppId, OdpContext&) { return NULL; } 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) {} diff --git a/src/packet_io/active.cc b/src/packet_io/active.cc index 5756b229c..66c9b5eef 100644 --- a/src/packet_io/active.cc +++ b/src/packet_io/active.cc @@ -30,6 +30,7 @@ #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" @@ -217,6 +218,49 @@ void Active::thread_term() } //-------------------------------------------------------------------- +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) { @@ -236,10 +280,14 @@ 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 { @@ -252,14 +300,24 @@ void Active::send_reset(Packet* p, EncodeFlags ef) 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"); + } } } } @@ -277,14 +335,24 @@ void Active::send_unreach(Packet* p, UnreachResponse type) 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( @@ -313,10 +381,14 @@ 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 { @@ -327,12 +399,24 @@ uint32_t Active::send_data( { 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; @@ -357,11 +441,15 @@ uint32_t Active::send_data( 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 { @@ -370,6 +458,7 @@ uint32_t Active::send_data( if (maxPayload) { uint32_t toSend; + bool success = true; do { plen = 0; @@ -381,12 +470,17 @@ uint32_t Active::send_data( 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++; @@ -394,6 +488,9 @@ uint32_t Active::send_data( buf += toSend; } while (blen -= toSend); + + if (PacketTracer::is_active()) + add_payload_trace_log(flags, false, success, "send_data", sent); } } } @@ -409,14 +506,24 @@ uint32_t Active::send_data( 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++; @@ -435,10 +542,14 @@ uint32_t Active::send_data( 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 { @@ -449,12 +560,24 @@ uint32_t Active::send_data( { 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"); + } } } @@ -477,14 +600,24 @@ void Active::inject_data( 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); + } } //-------------------------------------------------------------------- diff --git a/src/packet_io/active.h b/src/packet_io/active.h index 2ea0fca16..d51c1dc38 100644 --- a/src/packet_io/active.h +++ b/src/packet_io/active.h @@ -187,6 +187,11 @@ public: 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(); diff --git a/src/packet_io/packet_tracer.cc b/src/packet_io/packet_tracer.cc index 1d3db53d1..d9a4fe907 100644 --- a/src/packet_io/packet_tracer.cc +++ b/src/packet_io/packet_tracer.cc @@ -78,13 +78,11 @@ static constexpr int max_buff_size = 2048; // 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) { diff --git a/src/packet_io/packet_tracer.h b/src/packet_io/packet_tracer.h index aa89208d9..a589393a0 100644 --- a/src/packet_io/packet_tracer.h +++ b/src/packet_io/packet_tracer.h @@ -63,16 +63,8 @@ public: 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(); diff --git a/src/packet_io/test/CMakeLists.txt b/src/packet_io/test/CMakeLists.txt index 777a08e06..55a399a40 100644 --- a/src/packet_io/test/CMakeLists.txt +++ b/src/packet_io/test/CMakeLists.txt @@ -2,3 +2,7 @@ add_cpputest(sfdaq_counters_test SOURCES ../sfdaq_module.cc ) + +add_cpputest(active_packet_trace_test + SOURCES +) diff --git a/src/packet_io/test/active_packet_trace_stubs.h b/src/packet_io/test/active_packet_trace_stubs.h new file mode 100644 index 000000000..3b0c55826 --- /dev/null +++ b/src/packet_io/test/active_packet_trace_stubs.h @@ -0,0 +1,245 @@ +//-------------------------------------------------------------------------- +// 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 + +#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() { } + diff --git a/src/packet_io/test/active_packet_trace_test.cc b/src/packet_io/test/active_packet_trace_test.cc new file mode 100644 index 000000000..4e1f350e2 --- /dev/null +++ b/src/packet_io/test/active_packet_trace_test.cc @@ -0,0 +1,375 @@ +//-------------------------------------------------------------------------- +// 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 + +// ----------------------------------------------------------------------------- +// 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 +#include +#include + +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); +}