From: Davis McPherson -X (davmcphe - XORIANT CORPORATION at Cisco) Date: Fri, 8 Aug 2025 19:48:11 +0000 (+0000) Subject: Pull request #4741: stream_tcp: fix issues with skipping seglist holes in ids mode X-Git-Tag: 3.9.3.0~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e35219f48d1039780f370be4087f40a289c41ad7;p=thirdparty%2Fsnort3.git Pull request #4741: stream_tcp: fix issues with skipping seglist holes in ids mode Merge in SNORT/snort3 from ~DAVMCPHE/snort3:ids_skip_seglist_holes_fix to master Squashed commit of the following: commit 3590f4bed9550af66f9260739fd66bf218146c3f Author: davis mcpherson 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 Date: Fri Jun 13 08:11:19 2025 -0400 snort3: add build directory and vscode workspace config file to git ignore list --- diff --git a/.gitignore b/.gitignore index 67c8fc52a..f61a28868 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,8 @@ build.env coverage.info coverage.txt src/uncovered.txt +build/ + +# vscode config +snort3.code-workspace + diff --git a/src/stream/stream_splitter.cc b/src/stream/stream_splitter.cc index dc98fbd6e..312034bc0 100644 --- a/src/stream/stream_splitter.cc +++ b/src/stream/stream_splitter.cc @@ -98,6 +98,12 @@ StreamSplitter::Status AtomSplitter::scan( return SEARCH; } +bool AtomSplitter::restart() +{ + reset(); + return true; +} + void AtomSplitter::reset() { segs = bytes_scanned = 0; } diff --git a/src/stream/stream_splitter.h b/src/stream/stream_splitter.h index d23820cc5..5b446d814 100644 --- a/src/stream/stream_splitter.h +++ b/src/stream/stream_splitter.h @@ -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(); diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index ac2567d43..63e83fc70 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -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" }, diff --git a/src/stream/tcp/tcp_module.h b/src/stream/tcp/tcp_module.h index 7bcaccd2e..5d7b3814d 100644 --- a/src/stream/tcp/tcp_module.h +++ b/src/stream/tcp/tcp_module.h @@ -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; diff --git a/src/stream/tcp/tcp_reassembler.cc b/src/stream/tcp/tcp_reassembler.cc index 6b2df0fd5..51ab31c8e 100644 --- a/src/stream/tcp/tcp_reassembler.cc +++ b/src/stream/tcp/tcp_reassembler.cc @@ -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); diff --git a/src/stream/tcp/tcp_reassembler.h b/src/stream/tcp/tcp_reassembler.h index b69bdfab3..3d82610d2 100644 --- a/src/stream/tcp/tcp_reassembler.h +++ b/src/stream/tcp/tcp_reassembler.h @@ -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); diff --git a/src/stream/tcp/tcp_reassembler_ids.cc b/src/stream/tcp/tcp_reassembler_ids.cc index c60005ac9..5520c7e5a 100644 --- a/src/stream/tcp/tcp_reassembler_ids.cc +++ b/src/stream/tcp/tcp_reassembler_ids.cc @@ -44,54 +44,6 @@ 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); diff --git a/src/stream/tcp/tcp_reassembler_ids.h b/src/stream/tcp/tcp_reassembler_ids.h index 8b9f6f8d9..5bf989652 100644 --- a/src/stream/tcp/tcp_reassembler_ids.h +++ b/src/stream/tcp/tcp_reassembler_ids.h @@ -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 diff --git a/src/stream/tcp/tcp_reassembly_segments.cc b/src/stream/tcp/tcp_reassembly_segments.cc index 0b5ad0402..4a4f4109f 100644 --- a/src/stream/tcp/tcp_reassembly_segments.cc +++ b/src/stream/tcp/tcp_reassembly_segments.cc @@ -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; } diff --git a/src/stream/tcp/tcp_segment_node.h b/src/stream/tcp/tcp_segment_node.h index 450c32a79..fe8042358 100644 --- a/src/stream/tcp/tcp_segment_node.h +++ b/src/stream/tcp/tcp_segment_node.h @@ -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: diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index 387f4b906..fc89334b4 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -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; diff --git a/src/stream/tcp/tcp_stream_tracker.cc b/src/stream/tcp/tcp_stream_tracker.cc index aecce6a77..4cd432398 100644 --- a/src/stream/tcp/tcp_stream_tracker.cc +++ b/src/stream/tcp/tcp_stream_tracker.cc @@ -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() diff --git a/src/stream/tcp/tcp_stream_tracker.h b/src/stream/tcp/tcp_stream_tracker.h index 97c255bdd..cd93c2be4 100644 --- a/src/stream/tcp/tcp_stream_tracker.h +++ b/src/stream/tcp/tcp_stream_tracker.h @@ -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