]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4741: stream_tcp: fix issues with skipping seglist holes in ids mode
authorDavis McPherson -X (davmcphe - XORIANT CORPORATION at Cisco) <davmcphe@cisco.com>
Fri, 8 Aug 2025 19:48:11 +0000 (19:48 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Fri, 8 Aug 2025 19:48:11 +0000 (19:48 +0000)
Merge in SNORT/snort3 from ~DAVMCPHE/snort3:ids_skip_seglist_holes_fix to master

Squashed commit of the following:

commit 3590f4bed9550af66f9260739fd66bf218146c3f
Author: davis mcpherson <davmcphe@cisco.com>
Date:   Sun May 11 17:59:09 2025 -0400

    stream_tcp: fix issues with skipping seglist holes in ids mode

    stream_tcp: add splitter restart function, restart when hole skipped by AtomSplitter

    stream_tcp: when reassembly is disable/ignored update rcv_nxt to left edge of first hole or to end of seglist
                if no holes on each received data segment

commit 8c00c0a46628f4d5240478029530cb5227152f26
Author: davis mcpherson <davmcphe@cisco.com>
Date:   Fri Jun 13 08:11:19 2025 -0400

    snort3: add build directory and vscode workspace config file to git ignore list

14 files changed:
.gitignore
src/stream/stream_splitter.cc
src/stream/stream_splitter.h
src/stream/tcp/tcp_module.cc
src/stream/tcp/tcp_module.h
src/stream/tcp/tcp_reassembler.cc
src/stream/tcp/tcp_reassembler.h
src/stream/tcp/tcp_reassembler_ids.cc
src/stream/tcp/tcp_reassembler_ids.h
src/stream/tcp/tcp_reassembly_segments.cc
src/stream/tcp/tcp_segment_node.h
src/stream/tcp/tcp_session.cc
src/stream/tcp/tcp_stream_tracker.cc
src/stream/tcp/tcp_stream_tracker.h

index 67c8fc52a1c37903a133095e57d2c23033a9f32b..f61a288682ce87e52ae93d86a85203b78d040698 100644 (file)
@@ -57,3 +57,8 @@ build.env
 coverage.info
 coverage.txt
 src/uncovered.txt
+build/
+
+# vscode config
+snort3.code-workspace
+
index dc98fbd6e403b16e993da8373fea7b922558bd3b..312034bc089bc3476abc90ef1bff8005b3267b6f 100644 (file)
@@ -98,6 +98,12 @@ StreamSplitter::Status AtomSplitter::scan(
     return SEARCH;
 }
 
+bool AtomSplitter::restart()
+{ 
+    reset();
+    return true;
+}
+
 void AtomSplitter::reset()
 {  segs = bytes_scanned = 0; }
 
index d23820cc520d926bd106f28f0130cbc1dee75594..5b446d8144d3d48595f0d4b9f071ab8f6aedeb09 100644 (file)
@@ -80,6 +80,7 @@ public:
         unsigned& copied       // actual data copied (1 <= copied <= len)
         );
 
+    virtual bool restart() { return false; }
     virtual bool sync_on_start() const { return false; }
     virtual bool is_paf() { return false; }
     virtual unsigned max(Flow* = nullptr);
@@ -107,6 +108,8 @@ public:
 
     Status scan(Packet*, const uint8_t*, uint32_t, uint32_t, uint32_t*) override;
 
+    bool restart() override;
+
 private:
     void reset();
 
index ac2567d437da8bce2aae1d027ca5c31a9820de26..63e83fc70e255e523922c7e15c2d3ecee371551d 100644 (file)
@@ -115,6 +115,7 @@ const PegInfo tcp_pegs[] =
     { CountType::SUM, "partial_flush_bytes", "partial flush total bytes" },
     { CountType::SUM, "inspector_fallbacks", "count of fallbacks from assigned service inspector" },
     { CountType::SUM, "partial_fallbacks", "count of fallbacks from assigned service stream splitter" },
+    { CountType::SUM, "splitter_restarts", "count of splitter restarts from skipping seglist holes" },
     { CountType::MAX, "max_segs", "maximum number of segments queued in any flow" },
     { CountType::MAX, "max_bytes", "maximum number of bytes queued in any flow" },
     { CountType::SUM, "zero_len_tcp_opt", "number of zero length tcp options" },
index 7bcaccd2ea82d7003c2519547a3953c7a0ef46f2..5d7b3814d5de5523c6ef32f276e65ddeb8fd5631 100644 (file)
@@ -113,6 +113,7 @@ struct TcpStats
     PegCount partial_flush_bytes;
     PegCount inspector_fallbacks;
     PegCount partial_fallbacks;
+    PegCount splitter_restarts;
     PegCount max_segs;
     PegCount max_bytes;
     PegCount zero_len_tcp_opt;
index 6b2df0fd5f411543e6ae529469ff461ce4c2464f..51ab31c8e52ff67886b26db68abc7ae2bf72268d 100644 (file)
@@ -80,26 +80,6 @@ bool TcpReassemblerBase::fin_acked_no_gap(const TcpSegmentNode& tsn)
         and SEQ_GEQ(tsn.next_seq(), tracker.get_fin_i_seq());
 }
 
-// If we are skipping seglist hole, update tsn so that we can purge
-void TcpReassemblerBase::update_skipped_bytes(uint32_t remaining_bytes)
-{
-    TcpSegmentNode* tsn;
-
-    while ( remaining_bytes and (tsn = seglist.cur_rseg) )
-    {
-        auto bytes_skipped = ( tsn->unscanned() <= remaining_bytes ) ? tsn->unscanned() : remaining_bytes;
-
-        remaining_bytes -= bytes_skipped;
-        tsn->advance_cursor(bytes_skipped);
-
-        if ( !tsn->unscanned() )
-        {
-            seglist.flush_count++;
-            seglist.update_next(tsn);
-        }
-    }
-}
-
 void TcpReassemblerBase::purge_to_seq(uint32_t flush_seq)
 {
     seglist.purge_flushed_segments(flush_seq);
@@ -192,9 +172,8 @@ int TcpReassemblerBase::flush_data_segments(uint32_t flush_len, Packet* pdu)
 
         /* Check for a gap/missing packet */
         // FIXIT-L FIN may be in to_seq causing bogus gap counts.
-        if ( tsn->is_packet_missing(to_seq) or paf.state == StreamSplitter::SKIP )
+        if ( tsn->is_packet_missing(to_seq) )
         {
-            // FIXIT-H // assert(false); find when this scenario happens
             // FIXIT-L this is suboptimal - better to exclude fin from to_seq
             if ( !tracker.is_fin_seq_set() or
                 SEQ_LEQ(to_seq, tracker.get_fin_final_seq()) )
@@ -208,9 +187,6 @@ int TcpReassemblerBase::flush_data_segments(uint32_t flush_len, Packet* pdu)
             break;
     }
 
-    if ( paf.state == StreamSplitter::SKIP )
-        update_skipped_bytes(remaining_bytes);
-
     return total_flushed;
 }
 
@@ -567,17 +543,6 @@ void TcpReassemblerBase::flush_queued_segments(Flow* flow, bool clear, Packet* p
     }
 }
 
-
-void TcpReassemblerBase::check_first_segment_hole()
-{
-    if ( SEQ_LT(seglist.seglist_base_seq, seglist.head->start_seq()) )
-    {
-        seglist.seglist_base_seq = seglist.head->start_seq();
-        seglist.advance_rcv_nxt();
-        paf.state = StreamSplitter::START;
-    }
-}
-
 uint32_t TcpReassemblerBase::perform_partial_flush(Flow* flow, Packet*& p)
 {
     p = get_packet(flow, packet_dir, server_side);
index b69bdfab3ca53427e76cb42ce410884f274aff0b..3d82610d217e0393920e3f0d5f47982f6c957fdc 100644 (file)
@@ -208,8 +208,6 @@ protected:
 
     bool fin_no_gap(const TcpSegmentNode&);
     bool fin_acked_no_gap(const TcpSegmentNode&);
-    void update_skipped_bytes(uint32_t);
-    void check_first_segment_hole();
     uint32_t perform_partial_flush(snort::Packet*);
     bool final_flush_on_fin(int32_t flush_amt, snort::Packet*, FinSeqNumStatus);
     bool asymmetric_flow_flushed(uint32_t flushed, snort::Packet *p);
index c60005ac92124df995cf72c11b4ed22eff1d4e27..5520c7e5ae4d59d23e3146947809ed0eb728151e 100644 (file)
 
 using namespace snort;
 
-bool TcpReassemblerIds::has_seglist_hole(TcpSegmentNode& tsn, uint32_t& total, uint32_t& flags)
-{
-    if ( !tsn.prev or SEQ_GEQ(tsn.prev->scan_seq() + tsn.prev->unscanned(), tsn.scan_seq())
-       or SEQ_GEQ(tsn.scan_seq(), tracker.r_win_base) )
-    {
-       check_first_segment_hole();
-       return false;
-    }
-
-    // safety - prevent seq + total < seq
-    if ( total > 0x7FFFFFFF )
-        total = 0x7FFFFFFF;
-
-    if ( !paf.tot )
-        flags |= PKT_PDU_HEAD;
-
-    paf.state = StreamSplitter::SKIP;
-    return true;
-}
-
-void TcpReassemblerIds::skip_seglist_hole(Packet* p, uint32_t flags, int32_t flush_amt)
-{
-    if ( is_splitter_paf() )
-    {
-        if ( flush_amt > 0 )
-            update_skipped_bytes(flush_amt);
-        tracker.fallback();
-    }
-    else
-    {
-        if ( flush_amt > 0 )
-            flush_to_seq(flush_amt, p, flags);
-        paf.state = StreamSplitter::START;
-    }
-
-    if ( seglist.head )
-    {
-        if ( flush_amt > 0 )
-            purge_to_seq(seglist.seglist_base_seq + flush_amt);
-        seglist.seglist_base_seq = seglist.head->scan_seq();
-    }
-    else
-        seglist.seglist_base_seq = tracker.r_win_base;  // FIXIT-H - do we need to set rcv_nxt here?
-
-    seglist.cur_rseg = seglist.head;
-    tracker.set_order(TcpStreamTracker::OUT_OF_SEQUENCE);
-}
-
 // iterate over seglist and scan all new acked bytes
 // - new means not yet scanned
 // - must use seglist data (not packet) since this packet may plug a
@@ -108,12 +60,7 @@ void TcpReassemblerIds::skip_seglist_hole(Packet* p, uint32_t flags, int32_t flu
 //   know where we left off and can resume scanning the remainder
 int32_t TcpReassemblerIds::scan_data_post_ack(uint32_t* flags, Packet* p)
 {
-    assert(seglist.session->flow == p->flow);
-
-    int32_t ret_val = FINAL_FLUSH_HOLD;
-
-    if ( !seglist.cur_sseg || SEQ_GEQ(seglist.seglist_base_seq, tracker.r_win_base) )
-        return ret_val ;
+    assert( seglist.cur_sseg );
 
     if ( !seglist.cur_rseg )
         seglist.cur_rseg = seglist.cur_sseg;
@@ -126,21 +73,32 @@ int32_t TcpReassemblerIds::scan_data_post_ack(uint32_t* flags, Packet* p)
         if ( SEQ_EQ(end_seq, paf.paf_position()) )
         {
             total = end_seq - seglist.seglist_base_seq;
-            tsn = tsn->next;
+            if ( tsn->next_no_gap() )
+                tsn = tsn->next;
+            else if ( tsn->next )
+            {
+                if ( SEQ_GT(tracker.r_win_base, tsn->next->start_seq()) 
+                     or SEQ_GT(tracker.r_win_base, tsn->next_seq()) )
+                {
+                    paf.state = StreamSplitter::SKIP;
+                    return total;
+                }
+            }
+            else
+                return FINAL_FLUSH_OK;
         }
         else
             total = tsn->scan_seq() - seglist.cur_rseg->scan_seq();
     }
 
-    ret_val = FINAL_FLUSH_OK;
+    int32_t ret_val = FINAL_FLUSH_OK;
     while (tsn && *flags && SEQ_LT(tsn->scan_seq(), tracker.r_win_base))
     {
-        // only flush acked data that fits in pdu reassembly buffer...
         uint32_t end = tsn->scan_seq() + tsn->unscanned();
         uint32_t flush_len;
         int32_t flush_pt;
 
-        if ( SEQ_GT(end, tracker.r_win_base))
+        if ( SEQ_GT(end, tracker.r_win_base) )
             flush_len = tracker.r_win_base - tsn->scan_seq();
         else
             flush_len = tsn->unscanned();
@@ -150,25 +108,26 @@ int32_t TcpReassemblerIds::scan_data_post_ack(uint32_t* flags, Packet* p)
         else
             *flags &= ~PKT_MORE_TO_FLUSH;
 
-        if ( has_seglist_hole(*tsn, total, *flags) )
-            flush_pt = total;
-        else
-        {
-            total += flush_len;
-            flush_pt = paf.paf_check(p, tsn->paf_data(), flush_len, total, tsn->scan_seq(), flags);
-        }
-
-        // Get splitter from tracker as paf check may change it.
+        total += flush_len;
+        flush_pt = paf.paf_check(p, tsn->paf_data(), flush_len, total, tsn->scan_seq(), flags);
         seglist.cur_sseg = tsn;
 
         if ( flush_pt >= 0 )
+            return flush_pt;
+        else if ( !tsn->next_no_gap() )
         {
-            seglist.seglist_base_seq = seglist.cur_rseg->scan_seq();
+            // if ack is past the hole flush what we have... 
+            if ( tsn->next && SEQ_LEQ(tsn->next->start_seq(), tracker.r_win_base))
+            {
+                paf.state = StreamSplitter::SKIP;
+                flush_pt = total;
+            }
+
             return flush_pt;
         }
 
-        if (flush_len < tsn->unscanned() || (splitter->is_paf() and !tsn->next_no_gap()) ||
-            (paf.state == StreamSplitter::STOP))
+        if ( flush_len < tsn->unscanned() || (splitter->is_paf() and !tsn->next_no_gap())
+             or (paf.state == StreamSplitter::STOP) )
         {
             if ( !(tsn->next_no_gap() || fin_acked_no_gap(*tsn)) )
                 ret_val = FINAL_FLUSH_HOLD;
@@ -181,40 +140,89 @@ int32_t TcpReassemblerIds::scan_data_post_ack(uint32_t* flags, Packet* p)
     return ret_val;
 }
 
+void TcpReassemblerIds::skip_seglist_hole()
+{
+    if ( SEQ_LT(seglist.seglist_base_seq, seglist.head->start_seq()) )
+    {
+        uint32_t old_seglist_base_seq = seglist.seglist_base_seq;
+        
+        if ( SEQ_LT(tracker.r_win_base, seglist.head->start_seq()) )
+        {
+            seglist.seglist_base_seq = tracker.r_win_base;
+            tracker.set_rcv_nxt(tracker.r_win_base);
+        }
+        else
+        {
+            seglist.seglist_base_seq = seglist.head->start_seq();
+            seglist.advance_rcv_nxt();
+        }
+
+        uint32_t hole_size = seglist.seglist_base_seq - old_seglist_base_seq;
+        tracker.bytes_missing += hole_size;
+        tracker.holes_detected++;
+
+        if (PacketTracer::is_active())
+            PacketTracer::log("stream_tcp: IDS mode - skipping hole from %u to %u, size: %u"
+                " total holes: %u, total bytes skipped: %lu total bytes missing: %lu\n", 
+                old_seglist_base_seq, seglist.seglist_base_seq,
+                hole_size, tracker.holes_detected, tracker.bytes_skipped, tracker.bytes_missing);
+
+        if ( is_splitter_paf() )
+            tracker.fallback();
+        else
+        {
+            splitter->restart();
+            paf.paf_reset();
+            tcpStats.splitter_restarts++;
+            
+            if (PacketTracer::is_active())
+                PacketTracer::log("stream_tcp: IDS mode - splitter restarted due to seglist hole\n");
+        }
+            
+        seglist.cur_rseg = seglist.head;
+        tracker.set_order(TcpStreamTracker::OUT_OF_SEQUENCE);
+    }
+}
+
 int TcpReassemblerIds::eval_flush_policy_on_ack(Packet* p)
 {
+    // anything here to scan/flush?
+    if ( !seglist.head || SEQ_GEQ(seglist.seglist_base_seq, tracker.r_win_base) )
+        return 0;
+
     last_pdu = nullptr;
     uint32_t flushed = 0;
     int32_t flush_amt;
     uint32_t flags;
-
+    
     do
     {
+        skip_seglist_hole();
+
         flags = packet_dir;
         flush_amt = scan_data_post_ack(&flags, p);
-        if ( flush_amt <= 0 or paf.state == StreamSplitter::SKIP )
+        if ( flush_amt <= 0 )
             break;
 
-        // for consistency with other cases, should return total
-        // but that breaks flushing pipelined pdus
+        if ( paf.state == StreamSplitter::SKIP and is_splitter_paf() )
+        {
+            // hole in seglist with paf splitter, fallback to AtomSplitter and rescan data
+            tracker.fallback();
+            continue;
+        }
         flushed += flush_to_seq(flush_amt, p, flags);
-        assert( flushed );
-
-        // ideally we would purge just once after this loop but that throws off base
         if ( seglist.head )
             purge_to_seq(seglist.seglist_base_seq);
-    } while ( seglist.head and !p->flow->is_inspection_disabled() );
+            
+    } while ( seglist.head and !p->flow->is_inspection_disabled() 
+              and SEQ_LT(seglist.seglist_base_seq, tracker.r_win_base) );
 
     if ( (paf.state == StreamSplitter::ABORT) && is_splitter_paf() )
     {
         tracker.fallback();
         return eval_flush_policy_on_ack(p);
     }
-    else if ( paf.state == StreamSplitter::SKIP )
-    {
-        skip_seglist_hole(p, flags, flush_amt);
-        return eval_flush_policy_on_ack(p);
-    }
     else if ( final_flush_on_fin(flush_amt, p, FIN_WITH_SEQ_ACKED) )
         finish_and_final_flush(p->flow, true, p);
 
index 8b9f6f8d922b7d234692fb96b75d5568575196ed..5bf9896520b752af257bdb842d60b5a9c3e1a9da 100644 (file)
@@ -53,8 +53,7 @@ public:
 
 private:
     int32_t scan_data_post_ack(uint32_t* flags, snort::Packet*);
-    bool has_seglist_hole(TcpSegmentNode&, uint32_t& total, uint32_t& flags);
-    void skip_seglist_hole(snort::Packet*, uint32_t flags, int32_t flush_amt);
+    void skip_seglist_hole();
 };
 
 #endif
index 0b5ad0402a936b79e52ab5dbfc3c761d32b5d036..4a4f4109f649b8a84be484d33065dc27a3f8c3db 100644 (file)
@@ -131,11 +131,11 @@ void TcpReassemblySegments::print_stream_state(TcpStreamTracker* talker)
     ss << " seglist_base_seq: " << seglist_base_seq;
     ss << ", rcv_next: " << tracker->get_rcv_nxt();
     ss << ", r_win_base: " << talker->r_win_base;
-    if(head)
+    if( head )
         ss << ", head: " << head->start_seq();
-    if(cur_sseg)
+    if( cur_sseg )
         ss << ", cur_sseg: " << cur_sseg->start_seq();
-    if(cur_rseg)
+    if( cur_rseg )
         ss << ", cur_rseg: " << cur_rseg->start_seq();
     ss << "\n";
     PacketTracer::log("%s", ss.str().c_str());
@@ -215,7 +215,12 @@ void TcpReassemblySegments::insert_segment_data(TcpSegmentNode* prev, TcpSegment
     insert(prev, tsn);
 
     if ( !cur_sseg )
+    {
         cur_sseg = tsn;
+        cur_rseg = tsn;
+        if ( SEQ_LT(tsn->scan_seq(), seglist_base_seq) )
+            seglist_base_seq = tsn->scan_seq();
+    }
     else if ( SEQ_LT(tsn->scan_seq(), cur_sseg->scan_seq()) )
     {
         cur_sseg = tsn;
@@ -413,11 +418,18 @@ bool TcpReassemblySegments::skip_hole_at_beginning(TcpSegmentNode *tsn)
 
     if ( SEQ_GT(tsn->seq, seglist_base_seq) )
     {
+        uint32_t hole_size = tsn->seq - seglist_base_seq;
+        if ( PacketTracer::is_active() )
+            PacketTracer::log("stream_tcp: Seglist hole %u-->%u skipped at beginning of the seglist,"
+            " bytes missing: %u\n", seglist_base_seq, tsn->seq, hole_size);
+
+        tracker->bytes_missing += hole_size;
+        tracker->holes_detected++;
+
         hole_skipped = true;
         seglist_base_seq = tsn->seq;
         tracker->set_order(TcpStreamTracker::OUT_OF_SEQUENCE);
-        if ( PacketTracer::is_active() )
-            PacketTracer::log("stream_tcp: Skipped hole at beginning of the seglist\n");
+
     }
 
     return hole_skipped;
@@ -428,7 +440,7 @@ void TcpReassemblySegments::skip_holes()
     assert( head );
 
     TcpSegmentNode* tsn = head;
-    uint32_t num_segs = 0, total_segs = 0, num_holes = 0;
+    uint32_t num_segs = 0, num_holes = 0;
 
     // if there is a hole at the beginning, skip it...
     if ( skip_hole_at_beginning(tsn) )
@@ -441,10 +453,17 @@ void TcpReassemblySegments::skip_holes()
         if ( tsn->next and SEQ_GT(tsn->next->start_seq(), tsn->next_seq()) )
         {
             ++num_holes;
-            total_segs += num_segs;
+            uint32_t hole_size = tsn->next->start_seq() - tsn->next_seq();
             if ( PacketTracer::is_active() )
-                PacketTracer::log("stream_tcp: Seglist hole(%u): %u-->%u:%u. Segments purged: %u Total purged: %u\n",
-                    tsn->seq, tsn->next->seq, tsn->next->seq - tsn->seq, num_holes, num_segs, total_segs);
+                PacketTracer::log("stream_tcp: Seglist hole[%u]: %u-->%u segments purged: %u, bytes purged: %u,"
+                    " bytes missing: %u\n",
+                    num_holes, tsn->next_seq(), tsn->next->start_seq(), num_segs,
+                    tsn->next_seq() - seglist_base_seq, hole_size);
+            
+            tracker->bytes_skipped += tsn->next_seq() - seglist_base_seq;
+            tracker->bytes_missing += hole_size;
+            tracker->holes_detected++;
+
             tsn = tsn->next;
             purge_segments_left_of_hole(tsn);
             seglist_base_seq = head->start_seq();
@@ -479,7 +498,7 @@ void TcpReassemblySegments::skip_midstream_pickup_seglist_hole(TcpSegmentDescrip
             tsn = tsn->next;
             purge_segments_left_of_hole(tsn);
             seglist_base_seq = ack;
-        }
+       }
         else
             tsn = tsn->next;
     }
index 450c32a792cc843fe15f54647146a04857fe4c52..fe8042358effd4caf2c9d65f8b262831fa116ed3 100644 (file)
@@ -96,7 +96,7 @@ public:
         if ( !next_no_gap() )
             return false;
 
-        return SEQ_LT(next->start_seq() + next->cursor, seq_acked);
+        return SEQ_LT(next->start_seq(), seq_acked);
     }
 
 public:
index 387f4b906937d588828ae3d8cbb7d43195e397ad..fc89334b457b1ba88aa048138cf1bbb4e455d061 100644 (file)
@@ -696,7 +696,16 @@ bool TcpSession::check_reassembly_queue_thresholds(TcpSegmentDescriptor& tsd, Tc
 bool TcpSession::filter_packet_for_reassembly(TcpSegmentDescriptor& tsd, TcpStreamTracker* listener)
 {
     if ( tsd.are_packet_flags_set(PKT_IGNORE) or listener->get_flush_policy() == STREAM_FLPOLICY_IGNORE )
+    {
+        listener->update_stream_order(tsd, tsd.is_packet_inorder());
+
+        if ( tsd.is_packet_inorder() )
+            listener->set_rcv_nxt(tsd.get_end_seq());
+        else if ( SEQ_GT(listener->r_win_base, listener->rcv_nxt) )
+            listener->set_rcv_nxt(listener->r_win_base); 
+
         return false;
+    }
 
     return !check_reassembly_queue_thresholds(tsd, listener);
 }
@@ -747,11 +756,9 @@ void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd, bool flush)
                     tel.set_tcp_event(EVENT_EXCESSIVE_OVERLAP);
                     listener->seglist.set_overlap_count(0);
                 }
+                
+                listener->update_stream_order(tsd, tsd.is_packet_inorder());
             }
-            else if ( tsd.is_packet_inorder() )
-                listener->set_rcv_nxt(tsd.get_end_seq());
-
-            listener->update_stream_order(tsd, tsd.is_packet_inorder());
 
             break;
 
index aecce6a7732c540ba0046ad1d3872997dbd3ed38..4cd4323984542cd26d2f788dad2c2c3d42bbd03d 100644 (file)
@@ -66,6 +66,8 @@ const char* tcp_event_names[] = {
     "TCP_RST_SENT_EVENT", "TCP_RST_RECV_EVENT"
 };
 
+static constexpr uint32_t BOTH_SPLITTERS_YOINKED = (SSNFLAG_ABORT_CLIENT | SSNFLAG_ABORT_SERVER);
+
 TcpStreamTracker::TcpStreamTracker(bool client) :
     client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN)
 { 
@@ -431,8 +433,7 @@ void TcpStreamTracker::set_splitter(const Flow* flow)
 
 static inline bool both_splitters_aborted(Flow* flow)
 {
-    uint32_t both_splitters_yoinked = (SSNFLAG_ABORT_CLIENT | SSNFLAG_ABORT_SERVER);
-    return (flow->get_session_flags() & both_splitters_yoinked) == both_splitters_yoinked;
+    return (flow->get_session_flags() & BOTH_SPLITTERS_YOINKED) == BOTH_SPLITTERS_YOINKED;
 }
 
 void TcpStreamTracker::fallback()
index 97c255bddacd62460732d5efad7618eea5c3385e..cd93c2be41b07666bcc2483eaf610d47c9ae78f1 100644 (file)
@@ -315,7 +315,6 @@ public:
     static void thread_init();
     static void thread_term();
 
-public:
     uint32_t rcv_nxt = 0;          // RCV.NXT - receive next
     uint32_t rcv_wnd = 0;          // RCV.WND - receive window
 
@@ -332,6 +331,10 @@ public:
     TcpSession* session = nullptr;
     TcpAlerts tcp_alerts;
 
+    uint64_t bytes_skipped = 0;    // number of bytes skipped in the stream
+    uint64_t bytes_missing = 0;    // number of bytes missing in the stream
+    uint32_t holes_detected = 0;   // number of holes detected in the stream
+
     uint32_t r_win_base = 0; // remote side window base sequence number (the last ack we got)
     uint32_t small_seg_count = 0;
     FinSeqNumStatus fin_seq_status = FIN_NOT_SEEN;
@@ -372,6 +375,7 @@ private:
     uint32_t irs = 0;              // IRS     - initial receive sequence number
     uint16_t snd_up = 0;           // SND.UP  - send urgent pointer
     uint16_t rcv_up = 0;           // RCV.UP  - receive urgent pointer
+
 };
 
 // <--- note -- the 'state' parameter must be a reference