TCP(Transmission Control Protocol)传输控制协议是一种面向连接的、可靠的、基于字节流的传输层协议。
重要字段:
1)源端口:源端口和IP地址的作用是标识报文的返回地址。
2)目的端口:端口指明接收方计算机上的应用程序接口。
序号:Seq序号,32位,一次TCP通信 (从TCP连接建立到断开) 过程中某一个传输方向上的字节流的每个字节的编号。
确认序号:ACK序号,32位,用作对另一方发送来的TCP报文段的响应。只有ACK标志位为1时,确认序号字段才有效,其值是收到的TCP报文段的序号值加1。
标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN 等。
标志位 | 名称 | 具体含义 |
---|---|---|
URG | 紧急标志 | 紧急指针(urgent pointer)有效 |
ACK | 确认标志 | 确认序号有效 |
PSH | 推标志 | 接收方应尽快将报文交给应用层 |
RST | 复位标志 | 重置连接 |
SYN | 同步标志 | 发起一个新连接 |
FIN | 结束标志 | 释放一个连接 |
建立TCP连接时,客户端和服务器总共发送3个包。
三次握手是为了让双方验证各自接收能力和发送能力。
1st:A发送SYN给B,B接收到。这里B能确认A的发送能力和B的接收能力。
2nd:B发送SYNACK给A,A收到。这里A能确认A的接收能力和B的发送能力。此外,A收到SYNACK,说明前面A的SYN成功到达B,也能确认A自己的发送能力和B的接收能力。至此,A已经确认双方各自发送能力和接收能力OK,因此转为ESTABLISHED状态。
3rd:A发送ACK到B,B接收。这里B能确认A的发送能力和B的接收能力。由于B能收到ACK,说明前面发送的SYNACK已经被接受了,说明A的接收能力和B的发送能力正常。
若使用两次握手,就不能确认上述四种能力,可能有问题。
假定A发的SYN报文没消失,而是在某网络节点长时间滞留了,以至于到连接释放后的某个时间才到达B。
本来这是一个早已失效的报文段,但B收到此失效连接请求报文段后,却误以为是A又发出一次新的连接请求,于是B就发出确认报文段,同时建立连接。
由于现在A并没有发出建立连接请求,因此不理睬B的SYNACK报文,也不会向B发送数据,但B却以为新连接已经建立,并一直等待A发来的数据,B的许多资源被白白浪费。
前两次不行,第三次可以携带。 假如第一次可以,如果有人恶意攻击服务器,那他在第一次SYN 报文中放入大量数据。因为攻击者根本不理会服务器的接收、发送能力是否正常,只是疯狂重复发 SYN 报文,这会让服务器花费很多内存与时间来接收这些报文。也就是说,第一次握手不能放数据,1个简单原因服务器会更容易受到攻击。而对于第三次,此时客户端处于 ESTABLISHED 状态,已经建立起连接,知道服务器接收与发送能力正常,所以携带数据也没毛病。
不固定,client_isn是随机生成的,而server_isn则需要根据SYN报文中的源、IP和端口,加上服务器本身密码数进行相同散列得到,显然也不固定。
在三次握手过程中,服务器发送SYN-ACK之后,收到客户端ACK之前的TCP连接称为半连接(half-open connect)。此时服务器处于SYN-RECV。当收到ACK后,服务器转入ESTABLISHED状态。
SYN攻击就是攻击客户端,在短时间内伪造大量不存在的IP地址,向服务器不断发送SYN包,服务器回复确认包,并等待客户确认。 由于源地址不存在,服务器需要不断重发直至超时,这些伪造SYN包将长时间占用未连接队列,正常SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
SYN攻击是一种典型的DoSe/DDoS攻击。
检测SYN攻击非常方便,当你在服务器上看到大量半连接状态时,特别是IP地址是随机的,基本可以断定这是一次SYN攻击,在Linux/Unix可用netstat命令检测。
SYN攻击不能完全被阻止,除非重新设计TCP协议。能做的就是就是尽可能减轻SYN攻击危害,常见防御方法有:缩短超时(SYN Timeout)时间、增大最大半连接数、过滤网关防护、SYN cookies技术。
系统用四元组{Local IP,Local Port,Remote IP,Remote Port} 来唯一标识TCP连接。
Client发起TCP连接时,系统通常会选取一个空闲本地端口(Local Port),该端口,类型是Unsigned short,最大65536,端口0有特殊含义,因此最大可用端口,即最大TCP连接数只有65535。
Server部分的Remote IP和Remote Port可变,因此最大TCP连接为客户端IP数*客户端Port数,IPV4简单情况(不考虑地址分类) 最大连接数为232(IP数)* 216(Port数) ,也就是Server端单机最大TCP连接数约为248 。
TCP连接拆除需要发送四个包,因此称为四次挥手。
Client或Server均可主动发起。在socket编程中,执行close()操作即可产生挥手操作。
客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
TCP协议的连接是全双工连接,一个TCP连接存在双向的读写通道。
简单说来是 “先关读,后关写”,一共需要四个阶段。以客户机发起关闭连接为例:
关闭行为是在发起方数据发送完毕之后,给对方发出一个FIN(finish)数据段。直到接收到对方发送的FIN,且对方收到了接收确认ACK之后,双方的数据通信完全结束,过程中每次接收都需要返回确认数据段ACK。
客户端TCP状态迁移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服务器TCP状态迁移:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
各个状态的意义如下:
LISTEN - 侦听来自远方TCP端口的连接请求; SYN-SENT - 在发送连接请求后等待匹配的连接请求; SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认; ESTABLISHED - 代表一个打开的连接,数据可以传送给用户; FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认; FIN-WAIT-2 - 从远程TCP等待连接中断请求; CLOSE-WAIT - 等待从本地用户发来的连接中断请求; CLOSING - 等待远程TCP对连接中断的确认; LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认; TIME-WAIT - 等待足够的时间以确保远程TCP接收到连接中断请求的确认; CLOSED - 没有任何连接状态;
SYN_RECV
服务端收到建立连接的SYN没有收到ACK包的时候处在SYN_RECV状态。处在SYNC_RECV的TCP连接称为半连接,并存储在内核的半连接队列中,在内核收到对端发送的ack包时会查找半连接队列,并将符合的requst_sock信息存储到完成三次握手的连接的队列中,然后删除此半连接 。
CLOSE_WAIT
发起TCP连接关闭的一方称为client,被动关闭的一方称为server。在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。出现这种状况一般都是由于server端代码的问题,如果服务器出现大CLOSE_WAIT,应该要考虑检查代码 。
TIME_WAIT
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态。TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒。TIME_WAIT状态下的socket不能被回收使用。
关键在中间两步: