tcp: fix OoO reassembly when the first data packet is OoO
authorPeter Wu <peter@lekensteyn.nl>
Mon, 27 Aug 2018 13:31:03 +0000 (15:31 +0200)
committerAnders Broman <a.broman58@gmail.com>
Thu, 30 Aug 2018 04:07:01 +0000 (04:07 +0000)
OoO reassembly assumed that the stream starts with the first data
segment, but this can already be OoO. Use the hint from SYN instead.
The test capture is based on a local capture, post-processed with scapy
to introduce an OoO condition and fixup the frame time.

Bug: 15078
Change-Id: Id0e312bb3d0e7c7f8f1b243a2be9f15c9851c501
Fixes: v2.9.0rc0-1097-gca42331437 ("tcp: add support for reassembling out-of-order segments")
Reviewed-on: https://code.wireshark.org/review/29305
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
epan/dissectors/packet-tcp.c
test/captures/dns-ooo.pcap [new file with mode: 0644]
test/suite_dissection.py

index 73f4a2647a7f832d781eb3b276327d0993080353..e25f18a487ed30b72d705480895ce6a62b4eb5f0 100644 (file)
@@ -3179,8 +3179,8 @@ again:
              * the MSP is not complete yet. */
         }
         if (tcpd->fwd->maxnextseq == 0 || LT_SEQ(tcpd->fwd->maxnextseq, nxtseq)) {
-            /* Update the maximum expected seqno if unknown or if the new
-             * segment succeeds previous segments. */
+            /* Update the maximum expected seqno if no SYN packet was seen
+             * before, or if the new segment succeeds previous segments. */
             tcpd->fwd->maxnextseq = nxtseq;
         }
     }
@@ -6308,6 +6308,12 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
            tcpd->server_port = tcph->th_dport;
            tcpd->ts_mru_syn = pinfo->abs_ts;
         }
+        /* Remember where the next segment will start. */
+        if (tcp_desegment && tcp_reassemble_out_of_order && tcpd && !PINFO_FD_VISITED(pinfo)) {
+            if (tcpd->fwd->maxnextseq == 0) {
+                tcpd->fwd->maxnextseq = tcph->th_seq + 1;
+            }
+        }
     }
     if(tcph->th_flags & TH_FIN) {
         /* XXX - find a way to know the server port and output only that one */
diff --git a/test/captures/dns-ooo.pcap b/test/captures/dns-ooo.pcap
new file mode 100644 (file)
index 0000000..594b925
Binary files /dev/null and b/test/captures/dns-ooo.pcap differ
index cfec7c4c668a5c33d106212a1802b28084cd9b6f..540fe5a2ef257b0e5fb47bfae3de5970429be581 100644 (file)
@@ -79,3 +79,14 @@ class case_dissect_tcp(subprocesstest.SubprocessTestCase):
         self.assertTrue(self.grepOutput(r'^\s*11\s.*PUT /3 HTTP/1.1'))
         self.assertTrue(self.grepOutput(r'^\s*11\s.*PUT /4 HTTP/1.1'))
         self.assertTrue(self.grepOutput(r'^\s*15\s.*PUT /5 HTTP/1.1'))
+
+    def test_tcp_out_of_order_data_after_syn(self):
+        '''Test when the first non-empty segment is OoO.'''
+        capture_file = os.path.join(config.capture_dir, 'dns-ooo.pcap')
+        proc = self.runProcess((config.cmd_tshark,
+                '-r', capture_file,
+                '-otcp.reassemble_out_of_order:TRUE',
+                '-Y', 'dns', '-Tfields', '-edns.qry.name',
+            ),
+            env=config.test_env)
+        self.assertEqual(proc.stdout_str.strip(), 'example.com')