TCP Analysis Flags 之 TCP Out-Of-Order

news2025/1/1 10:58:02

前言

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

TCP 分析展示

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

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

考虑到 TCP 乱序、重传场景的复杂性,专家信息在乱序的判断上,前面都会有一个(suspected),表示疑似,说明并不是百分百正确,属于 Warning 级别。

TCP Out-Of-Order 定义

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

TCP Out-Of-Order 的定义如下,当以下所有条件都为真时设置:

  • 不是 Keep-Alive 数据包
  • TCP 段大小大于零或设置了 SYN/FIN
  • 同方向之前下一个期望的 Seq Num 大于当前数据包的 Seq Num
  • 同方向之前下一个期望的 Seq Num 和当前数据包的 Next Seq Num 不同
  • 最后一个报文段到达的时间在乱序 RTT 阈值内。这个阈值可以是两种情况之一:1). 如果在"SEQ/ACK 分析"下存在 “IRTT”(tcp.analysis.initial_rtt)字段,则使用该值作为阈值。2).如果不存在,则使用默认值 3 毫秒作为阈值。

替代 Retransmission

Set when all of the following are true:

This is not a keepalive packet.
In the forward direction, the segment length is greater than zero or the SYN or FIN is set.
The next expected sequence number is greater than the current sequence number.
The next expected sequence number and the next sequence number differ.
The last segment arrived within the Out-Of-Order RTT threshold. The threshold is either the value shown in the “iRTT” (tcp.analysis.initial_rtt) field under “SEQ/ACK analysis” if it is present, or the default value of 3ms if it is not.

Supersedes “Retransmission”.

具体的代码如下,总的来说这段代码是 Wireshark 中 TCP 分析模块的一部分,用于检测和标识 TCP 数据包中的各种重传/乱序类型。它的主要功能是根据当前数据包的序列号、长度、标志位以及之前收到的 TCP 数据包的信息,判断当前数据包是否属于重传/乱序,如果是则进一步确定它属于哪种重传/乱序类型。

根据分析 TCP 数据包的各种特征,对重传/乱序数据包进行分类,有助于更好地理解 TCP 连接中的重传/乱序行为,对于诊断网络问题很有帮助。这段代码的主要逻辑如下,如果所有下述条件均满足,则认为该数据包是一个乱序包(详见 case FALSE 部分)。

首先判断:

  • 检查 seq_not_advanced,序列号是否未递增;
  • 检查数据包到达的时间是否在设定的阈值内(IRTT 或 3ms);
  • 检查数据包之前是否未被看到;

继续判断:

  • 如果同方向之前下一个期望的 Seq Num 不等于当前数据包 Seq Num + Len + 1(SYN|FIN)/0,则标记为乱序;
  • 否则,如果同方向之前 LastACK 的段长度为 0(可能是纯ACK),也标记为乱序,这处理了一系列乱序包被纯 ACK 分隔的情况。
    /* 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;
        }

        ...

        nextseq = seq+seglen;

        gboolean precedence_count = tcp_fastrt_precedence;
        do {
            switch(precedence_count) {
                case TRUE:
                    ...

                case FALSE:
                    /* If the segment came relatively close since the segment with the highest
                     * seen sequence number and it doesn't look like a retransmission
                     * then it is an OUT-OF-ORDER segment.
                     */
                    t=(pinfo->abs_ts.secs-tcpd->fwd->tcp_analyze_seq_info->nextseqtime.secs)*1000000000;
                    t=t+(pinfo->abs_ts.nsecs)-tcpd->fwd->tcp_analyze_seq_info->nextseqtime.nsecs;
                    if (tcpd->ts_first_rtt.nsecs == 0 && tcpd->ts_first_rtt.secs == 0) {
                        ooo_thres = 3000000;
                    } else {
                        ooo_thres = tcpd->ts_first_rtt.nsecs + tcpd->ts_first_rtt.secs*1000000000;
                    }

                    /* If the segment is already seen and waiting to be acknowledged, ignore the
                     * Fast-Retrans/OOO debate and go ahead, as it only can be an ordinary Retrans.
                     * Fast-Retrans/Retrans are never ambiguous in the context of packets seen but
                     * this code could be moved above.
                     * See Issues 13284, 13843
                     * XXX: if compared packets have different sizes, it's not handled yet
                     */
                    gboolean pk_already_seen = FALSE;
                    ual = tcpd->fwd->tcp_analyze_seq_info->segments;
                    while(ual) {
                        if(GE_SEQ(seq,ual->seq) && LE_SEQ(seq+seglen,ual->nextseq)) {
                            pk_already_seen = TRUE;
                            break;
                        }
                        ual=ual->next;
                    }

                    if(seq_not_advanced && t < ooo_thres && !pk_already_seen) {
                        /* ordinary OOO with SEQ numbers and lengths clearly stating the situation */
                        if( tcpd->fwd->tcp_analyze_seq_info->nextseq != (seq + seglen + (flags&(TH_SYN|TH_FIN) ? 1 : 0))) {
                            if(!tcpd->ta) {
                                tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
                            }

                            tcpd->ta->flags|=TCP_A_OUT_OF_ORDER;
                            goto finished_checking_retransmission_type;
                        }
                        else {
                            /* facing an OOO closing a series of disordered packets,
                               all preceded by a pure ACK. See issue 17214 */
                            if(tcpd->fwd->tcp_analyze_seq_info->lastacklen == 0) {
                                if(!tcpd->ta) {
                                    tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
                                }

                                tcpd->ta->flags|=TCP_A_OUT_OF_ORDER;
                                goto finished_checking_retransmission_type;
                            }
                        }
                    }
                    precedence_count=!precedence_count;
                    break;
            }
        } while (precedence_count!=tcp_fastrt_precedence) ;

...

finished_checking_retransmission_type:
  1. next expected sequence number,为 nextseq,定义为 highest seen nextseq。
  2. lastack,定义为 Last seen ack for the reverse flow。
  3. lastacklen,定义为 length of the last fwd ACK packet - 0 means pure ACK。

Packetdrill 示例

根据上述 TCP Out-Of-Order 定义和代码说明,通过 packetdrill 模拟连续传入数据分段,但顺序颠倒了一个,满足乱序的判断条件后,会标记成 TCP 乱序数据包。

# cat tcp_out_of_order_01.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.001 < P. 41:61(20) ack 1 win 15000
+0.001 < P. 21:41(20) ack 1 win 15000
# 

经 Wireshark 展示如下,可以看到满足判断条件后,No.8 标识 [TCP Out-Of-Order] ,是因为客户端发送的数据分段 No.6 Seq Num 41 和 No.4 Next Seq Num 21 之间缺少了一个长度为 20 字节的数据分段,No.6 标识为 [TCP Previous segment not captured] ,而 No.7 标识为 [TCP Dup ACK] ,紧接着之后的 No.8 Seq Num 21 + Len 20 数据包,标识为 [TCP Out-Of-Order]。

在这里再验证下,数据包到达的时间如果不在设定的阈值内,也就是 11ms 大于 IRTT 10ms,是否会被标记成乱序数据包。

# cat tcp_out_of_order_02.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.001 < P. 41:61(20) ack 1 win 15000
+0.011 < P. 21:41(20) ack 1 win 15000
# 

答案是不会,不满足乱序数据包条件,被标记成了重传数据包。

实例

关于 TCP Out-Of-Order 的实例,实际日常抓包中经常会看到,是比较常见的一种 TCP 分析信息,而在各类场景中,也会伴生着出现像是 TCP Dup ACKTCP Previous segment not captured 等信息。

  1. 标准 TCP 乱序

标准的 TCP 乱序场景,No.119 和 No.120 中间缺失一个 Seq 237 + Len 207 的数据分段,No.120 首先会提示 [TCP Previous segment not captured],之后 No.122 Seq 237 + Len 207 的数据包到来,满足乱序数据包的判断条件,标记成 [TCP Out-Of-Order]

也可以使用 ip.id 加以佐证,如下,No.122 IP ID 15284,实际上是在 No.119 15283 和 No.120 15286 之间,说明就是乱序数据包。

ip.id 辅助的方式非标准实现,多数场景下可用,但不是所有场景都适合。

  1. TCP 乱序(纯 ACK)

代码中描述的一系列乱序包被纯 ACK 分隔的场景,其中 No.13 为纯 ACK,No.15 为乱序的第一个数据包,它满足判断乱序代码中继续判断的第一种场景,nextseq != (seq + seglen),因此被标记为 [TCP Out-Of-Order],而 No.19 为乱序的第二个数据包,它满足判断乱序代码中继续判断的第二种场景,lastacklen = 0,因为 No.13 为纯 ACK,所以 No.19 也被标记为 [TCP Out-Of-Order]

  1. TCP 快速重传还是 TCP 乱序

TCP 快速重传和乱序混淆,这似乎在目前的 Wireshark 版本中是经常可以看到的一种场景,如下案例:

  1. 服务器所发的数据包 No.20 前丢了一个 TCP 分段 Seq 9577 ,所以 No.20 标记为 TCP Previous segment not captured
  2. 客户端回应第一个 No.21 DUP ACK 确认还要 Seq 9577 分段(原 ACK 在 No.19);
  3. 服务器下一个数据包 No.22 仍不是 TCP 分段 Seq 9577;
  4. 因此客户端回应第二个 No.23 DUP ACK 确认继续要 Seq 9577 分段;
  5. 此时服务器像是因为 DUP ACK 的原因触发了快速重传,发送了 No.24 Seq 9577 数据包。

Wireshark 在此判断 No.24 为快速重传感觉确实合情合理,因为包括 DUP ACK >=2 等条件综合判断为真时就会认为是快速重传。但是细细一琢磨,会发现里面有些问题:IRTT,IRTT 为 0.103362s ,说明客户端和服务器端 RTT 约为 103ms,如果捕获点在客户端,No.24 和 No.23 之间的时间差值仅为 71ns。试问从客户端发出 No.23 到服务器收到 No.23 之后触发快速重传,再到客户端所捕获,这个 71ns 的时间完全不符合现实。

此时通过 IP.ID 加以佐证,No.24 的 IP ID 为 49749 ,在 No.20 和 No.22 之前,因此 No.24 实际上是乱序,而不是快速重传。

总结

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

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

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

相关文章

鸿蒙开发实战之“使用HiLog和HiSysEvent进行日志与系统事件管理”

HiLog和HiSysEvent作为鸿蒙&#xff08;HarmonyOS&#xff09;系统中进行日志记录和系统事件管理的关键组件&#xff0c;为开发者提供了强大的工具来追踪系统行为、调试应用以及监控设备状态。它们不仅简化了日志管理和事件追踪的流程&#xff0c;还提高了开发效率和系统可维护…

机器学习之PCA降维

主成分分析&#xff08;PCA&#xff0c;Principal Component Analysis&#xff09; 主成分分析&#xff08;PCA&#xff09;是一种常见的无监督学习技术&#xff0c;广泛应用于数据降维、数据可视化以及特征提取等任务。PCA的目标是通过线性变换将数据从高维空间映射到低维空间…

【CSS in Depth 2 精译_098】17.3:CSS 动画延迟技术与填充模式设置 + 17.4:通过 CSS 动画传递意图的秘诀

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 17 章 动画】 ✔️ 17.1 关键帧17.2 3D 变换下的动画设置 17.2.1 添加动画前页面布局的构建17.2.2 为布局添加动画 17.3 动画延迟与填充模式 ✔️17.4 通过动画传递意图…

python+PyMuPDF库:(一)创建pdf文件及内容读取和写入

目录 文档操作 打开文档 获取文档信息 删除页 复制页 移动页 选择重构合并 保存关闭 页对象操作 内容读取 获取页对象的字体样式 插入文本标签 插入文本内容 字体设置 insert_text添加文本 insert_textbox添加文本 插入图片 获取页面注释、链接、表单字段 …

Datawhale AI冬令营 动手学AI Agent

背景——什么是Agent 在人工智能领域&#xff0c;agent可以指一个能够感知环境并作出决策以实现特定目标的系统。比如&#xff0c;一个聊天机器人&#xff08;chatbot&#xff09;就是一个agent&#xff0c;它能够理解用户的输入并给出相应的回复。 学习目标 学会使用百宝箱…

高精度保形滤波器Savitzky-Golay的数学原理、Python实现与工程应用

面向信号处理的特征保持平滑技术 在数据分析领域&#xff0c;信号处理中的噪声问题始终是一个重要议题。无论是实验数据、金融时间序列还是其他形式的信号处理&#xff0c;噪声都会干扰目标模式和趋势的识别。尽管存在多种降噪方法&#xff0c;但在处理短时信号时&#xff0c;…

九点标定+旋转标定

眼在手外方式 1.夹取make点位置要求 机械手夹具夹持一个款标定板或者物料露出make点让视觉定位抓取 高度&#xff1a;与产品识别高度一致 左右位置&#xff1a;在相机视野内可以拍到make点 2.机械手走9个点移动位置要求&#xff08;九点标定&#xff09; 保证make在视野内…

RealityCapture导入视频序列失败

问题原因&#xff1a;如果导入的视频文件存在多余的元数据&#xff0c;那么在这里会发生导入失败。 以本人华为手机拍摄的一段.mp4视频为例&#xff1a; 利用ffmpeg在窗口命令行中检查你的视频—— ffmpeg -i your_video_name.mp4your_video_name是你的视频文件名 如下图所示&…

计算机网络|数据流向剖析与分层模型详解

文章目录 一、网络中的数据流向二、计算机网络通信模型1.OSI 模型2.TCP/IP 模型3.TCP/IP五层模型3.1 分层架构描述3.2各层地址结构3.3UDP数据包报头结构 三、总结 一、网络中的数据流向 在计算机网络中&#xff0c;数据的流向是指数据从发送端到接收端的传输路径。数据流向涉及…

正则表达式(三剑客之awk)

1.awk工具的使用 1.1 截取文档中的某个段 1&#xff09;打印以 : 为分隔的第一个字段 [rootlocalhost ~]# head -n3 /etc/passwd | awk -F : {print $1} 2&#xff09;注意事项 -F&#xff1a;作用是指定分隔符。如果不加分隔符&#xff0c;则以空格或者tab为分隔符 print&…

【基于rust-wasm的前端页面转pdf组件和示例】

基于rust-wasm前端页面转pdf组件和示例 朔源多余的废话花哨的吹牛那点东西要不要拿来试试事到如今 做个美梦 我觉得本文的意义在于,wasm扩展了浏览器的边界,但是又担心如同java的web applet水土不服. 如同我至今看不出塞班和iOS的不同下载地址&#xff1a;在github的备份 朔源…

图扑可视化赋能挖掘机高效操控

数字孪生挖掘机通过图扑可视化实时数据呈现和精准环境模拟&#xff0c;提升操作精度与施工效率&#xff0c;助力施工项目可视化管理&#xff0c;优化资源配置&#xff0c;为工程机械行业带来了新的智能化革新。

【多维DP】力扣3366. 最小数组和

给你一个整数数组 nums 和三个整数 k、op1 和 op2。 你可以对 nums 执行以下操作&#xff1a; 操作 1&#xff1a;选择一个下标 i&#xff0c;将 nums[i] 除以 2&#xff0c;并 向上取整 到最接近的整数。你最多可以执行此操作 op1 次&#xff0c;并且每个下标最多只能执行一…

支付域——“奖、惩、贴“特殊清算

摘要 在现代的服务平台经济中&#xff0c;比如网约车、外卖服务等&#xff0c;奖惩机制是用来管理服务提供者行为和确保服务品质的一种重要工具。所谓的“奖惩贴”就是这种机制中的一种具体形式&#xff0c;它包括了给予服务提供者的奖金、罚款和补贴。这些措施能够激励平台商…

网易企业邮箱登陆:保障数据安全

网易企业邮箱是一款为企业提供安全可靠的电子邮件服务的工具。通过网易企业邮箱&#xff0c;企业可以实现员工之间的高效沟通和信息共享&#xff0c;同时保障数据的安全性。 企业邮箱的安全性是企业信息保护的重要组成部分。网易企业邮箱采用了多层加密技术&#xff0c;确保邮件…

java常用类(下)

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;javase &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一、Math 类 1.1基本介…

计算机的错误计算(一百九十四)

摘要 用两个大模型计算 其中&#xff0c;一个大模型通过化简&#xff0c;得出正确结果 0&#xff1b;而另外一个在化简过程中出现错误&#xff0c;得出了错误结果。 例1. 计算 下面是一个大模型的推导化简过程。 以上为一个大模型的回答。 下面是另外一个大模型的回复。 点评…

电脑缺失sxs.dll文件要怎么解决?

一、文件丢失问题&#xff1a;以sxs.dll文件缺失为例 当你在运行某个程序时&#xff0c;如果系统提示“找不到sxs.dll文件”&#xff0c;这意味着你的系统中缺少了一个名为sxs.dll的动态链接库文件。sxs.dll文件通常与Microsoft的.NET Framework相关&#xff0c;是许多应用程序…

初始c语言第一个c语言项目

第一个c语言项目 //c语言中一定要有main函数 //主函数//printf是一个库函数 //专门用来打印数据//std 标准 //i-input //o-output // #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//c语言规定main函数是程序的入口 //标准的主函数的写法 int main() {printf(&qu…

进军AI大模型-环境配置

语言环境配置 合法上网工具&#xff1a; 这个T子试试&#xff0c;一直稳定。走我链接免费用5天: https://wibnm.com/s/ywtc01/pvijpzy python版本&#xff1a; python3.12 Langchain: Introduction | &#x1f99c;️&#x1f517; LangChain v0.3 9月16日升级的版本 pip3…