TCP 三次握手
其中第2步,server 回复 SYN + ACK 是合并在一起发送的,piggybacking,背着走,搭顺风车。
server 不想接收这次握手,2种情况:
# 列出所有 chain=INPUT 的规则,并且显示行号(便于后续删除使用)
iptables -L INPUT --line-numbers
# 删除某一规则
iptables -D INPUT 1
root@node2:~# iptables -L INPUT --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP tcp -- anywhere anywhere tcp dpt:http
root@node2:~# iptables -D INPUT 1
root@node2:~# iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
# 实验环境
# client node1 192.168.0.21
# server node2 192.168.0.22
# server 安装并启动默认的 nginx
# 实验1 - 正常 TCP 三次握手
# server 查看80端口
root@node2:~# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 719 root 6u IPv4 23596 0t0 TCP *:http (LISTEN)
nginx 719 root 7u IPv6 23597 0t0 TCP *:http (LISTEN)
nginx 724 www-data 6u IPv4 23596 0t0 TCP *:http (LISTEN)
nginx 724 www-data 7u IPv6 23597 0t0 TCP *:http (LISTEN)
# client-1 1个窗口使用 tcpdump 抓包
sudo tcpdump -i any host 192.168.0.22 and port 80
# client-2 另一个窗口使用 telnet 连接 server
telnet 192.168.0.22 80
# 此时可以在 client-1 看到三次握手的包
00:49:51.387721 IP 192.168.0.21.54384 > 192.168.0.22.http: Flags [S], seq 2868519268, win 64240, options [mss 1460,sackOK,TS val 2126477609 ecr 0,nop,wscale 6], length 0
00:49:51.388426 IP 192.168.0.22.http > 192.168.0.21.54384: Flags [S.], seq 3802430513, ack 2868519269, win 65160, options [mss 1460,sackOK,TS val 4198512138 ecr 2126477609,nop,wscale 6], length 0
00:49:51.388586 IP 192.168.0.21.54384 > 192.168.0.22.http: Flags [.], ack 1, win 1004, options [nop,nop,TS val 2126477609 ecr 4198512138], length 0
# 实验2 - 静默丢包
# server 使用 iptables 把 80 端口收到的包扔掉
iptables -I INPUT -p tcp --dport 80 -j DROP
# client-1 1个窗口使用 tcpdump 抓包
sudo tcpdump -i any host 192.168.0.22 and port 80
# client-2 另一个窗口使用 telnet 连接 server
telnet 192.168.0.22 80
# client-2 会挂起
# client-1 会看到client 一直发送 SYN 包
00:59:29.556304 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127055777 ecr 0,nop,wscale 6], length 0
00:59:30.580021 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127056801 ecr 0,nop,wscale 6], length 0
00:59:32.595259 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127058816 ecr 0,nop,wscale 6], length 0
00:59:36.723466 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127062944 ecr 0,nop,wscale 6], length 0
00:59:44.915446 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127071136 ecr 0,nop,wscale 6], length 0
01:00:01.043084 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127087264 ecr 0,nop,wscale 6], length 0
01:00:33.300038 IP 192.168.0.21.54430 > 192.168.0.22.http: Flags [S], seq 1232420566, win 64240, options [mss 1460,sackOK,TS val 2127119521 ecr 0,nop,wscale 6], length 0
# 仔细观察,第一次是正常发送 SYN 包
# 指数退避
# 后面6次是重试,并且时间间隔分别是 1s 2s 4s 8s 16s 32s
# 经过6次重试后,又等待了 64s,client-2 telnet 才退出
root@node1:~# telnet 192.168.0.22 80
Trying 192.168.0.22...
telnet: Unable to connect to remote host: Connection timed out
# 实验3 - 直接拒绝
# server 拒绝80端口请求
iptables -I INPUT -p tcp --dport 80 -j REJECT
# client-1 1个窗口使用 tcpdump 抓包
sudo tcpdump -i any host 192.168.0.22 and port 80
# client-2 另一个窗口使用 telnet 连接 server
# 直接显示被拒绝
root@node1:~# telnet 192.168.0.22 80
Trying 192.168.0.22...
telnet: Unable to connect to remote host: Connection refused
# client-1 抓包情况
# 只有1个 SYN 包,没有看到回包
01:11:40.080738 IP 192.168.0.21.54492 > 192.168.0.22.http: Flags [S], seq 599140845, win 64240, options [mss 1460,sackOK,TS val 2127786302 ecr 0,nop,wscale 6], length 0
# 改变抓包条件,把端口去掉,重新抓包
sudo tcpdump -i any host 192.168.0.22
# 可以看到 ICMP 的回包
01:14:08.840140 IP 192.168.0.21.54506 > 192.168.0.22.http: Flags [S], seq 514234273, win 64240, options [mss 1460,sackOK,TS val 2127935061 ecr 0,nop,wscale 6], length 0
01:14:08.840707 IP 192.168.0.22 > 192.168.0.21: ICMP 192.168.0.22 tcp port http unreachable, length 68
# 在 server 上查看 iptables 规则
root@node2:~# iptables-save
# Generated by iptables-save v1.8.4 on Sat Mar 19 01:16:49 2022
*filter
:INPUT ACCEPT [526:44429]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [502:35372]
-A INPUT -p tcp -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -m tcp --dport 80 -j DROP
COMMIT
# Completed on Sat Mar 19 01:16:49 2022
# 可以看到 iptables 在 REJECT 后面跟上了默认的拒绝行为 --reject-with icmp-port-unreachable
# 可以指定
iptables -I INPUT -p tcp --dport 80 -j REJECT --reject-with tcp-reset
# 在 client-2 中 telnet,同样会被拒绝
root@node1:~# telnet 192.168.0.22 80
Trying 192.168.0.22...
telnet: Unable to connect to remote host: Connection refused
# 可以在 client-1 中看到抓包情况
01:19:19.054012 IP 192.168.0.21.54528 > 192.168.0.22.http: Flags [S], seq 1408630290, win 64240, options [mss 1460,sackOK,TS val 2128245275 ecr 0,nop,wscale 6], length 0
01:19:19.054588 IP 192.168.0.22.http > 192.168.0.21.54528: Flags [R.], seq 0, ack 1408630291, win 0, length 0