TCP协议详解一
TCP协议的报文格式
传输层TCP协议提供了一种面向连接的、可靠的字节流服务,其数据帧格式,大致如下图所示:
图:传输层TCP协议的数据帧格式
一个传输层TCP协议的数据帧,大致包含以下字段:
(一)源端口号
源端口号表示报文的发送端口,占16位。源端口和源IP地址组合起来,可以标识报文的发送地址。
(二)目的端口号
目的端口号表示报文的接收端口,占16位。目的端口和目的IP地址相结合,可以标识报文的接收地址。
TCP协议是基于IP协议的基础上传输的,TCP报文中的源端口号+源IP,与TCP报文中的目的端口号+目的IP一起,组合起来唯一性的确定一条TCP连接。
(三)序号(Sequence Number)
TCP传输过程中,每个报文都有它的编号。序号(Sequence Number)占32位,发起方发送数据时,都需要标记序号。
序号(Sequence Number)的语义与SYN控制标志(Control Bits)的值有关。根据控制标志(Control Bits)中的SYN是否为1,序号(Sequence Number)表达不同的含义
a. 当 SYN=1 时, 当前为连接建立阶段, 此时的序号为初始序号ISN((Initial Sequence Number)通过算法来随机生成序号;
b. 当 SYN=0 时, 在数据传输正式开始时, 第一个报文的序号为 ISN+1(即Seq=1), 后面的报文的序号为前一个报文的SN值+TCP报文的实际数据长度
例如, 如果前一个报文的 Seq=5, Len=12 那么当前报文的 Seq=17
在数据传输过程中,TCP协议通过序号(Sequence Number)对上层提供有序的数据流, 发送端可以用序号来跟踪发送的数据量, 接收端可以用序号识别出重复接收到的TCP包从而丢弃重复包,对于乱序的数据包接收端也可以依靠序号对其进行排序。
(四)确认序号(Acknowledgment Number)
确认序号(Acknowledgment Number)标识了报文接收端期望接收的字节序列。如果设置了ACK控制位,确认序号的值表示一个准备接收的包的序列码,注意,它所指向的是准备接收的包,也就是下一个期望接收的包的序列码。
例如, 发送端(如Client)发送 Seq=10, Len=30 数据包给接收端(如server), Server收到数据包之后会回复一个ACK确认数据包给Client。
ACK确认数据包的值为当前接收到数据包的 Seq+Len, 表示Server已经确认收到的字节数,还表示期望接收到的下一个Client发送包的SN序号。(因为存在滑动窗口,Client的Seq不一定是Server端的ACK值)
TCP协议规定,连接建立后,所有发送的报文的ACK必须为1,也就是建立连接后,所有报文的确认序号有效。如果是SYN类型的报文,其ACK标志为0,故没有确认序号。
对于三次握手中第二次握手,接收数据包的 Seq+Len =0,但是TCP协议要求确认序号必须有效,因此ACK=1。
对于三次握手中第三次握手,也是同样的原因。
(五)头部长度
该字段占用4位,用来表示TCP报文首部的长度,单位是4bit位。其值所表示的并不是字节数,而是头部的所含有的32bit的数目(或者倍数),或者4个字节的倍数,所以TCP头部最多可以有60字节(4*15=60)。没有任何选项字段的TCP头部长度为20字节,所以其头部长度为5,可以通过20/4=5计算得到。
(六)预留6位
头部长度后面预留的字段长度为6位,作为保留字段,暂时没有什么用处。
(七)控制标志
控制标志(Control Bits)共6个bit位,具体的标志位为:URG、ACK、PSH、RST、SYN、FIN。6个标志位的说明,如下所示。
URG 占1位,表示紧急指针字段有效。URG位指示报文段里的上层实体(数据)标记为“紧急”数据。当URG=1时,其后的紧急指针指示紧急数据在当前数据段中的位置(相对于当前序列号的字节偏移量),TCP接收方必须通知上层实体。
ACK 占1位,置位ACK=1表示确认号字段有效;TCP协议规定,接建立后所有发送的报文的ACK必须为1;当ACK=0时,表示该数据段不包含确认信息。当ACK=1时,表示该报文段包括一个对已被成功接收报文段的确认序号Acknowledgment Number,该序号同时也是下一个报文的预期序号。
PSH 占1位,表示当前报文需要请求推(push)操作;当PSH=1时,接收方在收到数据后立即将数据交给上层,而不是直到整个缓冲区满。
RST 占1位,置位RST=1表示复位TCP连接;用于重置一个已经混乱的连接,也可用于拒绝一个无效的数据段或者拒绝一个连接请求。如果数据段被设置了RST位,说明报文发送方有问题发生。
SYN 占1位,在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1。 综合一下,SYN置1就表示这是一个连接请求或连接接受报文。
FIN 占1位,用于在释放TCP连接时,标识发送方比特流结束,用来释放一个连接。当 FIN = 1时,表明此报文的发送方的数据已经发送完毕,并要求释放连接。
在连接建立的三次握手过程中,若只是单个SYN置位,表示的只是建立连接请求。如果SYN和ACK同时置位为1,表示的建立连接之后的响应。
(八)窗口大小:
长度为16位,共2个字节。此字段用来进行流量控制。流量控制的单位为字节数,这个值是本端期望一次接收的字节数。
(九)校验和:
长度为16位,共2个字节。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,接收端用于对收到的数据包进行验证。
(十)紧急指针:
长度为16位,2个字节。它是一个偏移量,和SN序号值相加表示紧急数据最后一个字节的序号。
以上十项内容是TCP报文首部必须的字段,也称固有字段,长度为20个字节。接下来是TCP报文的可选项和填充部分。
(十一)可选项和填充部分
可选项和填充部分的长度为4n字节(n是整数),该部分是根据需要而增加的选项。如果不足4n字节,要加填充位,使得选项长度为32位(4字节)的整数倍,具体的做法是在这个字段中加入额外的零,以确保TCP头是32位(4字节)的整数倍。
最常见的选项字段是MSS(Maximum Segment Size最长报文大小),每个连接方通常都在通信的第一个报文段(SYN标志为1的那个段)中指明这个选项字段,表示当前连接方所能接受的最大报文段的长度。由于可选项和填充部分不是必须的,所以TCP报文首部最小长度为20个字节。
至此,TCP报文首部的字段,就全部介绍完了。TCP报文首部的后面,接着的是数据部分,不过数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有TCP首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据,比如在处理超时的过程中,也会发送不带任何数据的报文段。
总体来说,TCP协议的可靠性,主要通过以下几点来保障:
(1)应用数据分割成TCP认为最适合发送的数据块。这部分是通过MSS(最大数据包长度)选项来控制的,通常这种机制也被称为一种协商机制,MSS规定了TCP传往另一端的最大数据块的长度。值得注意的是,MSS只能出现在SYN报文段中,若一方不接收来自另一方的MSS值,则MSS就定为536字节。一般来讲,MSS值还是越大越好,这样可以提高网络的利用率。
(2)重传机制。设置定时器,等待确认包,如果定时器超时还没有收到确认包,则报文重传。
(3)对首部和数据进行校验。
(4)接收端对收到的数据进行排序,然后交给应用层。
(5)接收端丢弃重复的数据。
(6)TCP还提供流量控制,主要是通过滑动窗口来实现流量控制。
RST标志位
RST表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。就像上面说的一样,发送RST包关闭连接时,不必等缓冲区的包都发出去(不像上面的FIN包),直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。
TCP处理程序会在自己认为的异常时刻发送RST包。例如,A向B发起连接,但B之上并未监听相应的端口,这时B操作系统上的TCP处理程序会发RST包。
又比如,AB正常建立连接了,正在通讯时,A向B发送了FIN包要求关连接,B发送ACK后,网断了,A通过若干原因放弃了这个连接(例如进程重启)。网通了后,B又开始发数据包,A收到后表示压力很大,不知道这野连接哪来的,就发了个RST包强制把连接关了,B收到后会出现connect reset by peer错误。
RST攻击
A和服务器B之间建立了TCP连接,此时C伪造了一个TCP包发给B,使B异常的断开了与A之间的TCP连接,就是RST攻击了。实际上从上面RST标志位的功能已经可以看出这种攻击如何达到效果了。
那么伪造什么样的TCP包可以达成目的呢?我们至顶向下的看。
假定C伪装成A发过去的包,这个包如果是RST包的话,毫无疑问,B将会丢弃与A的缓冲区上所有数据,强制关掉连接。
如果发过去的包是SYN包,那么,B会表示A已经发疯了(与OS的实现有关),正常连接时又来建新连接,B主动向A发个RST包,并在自己这端强制关掉连接。
这两种方式都能够达到复位攻击的效果。