linux开启tcp_timestamps和tcp_tw_recycle引发的问题研究

linux开启tcp_timestamps和tcp_tw_recycle引发的问题研究,第1张

概述环境:centos7.4 内核版本3.10 最近看内核参数tcp_tw_recycle(该参数在内核 4.12 之后被移除),它用于快速回收处理TIME_WAIT状态的socket。搜索该参数相关的资

环境:centos7.4 内核版本3.10

最近看内核参数tcp_tw_recycle(该参数在内核 4.12 之后被移除),它用于快速回收处理TIME_WAIT状态的socket。搜索该参数相关的资料,发现同时启用该参数和tcp_timestamps后有可能在NAT环境下导致客户端始连接失败,抓包表现为:客户端一直发送SYN报文,但服务端不响应。但这些文章中只给出了如何解决问题,并没有给出如何复现问题。特别怪异的是,服务端是被动关闭的,并不会进入TIME_WAIT状态,到底怎么产生的呢?

先使用如下拓扑复现该场景,其中10.85.3.51机器为NAT服务器,10.85.1.2和10.85.3.52通过NAT服务器访问server 10.85.3.111:19090

+-------------+|  10.85.1.2  +------------++-------------+            |                     +-----+-------+         +---------------------+                     |  3.51 +---------+  3.111:19090  +                     +-----+-------+         +---------------------++-------------+            ||  3.52 +------------++-------------+

在10.85.3.51机器上配置如下iptables表项,用于转发clIEnt和server之间的TCP报文。(10.85.3.51需要开启net.ipv4.ip_forward功能)

# iptables -t nat -I PREROUTING -d 3.51 -p tcp -m tcp --dport 29090 -j DNAT --to 3.111:19090
# iptables -t nat -I POSTROUTING -d 3.111 -p tcp -m tcp --dport 19090 -j SNAT --to 3.51
首先开启tcp_timestamps,关闭tcp_tw_recycle

在10.85.3.111上进行抓包并且启动10.85.1.2和10.85.3.52进行连接。报文如下,其中第4和第7条为两个连接的TCP SYN报文,后续server都进行了回复,两条连接正常建链

1 # tcpdump -i eth0 src port 19090 or dst port 190902 tcpdump: verbose output suppressed,use -v or -vv for full protocol decode3 Listening on eth0,link-type EN10MB (Ethernet),capture size 262144 bytes4 17:39:27.970358 IP 3.51.57104 > 3.111.19090: Flags [S],seq 2466985868,win 25200,options [mss 1260,sackOK,TS val 3075335984 ecr 0,nop,wscale 7],length 05 27.970417 IP 19090 > 57104: Flags [S.],1)">2846609535,ack 2466985869,1)">24960,TS val 2612548200 ecr 3075335984,1)">6 27.970783 IP 19090: Flags [.],1)">1,1)">197,options [nop,1)">3075335985 ecr 2612548200],1)">0
7 29.059890 IP 34230 > 2892210420,TS val 1740811766 ecr 8 29.059949 IP 34230: Flags [S.],1)">3434079625,1)">2892210421,1)">2612549289 ecr 1740811766,1)">9 29.060623 IP 1740811767 ecr 2612549289],1)">0

启用tcp_tw_recycle,重复上面 *** 作。发现即使后面一个连接的SYN报文的时间戳小于前面一个连接的SYN报文中的时间戳,也能够正常建链,并没有出现连接异常。

49:12.111152 IP 58164 > 2599215624,1)">3075920126 ecr 12.111221 IP 58164: Flags [S.],1)">795235982,1)">2599215625,1)">2613132341 ecr 3075920126,1)">12.111766 IP 3075920127 ecr 2613132341],1)">12.871092 IP 34234 > 3696139072,1)">1741395578 ecr 12.871149 IP 34234: Flags [S.],1)">3928136503,1)">3696139073,1)">2613133101 ecr 1741395578,1)">12.871697 IP 1741395579 ecr 2613133101],1)">0
后来在这篇文章中找到灵感。正常TCP TIME_WATI时长为2MSL,用于挥手阶段最后一个ACK报文的重传,以及防止当前连接上滞留的报文影响到下一个连接。当启用tcp_tw_recycle后,系统会在一个RTO的极短时间内回收处于TIME_WAIT状态的socket,但仍然无法杜绝接收到上一个连接在链路上滞留的报文。为了防止这种情况的发生,在启用tcp_tw_recycle的情况下,由于已经释放了socket,系统无法使用socket来标记一条连接,只能退而求其次,通过判断对端IP发过来的报文的时间戳来判断该报文是新产生的还是老的报文,如果是老报文,则丢弃且不回复。

因此复现场景为:服务端主动断开与客户端的一条连接,在后续的TCP_PAWS_MSL(60s)时间内,如果客户端发过来的SYN报文的TSVal时间戳小于系统保留的上一个连接的时间戳,则该SYN报文会被丢弃,实际表现为客户端连接超时或很慢(60s之后可正常连接)

 首先server使用命令 telnet 10.85.3.51 22 连接NAT机器,并立即断开连接,此时server会很快回收一个TIME_WAIT的socket。在server端抓包,可以看到保存的该连接上对端发来的最后一个时间戳为3035582641
 1 # tcpdump -i eth0 src host 3.51 or dst host 3.51 2 tcpdump: verbose output suppressed,1)"> 3 Listening on eth0,1)"> 4 22:45:10.015335 IP 10.85.3.111.49416 > 3.51.ssh: Flags [S],1)">1039611753,1)">2630890245 ecr  5 10.016055 IP 3.51.ssh > 10.85.3.111.49416: Flags [S.],1)">489573340,1)">1039611754,1)">3035577005 ecr 2630890245,1)"> 6 10.016074 IP 10.85.3.111.3.51.ssh: Flags [.],1)">2630890246 ecr 3035577005],1)"> 7 10.023482 IP 49416: Flags [P.],1)">1:22,1)">195,1)">3035577013 ecr 2630890246],1)">21 8 10.023507 IP 10.85.3.111.2630890253 ecr 3035577013],1)"> 9 10 15.648562 IP 10.85.3.111.3.51.ssh: Flags [F.],1)">2630895878 ecr 11 15.649128 IP 49416: Flags [.],1)">2,1)">3035582639 ecr 2630895878],1)">12 15.651394 IP 49416: Flags [F.],1)">3035582641 ecr 13 15.651411 IP 10.85.3.111.23,1)">2630895881 ecr 3035582641],1)">0

在断开连接的TCP_PAWS_MSL时间内启动10.85.1.2通过NAT连接到server,server端抓包可以看到该连接的SYN报文的时间戳1759176699远小于保存的时间戳3035582641,此时server端丢弃接收到的所有SYN报文,客户端连接超时。

1 33.942378 IP 34264 > 668096838,1)">1759176699 ecr 2 34.942300 IP 1759177700 ecr 3 36.946320 IP 1759179704 ecr 0
结合上述测试可以得出结论:同时启动tcp_timestamps和tcp_tw_recycle可能会导致客户端连接不上前提条件是server主动断开过与客户端的连接(可能是服务重启等原因),导致server处于TIME_WAIT状态的socket被快速回收,如果在TCP_PAWS_MSL时间内接收到客户端经NAT发过来的报文的时间戳小于前一个连接保存的时间戳,该报文会被认为是老链路残留的报文而丢弃。进而可以得出:在NAT场景下一定不能启用tcp_tw_recycle;NAT场景下单独启动tcp_timestamps不会影响正常使用,连接断链后会在2MSL过后回收socket;生产中不要使用tcp_tw_recycle,即使没有使用到NAT设备,但当前虚拟化环境下用到NAT的地方很多,如kubernetes的service等

TIPS:

为了复现如上问题,曾尝试过使用1.17.0版本的Nginx作为NAT服务。但发现经过Nginx的所有连接的SYN报文的时间戳都会被Nginx修改,且后面连接SYN报文的时间戳一定大于前面连接的SYN报文中的时间戳,因此Nginx下面不会出现客户端方式失败的场景

参考:

NAT网络下TCP连接建立时可能SYN包被服务器忽略-tcp_tw_recycle 总结

以上是内存溢出为你收集整理的linux开启tcp_timestamps和tcp_tw_recycle引发的问题研究全部内容,希望文章能够帮你解决linux开启tcp_timestamps和tcp_tw_recycle引发的问题研究所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1015386.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)