Wireshark 提示和技巧 | 捕获点之 TCP 三次握手

3,078 阅读11分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

在网络数据包分析中,如何选取捕获点,是一个很基础也很重要的工作。通用的方法论中捕获点可能会包括客户端、服务端和中间端,同时根据中间端设备能力的不同,像是否具有直接抓包的能力,可能又会分为多个捕获点,譬如某个设备的前后。这样在多点捕获数据包的结果下,再进行一定的处理过滤,进而分析定位故障原因。

但很多真实的业务场景是无法获得这么多数据包信息的,也许仅有客户端或服务端的数据包、或者仅有中间端的数据包等,那么它们具体有什么不同嘛?或者说当你拿到一个数据包文件时,是否能判断出它的捕获点,是客户端、服务端还是中间端?

对我来说,捕获点一直是一个很深奥的话题 ,虽然可能最后的分析结果指向是一样,但是数据包在不同的捕获点所展现出来的现象有时是完全不一样的。

本文仅从个人角度,简单概括不同捕获点下的 TCP 三次握手数据包的相关内容。

TCP 三次握手

TCP 三次握手简图如上,主要从几个方面阐述:

  1. IRTT 篇
  2. Length 篇
  3. TTL 篇
  4. Offload 篇
  5. 其他篇

TCP 三次握手的数据包分析所涉及到知识点很多,所选取的 IRTT、Length、TTL、Offload 几个方面,主要是和捕获点关联可展开分析的较多。

IRTT 篇

什么是 IRTT ? Wireshark 中所定义的 IRTT 是 TCP 三次握手中的初始化 RTT ,对应的显示过滤字段和含义如下

tcp.analysis.initial_rtt
How long it took for the SYN to ACK handshake(iRTT) 

示例

IRTT 值为 [iRTT: 0.001654000 seconds] ,即 TCP 三次握手中第三个包 ACK 与第一个包 SYN 之间的时间差值。

对于客户端、服务端和中间端等不同捕获点,上述其实是一个计算 IRTT 的通用方式。

那么对应于客户端、服务端和中间端三个不同捕获点,每一个值或差值又有什么实际差异呢?

客户端

当在客户端上捕获数据包时,从客户端发出 SYN , 经过中间网络设备传输至服务器,再由服务器处理发出 SYN/ACK 到客户端收到,此时 SYN/ACK 与 SYN 之间的时间差值为 a 。客户端之后再返回确认 ACK,此时 ACK 与 SYN/ACK 之间的时间差值为 b

综合考虑各端协议栈的处理能力和时延、网络传播时延和传输时延等等,正常情况下关系式应该是 a > b

所以说在客户端抓包的情况下,SYN-SYN/ACK 之间时间差值高于 SYN/ACK-ACK 时间差值

那么这种结论反过来说是否正确?在 SYN-SYN/ACK 之间时间差值高于 SYN/ACK-ACK 时间差值 的情况下,能否确认该数据包一定是在客户端上所抓取的?答案是否定的。 很明显的一种情况是在靠近客户端的地方捕获数据包(本文把这种捕获点场景定义为是中间端,详见下文)。

服务端

当在服务端上捕获数据包时,从收到客户端的 SYN 开始,服务器处理返回 SYN/ACK,此时 SYN/ACK 与 SYN 之间的时间差值为 a ,再经过中间网络设备传输至客户端,客户端回复确认 ACK 至服务端收到,此时 ACK 与 SYN/ACK 之间的时间差值为 b

综合考虑各端协议栈的处理能力和时延、网络传播时延和传输时延等等,正常情况下关系式应该是 a < b

所以说在服务端抓包的情况下,SYN-SYN/ACK 之间时间差值低于 SYN/ACK-ACK 时间差值

同样,那么这种结论反过来说是否正确?在 SYN-SYN/ACK 之间时间差值低于 SYN/ACK-ACK 时间差值的情况下,能否确认该数据包一定是在服务端上所抓取的?答案也是否定的。 同样很明显的一种情况是在靠近服务端的地方捕获数据包(本文把这种捕获点场景定义为是中间端,详见下文)。

中间端

当在中间端上捕获数据包时,从收到客户端的 SYN 开始,之后服务器处理返回 SYN/ACK ,再由中间端收到,此时 SYN/ACK 与 SYN 之间的时间差值为 a 。之后服务器 SYN/ACK 传输至客户端,客户端回复确认 ACK ,返至中间端收到,此时 ACK 与 SYN/ACK 之间的时间差值为 b

根据中间端选取的不同,a 与 b 值的关系式不定。如上文所说,如果是在靠近客户端的中间端抓包,a > b ;如果是在靠近服务端的中间端抓包,a < b ;如果刚好是在真的中间端, a ≈ b 也是有可能的。

小结

以上为正常情况下不同捕获点的 TCP 三次握手 IRTT 分析,强调正常情况下,是考虑客户端、服务端操作系统协议栈处理极快的情况,如果客户端或服务端的负载、性能或其他原因,导致处理慢,这个只能根据实际场景具体再判断。

同样对于 a 和 b 值的比较,具体是大多少或是小多少,这个要根据客户端和服务端两者之间的距离来判断。如果客户端和服务器在同一台接入交换机上进行通讯,在客户端或服务端所抓包显示的 a 和 b 的差值会很小,又假设是个低时延交换机使得中间网络时延极低,此时 a 和 b 的关系就更不好说了,这个得从同一个捕获点多个数据包样例来分析规律。如果客户端和服务器在广域网或互联网上进行通讯,在客户端或服务端所抓包显示的 a 和 b 的差值就会很大。

综合上述,汇总如下

捕获点IRTT 差值关系备注
客户端SYN-SYN/ACK 之间时间差值高于 SYN/ACK-ACK 时间差值
中间端SYN-SYN/ACK 之间时间差值高于 SYN/ACK-ACK 时间差值靠近客户端
SYN-SYN/ACK 之间时间差值低于 SYN/ACK-ACK 时间差值靠近服务端
SYN-SYN/ACK 之间时间差值和 SYN/ACK-ACK 时间差值关系不定其他
服务端SYN-SYN/ACK 之间时间差值低于 SYN/ACK-ACK 时间差值

Length 篇

什么是 Length ?Wireshark 中所定义的 Length 是指 Packet length 数据包或是分组长度(以字节为单位),对应的显示过滤字段和含义如下

frame.len
Frame length on the wire

最小长度

众所周知,以太网帧最小长度为 64 字节,而一般捕获到的数据包是不包含有 FCS ,所以数据包最小长度是 60 字节,其中数据字段最小长度就是 46 字节,也就是平常所说的 MTU 最小值 。

14 字节 ( Ethernet II 首部长度 ) + 46 字节 ( 数据字段最小长度要求 ) + 4 字节 ( FCS ) = 64 字节

那么对于一个标准的纯 ACK (不带数据)来说,它是多大呢?54 字节 ,明显小于数据包最小长度 60 字节的要求,

14 字节 ( Ethernet II 首部长度 ) + 20 字节 ( IPv4 首部长度 ) + 20 字节(TCP 首部长度) = 54 字节

因此在以太网传输中是需要填充全 0 数据,以满足最小长度 60 字节的要求。以下示例中 No.7 ACK 数据包填充了 6 字节的 0 值 。

但是为什么在上述示例中,仍可以看到 Length 长度为 54 字节 的数据包呢?No.3 ( TCP 三次握手的第三个包 ) 、No.6(含 FIN ) 和 No.9 等纯 ACK 。

原因是 Wireshark 的抓包方式(或者说是原理)和位置,Wireshark 抓包位置如果是在本地,那么对于本地产生所发出的数据包,是在进网卡之前所抓取的包,而填充数据以及 FCS 一般是由网卡硬件/驱动程序完成,所以 54 字节的组成并不包含填充数据。反过来说,60 字节的纯 ACK 是来自对方的数据包,包含了由对方网卡完成的填充数据,再由本端抓包时捕获到。

小结

所以说,观察 TCP 三次握手中的第三个包,也就是 ACK 的 Length ,如果是 54 字节的话,那么就是在 客户端 本地所抓取,而不是在 中间端 或是 服务端 所抓取。为什么能这样下定义?因为数据包从本地客户端传输出去后,在任意中间段捕获所看到的最小数据包长度都只会是 60 字节,同样 TCP 三次握手中的第三个包是由客户端所发出的,在服务端捕获当然看到的也只会是 60 字节。

那么扩展开来,

  • 怎么判断是捕获点是服务端的情况?单独以 TCP 三次握手的数据包是无法判断的,只有结合后续数据包,观察服务端本地所发出来的纯 ACK (或者其他数据包)是否 Length 小于 60 字节,辅助判断得出结论。
  • 怎么判断是捕获点是中间端的情况?观察包括 TCP 三次握手在内的所有数据包,没有 Length 小于 60 字节的数据包的话,一般都是在中间端所捕获。

综合上述,汇总如下

捕获点Frame Length备注
客户端TCP 三次握手中的第三个包以及其他纯 ACK 小于 60字节带有时间戳选项的情况除外
中间端包括 TCP 三次握手在内的所有数据包,没有 Length 小于 60 字节特殊情况,有剥离全0填充数据的
服务端TCP 三次握手的数据包无法单独判断,需结合服务端发出来的其他数据包,是否有 Length 小于 60 字节的

Length 中还有一种情况,是大于 MTU 的数据包长度,这和 Offload 特性相关,在后篇章节中概述。

TTL 篇

什么是 TTL ? Wireshark 中所定义的 TTL 是指 IPv4 TTL 字段,对应的显示过滤字段和含义如下

ip.ttl
Time to Live,1byte

A timer field used to track the lifetime of the datagram. When the TTL field is decremented down to zero, the datagram is discarded.

虽然从 TTL 字面上解释,是可以存活的时间,但实际上 TTL 是 IP 数据包在网络中可以转发的最大跳数。TTL 字段 由 IP 数据包的发送者设置,在 IP 数据包从源到目的的整个转发路径上,每经过一个路由设备,路由设备都会修改这个 TTL 字段值,具体的做法是把该 TTL 的值减 1,然后再将 IP 包转发出去。如果在 IP 包到达目的 IP 之前,TTL 减少为 0,路由器将会丢弃收到的 TTL=0 的 IP 包并向 IP 包的发送者发送 ICMP time exceeded 消息。

对于不同的操作系统,TTL值是不同的,简要版本如下

设备/操作系统TTL备注
Linux64/255
Windows128

示例

考虑到 TTL 字段 由 IP 数据包的发送者设置,所以可以检查 TCP 三次握手数据包中的 TTL 值,如果非 64、128、255 等标准值,则可以初步判断为捕获点为中间端。

那么反过来说,如果 TTL 值是 64、128、255 等标准值,是否能确定捕获点是在客户端或是服务端?答案是否定的。 因为如果端到端有类似二层交换机的设备,那么 TTL 值经过的时候是不会减 1 的,譬如在客户端或是服务端所在的接入交换机上抓包,TTL 值看到的值也会是 64、128、255 等标准值。因此这种情形下,需要结合实际环境,TTL 用以辅助判断。

Offload 篇

对于网卡 Offload 特性,大多数操作系统都支持多种形式的网络卸载,包括在 TCP/IP 协议栈中进行的 IP 分片、TCP 分段、重组、checksum 校验等操作,会转移到网卡硬件中进行,而不是 CPU 上,这样可以降低系统 CPU 的消耗,提高处理性能。

根据 Offload 功能的不同,在数据包捕获和分析上体现在两方面,一是与数据包 Checksum 相关,二是与数据包 Length 相关(前文提及)。

实际本篇部分已经超出 TCP 三次握手的范围,像是 Length 涉及到具体传输中大段数据的内容,因也是捕获点的不同表现,所以简单总结下。

数据包 Checksum

CheckSum Offload 实际上就是是将 TCP/UDP/IP 校验和工作交给了网卡硬件完成,以节约系统的 CPU 资源。譬如:以太网发送网卡计算以太网 CRC32 校验和,接收网卡验证这个校验和。如果接收到的校验和错误,Wireshark 甚至不会看到数据包,因为以太网网卡会丢弃该数据包。

TCP/UDP/IP 校验和

  • TCP 校验和计算三部分:TCP 头部、TCP 数据和 TCP 伪头部。TCP 校验和是必须的。
  • UDP 校验和计算三部分:UDP 头部、UDP 数据和 UDP 伪头部。UDP 校验和是可选的。
  • IP 校验和只计算检验 IP 数据报的首部,但不包括 IP 数据报中的数据部分。

TCP/IP 协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。

那么在基于端到端数据包正常传输的情况下,Wireshark 抓包位置如果是在本地,那么对于本地产生所发出的数据包,是在进网卡之前所抓取,在 Wireshark 开启 Validate the IPv4 checksum if possible 选项后,会显示校验和有问题。

而对端发送的数据包,在本端抓取,IPv4 显示校验和验证正常。

Wireshark TCP/UDP 校验和场景与 IP 校验和基本一致,稍微区别的是 TCP/UDP 校验和,TCP/IP 协议栈是随机填充校验和字段再交给网卡硬件,而 IP 校验和是填充零。

TCP 选项为 Validate the TCP checksum if possible

UDP 选项为 Validate the UDP checksum if possible

因此再次强调,基于端到端数据包正常传输的情况下(而不是校验和有问题的情况) ,客户端或服务端本地所发出的数据包(譬如 SYN-SYN/ACK-ACK ),在 Wireshark 开启 IP、TCP 或 UDP 等校验和功能的情况下,相对应的校验和会显示为错误(实际是正常的,网卡填充之前),而在中间端捕获数据包时,会显示为正常(网卡填充之后)。

数据包 Length

网卡 Offload 特性中的 TSO、GSO、LRO、GRO 等功能,意味着分片、分段和重组等功能会在网卡上卸载执行。

同样的原因, Wireshark 的抓包方式(或者说是原理)和位置,Wireshark 抓包位置如果是在本地,那么对于本地产生所发出的数据包,是在进网卡之前所抓取,所以对于开启 TSO、GSO 等功能的设备,会在抓包结果中可能看到大于 MTU 的数据包。(这里指的是标准 MTU 大小 1500)

反之,如果对于本地接收的数据包,Wireshark 是在网卡之后所抓取,如果开启了 LRO、GRO 等功能,会在抓包结果中可能看到大于 MTU 的数据包。

然后对于数据包传送出去,由于 MTU 的原因,数据包会产生分片、分段等,所以捕获点在中间端,捕获结果中是不会看到大于 MTU 的数据包。

其他篇

其他就是很常见会在网络传输中可能有所变化的字段,像是 Ethernet II 中的 MAC 地址、IPv4 中的 IP 地址、TCP/UDP 中的 Port 等等,这些字段在不同的场景以及不同的捕获点下,自然是可能不同的,在此不一一赘述。

总结

一言蔽之,“站的角度不一样,看到的结果也不一样”。