TCP三次握手
模拟三次握手
telnet连接虚拟机192.168.0.107。用tcpdump抓包,然后用wireshark分析报文。
以上过程如下图:
分析
上图2,3,4就是三次握手的过程。本地端口号为52368,telnet端口号23。
上面截图就是第一次握手的数据分析,可以清晰的看出TCP报文头的结构:
1、16位源目的端口号;
2、32的Sequence number号(e4 6d 0c 3c)和32位的确认号(Acknowledgment number) :ACK number是接收到的报文的sequence+1。这里截图显示seq number和ack number都是0,但看最下面的内容会发现不是0,这里WireShark只是为了大家看着方便,所以把它简化成逻辑sequence number 0,否则看一个32位的数,然后再+1,看着累伐。sequence number用来解决网络报文乱序的问题,32位,超过2^32-1后,从0重新开始。 Acknowledgment number用于确认收到报文,解决丢包的问题。
3、4位首部长度(Header Length):表示TCP报文头的大小=20字节的正常报文头大小+可选项所占字节数。整个首部长度等于header Length *4(首部是4字节的整数倍);
4、12位标志位-flags(一般是前6位保留,后6位有效):(Urgent, Acknowledgment,Push,Reset,Synchronized,Finish)
5、16位窗口大小(window size value):窗口大小为字节数,窗口大小是16字段,因而窗口大小最大65535,具体怎么控制流程,以后再细说;
6、16位校验和(checksum)和16位紧急指针(urgent pointer)。
7、选项(options):TCP报文头正常长度一共20个字节,这是固定的。但是TCP报文头有时还有可选项(options),本例中为24字节,所以4整个报文头我们可以认为是44字节,因此之前的首部长度的值为1011,即44字节。options可选字段最常见的内容是MSS(maximum segment Size),即最长报文大小。每个连接方通常都会在第一个报文中指明这个选项,它表示本端能接受的最大报文长度。
下图是107回应的报文:
可以看出该确认报文的ACK标志位已经被置1,而32位的acknowledgment是收到报文的seqence number+1得到的。自己的sequence number是c1 bf 5a 89(当然,为了简单查看,显示的是relative seqence number 0)。我们还注意到options中同样有MSS 1460字节,因为这是107第一次给108发报文,前面我们说到第一次通信一般都会告知对方自己能接收的最长报文大小。接下来108收到这个报文要做同样的事情,回复一个确认报文给107,该报文截图如下:
同样看到ACK被设置成1.而options中没有MSS了,因为这是108第二次和107通信了,第一次已经告知对方自己的MSS了。sequence numer=e4 6d 0c 3d(上一个报文的sequence number e4 6d 0c 3c加1), acknowledgment number = c1 bf 5a 8a(c1 bf 5a 89+1)。
TCP重传机制
TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。
注意,接收端给发送端的Ack确认只会确认最后一个连续的包,比如,发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,于是回ack 3,然后收到了4(注意此时3没收到),此时的TCP会怎么办?我们要知道,因为正如前面所说的,SeqNum和Ack是以字节数为单位,所以ack的时候,不能跳着确认,只能确认最大的连续收到的包,不然,发送端就以为之前的都收到了。
超时重传机制
一种是不回ack,死等3。当发送方收不到3的ack后,会等待,超时后重传报文3。当收到3的ack后,会ack回4,表示报文4也收到了。
但是,这种机制有一个问题,那就是因为要死等3,会导致即使4、5都收到了,而发送方没有收到3的ack,所以发送方悲观的的认为4、5也丢了,转而重传3、4、5。
对此,有两种选择:
1、仅重传报文3。
2、重传3之后的所有报文,即重传3、4、5。
这两种方式有好有不好。第一种方式节约带宽,但是慢。第二种快一点,但是会浪费带宽,也有可能在做无用功。总体来说都不好。因为在等待timeout,timeout时间有可能会很长。
SYN_SENT状态
客户端发出SYN报文后,收到服务端确认报文之前的这段时间,客户端处于SYN_SENT状态。
SYN_RCVD状态
服务器一开始是LISTEN状态,当收到客户端发来的SYN报文后,服务器端TCP状态就变成SYN_RCVD状态,此时ACK和SYN标志位都置1,并返回ACK报文。 如果一切顺利,服务器端将会在收到客户端发来的ACK报文后,从SYN_RCVD切换到ESTABLISHED状态。正常情况下SYN_RCVD状态非常短暂。如果发现有大量的SYN_RCVD状态,那可能遭到了SYN Flood的DoS(拒绝服务攻击)攻击了。
SYN Flood攻击原理
三次握手时,攻击端伪造不存在的IP地址,向服务器端发送SYN报文,服务器端收到SYN报文后进入SYN_RCVD状态,并返回SYN+ACK,并等待客户端的ACK。由于这些客户端地址是假的,服务器当然不会收到客户端的ACK报文。服务器遇到这种情况一般会重发SYN+ACK报文,并等待一段时间,这段时间我们称之为SYN timeout,一般30s-2min。一个客户端异常导致服务器端的一个线程等1分钟不是什么问题,但是如果有攻击端恶意模拟这种情况,导致服务端消耗大量的资源去维护一个半连接列表,并消耗CPU资源、增加CPU响应正常客户情况的时间。在客户端看来,服务器失去响应,这种情况我们称做:服务器端受到了SYN Flood攻击(SYN洪水攻击)。
解决方法