我已经从 iptables 迁移到 nftables,但遇到了一个恼人的问题。在旧系统中,我有一个脚本每天删除/添加一些规则。我能够根据 iptables 规则的位置轻松添加/删除它们,这是恒定的。
现在我们有了烦人的手柄。当我从脚本添加规则时,它会通过动态句柄编号进行分配。我可以首先通过检索该句柄号来删除规则。问题是当相同的规则被删除并重新添加时。之后,它的句柄号会增加,所以不一样。因此,我无法使用与旧系统中相同的简单方法。
任何人都可以给我一个解决方案来解决这个问题 - 链中至少有 40 条规则,我想删除相同的规则,每天重新添加几条规则。使用 iptables 是如此简单,但现在我找不到简单的解决方案
谢谢。
OP 使用这种规则,这就是我将用作示例的布局,以作为答案的基础:
Run Code Online (Sandbox Code Playgroud)add rule ip nat postrouting oifname $inet_if ip saddr 172.xx.xx.xx counter snat to $inet_if_ip add rule ip nat postrouting oifname $inet_if ip saddr 172.xx.xx.xx counter snat to $inet_if_ip
...等等...
nftables功能集,类似于iptables 的ipset伴侣,但更通用。
因此,可以将nat规则分解为一个规则,然后仅操作关联的集合,而不再触及该规则。对集合元素的操作(包括删除)不需要任何句柄,因为与规则相反,它的内容顺序是无关的,因此可以使用哈希列表在内核内存中有效地搜索和重新排序。
如果计算独立的nat流量(即:保持 的角色counter
很重要,这需要最新的工具(至少 >= 0.9.1 但建议 nftables >= 0.9.4,请参阅我对此的回答,但也请参阅“错误”)在这个答案的末尾)。nftables仍在不断发展,因此某些功能取决于nftables或内核的版本。
此答案中使用了nftables 0.9.6 0.9.8。这可能会影响某些语法和功能(例如 JSON)。
因此,而不是这种规则集:
define inet_if = eth0
define inet_if_ip = 192.0.2.2
table ip nat # for idempotency
delete table ip nat # for idempotency
table ip nat {
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname $inet_if ip saddr 172.17.1.2 counter snat to $inet_if_ip
oifname $inet_if ip saddr 172.17.1.3 counter snat to $inet_if_ip
}
}
Run Code Online (Sandbox Code Playgroud)
可以使用一组可以稍后填充的集合(或者也可以直接填充):
define inet_if = eth0
define inet_if_ip = 192.0.2.2
table ip nat
delete table ip nat
table ip nat {
set curfewlist {
type ipv4_addr
counter # optional
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname $inet_if ip saddr @curfewlist snat to $inet_if_ip
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以在 06:00 在 crontab 中填充该集合(遵循前面的示例):
nft 'add element ip nat curfewlist { 172.17.1.2, 172.17.1.3 }'
Run Code Online (Sandbox Code Playgroud)
到了23:00,就可以逐个删除了:
nft 'delete element ip nat curfewlist { 172.17.1.2 }'
nft 'delete element ip nat curfewlist { 172.17.1.3 }'
Run Code Online (Sandbox Code Playgroud)
或一次多个元素:
nft 'delete element ip nat curfewlist { 172.17.1.2, 172.17.1.3 }'
Run Code Online (Sandbox Code Playgroud)
或者简单地冲洗:
nft flush set ip nat curfewlist
Run Code Online (Sandbox Code Playgroud)
注意:集合的范围(也称为命名空间)位于其表内:集合不能从其他表引用,但与iptables相反,表不限于一种钩子类型。在同一个表中可以而且可能应该有多种类型的链,允许在过滤规则和nat规则中重用同一组链,而不是模仿iptables每个表只有一种钩子类型的限制。
meta hour
比赛对于内核 >= 5.5,甚至不需要再更改任何内容,使用它meta hour
可以在数据包路径中进行检查。单个nat规则可以替换为:
meta hour 06:00-23:00 oifname $inet_if ip saddr @curfewlist snat to $inet_if_ip
Run Code Online (Sandbox Code Playgroud)
并且这个集合永远填满了。每年只有两次,在夏令时更改期间,应该重新加载规则集,因为内核始终使用 UTC 时间。完整的规则集是:
define inet_if = eth0
define inet_if_ip = 192.0.2.2
table ip nat
delete table ip nat
table ip nat {
set curfewlist {
type ipv4_addr
counter
elements = { 172.17.1.2, 172.17.1.3 }
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
meta hour 06:00-23:00 oifname $inet_if ip saddr @curfewlist snat to $inet_if_ip
}
}
Run Code Online (Sandbox Code Playgroud)
注意:存储在内核内存中的小时间隔采用 UTC 时区,并且始终以 24 小时为模的单个连续间隔。根据当地时区,小时表达式可能会以不同的方式读回,例如!= "23:00"-"06:00"
,其含义与 相同"06:00"-"23:00"
。
虽然我认为上面简化了结果,但下面我将介绍如何解决或仍然尝试以其他方式使用句柄。
如果上述方法不足以满足用例,您仍然可以移动用户链中的所有逻辑规则,并在链级别而不是规则级别执行操作。这在这里给出:
define inet_if = eth0
table ip nat
delete table ip nat
table ip nat {
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname $inet_if jump curfew
}
chain curfew { }
}
Run Code Online (Sandbox Code Playgroud)
在 06:00 将加载以下规则集部分(例如nft -f curfew.nft
:):
define inet_if_ip = 192.0.2.2
flush chain ip nat curfew #for idempotency
table ip nat {
chain curfew {
ip saddr 172.17.1.2 counter snat to $inet_if_ip
ip saddr 172.17.1.3 counter snat to $inet_if_ip
}
}
Run Code Online (Sandbox Code Playgroud)
在 23:00 只需运行以下命令:
nft flush chain ip nat curfew
Run Code Online (Sandbox Code Playgroud)
这需要以某种方式使用脚本,而不仅仅是nft。
稍后尝试识别规则需要转储所有链的规则(即:将它们从内核传输到用户态)。这正是nftables的开发者从一开始就极力避免的。
如果您计划添加稍后可能在给定用例中删除的规则,请在添加它们时存储它们的句柄,这样以后就不需要查找句柄了。
使用--echo
该--handle
选项将自动显示刚刚添加的内容,包括句柄(单独运行nft --handle monitor
也可以)。使用先前的curfew.nft
文件将给出(句柄在每次调用时发生变化):
# nft --echo --handle -f curfew.nft
add chain ip nat curfew # handle 2
add rule ip nat curfew ip saddr 172.17.1.2 counter packets 0 bytes 0 snat to 192.0.2.2 # handle 4
add rule ip nat curfew ip saddr 172.17.1.3 counter packets 0 bytes 0 snat to 192.0.2.2 # handle 5
Run Code Online (Sandbox Code Playgroud)
因此,使用合理的过滤器再次运行(通过了解此特定规则集部分中添加的内容可以更轻松):
# nft --echo --handle -f curfew.nft | sed -n 's/^add rule.*# handle \(.*\)$/\1/p' | tee curfew-handles.txt
6
7
Run Code Online (Sandbox Code Playgroud)
人们可以手动附加一条附加规则并存储其句柄:
# nft --echo --handle add rule ip nat curfew ip saddr 172.17.1.4 snat to 192.0.2.2 | sed -n 's/^add rule.*# handle \(.*\)$/\1/p' | tee -a curfew-handles.txt
8
Run Code Online (Sandbox Code Playgroud)
然后删除列表中句柄的所有规则:
# for i in $(cat curfew-handles.txt); do printf 'delete rule ip nat curfew handle %d\n' $i; done | nft -f - && : > curfew-handles.txt
Run Code Online (Sandbox Code Playgroud)
更新: nftables >= 0.9.8 提供更好的 JSON 支持
nftables支持JSON 输出,但需要版本 0.9.8:nft --echo --handle --json add rule ...
在版本 0.9.6 上不回显任何内容,但在 0.9.8 上正常工作(并在此处使用内核 5.10.x 进行测试)。
使用 检索刚刚添加的规则的句柄的示例jq
。附加输出注释行本身不是 JSON 输出,因此必须被过滤掉:
# nft --echo --json add rule ip nat curfew ip saddr 172.17.1.4 snat to 192.0.2.2 |
grep -v '^#' |
jq '.nftables[].add.rule.handle'
40
Run Code Online (Sandbox Code Playgroud)
或者nft monitor
同时使用,同时沿着规则提供链信息,在这种情况下更有用:
nft --json monitor |
grep --line-buffered -v '^#' |
jq -j '
.add.rule |
if . != null then
(.handle, " ", .family, " ", .table, " ", .chain, "\n")
else
empty
end'
Run Code Online (Sandbox Code Playgroud)
执行上面的前一个规则命令时的结果:
40 ip nat curfew
Run Code Online (Sandbox Code Playgroud)
警告:
某些 nftables 版本中的错误
目前(v0.9.8),--echo --handle
在一些完整的规则集上使用可能会导致nft
发出警告(当之前的规则集为空时)甚至崩溃(例如:看起来最近counter
在集合中引入的关键字将使此类命令或正在运行的命令崩溃nft --handle monitor
) 。现在最好坚持在命令上使用它,只需添加规则。
归档时间: |
|
查看次数: |
1478 次 |
最近记录: |