TCP SYN Cookie

Last Updated: 2023-03-24 07:43:48 Friday

-- TOC --

在面对Syn-Flood攻击的时候,服务器给TCP连接的资源会被大量消耗,可能会无法再响应正常的连接请求。当服务器TCP的半连接队列被SYN攻击请求塞满后,SYN Cookie就成为一种可能还可以接收正常请求的机制。

Linux文档中说明,SYN Cookie机制只是用来应对攻击,如果没有攻击,只是服务器负担过重,不建议使用这个功能。因为这个功能不是TCP标准,通过Cookie建立的TCP连接,不支持TCP扩展功能。但是,tcp_syncookies默认开启,设置为1,在SYN队列被塞满后开始工作。

Syn-Flood攻击成立的关键在于服务器资源的有限性,服务器收到请求会分配资源。通常来说,服务器用这些资源保存此次请求的关键信息,包括连接五元组,TCP选项,如最大报文段长度MSS、时间戳timestamp、选择应答使能Sack、窗口缩放因子Wscale等等。当后续的ACK报文到达,三次握手完成,全连接成功创建,这些信息会被复制到连接结构中,用来指导后续的报文收发。

那么现在的问题就是,服务器如何在没有资源可分的情况下:

  1. 验证之后可能到达的ACK的有效性,保证这是一次完整的握手
  2. 获得SYN报文中携带的TCP选项信息

SYN Cookie算法解决了问题(1)和问题(2)的一部分。

我们知道,TCP连接建立时,双方的起始报文序号是任意的。SYN cookies利用这一点,按照以下规则构造初始序列号:

  1. 设t为一个缓慢增长的时间戳(典型实现是每64s递增一次)
  2. 设m为客户端发送的SYN报文中的MSS选项值
  3. 设s是连接信息(源IP,目的IP,源端口,目的端口)和t的Hash值,即s = hash(sip,dip,sport,dport,t),s的结果取低 24 位

则初始序列号n为:

  1. 高 6 位为t mod 32
  2. 接下来 2 位为mss的编码值
  3. 低 24 位为s
+----------+--------+-------------------+
|  6 bits  | 2 bits |     24 bits       |
| t mod 32 |  MSS   | hash(ip, port, t) |
+----------+--------+-------------------+

当客户端收到此SYN+ACK报文后,根据TCP标准,它会回复ACK报文,且报文中ack = n + 1,那么在服务器收到它时,将 ack-1 就可以拿回当初发送的SYN+ACK报文中的序号了!服务器巧妙地通过这种方式间接保存了一部分SYN报文的信息。

接下来,服务器需要对 ack-1 这个序号进行检查:

  1. 将高 6 位表示的t与当前之间比较,看其到达地时间是否能接受。
  2. 根据t和连接信息重新计算s,看是否和低 24 一致,若不一致,说明这个报文是被伪造的。
  3. 解码序号中隐藏的mss信息

到此,连接就可以顺利建立了,并且没有占用半连接SYN队列的资源。

tcp_syncookies.png

既然SYN Cookies可以跳过资源分配环节,那为什么没有被纳入TCP标准呢?原因是SYN Cookies也是有代价的:

  1. MSS的编码只有2位,因此最多只能使用 4 种MSS值;
  2. 服务器必须拒绝客户端SYN报文中的其他只在SYN和SYN+ACK中协商的选项,原因是服务器没有地方可以保存这些选项,比如Wscale和SACK;
  3. 增加了Hash运算;
/*
 * MSS Values are chosen based on the 2011 paper
 * 'An Analysis of TCP Maximum Segement Sizes' by S. Alcock and R. Nelson.
 * Values ..
 *  .. lower than 536 are rare (< 0.2%)
 *  .. between 537 and 1299 account for less than < 1.5% of observed values
 *  .. in the 1300-1349 range account for about 15 to 20% of observed mss values
 *  .. exceeding 1460 are very rare (< 0.04%)
 *
 *  1460 is the single most frequently announced mss value (30 to 46% depending
 *  on monitor location).  Table must be sorted.
 */
static __u16 const msstab[] = {
    536,
    1300,
    1440,   /* 1440, 1452: PPPoE */
    1460,
};

Linux doesn't know any optional TCP parameters of the other party. Information about Timestamps, ECN, Selective ACK, or Window Scaling is lost, and can lead to degraded TCP session performance.

Linux中的SYN Cookie与上文描述的稍有不同,其初始序列号的生成:

seq = hash(saddr, daddr, sport, dport, 0, 0) + req.th.seq + t << 24 + (hash(saddr, daddr, sport, dport, t, 1) + mss_ind) & 0x00FFFFFF

内核编译需要打开 CONFIG_SYN_COOKIES,内核参数:net.ipv4.tcp_syncookie

代码线索:

tcp_conn_request
  |-- cookie_init_sequence
     |-- cookie_v4_init_sequence
        |-- __cookie_v4_init_sequence
           |-- secure_tcp_syn_cookie

SYN Cookie与TCP timestamps

承接前面所述SYN Cookie的缺点,Fortunately Linux has a work around. If TCP Timestamps are enabled, the kernel can reuse another slot of 32 bits in the Timestamp field. It contains:

+-----------+-------+-------+--------+
|  26 bits  | 1 bit | 1 bit | 4 bits |
| Timestamp |  ECN  | SACK  | WScale |
+-----------+-------+-------+--------+

如果服务器和客户端都打开了时间戳选项(Linux默认打开),那么服务器可以将客户端在SYN报文中携带了TCP选项的部分使能情况暂时保存在时间戳中。当前使用了低 6 位,分别保存Wscale、SACK和ECN。

syn_cookie_timestamps.png

客户端会在ACK的TSecr字段,把这些值带回来。

accept会将全连接队列中的ESTABLISHED的连接取出来,如果不调用accept,多个client调用connect后,可以达到让server的队列满的测试效果。这个队列的长度,由listen接口的backlog参数控制。

虽然net.ipv4.tcp_timestamps默认是打开的,它在SYN Cookie启用的时候,可以带来一些好处,但它也会给每个报文增加12byte的长度,non-trivial amount of bandwidth。当然,tcp_timestamps的作用一开始并不是为了SYN Cookie,它还有别的重要功能。

The Linux SYN packet handling landscape is constantly evolving. Until recently SYN Cookies were slow, due to an old fashioned lock in the kernel. This was fixed in 4.4 and now you can rely on the kernel to be able to send millions of SYN Cookies per second, practically solving the SYN Flood problem for most users. With proper tuning it's possible to mitigate even the most annoying SYN Floods without affecting the performance of legitimate connections.

本文链接:https://cs.pynote.net/net/tcp/202205052/

-- EOF --

-- MORE --