news 2026/9/23 14:19:24

Salt 之 ipset 模块实战:用执行模块与状态模块管理 iptables IP 集合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Salt 之 ipset 模块实战:用执行模块与状态模块管理 iptables IP 集合

Salt 之 ipset 模块实战:用执行模块与状态模块管理 iptables IP 集合

【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址: https://gitcode.com/gh_mirrors/sa/salt

本文基于当前开源仓库中的 ipset 模块文档(doc/ref/modules/all/salt.modules.ipset.rst)展开,系统讲解 Salt 如何通过执行模块(salt.modules.ipset)与状态模块(salt.states.ipset)管理 Linux 内核的 IP 集合(ipset),用于配合 iptables 防火墙实现高效的 IP/端口/网段批量匹配。读完本文,你将掌握 ipset 集合的创建、增删改查、清空等全部命令的调用方式,理解底层参数映射与校验逻辑,并能在 SLS 状态文件中实现集合与成员的幂等管理。

模块定位与加载条件

ipset 模块用于操作 Linux 内核提供的 ipset 工具——一种面向 iptables 的高性能集合数据结构,可将大量 IP 地址、网段、端口、MAC 地址等组织为命名集合,供防火墙规则引用,避免逐条编写 iptables 规则。Salt 将该能力封装为统一接口,便于通过salt '*' ipset.xxx批量下发到所有 minion。

从源码 salt/modules/ipset.py 可见,模块的__virtual__()会检查系统中是否存在ipset二进制文件:

def __virtual__(): if salt.utils.path.which("ipset"): return True return ( False, "The ipset execution modules cannot be loaded: ipset binary not in path.", )

也就是说,只有在 minion 上安装了ipset命令(如yum install ipsetapt install ipset)时,模块才会被加载,否则返回加载失败原因。状态模块 salt/states/ipset.py 则依赖执行模块是否可用("ipset.version" in __salt__)来决定是否加载。

集合类型与地址族映射

模块内部维护了两张核心常量表,这是理解所有命令参数的基础。

支持的集合类型_IPSET_SET_TYPES

源码 salt/modules/ipset.py 定义了模块支持的全部 15 种集合类型:

集合类型说明
bitmap:ipIP 位图(必须指定 range)
bitmap:ip,macIP+MAC 位图
bitmap:port端口位图
hash:ipIP 哈希
hash:macMAC 哈希
hash:ip,portIP+端口哈希
hash:ip,port,ipIP+端口+IP 哈希
hash:ip,port,netIP+端口+网段哈希
hash:net网段哈希
hash:net,net网段+网段哈希
hash:net,iface网段+网卡接口哈希
hash:net,port网段+端口哈希
hash:net,port,net网段+端口+网段哈希
hash:ip,markIP+防火墙标记(mark)哈希
list:set集合的列表(可聚合其他集合)

地址族映射_IPSET_FAMILIES

源码 salt/modules/ipset.py 将 family 参数映射为 ipset 命令内部的 inet 族:

_IPSET_FAMILIES = { "ipv4": "inet", "ip4": "inet", "ipv6": "inet6", "ip6": "inet6", }

family参数既支持完整的ipv4/ipv6,也兼容ip4/ip6缩写。默认值为ipv4

执行模块函数全解析

以下函数均位于 salt/modules/ipset.py,命令通过__salt__["cmd.run"]在 minion 本地执行,python_shell=False保证不经过 shell 解释。

version——查看 ipset 版本

执行ipset --version并解析出版本号:

salt '*' ipset.version

实现见 salt/modules/ipset.py,先运行ipset --version,对输出按空白切分后取第二个字段作为版本返回。

new_set——创建集合

new_set是使用频率最高的函数之一,负责创建自定义集合。其签名与典型调用如下(自 2014.7.0 版本加入):

def new_set(name=None, set_type=None, family="ipv4", comment=False, **kwargs):

CLI 示例(源码 salt/modules/ipset.py):

# 创建一个 list:set 类型的集合 salt '*' ipset.new_set custom_set list:set # 带注释创建 salt '*' ipset.new_set custom_set list:set comment=True # IPv6 salt '*' ipset.new_set custom_set list:set family=ipv6

创建过程会依次校验:集合名必须指定、集合类型必须指定、类型必须在_IPSET_SET_TYPES中。随后通过_CREATE_OPTIONS_REQUIRED检查该类型必须携带的参数(如bitmap:ip必须提供range),再按_CREATE_OPTIONS中的选项表拼接ipset create <name> <type> [options]命令。

各类型创建选项表(_CREATE_OPTIONS

源码 salt/modules/ipset.py 定义了每种类型可用的创建选项:

  • bitmap 系列bitmap:ipbitmap:ip,macbitmap:port):range(必填)、timeoutcounterscommentskbinfo
  • hash 系列hash:iphash:nethash:net,nethash:net,porthash:net,port,nethash:ip,porthash:ip,port,iphash:ip,port,nethash:net,iface):familyhashsizemaxelemnetmasktimeoutcounterscommentskbinfo
  • hash:machashsizemaxelemtimeoutcounterscommentskbinfo
  • hash:ip,mark:额外支持markmask
  • list:setsizetimeoutcounterscomment

其中commentcountersskbinfo属于无值选项_CREATE_OPTIONS_WITHOUT_VALUE,见 salt/modules/ipset.py),拼接命令时不带值,直接追加选项名。

必填选项表(_CREATE_OPTIONS_REQUIRED

源码 salt/modules/ipset.py 中,仅 bitmap 系列要求range必填,其余 hash/list 系列无必填项:

_CREATE_OPTIONS_REQUIRED = { "bitmap:ip": ["range"], "bitmap:ip,mac": ["range"], "bitmap:port": ["range"], "hash:ip": [], # ... 其余 hash/list 类型均为空列表 }

此外,仅当集合类型支持family选项时才追加family <inet|inet6>参数;comment=True时追加comment标志。命令成功(无输出)时返回True

单元测试 tests/pytests/unit/modules/test_ipset.py 验证了缺失名称、缺失类型、非法类型、bitmap 缺range时的错误返回,以及成功路径返回True的行为。

delete_set——删除集合

执行ipset destroy <name>删除整个集合(自 2014.7.0 加入):

salt '*' ipset.delete_set custom_set salt '*' ipset.delete_set custom_set family=ipv6

实现见 salt/modules/ipset.py,未指定名称时返回"Error: Set needs to be specified"

rename_set——重命名集合

salt '*' ipset.rename_set custom_set new_set=new_set_name salt '*' ipset.rename_set custom_set new_set=new_set_name family=ipv6

实现见 salt/modules/ipset.py。重命名前会先通过_find_set_type确认原集合存在、新名称未被占用,两个前置校验失败分别返回"Error: Set does not exist""Error: New Set already exists",再执行ipset rename <old> <new>

list_sets——列出所有集合

salt '*' ipset.list_sets

实现见 salt/modules/ipset.py。执行ipset list -t,将输出按空行切分为多个集合对象,每一行按key: value解析成字典,返回由多个字典组成的列表,每个字典含NameTypeHeader等字段。

check_set——检查集合是否存在

salt '*' ipset.check_set name

实现见 salt/modules/ipset.py。内部调用_find_set_info(执行ipset list -t <name>),集合存在返回True,不存在返回False

add——向集合追加条目

# 追加单个 IP salt '*' ipset.add name 192.168.1.26 # 追加 IP+MAC 复合条目 salt '*' ipset.add name 192.168.0.3,AA:BB:CC:DD:EE:FF # 带注释(entry 内联写法) salt '*' ipset.add name '192.168.0.1 comment "Hello"'

实现见 salt/modules/ipset.py,是校验最丰富的函数之一:

  1. 名称与条目必填,集合必须存在(_find_set_info返回集合元信息,包括TypeHeader);
  2. 命令使用ipset add -exist <name> <entry...>-exist保证条目已存在时不会报错,同时可用于更新条目的注释;
  3. 选项与集合创建能力绑定校验:
    • 传入timeout时,集合 Header 必须包含timeout(否则返回"Error: Set {name} not created with timeout support");
    • 传入packets/bytes时,集合必须创建于counters支持;
    • 传入comment时,集合必须创建于comment支持;
    • 传入skbmark/skbprio/skbqueue时,集合必须创建于skbinfo支持;
  4. 通过_ADD_OPTIONS选项表(见 salt/modules/ipset.py)拼接条目附加选项,如hash:net系列额外支持nomatch
  5. 先读取集合现有成员,若条目已存在返回"Warn: Entry {entry} already exists in set {name}"
  6. 命令成功返回"Success",失败返回"Error: {输出}"

单元测试 tests/pytests/unit/modules/test_ipset.py 覆盖了缺失参数、集合不存在、timeout/counters/comment 能力校验、重复条目告警以及成功路径。功能测试 tests/pytests/functional/modules/test_ipset.py 则演示了真实环境下的bitmap:ip集合创建与条目添加。

delete——删除集合条目

salt '*' ipset.delete name 192.168.0.3,AA:BB:CC:DD:EE:FF

实现见 salt/modules/ipset.py。校验集合存在后执行ipset del <name> <entry>,成功返回"Success"

check——检查条目是否在集合中(智能匹配)

check是模块中智能度最高的函数,它不只是简单执行ipset test,而是读取集合成员后用 Python 的ipaddress库做语义化匹配:

# 单 IP salt '*' ipset.check name 192.168.0.1 # IP 范围 salt '*' ipset.check name 192.168.0.2-192.168.0.19 # 子网 salt '*' ipset.check name 192.168.0.0/25 # 带注释的条目 salt '*' ipset.check name '192.168.0.1 comment "Hello"'

参数说明(源码 salt/modules/ipset.py):

  • name:集合名;
  • entry:单个 IP、IP 范围或子网块;支持传列表;
  • family:ipv4 或 ipv6。

匹配逻辑依赖辅助函数链:_parse_members_parse_member_member_contains_compare_member_parts(见 salt/modules/ipset.py)。核心能力包括:

  • 按集合类型(如hash:net)拆分子类型,ip/net字段尝试解析为ipaddress.IPv4Network/IPv6NetworkIPv4Address/IPv6Addressport转为整数;
  • IP 范围(a-b)用summarize_address_range展开为网段列表;
  • 子网包含关系判断:如集合成员为192.168.0.4/31,检查192.168.0.4/30时能正确判定包含/被包含关系(见 salt/modules/ipset.py)。

单元测试 tests/pytests/unit/modules/test_ipset.py 对hash:iphash:net两种类型分别验证了单 IP、/31网段、范围条目的匹配结果。

test——用内核测试条目是否在集合中

check的语义化解析不同,test直接调用底层ipset test <name> <entry>命令,依据退出码判断:

salt '*' ipset.test name 192.168.0.2 salt '*' ipset.test name fd81:fc56:9ac7::/48 # IPv6

实现见 salt/modules/ipset.py:使用cmd.run_all执行,retcode > 0返回False,否则返回True。单元测试 tests/pytests/unit/modules/test_ipset.py 验证了该退出码判定逻辑。

flush——清空集合条目

不指定集合时清空所有集合,指定时只清空该集合:

salt '*' ipset.flush salt '*' ipset.flush set salt '*' ipset.flush # IPv6 同理 salt '*' ipset.flush set

实现见 salt/modules/ipset.py:执行ipset flush [name],命令无输出(成功)时返回True

状态模块:以声明式 SLS 管理 ipset

salt.states.ipset(源码 salt/states/ipset.py)将上述执行模块封装为幂等的声明式状态,自 2014.7.0 加入,共五个状态函数。所有状态均遵循 Salt 标准返回结构(namechangesresultcomment),并支持test=True试运行模式(此时返回result: None与“would be...”注释)。

set_present / set_absent——管理集合本身

setname: ipset.set_present: - set_type: bitmap:ip - range: 192.168.0.0/16 - comment: True setname: ipset.set_absent: - set_type: bitmap:ip - range: 192.168.0.0/16 - comment: True
  • set_present(salt/states/ipset.py):先check_set判断,已存在则直接成功;test 模式提示“would be added”;否则调用ipset.new_set,成功后记录 changes。
  • set_absent(salt/states/ipset.py):集合不存在视为成功;存在时先ipset.flush清空,再ipset.delete_set删除。

present / absent——管理集合条目

setname_entries: ipset.present: - set_name: setname - entry: 192.168.0.3 - comment: Hello - require: - ipset: baz setname_entries: ipset.present: - set_name: setname - entry: - 192.168.0.3 - 192.168.1.3 - comment: Hello - require: - ipset: baz setname_entries: ipset.absent: - set_name: setname - entry: - 192.168.0.3 - 192.168.1.3 - comment: Hello - require: - ipset: baz
  • present(salt/states/ipset.py):name只是状态内部的用户自定义标识,并非真实条目;entry支持单个值或列表。状态会自动把timeoutcomment等 kwargs 拼入条目字符串(如timeout 300 comment Hello),先ipset.check判断条目是否已存在,不存在才调用ipset.add
  • absent(salt/states/ipset.py):逻辑相反,条目已不在集合中视为成功,存在则调用ipset.delete移除。

flush——清空指定集合

setname: ipset.flush:

实现见 salt/states/ipset.py:集合不存在直接失败;test 模式提示“would be flushed”;否则调用执行模块的ipset.flush

功能测试 tests/pytests/functional/states/test_ipset.py 验证了states.ipset.present在真实 ipset 环境下的添加行为与注释输出格式。

典型实战:配合 iptables 的完整链路

结合执行模块与状态模块,一个典型场景——在 minion 上维护“黑名单 IP 集合”并让 iptables 引用它:

# 1. 创建 hash:net 集合(支持网段与超时) salt '*' ipset.new_set blacklist hash:net family=ipv4 timeout=86400 comment=True # 2. 添加条目 salt '*' ipset.add blacklist '203.0.113.5' salt '*' ipset.add blacklist '198.51.100.0/24 comment "spam net"' # 3. 校验 salt '*' ipset.list_sets salt '*' ipset.check blacklist '198.51.100.0/24' salt '*' ipset.test blacklist 203.0.113.5 # 4. 清空/删除 salt '*' ipset.flush blacklist salt '*' ipset.delete_set blacklist

等价的状态声明:

blacklist: ipset.set_present: - set_type: hash:net - family: ipv4 - timeout: 86400 - comment: True blacklist_entries: ipset.present: - set_name: blacklist - entry: - 203.0.113.5 - 198.51.100.0/24 - comment: 'spam net' - require: - ipset: blacklist

随后在 iptables 中引用该集合(可配合 Salt 的 iptables 状态模块):

iptables -A INPUT -m set --match-set blacklist src -j DROP

注意事项与适用前提

  • 依赖 ipset 二进制:模块通过which("ipset")检测,未安装时执行模块与状态模块均不加载,详见 salt/modules/ipset.py。
  • 能力校验是双向的:向集合add带 timeout/counters/comment/skbinfo 的条目时,集合本身必须在创建时启用了对应能力,否则返回明确错误。
  • checktest语义不同test依赖内核精确匹配;check由 Python 侧解析 IP 对象,支持范围/子网包含关系判断,适合状态模块做幂等判断,但也依赖集合类型解析正确。
  • 条目内联注释checkadd均支持在 entry 中携带comment "xxx"片段(见 salt/modules/ipset.py),状态模块会自动拼装timeout/comment到条目字符串中。
  • IPv6 支持:所有函数均接受family=ipv6(或ip6),最终映射为inet6族。
  • 执行环境为 Linux 内核 ipset:该模块面向 Linux 系统,Windows 下不可用(功能测试也通过skip_if_binaries_missing("ipset")跳过)。

延伸阅读

  • 执行模块完整实现:salt/modules/ipset.py
  • 状态模块完整实现:salt/states/ipset.py
  • 状态模块文档:doc/ref/states/all/salt.states.ipset.rst
  • 单元测试:tests/pytests/unit/modules/test_ipset.py
  • 功能测试:tests/pytests/functional/modules/test_ipset.py、tests/pytests/functional/states/test_ipset.py

【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址: https://gitcode.com/gh_mirrors/sa/salt

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 14:18:28

看完就会:盘点2026年标杆级的降AI率工具

每年3月到5月&#xff0c;论文查重和降AI检测就是毕业生绕不开的两道坎。知网和维普陆续上线AI生成内容检测功能后&#xff0c;不少学生因为论文被标记为“疑似AI写作”而被迫返工。降AI率这件事&#xff0c;已经从“可选优化”变成了论文送审前的硬性门槛。市面上声称能解决这…

作者头像 李华
网站建设 2026/9/23 14:13:04

DGA恶意域名检测:LSTM+CNN双路模型与随机森林融合实战

简介&#xff1a;本资源是一套面向网络安全研究人员与AI安全工程师的DGA恶意域名检测实战方案&#xff0c;聚焦于利用机器学习与深度学习技术突破传统黑名单防御局限&#xff0c;解决高级持续性威胁中隐蔽C2通信识别难题。压缩包共5个文件&#xff08;17.59MB&#xff09;&…

作者头像 李华
网站建设 2026/9/23 14:11:32

元宇宙架构升级:元域数融体与规则拓扑网络解析

1. 项目概述&#xff1a;元宇宙架构的范式升级当我们在谈论元宇宙构建时&#xff0c;传统思路往往停留在"连接"层面——通过API接口打通不同平台&#xff0c;或是用统一账号系统实现身份互通。这种"物理拼接"式的架构虽然解决了基础互联问题&#xff0c;却…

作者头像 李华
网站建设 2026/9/23 14:11:00

Linux环境变量详解:从command not found到永久配置与急救

新装好的Linux&#xff0c;你满怀期待地敲下java&#xff0c;结果终端冷冷回了一句&#xff1a;command not found。别急着怀疑JDK没装好&#xff0c;多半是系统根本没被告知上哪儿找java这个命令。这个“告诉系统去哪儿找”的机制&#xff0c;就是环境变量。今天就把这玩意儿彻…

作者头像 李华
网站建设 2026/9/23 14:10:10

HDLC协议实现避坑指南:状态机、零比特填充与CRC校验

简介&#xff1a;本资源是一套面向嵌入式开发与网络协议学习者的HDLC协议实践代码包&#xff0c;聚焦同步数据链路层核心机制的工程实现&#xff0c;适用于通信类课程设计、协议栈开发入门及底层驱动调试场景。压缩包含8个文件&#xff08;93KB&#xff09;&#xff0c;以5个头…

作者头像 李华
网站建设 2026/9/23 14:10:08

光伏功率预测LSTM毕业设计:从数据清洗到多步预测的完整实战

简介&#xff1a;这是一份面向计算机相关专业毕业设计学生与项目实战学习者的LSTM光伏预测完整项目包&#xff0c;选题聚焦短期光伏功率预测这一新能源与深度学习交叉方向&#xff0c;难度适中&#xff0c;适合作为毕设选题或算法练习案例。资源共28个文件&#xff0c;压缩包约…

作者头像 李华