Wireshark & Packetdrill | TCP 三次握手之 SYN 超时重传

admin 2024年2月13日22:51:11评论13 views字数 5676阅读18分55秒阅读模式

新年伊始,常安常乐。

实验目的

基于 packetdrill TCP 三次握手脚本,通过构造模拟客户端场景,测试客户端 SYN 超时重传现象。

基础脚本

# cat tcp_3hs_007.pkt // TCP 基础之三次握手0  socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0+0 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0

+0 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)

+0 > S 0:0(0) <...>+0.01 < S. 0:0(0) ack 1 win 10000 <mss 1000>+0 > . 1:1(0) ack 1

基础测试

测试脚本很简单,注释掉或者删除 SYN/ACK 和 ACK ,并使得程序不要退出即可,这样在客户端发起 connect(),协议栈发出 SYN 后,没有得到响应,即会进入超时重传现象。

# cat tcp_rto_001.pkt 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0+0 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0

+0 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)

+0 > S 0:0(0) <...>

+0 `sleep 10000000`# 

执行脚本,保持不退出状态# packetdrill tcp_rto_001.pkt 



同时 tcpdump 捕获数据包,等待一段时间后,即可捕获到所有的 SYN 超时重传数据包。# tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes19:30:54.320911 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176847787 ecr 0,nop,wscale 7], length 019:30:55.352720 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176848819 ecr 0,nop,wscale 7], length 019:30:57.368698 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176850835 ecr 0,nop,wscale 7], length 019:31:01.624696 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176855091 ecr 0,nop,wscale 7], length 019:31:09.816700 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176863283 ecr 0,nop,wscale 7], length 019:31:25.944705 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176879411 ecr 0,nop,wscale 7], length 019:31:58.200703 tun0  Out IP 192.168.76.212.50560 > 192.0.2.1.8080: Flags [S], seq 1216637537, win 64240, options [mss 1460,sackOK,TS val 176911667 ecr 0,nop,wscale 7], length 0



期间 ss 输出的 TCP 状态# ss -ntoState          Recv-Q       Send-Q             Local Address:Port                 Peer Address:Port        Process                     SYN-SENT       0            1                  192.168.76.212:50560               192.0.2.1:8080           timer:(on,1.980ms,2)

通过 tcpdump 捕获的数据包跟踪文件,再通过 Wireshark 打开如下,共计重传 6 次,间隔时间以 1s、2s、4s、8s、16s、32s 翻倍递增,最后一次超时重传后还会持续 64s,所以 SYN-SENT 状态也就维持了大约 127s 左右。

Wireshark & Packetdrill | TCP 三次握手之 SYN 超时重传

不通过 packetdrill 脚本测试的话,随便以 nc 或 telnet 测试一个不存在的端口服务,也可以看到一样的结果。
# date; nc 1.1.1.1 1111; dateThu Jan 11 08:32:36 PM CST 2024Thu Jan 11 08:34:46 PM CST 2024#

对于不同的操作系统以及版本,初始超时重传的时间一般有 1s 和 3s 两种,且通常不能更改,本次测试系统的初始超时重传时间是 1s。

客户端的 SYN 报文最大重传次数由 tcp_syn_retries 内核参数控制,这个参数是可以自定义的,本次测试系统的 SYN 报文最大重传次数为 6 次,相关参数如下:

# uname -r5.15.0-76-generic



其中HZ的值为1000,即初始值为1秒。#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))  /* RFC6298 2.1 initial RTO value  */



# cat /proc/sys/net/ipv4/tcp_syn_retries6 # sysctl -a | grep syn_retnet.ipv4.tcp_syn_retries = 6#

扩展测试一

Linux ss -i 参数能展现出很多 TCP 信息,因此继续扩展测试一下。考虑到 TCP SYN 重传次数太多,总的超时时间太长,因此先把 SYN 重传次数改为 3。

# sysctl -q net.ipv4.tcp_syn_retries=3#

仍然是通过 packetdrill 执行 tcp_rto_001.pkt 脚本,保持不退出状态,同时间通过 tcpdump 以及 ss 命令捕获的数据包和 TCP 信息如下。

一共4个SYN数据包,包括原始1个+超时重传3个。# tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes17:45:06.971565 tun0  Out IP 192.168.230.225.33896 > 192.0.2.1.8080: Flags [S], seq 2346089904, win 64240, options [mss 1460,sackOK,TS val 1071063904 ecr 0,nop,wscale 7], length 017:45:07.992707 tun0  Out IP 192.168.230.225.33896 > 192.0.2.1.8080: Flags [S], seq 2346089904, win 64240, options [mss 1460,sackOK,TS val 1071064925 ecr 0,nop,wscale 7], length 017:45:10.008697 tun0  Out IP 192.168.230.225.33896 > 192.0.2.1.8080: Flags [S], seq 2346089904, win 64240, options [mss 1460,sackOK,TS val 1071066941 ecr 0,nop,wscale 7], length 017:45:14.104694 tun0  Out IP 192.168.230.225.33896 > 192.0.2.1.8080: Flags [S], seq 2346089904, win 64240, options [mss 1460,sackOK,TS val 1071071037 ecr 0,nop,wscale 7], length 0



原始SYN(默认rto 1s),第一次超时重传(rto 2s),第二次超时重传(rto 4s),第三次超时重传(rto 8s),8秒之后退出SYN-SENT状态。# for i in `seq 1 100`; do ss -i dport 8080 | grep rto | awk '{print $2}'; sleep 1; donerto:1000rto:2000rto:2000rto:4000rto:4000rto:4000rto:4000rto:8000rto:8000rto:8000rto:8000rto:8000rto:8000rto:8000rto:8000

简单学习了下 ebpf bcc,有几个工具也可以观测到相关现象。

SYN 重传三次,状态 SYN_SENT# ./tcpretrans.pyTracing retransmits ... Hit Ctrl-C to endTIME     PID     IP LADDR:LPORT          T> RADDR:RPORT          STATE20:46:01 0       4  192.168.241.152:37628 R> 192.0.2.1:8080       SYN_SENT20:46:03 0       4  192.168.241.152:37628 R> 192.0.2.1:8080       SYN_SENT20:46:07 0       4  192.168.241.152:37628 R> 192.0.2.1:8080       SYN_SENT## ./tcpretrans.py -cTracing retransmits ... Hit Ctrl-C to end^CLADDR:LPORT               RADDR:RPORT               RETRANSMITS[192.168.171.239]#59302 <-> [192.0.2.1]#8080              3#



SYN_SENT到CLOSE状态变化,用时15477.044ms,也就是约15秒,1+2+4+8=15.# ./tcpstates.pySKADDR           C-PID C-COMM     LADDR           LPORT RADDR           RPORT OLDSTATE    -> NEWSTATE    MSffff8c7e6d6a2bc0 30738 packetdril 0.0.0.0         41135 0.0.0.0         0     CLOSE       -> LISTEN      0.000ffff8c7e6d6a3d40 30738 packetdril 192.168.231.85  0     192.0.2.1       8080  CLOSE       -> SYN_SENT    0.000ffff8c7e6d6a3d40 0     swapper/0  192.168.231.85  39682 192.0.2.1       8080  SYN_SENT    -> CLOSE       15477.044ffff8c7e6d6a2bc0 30738 packetdril 0.0.0.0         41135 0.0.0.0         0     LISTEN      -> CLOSE       26425.808

扩展测试二

上面提到说不同的操作系统的区别,正好手上有测试环境,顺便验证了一个 Windows 和 Mac 系统下的 SYN 超时重传现象。

Windows

Windows 10 企业版,使用 telnet 测试,初始超时重传的时间 3s ,重传两次,同样超时时间会翻倍。

λ telnet 1.1.1.1 1111正在连接1.1.1.1...无法打开到主机的连接。在端口 1111: 连接失败λ

Wireshark & Packetdrill | TCP 三次握手之 SYN 超时重传

通过 netsh 可查看 tcp 全局参数,可看到初始 RTO:3000,最大 SYN 重新传输次数 2。

λ netsh int tcp show global查询活动状态...

TCP 全局参数----------------------------------------------接收端缩放状态          : enabled接收窗口自动调节级别    : normal附加拥塞控制提供程序  : defaultECN 功能                      : disabledRFC 1323 时间戳                 : disabled初始 RTO                         : 3000接收段合并状态    : enabled非 Sack Rtt 复原             : disabled最大 SYN 重新传输次数             : 2快速打开                           : enabled快速打开回退                  : enabledHyStart                             : enabled节奏配置文件                      : off

Mac

macOS Ventura,版本 13.6.3,使用 nc 命令测试,初始超时重传的时间为 1s ,重传十次,间隔时间不太一样,前五次保持 1s 超时时间,后五次开始翻倍,2s、4s、8s、16s、32s。

$ nc 1.1.1.1 1111$

Wireshark & Packetdrill | TCP 三次握手之 SYN 超时重传

貌似和 Linux 一样,初始超时重传的时间一般不能更改,而超时重传的次数由以下参数控制。

$ sysctl -a | grep rexmitnet.inet.tcp.broken_peer_syn_rexmit_thres: 10

原文始发于微信公众号(Echo Reply):Wireshark & Packetdrill | TCP 三次握手之 SYN 超时重传

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月13日22:51:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Wireshark & Packetdrill | TCP 三次握手之 SYN 超时重传https://cn-sec.com/archives/2490588.html

发表评论

匿名网友 填写信息