news 2026/9/23 14:28:55

Salt 执行模块 dig 完全指南:用 Salt 批量解析 DNS 记录(A/AAAA/CNAME/NS/SPF/MX/TXT/PTR)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Salt 执行模块 dig 完全指南:用 Salt 批量解析 DNS 记录(A/AAAA/CNAME/NS/SPF/MX/TXT/PTR)

Salt 执行模块 dig 完全指南:用 Salt 批量解析 DNS 记录(A/AAAA/CNAME/NS/SPF/MX/TXT/PTR)

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

本文聚焦于 Salt 项目中的salt.modules.dig执行模块(Execution Module),这是一套"通用 DNS 工具集"(Compendium of generic DNS utilities),它封装了系统自带的dig命令行工具,让运维人员可以在任意受管 Minion 上通过salt命令批量完成 A、AAAA、CNAME、NS、SPF、MX、TXT、PTR 等 DNS 记录的查询与解析。读完本文,你将掌握每个函数的确切用法、返回结构、nameserver指定方式,以及如何把它嵌入 state 或 Reactor 流程做 DNS 健康巡检与邮件域配置核查。

本文对应的官方 API 文档入口为 salt.modules.dig(该页通过 Sphinxautomodule指令直接渲染salt/modules/dig.py的全部 docstring),核心实现位于 salt/modules/dig.py,配套单元测试位于 test_dig.py,模块在模块索引中的登记见 doc/ref/modules/all/index.rst。

一、模块前提:必须安装 dig 二进制

模块 docstring 开门见山:The 'dig' command line tool must be installed in order to use this module.也就是说,本模块不实现 DNS 协议解析逻辑,而是包装系统上的dig可执行文件

对应地,模块通过__virtual__()钩子做加载条件判断(salt/modules/dig.py):

def __virtual__(): """ Only load module if dig binary is present """ if salt.utils.path.which("dig"): return __virtualname__ return ( False, "The dig execution module cannot be loaded: the dig binary is not in the path.", )
  • 模块虚拟名(__virtualname__)为dig,即调用时使用salt <target> dig.xxx
  • dig不在 PATH 中,模块加载失败并返回说明性字符串,此时执行salt <target> dig.check_ip 127.0.0.1会报"模块不可用"错误。
  • 因此在使用前需确保目标 Minion 已安装dnsutils(Debian/Ubuntu)或bind-utils(RHEL/CentOS)等提供dig命令的软件包。

所有 DNS 查询函数最终都通过__salt__"cmd.run_all"非 shell 方式python_shell=False)调用dig,避免 shell 注入风险,并统一约定:只要dig进程返回码非 0,函数即回退返回空列表(源码中多处注释强调 "In this case, 0 is not the same as False")。

二、IP 地址校验:dig.check_ip

check_ip是模块内的基础校验函数,也暴露为可调用的执行函数,用于判断一个字符串是否为合法的 IPv4 / IPv6 地址(可附带 CIDR 前缀),源码见 salt/modules/dig.py。

salt ns1 dig.check_ip 127.0.0.1 salt ns1 dig.check_ip 1111:2222:3333:4444:5555:6666:7777:8888

校验逻辑分三步:

  1. /为分隔符rsplit拆出地址与可选的子网前缀;若传入的不是字符串(如 None、数字),直接返回False
  2. 对 IPv4:前缀必须落在1 <= n <= 32区间;不带前缀(无/)视为合法。
  3. 对 IPv6:前缀必须落在8 <= n <= 128区间;不带前缀视为合法。
  4. 底层有效性判定依赖salt.utils.network中的is_ipv4/is_ipv6(见 salt/utils/network.py),其实现使用 Python 标准库ipaddress.ip_address(...).version判断地址族,并对ValueError兜底返回False

测试用例对此覆盖较全(test_dig.py):

  • check_ip("127.0.0.1")→ True
  • check_ip("1111:2222:3333:4444:5555:6666:7777:8888")→ True
  • check_ip("2607:fa18:0:3::4")→ True(IPv6 压缩写法同样支持)
  • check_ip("-127.0.0.1")→ False
  • check_ip("")→ False

三、正向记录查询:A / AAAA / CNAME

3.1 dig.A —— IPv4 地址

返回host的 A 记录,永远返回列表(Always returns a list),源码见 salt/modules/dig.py:

salt ns1 dig.A www.google.com

实现要点:

  • 拼装命令["dig", "+short", host, "A"]+short让输出精简为纯地址列表。
  • 可选参数nameserver:非空时追加@nameserver,用于指定上游 DNS 服务器。
  • 解析结果按行拆分后,check_ip逐条过滤,只保留真正的 IP 地址行(防止返回非 IP 的杂讯)。
  • dig返回码非 0 时告警并返回[]

对应测试 test_dig.py 验证:对www.google.com返回包含 6 个 IPv4 地址的列表。

3.2 dig.AAAA —— IPv6 地址

与 A 完全对称,返回host的 AAAA 记录列表,源码见 salt/modules/dig.py:

salt ns1 dig.AAAA www.google.com

同样支持nameserver参数、check_ip过滤与失败回退[]。测试(test_dig.py)验证 IPv6 地址2607:f8b0:400f:801::1014能被正确解析并返回。

3.3 dig.CNAME —— 别名记录(自 3005 起提供)

CNAMEversionadded:: 3005加入,返回host的 CNAME 记录,源码见 salt/modules/dig.py:

salt ns1 dig.CNAME mail.google.com

与其他函数不同,CNAME返回的是字符串而非列表return cmd["stdout"]),失败时返回空字符串""。测试用例(test_dig.py)验证:

  • 查询命中时返回形如"bellanotte1986.github.io."的目标域名(注意末尾点);
  • 查询无记录时返回空字符串""

四、反向解析:dig.PTR(自 3006.0 起提供)

PTR函数在versionadded:: 3006.0加入(对应版本说明见 doc/topics/releases/3006.0.md),用于反向地址解析,源码见 salt/modules/dig.py:

salt ns1 dig.PTR 1.2.3.4

实现细节:

  • 拼装命令["dig", "+short", "-x", host],其中-x是 dig 的反向解析(reverse lookup)选项,支持 IPv4 与 IPv6 地址。
  • 返回结果为按行拆分的列表,测试中dig.PTR("8.8.8.8")返回["dns.google."](见 test_dig.py)。
  • 同样支持nameserver参数与失败回退[]

五、权威域名服务器:dig.NS

NS返回domain的权威名称服务器列表,默认自动把 NS 主机名解析为 IP,源码见 salt/modules/dig.py:

salt ns1 dig.NS google.com

参数说明:

参数类型默认值说明
domainstr必填要查询的域名
resolveboolTrue是否将 NS 主机名解析为 IP 地址
nameserverstrNone指定上游 DNS 服务器(追加@nameserver
  • resolve=True(默认):先执行dig +short <domain> NS拿到 NS 主机名列表,再对每个主机名调用本模块的A()函数解析出 IP,并摊平成单个 IP 列表返回。
  • resolve=False:直接返回 NS 主机名字符串列表,如["ns4.google.com."]

对应测试(test_dig.py)通过 mock 内部的A()返回值验证了NS("google.com")的默认解析路径。

六、邮件域核查:dig.MX 与 dig.TXT

6.1 dig.MX —— 邮件交换记录

MX返回domain的 MX 记录,返回值为"列表的列表":每个子列表形如[优先级, 服务器主机名],源码见 salt/modules/dig.py:

salt ns1 dig.MX google.com

参数:

  • resolve(默认False):若为True,则对每个 MX 主机名调用A()解析其 IP,返回[优先级, IP]
  • 源码注释明确了一个设计取舍:解析模式下每个 MX 服务器只取第一个 IPA(x[1], nameserver)[0]),因为实践中 MX 指向的服务器极少做 round-robin 多 IP,这样能保持与不解析模式返回结构的一致性;如果怀疑某个 MX 有多个 IP,请不要依赖该内置解析,而是单独解析。

测试(test_dig.py)验证MX("google.com")返回形如[["10", "aspmx.l.google.com."], ["20", "alt1.aspmx.l.google.com."], ...]的结构(注意数字以字符串形式保留)。

6.2 dig.TXT —— 文本记录

TXT返回host的 TXT 记录列表,永远返回列表,源码见 salt/modules/dig.py:

salt ns1 dig.TXT google.com

实现与 A/AAAA 同构:拼装dig +short <host> TXT(支持nameserver),按行拆分返回,失败回退[]。它也是下方SPF函数的底层依赖。

七、SPF 记录解析:dig.SPF(模块最有特色的函数)

SPF返回domain的 SPF 记录中所允许的 IPv4/IPv6 网段列表,是模块中逻辑最复杂的函数,源码见 salt/modules/dig.py:

salt ns1 dig.SPF google.com

7.1 参数与自动降级机制

  • record参数默认"SPF":当 SPF 记录查询结果为空时,自动改查 TXT 记录(SPF 记录常以 TXT 形式发布);若明确知道该域只用 TXT,直接传"TXT"可省一次查询。
  • 兜底逻辑:if result["stdout"] == "" and record == "SPF": return SPF(domain, "TXT", nameserver)

7.2 解析流程

  1. 去除输出中的双引号并按空白拆分(re.sub('"', "", stdout).split())。
  2. 首段必须是v=spf1,否则返回[]
  3. 若第二段以redirect=开头,则对redirect=之后 9 个字符起的域名递归查询(SPF redirect 机制)。
  4. 其余段用正则(?:\+|~)?(ip[46]|include):(.+)匹配:
    • 命中include:机制 → 对目标域递归调用 SPF并把结果合并;
    • 命中ip4:/ip6:机制 → 用check_ip校验网段合法后加入结果;
    • 不匹配的段(如amx?all~all等)直接跳过。

7.3 测试用例印证

test_dig.py 中的SpfValues夹具模拟了多轮 dig 输出,验证了三种典型场景:

  • 普通域foo.com"v=spf1 ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all"→ 返回["216.73.93.70/31", "216.73.93.72/31"]
  • include机制域xmission.com:先查 TXT 得到"v=spf1 a mx include:_spf.xmission.com ?all",再递归_spf.xmission.com得到ip4:198.60.22.0/24ip4:166.70.13.0/24,最终合并返回这两个网段;
  • redirect机制域xmission-redirect.com"v=spf1 redirect=_spf.xmission.com"触发对_spf.xmission.com的递归查询,同样返回上述两个网段。

这一实现让运维人员无需手工追踪 include/redirect 链,即可拿到域名"最终允许发信的全部 IP 网段",非常适合邮件域 SPF 合规审计。

八、小写别名约定

Salt 执行函数遵循小写命名约定,因此模块在文件末尾定义了一批别名(salt/modules/dig.py):

# Let lowercase work, since that is the convention for Salt functions a = A ptr = PTR aaaa = AAAA cname = CNAME ns = NS spf = SPF mx = MX

这也解释了 API 文档页中:exclude-members: a, aaaa, ns, spf, mx的原因:这些名字只是别名,Sphinx 自动文档生成时将其排除以避免重复渲染。实际使用中dig.adig.Adig.nsdig.NS完全等价;而dig.check_ipdig.TXT本身就是小写形式,无需别名。

九、使用场景与实战建议

基于以上函数,该模块在 Salt 管理体系中典型应用包括:

  1. DNS 记录巡检:用salt '*' dig.A www.example.com批量核对各 Minion 视角下域名解析结果,快速定位内网 DNS 不一致问题;通过nameserver参数可对比不同上游(如内网 DNS 与公网 8.8.8.8)的解析差异。
  2. 邮件配置审计dig.MX domain resolve=True获取邮件服务器实际 IP,dig.SPF domain提取允许发信网段,可用于校验邮件域配置与反垃圾邮件策略。
  3. State / Orchestrate 集成dig是标准执行模块,可在 SLS 文件中通过module.run调用,或结合 reactor 事件做自动化 DNS 健康检查;返回值是标准 Python 结构(列表/字符串),可直接参与 Jinja 判断。
  4. 可靠性注意:所有函数在dig失败时返回空列表(CNAME 返回空字符串)并记录log.warning,因此自动化流程中"空结果"既可能是"无记录"也可能是"dig 执行失败",编排时应结合cmd.run_all的返回码语义自行区分。

十、源码速查

能力源码位置测试位置
模块加载条件__virtual__salt/modules/dig.py
IP 校验check_ipsalt/modules/dig.pytest_dig.py
A 记录salt/modules/dig.pytest_dig.py
PTR 反向解析salt/modules/dig.pytest_dig.py
AAAA 记录salt/modules/dig.pytest_dig.py
CNAME 记录salt/modules/dig.pytest_dig.py
NS 记录salt/modules/dig.pytest_dig.py
SPF 记录salt/modules/dig.pytest_dig.py
MX 记录salt/modules/dig.pytest_dig.py
TXT 记录salt/modules/dig.py
小写别名salt/modules/dig.py

总而言之,salt.modules.dig是一个"小而精"的执行模块:全部功能建立在dig +short之上,通过统一的cmd.run_all调用、统一的失败回退策略、以及对 A/AAAA 结果做 IP 合法性过滤,为 Salt 用户提供了稳定、可脚本化的 DNS 查询原语;其中SPF的 include/redirect 递归解析和NS的自动解析是远超裸dig命令的增值能力,可直接嵌入自动化运维流程。

【免费下载链接】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:28:51

燃料电池汽车双层优化策略与Matlab实现

1. 项目背景与核心价值燃料电池混合动力汽车&#xff08;FCHV&#xff09;作为清洁能源交通的代表&#xff0c;其能量管理策略一直是学术界和工业界的研究热点。特别是在城市交通场景下&#xff0c;信号交叉口的频繁启停对整车经济性和排放特性产生显著影响。传统单层优化方法往…

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

版本升级API全变了?一文搞懂偷梁换柱避坑指南

版本升级API全变了?一文搞懂偷梁换柱避坑指南 版本升级后 API 全变了,代码跑一半直接报 AttributeError 或者 TypeError ,这种绝望感每个开发者都经历过。别急着骂娘,这往往不是库作者的锅,而是你掉进了“偷梁换柱”的陷阱。今天咱们不整虚的, 一文搞懂…

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

2026最新信用评估实战:Python从0到1搭建风控模型

2026最新信用评估实战:Python从0到1搭建风控模型 版本升级后 API 全变了,这是很多老鸟在迁移项目时遇到的噩梦。特别是当你要从旧的 Excel 脚本转向 Python 自动化,或者从 Pandas 1.x 升级到 2.x 时,那些熟悉的 append 和 ix…

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

易中天品三国mp3图解原理:3步搞定Java异常堆栈

易中天品三国mp3图解原理:3步搞定Java异常堆栈 刚接手的微服务项目,线上突然报警。日志里全是红色的 Error,StackTrace 长得像天书, java.lang.NullPointerException…

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

2026最新交通卡app选型实战:5个技术栈深度对比

2026最新交通卡app选型实战:5个技术栈深度对比 刚把Python类学完,或者Java泛型搞明白,却对着空白的IDE发呆?这是太多初级开发者踩过的坑。知道怎么写一个Hello World,但不知道一个真正的 交通卡app 该怎么从0搭到1,更不知道选Go、Rust还是Java才不踩雷。…

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

不灭元尊实战避坑指南:从教程到落地的5个致命断层

不灭元尊实战避坑指南:从教程到落地的5个致命断层 看了一堆教程还是不会写项目?这种无力感我太熟悉了。很多人把【不灭元尊】当成一个普通的代码片段或配置模板,结果一上真项目就崩盘。今天这份【避坑指南】,专门拆解【不灭元尊】在真实业务流中的常见报错与解决路径,帮你在落地前扫清障碍。 1.…

作者头像 李华