From: Nirmala Venkata Subbaiah -X (nirmvenk - XORIANT CORPORATION at Cisco) Date: Mon, 12 May 2025 22:45:23 +0000 (+0000) Subject: Pull request #4609: stream_tcp: detection of gaps in packet stream X-Git-Tag: 3.8.1.0~14 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=4d0bc2b8b0cfdd7d35209f4e0592b2d1bc239050;p=thirdparty%2Fsnort3.git Pull request #4609: stream_tcp: detection of gaps in packet stream Merge in SNORT/snort3 from ~NIRMVENK/snort3:seglist_hole to master Squashed commit of the following: commit 067ed3b736175cad013725eba8393a26d0a2944c Author: Nirmala Subbaiah Date: Fri Feb 7 13:42:24 2025 -0500 stream: detection of gaps in packet stream --- diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index 1053f2069..db4ea1990 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -121,6 +121,8 @@ const PegInfo tcp_pegs[] = { CountType::SUM, "full_retransmits", "number of fully retransmitted segments" }, { CountType::SUM, "flush_on_asymmetric_flow", "number of flushes on asymmetric flows" }, { CountType::SUM, "asymmetric_flows", "number of completed flows having one-way traffic only" }, + { CountType::SUM, "max_bytes_exceeded_hole", "number of times max bytes were exceeded due to a hole" }, + { CountType::SUM, "max_segs_exceeded_hole", "number of times max segs were exceeded due to a hole" }, { CountType::END, nullptr, nullptr } }; diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index 779935ffd..d6cf39921 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -121,6 +121,8 @@ struct TcpStats PegCount full_retransmits; PegCount flush_on_asymmetric_flow; PegCount asymmetric_flows; + PegCount max_bytes_exceeded_hole; + PegCount max_segs_exceeded_hole; }; extern THREAD_LOCAL struct TcpStats tcpStats; diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index ee4c13f98..3ea775ceb 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -600,7 +600,7 @@ void TcpSession::mark_packet_for_drop(TcpSegmentDescriptor& tsd) bool TcpSession::check_reassembly_queue_thresholds(TcpSegmentDescriptor& tsd, TcpStreamTracker* listener) { // if this packet fits within the current queue limit window then it's good - if( listener->seglist.segment_within_seglist_window(tsd) ) + if ( listener->seglist.segment_within_seglist_window(tsd) ) return false; bool inline_mode = tsd.is_nap_policy_inline(); @@ -613,6 +613,10 @@ bool TcpSession::check_reassembly_queue_thresholds(TcpSegmentDescriptor& tsd, Tc if ( space_left < (int32_t)tsd.get_len() ) { tcpStats.exceeded_max_bytes++; + + if ( is_hole_present(listener, tsd.get_pkt()) ) + tcpStats.max_bytes_exceeded_hole++; + bool ret_val = true; // if this is an asymmetric flow then skip over any seglist holes @@ -651,6 +655,9 @@ bool TcpSession::check_reassembly_queue_thresholds(TcpSegmentDescriptor& tsd, Tc { tcpStats.exceeded_max_segs++; + if ( is_hole_present(listener, tsd.get_pkt()) ) + tcpStats.max_segs_exceeded_hole++; + // if this is an asymmetric flow then skip over any seglist holes // and flush to free up seglist space if ( !tsd.get_pkt()->flow->two_way_traffic() ) @@ -1427,4 +1434,41 @@ void TcpSession::check_for_pseudo_established(Packet* p) } } +bool TcpSession::is_hole_present(TcpStreamTracker* listener, snort::Packet* pkt) +{ + // This function logs detection of hole in IPS mode + if ( listener->get_flush_policy() != STREAM_FLPOLICY_ON_DATA ) + return false; + + auto log_hole_detection = [pkt](const uint32_t leftmost_hole, const uint32_t hole_size) + { + if ( hole_size ) + { + if ( PacketTracer::is_active() ) + PacketTracer::log("stream_tcp: Hole detected at seq %u of size %u bytes\n", \ + leftmost_hole, hole_size); + if ( stream_tcp_trace_enabled && pkt ) + trace_logf(TRACE_WARNING_LEVEL, stream_tcp_trace, DEFAULT_TRACE_OPTION_ID, pkt, \ + "stream_tcp: Hole detected at seq %u of size %u bytes\n", leftmost_hole, hole_size); + return true; + } + return false; + }; + + // Check for hole at the beginning of seglist + if ( SEQ_LT(listener->rcv_nxt, listener->seglist.head->start_seq()) ) + { + auto hole_size = listener->seglist.head->start_seq() - listener->rcv_nxt; + return log_hole_detection(listener->rcv_nxt, hole_size); + } + + if ( listener->seglist.cur_sseg && listener->seglist.cur_sseg->next ) + { + auto leftmost_hole = listener->seglist.cur_sseg->next_seq(); + auto hole_size = listener->seglist.cur_sseg->next->start_seq() - \ + listener->seglist.cur_sseg->next_seq(); + return log_hole_detection(leftmost_hole, hole_size); + } + return false; +} diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index e83939f16..2e4de5705 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -159,6 +159,7 @@ private: void set_packet_header_foo(const TcpSegmentDescriptor&); void update_session_on_server_packet(TcpSegmentDescriptor&); void update_session_on_client_packet(TcpSegmentDescriptor&); + bool is_hole_present(TcpStreamTracker*, snort::Packet*); TcpStateMachine* tsm; bool splitter_init = false;