TCP Analysis Flags 之 TCP Keep-Alive

news/2024/12/28 11:08:08/

前言

默认情况下,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 ,其实也有大学问,不是嘛。


http://www.ppmy.cn/news/1544863.html

相关文章

Rust移动开发:Rust在Android端集成使用介绍

Andorid调用Rust 目前Rust在移动端上的应用&#xff0c;一般作为应用sdk的提供&#xff0c;供各端使用&#xff0c;目前飞书底层使用Rust编写通用组件。 该篇适合对Android、Rust了解&#xff0c;想看如何做整合&#xff0c;如果想要工程源码&#xff0c;可以评论或留言有解疑…

什么是Java的线程(Thread)?

Java的线程&#xff08;Thread&#xff09;是Java程序中执行的最小单位。线程是操作系统调度的基本单位&#xff0c;它可以独立执行一段代码&#xff0c;并拥有自己的程序计数器、栈和局部变量。Java中的线程通过使用Thread类来实现&#xff0c;可以通过继承Thread类或实现Runn…

Python小游戏19——滑雪小游戏

运行效果 python代码 import pygame import random # 初始化Pygame pygame.init() # 设置屏幕尺寸 screen_width 800 screen_height 600 screen pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("滑雪小游戏") # 定义颜色 WH…

Docker打包自己项目推到Docker hub仓库(windows10)

一、启用Hyper-V和容器特性 1.应用和功能 2.点击程序和功能 3.启用或关闭Windows功能 4.开启Hyper-V 和 容器特性 记得重启生效&#xff01;&#xff01;&#xff01; 二、安装WSL2&#xff1a;写文章-CSDN创作中心https://mp.csdn.net/mp_blog/creation/editor/143057041 三…

Python软体中使用Pandas库读取数据并绘制柱状图的实用指南

Python软体中使用Pandas库读取数据并绘制柱状图的实用指南 在数据分析和可视化的过程中,Python的Pandas库和Matplotlib库是两个不可或缺的工具。Pandas用于数据处理和分析,而Matplotlib则用于数据可视化。本文将详细介绍如何使用Pandas库读取数据,并利用Matplotlib绘制柱状…

【Linux第七课--基础IO】内存级文件、重定向、缓冲区、文件系统、动态库静态库

目录 引入内存级文件重新使用C文件接口 -- 对比重定向写文件读文件文件流 认识文件操作的系统接口open参数 -- flagflag的内容宏的传参方式 open关闭文件写文件读文件结论 引入文件描述符fd、对文件的理解理解一切皆文件方法集文件fd的分配规则 重定向代码的重定向输入重定向输…

【连续多届检索,ACM出版】第四届大数据、人工智能与风险管理国际学术会议 (ICBAR 2024,11月15-17)--冬季主会场

第四届大数据、人工智能与风险管理国际学术会议 (ICBAR 2024)--冬季主会场 2024 4th International Conference on Big Data, Artificial Intelligence and Risk Management 会议官网&#xff1a;www.icbar.net 2024 4th International Conference on Big Data, Artificial I…

Linux云计算 |【第五阶段】PROJECT3-DAY1

主要内容&#xff1a; 跳板机&#xff08;堡垒机&#xff09;的概念、部署JumpeServer 一、跳板机&#xff08;堡垒机&#xff09;的概念 跳板机&#xff08;Jump Server 或 Bastion Host&#xff09;是一种网络安全设备或服务器&#xff0c;也称堡垒机&#xff0c;是一类可作…