]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4609: stream_tcp: detection of gaps in packet stream
authorNirmala Venkata Subbaiah -X (nirmvenk - XORIANT CORPORATION at Cisco) <nirmvenk@cisco.com>
Mon, 12 May 2025 22:45:23 +0000 (22:45 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Mon, 12 May 2025 22:45:23 +0000 (22:45 +0000)
Merge in SNORT/snort3 from ~NIRMVENK/snort3:seglist_hole to master

Squashed commit of the following:

commit 067ed3b736175cad013725eba8393a26d0a2944c
Author: Nirmala Subbaiah <nirmvenk@cisco.com>
Date:   Fri Feb 7 13:42:24 2025 -0500

    stream: detection of gaps in packet stream

src/stream/tcp/tcp_module.cc
src/stream/tcp/tcp_module.h
src/stream/tcp/tcp_session.cc
src/stream/tcp/tcp_session.h

index 1053f206931ece68155cf65bc12c0f9020ab1ef1..db4ea19908947013c1abd6f1423912bd53bcaa34 100644 (file)
@@ -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 }
 };
 
index 779935ffd906be0a2051a34b245a07c5d52593f5..d6cf39921cac133894f917bbc08f2b700e24a4f9 100644 (file)
@@ -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;
index ee4c13f98cca128211d8e0b97698de6432b140d3..3ea775ceb40403b7d755e93fb6a5a3209a39a405 100644 (file)
@@ -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;
+}
index e83939f161663b66fc34c2167a2c514b2ecb0a10..2e4de570579b401f00df8ef5fc2ebccefd3e2c71 100644 (file)
@@ -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;