問題現象
內網的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,發現問題解決了。