問題背景
來自于學習群里群友討論的一個數據包跟蹤文件,在其中涉及到兩處數據包異常現象,而產生這些現象的實際原因是數據包亂序。由于這兩處數據包異常,都有點特別,本篇也就其中一個異常現象單獨展開說明。
問題信息
數據包跟蹤文件基本信息如下:
λ 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`
問題總結
存在即合理,數據包分析也會有這樣的一個觀點,不是嘛。