最全的三握四挥!

连接过程中的标志位、序号

  • 序号seq:报文段序号字段,其值是本报文段的数据部分的第一个字节的序号
  • 确认号ack:是期望收到对方的下一个报文段的数据部分的第一个字节的序号
  • 确认比特ACK:只有当ACK=1时,确认号字段才有效
  • 同步比特SYN:SYN置位1时,表示这是一个连接请求或连接接受报文
  • 终止比特FIN(FINal):用来释放一个连接,FIN=1时,表示此报文段的发送端的数据已发送完毕,并要求释放运输连接
  • 确认比特ACK:只有当ACK=1时,确认号字段才有效
  • 推送比特PSH(PuSH):TCP接收方收到推送比特置为1的报文段,就尽快将数据交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付
  • 复位比特RST(ReSeT):当RST=1时,表示TCP连接中出现严重差错(如主机崩溃等),必须释放连接然后再重新建立运输连接。也用于拒绝非法的TCP报文段或拒绝连接请求

TCP三握四挥

3次握手

三握

  • 第1次握手,建立连接,客户端的TCP发送SYN连接请求报文段,将首部的同步位SYN置为1,并且选择序号seq为x(x为随机生成数值) ,客户端进入SYN_SENT状态,等待服务器的确认。(TCP规定,SYN报文段(SYN=1的报文段,不能携带数据,但需要消耗掉一个序号。)
  • 第2次握手,服务器的TCP收到SYN报文段后,如果同意连接,则发回确认。在确认报文段中将SYN置为1,ACK置为1,其确认号ack=x+1,自己选择的序号seq=y(y为随机生成数值),
    然后服务器进入SYN_RECV状态。(这个报文也不能携带数据,但是同样要消耗一个序号。)
  • 第3次握手,客户端收到服务器的SYN+ACK报文段后,检查ack是否为seq+1和ACK是否为1,如果正确,向服务器发送确认包,其ACK=1,确认号ack=y+1,
    发送完后两者进入(established)TCP连接成功状态。(TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。)
注意:完成三次握手后,客户端与服务器开始传送数据,其实在第三次握手的同时,client就可以向Server发送数据

为什么需要三次握手

为防止已失效的连接请求报文突然传送到服务端,因而产生错误情况,防止服务端一直等待浪费资源。如果服务器没有收到A的确认报文,就知道A并没有要求建立连接

三次握手正常建立连接,两次握手不能保证成功率,四次握手会导致流量浪费,没有必要。

已失效的连接请求报文

  1. 正常情况:

A发出连接请求,但因连接请求报文丢失而未收到确认。于是A再重传一次连接请求,后来收到了确认,确认了连接。数据传输完毕后,就释放了连接。A共发送了两个连接请求报文,其中第一个丢失,第二个到达了B,没有已失效的请求报文

  1. 异常情况:

A 发送的第一个请求报文并没有丢失,而是在某些网络结点长时间滞留了,以致延误到连接释放以后的某个时间才能到达B,本来是一个早已经失效的报文段,但B收到这个失效的请求连接报文后,误以为是A又发送了一次新的连接请求,于是就向A发出确认报文,同意建立连接,假定没有第三次握手,那么B发出确认,新的连接就建立了。

由于现在A并没有发出建立连接的请求,因此不会理睬B的确认,也不会向B发送数据,但B却以为新的运输已经建立了,并一直等待A发来数据,B的资源就浪费了

4次挥手

四挥

数据传输结束后,通信的双方够可以释放连接(可以是客户端,也可以是服务器),如果主机1的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接

  • 第1次挥手,主机1向主机2发送FIN连接释放报文段,将首部的FIN置为1,其序号seq=u ,
    然后主机1进入FIN_WAIT_1状态,表示主机1没有数据要发送给主机2了,请求关闭连接,等待B的确认。(TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。)

  • 第2次挥手,主机2收到主机1的FIN报文段,向主机1回传一个ACK报文段,设置确认号ack=u+1,而自己的序号seq=v,主机2进入了CLOSE_WAIT状态,主机1收到返回的ACK报文后,进入FIN_WAIT_2状态,表示主机2同意关闭请求。此时从主机1到主机2这个方向的连接就释放了,TCP连接处于半关闭状态。主机2若发送数据,主机1仍然可以接收。

  • 第3次挥手,主机2会观察自己是否还有数据要发送给主机1,如果有,先把数据发送给主机1,再发送FIN报文;如果没有,那么主机2直接向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态

  • 第4次挥手,主机1收到主机2的FIN报文段,向主机2发送ACK确认报文段(seq、ack),主机1进入TIME_WATI状态,
    主机2收到主机1发来的ACK报文就关闭连接。
    此时,主机1等待2msl后仍然没有收到回复,
    则证明主机2已正常关闭,然后主机1也关闭连接
    image

    状态分析

    主动方在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时主动方进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的。

CLOSE_WAIT表示在等待去关闭连接。当主动方发送FIN报文给被动方,被动方毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来,被动方需要考虑的事情是察看是否还有数据发送给主动方,如果没有的话,发送FIN+ACK报文给对方,即关闭连接。

为什么需要四次挥手

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式。

这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,告诉主机2它的数据已经全部发送完毕了,但是主机1还是可以接受来自主机2的数据。

当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以给主机1发送数据

当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后主机1再发送ACK给主机2,等待2msl后没有收到回复则说明主机2关闭成功,中断这次TCP连接

为什么TIME_WAIT需要经过2msl(最大报文段生存时间)才能返回close状态

MSL 最长报文寿命:指任何报文段被丢弃前在网络内的最长时间,作用:

  • 为了保证主动方发送的最后一个ACK报文段能够到达被动方
  • 防止 已失效的连接请求报文段 出现在本连接中
  1. 为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次ACK确认报文,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。

  2. 还可以防止已失效的报文段。客户端在发送最后一个ACK之后,再经过2MSL,就可以使本链接持续时间内所产生的所有报文段都从网络中消失。从保证在关闭连接后不会有还在网络中滞留的报文段去骚扰服务器。

SYN攻击

1. SYN Flood

在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才能转入 ESTABLISHED 状态.

SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN包,服务器回复确认包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢,严重者会引起网络堵塞甚至系统瘫痪。

SYN 攻击是一种典型的 DoS/DDoS 攻击。

2. 如何检测SYN攻击

检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。

3. 如何防御SYN攻击

SYN攻击不能完全被阻止,除非将TCP协议重新设计。我们所做的是尽可能的减轻SYN攻击的危害,常见的防御 SYN 攻击的方法有如下几种:

  • 缩短超时(SYN Timeout)时间
  • 增加最大半连接数
  • 过滤网关防护
  • SYN cookies技术