TCP和UDP
TCP报文格式
TCP首部的报文格式如下:
宏观上来看如下:
此图来源于:https://zhuanlan.zhihu.com/p/144273871 知乎-腾讯技术-TCP拥塞控制详解
- 来源连接端口(16位长)-识别发送连接端口
- 目的连接端口(16位长)-识别接收连接端口
- 序列号(seq,32位长):
- 如果含有同步化旗标(SYN),则此为最初的序列号;第一个数据比特的序列码为本序列号加一。
- 如果没有同步化旗标(SYN),则此为第一个数据比特的序列码。
- 确认号(ack,32位长)— 期望收到的数据的开始序列号。也即已经收到的数据的字节长度加1。
- 数据偏移(4位长)— 以4字节为单位计算出的数据段开始地址的偏移值。
- 保留(3比特长)— 须置0
- 标志符(9比特长)
- NS—ECN-nonce。ECN显式拥塞通知(Explicit Congestion Notification)是对TCP的扩展,定义于RFC 3540(2003)。ECN允许拥塞控制的端对端通知而避免丢包。ECN为一项可选功能,如果底层网络设施支持,则可能被启用ECN的两个端点使用。在ECN成功协商的情况下,ECN感知路由器可以在IP头中设置一个标记来代替丢弃数据包,以标明阻塞即将发生。数据包的接收端回应发送端的表示,降低其传输速率,就如同在往常中检测到包丢失那样。
- CWR—Congestion Window Reduced,定义于RFC 3168(2001)。
- ECE—ECN-Echo有两种意思,取决于SYN标志的值,定义于RFC 3168(2001)。
- URG—为1表示高优先级数据包,紧急指针字段有效。
- ACK—为1表示确认号字段有效
- PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
- RST—为1表示出现严重差错。可能需要重新创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。
- SYN—为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
- FIN—为1表示发送方没有数据要传输了,要求释放连接。
- 窗口(WIN,16位长)—表示从确认号开始,本报文的发送方可以接收的字节数,即接收窗口大小。用于流量控制。
- 校验和(Checksum,16位长)—对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。
- 紧急指针(16位长)—本报文段中的紧急数据的最后一个字节的序号。
- 选项字段—最多40字节。每个选项的开始是1字节的kind字段,说明选项的类型。
- 0:选项表结束(1字节)
- 1:无操作(1字节)用于选项字段之间的字边界对齐。
- 2:最大报文段长度(4字节,Maximum Segment Size,MSS)通常在创建连接而设置SYN标志的数据包中指明这个选项,指明本端所能接收的最大长度的报文段。通常将MSS设置为(MTU-40)字节,携带TCP报文段的IP数据报的长度就不会超过MTU(MTU最大长度为1518字节,最短为64字节),从而避免本机发生IP分片。只能出现在同步报文段中,否则将被忽略。
- 3:窗口扩大因子(3字节,wscale),取值0-14。用来把TCP的窗口的值左移的位数,使窗口值乘倍。只能出现在同步报文段中,否则将被忽略。这是因为现在的TCP接收数据缓冲区(接收窗口)的长度通常大于65535字节。
- 4:sackOK—发送端支持并同意使用SACK选项。
- 5:SACK实际工作的选项。
- 8:时间戳(10字节,TCP Timestamps Option,TSopt)
- 发送端的时间戳(Timestamp Value field,TSval,4字节)
- 时间戳回显应答(Timestamp Echo Reply field,TSecr,4字节)
参考:https://baike.baidu.com/item/TCP%E6%8A%A5%E6%96%87%E6%A0%BC%E5%BC%8F/53100036?fr=aladdin
在了解 TCP 的拥塞控制之前,先来看看 TCP 的首部格式和一些基本概念。
TCP 头部标准长度是 20 字节。包含源端口、目的端口、序列号、确认号、数据偏移、保留位、控制位、窗口大小、校验和、紧急指针、选项等。
1.1 数据偏移(Data Offset)
该字段长 4 位,单位为 4 字节。表示为 TCP 首部的长度。所以 TCP 首部长度最多为 60 字节。
1.2 控制位
目前的 TCP 控制位如下,其中 CWR 和 ECE 用于拥塞控制,ACK、RST、SYN、FIN 用于连接管理及数据传输。
CWR:用于 IP 首部的 ECN 字段。ECE 为 1 时,则通知对方已将拥塞窗口缩小。 ECE:在收到数据包的 IP 首部中 ECN 为 1 时将 TCP 首部中的 ECE 设置为 1,表示从对方到这边的网络有拥塞。 URG:紧急模式 ACK:确认 PSH:推送,接收方应尽快给应用程序传送这个数据。没用到 RST:该位为 1 表示 TCP 连接中出现异常必须强制断开连接。 SYN:初始化一个连接的同步序列号 FIN:该位为 1 表示今后不会有数据发送,希望断开连接。
1.3 窗口大小(Window)
该字段长度位 16 位,即 TCP 数据包长度位 64KB。可以通过 Options 字段的 WSOPT 选项扩展到 1GB。
1.4 选项(Options)
受 Data Offset 控制,长度最大为 40 字节。一般 Option 的格式为 TLV 结构:
常见的 TCP Options 有,SACK 字段就位于该选项中。:
1.5 SACK 选项
SACK 包括了两个 TCP 选项,一个选项用于标识是否支持 SACK,是在 TCP 连接建立时发送;另一种选项则包含了具体的 SACK 信息。
- SACK_Permitted 选项,该选项只允许在 TCP 连接建立时,有 SYN 标志的包中设置,也即 TCP 握手的前两个包中,分别表示通信的两方各自是否支持 SACK。
TCP SACK-Permitted Option: Kind: 4 Length: Variable +----------+----------+ | Kind=4 | Length=2 | +----------+----------+
- SACK(选择性确认) 选项位于 Options 中。该选项参数告诉对方已经接收到并缓存的不连续的数据块,发送方可根据此信息检查究竟是哪些块丢失,从而发送相应的数据块。受 TCP 包长度限制,TCP 包头最多包含四组 SACK 字段。
TCP SACK Option: Kind: 5 Length: Variable +--------+--------+ | Kind=5 | Length | +--------+--------+--------+--------+ | Left Edge Of lst Block | +--------+--------+--------+--------+ | Right Edge Of lst Block | +--------+--------+--------+--------+ | . . . | +--------+--------+--------+--------+ | Left Edge Of nth Block | +--------+--------+--------+--------+ | Right Edge Of nth Block | +--------+--------+--------+--------+
- SACK 的工作原理
如下图所示, 接收方收到 500-699 的数据包,但没有收到 300-499 的数据包就会回 SACK(500-700) 给发送端,表示收到 500-699 的数据。
WireShark抓包TCP三次握手
- 第一次握手:客户端向服务端发送SYN包到服务器,并进入SYN_SNET状态,等待服务器确认。
- 第二次握手:服务器收到SYN包之后,必须先确认客户端的SYN包,同时自己也发一个SYN包,即一次发送ACK+SYN的包给到客户端,此时服务器进入SYN_RECV状态
- 第三次握手:客户端收到服务器的ACK+SYN包之后,向服务器端发送ACK包。
第三次握手完成之后,客户端和服务器端都进入ESTABLISHED状态。
为什么客户端还要发送最后一次确认呢?
主要是为了防止已经失效的连接请求报文突然又传送到了服务端,因而产生错误。
所谓「已经失效的连接请求报文」是这样产生的:客户端发送的第一个连接请求报文段没有丢失,而是在某些网络结点长时间滞留了,导致延误到连接释放以后的某个时刻才到达服务端。本来这是一个已经失效的报文,但是服务端接收到此请求报文之后,被误认为是客户端又发出一次新的连接请求,于是又向客户端发送确认报文,同意建立连接。假设没有最后一次握手,那么只要服务端发出确认,新的连接就建立了。
由于现在客户端并没有发出建立连接的请求,因此不会理睬服务端的确认,也不会向服务端发送数据。但是服务端却以为新的连接已经建立了,并一直等待客户端发来数据,服务端的许多资源就这样白白浪费了。
什么是SYN泛洪攻击
TCP SYN泛洪发生在OSI第四层,这种方式利用TCP协议的特性,就是三次握手。攻击者发送TCP SYN,SYN是TCP三次握手中的第一个数据包,而当服务器返回ACK后,该攻击者就不对其进行再确认,那这个TCP连接就处于挂起状态,也就是所谓的半连接状态,服务器收不到再确认的话,还会重复发送ACK给攻击者。这样更加会浪费服务器的资源。攻击者就对服务器发送非常大量的这种TCP连接,由于每一个都没法完成三次握手,所以在服务器上,这些TCP连接会因为挂起状态而消耗CPU和内存,最后服务器可能死机,就无法为正常用户提供服务了。
SYN泛洪攻击的防范措施
对于SYN泛洪攻击的防范,优化主机系统设置是常用的手段。
- 降低SYN timeout时间,使得主机尽快释放半连接的占用;
- 采用SYN cookie设置,如果短时间内连续收到某个IP的重复SYN请求,则认为受到了该IP的攻击,丢弃来自该IP的后续请求报文。
- 限制SYN缓存队列,是从内存资源的角度进行预防的。客户端发来的SYN请求数据都会放到SYN队列中,当客户端发来ACK确认时,数据会放到Accept队列中,大量的SYN请求会使SYN队列激增,耗尽内存,因此我们可以限制SYN队列的大小,超过门限,直接拒绝请求;缺点很明显,正常的客户端ip也会被拒之门外,但至少可以保证服务端不崩溃;
- 防护系统隔离,原理是syn报文首先由DDOS防护系统 带上特定的seq(记为cookie)来响应syn_ack,并不分配储存连接的数据区(不对SYN的信息进行任何存储)。真实的客户端会返回一个ack 为cookie+1,此时再分配内存。 而伪造的客户端,将不会作出响应。这样我们就可以知道那些IP对应的客户端是真实的,将真实客户端IP加入白名单。未及时做出响应的,会作为黑用户屏蔽一段时间;
下次访问直接通过,而其他伪造的syn报文就被拦截。由于防护系统不需要分配储存连接的数据区,以及进入SYN-RCVD状态,因此不会被击溃;
此外合理地采用防火墙等外部网络安全设施也可缓解SYN泛洪攻击。
参考:https://zhuanlan.zhihu.com/p/451051795 「SYN泛洪攻击原理及预防策略详解」
WireShark抓包TCP四次挥手
准确来说,客户端和服务端都能作为主动方去发起断开链接,也就是说active close端既可以是我们平时认为的client端也可以是我们平时认为的server端,而对端就是passive close端。所以为了方便称呼,我们下面把主动断开的一方称呼为「客户端」,被动断开的一端称为「服务端」。这里称呼的「客户端」并不是指的我们认为的浏览器端、手机端等客户端,而是主动断开的一方(active close),只是为了方便称呼描述。
- 第一次挥手:客户端进程发出释放报文,并且停止发送数据。释放数据报文首部之后,向服务端发送FIN包到服务器,并进入FIN_WAIT_1状态,即半关闭状态,等待服务器确认,但这个时候客户端仍然可以收到服务端发送过来的数据,只是停止自己这边发送给服务器数据。
- 第二次挥手:服务器收到FIN包之后,确认了客户端想要释放连接,随后服务器端会发送一个ACK包给客户端确认自己收到了此次客户端的FIN包,并随之进入了CLOSE_WAIT状态。客户端收到了服务端发来的ACK确认报文之后就会进入FIN_WAIT_2状态。
- 第三次挥手:服务器端发送ACK确认报文之后,经过CLOSE_WAIT阶段之后,做好了释放服务器端到客户端的连接准备,再次向客户端发送一个FIN报文。随后服务器端结束CLOSE_WAIT阶段,进入了LAST_ACK状态。
- 第四次挥手:客户端收到了服务器端发出的FIN报文,确认了服务器端已经做好释放连接的准备,向服务器端发送确认报文将ACK置为1之后进入TIME_WAIT阶段。
- 客户端在TIME_WAIT阶段之后经过2MSL时间段之后就进入了CLOSED阶段,服务器端在收到了客户端发送来的ACK确认报文段之后也进入了CLOSED阶段。