问题背景
来自于学习群里群友讨论的一个数据包跟踪文件,在其中涉及到两处数据包异常现象,而产生这些现象的实际原因是数据包乱序。由于这两处数据包异常,都有点特别,本篇也就其中一个异常现象单独展开说明。
问题信息
数据包跟踪文件基本信息如下:
λ capinfos test0609.pcapng
File name: test0609.pcapng
File type: Wireshark/... - pcapng
File encapsulation: Ethernet
File timestamp precision: microseconds (6)
Packet size limit: file hdr: (not set)
Packet size limit: inferred: 66 bytes
Number of packets: 44
File size: 5096 bytes
Data size: 4010 bytes
Capture duration: 0.959479 seconds
First packet time: 2024-06-03 19:32:20.136281
Last packet time: 2024-06-03 19:32:21.095760
Data byte rate: 4179 bytes/s
Data bit rate: 33 kbps
Average packet size: 91.14 bytes
Average packet rate: 45 packets/s
SHA256: 6d472bd621d89b2330ceb61a9b14756c7991e157b1e9e8960580379129275bf8
SHA1: c849b01ccdbe4ed131a3c67ac4bb768f7ac680fc
Strict time order: True
Capture application: Editcap (Wireshark) 4.2.5 (v4.2.5-0-g4aa814ac25a1)
Capture comment: Sanitized by TraceWrangler v0.6.8 build 949
Number of interfaces in file: 1
Interface #0 info:Encapsulation = Ethernet (1 - ether)Capture length = 262144Time precision = microseconds (6)Time ticks per second = 1000000Time resolution = 0x06Number of stat entries = 0Number of packets = 44
数据包文件根据 IP 通讯对做过一定过滤,按 66 字节长度做了截断,并且经过 TraceWrangler 匿名化软件处理。捕获总时长 0.95 秒,数据包数量 44 个,速率 33 kbps 。
关于 TraceWrangler 匿名化软件简介,可以查看之前的文章《Wireshark 提示和技巧 | 如何匿名化数据包》。
专家信息如下,仅有一个 Dup ACK 信息,需要进一步分析。
问题分析
数据包跟踪文件展开详细信息如下,粗看下来,除了 TCP Dup ACK
,感觉没有其他什么问题。
什么是 TCP Dup ACK
,简单看下 Wireshark 官方文档对此的定义如下:
- TCP 段大小为 0
- 窗口大小非零且没有改变,或者有有效的 SACK 数据
- Next Seq Num 和最后一次看到的 ACK Num 是非 0 的(即连接已经建立)
- 没有设置 SYN、FIN、RST
Set when all of the following are true:The segment size is zero.
The window size is non-zero and hasn’t changed, or there is valid SACK data.
The next expected sequence number and last-seen acknowledgment number are non-zero (i.e., the connection has been established).
SYN, FIN, and RST are not set.
明白了什么是 TCP Dup ACK
之后,我们继续研究为什么会产生 TCP Dup ACK
,先简单的就数据包展开说明:
- No.10 和 No.11 为服务器端所发送的数据包,其中 No.10 为数据段,Seq Num 70 + Len 12,No.11 为纯 ACK;
- No.12 为客户端对接收到的 No.10 数据包做出的 ACK 响应,ACK Num 为 82;
- 但 No.13 ACK 数据包是什么,为什么会被触发出来?同样的 ACK Num 82 表明并没有确认新数据,而且从上面服务器端发包来看,实际也没有其他数据,所以这个 ACK 符合了
TCP Dup ACK
代码的判断,因此标识。
难道 No.13 是对 No.11 ACK 数据包的 ACK ,也就是 ACK 了一个纯 ACK??? 从常理上来说是不可能的。但为什么会产生这样反常的现象呢,合理还是不合理。
探究 No.13 的由来,就得去找触发的原因,首先还是问题背景章节中提到的数据包乱序,在这里服务器端所发送的 No.10 和 No.11,在客户端接收时已经是乱序了。两个地方说明,一是标准的 Seq Num,如果正常的顺序,No.11 ACK 的 Seq Num 应该为 82 ,但实际为 70 ,说明应该出现在 No.10 之前;二是 ip.id 辅助判断,理论是顺序递增的,而 No.11 的 4916 反而小于 No.10 4917,也说明发生了乱序。
乱序比较常见,但一个纯 ACK 在前,一个数据段在后,单独两者之间出现乱序,确实比较少见,这也是之后触发生成 No.13 比较少见的原因。
继续分析 No.13 TCP Dup ACK
,实际在一开始讨论时,我就表达了这个观点,这个 Dup ACK 的产生比较突兀,ACK 了纯 ACK,这个现象不合理,如果需要用 ACK 来确认 ACK ,那实际在 TCP 数据包中的交互上永远没有停止的时候了。
再之后仔细琢磨了下,确实不会,确实不会出现 ACK 一个 ACK,但这里有一个前提,后一个 ACK 得是正常的,或者说是有效的。而实际上 No.11 对于客户端上来说并不是有效的,因为先收到 No.10 之后,客户端接收窗口已经确认收到了 82 之前的所有数据了,而 No.11 Seq Num 70 小于 82,判断为异常,因此产生出一个 TCP Dup ACK
。
为了验证上述结论,通过 packetdrill 以下代码做了相关测试,结果也符合预期。
# cat dupack.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0+0 < S 0:0(0) win 10000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4+0.01 write(4, ..., 1000) = 1000
+0.01 < . 1:1(0) ack 1001 win 10000
+0.01 < P. 1:11(10) ack 1001 win 10000
+0 < . 1:1(0) ack 1001 win 10000+0 `sleep 10`
问题总结
存在即合理,数据包分析也会有这样的一个观点,不是嘛。