运行 resolvectl status,你会得到一堵按连接分块的输出,每个块都有自己的服务器和自己的域行。决定路由的是域列表,而不是名称服务器地址,因为本地 stub 会把每个查询转发给声明该域名的连接。先读这些声明,再读答案,然后查询域名,看是哪个连接产生了它。来自正确连接的错误答案,与来自错误连接的正确答案,是两种不同的问题。

每个按连接的块告诉你什么

每个块列出解析器将用于该接口的服务器、域列表,以及该连接是否为默认路由。域列表是一组声明,解析器按最长后缀匹配:对 host.corp.example 的查询会先被带有 corp.example 的连接认领,而不是只带默认路由的连接。两个连接声明同一后缀时,结果取决于优先级和顺序,因此重复项最值得先看。当前服务器那一行显示所列服务器中此刻正在使用的是哪一个。

/etc/resolv.conf 中像 127.0.0.53 这样的 stub 地址只说明 stub 在前面。它并没有指出作答的上游,因此仅凭 resolv.conf 的诊断会卡住。

正确读懂三类域条目

条目声明什么常见错误
corp.example路由域兼搜索后缀:其下的名称走这个连接,并且该字符串会附加到裸名称后因路由看起来照常工作而被删除
~corp.example仅路由:其下的名称走这个连接,但不附加后缀被假定为路由所必需
~.默认路由:认领没有其他连接匹配的查询在分流配置中被留着生效,于是公共名称走了隧道

波浪号改变的是搜索行为,而不是路由。没有波浪号的条目既是路由域又是搜索域,因此其下的名称会发往该连接,单标签名称会附加后缀。带波浪号的条目路由同一后缀,但把它排除在搜索列表之外。所以去掉波浪号会改变哪些裸名称能被解析,也所以缺少波浪号是搜索问题,而不是分流 DNS 的故障。

默认路由条目认领没有其他连接匹配的一切。全隧道配置通常需要它,分流配置通常不需要,因为公共名称那时会去往私有解析器,并可能在那里失败。要对照配置的意图来读这张表,而不是在配置之间复制标志。当两个连接声明同一后缀时,先把优先级问题解决,再改其他东西。

查询一个名称,看是哪个连接作答

query 子命令会打印地址、协议,以及产生答案的连接或作用域。测试一个应由私有后缀认领的名称和一个普通公共名称,然后比较报告的来源。如果私有名称从无线连接作答,说明声明缺失或隧道断开;如果分流配置中的公共名称从隧道作答,说明默认路由过宽。这两种失败在浏览器里看起来一样,在这个输出里却相反。

resolvectl status
resolvectl query host.corp.example

也要留意报告的协议,因为来自缓存或 hosts 文件的答案可能在没有询问任何上游的情况下到达。来自缓存的答案只证明该名称曾经被解析过,并不证明当前策略把它路由对了。

把名称路由与数据包路由分开

解析器的决定不会创造路径。被选中的服务器仍然需要通往其地址的路由,返回的地址也仍然需要进入私有网络的路由,因此正确的 DNS 策略可以与一条永不建立的连接并存。当名称解析成功而应用失败时,应当检查地址和路由,而不是再次改 DNS。名称解析与可达性是两个问题,有两个不同的负责人。

应用可以通过自己的安全 DNS 设置或内置解析器完全绕过系统解析器。resolvectl 的结果描述的是系统路径,而忽略它的浏览器会与你做的每一项测试相矛盾。在断定策略有问题之前,先检查那个设置。

把名称解析到的地址记在连接旁边。指向错误地址的正确名称是记录问题,而不是路由问题。

连接变化后重新检查

重新连接或切换无线会重建连接状态,网络管理器可能把手动设置的一切覆盖掉,重新安装自己的域和服务器。之后查询同样两个名称,并与记录的基线比较。如果手动修改消失了,修复应放在连接配置里,而不是 shell 命令里。正是前后记录让这一点可见。

只分享报告需要的名称和服务器背景,因为内部后缀会暴露拓扑。关于域路由的 systemd-resolved 文档涵盖了最长匹配规则和波浪号行为,读一遍就能避免上面表格里的大部分错误:systemd-resolved 中的查询路由。

相关文章