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 是查看集合时显示的剩余倒计时。前者是设置,后者是状态。元素倒计时归零后会被垃圾回收,后续匹配自然失效。

二、创建一条固定引用集合的封禁规则
先创建 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 网段,仅用于说明配置形状。实际使用时应替换成经过授权的来源地址,并在变更前确认不会把管理入口一起封掉。

四、怎样读取剩余时间并判断是否已经过期
执行 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 秒的一次性封禁。
为什么重启后临时封禁消失了?
运行时集合元素通常属于当前内核规则状态。若业务需要恢复,必须把恢复动作纳入受控的启动或配置管理流程,并重新评估是否应该恢复旧封禁。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
162 收藏
-
181 收藏
-
361 收藏
-
140 收藏
-
256 收藏
-
文章 · linux | 39分钟前 | Linux · systemd-journald RateLimitIntervalSec RateLimitBurst LogRateLimitBurst Linux 日志限流477 收藏
-
171 收藏
-
130 收藏
-
208 收藏
-
367 收藏
-
226 收藏
-
294 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习