雁过留声 发表于 2024-12-5 06:24:44

TCP Analysis Flags 之 TCP Spurious Retransmission

媒介

默认情况下,Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态,并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时,会对每个 TCP 数据包进行一次分析,数据包按照它们在数据包列表中出现的顺序进行处置惩罚。可以通过 “Analyze TCP sequence numbers” TCP 解析首选项启用或禁用此功能。
TCP 分析展示

在数据包文件中进行 TCP 分析时,关于 “TCP Spurious Retransmission” 一样平常是如下表现的,包括:

[*]Packet List 窗口中的 Info 信息列,以 黑底红字进行标注;
[*]Packet Details 窗口中的 TCP 协议树下,在 -> 中界说该 TCP 数据包的分析说明。
https://i-blog.csdnimg.cn/img_convert/1b1619b7183a49505b1085f22cdcb382.png
   
[*]考虑到 TCP 乱序、重传场景的复杂性,专家信息在重传的判定上,前面都会有一个(suspected),表现疑似,说明并不是百分百正确,属于 Note 留意。
[*]另在专家信息中,对于 TCP Spurious Retransmission 标志位分析同时会增加两种 Note,包括 Spurious Retransmission 和 Retransmission。
TCP Spurious Retransmission 界说

文档中关于 TCP Spurious Retransmission 的界说看起来简朴,但实际考虑到 TCP 乱序、重传场景的复杂性,在 TCP 分析中对于 TCP Spurious Retransmission 是与 TCP Out-Of-Order、TCP Fast Retransmission、TCP Retransmission 等在一起判定标志乱序或重传类型,而在不少场景还会有判定堕落的问题,固然 Wireshark 考虑到这种情况,也有手动修正的选项,这恰好也侧面证明了上面的说法,关于 TCP 乱序、重传的复杂性。
TCP Spurious Retransmission 的界说如下,当以下全部条件都为真时设置:


[*]SYN 或者 FIN 标志位设置
[*]不是 Keep-Alive 数据包
[*]TCP 段长度大于零
[*]该 TCP 流的数据已被确认,也就是说,反方向之前的 LastACK Num 已被设置
[*]该数据包的 Next Seq Num 小于或即是反方向之前的 LastACK Num
替换 Fast Retransmission 、Out-Of-Order 和 Retransmission。
Checks for a retransmission based on analysis data in the reverse direction. Set when all of the following are true:

The SYN or FIN flag is set.
This is not a keepalive packet.
The segment length is greater than zero.
Data for this flow has been acknowledged. That is, the last-seen acknowledgment number has been set.
The next sequence number is less than or equal to the last-seen acknowledgment number.

Supersedes “Fast Retransmission”, “Out-Of-Order”, and “Retransmission”.
   联合实际源码+场景,文档中界说有错误,第1个条件(SYN 或者 FIN 标志位设置)和第3个条件(TCP 段长度大于零)应该是或的关系,而不是与的关系。
详细的代码如下,总的来说这段代码是 Wireshark 中 TCP 分析模块的一部门,用于检测和标识 TCP 数据包中的各种重传类型。它的主要功能是根据当前数据包的序列号、长度、标志位以及之前收到的 TCP 数据包的信息,判定当前数据包是否属于重传,如果是则进一步确定它属于哪种重传类型。
根据分析 TCP 数据包的各种特征,对重传数据包进行分类,有助于更好地理解 TCP 连接中的重传行为,对于诊断网络问题很有资助。在打扫了 KeepAlive 数据包后,如果全部下述条件均满足,则以为该数据包是一个虚伪重传包。


[*]检查 TCP 段巨细是否大于 0;
[*]检查反方向之前的 LastACK Num 是否不为 0;
[*]检查数据包的 Next Seq Num(seq+seglen)是否小于或即是反方向之前的 LastACK Num。
    /* RETRANSMISSION/FAST RETRANSMISSION/OUT-OF-ORDER
   * If the segment contains data (or is a SYN or a FIN) and
   * if it does not advance the sequence number, it must be one
   * of these three.
   * Only test for this if we know what the seq number should be
   * (tcpd->fwd->nextseq)
   *
   * Note that a simple KeepAlive is not a retransmission
   */
    if (seglen>0 || flags&(TH_SYN|TH_FIN)) {
      gboolean seq_not_advanced = tcpd->fwd->tcp_analyze_seq_info->nextseq
                && (LT_SEQ(seq, tcpd->fwd->tcp_analyze_seq_info->nextseq));

      guint64 t;
      guint64 ooo_thres;

      if(tcpd->ta && (tcpd->ta->flags&TCP_A_KEEP_ALIVE) ) {
            goto finished_checking_retransmission_type;
      }

      /* This segment is *not* considered a retransmission/out-of-order if
         *the segment length is larger than one (it really adds new data)
         *the sequence number is one less than the previous nextseq and
         *      (the previous segment is possibly a zero window probe)
         *
         * We should still try to flag Spurious Retransmissions though.
         */
      if (seglen > 1 && tcpd->fwd->tcp_analyze_seq_info->nextseq - 1 == seq) {
            seq_not_advanced = FALSE;
      }

      /* Check for spurious retransmission. If the current seq + segment length
         * is less than or equal to the current lastack, the packet contains
         * duplicate data and may be considered spurious.
         */
      if ( seglen > 0
      && tcpd->rev->tcp_analyze_seq_info->lastack
      && LE_SEQ(seq + seglen, tcpd->rev->tcp_analyze_seq_info->lastack) ) {
            if(!tcpd->ta){
                tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
            }
            tcpd->ta->flags|=TCP_A_SPURIOUS_RETRANSMISSION;
            goto finished_checking_retransmission_type;
      }
    ...
    }

finished_checking_retransmission_type:
   
[*]next expected sequence number,为 nextseq,界说为 highest seen nextseq。
[*]lastack,界说为 Last seen ack for the reverse flow。
Packetdrill 示例

根据上述 TCP Spurious Retransmission 界说和代码说明,通过 packetdrill 模拟在收到对一个数据分段 ACK 已确认的情况下,仍然再次重传同一个数据分段即可,就会以为是 TCP Spurious Retransmission 。
# cat tcp_spurious_retrans.pkt
0   socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0setsockopt(3, SOL_SOCKET, SO_REUSEADDR, , 4) = 0
+0bind(3, ..., ...) = 0
+0listen(3, 1) = 0

+0 < S 0:0(0) win 16000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 16000

+0 accept(3, ..., ...) = 4
+0 < P. 1:21(20) ack 1 win 15000
+0 > . 1:1(0) ack 21 <...>
+0 < P. 21:41(20) ack 1 win 15000
#
经 Wireshark 展示如下,可以看到满足判定条件后,No.6 标识 ,是因为客户端发送的数据分段 No.4 Seq Num 1 + Len 20,已由服务器 No.5 ACK 21 确认收到了该数据分段,但是在之后客户端又再次发送了同样一个数据分段 No.6 Seq Num 1 + Len 20,此时 Wireshark 就会以为 No.6 是虚伪重传,而 No.7 是一次重复确认。
https://i-blog.csdnimg.cn/img_convert/1e69a1ceadc7ce84cefb2d715fdf03d3.png
实例

关于 TCP Spurious Retransmission 的实例,实际日常抓包中不算少见,是一种比力好理解的 TCP 分析标志。在差别的场景中,也会伴生着出现像是 TCP Dup ACK 、TCP ACKed unseen segment、TCP Previous segment not captured 等信息。

[*]TCP Spurious Retransmission + TCP Dup ACK
一个 ACK 响应慢的的场景,根据 Length 54 长度,可知该数据包跟踪文件是在客户端捕获,IRTT 为 45.7ms,但在客户端收到服务器端 No.181 的数据分段后,理论应该最多几 ms 内说响应 ACK,但是直到 209ms 之后才复兴 No.182 ACK,此时在服务器端已产生了超时重传,也就是 No.183,所以在客户端收到 No.183 同样的一个数据分段后,即标识为 , 而此次客户端不到 1ms 就响应了 ACK,也就是 。
https://i-blog.csdnimg.cn/img_convert/789d6bc448ef58c0872d4e9daa2ae4d4.png

[*]TCP Spurious Retransmission + TCP ACKed unseen segment
一个 ACK 丢失的场景,根据客户端 No.6 数据包 ACK Num 9 可知已经收到了服务器端发送的 Seq Num 9 之前的全部数据分段,但往上到 No.4 却没有看到相关数据分段,固然只是没有捕获到,实际上客户端已收到,因此 No.6 标识成 ,但为什么看到了 No.6 ACK 了,服务器端仍然重传了 No.7 。实际上这是抓包点的问题,或者说此数据包跟踪文件不是在服务器端上抓的,譬如在中间端抓取,捕获到了 No.6 ACK,但是这个 ACK 再往服务器去传输时丢失了,因此服务器在没收到 ACK 的情况下,重传了 No.7 Seq Num 1 + Len 8 的数据分段,也因此被标识成 。
https://i-blog.csdnimg.cn/img_convert/8c68c08e10855378fad5953a0b6be332.png

[*]错误的 TCP Spurious Retransmission
错误的 TCP 虚伪重传场景,如下所示,No.5-6 发送端所发送的数据分段,因个别未捕获到,标识为 ,但接收端 No.9 的 ACK Num 9881 说明已确认接收了序号 9881 之前的数据段,但在 No.11 发送端又重新发送了 Seq Num 4940 + Len 1368 的数据分段,因此符合条件,标识为 。
https://i-blog.csdnimg.cn/img_convert/9f8bbbcc5855299ee3834954b94963af.png
一切看起来挺合理,但为什么说是判定错误呢?凡事深想一层,干活多做一步,再瞅瞅 ip.id ,你会发现有些问题。发送端 No.11 的 ip.id 为 29559,这不是应该是在 No.4 和 No.5 之间的一个数据包嘛,所以呢,No.11 不是重传,它是原本的数据分段,也因此它应该被标识成 。
https://i-blog.csdnimg.cn/img_convert/8031508f7a032cf6c0d2594deb3aafb2.png
但是为什么会出现如许的情况,乱序的数据段出现在了 ACK 确认之后,虽然不是完全确认抓包的情况,但根本上可以猜测是互换机镜像或者 TAP 出了问题,更有可能是后者造成的乱序。
总结

考虑到数据包会出现乱序、重传等各类差别的场景,产生 TCP Spurious Retransmission 的情形自然也是五花八门,详细问题详细分析。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: TCP Analysis Flags 之 TCP Spurious Retransmission