TCP Analysis Flags 之 TCP Spurious Retransmission

前言

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

TCP 分析展示

在数据包文件中进行 TCP 分析时,关于 “TCP Spurious Retransmission” 一般是如下显示的,包括:

  1. Packet List 窗口中的 Info 信息列,以 [TCP Spurious Retransmission] 黑底红字进行标注;
  2. Packet Details 窗口中的 TCP 协议树下,在 [SEQ/ACK analysis] -> [TCP Analysis Flags] 中定义该 TCP 数据包的分析说明。

  1. 考虑到 TCP 乱序、重传场景的复杂性,专家信息在重传的判断上,前面都会有一个(suspected),表示疑似,说明并不是百分百正确,属于 Note 注意。
  2. 另在专家信息中,对于 TCP Spurious Retransmission 标志位分析同时会增加两种 Note,包括 Spurious Retransmission 和 Retransmission。

TCP Spurious Retransmission 定义

文档中关于 TCP Spurious Retransmission 的定义看起来简单,但实际考虑到 TCP 乱序、重传场景的复杂性,在 TCP 分析中对于 TCP Spurious Retransmission 是与 TCP Out-Of-OrderTCP Fast RetransmissionTCP Retransmission 等在一起判断标记乱序或重传类型,而在不少场景还会有判断出错的问题,当然 Wireshark 考虑到这种情况,也有手动修正的选项,这正好也侧面证明了上面的说法,关于 TCP 乱序、重传的复杂性。

TCP Spurious Retransmission 的定义如下,当以下所有条件都为真时设置:

  • SYN 或者 FIN 标志位设置
  • 不是 Keep-Alive 数据包
  • TCP 段长度大于零
  • 该 TCP 流的数据已被确认,也就是说,反方向之前的 LastACK Num 已被设置
  • 该数据包的 Next Seq Num 小于或等于反方向之前的 LastACK Num

替代 Fast RetransmissionOut-Of-OrderRetransmission

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:
  1. next expected sequence number,为 nextseq,定义为 highest seen nextseq。
  2. 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
+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 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 标识 [TCP Spurious Retransmission] ,是因为客户端发送的数据分段 No.4 Seq Num 1 + Len 20,已由服务器 No.5 ACK 21 确认收到了该数据分段,但是在之后客户端又再次发送了同样一个数据分段 No.6 Seq Num 1 + Len 20,此时 Wireshark 就会认为 No.6 是虚假重传,而 No.7 是一次重复确认。

实例

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

  1. TCP Spurious Retransmission + TCP Dup ACK

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

  1. TCP Spurious Retransmission + TCP ACKed unseen segment

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

  1. 错误的 TCP Spurious Retransmission

错误的 TCP 虚假重传场景,如下所示,No.5-6 发送端所发送的数据分段,因个别未捕获到,标识为 [TCP Previous segment not caputred] ,但接收端 No.9 的 ACK Num 9881 说明已确认接收了序号 9881 之前的数据段,但在 No.11 发送端又重新发送了 Seq Num 4940 + Len 1368 的数据分段,因此符合条件,标识为 [TCP Spurious Retransmission]

一切看起来挺合理,但为什么说是判断错误呢?凡事深想一层,干活多做一步,再瞅瞅 ip.id ,你会发现有些问题。发送端 No.11 的 ip.id 为 29559,这不是应该是在 No.4 和 No.5 之间的一个数据包嘛,所以呢,No.11 不是重传,它是原本的数据分段,也因此它应该被标识成 [TCP Out-Of-Order]

但是为什么会出现这样的情况,乱序的数据段出现在了 ACK 确认之后,虽然不是完全确认抓包的环境,但基本上可以猜测是交换机镜像或者 TAP 出了问题,更有可能是后者造成的乱序。

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/888818.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c# 设计模式--抽象工厂模式 (Abstract Factory)

定义 抽象工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。抽象工厂模式强调的是对象族的创建&#xff0c;而不是单一对象的创建。 用例写法 假设我们有一个场景&#xff0c;需要根据不同的平…

MySQL 8.0 的主主复制(双向复制)

在 Windows Server 2022 Datacenter 上配置 MySQL 8.0 的主主复制&#xff08;双向复制&#xff09;&#xff0c;步骤与 Linux 类似&#xff0c;但有一些特定的配置和路径需要注意。以下是详细的简化步骤&#xff1a; 1. 使用 root 用户登录 确保你以 root 用户登录到 MySQL …

1. 设计模式的由来

设计模式的灵感来自建筑师亚历山大的“设计套路”&#xff0c;后来被程序员借用&#xff0c;总结出一套“编程武功秘籍”。 20世纪90年代&#xff0c;四位软件工程师&#xff08;被称为“四人帮”&#xff09;——Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides&…

【笔记】Linux中使用到的一些操作

1、查找指定文件并执行删除 find . -name "checkpoint_*_*.pth" -type f -exec rm -f {} \; 2、查看每个文件夹占用空间 du -h --max-depth1 3、移动文件 mv valid.zip ./xg mv 文件 目标位置 4、删除文件夹 rmdir folder rm -r folder # 递归删除文件夹下所有内容…

java如何判断object是基本数据类型还是引用数据类型

如何判断object是基本数据类型还是引用数据类型 ‍ 直接用apache commons下的工具类isPrimitiveOrWrapper即可,没必要造轮子 /*** Returns whether the given {code type} is a primitive or primitive wrapper ({link Boolean}, {link Byte}, {link Character},* {link Shor…

Java线程的interrupt中断、wait-notify/all(源码级分析)

实例方法&#xff1a; interrupt()方法是设置结束阻塞(sleep、wait等)&#xff0c;并且设置中断标记true isInterrupted()判断当前是否中断 静态方法&#xff1a; Thread.interrupted():调用这个方法的线程中断标记位还原为false 那么好&#xff0c;既然上面的方法作用是清…

Burp Suite 实战指南:Proxy 捕获与修改流量、HTTP History 筛选与分析

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

12月第1周AI资讯

阅读时间:3-4min 更新时间:2024.12.2-2024.12.6 目录 OpenAI CEO Sam Altman 预告“12天OpenAI”系列活动 腾讯HunyuanVideo:130亿参数的开源视频生成模型 李飞飞的World Labs发布空间智能技术预览版 中科院联手腾讯打造“AI带货王”AnchorCrafter OpenAI CEO Sam Alt…

服务器带宽与数据安全的重要性与作用

服务器带宽指的是服务器与外部网络通信的能力&#xff0c;即服务器发送和接收数据的速率。带宽越大&#xff0c;服务器在同一时间内能够处理的数据量就越多&#xff0c;数据传输的速度和稳定性也就越高。在数字化时代&#xff0c;企业对于数据的依赖程度日益加深&#xff0c;无…

YoloV8实战:使用Yolo训练Objects365数据集

摘要 预训练模型在提高训练成绩上是非常有效,大家通常使用COCO数据集训练的模型做为预训练模型,在小型数据集做实验发现,使用COCO数据集训练的预训练模型比没有使用预训练模型的得分能高出2%mAP,同时,如果使用Objects365做预训练,能比没有使用预训练的模型高出4%的mAP,…

从零开始学TiDB(1) 核心组件架构概述

首先TiDB深度兼容MySQL 5.7 1. TiDB Server SQL语句的解析与编译&#xff1a;首先一条SQL语句最先到达的地方是TiDB Server集群&#xff0c;TiDB Server是无状态的&#xff0c;不存储数据&#xff0c;SQL 发过来之后TiDB Server 负责 解析&#xff0c;优化&#xff0c;编译 这…

记录一次使用git无权限的问题排查

正常的配置了公私钥之后&#xff0c;在gitlab中也存储了配对的公钥&#xff0c;但当使用git clone 时&#xff0c;总是报无权限 由于在这台机器中添加了多个公私钥&#xff0c;有点复杂&#xff0c;我们可以使用命令 ssh -vvvT 调试一下 ssh -vvvT yourGitlabAddr

VsCode运行Ts文件

1. 生成package.json文件 npm init 2. 生成tsconfig.json文件 tsc --init 3. Vscode运行ts文件 在ts文件点击右键执行Run Code,执行ts文件

python调用GPT-4o实时音频 Azure OpenAI GPT-4o Audio and /realtime

发现这块网上信息很少&#xff0c;记录一下 微软azure入口 https://learn.microsoft.com/zh-cn/azure/ai-services/openai/realtime-audio-quickstart?pivotsprogramming-language-ai-studio sdk文档 https://github.com/azure-samples/aoai-realtime-audio-sdk?tabread…

fastadmin 后台插件制作方法

目录 一&#xff1a;开发流程 二&#xff1a;开发过程 &#xff08;一&#xff09;&#xff1a;后台功能开发 &#xff08;二&#xff09;&#xff1a;功能打包到插件目录 &#xff08;三&#xff09;&#xff1a;打包插件 &#xff08;四&#xff09;&#xff1a;安装插件…

Kafka单机及集群部署及基础命令

目录 一、 Kafka介绍1、kafka定义2、传统消息队列应用场景3、kafka特点和优势4、kafka角色介绍5、分区和副本的优势6、kafka 写入消息的流程 二、Kafka单机部署1、基础环境2、iptables -L -n配置3、下载并解压kafka部署包至/usr/local/目录4、修改server.properties5、修改/etc…

Docker部署的gitlab升级的详细步骤(升级到17.6.1版本)

文章目录 一、Gitlab提示升级信息二、老版本的docker运行gitlab命令三、备份老版本Gitlab数据四、确定升级路线五、升级(共分3个版本升级)5.1 升级第一步(17.1.2 > 17.3.7)5.2 升级第二步(17.3.7 > 17.5.3)5.3 升级第三步(17.5.3 > 17.6.1) 六、web端访问gitlab服务 一…

在Java的xml的sql语句里面的某一个参数是list集合的时候

经常在Java里面&#xff0c;遇到这样的问题&#xff0c;sql的一个查询语句&#xff0c;它的某一个参数是一个List集合&#xff0c;然而&#xff0c;在xml.mapper文件里面的时候&#xff0c;不知道如何去组成这个查询语句&#xff0c;不知道兄弟们是否经常忘记如何去写这个语句&…

前端技术(23) : 聊天页面

来源: GPT生成之后微调 效果图 HTML代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>聊天</t…

内存图及其画法

所有的文件都存在硬盘上&#xff0c;首次使用的时候才会进入内存 进程&#xff1a;有自己的Main方法&#xff0c;并且依赖自己Main运行起来的程序。独占一块内存区域&#xff0c;互不干扰。内存中有一个一个的进程。 操作系统只认识c语言。操作系统调度驱动管理硬件&#xff0…