登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

nftables 动态集合怎样让临时封禁规则自动过期怎样完成一个可复用的最小示例

来源:17golang原创

时间:2026-11-10 05:56:18 261浏览 收藏

做临时封禁时,最省心的做法不是不断创建和删除整条规则,而是让一条规则固定引用一个 named set,再给 set 中的每个 IPv4 地址设置独立的 timeout。倒计时结束后,元素会从集合中自动移除,规则也就不再匹配它。需要注意的是:集合的 timeout 能力、元素的 timeout 值和动态更新方式是三件事,不能混为一谈。

官方资料:https://wiki.nftables.org/wiki-nftables/index.php/Sets

下面的示例只聚焦一个边界清楚的任务:把 203.0.113.10 临时加入封禁集合 60 秒,把 203.0.113.11 临时加入 5 分钟,并能通过 nft list set 看到剩余时间。

一、先分清动态集合、timeout 和 expires

nftables 的 named set 是可以被规则引用、也可以被后续命令更新的集合。集合声明为 flags timeout 后,集合元素才可以携带过期时间;如果还要在数据包路径中自动添加元素,则通常再声明 flags dynamic。常见的临时封禁场景由管理命令添加元素,因此不一定必须使用 dynamic,但要保留 timeout 能力。

timeout 表示元素可以存活多久;expires 是查看集合时显示的剩余倒计时。前者是设置,后者是状态。元素倒计时归零后会被垃圾回收,后续匹配自然失效。

nftables 动态集合元素从加入到 timeout 过期自动移除的静态生命周期说明图
图1:nftables 元素 timeout 的生命周期说明图,不是运行截图。

二、创建一条固定引用集合的封禁规则

先创建 inet 表、input 链和名为 temp_ban 的 IPv4 地址集合。为了让配置可以反复加载,示例把声明写成 nftables 配置文件格式;注释解释每个关键选项的目的。

table inet temporary_ban {
    # IPv4 地址作为集合键,timeout 允许元素携带过期时间。
    set temp_ban {
        type ipv4_addr
        flags timeout
    }

    chain input {
        type filter hook input priority filter; policy accept;

        # 只要来源地址在集合中,就执行临时封禁动作。
        ip saddr @temp_ban drop
    }
}

这里把默认策略保留为 accept,只让集合中的来源地址走 drop。这比把整条 input 链改成拒绝更容易控制影响范围;如果主机本身已有生产规则,应把集合和引用规则放进现有规则结构,而不是直接覆盖整套规则。

三、给每个封禁地址设置独立 timeout

集合声明好以后,可以使用 add element 为每个地址指定自己的时间。地址、超时时间和封禁理由可以由上层脚本决定,但 nftables 只负责保存元素、匹配集合并在到期时清理。

# 写入两条不同期限的临时封禁元素。
nft add element inet temporary_ban temp_ban {
    203.0.113.10 timeout 60s,
    203.0.113.11 timeout 5m
}

# 按集合查看元素及其剩余 expires 倒计时。
nft list set inet temporary_ban temp_ban

这组地址使用了文档示例保留的 TEST-NET-3 网段,仅用于说明配置形状。实际使用时应替换成经过授权的来源地址,并在变更前确认不会把管理入口一起封掉。

nftables input 链引用 temp_ban 集合并作出 drop 决策的静态关系说明图
图2:规则引用动态集合并作出丢弃决策的关系说明图,不是运行截图。

四、怎样读取剩余时间并判断是否已经过期

执行 nft list set 时,带超时的元素通常会同时显示 timeout 和 expires。可以把它理解为“原始倒计时”和“当前剩余量”:原始的 timeout 5m 决定元素初始寿命,expires 随时间减少。

# 只读取指定集合,减少排查时的输出范围。
nft list set inet temporary_ban temp_ban

# 需要移除仍在有效期内的地址时,显式删除该集合元素。
nft delete element inet temporary_ban temp_ban { 203.0.113.10 }

如果查询时看不到某个地址,可能是它已经过期,也可能是它从未成功加入集合。应先确认表名、集合名和地址类型一致,再决定是否重新添加;不要因为看不到元素就无条件创建第二套规则。

五、add 和 update 有什么区别

管理脚本用 add element 做一次性封禁时,语义通常是“加入后倒计时”。而在数据包路径里用 update,可以在元素再次被匹配时刷新其剩余时间,适合“只要持续出现就继续观察”的动态黑名单或限速器。两者的选择会直接改变封禁窗口。

写法适合场景时间行为
add element人工或脚本发起一次临时封禁按本次写入的 timeout 倒计时
update @集合按数据包持续更新的动态规则再次命中时可刷新元素 timeout
delete element提前解除封禁立即移除元素,不等待自然过期

如果只是“封禁 60 秒”,不要把 update 误加到每个入站包的路径上,否则攻击源持续发包时,60 秒可能不断从当前时刻重新计算。需要滑动窗口时才选择刷新语义,并为集合设置合理的容量和清理策略。

六、把最小示例放进持久化配置时要留意什么

运行时用命令添加的元素是否能在重启后保留,取决于你的发行版如何加载 nftables 配置,以及你是否把集合声明和元素写入持久化配置。临时封禁通常不应在重启后永久恢复;如果业务需要恢复,则应由受控的启动脚本或配置管理流程重新注入,而不是把所有动态地址硬编码进静态规则文件。

同时要区分“规则已加载”和“元素仍在集合中”:前者可以通过列出规则集确认,后者要看指定集合的元素及 expires。排查时先读集合,再判断封禁规则,能避免把“倒计时已结束”误判成“规则加载失败”。

总结

临时封禁的核心是一个命名的 IPv4 地址集合、一条引用该集合的匹配规则,以及每个元素自己的 timeout。集合声明 flags timeout,写入时使用 timeout 60s 或 timeout 5m,查询时使用 nft list set 观察 expires。到期后元素自动移除,固定规则无需反复增删。

常见问题

集合有 timeout,为什么新增元素还提示不支持?

检查集合是否真的声明了 timeout 能力,以及当前 nft 命令使用的表族、表名和集合名是否一致。不要把普通 set 的元素语法直接套到另一个集合上。

expires 会不会把 timeout 配置永久改掉?

不会。expires 是当前剩余倒计时;重新创建元素或按规则更新时,才会根据写入语义重新计算时间。

怎样让每次命中都延长封禁?

需要在数据包路径中使用支持 timeout 的动态集合和 update 语义,但这代表滑动窗口,不再是固定 60 秒的一次性封禁。

为什么重启后临时封禁消失了?

运行时集合元素通常属于当前内核规则状态。若业务需要恢复,必须把恢复动作纳入受控的启动或配置管理流程,并重新评估是否应该恢复旧封禁。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>