我会做什么

我会做什么

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

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

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

谢谢。

答案1

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

...等等...

使用一套

nftables特征,类似于IP集iptables 的伴侣,但更通用。

因此可以因式分解纳特将规则合并为一个规则,然后仅操作关联的集合,而不再触及该规则。对集合元素的操作(包括删除)不需要任何句柄,因为与规则相反,它的内容顺序是无关的,因此可以使用哈希列表在内核内存中有效地搜索和重新排序。

如果独立计数纳特流(即:保持 的角色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
    }
}

可以使用一组可以稍后填充的集合(或者也可以直接填充):

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
    }
}

然后可以在 06:00 在 crontab 中填充该集合(遵循前面的示例):

nft 'add element ip nat curfewlist { 172.17.1.2, 172.17.1.3 }'

到了23:00,就可以逐个删除了:

nft 'delete element ip nat curfewlist { 172.17.1.2 }'
nft 'delete element ip nat curfewlist { 172.17.1.3 }'

或一次多个元素:

nft 'delete element ip nat curfewlist { 172.17.1.2, 172.17.1.3 }'

或者简单地冲洗:

nft flush set ip nat curfewlist

注意:a 的范围(也称为名称空间)位于其表内:集合不能从其他表引用,但与iptables桌子不限于一种挂钩类型。一个可以和可能应该同一个表中有多种类型的链,允许重复使用相同的集合,例如在筛选规则并在纳特规则,而不是模仿iptables' 每个表限制一种钩子类型。

使用meta hour比赛

对于内核 >= 5.5,甚至不需要再更改任何内容,只需使用meta hour可以在数据包路径中进行检查。单人纳特规则可以替换为:

meta hour 06:00-23:00 oifname $inet_if ip saddr @curfewlist snat to $inet_if_ip

并且这个集合永远填满了。每年只有两次,在夏令时更改期间,应该重新加载规则集,因为内核始终使用 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
    }
}

注意:存储在内核内存中的小时间隔采用 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 { }
}

在 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
    }
}

在 23:00 只需运行以下命令:

nft flush chain ip nat curfew

还有其他方法仍然可以使用手柄吗?

这需要以一种或另一种方式使用脚本,而不仅仅是NFFT

稍后尝试识别规则需要转储全部链的规则(即:将它们从内核转移到用户态)。这是什么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

因此,使用合理的过滤器再次运行(通过了解此特定规则集部分中添加的内容可以更轻松):

# nft --echo --handle -f curfew.nft | sed -n 's/^add rule.*# handle \(.*\)$/\1/p' | tee curfew-handles.txt
6
7

人们可以手动附加一条附加规则并存储其句柄:

# 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

然后删除列表中句柄的所有规则:

# for i in $(cat curfew-handles.txt); do printf 'delete rule ip nat curfew handle %d\n' $i; done | nft -f - && : > curfew-handles.txt

更新: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

nft monitor或者同时使用,同时沿着规则提供链信息,在这种情况下更有用:

nft --json monitor | 
    grep --line-buffered -v '^#' |
    jq -j '
        .add.rule |
            if . != null then
                (.handle, " ", .family, " ", .table, " ", .chain, "\n")
            else
                empty
            end'

执行上面的前一个规则命令时的结果:

40 ip nat curfew

警告:

  • 某些 nftables 版本中的错误

    目前(v0.9.8),--echo --handle在某些完整的规则集上使用可能会导致nft发出警告(当之前的规则集为空时)甚至崩溃(例如:似乎counter集合中最近引入的关键字会导致此类命令或正在运行的命令崩溃nft --handle monitor)。目前最好坚持在仅添加规则的命令上使用它。

答案2

这可以工作:

handle=$(nft list ruleset -a | grep "$your_rule" | grep "#" | awk '{print $NF}')
test -n "$handle" && nft delete rule filter output handle "$handle"
nft insert rule filter output position XX ...

答案3

我会做什么

是一个自定义表格,并且每次都更换它。如果通过一次调用即可完成表更新,那么表更新是原子的nft

因此,更改我的程序中的规则,重新生成表,调用nft.

答案4

元素超时可能会提供您需要的解决方案。您可以将地址或端口放在一个集合中,到期后它们将自动从该集合中删除。

超时可以以小时、分钟、秒或组合形式指定,例如 2 小时 10 分 5 秒。

引用 nftables wiki 中的示例:

% nft add table inet myfilter
% nft add set inet myfilter myset {type ipv4_addr\; flags timeout\; }
% nft add element inet myfilter myset {10.0.0.1 timeout 10s }

结果:

% nft list ruleset
table inet myfilter {
    set myset {
        type ipv4_addr
        flags timeout
        elements = { 10.0.0.1 timeout 10s expires 8s}
    }
}

来源:https://wiki.nftables.org/wiki-nftables/index.php/Element_timeouts

相关内容