TCP状态转移图说明及使用tcpdump进行观测

一、TCP状态转移图说明

图1.TCP状态转移图

 

  这张图展示了 TCP(Transmission Control Protocol,传输控制协议)的状态转移图,描述了 TCP 连接在不同阶段之间的状态变化和相互转换。

(一)、建立连接(三次握手)

 

图2.TCP三次握手示意图

  1、服务器准备好接受外来连接,通常通过socket、bind和listen完成。(服务器:CLOSED->LISTEN)

  2、客户端通过connect连接服务器,客户端TCP将发送一个SYN包,告诉服务器客户端将在待建立连接发送数据的初始序列号。(客户端:CLOSED->SYN_SENT)

  3、服务器端必须ACK客户端SYN,同时发送一个SYN,告诉客户端,服务器将在待建立连接发送数据的初始序列号。(服务器:SYN_RCVD)

  4、客户端ACK服务器SYN。(客户端:SYN_SENT->ESTABLISHED)

  5、服务器接收到客户端ACK。(服务器:SYN_RECV->ESTABLISHED)

(二)、建立连接(同时打开simultaneous open)

  参考《TCP/IP详解》卷一第18章18.8节。这种情况发生在两端几乎同时发送SYN并且这两个SYN在网络中交错的情形。这种情况可能发生,但是非常罕见。

  例如,主机A的应用程序使用本地端口7777,并主动连接主机B的端口8888。主机B的应用程序使用本地端口8888,并主动连接主机A的端口7777。

  下图给出同时打开过程:

图3.TCP建立连接同时打开示意图

 

(三)、断开连接(四次挥手)

图4.TCP四次挥手打开示意图

  1、客户端首先调用close,该端发送一个FIN包,表示数据发送完毕,该应用程序再无更多数据发送给对端。(客户端:ESTABLISHED->FIN_WAIT_1)

  2、接收到FIN的对端执行被动关闭,FIN包意味着接收端应用进程在相应的连接上再无额外数据可接收。在收到FIN报文的时候,TCP协议栈会为FIN包插入一个文件结束符EOF到接收缓冲区中,服务端应用程序可以通过read调用来感知这个FIN包,这个EOF会被放在已排队等候的其它已接收的数据之后,所以服务端会先read完接收缓冲区已接收的数据,然后read到EOF,read()就会返回0。然后服务端会ACK这个收到的FIN包。(服务端:ESTABLISHED->CLOSE_WAIT,客户端:FIN_WAIT_1->FIN_WAIT_2)

  3、服务端可能会立即关闭socket,也可能继续发送一些数据给客户端后再执行关闭scoket(由上层应用程序决定),所以,客户端的 ACK和 FIN一般都会分开发送,这里就会导致次数增加1。

  4、服务端关闭socket时,将发送一个FIN包给客户端。(服务端:CLOSE_WAIT->LAST_ACK)

  5、接收FIN的客户端ACK这个FIN。(被动端:LAST_ACK->CLOSED,主动端:FIN_WAIT_2->TIME_WAIT(2MSL之后,TIME_WAIT->CLOSED))

(四)、断开连接(同时关闭simultaneous close)

  参考《TCP/IP详解》卷一第18章18.9节。我们在前面讨论了一方(通常但不总是客户方)发送第一个FIN执行主动关闭。双方都执行主动关闭也是可能的,TCP协议也允许这样的同时关闭(simultaneous close)。

  下图给出同时关闭过程:

图5.TCP连接同时关闭示意图

  

二、使用tcpdump观测

(一)、观测TCP连接的建立

  TCP三次握手的过程通常涉及以下三个步骤:

  1、SYN包发送:客户端向服务器发送一个SYN(同步序列编号)包,请求建立连接。SYN包中的序列号是一个随机值,用于标识该TCP连接的初始序列号。

  2、SYN-ACK包响应:服务器收到SYN包后,会发送一个SYN-ACK(同步序列编号确认)包作为响应。这个包同时包含了服务器的SYN序列号(也是一个随机值)和对客户端SYN包的确认(即客户端SYN包的序列号加1)。

  3、ACK包确认:客户端收到SYN-ACK包后,会发送一个ACK(确认)包给服务器。这个包中的确认号设置为服务器SYN序列号加1,表示客户端已经成功接收到了服务器的SYN包。

  以下是一个tcpdump输出示例,展示了TCP三次握手的过程:

tcpdump -i any tcp port 8888 -S

  在tcpdump命令中,-S选项用于指定在打印TCP数据包时,不将序列号(sequence numbers)转换为相对序列号。默认情况下,当tcpdump显示TCP数据包时,它会尝试将序列号转换为相对于第一个捕获到的数据包的序列号(即相对序列号),以便更容易地观察数据包之间的顺序和数据流。然而,在某些情况下,用户可能希望看到数据包的原始序列号,而不是相对序列号,这时就可以使用-S选项。

(二)、观测TCP连接的关闭

  在TCP连接的关闭过程中,你会看到以下类型的TCP数据包:

  1、FIN包:表示一方(通常是客户端)想要关闭连接。FIN包的TCP标志位中FIN标志被设置。

  2、ACK包:对FIN包的确认。接收方发送ACK包,其确认号设置为FIN包的序列号加1。

  3、反向FIN包:如果双方都关闭了它们的数据发送通道,则接收FIN包的一方也会发送一个FIN包。

  4、最终ACK包:对反向FIN包的确认,标志着TCP连接的完全关闭。

  以下是一个tcpdump输出示例,展示了TCP四次挥手的过程:

  1. 第一行是客户端发送的FIN包,这是第一次挥手。
  2. 第二行是服务器对FIN包的确认,并发送自己的FIN包,这是第二次和第三次挥手,常常会将这两次挥手合并,只发送一个 Flags [ F .]包,即 ACK 和 FIN。
  3. 第三行是客户端对服务器FIN包的确认。

(三)、观测server端不启动服务,client端尝试连接

  Server(127.0.0.1:8888)未启动服务,如图抓包所示,Client(127.0.0.1:49544)发送SYN(localhost.49544 > localhost.8888: Flags [S])启动TCP连接,Server返回localhost.8888 > localhost.49544: Flags [R.],R=RESET表示异常关闭连接,连接重置。

(四)、模拟出现SYN_SENT状态

  1、设置防火墙iptables丢弃发送给Server(127.0.0.1:8888)的数据包,这样Server不会收到Client发送的SYN。

iptables -I INPUT -s 127.0.0.1 -p tcp --dport 8888 -j DROP

  参数说明:

  • iptables:这是用于设置、维护和检查 IPv4 数据包过滤规则的工具。

  • -I INPUT-I 选项用于向指定的链(在这个例子中是 INPUT 链)中插入一条规则。INPUT 链用于处理进入本机的数据包。默认情况下,iptables 的规则是按照添加的顺序来处理的,但使用 -I 选项时,你可以指定将规则插入到链的开头(如果不指定位置的话)。

  • -s 127.0.0.1-s 选项用于指定源 IP 地址。在这个例子中,它指定了源 IP 地址为 127.0.0.1,即本机地址(回环地址)。这意味着这条规则只适用于从本机发出的数据包。

  • -p tcp-p 选项用于指定协议类型。这里指定为 tcp,表示这条规则只适用于 TCP 协议的数据包。

  • --dport 8888:这个选项用于指定目标端口(destination port)。这里指定为 8888,意味着这条规则只适用于目标端口为 8888 的数据包。

  • -j DROP-j 选项用于指定匹配规则后采取的动作(jump to target)。DROP 是一个目标动作,意味着如果数据包与这条规则匹配,那么该数据包将被丢弃,且不会给出任何响应

  2、使用tcpdump抓取的输出如下:

  我们一共抓取了7个TCP报文段,它们都是同步报文段,并且具有相同的序列号,这说明后面6个同步报文段都是超时重连报文段,观察这些TCP报文段的时间间隔,它们分别是1s、2s、4s、8s、16s、32s。因此,TCP模块一共执行了6次重连操作,这是由/proc/sys/net/ipv4/tcp_syn_retries 内核参数定义的。每次重连的超时时间都增加一倍。在6次重连均失败的情况下,TCP模块放弃重连并通知应用程序。

(base) [root@HBD1MM opensource]# cat /proc/sys/net/ipv4/tcp_syn_retries 
6

  3、netstatat命令也能看到,此时客户端的连接处于SYN_SENT状态。

(五)、模拟出现SYN_RCVD状态

  1、设置防火墙丢弃Server(127.0.0.1:8888)发送出去的数据包,这样Client不会收到Server发送的SYN&ACK包。

iptables -I INPUT -s 127.0.0.1 -p tcp --sport 8888 -j DROP

  2、使用tcpdump抓取的输出如下:

  Client(localhost:49728)发送SYN给Server(localhost:8888),Server发送SYN ACK给Client,但是被防火墙丢弃Server发送Client端的SYN&ACK,Client也就不会发送SYN ACK给Server。

  3、Client TCP连接状态转移为SYN_SENT,但是不会转移到ESTABLISHED,Server TCP连接状态由LISTEN转移到SYN_RCVD,但是不会转移到ESTABLISHED。使用netstat命令可观察到:

(六)、模拟出现FIN_WAIT1状态

  1、Client在断开连接之前,设置防火墙丢弃Client发送给Server(127.0.0.1:2017)的数据包,这样Server不会收到Client发送的FIN而返回FIN ACK。

  2、使用tcpdump抓取的输出如下:

  3、Client收不到Server发送的FIN ACK, TCP状态不能由FIN_WAIT1转移到FIN_WAIT2;Server TCP状态为ESTABLISHED,Server接收不到Client的FIN而没有发送FIN ACK, TCP状态不能由ESTABLISHED转移到CLOSE_WAIT。Client TCP连接状态保持在FIN_WAIT1,达到最大重试次数后,超时转移到CLOSED。使用netstatat命令可观察到:

 

posted @ 2024-07-31 14:00  阿玛尼迪迪  阅读(63)  评论(0编辑  收藏  举报