TCP网络协议是较常用的,也基本上都会接触,那么来简单了解下它吧。TCP 是一种面向连接的、可靠的传输协议,它能够将数据分成一些小块,并通过 Internet 进行传输。在 TCP 中,数据被分割成一些称为 TCP 报文段(TCP segment)的小块,每个 TCP 报文段携带了一部分数据,以及一些用于传输控制的信息。本文将通过抓包分析,介绍 TCP 报文段的结构和各个字段的含义与解析。
TCP传输层封包描述:
抓包工具
本文使用 Wireshark 作为抓包工具。Wireshark 是一个流行的开源网络协议分析工具,能够捕获和分析网络数据包。Wireshark 支持多种协议,包括 TCP、UDP、HTTP 等。在本文中,我们将使用 Wireshark 抓取并分析 TCP 报文段。
抓包分析
下面我们将通过抓包分析 TCP 报文段的结构和各个字段的含义。
打开 Wireshark,选择一个合适的接口,开始抓包。在本例中,我们使用的是一个在局域网中运行的 TCP客户端与服务端链接示例。
选中任意一个 TCP 报文段,Wireshark 会显示出该数据包的详细信息,包括 TCP 报文段的结构和各个字段的值。下面是一个 TCP 报文段的示例(SYNC包,没有带data):
我们逐一分析每个字段的含义和解析。
-
源端口号和目标端口号
源端口号(Source Port)和目标端口号(Destination Port)用于标识通信的源和目的地应用程序。在本例中,源端口号为 12345,目标端口号为 50302,这表示这是一个从本地主机的端口号为 12345 的应用程序向远程服务器的端口号为 50302 的 TCP 服务器发送的数据。
2. 序列号和确认号
序列号(Sequence Number):表示本次传输数据的起始字节在整个数据流中的位置,用于数据的重组和接收方确认使用。这里的0是相对序号,wireshark自行减去的首次相对的。原始序号(Sequence Number (Raw)):2407429255;
[Next Sequence Numvber:1 指的该方向下一包的序号,这个不在数据流中,是wireshark自己解析的
确认序号(Acknowledgment Number): 值为期望收到下一包的序号,用于确认已经收到数据的偏移序号; 示例中:为0
3. 4位首部长度(数据偏移):占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的,注意,“数据偏移”的单位是字节。由于4位二进制数能表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大字节(即选项长度不能超过40字节=60-20)。 示例中:这里的首部长度为8 * 4 = 44字节
4. 保留位:
5. 标志位(按位占用):
(1)紧急URG:当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。当URG置为1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。
(2)确认ACK: 仅当ACK = 1时确认号字段才有效,当ACK = 0时确认号无效。TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1。
(3)推送PSH:当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。一般这个不需要手动执标志,TCP默认实现;
(4)复位RST:当RST=1时,表名TCP连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。
(5)同步SYN:在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1,因此SYN置为1就表示这是一个连接请求或连接接受报文。
(6)终止FIN:发送端完成任务,表要求释放运输连接。
示例中,是将SYN标志给执了起来;
6. 窗口:接收方的流量控制手段,窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。告诉发送端,接收端目前允许发送端数据量。大小两字节65535,在客户端与服务端TCP都允许的情况下,选项中可存在窗口扩展选项。 示例中:窗口大小65535,代表告诉发送方,从这个下一包0的序号开始,接收方只能接受65535个字节长度了(当然这里还没有算上扩展选项,稍后再讲)
7. 校验和:2字节,检验和覆盖了整个的TCP报文段: TCP首部和TCP数据。这是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式和UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6);把第5字段中的UDP中的长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用TPv6,则相应的伪首部也要改变。 示例中:0xfe34
8. 紧急指针:2字节,在紧急URG标志执1的时候有效,代表一个偏移量,和序号字段值相加,代表紧急数据最后一个字节的序号。示例中: 为0
9. 选项:长度可变,最长可达40字节。当没有使用“选项”时,TCP的首部长度是20字节。其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*4-20=40字节。以下讲下最常见的一些选项:
本次选项中看到有24字节
9.1 MSS(最大报文段长度-Maxium Segment Size):MSS是每一个TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是整个TCP报文段的最大长度,而是“TCP报文段长度减去TCP首部长度”。
为什么要有MSS:为了增加网络利用率
一般说来,如果没有分段发生, MSS大部分时候还是越大越好。报文段越大允许每个报文段传送的数据就越多,相对IP和TCP首部有更高的网络利用率。则MSS的默认值是536字节长(这个默认值允许20字节的IP首部和20字节的TCP首部以适合576字节IP数据报)
本示例中:MSS为16344
9.2 其他选项:
-
窗口扩大选项(Windows Scaling):是为了扩大窗口。我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。
(1)窗口扩大选项占3字节,其中第一字节代表类型,第二字节代表长度,第三字节(shift count)则是扩展移位值S了,新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2^(16+14)-1=2^30-1。
(2)窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0选项,使窗口大小回到16。
本示例中:窗口扩大选项则是移位6,等于扩展了64倍(65565 * 2^6)
- 时间戳选项(Timestamps):占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。时间戳选项有以下两个概念:
(1)用来计算往返时间RTT(往返时间)。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出RTT来。为了减少任一端所维持的状态数量,对于每个连接只保持一个时间戳的数值。选择何时,更新这个数值的算法非常简单(《TCP/IP详解》):
1 ) T C P 跟踪下一个 A C K 中将要发送的时间戳的值(一个名为 t s re c e n t 的 变 量 ) 以 及 最 后 发 送的 A C K 中的确认序号(一个名为 l a s t a c k的变量)。这个序号就是接收方期望的序号。
2) 当一个包含有字节号 l a s t a c k的报文段到达时,则该报文段中的时间戳被保存在 t s re c e n t 中。
3) 无论何时发送一个时间戳选项, t s re c e n t就 作 为 时 间 戳 回 显 应 答 字 段 被 发 送 , 而 序 号 字 段被保存在 l a s t a c k 中。 (2)用于处理防止序号绕回PAWS(TCP序号超过2^32的情况):TCP报文段的序号只有32位,而每增加2^32个序号就会重复使用原来用过的序号。当使用高速网络时,在一次TCP连接的数据传送中序号很可能被重复使用。为了使接收方能够把新的报文段和迟到很久的报文段区分开,则可以在报文段中加上这种时间戳。
本示例中: 发送的3588061560,因为是第一个SYN所以回复的是0
-
NOP(NO-Operation):它要求选项部分中的每种选项长度必须是4字节的倍数,不足的则用NOP填充。同时也可以用来分割不同的选项字段。如窗口扩大选项和SACK之间用NOP隔开
至此,一个SYN包就解析完了,对于PSH、ACK解析类似哦