diff options
author | John Thacker <johnthacker@gmail.com> | 2022-04-07 20:30:48 -0400 |
---|---|---|
committer | A Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org> | 2022-05-26 00:49:16 +0000 |
commit | 7ab343e7d6012dc9c5bb74d1e71d0e775291467a (patch) | |
tree | f1f18336e537d4060317ba963e0e0ee226cb9171 /epan/reassemble.c | |
parent | ab33d9b8092d89550f82678caea40a6f29b5c4d9 (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.c | 80 |
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 |