是否可以使用 丢弃所有带有有效载荷的 TCP SYN 数据包nftables
?
手册页提到了各种length
选项,但没有一个能够让我在不出现语法错误的情况下处理 TCP 数据包。
我正在使用内核 v6.2.10 和 nftables v1.0.7。
答案1
今天直接的此功能不存在nftables。nftables' 原始有效负载功能对此来说太有限了。TCP 段没有数据长度的直接标头信息。它的标头长度为,@th,96,4 << 2
这对于到达数据部分没有用处。iptables‘u32
match 可以做得更好,但还不够:它可以进行链式计算,并获取指向 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 数据大小为零,并且匹配(或匹配失败)该查找表。
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 快速打开模式,因此有效载荷更少)