linux --- 一切皆文件
分类: C/C++
2017-11-10 10:46:46
Client发送SYN包后收到ACK而不是SYN/ACK
拓扑如下:
异常现象:
Client偶尔出现到Server的链接异常。Client发送SYN包,在FW内网侧抓包,没有任何回应报文,在FW外网侧抓包,发现Server回了一个ACK报文,并且SEQ和ACK号异常。
问题排查与确认:
由此可推断出,FW丢弃了Server回应的ACK报文。经过与防火墙公司确认,此公司确实会丢弃此类ACK报文,将此类报文放行即可解决问题。
原因分析:
Client1 ip:1.1.1.1:12345请求到server ip:222.222.222.80。到达防火墙之后,将Client1的ip/port改成10.10.10.10:12345。(虽然NAT使用了动态端口模式,但是如果12345这个端口在会话表中没有,则防火墙还是将12345作为源端口,并不会重新选择随机端口,当12345源端口正在使用,则防火墙重新随机选择新端口作为源端口。)
Client1发送http请求,请求结束后,Server主动关闭链接发送FIN/ACK报文,最终Server进入TIME-WAIT状态(Linux等待60秒)。但是FW会很快将此会话超时掉,此FW time-wait默认超时时间为1秒。
Server端会话 10.10.10.10:12345 222.222.222.222:80此会话正在Time-wait状态超时时。在时间隔大于1秒小于60秒时间中,Client2又以12345端口发送请求,会话信息如下:1.1.1.2:12345 222.222.222.222:80。此syn包到达FW,FW会进行SNAT,转换为10.10.10.10:12345 222.222.222.222:80(此时Client1使用12345端口的会话在FW上已经超时了,所以转换出去源端口还是12345)。
但是,此时Server端还是处于Time-Wait状态,收到一个syn包,Server会做如下操作:
1) 如果此syn包的SEQ号大于Server端此会话收到最后一个包的SEQ号,则新建会话,回应SYN-ACK报文
2) 如果此syn包的SEQ号小于Server端此会话收到最后一个包的SEQ号,则Server认为是此会话之前的报文,只是延迟到达而已。则返回一个ACK报文。
异常情况下,就是发送的SYN包的SEQ小于Server端此会话收到最后一个包的SEQ号,Server在Time-out状态下返回ACK报文。但是此时FW则认为此ACK报文异常,则将此报文丢弃。
如果防火墙规则不丢弃此ACK报文:
如果此ACK报文通过FW,回到了Client2,Client2则认为此ACK包异常,并且此链接也异常,则Client2直接会反弹RST报文到Server,Server收到RST报文后,立即将Time-wait状态的会话释放。此时Client2继续会发送一个相同源端口的SYN包到到Server。会话建立成功。
参考资料:
注意:
1.此问题只针对Server主动关闭链接的场景。
2.如果Server上的会话在ESTABLISH状态,收到syn包,也会回应ACK报文。
3.可给Client1和Client2各分配一个NAT公网地址,作为应急方案。