概述
如果你在客户端发现一些莫名其妙的 504 响应码,却不知道为什么,那么本文对你可能有帮助。
如果你查看 Nginx 日志发现有时出现 lua tcp socket connect timed out ,却不知道为什么,那么本文对你可能有帮助。
如果你发现你的机器向别的机器发送 RST 包,却不知道为什么,那么本文对你可能有帮助。
前段时间在排查一个传输层的问题,通过抓包发现我们的机器(此处可以认为为客户端)向服务端发出了 RST 包。我们的机器为什么会莫名其妙 reset 别人的连接呢?通过进一步排查,发现根本原因在三次握手的第二次丢包了!
这个问题需要同时在客户端与服务端抓包才能发现。如果不方便在双方向抓包,只能抓到单方向包的朋友,可以参考此文中单方向的包,与你的包进行比对,看是否也属于第三次握手中的第二次包丢失的情况。
报文解析
在最后的附录,附上了笔者当时排查用到的双方向报文,按需自行查阅。 如果你是为了调查 RST 问题,下方的原因解析可以先跳过,先看现象对比中的客户端与服务端部分,如果与你的抓包结果相匹配,则可以继续阅读此文。如果不匹配,那说明你遇到问题很可能不是这个,这篇文章可能帮不到你。 如果你是为了增加一些奇怪的知识,请按顺序继续向下阅读。
原因解析
上图是 TCP 三次握手中的第二次(SYN+ACK)报文丢失进而引发 RST 的完整过程,下面我用文字叙述一遍:
首先,正常的三次握手流程应该是:
- 客户端发出 SYN【SYN=1, Seq=x】
- 服务端返回 SYN+ACK 【SYN=1, ACK=1, Seq=y, Ack=x+1】
- 客户端返回 ACK【ACK=1, Seq=x+1, Ack=y+1】
而第二次握手报文丢失情况的过程是:
- 客户端向服务端发出握手报文,请求建立 TCP 连接,即第一次握手【SYN=1, ACK=0, Seq=x】
- 服务端向客户端回复 SYN+ACK 包,但是这个包在网络中丢失了
- 客户端等啊等,一直等不到服务端的 SYN+ACK,以为自己的 SYN 丢了,触发超时重传机制,向服务端又发了一个【SYN=1, ACK=0, Seq=z】
- 服务端也知道自己的 SYN+ACK 丢了,于是又重传了若干次 SYN+ACK。这时服务端突然收到了客户端重传的【SYN=1, ACK=0, Seq=z】。根据 RFC5691 指出:为了减轻通过 SYN 标志位进行的 RST 攻击(Blind Reset Attack Using the SYN Bit)的影响,服务端此时应立即发送一个【ACK=1, Seq=y, Ack=x+1】给客户端,用以重置连接。
- 客户端在接收到 【ACK=1, Seq=y, Ack=x+1】后,立即回复【RST=1, Seq=x+1】。此处的 Seq=x+1 表明:这个 RST 是前面那个 ACK:【ACK=1, Seq=y, Ack=x+1】引起的。然后,双方断开连接。
至此,服务端第二次握手的 SYN+ACK 包丢失,最终导致了客户端“莫名其妙”地发出 RST 包。
PS:KleeNet 论文中指出服务端回复 ACK 给客户端是因为服务端忽略了重传报文的 SYN 标志位,并认为这是一个 BUG。而实际上,这并不是一个 BUG,而是 TCP 为了减轻通过 SYN 标志位进行的 RST 攻击(Blind Reset Attack Using the SYN Bit)的影响 ,有意为之的。
PS:我们事后排查,是因为客户端与服务端之间存在防火墙,防火墙的硬件模块故障导致某些 TCP 包被防火墙丢弃,进而引发丢包,进而引发了 TCP 建连失败,进而引发了 Nginx 的 504 问题
现象对比
客户端
如果你是客户端,你发现你的抓包结果有如下几个特征,那么极有可能就是本文所述的情况:
- 最开始向服务端发送了一个【SYN=1, Seq=x】
- 从来没收到过 SYN+ACK 报文
- 存在 SYN 报文的超时重传(TCP Retransmission)
- 在发出 RST 报文前突然收到一个 ACK 报文,且 Ack=x+1
服务端
如果你是服务端,你发现你的抓包结果有如下几个特征,那么极有可能就是本文所述的情况:
- 最开始收到了客户端发来的【SYN=1, Seq=x】
- 存在很多 SYN+ACK 的重传报文(TCP Retransmission)
- 在若干个 SYN+ACK 的重传报文之后突然又收到了客户端的 SYN
- 在收到了客户端 SYN 后,给客户端返了一个 ACK,且 Ack=x+1
附录
客户端报文
服务端报文
参考文献
KleeNet: Discovering insidious interaction bugs in wireless sensor networks before deployment RFC5961
|