名词解释:
两个序号和六个标志位:
序号:
seq序号,占32位;
ack序号,32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1;
标志位:
①ACK:确认序号有效
②SYN:发起一个新连接
③FIN:释放一个连接
④URG:紧急指针有效
⑤PSH:接收方应该尽快将这个报文交给应用层
⑥RST:重置连接
三次握手过程:
第一次:客户端向服务端发起连接请求,将SYN置为1,并随机生成一个序列号seq=x,然后将该数据包发送给服务器此时客户端进入SYN-SENT状态,等待服务端的确认;
第二次:服务器收到数据包之后,由SYN标志位为1得知客户端请求建立连接,需要确认客户端的SYN,将ACK标志位置为1,ack=x+1,同时自己也发送一个SYN包,随机产生一个序列号seq=y,将SYN+ACK发送给客户端,此时服务端进入SYN-RECV状态;
第三次:客户端收到服务器的SYN+ACK包,向服务器发送确认包,ack=y+1,此包发送完毕后,客户端和服务端进入ESTABLISHED状态,表示TCP连接成功,完成三次握手;
为什么要三次握手:
一方面,3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
就两次握手而言,在服务端向客户端回复SYN+ACK后,服务端认为连接已经建立,故而开始发送数据,但对于客户端而言,在服务端的SYN+ACK分组在传输中被丢失的情况下,客户端不知道服务端用怎样的序列号,甚至不知道服务端是否收到自己的连接请求,故一直等待服务端的确认应答分组,服务端传来的数据会被丢弃,而服务端在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
另一方面,三次握手可以防止已经失效的连接请求报文突然又传送到服务器,从而产生错误 ;
如果使用的是两次握手连接,假设客户端发送了第一个请求连接并且没有丢失,只是因为在网络节点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接,此时从前滞留的那一次请求连接,网络通畅之后到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费 ;
四次挥手:
第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,生成一个序列号seq=u,Client进入FIN_WAIT_1状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
第二次挥手:Server收到FIN后,发送一个ACK给Client,其确认序号ack为收到序号+1(u+1)(与SYN相同,一个FIN占用一个序号),服务器Server进入CLOSE_WAIT状态。
TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
第三次挥手:客户端收到服务器的确认请求之后,此时,客户端就进入FIN_WAIT_2状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据),服务器Server发送一个FIN,seq=w,用来关闭服务器Server到客户Client的数据传送,服务器Server进入LAST_ACK状态。
第四次挥手:客户Client收到FIN后,必须发出确认,ACK=1,ack为收到序号+1(w+1),seq=u+1,进入TIME_WAIT状态(注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
建议理解方式:
建立TCP连接:三次握手协议
客户端:我要对你讲话,你能听到吗;
服务端:我能听到;而且我也要对你讲话,你能听到吗;
客户端:我也能听到。
…….互相开始通话………
二:关闭TCP连接:四次挥手协议
客户端:我说完了,我要闭嘴了;
服务端:我收到请求,我要闭耳朵了;(客户端收到这个确认,于是安心地闭嘴了。)
服务端还没说完,于是继续向客户端说了半天,直到说完为止…….
服务端:我说完了,我也要闭嘴了;
客户端:我收到请求,我要闭耳朵了;(事实上,客户端为了保证这个确认包成功送达,等待了两个最大报文生命周期后,才闭上耳朵。)(服务端收到这个确认,于是安心地闭嘴了。)
为什么建立的是三次握手,关闭是四次挥手 :
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。
SYN攻击:
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接,此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发甚至超时,这些伪造的SYN包将占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。
防御:
在服务端利用syn cookie技术,就是服务器在收到syn包时并不马上分配储存连接的数据区,而是根据这个syn包计算出一个cookie,把这个cookie填入tcp的Sequence Number字段发送syn+ack包,等对方回应ack包时检查回复的Acknowledgment Number字段的合法性,如果合法再分配专门的数据区。
所以说syn cookie虽然能抵御syn攻击但是却容易受到ack攻击。想要防御住所有类型的DOS攻击是很苦难的,需要对各种攻击的原理与防御方法非常了解,并且针对不同攻击选择合适的防御方法才行。