Search K
Appearance
Appearance
除了我们之前介绍的 MSS、Window Scale 还有以一个非常重要的选项:时间戳(TCP Timestamps Option,TSopt)。这个选项在 TCP 头部的位置如下所示。

Timestamps 选项最初是在 RFC 1323 中引入的,这个 RFC 的标题是 "TCP Extensions for High Performance",在这个 RFC 中同时提出的还有 Window Scale、PAWS 等机制。
在 Wireshark 抓包中,常常会看到 TSval 和 TSecr 两个选项,值得注意的是第二个选项 TSecr 不是 secrets 的意思,而是 "TS Echo Reply" 的缩写,TSval 和 TSecr 是 TCP 选项时间戳的一部分。
TCP Timestamps Option 由四部分构成:类别(kind)、长度(Length)、发送方时间戳(TS value)、回显时间戳(TS Echo Reply)。时间戳选项类别(kind)的值等于 8,用来与其它类型的选项区分。长度(length)等于 10。两个时间戳相关的选项都是 4 字节。
如下图所示:

是否使用时间戳选项是在三次握手里面的 SYN 报文里面确定的。下面的包是 curl github.com 抓包得到的结果。

TSval 中TSecr 字段中,同时把自己的时间戳 3303928779 放在 TSval 中
Timestamps 选项的提出初衷是为了解决两个问题:
发送端在收到接收方发出的 ACK 报文以后,就可以通过这个响应报文的 TSecr
在启用 timestamp 选项之前,测量 RTT 的过程如下。

TCP 在发送一个包时,会记录这个包的发送的时间 t1,用收到这个包的确认包时 t2 减去 t1 就可以得到这次的 RTT。这里有一个问题,如果发出的包出现重传,计算就变得复杂起来,如下所示。

这里的 RTT 到底是 t3 - t1 还是 t3 - t2 呢?这两种方式无论选择哪一种都不太合适,无法得知收到的确认 ACK 是对第一次包还是重传包的的确认。TCP RFC6298 对这种行为的处理是不对重传包进行 RTT 计算,这样计算不会带来错误,但当所有包都出现重传的情况下,将没有包可用来计算 RTT。
在启用 Timestamps 选项以后,因为 ACK 包里包含了 TSval 和 TSecr,这样无论是正常确认包,还是重传确认包,都可以通过这两个值计算出 RTT。
Timestamps 选项带来的第二个作用是帮助判断 PAWS,TCP 的序列号用 32bit 来表示,因此在 2^32 字节的数据传输后序列号就会溢出回绕。TCP 的窗口经过窗口缩放可以最高到 1GB(2^30),在高速网络中,序列号在很短的时间内就会被重复使用。
下面以一个实际的例子来说明,如下图所示。

假设发送了 6 个数据包,每个数据包的大小为 1GB,第 5 个包序列号发生回绕。第 2 个包因为某些原因延迟导致重传,但没有丢失到时间 t7 才到达。这个迷途数据包与后面要发送的第 6 个包序列号完全相同,如果没有一些措施进行区分,将会造成数据的紊乱。
如果有 Timestamps 的存在,内核会维护一个为每个连接维护一个 ts_recent 值,记录最后一次通信的的 timestamps 值,在 t7 时间点收到迷途数据包 2 时,由于数据包 2 的 timestamps 值小于 ts_recent 值,就会丢弃掉这个数据包。等 t8 时间点真正的数据包 6 到达以后,由于数据包 6 的 timestamps 值大于 ts_recent,这个包可以被正常接收。
有几个需要说明的点
curl www.baidu.com 得到的包。
可以看到客户端发起 SYN 包时带上了自己的 TSval,服务器回复的 SYN+ACK 包没有 TSval 和 TSecr,从此之后的包都没有带上时间戳选项了。
三次握手中的第二步,如果服务端回复 SYN+ACK 包中的 TSecr 不等于握手第一步客户端发送 SYN 包中的 TSval,客户端在对 SYN+ACK 回复 RST。示例包如下所示。

待补充内容
随着 Timestamps 选项的引入,带来了一些安全性相关的问题,因为比较冷门,如果有读者感兴趣,可以留言,后面我再补充。