Nftables管理问题

Rim*_*das 4 nftables

我已经从 iptables 迁移到 nftables,但遇到了一个恼人的问题。在旧系统中,我有一个脚本每天删除/添加一些规则。我能够根据 iptables 规则的位置轻松添加/删除它们,这是恒定的。

现在我们有了烦人的手柄。当我从脚本添加规则时,它会通过动态句柄编号进行分配。我可以首先通过检索该句柄号来删除规则。问题是当相同的规则被删除并重新添加时。之后,它的句柄号会增加,所以不一样。因此,我无法使用与旧系统中相同的简单方法。

任何人都可以给我一个解决方案来解决这个问题 - 链中至少有 40 条规则,我想删除相同的规则,每天重新添加几条规则。使用 iptables 是如此简单,但现在我找不到简单的解决方案

谢谢。

A.B*_*A.B 5

OP 使用这种规则,这就是我将用作示例的布局,以作为答案的基础:

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
Run Code Online (Sandbox Code Playgroud)

...等等...

使用一套

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) 。现在最好坚持在命令上使用它,只需添加规则。