在 Fedora 33 中,systemd-resolved 默认启用。大多数用户可能不会注意到变化,但如果你使用 VPN 或依赖 DNSSEC,那么 systemd-resolved 可能对你来说非常重要。在测试 Fedora 33 时,我们发现了一份错误报告,用户发现 systemd-resolved 破坏了他的 VPN 配置。在这个错误修复后,没有人报告进一步的问题,我对迁移到 systemd-resolved 感到相当自信。然而,当 Fedora 33 发布时,我注意到在 Ask Fedora 和 Reddit 上有大量用户请求帮助解决破损的 VPN 问题,而这些问题在 Fedora 33 测试版中并未被检测到。这让我感到非常惊讶,因为 Ubuntu 自 16.10 版本起就默认启用了 systemd-resolved,意味着我们在这方面落后了四年,这应该有足够的时间来解决任何问题。那么,到底发生了什么呢?
传统 DNS 的工作方式
在讨论 systemd-resolved 之前,我们先看看传统 DNS 的工作方式。首先,我们需要讨论两个重要的配置文件。第一个是 /etc/nsswitch.conf
,它控制 glibc 在执行名称解析时调用哪些 NSS 模块。需要注意的是,这些是 glibc 的名称服务切换模块,与 Firefox 的 NSS(网络安全服务)无关。值得一提的是,在 Fedora(以及 Red Hat Enterprise Linux)中,/etc/nsswitch.conf
是由 authselect 管理的,不能直接编辑。如果你想更改它,需要编辑 /etc/authselect/user-nsswitch.conf
,然后运行 sudo authselect apply-changes
。
在 Fedora 32 中,/etc/nsswitch.conf
中的 hosts 行如下所示:
hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname
这意味着:首先调用 nss-files,这将查看 /etc/hosts
文件以检查主机名是否在其中。如果没有,则调用 nss-mdns4_minimal,它使用 avahi 实现 mDNS 解析。[NOTFOUND=return] 表示 avahi 不必安装;在这种情况下,它将被忽略。接下来,大多数 DNS 解析由 nss-dns 执行。最后,我们有 nss-myhostname,它的存在是为了确保你的本地主机名始终可解析。总之,nss-dns 是关键部分,nss-dns 用于读取 /etc/resolv.conf
。
接下来,让我们看一下 /etc/resolv.conf
。该文件包含最多三个 DNS 服务器的列表。服务器按顺序尝试。如果列表中的第一个服务器损坏,则使用第二个服务器;如果第二个服务器损坏,则使用第三个服务器。如果第三个服务器也损坏,则所有操作失败,因为无论你在此列出多少服务器,除了前面三个外,其他都将被忽略。在 Fedora 32 中,/etc/resolv.conf
默认是由 NetworkManager 管理的普通文件,可能如下所示:
```
nameserver 192.168.122.1 ```
这意味着所有 DNS 请求都应发送到我的路由器。我的路由器必须通过 DHCP 配置此设置,从而导致 NetworkManager 将其添加到 /etc/resolv.conf
。
传统 DNS 的问题
传统的 DNS 在简单情况下工作良好,但在添加 VPN 后,问题就出现了。我们考虑两种类型的 VPN:一种是始终启用的隐私 VPN,它是所有网络流量的默认路由;另一种是仅接收内部公司资源流量的企业 VPN。(要在这两种不同类型的 VPN 配置之间切换,请在系统设置的 VPN 配置的 IPv4 和 IPv6 标签底部使用“仅将此连接用于其网络上的资源”复选框。)
现在,如果我们同时连接这两个 VPN,会发生什么呢?首先连接的 VPN 会在 /etc/resolv.conf
中排在第一位,第二个连接的 VPN 排在第二位,接着是你的本地 DNS 服务器。假设所有 DNS 服务器都正常工作,这意味着:
- 如果你先连接隐私 VPN,然后连接企业 VPN,所有 DNS 请求将发送到隐私 VPN,你将无法访问内部企业网站。
- 如果你先连接企业 VPN,然后连接隐私 VPN,所有 DNS 请求将发送到企业 VPN,而没有发送到隐私 VPN。这违背了使用隐私 VPN 的初衷。
如果你在相反的顺序连接 VPN,例如,如果一个连接暂时断开,你需要重新连接,那么你将得到相反的行为。如果你没有注意到这些失败背后的模式,这可能会使问题难以重现。
当然,你并不需要两个 VPN 才会出现此问题。假设你没有隐私 VPN,只有企业 VPN。如果你的雇主注意到它不喜欢的 DNS 请求,它可能会解雇你。如果你每小时向 facebook.com、youtube.com 或其他网站发送 30 个请求,这看起来就像你没有在认真工作。对于员工来说,向雇主发送不必要的 DNS 请求并不总是明智的选择。
如果你仅使用隐私 VPN,失败的情况可能更加严重。假设你的隐私 VPN 的 DNS 服务器暂时离线。由于 /etc/resolv.conf
是一个列表,glibc 将回退到使用正常的 DNS,可能是 ISP 的 DNS 服务器,或者是将所有内容转发到 ISP 的路由器。现在,您的 DNS 查询已发送到 ISP。如果你在错误的国家访问不利于政府的网站,这可能会导致你被监禁或处决。
最后,任何类型的 VPN 都会破坏本地域名的解析,例如 fritz.box,因为只有你的路由器能够正确解析该地址,但你正在将 DNS 查询发送到 VPN 的 DNS 服务器。因此,只要你连接到 VPN,本地资源将无法使用。
综上所述,在 systemd-resolved 之前的现状非常糟糕。显然需要更好的解决方案。现在,让我们看看 systemd-resolved 如何解决这个问题。
使用 nss-resolve 的现代 DNS
首先,让我们看看 /etc/nsswitch.conf
,在 Fedora 33 中它的样子有所不同:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] myhostname dns
nss-myhostname 和 nss-dns 的位置发生了变化,但这只是一个小改动,确保即使你的 DNS 服务器认为本地主机名不可用,它仍然是本地的。重要的改变是添加了 resolve [!UNAVAIL=return]
。nss-resolve 使用 systemd-resolved 来解析主机名,通过其 varlink API(使用 systemd 247)或 D-Bus API(使用旧版本的 systemd)。
总结
随着 systemd-resolved 的引入,Fedora 33 在 DNS 解析方面做出了显著改进,特别是在使用 VPN 时。通过合理配置 DNS,用户能够避免由于 VPN 配置错误而导致的网络访问问题。这为用户提供了更为安全和高效的网络体验。