原文:https://blog.csdn.net/hyg0811/article/details/102366854
一.三次握手:
前提:SYN报文用于请求连接,ACK报文用于应答,FIN报文用于释放连接
1.三次握手的简述:
实际上是在建立TCP连接的时候,客户端和服务器端需要相互发送三个包,以此确定客户端和服务器端是否可以建立TCP连接。
2.三次握手的目的:
其目的主要是为了确认双方的接收能力和指定自己的初始化序列号。
3.三次握手的过程:
3.1.由客户端发送给服务器端SYN报文和指明自身的ISN初始化序列号(客户端处于SYN_SENT状态)
3.2.服务器端收到SYN报文后,会返回自己的SYN报文和ISN初始化序列号,同时返回值为客户端ISN+1的ACK,表示服务器接收到了客户端的SYN(服务器端处于SYN_RCVD状态)
3.3.客户端收到SYN报文后,会把值为服务器端SYN+1的ACK和一个ACK报文返回,这个时候客户端处于ESTABLISHED状态,当服务器端接收到ACK报文后,也处于ESTABLISHED状态,这个时候双方就建立了连接。
附:在socket中,客户端执行connect()时就会触发三次握手。
4.三次握手的必要性:
三次握手之所以必须是三次,是因为在客户端和服务器端彼此发送、接收的三次过程中,会不断地判断对方的发送能力、接收能力是否正常,而确认双方发送、接收能力都正常就最少需要三次交流过程。
5.半连接队列:
半连接队列指的是服务器端第一次接收到SYN报文的时候,因为双方还没有建立完整的连接,所以会把这种处于SYN_RCVD状态的 连接请求都放在一个队列中,这个队列被称为半连接队列。
6.全连接队列:
全连接队列指的是当客户端和服务端均已经建立了连接之后,会把这种处于ESTABLISHED状态的连接请求放在一个队列中,这个队列被称之为全连接队列。但是队列满了之后,就可能会出现丢包的现象,这个时候就会涉及到SYN-ACK重传次数。
7.SYN-ACK重传次数:
在服务器发送了SYN-ACK包之后,如果没有收到客户端的确认包,那么服务器就会进行首次重传,如果之后还是没有收到客户端的确认包,那么服务器就会进行第二次重传。重传次数是根据系统规定的最大重传数决定的,如果超过了最大重传数,那么这个连接就会被半连接队列给删除。
注:重传时间不一定是一样的,一般是指数增长的,如1s,2s,4s,8s...
8.ISN的不固定性:
为了防止攻击者猜出来ISN的值,所以ISN并不是一个固定的值,而是一个32比特的计数器,它一般是每4s加1。除了可以防止被攻击之外,还有一个好处就是,可以避免当因为网络延迟而造成延迟分组,之后又正常传送从而造成连接方对其错误的解释。
9.三次握手什么时候可以携带数据:
在三次握手中,第一二次是不能携带数据的,第三次是可以携带数据的。之所以前两次不可以携带数据,是为了防止攻击者在尚未建立连接的时候,通过传送报文建立连接的时候加入大量数据并短时间内急速重复发送SYN报文,这样会极大地加重服务器的负担。而第三次的时候已经建立了连接,所以这个时候在可以携带数据是很合理的。
10.SYN攻击:
SYN攻击指的是客户端在短时间内大量伪造随机且不存在的IP地址,并向服务器端不断地发送SYN包。因为服务器资源是在第二次握手的时候分配的,而客户端资源是在第三次攻击时分配的,所以这种虚假的SYN包不仅会造成半连接队列长时间溢出被占用,会把正常的请求因为队列已满给丢弃,而且因为其不存在,服务器在短时间内大量重传造成网络阻塞或系统瘫痪。
想要检测SYN攻击,只需要在服务器上查看到有大量的半连接,且IP地址都是随机的,那么这很有可能就是SYN攻击。
在Linux和Unix系统上,可以使用系统自带的netstarts命令来检测SYN攻击。
netstart -n -p TCP | grep SYN_RECV
应对SYN攻击的办法:缩短超时时间、增加最大半连接数量、过滤网关防护、SYN cookies技术
二.四次挥手
1.四次挥手简述:
四次挥手指的是拆除一个TCP连接,需要服务器和客户端相互发送四个包,所以也称为四次挥手和四次握手。之所以需要四次挥手,是因为TCP的半关闭特性决定的。半关闭指的是其中一方在结束其发送能力之后,还是可以接收到另一方发送过来的包。
2.四次挥手过程:
在四次挥手开始的时候,双方都处于ESTABLISHED状态。
2.1.客户端发送一个指定了序列号的FIN报文,然后主动关闭TCP连接停止再发送数据,此时客户端处于连接释放报文段(FIN_WAIT1)状态,并等待服务器端的确认。
2.2.服务器端在接收后会发送值为客户端序列号+1的ACK报文,表示服务器端已经收到了客户端报文,服务器端进入CLOSE_WAIT状态。此时TCP处于半关闭状态,客户端到服务器端的连接被释放。客户端在收到ACK报文后进入FIN_WAIT2状态,等待服务端发出的连接释放报文段。
2.3.服务器端若是想断开和客户端的连接,同样需要发送FIN报文和初始化序列号,此时服务器端进入LOCK_ACK状态,等待客户端的确认。
2.4.客户端收到后会发送值为服务器端序列号+1的ACK报文,此时客户端处于TIME_WAIT状态。在经过一段时间的等待之后(时间等待计时器设置的2MSL),确保服务器端接收到ACK报文之后才会进入CLOSED状态关闭连接。
3.四次挥手的必要性:
当服务器端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。但是关闭连接时服务端收到FIN报文,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,通知客户端已收到报文,但是只有等到我当服务端发送完所有报文后才能发送FIN报文,因不能一起发送所以需要四次。
4.2MSL等待状态:
MSL:即最长报文段寿命(Maximum Segment Lifetime),它是任何报文在网络上存在的最长时间,超过这个时间报文就被会丢弃。
2MSL等待状态(又称为TIME_WAIT状态):每个具体的TCP实现必须选择一个MSL报文段最大生存时间,它是任何报文段在被丢弃之前可以在网络内存在的最长时间。这个时间是有限的,因为TCP报文段是以IP数据报的网络内传输,且IP数据报有专门限制其生存时间的TTL字段。
对一个具体实现所给定的MSL值,处理原则是当TCP执行一个主动关闭,并发挥最后一个ACK,该连接必须在TIME_WAIT状态停留时间为2倍MSL。这样可以让TCP再次发送最后的那个ACK防止丢失(另一端超时并发送最后的FIN)。2MSL的另一个结果是这个TCP连接在2MSL等待的时候,会定义这个连接的插口(客户端的端口号和IP地址,服务器端的端口号和IP地址)不能再被使用(只有在2MSL结束后才能被再次使用)。
4.3.2MSL等待的意义:
之所以需要等待2MSL,是为了确保客户端最后要发送的ACK报文一定能够被服务器端接收。如果这个ACK报文丢失,那么处于LAST_ACK状态的服务器端就会因为收不到报文而重传,这个时候客户端会再一次发送ACK报文并重置2MSL等待时间,知道服务器端正常接受报文,使得双方能够正常关闭。如果客户端在发送ACK报文之后没有进行2MSL等待就直接关闭,那么就可能会因为ACK报文丢失而导致服务器端无法正常关闭。