みなさんこんにちはヒロウミです。
「[改訂新版]プロのためのLinuxシステム構築・運用技術 (Software Design plus)」を読んでいてTCPのセッション確立タイムアウトについて出てきていたので実際に実験して みたいと思います。
とても面白い書籍なのでLinuxを普段業務で使う方におすすめです。
環境
- クライアント(CentOS7)
- 192.168.0.10/24
- サーバ(CentOS7)
- 192.168.0.7/24
実験内容
- クライアント -> サーバにSSH接続を試みる
- スリーウェイハンドシェイクが始まる
- ここでサーバからの「SYN/ACK」を意図的にクライアントで捨てる
- つまりクライアント->サーバのSYNに対するSYN/ACKを受信しないことになるのでクライアントはSYNをリトライし続ける
- クライアントのRTO(Retransmission Time Out)で127秒で接続(SYNの再送)を切断するかを確認する
実験
(クライアントで前準備)
(firewalldを止めておく)
# systemctl stop firewalld
(192.168.0.7:サーバからのTCP通信を全て捨てる) ※つまりサーバからの「SYN/ACK」の受信を拒否するので、クライアントは「SYN」をリトライし続ける
# iptables -I INPUT -p tcp -m tcp --source 192.168.0.7/32 -j DROP
(確認)
# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 871 packets, 113K bytes)
pkts bytes target prot opt in out source destination
45 2700 DROP tcp -- * * 192.168.0.7 0.0.0.0/0 tcp
(クライアントで確認用のtcpdumpを張っておく)
# tcpdump -i enp1s0 port 22 and dst 192.168.0.7
※ここでTCP接続セッション確立再送の様子をみる ※RTOでは1秒,2秒,4秒,8秒・・・と再送の秒すうが増えていくはず
(クライアントからTCPセッション確立タイムアウトの確認)
(127秒で接続切れた)
# date ; ssh vagrant@192.168.0.7 ; date
2019年 2月 25日 月曜日 20:44:24 JST
ssh: connect to host 192.168.0.7 port 22: Connection timed out
2019年 2月 25日 月曜日 20:46:31 JST
(クライアント側のtcpdumpを確認)
予想通り20:44:24以降1秒,2秒,4秒,8秒,16秒,32秒とリトライ時間が増加している
6回目の再送(20:45:27)を実施したあとは64秒待って接続を諦めてる
# tcpdump -i enp1s0 port 22 and dst 192.168.0.7
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp1s0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:44:24.724462 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195840518 ecr 0,nop,wscale 7], length 0
20:44:25.725593 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195841520 ecr 0,nop,wscale 7], length 0
20:44:27.729585 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195843524 ecr 0,nop,wscale 7], length 0
20:44:31.741591 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195847536 ecr 0,nop,wscale 7], length 0
20:44:39.757622 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195855552 ecr 0,nop,wscale 7], length 0
20:44:55.789627 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195871584 ecr 0,nop,wscale 7], length 0
20:45:27.821621 IP localhost.localdomain.42378 > 192.168.0.7.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195903616 ecr 0,nop,wscale 7], length 0
(サーバ側でTCP接続要求の確認しておく)
# tcpdump -i enp0s8 port 22 and src host 192.168.0.10
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
11:44:24.725284 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195840518 ecr 0,nop,wscale 7], length 0
11:44:25.726659 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195841520 ecr 0,nop,wscale 7], length 0
11:44:27.730566 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195843524 ecr 0,nop,wscale 7], length 0
11:44:31.742354 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195847536 ecr 0,nop,wscale 7], length 0
11:44:39.758633 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195855552 ecr 0,nop,wscale 7], length 0
11:44:55.790653 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195871584 ecr 0,nop,wscale 7], length 0
11:45:27.822760 IP 192.168.0.10.42378 > controller.ssh: Flags [S], seq 3551349053, win 29200, options [mss 1460,sackOK,TS val 195903616 ecr 0,nop,wscale 7], length 0
追加実験
ちなみにTCPの再送回数はカーネルパラメータの「net.ipv4.tcp_syn_retries」でいじれる。
CentOS7でデフォルトは以下の通り6回。最初の実験のリトライ回数とも一致してますね。
# sysctl -a | grep "net.ipv4.tcp_syn_retries"
net.ipv4.tcp_syn_retries = 6
では、最後にTCP接続リトライ回数をいじってTCPセッション確立のタイムアウトの秒数を伸ばしてみましょう。
予測では7回目の再送でRTOの上限秒数である「120秒」待つはずなので、「127 + 120 = 247秒」待つはずですね。それでは実験してみます。
手順はさっきと同じです。
(TCPリトライ上限回数をあげる)
# sysctl -w net.ipv4.tcp_syn_retries=7
net.ipv4.tcp_syn_retries = 7
(クライアントからTCPセッション確立タイムアウトの確認)
予想通り247秒(4分7秒で接続が切れた)
# date ; ssh vagrant@192.168.0.7 ; date
2019年 2月 25日 月曜日 21:11:01 JST
ssh: connect to host 192.168.0.7 port 22: Connection timed out
2019年 2月 25日 月曜日 21:15:08 JST
(クライアント側のtcpdumpを確認)
予想通り20:44:24以降1秒,2秒,4秒,8秒,16秒,32秒,64秒とリトライ時間が増加している
7回目の再送(21:13:08)を実施したあとはRTOの上限値である120秒待って接続を諦めてる
# tcpdump -i enp1s0 port 22 and dst 192.168.0.7
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp1s0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:11:01.575711 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197437370 ecr 0,nop,wscale 7], length 0
21:11:02.577596 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197438372 ecr 0,nop,wscale 7], length 0
21:11:04.581588 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197440376 ecr 0,nop,wscale 7], length 0
21:11:08.589595 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197444384 ecr 0,nop,wscale 7], length 0
21:11:16.605589 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197452400 ecr 0,nop,wscale 7], length 0
21:11:32.621619 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197468416 ecr 0,nop,wscale 7], length 0
21:12:04.685612 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197500480 ecr 0,nop,wscale 7], length 0
21:13:08.877616 IP localhost.localdomain.42380 > 192.168.0.7.ssh: Flags [S], seq 2378743619, win 29200, options [mss 1460,sackOK,TS val 197564672 ecr 0,nop,wscale 7], length 0