发送TCP请求连接远端服务器,在规定时间内没有返回ACK响应,这种情况一般我们称之为三次握手超时。
三次握手连接超时的原因主要有两种:
1)client发送SYN后,进入SYN_SENT状态,等待server的SYN+ACK超时;
2)server收到client发送的SYN后,返回SYN+ACK,进入SYN_RECV状态,等待client的ack超时;
当超时发生时,就会重传,一直到某一个阈值,还没有收到回应,则会放弃,终止本次连接的创建。
本文我们就来模拟下第一种超时现象。
1.环境准备
笔者准备一个Ubuntu docker应用,启动两个窗口,一个用于发送telnet命令,另一个用于启动tcpdump命令监听。
笔者向不存在的一个ip(172.17.0.6)端口(8080)发送telnet命令,我们通过tcpdump命令来查看整个网络请求过程。
2.模拟向不存在的ip发送建立连接请求 2.1 telnet命令执行
root@aa4e7f274852:/tmp# telnet 172.17.0.6 8080
Trying 172.17.0.6...
telnet: Unable to connect to remote host: No route to host
telnet命令很快就返回了一个报错,无法连接远端服务器
2.2 tcpdump监听
在上述telnet命令发送之前,tcpdump命令窗口就需要提前打开
# 当前Ubuntu没有其他请求,直接tcpdump就可以了,如果还有其他请求则需要加上src port等过滤信息
root@aa4e7f274852:/# tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:52:15.423557 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:15.423736 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:15.494858 IP aa4e7f274852.54353 > 192.168.65.5.domain: 37904+ PTR? 6.0.17.172.in-addr.arpa. (41)
10:52:15.513993 IP 192.168.65.5.domain > aa4e7f274852.54353: 37904 1/0/0 PTR 172.17.0.6. (88)
10:52:15.600244 IP aa4e7f274852.57219 > 192.168.65.5.domain: 25831+ PTR? 5.65.168.192.in-addr.arpa. (43)
10:52:15.614004 IP 192.168.65.5.domain > aa4e7f274852.57219: 25831 1/0/0 PTR 192.168.65.5. (94)
10:52:16.469452 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:16.469594 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:17.492538 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:17.492739 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:18.516694 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:18.516907 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:19.540455 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:19.540645 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:20.565124 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
10:52:20.565322 ARP, Request who-has 172.17.0.6 tell aa4e7f274852, length 28
可以看到,当前Ubuntu机器不断的发送ARP请求到子网,来询问谁知道172.17.0.6的mac地址信息,但是最终直到超时也没有获取响应。
以上就是我们对一个不存在的主机发送请求时的正常回应,主要卡在ARP协议获取mac地址上了,此时客户端还没有来及发送SYN请求。
那么我们主动设置下ip的mac信息,来模拟下客户端发送SYN超时的情况。
3.模拟客户端SYN请求超时
先来看下当前的arp信息
root@aa4e7f274852:/# arp
Address HWtype HWaddress Flags Mask Iface
172.17.0.1 ether 02:42:42:74:1e:a1 C eth0
172.17.0.2 ether 02:42:ac:11:00:02 C eth0
172.17.0.6 (incomplete) eth0
172.17.0.6并没有对应的mac地址,我们通过arp命令主动设置一个mac地址(不要与当前mac地址重复即可)
3.1 手动设置ip对应mac信息
root@aa4e7f274852:/# arp -s 172.17.0.6 02:42:ac:11:00:01
root@aa4e7f274852:/# arp
Address HWtype HWaddress Flags Mask Iface
172.17.0.1 ether 02:42:42:74:1e:a1 C eth0
172.17.0.2 ether 02:42:ac:11:00:02 C eth0
172.17.0.6 ether 02:42:ac:11:00:01 CM eth0
手动设置后,再来进行上述的2.1 2.2操作
3.2 telnet命令执行
root@aa4e7f274852:/tmp# date; telnet 172.17.0.6 8080; date
Sat Apr 30 10:55:53 UTC 2022
Trying 172.17.0.6...
telnet: Unable to connect to remote host: Connection timed out
Sat Apr 30 10:58:02 UTC 2022
可以发现整个请求时间明显长了很多。
此前2.1请求很快就返回超时失败了,这里却花了两分钟。
中间发生了什么呢?通过tcpdump来一探究竟吧
3.3 tcpdump监听
在上述telnet命令发送之前,tcpdump命令窗口就需要提前打开
root@aa4e7f274852:/# tcpdump
10:55:53.284573 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038423341 ecr 0,nop,wscale 7], length 0
10:55:53.284611 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038423341 ecr 0,nop,wscale 7], length 0
...
10:55:54.332652 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038424389 ecr 0,nop,wscale 7], length 0
10:55:54.332814 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038424389 ecr 0,nop,wscale 7], length 0
10:55:56.376816 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038426438 ecr 0,nop,wscale 7], length 0
10:55:56.377233 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038426438 ecr 0,nop,wscale 7], length 0
...
10:56:00.409275 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038430470 ecr 0,nop,wscale 7], length 0
10:56:00.409464 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038430470 ecr 0,nop,wscale 7], length 0
10:56:08.599729 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038438661 ecr 0,nop,wscale 7], length 0
10:56:08.599898 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038438661 ecr 0,nop,wscale 7], length 0
10:56:24.983778 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038455045 ecr 0,nop,wscale 7], length 0
10:56:24.983980 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038455045 ecr 0,nop,wscale 7], length 0
10:56:57.244222 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038487301 ecr 0,nop,wscale 7], length 0
10:56:57.244336 IP aa4e7f274852.52360 > 172.17.0.6.http-alt: Flags [S], seq 2562445399, win 64240, options [mss 1460,sackOK,TS val 2038487301 ecr 0,nop,wscale 7], length 0
我们来观察下这个SYN请求发送的规律
次数时间点110:55:53210:55:54310:55:56410:56:00510:56:08610:56:24710:56:57总共重试了6次,重试时间的间隔为:1秒、2秒、4秒、8秒、16秒、33秒,基本是成指数级避退的。
那么这个6是可配置的吗?配置在了哪里呢?
通过查看Linux系统配置参数,我们看到了SYN重试次数配置
root@aa4e7f274852:/# sysctl -a | grep net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries = 6
疑问:
从SYN请求发送的全过程了解到,总共耗时为1分钟,但是上面telnet命令却持续了两分钟才返回,这个实在百思不得其解。
希望知道答案的同学帮忙解读下,拜谢!
总结:
本文模拟了在主动配置了arp信息的情况下,对不存在的ip地址发送建立连接请求时,SYN请求会不断重试,一直达到系统配置阈值(net.ipv4.tcp_syn_retries)为止,而且重试间隔成指数级避退。
参考: