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

Linux nftables 动态集合怎么设置元素过期时间

来源:17golang原创

时间:2026-10-04 19:56:25 470浏览 收藏

Linux nftables 动态集合设置元素过期时间,最小答案是:在命名集合中启用 dynamic 和 timeout 标志,再用集合级 timeout 给元素设置默认寿命。某个地址需要不同寿命时,在添加元素时附加自己的 timeout;如果希望地址每次再次命中都重新开始倒计时,则在规则里使用 update。

先记住三个结论
  • 集合级 timeout 10m 是默认值,元素级 timeout 2m 可以覆盖它。
  • expires 是当前剩余寿命,适合观察和复制状态,不是平时设置默认值的入口。
  • gc-interval 决定回收扫描节奏,不会延长元素的逻辑有效期。

主要文档:https://netfilter.org/projects/nftables/manpage.html;集合参考:https://wiki.nftables.org/wiki-nftables/index.php/Sets。

先做一个带 10 分钟默认寿命的动态集合

下面用独立的 inet demo_guard 表演示。输入链保持 policy accept,只丢弃已经明确放进集合的文档示例地址,避免把“怎样设置过期时间”混成一套激进的主机防火墙。生产机器上不要直接照搬表名覆盖现有配置,应把 set 和引用规则合并到自己的规则文件。

# 这是独立演示规则;生产环境请合并到现有规则集。
table inet demo_guard {
    set temp_block_v4 {
        type ipv4_addr
        flags dynamic, timeout
        timeout 10m        # 未单独指定时,元素默认存活 10 分钟。
        gc-interval 30s    # 每 30 秒安排一次过期元素回收扫描。
        size 65536         # 限制集合容量,避免动态增长失去边界。
    }

    chain input {
        type filter hook input priority filter; policy accept;
        # 只匹配已经进入临时封禁集合的源地址。
        ip saddr @temp_block_v4 counter drop
    }
}

这里缺一项都可能让行为和预期不同:dynamic 允许从数据包路径动态更新集合;timeout 允许元素自动到期;集合级 timeout 10m 给没有单独声明寿命的元素提供默认值;size 给动态集合一个明确上限。官方手册还特别说明,从数据包路径向集合添加元素时应定义最大容量,添加动作也需要有超时边界。

先把规则保存为 /etc/nftables.d/demo-guard.nft,然后分两步检查和加载:

# 只检查规则文件语法与可解析性,不修改当前规则集。
sudo nft -c -f /etc/nftables.d/demo-guard.nft

# 确认仍有控制台或带外访问后,再加载这份独立演示规则。
sudo nft -f /etc/nftables.d/demo-guard.nft

# 查看集合定义,确认 flags、timeout、gc-interval 和 size 已生效。
sudo nft list set inet demo_guard temp_block_v4

如果主机正在远程维护,加载任何网络规则前都要保存当前规则集并预留恢复通道。本文示例使用文档专用地址段 192.0.2.0/24、198.51.100.0/24 和 203.0.113.0/24,不会把真实公网地址写进教程。

nftables 动态集合的类型、标志、默认超时、回收间隔、容量与元素寿命静态关系图
图1:动态集合的五个核心属性各管一件事;元素从默认 timeout 获得寿命,也可以在写入时覆盖该值。这是静态关系图。

给单个元素覆盖默认 timeout

集合默认是 10 分钟,并不妨碍某个元素只保留 2 分钟,另一个元素保留 1 小时。元素级 timeout 优先于集合默认值:

# 使用集合默认值,这个元素默认存活 10 分钟。
sudo nft add element inet demo_guard temp_block_v4 '{ 192.0.2.10 }'

# 覆盖默认值,这个元素只存活 2 分钟。
sudo nft add element inet demo_guard temp_block_v4 '{ 198.51.100.8 timeout 2m }'

# 为另一个元素指定 1 小时寿命。
sudo nft add element inet demo_guard temp_block_v4 '{ 203.0.113.20 timeout 1h }'

# 查看当前元素及其剩余 expires 时间。
sudo nft list set inet demo_guard temp_block_v4

输出中的 timeout 表示该元素被赋予的寿命,expires 表示此刻还剩多少时间。随着时间流逝,expires 会减少。手册把 expires 定义为剩余到期时间,它更适合做规则集状态复制或运维观察;日常配置元素寿命时仍应使用 timeout。

需要提前移除元素时,不必等待超时:

# 提前删除一个临时封禁元素,不影响集合中的其他地址。
sudo nft delete element inet demo_guard temp_block_v4 '{ 198.51.100.8 }'

# 再次列出集合,确认目标元素已经移除。
sudo nft list set inet demo_guard temp_block_v4

add 和 update 的差别在于是否刷新寿命

动态集合最常见的需求不是“固定两分钟后删除”,而是“只要一分钟内持续出现新连接,就继续把该地址视为活跃”。这时应使用 update。它会在元素已存在时刷新超时;add 更适合首次插入,不应拿它代替滑动窗口。

为了避免示例直接改变放行策略,下面创建一个只记录最近 SSH SYN 来源的观察集合。它不会丢弃流量:

# 这张表只演示动态观察,不包含 drop 或 reject 动作。
table inet demo_observe {
    set recent_ssh_v4 {
        type ipv4_addr
        flags dynamic, timeout
        timeout 1m         # 默认观察窗口是一分钟。
        gc-interval 15s    # 较短回收周期便于及时释放容量。
        size 32768         # 数据包路径更新必须有明确容量边界。
    }

    chain input {
        type filter hook input priority filter; policy accept;
        # 每次收到 SSH SYN 都写入或刷新源地址的一分钟寿命。
        tcp flags syn tcp dport 22 update @recent_ssh_v4 { ip saddr timeout 1m } counter
    }
}

同一个源地址在 40 秒后再次发送 SYN,update 会让它重新获得一分钟寿命;如果随后完全不再命中,它才会到期。这个行为就是滑动窗口。若改成 add,应把它理解为“缺少时加入”,而不是“每次访问都续期”。

观察效果时可以间隔几秒执行:

# 列出观察集合,关注每个元素不断变化的 expires 值。
sudo nft list set inet demo_observe recent_ssh_v4

# 以监视模式观察 nftables 对象变化;结束时按 Ctrl+C。
sudo nft monitor

将观察集合进一步用于限速、隔离或封禁属于另一个策略层问题。更稳妥的做法是先确认采集条件不会把堡垒机、反向代理或 NAT 出口误认为单一恶意来源,再增加动作规则。

gc-interval 不等于 timeout

timeout 决定元素何时不再有效,gc-interval 决定内核多久安排一次垃圾回收。两者是逻辑到期和资源回收两个阶段,不能互相替代。

例如元素寿命为 60 秒、回收间隔为 30 秒。元素在第 60 秒到期后不应再作为有效匹配项,但它占用的内部槽位可能要等到后续垃圾回收才彻底释放。官方手册提醒:已经超时但尚未被回收的元素仍可能计入集合大小。若 gc-interval 设得过大,而 size 又很小,高 churn 场景就可能暂时没有空间接收新元素。

nftables 元素从有效倒计时、逻辑到期到垃圾回收释放容量的静态状态关系图
图2:timeout 决定逻辑有效期,gc-interval 决定到期对象何时被扫描回收;两者共同影响高频动态集合的容量表现。这是静态状态图。

参数选择没有一组适合所有机器的固定答案,可以从业务窗口反推:

  • 短暂去重或近期来源观察:timeout 常常只需几十秒到几分钟,回收间隔也可以较短。
  • 临时阻断:寿命通常更长,但必须保留人工删除入口,不能只依赖自然到期。
  • 来源数量波动很大:优先估算峰值唯一地址数,再给 size 留余量,并监控集合是否接近上限。
  • CPU 更敏感:不要为了“立即清理”把回收周期压得过短,应在回收及时性与扫描开销之间折中。

把静态地址和临时地址分开更好维护

实践中我更倾向于把长期策略与自动过期状态放在两个集合。长期拒绝名单不设置超时,临时集合启用 timeout;规则可以同时引用两者。这样审计时一眼就能分清“管理员明确配置”与“运行中动态产生”,备份和恢复也更简单。

# 长期集合不声明 timeout,内容由配置管理维护。
set permanent_block_v4 {
    type ipv4_addr
    elements = { 192.0.2.10 }
}

# 临时集合启用自动过期,内容可以由受控自动化写入。
set temporary_block_v4 {
    type ipv4_addr
    flags dynamic, timeout
    timeout 15m        # 临时元素默认保留 15 分钟。
    gc-interval 30s    # 定期释放已到期元素占用的容量。
    size 65536         # 限制最坏情况下的元素数量。
}

不要把 nftables set 的元素超时与 conntrack 超时混为一谈。前者管理集合成员,后者管理连接跟踪状态;即使源地址从 set 中到期,既有连接是否继续、后续数据包如何处理,仍取决于完整规则顺序和连接状态匹配。

上线前的安全检查与回退

防火墙调整最危险的不是语法错误,而是语法正确却把管理入口一起挡掉。尤其通过 SSH 操作远程主机时,应保留控制台或带外访问,并保存当前规则:

# 保存当前完整规则集,文件权限应只允许管理员读取。
sudo nft list ruleset > /root/nftables-before-timeout.nft

# 检查待加载文件;通过后仍要人工确认表名、链优先级和策略。
sudo nft -c -f /etc/nftables.d/demo-guard.nft

# 如果新规则造成异常,可从已保存文件恢复原规则集。
sudo nft -f /root/nftables-before-timeout.nft

如果系统由发行版服务、配置管理平台、容器编排器或防火墙前端维护,不要绕开它直接写临时命令。应把 set 定义放进权威配置源,并确认重启后规则仍会恢复。直接命令适合实验和排查,不等于持久化。

常见问题对照

现象优先检查处理方向
元素一直不消失集合是否声明 timeout 标志,元素是否实际带有寿命补齐 flags 与默认 timeout,重新添加元素
重复命中却没有续期规则使用的是 add 还是 update滑动窗口使用 update,并显式给出 timeout
集合看似到期却仍很快满size 是否过小,gc-interval 是否过长估算峰值唯一元素数,并调整回收节奏
命令重启后失效是否只执行了即时 nft 命令写入系统实际加载的持久规则文件
远程加载后连接中断链策略、规则顺序、管理地址是否被加入集合通过控制台恢复备份,并缩小测试范围

最终配置清单

  1. 命名集合包含正确的 type。
  2. 动态写入场景启用 flags dynamic, timeout。
  3. 集合级 timeout 提供合理默认寿命。
  4. 特殊元素在写入时用自己的 timeout 覆盖默认值。
  5. 需要滑动窗口时使用 update 刷新寿命。
  6. 根据峰值元素数设置 size,并用 gc-interval 平衡回收及时性。
  7. 上线前检查规则文件、保存现有规则,并准备带外恢复路径。

小结:nftables 动态集合的元素过期并不是单个参数问题,而是四个职责清晰的部件:timeout 管寿命,update 管续期,gc-interval 管回收节奏,size 管容量边界。把它们分开理解后,无论是临时封禁、近期来源观察还是短时去重,都能得到可预测、可恢复的配置。

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