]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1337 in SNORT/snort3 from stream_tcp_dup_no_more to master
authorTom Peters (thopeter) <thopeter@cisco.com>
Mon, 27 Aug 2018 15:11:36 +0000 (11:11 -0400)
committerTom Peters (thopeter) <thopeter@cisco.com>
Mon, 27 Aug 2018 15:11:36 +0000 (11:11 -0400)
Squashed commit of the following:

commit a10f22c3f011ddf297f9170fed3054a4b52b7023
Author: davis mcpherson <davmcphe.cisco.com>
Date:   Wed Jul 25 10:33:48 2018 -0400

    stream_tcp: update tsn state when partial buffer flushed, do not duplicate

    stream_tcp: delete tsn&data after flush, use seglist_base_seq to track progress

    use orig_dsize instead of payload_size for overlap math

    stream_tcp: eliminate 'buffered' field for tcp segment node struct

    stream_tcp: improve tcp segment state variable names and usage during reassembley and overlap processing

    stream_tcp: some refactoring to improve symbol names and code readability

src/stream/libtcp/tcp_stream_tracker.h
src/stream/tcp/segment_overlap_editor.cc
src/stream/tcp/segment_overlap_editor.h
src/stream/tcp/tcp_reassembler.cc
src/stream/tcp/tcp_reassembler.h
src/stream/tcp/tcp_segment_node.cc
src/stream/tcp/tcp_segment_node.h

index de68ef4d324fc7e4384beab4e6581ee25ea13049..77813ec26025d9c0d704554e841ce09a6238c7ec 100644 (file)
@@ -47,7 +47,6 @@ extern const char* tcp_event_names[];
 
 class TcpReassembler;
 class TcpSession;
-struct TcpSegmentNode;
 
 class TcpStreamTracker
 {
index 0918acb3a2e5ffd26abf06e86a985f26d06067d9..a7479edf5673576e7421e3cc4f207cb8d0fb6532 100644 (file)
@@ -96,14 +96,14 @@ bool SegmentOverlapEditor::is_segment_retransmit(
     bool* pb = (trs.sos.rseq == trs.sos.tsd->get_seg_seq()) ? full_retransmit : nullptr;
 
     if ( trs.sos.right->is_retransmit(
-        trs.sos.rdata, trs.sos.rsize, trs.sos.rseq, trs.sos.right->orig_dsize, pb) )
+        trs.sos.rdata, trs.sos.rsize, trs.sos.rseq, trs.sos.right->i_len, pb) )
     {
         if ( !(*full_retransmit) )
         {
-            trs.sos.rdata += trs.sos.right->payload_size;
-            trs.sos.rsize -= trs.sos.right->payload_size;
-            trs.sos.rseq += trs.sos.right->payload_size;
-            trs.sos.seq += trs.sos.right->payload_size;
+            trs.sos.rdata += trs.sos.right->i_len;
+            trs.sos.rsize -= trs.sos.right->i_len;
+            trs.sos.rseq += trs.sos.right->i_len;
+            trs.sos.seq += trs.sos.right->i_len;
             trs.sos.left = trs.sos.right;
             trs.sos.right = trs.sos.right->next;
         }
@@ -135,21 +135,21 @@ int SegmentOverlapEditor::eval_left(TcpReassemblerState& trs)
 
 int SegmentOverlapEditor::eval_right(TcpReassemblerState& trs)
 {
-    while ( trs.sos.right && SEQ_LT(trs.sos.right->seq, trs.sos.seq_end) )
+    while ( trs.sos.right && SEQ_LT(trs.sos.right->i_seq, trs.sos.seq_end) )
     {
         trs.sos.trunc_len = 0;
 
-        assert(SEQ_LEQ(trs.sos.seq, trs.sos.right->seq));
-        trs.sos.overlap = ( int )( trs.sos.seq_end - trs.sos.right->seq );
+        assert(SEQ_LEQ(trs.sos.seq, trs.sos.right->i_seq));
+        trs.sos.overlap = ( int )( trs.sos.seq_end - trs.sos.right->i_seq );
 
         // Treat sequence number overlap as a retransmission, only check right side since
         //  left side happens rarely
         trs.sos.session->retransmit_handle(trs.sos.tsd->get_pkt());
 
-        if ( trs.sos.overlap < trs.sos.right->payload_size )
+        if ( trs.sos.overlap < trs.sos.right->i_len )
         {
             if ( trs.sos.right->is_retransmit(
-                trs.sos.rdata, trs.sos.rsize, trs.sos.rseq, trs.sos.right->orig_dsize, nullptr) )
+                trs.sos.rdata, trs.sos.rsize, trs.sos.rseq, trs.sos.right->i_len, nullptr) )
             {
                 // All data was retransmitted
                 trs.sos.session->retransmit_process(trs.sos.tsd->get_pkt());
@@ -199,10 +199,10 @@ int SegmentOverlapEditor::left_overlap_keep_first(TcpReassemblerState& trs)
 {
     // NOTE that overlap will always be less than left->size since
     // seq is always greater than left->seq
-    assert(SEQ_GT(trs.sos.seq, trs.sos.left->seq));
+    assert(SEQ_GT(trs.sos.seq, trs.sos.left->i_seq));
 
     trs.sos.len = trs.sos.tsd->get_seg_len();
-    trs.sos.overlap = trs.sos.left->seq + trs.sos.left->payload_size - trs.sos.seq;
+    trs.sos.overlap = trs.sos.left->i_seq + trs.sos.left->i_len - trs.sos.seq;
 
     if ( trs.sos.len < trs.sos.overlap )
         trs.sos.overlap = trs.sos.len;
@@ -212,13 +212,13 @@ int SegmentOverlapEditor::left_overlap_keep_first(TcpReassemblerState& trs)
         tcpStats.overlaps++;
         trs.sos.overlap_count++;
 
-        if ( SEQ_GT(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq_end) )
+        if ( SEQ_GT(trs.sos.left->i_seq + trs.sos.left->i_len, trs.sos.seq_end) )
         {
             if (trs.sos.tcp_ips_data == NORM_MODE_ON)
             {
-                unsigned offset = trs.sos.tsd->get_seg_seq() - trs.sos.left->seq;
+                unsigned offset = trs.sos.tsd->get_seg_seq() - trs.sos.left->i_seq;
                 memcpy(const_cast<uint8_t*>(trs.sos.tsd->get_pkt()->data),
-                    trs.sos.left->payload()+offset, trs.sos.tsd->get_seg_len());
+                    trs.sos.left->data + offset, trs.sos.tsd->get_seg_len());
                 trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
             }
             tcp_norm_stats[PC_TCP_IPS_DATA][trs.sos.tcp_ips_data]++;
@@ -227,11 +227,11 @@ int SegmentOverlapEditor::left_overlap_keep_first(TcpReassemblerState& trs)
         {
             if ( trs.sos.tcp_ips_data == NORM_MODE_ON )
             {
-                unsigned offset = trs.sos.tsd->get_seg_seq() - trs.sos.left->seq;
-                unsigned length = trs.sos.left->seq + trs.sos.left->payload_size -
+                unsigned offset = trs.sos.tsd->get_seg_seq() - trs.sos.left->i_seq;
+                unsigned length = trs.sos.left->i_seq + trs.sos.left->i_len -
                     trs.sos.tsd->get_seg_seq();
                 memcpy(const_cast<uint8_t*>(trs.sos.tsd->get_pkt()->data),
-                    trs.sos.left->payload()+offset, length);
+                    trs.sos.left->data + offset, length);
                 trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
             }
 
@@ -246,17 +246,17 @@ int SegmentOverlapEditor::left_overlap_keep_first(TcpReassemblerState& trs)
 
 int SegmentOverlapEditor::left_overlap_trim_first(TcpReassemblerState& trs)
 {
-    assert(SEQ_GT(trs.sos.seq, trs.sos.left->seq));
+    assert(SEQ_GT(trs.sos.seq, trs.sos.left->i_seq));
 
     trs.sos.len = trs.sos.tsd->get_seg_len();
-    trs.sos.overlap = trs.sos.left->seq + trs.sos.left->payload_size - trs.sos.seq;
+    trs.sos.overlap = trs.sos.left->i_seq + trs.sos.left->i_len - trs.sos.seq;
 
     if ( trs.sos.overlap > 0 )
     {
         tcpStats.overlaps++;
         trs.sos.overlap_count++;
 
-        if ( SEQ_GEQ(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq + trs.sos.len)  )
+        if ( SEQ_GEQ(trs.sos.left->i_seq + trs.sos.left->i_len, trs.sos.seq + trs.sos.len)  )
         {
             // existing packet overlaps new on both sides.  Drop the new data.
             trs.sos.seq += trs.sos.len;
@@ -264,7 +264,8 @@ int SegmentOverlapEditor::left_overlap_trim_first(TcpReassemblerState& trs)
         else
         {
             /* Otherwise, trim the old data accordingly */
-            trs.sos.left->payload_size -= ( int16_t )trs.sos.overlap;
+            trs.sos.left->c_len -= ( int16_t )trs.sos.overlap;
+            trs.sos.left->i_len -= ( int16_t )trs.sos.overlap;
             trs.sos.seg_bytes_logical -= trs.sos.overlap;
         }
     }
@@ -274,10 +275,10 @@ int SegmentOverlapEditor::left_overlap_trim_first(TcpReassemblerState& trs)
 
 int SegmentOverlapEditor::left_overlap_keep_last(TcpReassemblerState& trs)
 {
-    assert(SEQ_GT(trs.sos.seq, trs.sos.left->seq));
+    assert(SEQ_GT(trs.sos.seq, trs.sos.left->i_seq));
 
     trs.sos.len = trs.sos.tsd->get_seg_len();
-    trs.sos.overlap = trs.sos.left->seq + trs.sos.left->payload_size - trs.sos.seq;
+    trs.sos.overlap = trs.sos.left->i_seq + trs.sos.left->i_len - trs.sos.seq;
 
     if ( trs.sos.overlap > 0 )
     {
@@ -285,30 +286,34 @@ int SegmentOverlapEditor::left_overlap_keep_last(TcpReassemblerState& trs)
         trs.sos.overlap_count++;
 
         /* True "Last" policy" */
-        if ( SEQ_GT(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq + trs.sos.len) )
+        if ( SEQ_GT(trs.sos.left->i_seq + trs.sos.left->i_len, trs.sos.seq + trs.sos.len) )
         {
             /* New data is overlapped on both sides by existing data.  Existing data needs to be
              * split and the new data inserted in the middle.
              * Need to duplicate left. Adjust that seq by + (seq + len) and
-             * size by - (seq + len - left->seq).
+             * size by - (seq + len - left->i_seq).
              */
             int rc = dup_reassembly_segment(trs, trs.sos.left, &trs.sos.right);
 
             if ( rc != STREAM_INSERT_OK )
                 return rc;
 
-            trs.sos.left->payload_size -= ( int16_t )trs.sos.overlap;
+            trs.sos.left->c_len -= ( int16_t )trs.sos.overlap;
+            trs.sos.left->i_len -= ( int16_t )trs.sos.overlap;
 
-            trs.sos.right->seq = trs.sos.seq + trs.sos.len;
-            uint16_t delta = ( int16_t )( trs.sos.right->seq - trs.sos.left->seq );
-            trs.sos.right->payload_size -= delta;
+            trs.sos.right->i_seq = trs.sos.seq + trs.sos.len;
+            trs.sos.right->c_seq = trs.sos.right->i_seq;
+            uint16_t delta = ( int16_t )( trs.sos.right->i_seq - trs.sos.left->i_seq );
+            trs.sos.right->c_len -= delta;
+            trs.sos.right->i_len -= delta;
             trs.sos.right->offset += delta;
 
-            trs.sos.seg_bytes_logical -= trs.sos.len;
+            trs.sos.seg_bytes_logical -= delta;
         }
         else
         {
-            trs.sos.left->payload_size -= (int16_t)trs.sos.overlap;
+            trs.sos.left->c_len -= (int16_t)trs.sos.overlap;
+            trs.sos.left->i_len -= ( int16_t )trs.sos.overlap;
             trs.sos.seg_bytes_logical -= trs.sos.overlap;
         }
     }
@@ -318,17 +323,20 @@ int SegmentOverlapEditor::left_overlap_keep_last(TcpReassemblerState& trs)
 
 void SegmentOverlapEditor::right_overlap_truncate_existing(TcpReassemblerState& trs)
 {
-    if ( SEQ_EQ(trs.sos.right->seq, trs.sos.seq) && ( trs.sos.reassembly_policy != ReassemblyPolicy::OS_LAST ) )
+    if ( SEQ_EQ(trs.sos.right->i_seq, trs.sos.seq) &&
+        ( trs.sos.reassembly_policy != ReassemblyPolicy::OS_LAST ) )
     {
-        trs.sos.slide = ( trs.sos.right->seq + trs.sos.right->payload_size - trs.sos.seq );
+        trs.sos.slide = ( trs.sos.right->i_seq + trs.sos.right->i_len - trs.sos.seq );
         trs.sos.seq += trs.sos.slide;
     }
     else
     {
         /* partial overlap */
-        trs.sos.right->seq += trs.sos.overlap;
+        trs.sos.right->i_seq += trs.sos.overlap;
+        trs.sos.right->c_seq = trs.sos.right->i_seq;
         trs.sos.right->offset += trs.sos.overlap;
-        trs.sos.right->payload_size -= (int16_t)trs.sos.overlap;
+        trs.sos.right->c_len -= (int16_t)trs.sos.overlap;
+        trs.sos.right->i_len -= ( int16_t )trs.sos.overlap;
         trs.sos.seg_bytes_logical -= trs.sos.overlap;
         trs.sos.total_bytes_queued -= trs.sos.overlap;
     }
@@ -338,11 +346,11 @@ void SegmentOverlapEditor::right_overlap_truncate_new(TcpReassemblerState& trs)
 {
     if (trs.sos.tcp_ips_data == NORM_MODE_ON)
     {
-        unsigned offset = trs.sos.right->seq - trs.sos.tsd->get_seg_seq();
+        unsigned offset = trs.sos.right->i_seq - trs.sos.tsd->get_seg_seq();
         unsigned length = trs.sos.tsd->get_seg_seq() + trs.sos.tsd->get_seg_len() -
-            trs.sos.right->seq;
+            trs.sos.right->i_seq;
         memcpy(const_cast<uint8_t*>(trs.sos.tsd->get_pkt()->data) + offset,
-            trs.sos.right->payload(), length);
+            trs.sos.right->data, length);
         trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
     }
 
@@ -356,19 +364,19 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new(TcpReassemblerState& t
 {
     if ( trs.sos.tcp_ips_data == NORM_MODE_ON )
     {
-        unsigned offset = trs.sos.right->seq - trs.sos.tsd->get_seg_seq();
+        unsigned offset = trs.sos.right->i_seq - trs.sos.tsd->get_seg_seq();
         memcpy(const_cast<uint8_t*>(trs.sos.tsd->get_pkt()->data) + offset,
-            trs.sos.right->payload(), trs.sos.right->payload_size);
+            trs.sos.right->data, trs.sos.right->i_len);
         trs.sos.tsd->get_pkt()->packet_flags |= PKT_MODIFIED;
     }
 
     tcp_norm_stats[PC_TCP_IPS_DATA][trs.sos.tcp_ips_data]++;
 
-    if ( SEQ_EQ(trs.sos.right->seq, trs.sos.seq) )
+    if ( SEQ_EQ(trs.sos.right->i_seq, trs.sos.seq) )
     {
         /* Overlap is greater than or equal to right->size
          * slide gets set before insertion */
-        trs.sos.seq += trs.sos.right->payload_size;
+        trs.sos.seq += trs.sos.right->i_len;
         trs.sos.left = trs.sos.right;
         trs.sos.right = trs.sos.right->next;
 
@@ -378,7 +386,7 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new(TcpReassemblerState& t
     }
     else
     {
-        /* seq is less than right->seq,  trunc length is reset to 0 at beginning of loop */
+        /* seq is less than right->i_seq,  trunc length is reset to 0 at beginning of loop */
         trs.sos.trunc_len = trs.sos.overlap;
 
         /* insert this one, and see if we need to chunk it up
@@ -392,7 +400,7 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new(TcpReassemblerState& t
         // Set seq to end of right since overlap was greater than or equal to right->size and
         // inserted seq has been truncated to beginning of right and reset trunc length to 0
         // since we may fall out of loop if next right is NULL
-        trs.sos.seq = trs.sos.right->seq + trs.sos.right->payload_size;
+        trs.sos.seq = trs.sos.right->i_seq + trs.sos.right->i_len;
         trs.sos.left = trs.sos.right;
         trs.sos.right = trs.sos.right->next;
         trs.sos.trunc_len = 0;
@@ -407,8 +415,8 @@ int SegmentOverlapEditor::full_right_overlap_truncate_new(TcpReassemblerState& t
 // REASSEMBLY_POLICY_MACOS:
 int SegmentOverlapEditor::full_right_overlap_os1(TcpReassemblerState& trs)
 {
-    if ( SEQ_GEQ(trs.sos.seq_end, trs.sos.right->seq + trs.sos.right->payload_size) and
-        SEQ_LT(trs.sos.seq, trs.sos.right->seq) )
+    if ( SEQ_GEQ(trs.sos.seq_end, trs.sos.right->i_seq + trs.sos.right->i_len) and
+        SEQ_LT(trs.sos.seq, trs.sos.right->i_seq) )
     {
         drop_old_segment(trs);
     }
@@ -427,13 +435,13 @@ int SegmentOverlapEditor::full_right_overlap_os1(TcpReassemblerState& trs)
 // REASSEMBLY_POLICY_IRIX:
 int SegmentOverlapEditor::full_right_overlap_os2(TcpReassemblerState& trs)
 {
-    if ( SEQ_GEQ(trs.sos.seq_end, trs.sos.right->seq + trs.sos.right->payload_size) and
-        SEQ_LT(trs.sos.seq, trs.sos.right->seq) )
+    if ( SEQ_GEQ(trs.sos.seq_end, trs.sos.right->i_seq + trs.sos.right->i_len) and
+        SEQ_LT(trs.sos.seq, trs.sos.right->i_seq) )
     {
         drop_old_segment(trs);
     }
-    else if ( SEQ_GT(trs.sos.seq_end, trs.sos.right->seq + trs.sos.right->payload_size) and
-        SEQ_EQ(trs.sos.seq, trs.sos.right->seq) )
+    else if ( SEQ_GT(trs.sos.seq_end, trs.sos.right->i_seq + trs.sos.right->i_len) and
+        SEQ_EQ(trs.sos.seq, trs.sos.right->i_seq) )
     {
         drop_old_segment(trs);
     }
@@ -453,15 +461,15 @@ int SegmentOverlapEditor::full_right_overlap_os3(TcpReassemblerState& trs)
 {
     // If this packet is wholly overlapping and the same size as a previous one and we have not
     // received the one immediately preceding, we take the FIRST.
-    if ( SEQ_EQ(trs.sos.right->seq, trs.sos.seq) && (trs.sos.right->payload_size == trs.sos.len)
-        && (trs.sos.left && !SEQ_EQ(trs.sos.left->seq + trs.sos.left->payload_size, trs.sos.seq)) )
+    if ( SEQ_EQ(trs.sos.right->i_seq, trs.sos.seq) && (trs.sos.right->i_len == trs.sos.len)
+        && (trs.sos.left && !SEQ_EQ(trs.sos.left->i_seq + trs.sos.left->i_len, trs.sos.seq)) )
     {
         right_overlap_truncate_new(trs);
 
-        trs.sos.rdata += trs.sos.right->payload_size;
-        trs.sos.rsize -= trs.sos.right->payload_size;
-        trs.sos.rseq += trs.sos.right->payload_size;
-        trs.sos.seq += trs.sos.right->payload_size;
+        trs.sos.rdata += trs.sos.right->i_len;
+        trs.sos.rsize -= trs.sos.right->i_len;
+        trs.sos.rseq += trs.sos.right->i_len;
+        trs.sos.seq += trs.sos.right->i_len;
         trs.sos.left = trs.sos.right;
         trs.sos.right = trs.sos.right->next;
     }
@@ -491,7 +499,7 @@ void SegmentOverlapEditor::print(TcpReassemblerState& trs)
     snort::LogMessage("    seglist_base_seq:   %X\n", trs.sos.seglist_base_seq);
     snort::LogMessage("    seglist head:       %p\n", (void*)trs.sos.seglist.head);
     snort::LogMessage("    seglist tail:       %p\n", (void*)trs.sos.seglist.tail);
-    snort::LogMessage("    seglist next:       %p\n", (void*)trs.sos.seglist.next);
+    snort::LogMessage("    seglist current:    %p\n", (void*)trs.sos.seglist.cur_rseg);
     snort::LogMessage("    seg_count:          %d\n", trs.sos.seg_count);
     snort::LogMessage("    seg_bytes_total:    %d\n", trs.sos.seg_bytes_total);
     snort::LogMessage("    seg_bytes_logical:  %d\n", trs.sos.seg_bytes_logical);
index 22a8f59c14f25115581f47debae9bc413ea848a0..a0b25d7d1074c7014c2064aaef970f8f0f49dcf0 100644 (file)
@@ -23,7 +23,7 @@
 #define SEGMENT_OVERLAP_EDITOR_H
 
 #include "normalize/normalize.h"
-#include "stream/tcp/tcp_segment_node.h"
+#include "tcp_segment_node.h"
 
 class TcpSession;
 class TcpStreamTracker;
index 93682f20c97bb422703fa470725b2b98513bbea3..64cc1c5988f872b88252f36967f215023e193d3f 100644 (file)
@@ -46,17 +46,16 @@ void TcpReassembler::trace_segments(TcpReassemblerState& trs)
 
     while ( tsn )
     {
-        if (SEQ_LT(sx, tsn->seq))
-            fprintf(stdout, " +%u", tsn->seq - sx);
-        else if (SEQ_GT(sx, tsn->seq))
-            fprintf(stdout, " -%u", sx - tsn->seq);
+        if (SEQ_LT(sx, tsn->c_seq))
+            fprintf(stdout, " +%u", tsn->c_seq - sx);
+        else if (SEQ_GT(sx, tsn->c_seq))
+            fprintf(stdout, " -%u", sx - tsn->c_seq);
 
-        fprintf(stdout, " %hu", tsn->payload_size);
+        fprintf(stdout, " %hu", tsn->c_len);
 
         segs++;
-        bytes += tsn->payload_size;
-
-        sx = tsn->seq + tsn->payload_size;
+        bytes += tsn->i_len;
+        sx = tsn->c_seq + tsn->c_len;
         tsn = tsn->next;
     }
     assert(trs.sos.seg_count == segs);
@@ -80,7 +79,7 @@ uint32_t TcpReassembler::get_pending_segment_count(TcpReassemblerState& trs, uns
     tsn = trs.sos.seglist.head;
     while ( tsn )
     {
-        if ( !tsn->buffered && SEQ_LT(tsn->seq, trs.tracker->r_win_base) )
+        if ( tsn->c_len && SEQ_LT(tsn->c_seq, trs.tracker->r_win_base) )
             n++;
 
         if ( max && n == max )
@@ -108,12 +107,14 @@ bool TcpReassembler::flush_data_ready(TcpReassemblerState& trs)
 
 bool TcpReassembler::next_no_gap(TcpSegmentNode& tsn)
 {
-    return tsn.next and (tsn.next->seq == tsn.seq + tsn.payload_size);
+    return tsn.next and (tsn.next->i_seq == tsn.i_seq + tsn.i_len);
 }
 
 void TcpReassembler::update_next(TcpReassemblerState& trs, TcpSegmentNode& tsn)
 {
-    trs.sos.seglist.next = next_no_gap(tsn) ?  tsn.next : nullptr;
+    trs.sos.seglist.cur_rseg = next_no_gap(tsn) ?  tsn.next : nullptr;
+    if ( trs.sos.seglist.cur_rseg )
+       trs.sos.seglist.cur_rseg->c_seq = trs.sos.seglist.cur_rseg->i_seq;
 }
 
 int TcpReassembler::delete_reassembly_segment(TcpReassemblerState& trs, TcpSegmentNode* tsn)
@@ -121,61 +122,38 @@ int TcpReassembler::delete_reassembly_segment(TcpReassemblerState& trs, TcpSegme
     int ret;
     assert(tsn);
 
-    if (tsn->prev)
-        tsn->prev->next = tsn->next;
-    else
-        trs.sos.seglist.head = tsn->next;
-
-    if (tsn->next)
-        tsn->next->prev = tsn->prev;
-    else
-        trs.sos.seglist.tail = tsn->prev;
+    trs.sos.seglist.remove(tsn);
+    trs.sos.seg_bytes_total -= tsn->i_len;
+    trs.sos.seg_bytes_logical -= tsn->i_len;
+    ret = tsn->i_len;
 
-    trs.sos.seg_bytes_logical -= tsn->payload_size;
-    trs.sos.seg_bytes_total -= tsn->orig_dsize;
-
-    ret = tsn->orig_dsize;
-
-    if (tsn->buffered)
+    if ( !tsn->c_len )
     {
         tcpStats.segs_used++;
         trs.flush_count--;
     }
 
-    if (trs.sos.seglist.next == tsn)
+    if ( trs.sos.seglist.cur_rseg == tsn )
         update_next(trs, *tsn);
 
-    tsn->term( );
+    tsn->term();
     trs.sos.seg_count--;
 
     return ret;
 }
 
-int TcpReassembler::trim_delete_reassembly_segment(
-    TcpReassemblerState& trs, TcpSegmentNode* tsn, uint32_t flush_seq)
-{
-    if ( paf_active(&trs.tracker->paf_state) && ( ( tsn->seq + tsn->payload_size ) > flush_seq ) )
-    {
-        uint32_t delta = flush_seq - tsn->seq;
-
-        if (delta < tsn->payload_size)
-        {
-            tsn->seq = flush_seq;
-            tsn->payload_size -= (uint16_t)delta;
-            trs.sos.seg_bytes_logical -= delta;
-            return 0;
-        }
-    }
-
-    return delete_reassembly_segment(trs, tsn);
-}
-
 void TcpReassembler::queue_reassembly_segment(
     TcpReassemblerState& trs, TcpSegmentNode* prev, TcpSegmentNode* tsn)
 {
     trs.sos.seglist.insert(prev, tsn);
+    if ( SEQ_EQ(tsn->i_seq, trs.sos.seglist_base_seq) )
+    {
+       tsn->c_seq = tsn->i_seq;
+        trs.sos.seglist.cur_rseg = tsn;
+    }
+
     trs.sos.seg_count++;
-    trs.sos.seg_bytes_total += tsn->orig_dsize;
+    trs.sos.seg_bytes_total += tsn->i_len;
     trs.sos.total_segs_queued++;
     tcpStats.segs_queued++;
 }
@@ -183,7 +161,7 @@ void TcpReassembler::queue_reassembly_segment(
 bool TcpReassembler::is_segment_fasttrack(
     TcpReassemblerState&, TcpSegmentNode* tail, TcpSegmentDescriptor& tsd)
 {
-    if ( SEQ_EQ(tsd.get_seg_seq(), tail->seq + tail->payload_size) )
+    if ( SEQ_EQ(tsd.get_seg_seq(), tail->i_seq + tail->i_len) )
         return true;
 
     return false;
@@ -212,8 +190,9 @@ int TcpReassembler::add_reassembly_segment(
     // FIXIT-L don't allocate overlapped part
     tsn = TcpSegmentNode::init(tsd);
     tsn->offset = slide;
-    tsn->payload_size = (uint16_t)newSize;
-    tsn->seq = seq;
+    tsn->c_len = (uint16_t)newSize;
+    tsn->i_len = (uint16_t)newSize;
+    tsn->i_seq = tsn->c_seq = seq;
     tsn->ts = tsd.get_ts();
 
     // FIXIT-M the urgent ptr handling is broken... urg_offset is set here but currently
@@ -223,14 +202,10 @@ int TcpReassembler::add_reassembly_segment(
 
     queue_reassembly_segment(trs, left, tsn);
 
-    trs.sos.seg_bytes_logical += tsn->payload_size;
-    trs.sos.total_bytes_queued += tsn->payload_size;
+    trs.sos.seg_bytes_logical += tsn->c_len;
+    trs.sos.total_bytes_queued += tsn->c_len;
     tsd.get_pkt()->packet_flags |= PKT_STREAM_INSERT;
 
-
-#ifdef SEG_TEST
-    CheckSegments(trs.tracker);
-#endif
     return STREAM_INSERT_OK;
 }
 
@@ -241,9 +216,8 @@ int TcpReassembler::dup_reassembly_segment(
     tcpStats.segs_split++;
 
     // twiddle the values for overlaps
-    tsn->payload_size = left->payload_size;
-    tsn->seq = left->seq;
-
+    tsn->c_len = left->c_len;
+    tsn->i_seq = tsn->c_seq = left->i_seq;
     queue_reassembly_segment(trs, left, tsn);
 
     *retSeg = tsn;
@@ -265,31 +239,28 @@ int TcpReassembler::purge_alerts(TcpReassemblerState& trs, Flow* flow)
 int TcpReassembler::purge_to_seq(TcpReassemblerState& trs, uint32_t flush_seq)
 {
     assert(trs.sos.seglist.head != nullptr);
-    TcpSegmentNode* tsn = trs.sos.seglist.head;
-    TcpSegmentNode* dump_me = nullptr;
-    int purged_bytes = 0;
+    int total_purged = 0;
     uint32_t last_ts = 0;
 
-    while ( tsn )
-    {
-        dump_me = tsn;
-
-        tsn = tsn->next;
-        if ( SEQ_LT(dump_me->seq, flush_seq) )
-        {
-            if (dump_me->ts > last_ts)
-                last_ts = dump_me->ts;
-
-            purged_bytes += trim_delete_reassembly_segment(trs, dump_me, flush_seq);
-        }
-        else
-            break;
-    }
-
-    if ( SEQ_LT(trs.sos.seglist_base_seq, flush_seq) )
+    TcpSegmentNode* tsn = trs.sos.seglist.head;
+    while ( tsn && SEQ_LT(tsn->i_seq, flush_seq))
     {
-        // FIXIT-M these lines are out of code coverage. Is this even possible?
-        trs.sos.seglist_base_seq = flush_seq;
+        if ( !tsn->c_len )
+       {
+            TcpSegmentNode* dump_me = tsn;
+               tsn = tsn->next;
+               if (dump_me->ts > last_ts)
+                       last_ts = dump_me->ts;
+
+               total_purged += dump_me->last_flush_len;
+               delete_reassembly_segment(trs, dump_me);
+       }
+       else
+       {
+           total_purged += tsn->last_flush_len;
+               tsn->last_flush_len = 0;
+               break;
+       }
     }
 
     if ( SEQ_LT(trs.tracker->rcv_nxt, flush_seq) )
@@ -315,23 +286,23 @@ int TcpReassembler::purge_to_seq(TcpReassemblerState& trs, uint32_t flush_seq)
      * wouldn't be updated for the talker in ProcessTcp() since that
      * code specifically looks for the NEXT sequence number.
      */
-    if ( !last_ts )
-        return purged_bytes;
-
-    if ( !trs.server_side )
-    {
-        int32_t delta = last_ts - trs.sos.session->server.get_ts_last();
-        if ( delta > 0 )
-            trs.sos.session->server.set_ts_last(last_ts);
-    }
-    else
+    if ( last_ts )
     {
-        int32_t delta = last_ts - trs.sos.session->client.get_ts_last();
-        if ( delta > 0 )
-            trs.sos.session->client.set_ts_last(last_ts);
+        if ( trs.server_side )
+        {
+            int32_t delta = last_ts - trs.sos.session->client.get_ts_last();
+            if ( delta > 0 )
+                trs.sos.session->client.set_ts_last(last_ts);
+        }
+       else
+        {
+            int32_t delta = last_ts - trs.sos.session->server.get_ts_last();
+            if ( delta > 0 )
+                trs.sos.session->server.set_ts_last(last_ts);
+        }
     }
 
-    return purged_bytes;
+    return total_purged;
 }
 
 // purge_flushed_ackd():
@@ -348,11 +319,11 @@ int TcpReassembler::purge_flushed_ackd(TcpReassemblerState& trs)
     if (!trs.sos.seglist.head)
         return 0;
 
-    seq = trs.sos.seglist.head->seq;
+    seq = trs.sos.seglist.head->i_seq;
 
-    while ( tsn && tsn->buffered )
+    while ( tsn && !tsn->c_len )
     {
-        uint32_t end = tsn->seq + tsn->payload_size;
+        uint32_t end = tsn->i_seq + tsn->i_len;
 
         if ( SEQ_GT(end, trs.tracker->r_win_base) )
         {
@@ -362,7 +333,8 @@ int TcpReassembler::purge_flushed_ackd(TcpReassemblerState& trs)
         seq = end;
         tsn = tsn->next;
     }
-    if ( seq != trs.sos.seglist.head->seq )
+
+    if ( seq != trs.sos.seglist.head->i_seq )
         return purge_to_seq(trs, seq);
 
     return 0;
@@ -380,86 +352,73 @@ void TcpReassembler::show_rebuilt_packet(TcpReassemblerState& trs, Packet* pkt)
 uint32_t TcpReassembler::get_flush_data_len(
     TcpReassemblerState& trs, TcpSegmentNode* tsn, uint32_t to_seq, unsigned max)
 {
-    unsigned int flushSize = tsn->payload_size;
-
-    if ( flushSize > max )
-        flushSize = max;
+    unsigned int flush_len = ( tsn->c_len <= max ) ? tsn->c_len : max;
 
     // copy only to flush point
-    if ( paf_active(&trs.tracker->paf_state) && SEQ_GT(tsn->seq + flushSize, to_seq) )
-        flushSize = to_seq - tsn->seq;
+    if ( paf_active(&trs.tracker->paf_state) && SEQ_GT(tsn->c_seq + flush_len, to_seq) )
+        flush_len = to_seq - tsn->c_seq;
 
-    return flushSize;
+    return flush_len;
 }
 
 // flush the client trs.sos.seglist up to the most recently acked segment
 int TcpReassembler::flush_data_segments(
     TcpReassemblerState& trs, Packet* p, uint32_t total, Packet* pdu)
 {
-    uint32_t bytes_flushed = 0;
-    uint32_t segs = 0;
+    uint32_t total_flushed = 0;
     uint32_t flags = PKT_PDU_HEAD;
 
-    assert(trs.sos.seglist.next);
+    assert(trs.sos.seglist.cur_rseg);
     DeepProfile profile(s5TcpBuildPacketPerfStats);
 
-    uint32_t to_seq = trs.sos.seglist.next->seq + total;
+    uint32_t to_seq = trs.sos.seglist.cur_rseg->c_seq + total;
 
-    while ( SEQ_LT(trs.sos.seglist.next->seq, to_seq) )
+    while ( SEQ_LT(trs.sos.seglist.cur_rseg->c_seq, to_seq) )
     {
-        TcpSegmentNode* tsn = trs.sos.seglist.next, * sr = nullptr;
+        TcpSegmentNode* tsn = trs.sos.seglist.cur_rseg;
+        unsigned bytes_copied = 0;
         unsigned bytes_to_copy = get_flush_data_len(
             trs, tsn, to_seq, trs.tracker->splitter->max(p->flow));
-        unsigned bytes_copied = 0;
         assert(bytes_to_copy);
 
-        if ( !tsn->next or (bytes_to_copy < tsn->payload_size) or
-            SEQ_EQ(tsn->seq +  bytes_to_copy, to_seq) or
-            (bytes_flushed + tsn->payload_size + tsn->next->payload_size >
+        if ( !tsn->next or (bytes_to_copy < tsn->c_len) or
+            SEQ_EQ(tsn->c_seq + bytes_to_copy, to_seq) or
+            (total_flushed + tsn->c_len + tsn->next->c_len >
                 trs.tracker->splitter->get_max_pdu()) )
         {
             flags |= PKT_PDU_TAIL;
         }
         const StreamBuffer sb = trs.tracker->splitter->reassemble(
-            trs.sos.session->flow, total, bytes_flushed, tsn->payload(),
+            trs.sos.session->flow, total, total_flushed, tsn->payload(),
             bytes_to_copy, flags, bytes_copied);
 
-        flags = 0;
-
         if ( sb.data )
         {
             pdu->data = sb.data;
             pdu->dsize = sb.length;
             assert(sb.length <= Packet::max_dsize);
-
-            bytes_to_copy = bytes_copied;
         }
-        assert(bytes_to_copy == bytes_copied);
-        bytes_flushed += bytes_to_copy;
 
-        if ( bytes_to_copy < tsn->payload_size
-            && dup_reassembly_segment(trs, tsn, &sr) == STREAM_INSERT_OK )
+        total_flushed += bytes_copied;
+        tsn->c_seq += bytes_copied;
+        tsn->c_len -= bytes_copied;
+        tsn->offset += bytes_copied;
+        tsn->last_flush_len = bytes_copied;
+        flags = 0;
+
+        if ( !tsn->c_len )
         {
-            tsn->payload_size = bytes_to_copy;
-            sr->seq += bytes_to_copy;
-            sr->payload_size -= bytes_to_copy;
-            sr->offset += bytes_to_copy;
+            trs.flush_count++;
+            update_next(trs, *tsn);
+            if ( SEQ_EQ(tsn->c_seq, to_seq) )
+                break;
         }
-        tsn->buffered = true;
-        trs.flush_count++;
-        segs++;
-
-        update_next(trs, *tsn);
-
-        if ( SEQ_EQ(tsn->seq + bytes_to_copy, to_seq) )
-            break;
 
         /* Check for a gap/missing packet */
         // FIXIT-L PAF should account for missing data and resume
         // scanning at the start of next PDU instead of aborting.
         // FIXIT-L FIN may be in to_seq causing bogus gap counts.
-        if (((tsn->next && (tsn->seq + tsn->payload_size != tsn->next->seq))
-            || (!tsn->next && (tsn->seq + tsn->payload_size < to_seq))))
+        if ( tsn->is_packet_missing(to_seq) )
         {
             // FIXIT-L this is suboptimal - better to exclude fin from to_seq
             if ( !trs.tracker->is_fin_seq_set() or
@@ -470,15 +429,13 @@ int TcpReassembler::flush_data_segments(
             break;
         }
 
-        if ( sb.data || !trs.sos.seglist.next )
-            break;
-
-        if ( bytes_flushed + trs.sos.seglist.next->payload_size >
-            trs.tracker->splitter->get_max_pdu() )
+        if ( ( sb.data || !trs.sos.seglist.cur_rseg ) or
+             ( ( total_flushed + trs.sos.seglist.cur_rseg->c_len ) >
+                 trs.tracker->splitter->get_max_pdu() ) )
             break;
     }
 
-    return bytes_flushed;
+    return total_flushed;
 }
 
 // FIXIT-L consolidate encode format, update, and this into new function?
@@ -565,11 +522,11 @@ int TcpReassembler::_flush_to_seq(
     }
 
     uint32_t bytes_processed = 0;
-    uint32_t stop_seq = trs.sos.seglist.next->seq + bytes;
+    uint32_t stop_seq = trs.sos.seglist.cur_rseg->c_seq + bytes;
 
-    while ( trs.sos.seglist.next and SEQ_LT(trs.sos.seglist.next->seq, stop_seq) )
+    while ( trs.sos.seglist.cur_rseg and SEQ_LT(trs.sos.seglist.cur_rseg->c_seq, stop_seq) )
     {
-        trs.sos.seglist_base_seq = trs.sos.seglist.next->seq;
+        trs.sos.seglist_base_seq = trs.sos.seglist.cur_rseg->c_seq;
         uint32_t footprint = stop_seq - trs.sos.seglist_base_seq;
 
         if ( footprint == 0 )
@@ -583,7 +540,7 @@ int TcpReassembler::_flush_to_seq(
             ( trs.tracker->get_tf_flags() & TF_MISSING_PREV_PKT ) )
             fallback(trs);
 
-        Packet* pdu = initialize_pdu(trs, p, pkt_flags, trs.sos.seglist.next->tv);
+        Packet* pdu = initialize_pdu(trs, p, pkt_flags, trs.sos.seglist.cur_rseg->tv);
         int32_t flushed_bytes = flush_data_segments(trs, p, footprint, pdu);
         if ( flushed_bytes == 0 )
             break; /* No more data... bail */
@@ -636,24 +593,20 @@ int TcpReassembler::_flush_to_seq(
 int TcpReassembler::flush_to_seq(
     TcpReassemblerState& trs, uint32_t bytes, Packet* p, uint32_t pkt_flags)
 {
-    if ( !bytes || !trs.sos.seglist.next )
-    {
+    if ( !bytes || !trs.sos.seglist.cur_rseg )
         return 0;
-    }
 
     if ( !flush_data_ready(trs) and !(trs.tracker->get_tf_flags() & TF_FORCE_FLUSH) and
         !trs.tracker->splitter->is_paf() )
-    {
         return 0;
-    }
 
     trs.tracker->clear_tf_flags(TF_MISSING_PKT | TF_MISSING_PREV_PKT);
 
     /* This will set this flag on the first reassembly
      * if reassembly for this direction was set midstream */
-    if ( SEQ_LT(trs.sos.seglist_base_seq, trs.sos.seglist.next->seq) )
+    if ( SEQ_LT(trs.sos.seglist_base_seq, trs.sos.seglist.cur_rseg->c_seq) )
     {
-        uint32_t missed = trs.sos.seglist.next->seq - trs.sos.seglist_base_seq;
+        uint32_t missed = trs.sos.seglist.cur_rseg->c_seq - trs.sos.seglist_base_seq;
 
         if ( missed <= bytes )
             bytes -= missed;
@@ -661,7 +614,7 @@ int TcpReassembler::flush_to_seq(
         trs.tracker->set_tf_flags(TF_MISSING_PREV_PKT | TF_PKT_MISSED);
 
         tcpStats.gaps++;
-        trs.sos.seglist_base_seq = trs.sos.seglist.next->seq;
+        trs.sos.seglist_base_seq = trs.sos.seglist.cur_rseg->c_seq;
 
         if ( !bytes )
             return 0;
@@ -729,18 +682,21 @@ uint32_t TcpReassembler::get_q_sequenced(TcpReassemblerState& trs)
 {
     TcpSegmentNode* tsn;
 
-    if ( trs.sos.seglist.next )
-        tsn = trs.sos.seglist.next;
+    if ( trs.sos.seglist.cur_rseg )
+        tsn = trs.sos.seglist.cur_rseg;
     else
     {
-        trs.sos.seglist.next = trs.sos.seglist.head;
-        tsn = trs.tracker ? trs.sos.seglist.next : nullptr;  // FIXIT-H why check tracker here?
+        trs.sos.seglist.cur_rseg = trs.sos.seglist.head;
+        tsn = trs.tracker ? trs.sos.seglist.cur_rseg : nullptr;  // FIXIT-H why check tracker here?
 
         if ( !tsn or (trs.sos.session->flow->two_way_traffic() and
-            SEQ_LT(trs.tracker->r_win_base, tsn->seq)) )
+            SEQ_LT(trs.tracker->r_win_base, tsn->c_seq)) )
         {
-            if ( trs.sos.seglist.next )
-                trs.sos.seglist.next = trs.sos.seglist.next->prev;
+            if ( trs.sos.seglist.cur_rseg )
+                trs.sos.seglist.cur_rseg = trs.sos.seglist.cur_rseg->prev;
+
+            if ( trs.sos.seglist.cur_rseg )
+               trs.sos.seglist.cur_rseg->c_seq = trs.sos.seglist.cur_rseg->i_seq;
             return 0;
         }
     }
@@ -750,17 +706,17 @@ uint32_t TcpReassembler::get_q_sequenced(TcpReassemblerState& trs)
 
     while ( len < limit and next_no_gap(*tsn) )
     {
-        if ( tsn->buffered )
-            trs.sos.seglist.next = tsn->next;
+        if ( !tsn->c_len )
+            trs.sos.seglist.cur_rseg = tsn->next;
         else
-            len += tsn->payload_size;
+            len += tsn->c_len;
 
         tsn = tsn->next;
     }
-    if ( !tsn->buffered )
-        len += tsn->payload_size;
+    if ( tsn->c_len )
+        len += tsn->c_len;
 
-    trs.sos.seglist_base_seq = trs.sos.seglist.next->seq;
+    trs.sos.seglist_base_seq = trs.sos.seglist.cur_rseg->c_seq;
 
     return len;
 }
@@ -849,9 +805,7 @@ void TcpReassembler::flush_queued_segments(
         and (!trs.tracker->splitter or trs.tracker->splitter->finish(flow) );
 
     if ( pending and !(flow->ssn_state.ignore_direction & trs.ignore_dir) )
-    {
         final_flush(trs, p, trs.packet_dir);
-    }
 }
 
 // this is for post-ack flushing
@@ -898,14 +852,14 @@ int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags)
     TcpSegmentNode* tsn;
 
     avail = get_q_sequenced(trs);
-    tsn = trs.sos.seglist.next;
+    tsn = trs.sos.seglist.cur_rseg;
 
     // * must stop if gap (checked in paf_check)
     while ( tsn && *flags && ( total < avail ) )
     {
         int32_t flush_pt;
-        uint32_t size = tsn->payload_size;
-        uint32_t end = tsn->seq + tsn->payload_size;
+        uint32_t size = tsn->c_len;
+        uint32_t end = tsn->c_seq + tsn->c_len;
         uint32_t pos = paf_position(&trs.tracker->paf_state);
 
         total += size;
@@ -918,7 +872,7 @@ int32_t TcpReassembler::flush_pdu_ips(TcpReassemblerState& trs, uint32_t* flags)
 
         flush_pt = paf_check(
             trs.tracker->splitter, &trs.tracker->paf_state, trs.sos.session->flow,
-            tsn->payload(), size, total, tsn->seq, flags);
+            tsn->payload(), size, total, tsn->c_seq, flags);
 
         if (flush_pt >= 0)
         {
@@ -975,11 +929,11 @@ int32_t TcpReassembler::flush_pdu_ackd(TcpReassemblerState& trs, uint32_t* flags
     // must stop if not acked
     // must use adjusted size of tsn if not fully acked
     // must stop if gap (checked in paf_check)
-    while (tsn && *flags && SEQ_LT(tsn->seq, trs.tracker->r_win_base))
+    while (tsn && *flags && SEQ_LT(tsn->c_seq, trs.tracker->r_win_base))
     {
         int32_t flush_pt;
-        uint32_t size = tsn->payload_size;
-        uint32_t end = tsn->seq + tsn->payload_size;
+        uint32_t size = tsn->c_len;
+        uint32_t end = tsn->c_seq + tsn->c_len;
         uint32_t pos = paf_position(&trs.tracker->paf_state);
 
         if ( paf_initialized(&trs.tracker->paf_state) && SEQ_LEQ(end, pos) )
@@ -988,17 +942,19 @@ int32_t TcpReassembler::flush_pdu_ackd(TcpReassemblerState& trs, uint32_t* flags
             tsn = tsn->next;
             continue;
         }
+
         if ( SEQ_GT(end, trs.tracker->r_win_base))
-            size = trs.tracker->r_win_base - tsn->seq;
+            size = trs.tracker->r_win_base - tsn->c_seq;
 
         total += size;
-
         flush_pt = paf_check(
             trs.tracker->splitter, &trs.tracker->paf_state, trs.sos.session->flow,
-            tsn->payload(), size, total, tsn->seq, flags);
+            tsn->payload(), size, total, tsn->c_seq, flags);
 
         if ( flush_pt >= 0 )
         {
+               trs.sos.seglist.cur_rseg = trs.sos.seglist.head;
+               trs.sos.seglist_base_seq = trs.sos.seglist.head->c_seq;
             // for non-paf splitters, flush_pt > 0 means we reached
             // the minimum required, but we flush what is available
             // instead of creating more, but smaller, packets
@@ -1039,36 +995,15 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p)
     {
         uint32_t flags = get_forward_packet_dir(trs, p);
         int32_t flush_amt = flush_pdu_ips(trs, &flags);
-        uint32_t this_flush;
 
         while ( flush_amt >= 0 )
         {
             if ( !flush_amt )
-                flush_amt = trs.sos.seglist.next->seq - trs.sos.seglist_base_seq;
-#if 0
-// FIXIT-P can't do this with new HI - copy is inevitable
-            // if this payload is exactly one pdu, don't
-            // actually flush, just use the raw packet
-            if ( listener->trs.sos.seglist.next &&
-                ( tsd.seq == listener->trs.sos.seglist.next->seq ) &&
-                ( flush_amt == listener->trs.sos.seglist.next->payload_size ) &&
-                ( flush_amt == p->dsize ) )
-            {
-                this_flush = flush_amt;
-                listener->trs.sos.seglist.next->buffered = true;
-                listener->flush_count++;
-                p->packet_flags |= PKT_PDU_FULL;
-                ShowRebuiltPacket(p);
-            }
-            else
-#endif
-            {
-                this_flush = flush_to_seq(trs, flush_amt, p, flags);
-            }
-            // if we didn't flush as expected, bail
-            // (we can flush less than max dsize)
+                flush_amt = trs.sos.seglist.cur_rseg->c_seq - trs.sos.seglist_base_seq;
+
+            uint32_t this_flush = flush_to_seq(trs, flush_amt, p, flags);
             if (!this_flush)
-                break;
+                break;       // bail if nothing flushed
 
             flushed += this_flush;
             flags = get_forward_packet_dir(trs, p);
@@ -1083,12 +1018,13 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p)
     }
     break;
     }
+
     return flushed;
 }
 
 int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p)
 {
-    uint32_t flushed = 0;
+       uint32_t flushed = 0;
 
     switch (trs.tracker->flush_policy)
     {
@@ -1103,27 +1039,21 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p)
         while (flush_amt >= 0)
         {
             if (!flush_amt)
-                flush_amt = trs.sos.seglist.next->seq - trs.sos.seglist_base_seq;
-
-            trs.sos.seglist.next = trs.sos.seglist.head;
-            trs.sos.seglist_base_seq = trs.sos.seglist.head->seq;
+                flush_amt = trs.sos.seglist.cur_rseg->c_seq - trs.sos.seglist_base_seq;
 
             // for consistency with other cases, should return total
             // but that breaks flushing pipelined pdus
             flushed = flush_to_seq(trs, flush_amt, p, flags);
 
-            // ideally we would purge just once after this loop
-            // but that throws off base
+            // ideally we would purge just once after this loop but that throws off base
             if ( flushed and trs.sos.seglist.head )
-                purge_to_seq(trs, trs.sos.seglist.head->seq + flushed);
-
-            // if we didn't flush as expected, bail
-            // (we can flush less than max dsize)
-            if (!flushed)
-                break;
-
-            flags = get_reverse_packet_dir(trs, p);
-            flush_amt = flush_pdu_ackd(trs, &flags);
+            {
+                purge_to_seq(trs, trs.sos.seglist_base_seq);
+                flags = get_reverse_packet_dir(trs, p);
+                flush_amt = flush_pdu_ackd(trs, &flags);
+            }
+            else
+                break;  // bail if nothing flushed
         }
 
         if (!flags && trs.tracker->splitter->is_paf())
@@ -1172,34 +1102,28 @@ void TcpReassembler::insert_segment_in_empty_seglist(
 
     // BLOCK add new block to trs.sos.seglist containing data
     add_reassembly_segment(
-        trs, tsd, tsd.get_seg_len(), overlap, 0, tsd.get_seg_seq() + overlap, nullptr);
+        trs, tsd, tsd.get_seg_len(), overlap, 0, seq + overlap, nullptr);
 
 }
 
 void TcpReassembler::init_overlap_editor(
     TcpReassemblerState& trs, TcpSegmentDescriptor& tsd)
 {
-    TcpSegmentNode* left = nullptr;
-    TcpSegmentNode* right = nullptr;
-    TcpSegmentNode* tsn = nullptr;
-
-    int32_t dist_head;
-    int32_t dist_tail;
+    TcpSegmentNode* left = nullptr, *right = nullptr, *tsn = nullptr;
+    int32_t dist_head = 0, dist_tail = 0;
 
     if ( trs.sos.seglist.head && trs.sos.seglist.tail )
     {
-        if ( SEQ_GT(tsd.get_seg_seq(), trs.sos.seglist.head->seq) )
-            dist_head = tsd.get_seg_seq() - trs.sos.seglist.head->seq;
+        if ( SEQ_GT(tsd.get_seg_seq(), trs.sos.seglist.head->i_seq) )
+            dist_head = tsd.get_seg_seq() - trs.sos.seglist.head->i_seq;
         else
-            dist_head = trs.sos.seglist.head->seq - tsd.get_seg_seq();
+            dist_head = trs.sos.seglist.head->i_seq - tsd.get_seg_seq();
 
-        if ( SEQ_GT(tsd.get_seg_seq(), trs.sos.seglist.tail->seq) )
-            dist_tail = tsd.get_seg_seq() - trs.sos.seglist.tail->seq;
+        if ( SEQ_GT(tsd.get_seg_seq(), trs.sos.seglist.tail->i_seq) )
+            dist_tail = tsd.get_seg_seq() - trs.sos.seglist.tail->i_seq;
         else
-            dist_tail = trs.sos.seglist.tail->seq - tsd.get_seg_seq();
+            dist_tail = trs.sos.seglist.tail->i_seq - tsd.get_seg_seq();
     }
-    else
-        dist_head = dist_tail = 0;
 
     if ( SEQ_LEQ(dist_head, dist_tail) )
     {
@@ -1207,7 +1131,7 @@ void TcpReassembler::init_overlap_editor(
         {
             right = tsn;
 
-            if ( SEQ_GEQ(right->seq, tsd.get_seg_seq() ) )
+            if ( SEQ_GEQ(right->i_seq, tsd.get_seg_seq() ) )
                 break;
 
             left = right;
@@ -1222,7 +1146,7 @@ void TcpReassembler::init_overlap_editor(
         {
             left = tsn;
 
-            if ( SEQ_LT(left->seq, tsd.get_seg_seq() ) )
+            if ( SEQ_LT(left->i_seq, tsd.get_seg_seq() ) )
                 break;
 
             right = left;
@@ -1232,7 +1156,6 @@ void TcpReassembler::init_overlap_editor(
             left = nullptr;
     }
 
-
     trs.sos.init_soe(tsd, left, right);
 }
 
@@ -1245,10 +1168,8 @@ int TcpReassembler::insert_segment_in_seglist(
     if ( trs.sos.seglist.tail && is_segment_fasttrack(trs, trs.sos.seglist.tail, tsd) )
     {
         /* segment fit cleanly at the end of the segment list */
-        TcpSegmentNode* left = trs.sos.seglist.tail;
-        
-        // BLOCK add to existing block and/or allocate new block
-        rc = add_reassembly_segment(trs, tsd, tsd.get_seg_len(), 0, 0, tsd.get_seg_seq(), left);
+        rc = add_reassembly_segment(trs, tsd, tsd.get_seg_len(), 0, 0,
+                       tsd.get_seg_seq(), trs.sos.seglist.tail);
         return rc;
     }
 
@@ -1271,9 +1192,7 @@ int TcpReassembler::insert_segment_in_seglist(
             trs, tsd, trs.sos.len, trs.sos.slide, trs.sos.trunc_len, trs.sos.seq, trs.sos.left);
     }
     else
-    {
         rc = STREAM_INSERT_OK;
-    }
 
     return rc;
 }
@@ -1308,22 +1227,3 @@ int TcpReassembler::queue_packet_for_reassembly(
     return rc;
 }
 
-#ifdef SEG_TEST
-static void CheckSegments(const TcpStreamtrs.tracker* a)
-{
-    TcpSegmentNode* tsn = a->trs.sos.seglist.head;
-    uint32_t sx = tsn ? tsn->seq : 0;
-
-    while ( tsn )
-    {
-        if ( SEQ_GT(sx, tsn->seq) )
-        {
-            const int SEGBORK = 0;
-            assert(SEGBORK);
-        }
-        sx = tsn->seq + tsn->payload_size;
-        tsn = tsn->next;
-    }
-}
-#endif
-
index b59a2105ecd3dc407fad266e4792db8c0f0183f1..b66e8d78f17a589949313e0758d45ed1981f8f5c 100644 (file)
@@ -52,14 +52,10 @@ protected:
 
     int dup_reassembly_segment(
         TcpReassemblerState&, TcpSegmentNode* left, TcpSegmentNode** retSeg) override;
-
     int delete_reassembly_segment(TcpReassemblerState&, TcpSegmentNode*) override;
-
     virtual void insert_segment_in_empty_seglist(TcpReassemblerState&, TcpSegmentDescriptor&);
     virtual int insert_segment_in_seglist(TcpReassemblerState&, TcpSegmentDescriptor&);
-
     virtual uint32_t get_pending_segment_count(TcpReassemblerState&, unsigned max);
-
     bool flush_data_ready(TcpReassemblerState&);
     int trim_delete_reassembly_segment(TcpReassemblerState&, TcpSegmentNode*, uint32_t flush_seq);
     void queue_reassembly_segment(TcpReassemblerState&, TcpSegmentNode* prev, TcpSegmentNode*);
@@ -67,7 +63,6 @@ protected:
     bool is_segment_fasttrack(TcpReassemblerState&, TcpSegmentNode* tail, TcpSegmentDescriptor&);
     int purge_alerts(TcpReassemblerState&, snort::Flow*);
     void show_rebuilt_packet(TcpReassemblerState&, snort::Packet*);
-
     uint32_t get_flush_data_len(
         TcpReassemblerState&, TcpSegmentNode*, uint32_t to_seq, unsigned max);
     int flush_data_segments(
@@ -77,7 +72,6 @@ protected:
         snort::Packet* pdu);
     snort::Packet* initialize_pdu(
         TcpReassemblerState&, snort::Packet* p, uint32_t pkt_flags, struct timeval tv);
-
     int _flush_to_seq(TcpReassemblerState&, uint32_t bytes, snort::Packet*, uint32_t pkt_flags);
     int flush_to_seq(TcpReassemblerState&, uint32_t bytes, snort::Packet*, uint32_t pkt_flags);
     int do_zero_byte_flush(TcpReassemblerState&, snort::Packet* p, uint32_t pkt_flags);
index 47b19bb0a446f214d94d73a3e1f27e313883e843..0d2d02ef67b212f0fabeb3afe896a4d8d03800a9 100644 (file)
 #include "segment_overlap_editor.h"
 #include "tcp_module.h"
 
-// FIXIT-P this is going to set each member 2X; once here and once in init
-// separate ctors with default initializers would set them only once
-TcpSegmentNode::TcpSegmentNode() :
-    prev(nullptr), next(nullptr), data(nullptr),
-    tv({ 0, 0 }), ts(0), seq(0), offset(0), orig_dsize(0),
-    payload_size(0), urg_offset(0), buffered(false)
+TcpSegmentNode::TcpSegmentNode(const struct timeval& tv, const uint8_t* payload, uint16_t len) :
+    prev(nullptr), next(nullptr), tv(tv), ts(0), i_seq(0), c_seq(0), i_len(len),
+    c_len(len), offset(0), last_flush_len(0), urg_offset(0)
 {
+    data = ( uint8_t* )snort_alloc(len);
+    memcpy(data, payload, len);
+    tcpStats.mem_in_use += len;
 }
 
 //-------------------------------------------------------------------------
@@ -44,45 +44,32 @@ TcpSegmentNode::TcpSegmentNode() :
 //-------------------------------------------------------------------------
 TcpSegmentNode* TcpSegmentNode::init(TcpSegmentDescriptor& tsd)
 {
-    return init(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_seg_len() );
+    return new TcpSegmentNode(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_seg_len());
 }
 
 TcpSegmentNode* TcpSegmentNode::init(TcpSegmentNode& tns)
 {
-    return init(tns.tv, tns.payload(), tns.payload_size);
-}
-
-TcpSegmentNode* TcpSegmentNode::init(const struct timeval& tv, const uint8_t* data, unsigned dsize)
-{
-    TcpSegmentNode* ss = new TcpSegmentNode;
-    ss->data = ( uint8_t* )snort_alloc(dsize);
-    memcpy(ss->data, data, dsize);
-    ss->offset = 0;
-    ss->tv = tv;
-    ss->orig_dsize = dsize;
-    ss->payload_size = ss->orig_dsize;
-    tcpStats.mem_in_use += dsize;
-    return ss;
+    return new TcpSegmentNode(tns.tv, tns.payload(), tns.c_len);
 }
 
 void TcpSegmentNode::term()
 {
     snort_free(data);
     tcpStats.segs_released++;
-    tcpStats.mem_in_use -= orig_dsize;
+    tcpStats.mem_in_use -= i_len;
     delete this;
 }
 
 bool TcpSegmentNode::is_retransmit(const uint8_t* rdata, uint16_t rsize, uint32_t rseq, uint16_t orig_dsize, bool *full_retransmit)
 {
     // retransmit must have same payload at same place
-    if ( !SEQ_EQ(seq, rseq) )
+    if ( !SEQ_EQ(i_seq, rseq) )
         return false;
 
-    if( orig_dsize == payload_size )
+    if( orig_dsize == c_len )
     {
-        if ( ( ( payload_size <= rsize )and !memcmp(data, rdata, payload_size) )
-            or ( ( payload_size > rsize )and !memcmp(data, rdata, rsize) ) )
+        if ( ( ( c_len <= rsize )and !memcmp(data, rdata, c_len) )
+            or ( ( c_len > rsize )and !memcmp(data, rdata, rsize) ) )
         {
             return true;
         }
index 8092ab87d7385e3577cad2556ca301a92c5e7611..0d12dcb8472e4acf1eef722b33bc876b97af6d8a 100644 (file)
@@ -34,9 +34,10 @@ class TcpSegmentDescriptor;
 // ... however, use of padding below is critical, adjust if needed
 //-----------------------------------------------------------------
 
-struct TcpSegmentNode
+class TcpSegmentNode
 {
-    TcpSegmentNode();
+public:
+       TcpSegmentNode(const struct timeval& tv, const uint8_t* segment, uint16_t len);
 
     static TcpSegmentNode* init(TcpSegmentDescriptor& tsd);
     static TcpSegmentNode* init(TcpSegmentNode& tns);
@@ -44,10 +45,17 @@ struct TcpSegmentNode
 
     void term();
     bool is_retransmit(const uint8_t*, uint16_t size, uint32_t, uint16_t, bool*);
-
     uint8_t* payload()
     { return data + offset; }
 
+    bool is_packet_missing(uint32_t to_seq)
+    {
+        if ( next )
+            return (i_seq + i_len) != next->i_seq;
+        else
+            return (c_seq + c_len) < to_seq;
+    }
+
     TcpSegmentNode* prev;
     TcpSegmentNode* next;
 
@@ -55,14 +63,13 @@ struct TcpSegmentNode
 
     struct timeval tv;
     uint32_t ts;
-    uint32_t seq;
-
+    uint32_t i_seq;             // initial seq # of the data segment
+    uint32_t c_seq;             // current seq # of data for reassembly
+    uint16_t i_len;             // initial length of the data segment
+    uint16_t c_len;             // length of data remaining for reassembly
     uint16_t offset;
-    uint16_t orig_dsize;
-    uint16_t payload_size;
+    uint16_t last_flush_len;
     uint16_t urg_offset;
-
-    bool buffered;
 };
 
 class TcpSegmentList
@@ -77,10 +84,10 @@ public:
             i++;
             TcpSegmentNode* dump_me = head;
             head = head->next;
-            dump_me->term( );
+            dump_me->term();
         }
 
-        head = tail = next = nullptr;
+        head = tail = cur_rseg = nullptr;
         count = 0;
         return i;
     }
@@ -114,12 +121,12 @@ public:
 
     void remove(TcpSegmentNode* ss)
     {
-        if (ss->prev)
+        if ( ss->prev )
             ss->prev->next = ss->next;
         else
             head = ss->next;
 
-        if (ss->next)
+        if ( ss->next )
             ss->next->prev = ss->prev;
         else
             tail = ss->prev;
@@ -129,12 +136,7 @@ public:
 
     TcpSegmentNode* head = nullptr;
     TcpSegmentNode* tail = nullptr;
-
-    // FIXIT-P seglist_base_seq is the sequence number to flush from
-    // and is valid even when seglist is empty.  next points to
-    // the segment to flush from and is set per packet.  should keep
-    // up to date.
-    TcpSegmentNode* next = nullptr;
+    TcpSegmentNode* cur_rseg = nullptr;
     uint32_t count = 0;
 };