比较 NFTables 中 `saddr` 和 `daddr` 的字节

比较 NFTables 中 `saddr` 和 `daddr` 的字节

我有很多子网10.x.y.0/24,其中0 ≤ x ≤ 500 ≤ y ≤ 20

我希望允许 之间的流量10.x.y.0/24以及10.z.y.0/24的每个值(x, y, z)

我可以使用可执行文件编写脚本nft,但我想知道是否可以使用单个规则和二进制操作来完成它。

我可以y使用“提取”地址的“字节” ip saddr & 0.0.255.0,但是当我尝试使用==运算符时,nftables告诉我语法无效:

$ cat /etc/nftables.conf
# [...]
        ip saddr & 0.0.255.0 == daddr & 0.0.255.0 accept
# [...]
$ sudo nft -f /etc/nftables
/etc/nftables.conf:113:27-31: Error: syntax error, unexpected daddr
        ip saddr & 0.0.255.0 == daddr & 0.0.255.0 accept

我尝试了一些变体,但它们似乎都不起作用,并且 NFTables wiki 从不比较数据包的不同字段。

有没有办法做到这一点?

答案1

我不认为目前nftables支持比较右侧的任意非常量表达式。我不知道这个限制是否在用户空间端如何生成足够的字节码,或者内核端的字节码是否无法处理这样的事情。可以有一个常量或一个集合/映射查找,但仅此而已。这可能会在未来演变。

无论如何,我提出了一个替代解决方案,使用串联作为查找表。仍然使用您的特定网络掩码操作,这将只需要 y 元素 (21),这比详尽的规则集或其等效的完整集版本要好得多(它仍然比简单的规则集更快,因为它是散列的):它们可能需要更多规则或详尽的匹配列表的元素。

我将在示例中使用表ip myfilter及其type filter hook forward链,请修改:ip myfilter forward

nft add table myfilter
nft add chain ip myfilter forward '{ type filter hook forward priority 0; policy drop; }'

添加由两个 IP 地址类型串联组成的集合:

table ip myfilter {
    set same-y {
        type ipv4_addr . ipv4_addr
    }
}

创建于:

nft add set ip myfilter same-y  '{ type ipv4_addr . ipv4_addr; }'

查找将匹配两个 IP 地址的串联。现在仍然可以在比较的左侧应用运算符,因此仍将使用您的自定义网络掩码运算符:只需提供修改后的源地址和修改后的目标地址,如果集合中存在匹配元素,则结果将是true(并且规则将运行该accept语句)。

nft 'add ip myfilter forward ip saddr & 0.0.255.0 . ip daddr & 0.0.255.0 @same-y accept'

再次强调:使其工作的区别在于,在这里,取决于数据包内容的两个表达式都位于左手边的比较,因此是允许的。

现在用类型的条目填充集合0.0.y.0 : 0.0.y.0,以完成逻辑比较的部分,这部分不能纯粹在数据包路径遍历期间完成,例如使用以下 shell 循环:

for i in $(seq 0 20); do printf 'add element ip myfilter same-y { 0.0.%d.0 . 0.0.%d.0 }\n' $i $i; done | nft -f -

这将在 中添加 21 个元素@same-y

0.0.0.0 . 0.0.0.0,
0.0.1.0 . 0.0.1.0,
[...]
0.0.20.0 . 0.0.20.0

如果网络扩展并接收 类型的子网络10.x.21.0/24,则只需要添加一个元素,并且这仍然可以在运行时完成。


如果您需要过滤器的一些例外情况,同时保持其通用性,则可以将上面的集合转换为判定图。大多数判决元素将以 结尾: accept,例外情况如下0.0.15.0 . 0.0.15.0 : jump exception-net-15(此类用户链也必须在同一规则集中定义)。

有了这个判决图:

table ip myfilter {
    map accept-same-y {
        type ipv4_addr . ipv4_addr : verdict
    }
}

应该用这种元素填充:

0.0.0.0 . 0.0.0.0 : accept,
0.0.1.0 . 0.0.1.0 : accept,
[...]
0.0.20.0 . 0.0.20.0 : accept

并按照此规则使用,vmap如果找到,将从地图中执行判决:

ip saddr & 0.0.255.0 . ip daddr & 0.0.255.0 vmap @accept-same-y

相关内容