forked from osmocom/wireshark
tcp: fix reporting of "Reassembled in" for OoO initial segment
When the initial segment is OoO, it was recognized as retransmitted. Fix this by remembering which frame actually contains the initial segment. Bug: 15420 Change-Id: If63e2ff581775ff9d396a612839f1bfab30f111f Reviewed-on: https://code.wireshark.org/review/31720 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Peter Wu <peter@lekensteyn.nl>
This commit is contained in:
parent
394e39117f
commit
0b9b531726
|
@ -1733,6 +1733,7 @@ pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint32 seq, guint32 nx
|
|||
msp->nxtpdu=nxtpdu;
|
||||
msp->seq=seq;
|
||||
msp->first_frame=pinfo->num;
|
||||
msp->first_frame_with_seq=pinfo->num;
|
||||
msp->last_frame=pinfo->num;
|
||||
msp->last_frame_time=pinfo->abs_ts;
|
||||
msp->flags=0;
|
||||
|
@ -3065,6 +3066,7 @@ again:
|
|||
if ((msp = (struct tcp_multisegment_pdu *)wmem_tree_lookup32(tcpd->fwd->multisegment_pdus, seq)) &&
|
||||
!(msp->flags & MSP_FLAGS_MISSING_FIRST_SEGMENT) && msp->last_frame != pinfo->num) {
|
||||
const char* str;
|
||||
gboolean is_retransmission = FALSE;
|
||||
|
||||
/* Yes. This could be because we've dissected this frame before
|
||||
* or because this is a retransmission of a previously-seen
|
||||
|
@ -3074,19 +3076,29 @@ again:
|
|||
* find this retransmission instead of the original transmission
|
||||
* (breaking desegmentation if we'd already linked other segments
|
||||
* to the original transmission's entry).
|
||||
*
|
||||
* Cases to handle here:
|
||||
* - In-order stream, pinfo->num matches begin of MSP.
|
||||
* - In-order stream, but pinfo->num does not match the begin of the
|
||||
* MSP. Must be a retransmission.
|
||||
* - OoO stream where this segment fills the gap in the begin of the
|
||||
* MSP. msp->first_frame is the start where the gap was detected
|
||||
* (and does NOT match pinfo->num).
|
||||
*/
|
||||
|
||||
if (msp->first_frame == pinfo->num) {
|
||||
if (msp->first_frame == pinfo->num || msp->first_frame_with_seq == pinfo->num) {
|
||||
str = "";
|
||||
col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[TCP segment of a reassembled PDU]");
|
||||
} else {
|
||||
str = "Retransmitted ";
|
||||
is_retransmission = TRUE;
|
||||
/* TCP analysis already flags this (in COL_INFO) as a retransmission--if it's enabled */
|
||||
}
|
||||
|
||||
/* Fix for bug 3264: look up ipfd for this (first) segment,
|
||||
so can add tcp.reassembled_in generated field on this code path. */
|
||||
ipfd_head = fragment_get(&tcp_reassembly_table, pinfo, pinfo->num, NULL);
|
||||
if (!is_retransmission) {
|
||||
ipfd_head = fragment_get(&tcp_reassembly_table, pinfo, msp->first_frame, NULL);
|
||||
if (ipfd_head) {
|
||||
if (ipfd_head->reassembled_in != 0) {
|
||||
item = proto_tree_add_uint(tcp_tree, hf_tcp_reassembled_in, tvb, 0,
|
||||
|
@ -3094,6 +3106,7 @@ again:
|
|||
PROTO_ITEM_SET_GENERATED(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nbytes = tvb_reported_length_remaining(tvb, offset);
|
||||
|
||||
|
@ -3242,7 +3255,8 @@ again:
|
|||
|
||||
if (reassemble_ooo && !PINFO_FD_VISITED(pinfo)) {
|
||||
/* If the first segment of the MSP was seen, remember it. */
|
||||
if (msp->seq == seq) {
|
||||
if (msp->seq == seq && msp->flags & MSP_FLAGS_MISSING_FIRST_SEGMENT) {
|
||||
msp->first_frame_with_seq = pinfo->num;
|
||||
msp->flags &= ~MSP_FLAGS_MISSING_FIRST_SEGMENT;
|
||||
}
|
||||
/* Remember when all segments are ready to avoid subsequent
|
||||
|
|
|
@ -170,9 +170,11 @@ struct tcp_acked {
|
|||
struct tcp_multisegment_pdu {
|
||||
guint32 seq;
|
||||
guint32 nxtpdu;
|
||||
guint32 first_frame;
|
||||
guint32 first_frame; /* The frame where this MSP was created (used as key in reassembly tables). */
|
||||
guint32 last_frame;
|
||||
nstime_t last_frame_time;
|
||||
guint32 first_frame_with_seq; /* The frame that contains the first frame that matches 'seq'
|
||||
(same as 'first_frame', larger than 'first_frame' for OoO segments) */
|
||||
guint32 flags;
|
||||
#define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT 0x00000001
|
||||
/* Whether this MSP is finished and no more segments can be added. */
|
||||
|
|
Binary file not shown.
|
@ -87,3 +87,37 @@ class case_dissect_tcp(subprocesstest.SubprocessTestCase):
|
|||
'-Y', 'dns', '-Tfields', '-edns.qry.name',
|
||||
))
|
||||
self.assertEqual(proc.stdout_str.strip(), 'example.com')
|
||||
|
||||
def test_tcp_out_of_order_first_gap(self, cmd_tshark, capture_file):
|
||||
'''
|
||||
Test reporting of "reassembled_in" in the OoO frame that contains the
|
||||
initial segment (Bug 15420). Additionally, test for proper reporting
|
||||
when the initial segment is retransmitted.
|
||||
For PDU H123 (where H is the HTTP Request header and 1, 2 and 3 are part
|
||||
of the body), the order is: (SYN) 2 H H 1 3 H.
|
||||
'''
|
||||
proc = self.assertRun((cmd_tshark,
|
||||
'-r', capture_file('http-ooo2.pcap'),
|
||||
'-otcp.reassemble_out_of_order:TRUE',
|
||||
'-Tfields',
|
||||
'-eframe.number', '-etcp.reassembled_in', '-e_ws.col.Info',
|
||||
'-2',
|
||||
))
|
||||
lines = proc.stdout_str.replace('\r', '').split('\n')
|
||||
# 2 - start of OoO MSP
|
||||
self.assertIn('2\t6\t[TCP Previous segment not captured]', lines[1])
|
||||
self.assertIn('[TCP segment of a reassembled PDU]', lines[1])
|
||||
# H - first time that the start of the MSP is delivered
|
||||
self.assertIn('3\t6\t[TCP Out-Of-Order]', lines[2])
|
||||
self.assertIn('[TCP segment of a reassembled PDU]', lines[2])
|
||||
# H - first retransmission.
|
||||
self.assertIn('4\t\t', lines[3])
|
||||
self.assertNotIn('[TCP segment of a reassembled PDU]', lines[3])
|
||||
# 1 - continue reassembly
|
||||
self.assertIn('5\t6\t[TCP Out-Of-Order]', lines[4])
|
||||
self.assertIn('[TCP segment of a reassembled PDU]', lines[4])
|
||||
# 3 - finish reassembly
|
||||
self.assertIn('6\t\tPUT /0 HTTP/1.1', lines[5])
|
||||
# H - second retransmission.
|
||||
self.assertIn('7\t\t', lines[6])
|
||||
self.assertNotIn('[TCP segment of a reassembled PDU]', lines[6])
|
||||
|
|
Loading…
Reference in New Issue