问题背景
该问题案例来自于公众号朋友分享,故障现象比较少见,简单分析一下 TCP 三次握手中出现的 RST 连接问题。 ? 用户反馈的问题现象是在客户端通过 curl 访问 url ,访问不了,现象必现。
问题分析
网络拓扑
首先简单了解下网络拓扑,内网环境有多个客户端,通过防火墙出互联网访问服务器。 ?
数据包分析
考虑到用户的问题现象比较明确,直接在问题客户端上通过抓包进行分析,数据包可以看到明显的异常现象。
主要分析如下:
- TCP 握手阶段,以规律性的 SYN-SYN/ACK-RST 进行重复,并未成功建立起连接;
- SYN 重传,每次超时的时间是 1秒 、2秒 、4秒 、8秒 、16秒;
- 服务器能正常返回 SYN/ACK,排除服务端口未打开问题;
- RTT 时间约 9ms;
- 客户端和服务器均支持 WSOPT 以及 TSOPT;
- Seq num 和 Ack num 未见异常;
- 客户端主动发起 RST。
考虑到 TCP 三次握手阶段客户端主动发起 RST,那么很有可能与客户端有关,进一步检查,发现 TSOPT 可能有以下问题:
客户端 SYN
服务器 SYN/ACK
SYN/ACK 中的 TSecr 值 2174718965,不同于 SYN 中 TSval 值 538477964 , 正常情况下应该相同,且 TSval 值为 0 ,疑似造成客户端 RST 。之后尝试在客户端关闭 tcp Timestamp 选项支持后,客户端 curl 请求恢复正常。 ? 因公网服务器侧无法抓包,因此 SYN/ACK 中的 TSOPT 异常值无法完全定位问题点。可能是服务器,也可能是中间传输设备引起。 ? TSOPT 值仅在客户端和服务器两端均支持该选项的情况下,才会在会话中一直携带。上述客户端关闭选项的情况下,则服务器因此也不会发送带有 TSOPT 的数据包 。 ?
RFC 7323 TCP Timestamps option (TSopt): Kind: 8 Length: 10 bytes Timestamp Value (TSval). 32 bits. This field contains the current value of the timestamp clock of the TCP sending the option.
Timestamp Echo Reply (TSecr). 32 bits. This field is only valid if the ACK bit is set in the TCP header. If it is valid, it echos a timestamp value that was sent by the remote TCP in the TSval field of a Timestamps option. When TSecr is not valid, its value must be zero. The TSecr value will generally be from the most recent Timestamp option that was received; however, there are exceptions that are explained below. A TCP may send the Timestamp option in an initial SYN segment (i.e., segment containing a SYN bit and no ACK bit), and may send a TSopt in other segments only if it received a TSopt in the initial SYN segment for the connection.
?
扩展分析
在排障过程当中,也曾在防火墙连接互联网侧抓取包,抓取了客户端 2 正常请求的数据包,如下: 此处稍有不同的是,SYN/ACK 中 TSval 和 TSecr 的值均为 0 ,和 RFC 7323 所描述的有所不同,但后续是可以正常建连的。 ? 因为环境已无法复现,仅能推测出是在不同平台上实现的区别,TCP 三次握手阶段部分字段值以 0 替代,像是 ip.id ,或是这里的 TSval 和 TSecr 。在正常完成三次握手后,相应字段会以实际值继续交互,譬如数据包 6 中的 TSval 和 TSecr 值。
再展示另外两个简单示例
正常两端均支持 TSOPT 的连接,之后交互中均带有 TSOPT 值。
仅一端支持 TSOPT 的连接,之后交互中并无 TSOPT 值。
问题总结
其实说到 RST ,实际上产生 RST 数据包的原因会有很多,暂时整理总结的如下:
- 连接一个未打开的端口;
- 发送到一个已关闭的连接;
- 请求超时;
- socket 选项设置(SO_LINGER);
- 应用程序问题;
- 异常 SEQ 或 ACK Num ;
- 安全策略导致;
- 时间戳问题;
- 正常关闭连接;
- …
总之千奇百怪,需要根据实际环境再做具体分析。 ?
感谢阅读,更多技术文章可关注个人公众号:Echo Reply ,谢谢。
|