问题现象
内网的Linux服务器A日常需要通过curl命令连接公网的Linux服务器B,传输数据并执行脚本。A连接B的时候过了一个SNAT转换。
某日突然发现服务器A curl连接服务器B失败,但ping服务器B可通,telnet 443端口也正常,检查服务器A和B的配置情况,没有修改痕迹。
curl -v https://<服务器B的域名>
发现走到client hello之后就不往下走了
苦恼了许久,最后在google上找到了解决办法。特此记录
问题原因&解决方法
问题原因:
当客户端发出的syn包带有时间戳的情况下,经过NAT转换后,如果使用的端口被之前使用过,而且时间戳大于本次syn包中的时间戳。系统将会直接丢弃。造成本次链接无法正常完成TCP/IP的3次握手。
net.ipv4.tcp_timestamps这个参数默认是开启的,它会复用链接,并去检查这个IP包里面的时间是不是比当前的时间大,如果大,那么就丢弃该包(见rfc1323,TCP相关的,网上查到的),从而造成SYN-SENT发送后,没有回应。
然后检查LinuxA服务器的时间,发现Linux服务器A的时间比B快了5分钟,基本可以确认就是这个问题了
解决方法:
在Linux服务器A上 修改/etc/sysctl.conf文件,在最后增加如下内容
# Controls the timestamps check in syn-send
# 0 --> do not check
# 1 --> check
net.ipv4.tcp_timestamps = 0
配置完成后,重载sysctl规则
sysctl -p
随后查看生效情况
sysctl -a |grep timestamp
net.ipv4.tcp_timestamps = 0
再在Linux服务器A上curl服务器B,发现问题解决了。