nftables:是否可以阻止带有有效载荷的 SYN 数据包?

nftables:是否可以阻止带有有效载荷的 SYN 数据包?

是否可以使用 丢弃所有带有有效载荷的 TCP SYN 数据包nftables

手册页提到了各种length选项,但没有一个能够让我在不出现语法错误的情况下处理 TCP 数据包。

我正在使用内核 v6.2.10 和 nftables v1.0.7。

答案1

今天直接的此功能不存在nftablesnftables' 原始有效负载功能对此来说太有限了。TCP 段没有数据长度的直接标头信息。它的标头长度为,@th,96,4 << 2这对于到达数据部分没有用处。iptablesu32match 可以做得更好,但还不够:它可以进行链式计算,并获取指向 TCP 数据有效负载开头的指针,并匹配其内容(oknftables' 最近@ih可能也会这样做)。但是,由于它既不能做减法,也不够灵活,所以它不能用于计算数据有效负载长度,但可能已经足够好了(“对 [skb->data,skb->end] 之外的任何内存访问都会导致匹配失败。”:对于 1 到 3 之间的数据大小,行为可能未定义)。

物有所值,tcpdump的 BPF可以对 IPv4 进行此类计算因为它知道如何做减法:

tcpdump 'ip and (tcp[tcpflags] & (tcp-syn|tcp-rst|tcp-ack|tcp-fin) == tcp-syn) and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) > 0)'

使用查找表来处理 IPv4 情况

有时可以预先计算无法在运行时计算的内容,并将其放入查找表中。对于 IPv4 和nftables,可以构建一个查找表,包含三元组的所有有效值(IP总长度国际人道法数据偏移量) 其中 TCP 数据大小为零,并且匹配(或匹配失败)该查找表。

  • 可能的 IP 报头大小(以 4 字节字为单位)国际人道法):5至15之间。
  • TCP 报头大小(以 4 字节为单位)数据偏移量):也在5到15之间。

11x11=121 种可能性,其中 IP 长度(总长度) = IHLx4 + DOx4

注意:由于 IPv6 及其在固定报头和最终协议(TCP)报头之间的可变数量的额外报头,因此无法使用这种方法,因为查找表的大小可能非常大,而不仅仅是 121 个元素。

tcpsynzero.nft

table ip tcpsynzero # for idempotence
delete table ip tcpsynzero # for idempotence

table ip tcpsynzero {
    flags dormant

    set validtriplet {
        typeof ip length . @nh,4,4 . @th,96,4;
    }

    chain dropsynwithdata {
        tcp flags syn ip length . @nh,4,4 . @th,96,4 != @validtriplet counter drop
    }

    chain prerouting {
        type filter hook prerouting priority 0; policy accept;
        goto dropsynwithdata
    }

    chain output {
        type filter hook output priority 0; policy accept;
        goto dropsynwithdata
    }
}

首先加载nft -f tcpsynzero.nft(表格已加载,但蛰伏因此没有启用,因为如果没有加载的集合,它将丢弃所有 SYN)。

generatetriplets.bash生成Bash 脚本nftables填充集合的命令:

#!/bin/bash

for ihl in {5..15}; do
    for _do in {5..15}; do
        l=$((ihl*4+_do*4))
        printf 'add element ip tcpsynzero validtriplet { %d . %#x . %#x }\n' $l $ihl $_do
    done
done

填充集合:

bash generatetriplets.bash | nft -f -

最后启用该表(重新声明该表几乎是无操作的,除了它删除蛰伏旗帜):

nft add table ip tcpsynzero

测试

在 Linux 6.1.x 和 nftables 1.0.7 上进行了测试,并且通过(ab)使用TCP 快速打开有一些强制模式:

  • Linux 服务器地址为 192.0.2.2nftables规则集已安装。

    sysctl -w net.ipv4.tcp_fastopen=0x602
    

    socat tcp4-listen:8080,reuseaddr,fork -
    
  • Linux 客户端

    sysctl -w net.ipv4.tcp_fastopen=0x5
    

    • 立即工作:

      curl http://192.0.2.2:8080/
      
    • 第一个 SYN 被阻止(1 秒后使用正常 SYN 重试):

      curl --tcp-fastopen http://192.0.2.2:8080/
      

      注意:使用nftables客户端上的规则集(而不是服务器上的规则集)没有延迟,因为输出判定降低触发套接字上的即时错误,但内核会立即使用正常 SYN 重试此操作。丢弃规则中的计数器当然仍会递增,因为数据包仍被丢弃。


在其他中使用的类似解决方法nftables案件:Nftables 时间戳映射

答案2

那么通过 tcp 选项删除怎么样?

例如使用 TCP Fast Open Cookie 删除出站 TCP SYN:

iptables -t 过滤器 -A OUTPUT -p tcp --syn --tcp-option 34 -j DROP

(据我所知这实际上迫使其退回到非 TCP 快速打开模式,因此有效载荷更少)

相关内容