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

Linux nftables set 怎样按集合管理访问规则

来源:17golang原创

时间:2026-11-02 14:01:51 365浏览 收藏

Linux nftables 里,set 适合把一批同类型的地址、端口或接口名集中起来,再让一条规则引用这批成员。真正需要长期维护访问名单时,应使用 named set;只在某一条规则中做一次匹配时,匿名集合就够了。这样新增或删除地址时只改集合,不必重复改写所有规则。

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

最实用的落地路径是:先声明集合类型,再用 @集合名 接入规则,之后通过 add element、delete element 和 list set 维护成员。临时封禁再加 timeout,网段集合则考虑 interval 与 auto-merge。

先分清匿名集合和 named set

nftables 的集合本质上是同一数据类型的一组元素。匿名集合直接写在规则里,例如端口集合:

# 一次性匹配 SSH 和 HTTPS;集合跟随这条规则存在。
nft add rule inet filter input tcp dport { 22, 443 } accept

这种写法短而直接,但它没有独立名字,后续不能像资源清单一样单独增删成员。如果名单会被多条规则共享,或需要由脚本定期更新,就应该创建 named set。官方文档也明确区分了两者:匿名集合绑定在规则上,named set 则可以单独更新。

nftables 匿名集合与命名集合在规则绑定和独立更新上的边界说明图
图1:匿名集合与 named set 的职责边界说明图,展示规则绑定、集合类型和独立更新关系;这是静态说明图,不是终端截图。

创建地址集合并接入访问规则

下面的例子用 inet 表族创建一个 IPv4 地址集合。集合的 type 必须和成员类型一致,规则中的 ip saddr 也要与它相匹配。

# 创建表和输入链;重复执行前请先确认名称没有冲突。
nft add table inet edge_filter
nft 'add chain inet edge_filter input { type filter hook input priority 0; policy drop; }'

# 声明一个可独立维护的 IPv4 地址集合。
nft 'add set inet edge_filter trusted_v4 { type ipv4_addr; }'

# 把可信来源加入集合,再让规则引用集合。
nft 'add element inet edge_filter trusted_v4 { 192.0.2.10, 198.51.100.0/24 }'
nft 'add rule inet edge_filter input ip saddr @trusted_v4 tcp dport 22 accept'

这里的重点不是把地址写进规则,而是让规则只依赖集合名。后续名单变化时,规则仍然保留。生产环境中应按自己的默认策略补齐 established/related、回环和管理入口等规则,避免把这个示例直接当成完整防火墙策略。

只修改成员,不重写规则

named set 的价值在于成员生命周期独立于规则。管理员可以把一批地址一次性加入,也可以删除单个成员;集合引用关系不需要变化。

# 批量加入新的可信地址;花括号内的元素必须符合 ipv4_addr 类型。
nft 'add element inet edge_filter trusted_v4 { 192.0.2.11, 203.0.113.7 }'

# 删除不再信任的单个地址;删除成员不会删除引用它的规则。
nft 'delete element inet edge_filter trusted_v4 { 203.0.113.7 }'

# 查看集合的完整成员和声明,便于记录变更前后的状态。
nft list set inet edge_filter trusted_v4

# 查询一个地址是否存在;大集合或区间集合更适合用 get 判断。
nft 'get element inet edge_filter trusted_v4 { 192.0.2.11 }'

如果 add element 报类型错误,先检查集合声明而不是盲目改地址格式。比如把 IPv6 地址加入 ipv4_addr 集合,属于模型不匹配;应新建 ipv6_addr 集合,或在规则和表族设计中明确双栈边界。

nftables named set 从成员变更到规则匹配的静态关系图
图2:named set 的成员管理与规则匹配关系图,展示 add、delete、list、get 和 @集合名之间的静态关系;这是结构图,不是实际运行结果。

临时封禁用 timeout,网段集合用 interval

如果名单只应保留一段时间,可以在集合上启用 flags timeout,并为每个成员指定过期时间。超时是成员属性,不需要额外定时任务去执行删除。

# 创建支持成员超时的临时封禁集合;size 预留上限便于规划资源。
nft 'add set inet edge_filter temp_block { type ipv4_addr; flags timeout; size 4096; }'

# 新增地址并设置 10 分钟有效期;到期后成员会从集合中消失。
nft 'add element inet edge_filter temp_block { 198.51.100.23 timeout 10m }'

# 用集合命中后丢弃来源流量;集合为空时规则不会匹配到地址。
nft 'add rule inet edge_filter input ip saddr @temp_block drop'

如果集合用来保存连续地址段,则考虑 flags interval。多个相邻或重叠元素可能导致规则文件加载冲突,此时可以使用 auto-merge 让 nftables 合并相邻或重叠区间。auto-merge 只适用于 interval 集合,不要把它当成普通地址集合的通用开关。

table inet edge_filter {
    # interval 集合用于表达地址段,auto-merge 减少重叠区间冲突。
    set office_ranges {
        type ipv4_addr
        flags interval
        auto-merge
        elements = { 192.0.2.0/28, 198.51.100.0/25 }
    }
}

按三层清单做变更和回滚

我在实际维护中会把 nftables set 的变更拆成集合、规则、文件三层。集合层回答“成员是谁”,规则层回答“命中后做什么”,文件层回答“重启或恢复时从哪里加载”。三层混在一起时,最容易出现临时命令生效、重启后却丢失的问题。

# 先保存当前规则集,便于审查修改范围和准备回滚文件。
nft list ruleset > /var/tmp/edge-filter-before.nft

# 只查看目标集合,确认成员、类型和 timeout 等属性。
nft list set inet edge_filter temp_block

# 删除误加入的临时成员;这比删除整条规则影响面更小。
nft 'delete element inet edge_filter temp_block { 198.51.100.23 }'

# 需要恢复时加载已审查的 nftables 文件,避免手工遗漏规则。
nft -f /etc/nftables.conf

若使用发行版的 nftables 服务,还应把最终配置写入该服务加载的规则文件,并确认文件中的集合定义与运行时临时变更一致。nft list ruleset 只说明当前内核规则集,不会自动替你把临时变更写回配置文件。

常见错误与迁移清单

现象优先检查处理方向
集合无法加入成员type 与地址、端口类型不一致重新确认 ipv4_addr、ipv6_addr、inet_service 等类型
规则找不到集合表族、表名、集合名是否一致使用完整的 family table set 路径
匿名集合无法动态更新集合是否直接写在 rule 中改为 named set,再让规则引用 @集合名
临时封禁不自动消失是否声明 flags timeout 且元素带 timeout同时检查集合属性和元素属性
网段加载报 conflicting intervalsinterval 元素是否重叠合并网段或启用 auto-merge
重启后名单丢失临时命令是否写回配置文件保存并审查 nftables.conf,再由服务加载

把重复条件改成集合,解决的是规则维护成本,不会自动解决默认策略、连接跟踪、双栈设计和配置发布流程。正式变更前保留规则集备份,先在低风险入口确认集合类型和作用范围,再逐步扩大名单。

named set 和匿名集合应该怎么选?

规则内一次性匹配用匿名集合;需要被多条规则引用或需要独立增删成员时,用 named set。

删除 named set 会不会自动删除规则?

不应把删除集合当成安全的回滚动作。先找出引用该集合的规则,再按集合、规则的依赖关系修改。

timeout 是集合级还是成员级?

集合需要声明支持 timeout,具体持续时间可以在新增元素时按成员设置。

为什么地址段集合加载失败?

常见原因是 interval 元素重叠或相邻但未合并;检查 flags interval,并按需要启用 auto-merge。

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