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校验逻辑分三步:
- 以
/为分隔符rsplit拆出地址与可选的子网前缀;若传入的不是字符串(如 None、数字),直接返回False。 - 对 IPv4:前缀必须落在
1 <= n <= 32区间;不带前缀(无/)视为合法。 - 对 IPv6:前缀必须落在
8 <= n <= 128区间;不带前缀视为合法。 - 底层有效性判定依赖
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")→ Truecheck_ip("1111:2222:3333:4444:5555:6666:7777:8888")→ Truecheck_ip("2607:fa18:0:3::4")→ True(IPv6 压缩写法同样支持)check_ip("-127.0.0.1")→ Falsecheck_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 起提供)
CNAME在versionadded:: 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参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
domain | str | 必填 | 要查询的域名 |
resolve | bool | True | 是否将 NS 主机名解析为 IP 地址 |
nameserver | str | None | 指定上游 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 服务器只取第一个 IP(
A(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.com7.1 参数与自动降级机制
record参数默认"SPF":当 SPF 记录查询结果为空时,自动改查 TXT 记录(SPF 记录常以 TXT 形式发布);若明确知道该域只用 TXT,直接传"TXT"可省一次查询。- 兜底逻辑:
if result["stdout"] == "" and record == "SPF": return SPF(domain, "TXT", nameserver)。
7.2 解析流程
- 去除输出中的双引号并按空白拆分(
re.sub('"', "", stdout).split())。 - 首段必须是
v=spf1,否则返回[]。 - 若第二段以
redirect=开头,则对redirect=之后 9 个字符起的域名递归查询(SPF redirect 机制)。 - 其余段用正则
(?:\+|~)?(ip[46]|include):(.+)匹配:- 命中
include:机制 → 对目标域递归调用 SPF并把结果合并; - 命中
ip4:/ip6:机制 → 用check_ip校验网段合法后加入结果; - 不匹配的段(如
a、mx、?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/24与ip4: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.a与dig.A、dig.ns与dig.NS完全等价;而dig.check_ip与dig.TXT本身就是小写形式,无需别名。
九、使用场景与实战建议
基于以上函数,该模块在 Salt 管理体系中典型应用包括:
- DNS 记录巡检:用
salt '*' dig.A www.example.com批量核对各 Minion 视角下域名解析结果,快速定位内网 DNS 不一致问题;通过nameserver参数可对比不同上游(如内网 DNS 与公网 8.8.8.8)的解析差异。 - 邮件配置审计:
dig.MX domain resolve=True获取邮件服务器实际 IP,dig.SPF domain提取允许发信网段,可用于校验邮件域配置与反垃圾邮件策略。 - State / Orchestrate 集成:
dig是标准执行模块,可在 SLS 文件中通过module.run调用,或结合 reactor 事件做自动化 DNS 健康检查;返回值是标准 Python 结构(列表/字符串),可直接参与 Jinja 判断。 - 可靠性注意:所有函数在
dig失败时返回空列表(CNAME 返回空字符串)并记录log.warning,因此自动化流程中"空结果"既可能是"无记录"也可能是"dig 执行失败",编排时应结合cmd.run_all的返回码语义自行区分。
十、源码速查
| 能力 | 源码位置 | 测试位置 |
|---|---|---|
模块加载条件__virtual__ | salt/modules/dig.py | — |
IP 校验check_ip | salt/modules/dig.py | test_dig.py |
| A 记录 | salt/modules/dig.py | test_dig.py |
| PTR 反向解析 | salt/modules/dig.py | test_dig.py |
| AAAA 记录 | salt/modules/dig.py | test_dig.py |
| CNAME 记录 | salt/modules/dig.py | test_dig.py |
| NS 记录 | salt/modules/dig.py | test_dig.py |
| SPF 记录 | salt/modules/dig.py | test_dig.py |
| MX 记录 | salt/modules/dig.py | test_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),仅供参考