当前位置:首页 > 文章列表 > 文章 > linux > nftables set 怎么为大量 IP 规则减少重复配置

nftables set 怎么为大量 IP 规则减少重复配置

来源:17golang原创 2026-10-06 06:05:24 0浏览 收藏

大量 IP 规则不该靠复制粘贴维护。更稳妥的做法是把地址集中放进一个命名 set,规则里只写一次 ip saddr @blocked_ipv4。以后新增或删除 IP 时只改集合元素,不再复制整条匹配与动作,规则数量、漏改概率和审计成本都会下降。

下面用一个入口访问控制场景拆开说明:需要拒绝一批来源 IPv4 地址,其中既有单个地址,也有网段;地址列表会持续变化,但过滤动作始终是 drop。

先划清边界:规则负责动作,set 负责地址数据

如果把每个 IP 写成一条规则,地址与动作会被绑在一起。三十个地址就是三十次重复,后续把 drop 改成 counter drop 时也要改三十处。命名 set 将这两部分拆开:

  • set 保存同一种数据类型的元素,例如 ipv4_addr;
  • rule 只表达一次匹配和动作,例如“来源地址属于该集合就丢弃”;
  • 元素维护命令 独立增删地址,不必重建引用它的规则。

匿名集合适合少量且固定的值,例如端口 { 22, 443 };它绑定在规则上,不能在绑定后单独更新。地址较多或经常变化时,应使用带名称的 set。

重复 IP 条件集中到命名集合并由单条过滤规则引用的静态结构
图1:地址数据、命名 set 与过滤规则的边界关系说明图;这是静态结构图,不是运行截图。

准备权限和对象:类型先于元素

维护 nftables 通常需要 root 权限或等价的 CAP_NET_ADMIN 能力。不要把 IPv4、IPv6、端口混进同一个集合:集合的 type 决定了允许保存和匹配的数据。本文的来源地址集合使用 ipv4_addr,IPv6 应另建 ipv6_addr 集合。

一个可持久化的最小配置如下:

table inet access_control {
    set blocked_ipv4 {
        # 集合只保存 IPv4 地址和网段
        type ipv4_addr
        flags interval
        auto-merge
        elements = {
            198.51.100.23,
            203.0.113.0/24
        }
    }

    chain input {
        # 绑定输入钩子;默认策略按现网要求设置
        type filter hook input priority filter; policy accept;

        # 规则只引用一次命名集合,成员变化不需要复制规则
        ip saddr @blocked_ipv4 counter drop
    }
}

inet 表可以容纳 IPv4 与 IPv6 规则,但 blocked_ipv4 自身仍是明确的 IPv4 类型。这个边界能避免把看似相近、实际类型不同的数据塞进同一份清单。

让大量地址变短:interval 与 auto-merge 怎么选

如果集合只保存离散单个 IP,普通 ipv4_addr set 就够了。只要出现 CIDR、地址区间,或希望相邻与重叠范围自动合并,就应启用 flags interval。auto-merge 只对 interval set 有效,它会在加载时合并相邻或重叠的元素。

例如 203.0.113.0/24 已经覆盖其中的单个地址,就没有必要再保存 203.0.113.8。自动合并可以减少这种重复,也能避免重叠区间造成配置加载冲突。

地址形态建议配置适用判断
少量离散 IPtype ipv4_addr没有 CIDR 或范围
网段、范围flags interval元素含 CIDR 或起止区间
大量重叠网段interval + auto-merge希望加载时合并覆盖关系
临时封禁flags timeout元素应在到期后自动移除

不要随手添加 constant。它表示集合绑定后内容不应变化,与“地址名单经常增删”的目标相冲突。由数据包路径动态写入集合又是另一类设计,需要 dynamic、容量上限与超时控制,不能直接套用本文的人工或自动化清单维护方式。

批量更新元素,不再改动过滤规则

命名 set 的价值在于成员可以独立维护。一次加入多个地址:

# 批量加入三个离散地址;表名和集合名必须与现有配置一致
sudo nft add element inet access_control blocked_ipv4 \
  '{ 192.0.2.10, 192.0.2.11, 192.0.2.12 }'

# 只删除已解除封禁的地址,不触碰引用集合的过滤规则
sudo nft delete element inet access_control blocked_ipv4 \
  '{ 192.0.2.11 }'

如果名单来自配置管理系统,建议让自动化产出完整的 nft 脚本,再统一加载,而不是在循环中逐条执行命令。这样一批改动要么整体通过,要么不落地,失败时也容易定位到同一份输入文件。

# 文件片段:集中描述本批次需要增加的元素
add element inet access_control blocked_ipv4 {
    192.0.2.20,
    192.0.2.21,
    198.51.100.0/25
}

更新前先对输入去重,并明确谁是名单的唯一来源。否则人工命令、配置文件和自动化平台同时写同一集合,虽然规则变少了,数据所有权仍会混乱。

地址清单经过类型边界和区间合并进入 nftables set 的静态维护关系
图2:地址来源、类型边界、区间集合和规则引用之间的静态维护关系;这是说明图,不是执行流程或运行证据。

把预检查设为门禁,避免错误配置直接落地

正式加载前,用 -c 只检查命令有效性,不应用变更。检查通过后再用同一文件加载:

# 先检查语法、对象引用和元素类型,不修改当前规则集
sudo nft -c -f /etc/nftables.conf

# 检查成功后再加载同一份文件,避免检查对象与发布对象不一致
sudo nft -f /etc/nftables.conf

# 只查看目标集合,确认成员是否符合本次变更单
sudo nft list set inet access_control blocked_ipv4

这里的门禁重点不是“命令返回零就万事大吉”,而是保证检查和加载使用同一份文件,并在变更记录中保留集合名、元素来源、预期新增/删除数量和回退版本。对于远程主机的防火墙变更,还要预留独立管理通道,避免误伤当前 SSH 来源。

常见失败怎么定位

提示数据类型不匹配

先检查 set 的 type,再检查加入的元素。IPv6 地址不能写入 ipv4_addr,端口也不能写入地址集合。最直接的修复是按类型拆集合,而不是把所有条件改成字符串。

提示区间冲突

集合含网段或范围时确认是否启用了 interval。如果输入中有相邻、重叠或“网段已经覆盖单点”的情况,使用 auto-merge 或在上游先规范化地址清单。

元素改了但流量行为没变

检查规则是否真的引用了正确的表、集合和地址方向。ip saddr 匹配来源地址,ip daddr 匹配目的地址;表名相同但 family 不同,也不是同一个对象。还要留意更早命中的 accept/drop 规则是否已经决定了结果。

集合越来越大

静态名单要建立删除机制;临时名单应考虑 timeout。如果从数据包路径动态增加元素,必须设置 size 和超时,防止无限增长。超时元素的内存回收还受 gc-interval 影响,不能只看“逻辑上已经过期”。

维护清单:把 set 当成可审计的数据对象

  • 一个 set 只保存一种明确类型和一种业务含义;
  • IPv4、IPv6、端口分别建集合,不用名字相近掩盖类型差异;
  • 网段使用 interval,重叠清单按需启用 auto-merge;
  • 规则只引用集合,名单更新不复制匹配与动作;
  • 检查与加载使用同一份文件,变更前保留可回退版本;
  • 记录元素来源、责任人和过期策略,避免多个系统争抢写入权;
  • 定期列出目标 set,复盘是否仍需要每个地址或网段。

最终效果并不是“把很多 IP 换一种写法”这么简单,而是把防火墙规则拆成稳定的策略层和可更新的数据层。策略层保持一条清晰规则,数据层通过命名 set 批量维护,新增、删除、检查和回退都有明确入口。

相关问题

set 和 map 有什么区别?

set 主要回答“这个键是否存在”;map 则把键映射到一个值或 verdict。只做 IP 白名单、黑名单时优先用 set,需要不同地址映射到不同动作时再考虑 map。

可以在 inet 表中混合 IPv4 和 IPv6 吗?

表可以使用 inet family,但集合仍有具体元素类型。实际维护时分别创建 ipv4_addr 和 ipv6_addr 集合,规则分别用 ip 与 ip6 表达式引用。

元素很多时要不要设置 size?

由用户态命令加入元素时,size 不是必填,但明确上限有助于资源规划。若从数据包路径动态增加元素,官方手册要求为相应场景配置容量上限,并结合超时防止无界增长。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go iter.Pull 怎么把推送序列改成按需读取Go iter.Pull 怎么把推送序列改成按需读取
上一篇
Go iter.Pull 怎么把推送序列改成按需读取
Go Resolver LookupHost 为什么在容器里结果顺序变化
下一篇
Go Resolver LookupHost 为什么在容器里结果顺序变化
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    344次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    406次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    404次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    367次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    187次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码