TCP Analysis Flags 之 TCP Keep-Alive

前言

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

TCP 分析展示

在 TCP 分析中和 TCP Keep-Alive 相关的实际上有两种信息,分别是:TCP Keep-AliveTCP Keep-Alive ACK 。实际运行环境中,有时 TCP Keep-Alive 单独出现的,因为有可能对端未确认 ,有时是一起出现的,也就是对端对 TCP Keep-Alive 数据包进行了确认,回复了 TCP Keep-Alive ACK 数据包。

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

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

TCP Keep-Alive 定义

实际在 TCP 分析中,关于 TCP Keep-AliveTCP Keep-Alive ACK 相关的定义也相对简单,主要说明如下:

  1. TCP Keep-Alive

当 TCP 数据段大小为 0 或 1 时设置,当前序列号比下一个期望的序列号小 1 字节,并且没有设置 SYN、FIN 或 RST。

替代 Fast RetransmissionOut-Of-OrderSpurious RetransmissionRetransmission

Set when the segment size is zero or one, the current sequence number is one byte less than the next expected sequence number, and none of SYN, FIN, or RST are set.

Supersedes “Fast Retransmission”, “Out-Of-Order”, “Spurious Retransmission”, and “Retransmission”.

next expected sequence number,为 nextseq,定义为 highest seen nextseq。

具体的代码如下,总的来说这段代码的作用是检测出 TCP 保活包,并对其进行适当的标记,以便 Wireshark 能够正确识别和显示这种特殊的 TCP 控制数据包,帮助分析长连接的保活状态。这段代码的主要逻辑如下,如果所有下述条件均满足,则认为该数据包是一个保活探测包。

  • 检查 TCP 段大小是否为 0 或 1 字节;
  • 检查 Seq Num 比同方向之前的下一个期望的 Seq Num 少 1;
  • 检查当前数据包是否不是 SYN/FIN/RST 数据包。
    /* KEEP ALIVE
     * a keepalive contains 0 or 1 bytes of data and starts one byte prior
     * to what should be the next sequence number.
     * SYN/FIN/RST segments are never keepalives
     */
    if( (seglen==0||seglen==1)
    &&  seq==(tcpd->fwd->tcp_analyze_seq_info->nextseq-1)
    &&  (flags&(TH_SYN|TH_FIN|TH_RST))==0 ) {
        if(!tcpd->ta) {
            tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
        }
        tcpd->ta->flags|=TCP_A_KEEP_ALIVE;
    }
  1. TCP Keep-Alive ACK

当以下所有条件都为真时设置该标志:

  • TCP 段大小为 0
  • 窗口大小非零且没有改变
  • Seq Num 等于之前下一个期望的 Seq Num
  • ACK Num 等于之前的 LastACK Num
  • 最近看到的一个反向数据包是 Keep-Alive
  • SYN、FIN、RST 均未设置

替代 Dup ACKZeroWindowProbeAck

Set when all of the following are true:

The segment size is zero.
The window size is non-zero and hasn’t changed.
The current sequence number is the same as the next expected sequence number.
The current acknowledgment number is the same as the last-seen acknowledgment number.
The most recently seen packet in the reverse direction was a keepalive.
The packet is not a SYN, FIN, or RST.

Supersedes “Dup ACK” and “ZeroWindowProbeAck”.

具体的代码如下,总的来说这段代码的作用是检测对 TCP 保活包的 ACK 响应,并对其进行适当的标记,以便 Wireshark 能够正确分析和显示 TCP 长连接的保活状态。这段代码的主要逻辑如下,如果所有下述条件均满足,则认为该数据包是一个保活探测响应包。

  • 检查 TCP 段大小是否为 0;
  • 检查窗口大小是否不为 0;
  • 检查当前窗口大小与同方向之前窗口大小是否相同;
  • 检查 Seq Num 是否等于同方向之前下一个期望的 Seq Num;
  • 检查 ACK Num 是否等于同方向之前的 LastACK Num;
  • 检查反方向上一个数据包是否是 TCP Keep-Alive;
  • 检查当前数据包是否不是 SYN/FIN/RST 数据包。
    /* KEEP ALIVE ACK
     * It is a keepalive ack if it repeats the previous ACK and if
     * the last segment in the reverse direction was a keepalive
     */
    if( seglen==0
    &&  window
    &&  window==tcpd->fwd->window
    &&  seq==tcpd->fwd->tcp_analyze_seq_info->nextseq
    &&  ack==tcpd->fwd->tcp_analyze_seq_info->lastack
    && (tcpd->rev->lastsegmentflags&TCP_A_KEEP_ALIVE)
    &&  (flags&(TH_SYN|TH_FIN|TH_RST))==0 ) {
        if(!tcpd->ta) {
            tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
        }
        tcpd->ta->flags|=TCP_A_KEEP_ALIVE_ACK;
        goto finished_fwd;
    }
  1. next expected sequence number,为 nextseq,定义为 highest seen nextseq。
  2. lastack,定义为 Last seen ack for the reverse flow。

Packetdrill 示例

在上述 TCP Keep-AliveTCP Keep-Alive ACK 定义和代码可知,TCP 分析的逻辑相对比较简单,因此通过 packetdrill 比较容易模拟出相关现象。

# cat tcp_keep_alive.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 1000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 1000

+0 accept(3, ..., ...) = 4
+.1 write(4, ..., 500) = 500
+0 > P. 1:501(500) ack 1
+0.1 < . 1:1(0) ack 501 win 1000

+0.1 < . 0:0(0) ack 501 win 1000
#

经 Wireshark 展示如下,可以看到满足判断条件后,No.6 标识 [TCP Keep-Alive] ,No.7 标识 [TCP Keep-Alive ACK] ,此时 No.6 的 TCP Len 长度为 0 字节。

同样,可以验证一下 TCP Keep-Alive 数据包 TCP Len 长度为 1 字节的场景,这在 RFC9293 中也明确说明,0 或 1 字节都可以。

# cat tcp_keep_alive_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 1000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 1000

+0 accept(3, ..., ...) = 4
+.1 write(4, ..., 500) = 500
+0 > P. 1:501(500) ack 1
+0.1 < . 1:1(0) ack 501 win 1000

+0.1 < . 0:1(1) ack 501 win 1000
#

经 Wireshark 展示如下,可以看到满足判断条件后,No.6 标识 [TCP Keep-Alive] ,No.7 标识 [TCP Keep-Alive ACK] ,此时 No.6 的 TCP Len 长度为 1 字节。

实例

关于 TCP Keep-Alive 的实例,正常来说日常抓包中应该比较少看到,TCP Keep-Alive 数据包必须仅在没有未完成的发送数据,且在一定时间间隔内没有收到连接的数据或确认数据包时发送,默认的时间间隔为 2 小时,相对来说很长。

  1. TCP Keep-Alive Len 0 场景

TCP Keep-Alive 数据包 TCP Len 为 0 的场景相对来说更容易碰到。如下 TCP 流在经过 45 秒间隔后,客户端发出了 No.579 [TCP Keep-Alive] , 此时 TCP Len 为 0,之后服务器端响应 No.580 [TCP Keep-Alive ACK]

  1. TCP Keep-Alive Len 1 场景

TCP Keep-Alive 数据包 TCP Len 为 1 的场景相对来说少见。如下 TCP 流在经过 45 秒间隔后,客户端发出了 No.151 [TCP Keep-Alive] , 此时 TCP Len 为 1,之后服务器端响应 No.152 [TCP Keep-Alive ACK],之后每经过 45 间隔后,就继续保活检测和响应。

此案例有意思的是,No.151 TCP Keep-Alive 数据包 Seq Num 为 1155,TCP Len 为 1 ,相较于 No.124 Next Seq Num 1156 以及 No.125 ACK Num 1156,No.151 实际上回退了 1 字节,即所携带的 1 字节数据段为垃圾数据,而对于 No.152 在收到该数据后,除了响应标记 TCP Keep-Alive ACK 之外,同时会标记 [SLE==1155 SRE==1156],说明这 1 个字节的数据之前已收到过,属于重复数据,这属于该 TCP 流建连时均支持 SACK ,其中 D-SACK 的功能实现。

  1. TCP Keep-Alive 无响应场景

无响应的场景没有什么太多要说的,这也是网上经常讨论的,没有数据传输的时候,对端主机宕机或是什么拔掉网线的场景。一端到了规定的时间之后,即发出 TCP Keep-Alive 数据包,对端如果无响应,则每间隔一段时间继续发送探测,持续规定的一定次数之后,中断该连接。在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔,以下都为默认值:

net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75  
net.ipv4.tcp_keepalive_probes=9
  1. 不是 TCP Keep-Alive 的 TCP Keep-Alive 的场景一

一个特殊的例子,仔细看 No.1-2,再对比下标记成 TCP Keep-AliveTCP Keep-Alive ACK 的 No.134-135,你会发现实际的 Seq Num、ACK Num、TCP Len 以及 SLE SRE 基本都是一模一样的。

No.134-135 是 TCP Keep-AliveTCP Keep-Alive ACK,为什么 No.1-2 在这不是?真实的答案是,No.1-2 也是一对 TCP Keep-AliveTCP Keep-Alive ACK 数据包。原因自然是关于数据包跟踪文件中上下文的关系,对于 No.1-2 数据包,它们是这个 TCP 流中抓取的前两个数据包,从 Wireshark 代码判断条件下,它是无法匹配 TCP Keep-AliveTCP Keep-Alive ACK 的判断条件的,因此 No.1-2 不会标记,但实际确实是。

对比一下案例2,和案例4取自同一个跟踪文件,只不过案例2的TCP流中抓取到了前置数据包 No.123-125,因此后续的 TCP Keep-Alive 均能正常识别,而案例4缺少前置数据包,No.1-2 因此不会标记,空空如也。

  1. 不是 TCP Keep-Alive 的 TCP Keep-Alive 的场景二

另一个特殊的例子,其实原因是一样的,均是在 TCP 流中缺少前置数据包,只不过案例 4 中没有任何标记,而在此案例中会被标识为其它,也影响一定判断。

数据包 No.1-2 的类型实际上也是一对 TCP Keep-AliveTCP Keep-Alive ACK 数据包。因为捕获数据包并未抓到之前的包,Wireshark 无法根据上文判断,所以并未标记成 TCP Keep-Alive 数据包,造成之后的数据包 No.2-4 进行 TCP 分析判断时出现偏差,认为是存在丢包情况。

该案例之前在《丢包?不要轻易下结论续》有详细解释,有兴趣的可以瞅瞅。


总结

看似简单的 TCP Keep-Alive ,其实也有大学问,不是嘛。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用buildx构建多架构平台镜像

1. 查看buildx插件信息 比较新的docker-ce版本默认已经集成了buildx插件 [rootdocker ~]# docker buildx version github.com/docker/buildx v0.11.2 9872040 [rootdocker ~]#2. 增加多平台镜像构建支持 通过tonistiigi/binfmt:latest初始化一个基于容器的构建环境&#xff…

【Linux】编辑器vim 与 编译器gcc/g++

目录 一、编辑器vim&#xff1a; 1、对vim初步理解&#xff1a; 2、vim的模式&#xff1a; 3、进入与退出&#xff1a; 4、vim命令模式下的指令集&#xff1a; 移动光标&#xff1a; 删除&#xff1a; cv&#xff1a; 撤销&#xff1a; 其他&#xff1a; 5、vim底行模…

面试总结!

OSI七层模型&#xff1a; 什么是OSI七层模型&#xff1f; 我们需要了解互联网的本质是一系列的网络协议&#xff0c;这个协议就叫做OSI协议&#xff08;开放系统互联(Open System Interconnection&#xff09;&#xff09;&#xff0c;它是由ISO&#xff08;国际标准化组织&…

人工智能技术:未来生活的“魔法师”

想象一下&#xff0c;未来的某一天&#xff0c;你醒来时&#xff0c;智能助手已经为你准备好了早餐&#xff0c;你的智能家居系统根据你的心情和日程安排调整了室内的光线和音乐&#xff0c;而你的自动驾驶汽车已经在门口等你。这不是科幻小说&#xff0c;这是人工智能技术为我…

Multi Agents协作机制设计及实践

01 多智能体协作机制的背景概述 在前述博客中&#xff0c;我们利用LangChain、AutoGen等开发框架构建了一个数据多智能体的平台&#xff0c;并使用了LangChain的Multi-Agents框架。然而&#xff0c;在实施过程中&#xff0c;我们发现现有的框架存在一些局限性&#xff0c;这些…

100、Python并发编程:保护临界资源的最简单方式,加锁

引言 前面的文章中已经提到了并发编程中能够带来性能提升的同时&#xff0c;也带来了一些问题&#xff0c;比如对共享资源/临界资源的竞争&#xff0c;可能会导致状态的不一致。最终的结果是虽然性能提升了&#xff0c;但是结果却是错误的…… 所以&#xff0c;并发编程中一个…

PHP电商供应链ERP管理系统小程序源码

&#x1f680;电商供应链大揭秘&#xff01;ERP管理系统如何重塑你的商业版图✨ &#x1f50d; 什么是电商供应链ERP管理系统&#xff1f; 电商供应链ERP管理系统是一款基于FastAdminThinkPHP开发的系统。该系统可满足电商企业管理自身进销存&#xff0c;帮助中小型电商企业管…

python: Parent-child form operations using ttkbootstrap

# encoding: utf-8 # 版權所有 2024 ©塗聚文有限公司 # 許可資訊查看&#xff1a;言語成了邀功的功臣&#xff0c;還需要行爲每日來值班嗎&#xff1f; # 描述&#xff1a; 主、子表單 窗體傳值 Parent-child form operations # Author : geovindu,Geovin Du 塗聚文. …

跳表原理笔记

课程地址 跳表是一种基于随机化的有序数据结构&#xff0c;它提出是为了赋予有序单链表以 O(logn) 的快速查找和插入的能力 创建 首先在头部创建一个 sentinel 节点&#xff0c;然后在 L1 层采用“抛硬币”的方式来决定 L0 层的指针是否增长到 L1 层 例如上图中&#xff0c;L…

医院信息化与智能化系统(17)

医院信息化与智能化系统(17) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应…

selenium操作已开启的浏览器,方便调试

一、谷歌浏览器配置&#xff1a; 在所安装的谷歌下面&#xff0c;执行下面命令&#xff0c;打开谷歌浏览器&#xff0c;用来selenium的操作&#xff1a; 注意事项&#xff1a;端口需要不被占用&#xff0c;--user-data-dir"D:\workspace\chrome-data"这个路径需要有…

深度强化学习:从理论到应用

目录 1.引言 2.什么是强化学习&#xff1f; 3.深度学习和强化学习的结合 4.深度强化学习的主要方法 5.深度强化学习的应用领域 6.深度强化学习的挑战与未来 7.总结 1.引言 深度强化学习&#xff08;Deep Reinforcement Learning&#xff0c;DRL&#xff09;是近年来人工…

[Linux] 进程控制之创建和终止

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 每日吐槽 不得不说&a…

介绍一下rand函数生成随机数(c基础)

适合对象 c语言初学者 总结语言用色&#xff0c;个人强调用红色&#xff0c;注意为易错点&#xff0c;若有问题请告诉我谢谢。(建议通过目录观看)。一定要自己动手打代码。 rand函数 是生成随机数的函数&#xff0c;但实则是伪随机数。(即是同一个值) 格式 #include<st…

vue3入门知识(一)

vue3简介 性能的提升 打包大小减少41%初次渲染快55%&#xff0c;更新渲染快133%内存减少54% 源码的升级 使用Proxy代替defineProperty实现响应式重写虚拟DOM的实现和Tree-Shaking 新的特性 1. Composition API&#xff08;组合API&#xff09; setupref与reactivecomput…

FET113i-S核心板已支持RISC-V,打造国产化降本的更优解 -飞凌嵌入式

FET113i-S核心板是飞凌嵌入式基于全志T113-i处理器设计的国产工业级核心板&#xff0c;凭借卓越的稳定性和超高性价比&#xff0c;FET113i-S核心板得到了客户朋友们的广泛关注。作为一款拥有A7核RISC-V核DSP核的多核异构架构芯片&#xff0c;全志科技于近期释放了T113-i的RISC-…

C语言进阶:二.数据的存储(2)

❤个人主页❤&#xff1a;折枝寄北-CSDN博客 ❤学习专栏❤&#xff1a; C语言专栏&#xff1a;https://blog.csdn.net/2303_80170533/category_12794764.html?spm1001.2014.3001.5482https://blog.csdn.net/2303_80170533/category_12794764.html?spm1001.2014.3001.5482 在…

城市智慧公厕解决方案,建设城市智能化公厕

在城市的飞速发展进程中&#xff0c;公厕作为城市基础设施的重要一环&#xff0c;其智能化建设已成为提升城市品质与居民生活舒适度的关键举措。以下是关于城市智慧公厕的几点解决方案。 一、智能设施配备 首先&#xff0c;要引入智能化的卫生设备。例如&#xff0c;安装自动感…

【STL栈和队列】:高效数据结构的应用秘籍

前言&#xff1a; C 标准模板库&#xff08;STL&#xff09;为我们提供了多种容器&#xff0c;其中 stack&#xff08;栈&#xff09;和 queue&#xff08;队列&#xff09;是非常常用的两种容器。 根据之前C语言实现的栈和队列&#xff0c;&#xff08;如有遗忘&#xff0c;…

vue data变量之间相互赋值或进行数据联动

摘要&#xff1a; 使用vue时开发会用到data中是数据是相互驱动&#xff0c;经常会想到watch,computed&#xff0c;总结一下&#xff01; 直接赋值&#xff1a; 在 data 函数中定义的变量可以直接在方法中进行赋值。 export default {data() {return {a: 1,b: 2};},methods: {u…