咱们在介绍TCP头的时候,提到过其中有个RST标志位。当一个TCP报文中这个标志位打开的时候,咱们叫作reset包(严格的说应该叫作reset段,可是不少时候段包帧并不加以区分)或者简单称呼为reset、RST。一般reset的产生是因为一个异常包致使,reset通常会致使TCP链接的快速断开。产生reset的几种常见的情形以下linux
向一个未打开的端口发送链接请求缓存
应用程序主动终止一个链接sass
应用程序尚未接收缓存中的数据,链接被提早关闭socket
TWA(TIME-WAIT Assassination)
tcp
半开链接的状况下发送数据spa
注意咱们这里是描述的reset产生的一些场景(并且是部分场景),在具体reset的产生缘由上可能会有重复,好比第一、四、5均可以认为是对端没有打开相对应的TCP端口。3d
1、向一个未打开的端口发送链接请求orm
reset产生的一个常见的缘由是,在一个未打开的端口发送链接请求。这里未打开的端口是指没有应用程序在监听这个端口等待链接。server
以下图wireshark抓包,再不开启server状况下,没有应用程序监听9877端口,当client链接9877端口的时候就会产生reset消息。注意我截图中的系列号,在这个截图中我设置了wireshark显示绝对系列号(前面文章截图显示的都是相对系列号),由于SYN包中的ACK标志没有置位,ack number字段无效(实际是以0填充的),因此在reset中的seq=0,ack则为SYN包中的seq+1(由于SYN标志和FIN标志在逻辑上占1byte)。一个reset包若是要被TCP endpoint接收,ACK标志必须置位且ack number落在有效的窗口区间内(窗口相关知识后面细讲)。这帮助阻止了一个简单的reset攻击(RFC5961),不然攻击者能够经过伪造源IP地址、源端口号构造一个reset消息来中断TCP链接。blog
2、应用程序主动经过reset消息终止一个链接
应用程序能够经过socket API接口设置主动reset一个TCP链接,这种状况下的链接中断过程称为abortive release。以前咱们介绍过的四次挥手之类的经过FIN终止链接的过程咱们称呼为orderly release。在abortive release状况下,reset包的发送端缓存的待发送数据都会直接丢弃,接收端接收到reset后也能够知道是对端主动abort了这个tcp链接。
wireshark截图以下,注意client发送reset后,并不会引发server回应ACK之类的消息。
能够看到RST消息的seq正好是对端指望接收的seq,按照RFC5961要求,非SYN_SENT状态下,接收端须要判断RST消息的系列号seq为正好为本身指望接收的seq,才会认为这个RST消息有效。若是RST的系列号seq落在接收窗口内但不是指望的seq时候,接收端须要发送challenge ACK,若是落在接收窗口外则会直接丢弃这个RST消息。(实际上challenge ACK也会引发RST,详见RFC5961,此处不作介绍。)
3、应用层尚未读取完接收缓存中的数据,链接被提早关闭
当TCP接收端缓存中还有缓存数据而没有被应用层接收,可是应用层直接关闭TCP链接时候就会产生reset,以下图wireshark抓包所示,链接创建后client向server发送10bytes的数据,server应用层并无读取这10bytes的数据而是直接关闭tcp链接就会产生reset。
4、TWA(TIME-WAIT Assassination)
TCP在TIME-WAIT状态下的时候,若是接收到reset包,它可能会提早结束TIME-WAIT状态,这种行为即叫作TIME-WAIT Assassination(TWA),数据包的流程以下图所示
为了不TIME-WAIT状态提早被reset结束,一些系统的TCP实如今TIME-WAIT状态下不会响应rst消息。linux则能够经过net.ipv4.tcp_rfc1337设置TCP在TIME-WAIT下是否响应reset,若是设置tcp_rfc1337为0,在TIME-WAIT下若是接收到reset则会直接关闭tcp链接,而不会等到2MSL超时。
5、半开链接的状况下发送数据
关于半开链接咱们前面已经进行了介绍,同时wireshark抓包中也有对应的reset的展现,此处再也不介绍。