今天遇到一个非常诡异的问题。具体表现如下(两台机器分别用src和dst表示,两台机器在不同的数据中心,连接需要走公有网络)
- 在src主机,访问dst的8181端口,发现连接无法建立。
- src访问dst的非8181端口,连接正常建立
- 在src主机所在的集群,访问dst的8181端口,连接正常建立
- 在其它外网设备访问dst的8181端口,连接正常
- 通过内网访问dst的8181端口,连接正常
- 两个服务器都没有设置防火墙
于是在两边的节点分别抓了包,包的内容如下:
这是在src节点抓的包
这是在dst节点抓的包
乍一看,非常唬人,两边的节点都在收发rst包。那看来问题应该就是为什么会有rst包了。
重新组织包收发过程
这个时候就应该看图说话了,wireshark打开的包是两边分别抓到的,我们需要重新构建包发送的流程。我们以(8181, 54335)这一组画一下时序图
上图编号是对应抓包方在wireshark中显示的包号,黑色包号是发出的包,红色包号是收到的包。
可以看到在客户端,其实是按照基本法来的,三次握手,握手之后发一个数据包,然后在收到rst之后重置连接。
但是在服务端,就没有按照基本法来了。三次握手,第二次握手发出去之后,就收到了四个rst包,而且这四个rst包在客户端没有抓到。由于rst包的原因,之后客户端再发来的两个包,就都被认为非法,返回了rst。
由此可见,客户端收到的包,都是服务器发出来的。只是服务器这里,收到了四个莫名其妙的包。
问题处理
实际上没啥好处理的。这个很明显,就是中间有防火墙作祟,发了好几个rst包回来。
给两边云主机服务商提工单,要求检查路由,防火墙等,之后自然是恢复了,只是由于这个rst包不能判断从哪里发出来(至少我的能力范围内不行),同时没有进一步路由信息(当时制作了ping路由测试),所以两边陷入无休止扯皮中。我估计是某一方的防火墙出了问题,收到工单后悄咪咪修复了,不肯告知原因吧。
倒是阿里给我回了一个建议,下次遇到这个问题,可以使用traceroute进行节点测试:
这个大概就是用traceroute实现节点监测。嗯,看起来好像很科学,但是实际上不行。
首先来看看traceroute的执行原理。
traceroute原理
相当大部分人,都懂traceroute是设置了ip层的ttl来生成这个路由表的。但是进一步,如果用traceroute,怎么探测tcp端口可用呢?很简单,还是设置ttl,只不过这个时候上层不再使用ICMP的ping请求,而是发tcp的syn报文。
然后如果收到路由返回ICMP的ttl exceeded报文,说明节点没有拦截这个请求。如果被drop掉了或者返回了rst,那可能就是防火墙拦截了。
但是如果收到正常恢复的syn+ack呢?实际上这个时候traceroute就发送rst报文了。他并没有完成完整的三次握手。而从上面的抓包来看,客户端的三次握手,是正常的,所以这个时候,traceroute并不能帮助我们解决问题。
更新
在我把traceroute原理怼回去之后,对方乖乖跟我要了包,跟我方承认是防火墙拦截了。到此,再回复一句质疑下对方防火墙的设计,就打完收工了