aboutsummaryrefslogtreecommitdiffstats
path: root/epan/reassemble.c
diff options
context:
space:
mode:
authorJohn Thacker <johnthacker@gmail.com>2022-04-07 20:30:48 -0400
committerA Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2022-05-26 00:49:16 +0000
commit7ab343e7d6012dc9c5bb74d1e71d0e775291467a (patch)
treef1f18336e537d4060317ba963e0e0ee226cb9171 /epan/reassemble.c
parentab33d9b8092d89550f82678caea40a6f29b5c4d9 (diff)
tcp: Split MSPs in out of order processing
When processing segments out of order in TCP, it is possible to get new segments that fill a sequence gap and be able to dissect at least one PDU but need more data for additional PDUs (that have data from the contiguous stream bytes.) We can only determine this after passing the reassembled segments to the subdissector first. To keep dissection and layer numbers consistent between passes, split the multisegment PDU, keeping the already dissect PDU(s) in the current reassembly and creating a new MSP for the parts not yet dissected. Update the dissection test to enable the currently skipped test that require MSP splitting and remove test_tcp_out_of_order_twopass_with_bug
Diffstat (limited to 'epan/reassemble.c')
-rw-r--r--epan/reassemble.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/epan/reassemble.c b/epan/reassemble.c
index 3bc7d42090..672d2c554f 100644
--- a/epan/reassemble.c
+++ b/epan/reassemble.c
@@ -797,6 +797,85 @@ fragment_reset_tot_len(reassembly_table *table, const packet_info *pinfo,
fd_head->flags |= FD_DATALEN_SET;
}
+void
+fragment_truncate(reassembly_table *table, const packet_info *pinfo,
+ const guint32 id, const void *data, const guint32 tot_len)
+
+{
+ tvbuff_t *old_tvb_data;
+ fragment_head *fd_head;
+
+ fd_head = lookup_fd_head(table, pinfo, id, data, NULL);
+ if (!fd_head)
+ return;
+
+ /* Caller must ensure that this function is only called when
+ * we are defragmented. */
+ DISSECTOR_ASSERT(fd_head->flags & FD_DEFRAGMENTED);
+
+ /*
+ * If FD_PARTIAL_REASSEMBLY is set, it would make the next fragment_add
+ * call set the reassembled length based on the fragment offset and
+ * length. As the length is known now, be sure to disable that magic.
+ */
+ fd_head->flags &= ~FD_PARTIAL_REASSEMBLY;
+
+ /* If the length is already as expected, there is nothing else to do. */
+ if (tot_len == fd_head->datalen)
+ return;
+
+ DISSECTOR_ASSERT(fd_head->datalen > tot_len);
+
+ old_tvb_data=fd_head->tvb_data;
+ fd_head->tvb_data = tvb_clone_offset_len(old_tvb_data, 0, tot_len);
+ tvb_set_free_cb(fd_head->tvb_data, g_free);
+
+ if (old_tvb_data)
+ tvb_add_to_chain(fd_head->tvb_data, old_tvb_data);
+ fd_head->datalen = tot_len;
+
+ /* Keep the fragments before the split point, dividing any if
+ * necessary.
+ * XXX: In rare cases, there might be fragments marked as overlap that
+ * have data both before and after the split point, and which only
+ * overlap after the split point. In that case, after dividing the
+ * fragments the first part no longer overlap.
+ * However, at this point we can't test for overlap conflicts,
+ * so we'll just leave the overlap flags as-is.
+ */
+ fd_head->flags &= ~(FD_OVERLAP|FD_OVERLAPCONFLICT|FD_TOOLONGFRAGMENT|FD_MULTIPLETAILS);
+ fragment_item *fd_i, *prev_fd = fd_head;
+ for (fd_i = fd_head->next; fd_i && (fd_i->offset < tot_len); fd_i = fd_i->next) {
+ fd_i->flags &= ~(FD_TOOLONGFRAGMENT|FD_MULTIPLETAILS);
+ /* Check for the split point occuring in the middle of the
+ * fragment. */
+ if (fd_i->offset + fd_i->len > tot_len) {
+ fd_i->len = tot_len - fd_i->offset;
+ }
+ fd_head->flags |= fd_i->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT);
+ prev_fd = fd_i;
+
+ /* Below should do nothing since this is already defragmented */
+ if (fd_i->flags & FD_SUBSET_TVB)
+ fd_i->flags &= ~FD_SUBSET_TVB;
+ else if (fd_i->tvb_data)
+ tvb_free(fd_i->tvb_data);
+
+ fd_i->tvb_data=NULL;
+ }
+
+ /* Remove all the other fragments, as they are past the split point. */
+ prev_fd->next = NULL;
+ fragment_item *tmp_fd;
+ for (; fd_i; fd_i = tmp_fd) {
+ tmp_fd=fd_i->next;
+
+ if (fd_i->tvb_data && !(fd_i->flags & FD_SUBSET_TVB))
+ tvb_free(fd_i->tvb_data);
+ g_slice_free(fragment_item, fd_i);
+ }
+}
+
guint32
fragment_get_tot_len(reassembly_table *table, const packet_info *pinfo,
const guint32 id, const void *data)
@@ -812,7 +891,6 @@ fragment_get_tot_len(reassembly_table *table, const packet_info *pinfo,
return 0;
}
-
/* This function will set the partial reassembly flag for a fh.
When this function is called, the fh MUST already exist, i.e.
the fh MUST be created by the initial call to fragment_add() before