问题现象
微信、钉钉的流量经过FW后存在卡顿的情况,消息会加载较长时间才能发送或者接受;经过排查,发现和TCP状态检测有关。这里首先对问题结论做了总结,然后从理论+实验的形式对问题进行理解,加深对TCP状态监测的理解。
问题分析
- 卡顿分析
微信的收发消息需要TCP长连接监测在线状态,当关闭TCP状态检测后,将会匹配TCP简单状态会话参数配置,其默认的ESTABLISHED老化时间是60s,此时在FW上存在TCP的会话老化时间为60s。当60s内无收发消息ADX会释放会话,但微信对此会话仍在等待状态(微信认为此会话仍可靠)
收消息时,微信服务器通过此TCP会话通知客户端收消息,但因出口设备会话失效,导致客户端无法响应收消息请求。造成收消息过慢。
发消息时,若出口会话已经失效,但在客户端仍在等待状态,则会监测此TCP会话是否可用,若不可用则置为超时状态,重新建立新的TCP会话,此时消息正常发送(或延迟2-3s),由于TCP链接重新建立,此前未收到的消息又重新收到。
钉钉卡顿情况同理。 - TCP全状态检测的理解
TCP全状态监测指的不仅仅是TCP协议,也包括一些面向非连接的协议如UDP,ICMP等。数据报文都是有来有往的,如DNS,发一个DNS请求后,服务器会返回结果,因此防火墙可以根据请求包估计出返回包的协议、地址、端口五元组,等回应包到了以后进行相应匹配。同样ICMP,一个ping(echo request)包出去后,可以期望一个echo reply包回来,这也是一个连接过程。
其中开启状态监测和关闭状态监测差别如下图:
下面用实验来对手动开关状态,监测造成的影响进行简单分析。 - 实验过程
拓扑理解:PC访问目的NAT的公网IP:10.121.230.112,然后将流量引向Server,实现流量过FW设备,模拟前方微信钉钉访问的流量。
3.1开启TCP状态检测进行测试:
目的NAT配置:
会话参数(为了方便测试,这里将TCP简单状态会话参数的老化时间从60s改为20s):
开启TCP状态检测:
这里用netassist模拟微信客户端和服务器的收发消息:
客户端:
服务器端:
客户端模拟发送消息,在服务器端也同时收到了消息。
客户端发送:
服务器收到的信息:
此时去ADX上看会话情况,可以看到会话老化时间是1800s。
观察此时的报文,三次握手,以及消息的发送和接收是没有问题。
3.1关闭TCP状态检测进行测试:
此处只对状态检测进行修改,其他地方不做修改。
进行连接并发送消息,此时我们发现老化时间变成了简单状态的20s。
等老化时间过了之后,如果服务器端回消息,FW没有找到会话,会直接回RST断开连接,此时客户端发送消息也同样无法发送,服务器端会直接回RST。
在服务器端也检测到了连接断开。
此时客户端发送的任何消息都无法成功发送,只有断开连接重新进行三次握手才能继续发送消息和接收消息。
通过上述的分析,对TCP状态检测的实际效果做了一个分析。