我正在尝试自动替换 nftables 规则。 Nftables 官方 wiki状态-f 是实现此目的的推荐方法。然而,当我nft -f /path/to/new/rules
在 Debian Buster 上运行时,新规则会添加到当前规则中,而不是替换它们,最终我会得到一个同时执行两个规则集的系统。
当我尝试通过systemd
's重新加载配置时,也会发生同样的事情nftables.service
。
如何nft
在单个原子操作中丢弃当前规则集,同时添加新规则集?
答案1
操作完成nft -f /path/to/new/rules
是原子:这意味着它要么完全完成,要么根本没有完成(即:恢复),并且只有在提交后才会立即影响下一个符合规则的数据包。它不会结束(因为错误),只是完成了一半。因此,如果您之前没有删除以前的规则集,它的行为将按预期进行:它会自动添加规则再一次,如注释中所述原子规则替换在维基百科中:
重复规则:如果您在行
flush table filter
的最开头添加该行过滤表文件中,您可以实现与 iptables-restore 提供的等效的原子规则集替换。内核在一个事务中处理文件中的规则命令,因此基本上新规则的刷新和加载一次性发生。如果您选择不刷新表,那么每次重新加载配置时您都会看到重复的规则。
为此,您必须在同一笔交易中删除再次添加规则集之前先删除旧规则。最简单的(但影响所有nftables, 包括iptables-nft如果也使用),与上面描述的类似,只是在规则集前面添加/path/to/new/rules
:
flush ruleset
如果您在不同时间加载不同的表以保持逻辑功能分离(在nftables,一个表可以包含任何类型的基本链(对于给定的族),它不是直接等价于中的表iptables它有一组固定的可能链)它变得有点复杂,因为flush ruleset
在一个规则文件中会删除其他表(包括iptables-nft规则如果一起使用nftables)。那么这应该在表级别完成,例如(但在执行之前请进一步阅读):
delete table inet foo
接下来是对其的重新定义(table inet foo {
...)。按原样,这会产生另一个先有鸡还是先有蛋的问题:第一次读取该文件时(例如在启动时),删除操作将失败,因此所有内容都会自动失败,因为该表不存在。由于声明一个已经声明的表的名称被认为是无操作,因此不会失败,最终可以这样做:
table inet foo
delete table inet foo
table inet foo {
[...]
注1:为了在所有情况下都能正常工作需要内核 >= 3.18,否则最好坚持下去
flush ruleset
。注 2:上面的 wiki 注释建议在这种情况下使用
flush table inet foo
,但这可能应该避免,因为如果存在集合,则这不会删除集合中的元素,如果元素是由规则集添加并在其中更改的,则再次导致添加而不是替换元素。它也不允许重新定义基础链的类型/钩子。使用table inet foo
+delete table inet foo
就没有这些缺点。当然,如果在重新加载规则时需要将元素保留在集合中,则可能会考虑使用flush table inet foo
并适应这种方法的局限性。
在所有情况下,在使用将当前规则转储到规则文件时都应该小心nft list {ruleset, table inet foo, ...} > /path/to/new/rules
:它不会包含任何刷新或删除命令,并且您必须手动将它们添加回来。你也许可以使用include
通过将“管道工”声明置于实际规则之外来克服这个问题。