了解系统解析的DNS,拆分DNS和VPN配置

2020-12-19 08:09:46

因此,在Fedora 33中默认启用了systemd-resolved。大多数用户不会注意到其中的区别,但是如果您使用VPN-或依赖DNSSEC,则更多内容将在本文的底部-然后systemd-resolved可能会很大为您交易。在测试Fedora 33时,我们发现了一个错误报告,其中用户发现systemd-resolved破坏了他的VPN配置。修复此错误之后,没有人报告任何其他问题,我非常有信心向systemd-resolved的迁移将顺利进行。然后Fedora 33发布了,我注意到Ask Fedora和Reddit上有大量用户要求断开VPN的帮助,这些问题是Fedora 33 beta测试人员未能检测到的。自从Ubuntu 16.10起,Ubuntu就默认启用了systemd-resolved,这让我感到特别惊讶,因此我们在这里比Ubuntu落后了整整四年,这对于解决任何问题应该有足够的时间。那么出了什么问题?

首先,让我们谈谈在systemd解决之前事情是如何进行的,以便我们可以找出问题所在以及为什么需要进行更改。我们将看到具有systemd-resolved的拆分DNS与传统DNS有何不同。最后,我们将学习自定义VPN软件如何配置systemd-resolved以避免导致DNS损坏的问题。

我想指出的是,尽管我写了Fedora变更建议并代表systemd-resolved进行了一些布道,但我不是systemd开发人员,也没有为systemd-resolved提供任何代码。

首先,我们来看看在systemd-resolved之前事情是如何工作的。有两个重要的配置文件需要讨论。第一个是/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。

这意味着:首先调用nss-files,它查看/ etc / hosts以查看主机名是否在此处进行了硬编码。如果不是,请调用nss-mdns4_minimal,后者使用avahi实现mDNS解析。 [NOTFOUND = return]表示可以不安装avahi。在这种情况下,它只会被忽略。 (编辑:这是错误的。在下面的注释中提到的Mantas是为了允许尽早返回对.local域的查询,该查询永远都不应返回到其余的nss模块。)然后,大多数DNS解析都是由nss-dns执行的。最后,我们有nss-myhostname,用于确保您自己的本地主机名始终是可解析的。无论如何,nss-dns是这里的关键部分。 nss-dns读取/etc/resolv.conf。

接下来,让我们看一下/etc/resolv.conf。该文件包含最多三个要使用的DNS服务器的列表。按顺序尝试服务器。如果列表中的第一台服务器损坏,则将使用第二台服务器。如果第二台服务器损坏,将使用第三台服务器。如果第三台服务器也坏了,那么一切都会失败,因为无论您在此处列出多少台服务器,前三台服务器都将被忽略。在Fedora 32中,默认情况下/etc/resolv.conf是由NetworkManager管理的纯文件。它可能看起来像这样:

这是一个很常见的例子。这意味着所有DNS请求都应发送到我的路由器。我的路由器必须已经通过DHCP进行了配置,这导致NetworkManager将其忠实地添加到/etc/resolv.conf中。

传统的DNS对于像我们上面这样的简单情况来说都是很好的,但是事实证明,一旦您开始向组合中添加VPN,它就真的被打破了。让我们考虑两种类型的VPN:一种始终启用且是所有网络流量的默认路由的隐私VPN,以及一种仅接收内部公司资源流量的公司VPN。 (要在这两种不同类型的VPN配置之间切换,请使用“系统设置”中VPN配置的“ IPv4”和“ IPv6”标签底部的“仅将此连接用于其网络上的资源”复选框。)

现在,如果我们同时连接两个VPN会怎样?您首先连接的VPN在/etc/resolv.conf中首先列出,其次是您连接的VPN,然后是本地DNS服务器。假设DNS服务器都正常运行,这意味着:

如果您先连接到隐私VPN,然后再连接到公司VPN,则所有DNS请求都将发送到您的隐私VPN,您将无法访问内部公司网站。 (这种情况正是我对systemd-resolve感兴趣的原因。加入Red Hat之后,我发现如果我以错误的顺序连接到我的VPN,就无法访​​问各种redhat.com网站。)

如果您先连接到公司VPN,然后再连接到隐私VPN,则所有DNS都将转到公司VPN,而所有DNS都将不转到您的隐私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。如果您在错误的国家/地区提出错误的DNS请求-例如,如果您访问的政府网站与政府对立-这可能会使您入狱或被处决。

最后,任何一种VPN都会破坏本地域的解析,例如fritz.box,因为只有您的路由器才能正确解决该问题,但是您要将DNS查询发送到VPN的DNS服务器。因此,只要您连接到VPN,本地资源就会中断。

考虑所有因素,systemd-resolve之前的现状非常糟糕。明确需要更好的东西。现在让我们看看systemd-resolved如何解决此问题。

首先,让我们看一下/etc/nsswitch.conf,它在Fedora 33中看起来有点不同:

nss-myhostname和nss-dns切换了位置,但这只是一个很小的更改,即使您的DNS服务器认为不是,也可以确保您的本地主机名始终是本地主机名。此处的重要更改是添加了解析[!UNAVAIL = return]。 nss-resolve通过其varlink API(与systemd 247一起使用)或D-Bus API(与systemd的旧版本一起使用)使用systemd-resolved解析主机名。如果systemd-resolved正在运行,则glibc将在那里停止,并且即使nss-resolve不返回结果,也拒绝继续使用nss-myhostname或nss-dns,因为nss已淘汰了nss-myhostname和nss-dns -解决。但是,如果systemd-resolved没有运行,则它将继续运行(并且,如果解析的不是本地主机名,则将像以前一样使用nss-dns并读取/etc/resolv.conf)。

重要的是,使用nss-resolve时,glibc在执行名称解析时不会读取/etc/resolv.conf,因此您放置在此处的任何配置都将被完全忽略。这意味着写入/etc/resolv.conf的任何脚本或程序都可能已损坏。 /etc/resolv.conf仍然存在:它由systemd-resolved管理,以保持与手动读取/etc/resolv.conf并绕过glibc进行名称解析的程序的兼容性。尽管systemd-resolved支持几种不同的模式来管理/etc/resolv.conf,但默认模式以及Fedora和Ubuntu中使用的模式都是/etc/resolv.conf的符号链接,它是/ run / systemd / resolve的符号链接/stub-resolv.conf,现在看起来像这样:

#此文件由man:systemd-resolved(8)管理。不要编辑。 # #这是一个动态的resolv.conf文件,用于将本地客户端连接到 #systemd-resolved的内部DNS存根解析器。此文件列出了所有 #个配置的搜索域。 # #运行" resolvectl状态"查看有关上行DNS服务器的详细信息 #当前正在使用。 # #第三方程序通常不应直接访问此文件,而只能 #通过/etc/resolv.conf中的符号链接。要管理man:resolv.conf(5) #以不同的方式,用静态文件或其他符号链接替换此符号链接。 # #有关支持的以下模式的详细信息,请参见man:systemd-resolved.service(8)。 #/etc/resolv.conf的操作。 域名服务器127.0.0.53 选项edns0 trust-ad 搜索redhat.com局域网

redhat.com搜索域来自我的公司VPN,但是/etc/resolv.conf的其余部分应该看起来像您的。值得注意的是,127.0.0.53是systemd解析的本地存根响应器。这允许手动读取/etc/resolv.conf的程序无需更改即可继续运行:它们只会在127.0.0.53上与systemd-resolved对话,而不是像以前一样直接连接到真实的DNS服务器。

尽管Ubuntu已经使用systemd-resolve四年了,但它并未从nss-dns切换到nss-resolve,与上游建议相反。这意味着在Ubuntu上,glibc仍会读取/etc/resolv.conf,找到在那里列出的127.0.0.53,然后与systemd-resolved建立IP连接,而不是像Fedora那样通过varlink或D-Bus与之对话。实际的效果是,在Ubuntu上,您仍然可以手动编辑/etc/resolv.conf,与Fedora不同,应用程序将响应这些更改。当然,那将是一场灾难,因为这将导致systemd-resolved中的所有DNS配置都被完全忽略。但是在Ubuntu上仍然有可能。在Fedora上,这根本不起作用。

如果您使用的系统不支持systemd-resolved的自定义VPN软件,则很可能会尝试写入/etc/resolv.conf。

好的,现在我们来看一下/etc/nsswitch.conf和/etc/resolve.conf的变化方式,但是我们实际上没有解释如何配置拆分DNS。无需将您所有的DNS请求发送到/etc/resolv.conf中列出的第一台服务器,systemd-resolved能够基于DNS路由域拆分DNS。

systemd-resolved与DNS路由域和DNS搜索域一起使用。 DNS路由域仅确定您的DNS查询转到哪个DNS服务器。它无法确定IP流量去往何方:这将是IP路由域。通常,当人们谈论“路由域”时,它们可能是指IP路由域,而不是DNS路由域,因此请注意不要混淆这两个概念。对于本文的其余部分,我将使用“路由域”或“ DNS域”来表示DNS路由域。

DNS搜索域也不同。当您查询的名称仅是一个标签(一个没有点的域)时,搜索域将附加到您的查询中。例如,由于我当前已连接到Red Hat VPN,因此我为redhat.com配置了搜索域。这意味着如果我对仅一个标签的域进行查询,则redhat.com将被附加到查询中。例如,我可以查询bugzilla,这将被视为对bugzilla.redhat.com的查询。这可能无法在您的网络浏览器中使用,因为网络浏览器喜欢将单标签域转换为网络搜索,但确实可以在DNS级别使用。

在systemd解析中,每个DNS路由域都可以或可以不用作搜索域。默认情况下,systemd-resolved将为每个没有波浪号前缀的已配置路由域添加搜索域。例如,〜example.com仅是路由域,而example.com既是路由域又是搜索域。还有一个全局路由域〜。

$ resolvectl 全球 协议:LLMNR = resolve -mDNS -DNSOverTLS DNSSEC =否/不受支持 resolv.conf模式:存根 链接2(enp4s0) 当前范围:DNS LLMNR / IPv4 LLMNR / IPv6 协议:+ DefaultRoute + LLMNR -mDNS -DNSOverTLS DNSSEC =否/不受支持 当前的DNS服务器:192.168.1.1 DNS服务器:192.168.1.1 DNS域:lan 连结5(tun0) 当前范围:DNS LLMNR / IPv4 LLMNR / IPv6 协议:+ DefaultRoute + LLMNR -mDNS -DNSOverTLS DNSSEC =否/不受支持 当前的DNS服务器:10.8.0.1 DNS服务器:10.8.0.1 DNS域:〜。 链接9(tun1) 当前范围:DNS LLMNR / IPv4 LLMNR / IPv6 协议:-DefaultRoute + LLMNR -mDNS -DNSOverTLS DNSSEC =否/不受支持 当前的DNS服务器:10.9.0.1 DNS服务器:10.9.0.1 10.9.0.2 DNS域:example.com

为了简化此示例,我从上面的输出中删除了几个不有趣的网络接口:我未使用的第二个以太网接口,我未使用的Wi-Fi接口wlp5s0和我假定为libvirt使用的两个虚拟网络接口。这意味着我们只需要考虑三个接口:普通以太网enp4s0,隐私VPN tun0和公司VPN tun1。我当前正在运行NetworkManager 1.26.4,因此我也对输出进行了一些调整,使其看起来就像我在使用NetworkManager 1.26.6时一样(我将在下面讨论区别),因此该示例将是不错的选择为将来。让我们看一下几点注意事项:

tun1配置了-DefaultRoute和example.com的路由域。 (它也有example.com的搜索域,因为它不是以波浪号开头。)

systemd-resolved首先根据要查询的域名来确定哪个网络接口最适合您的DNS查询,然后将查询发送到与该接口关联的DNS服务器。在这种情况下,对example.com,foo.example.com等的查询将发送到10.9.0.1,因为这是为tun1配置的DNS服务器,该服务器与域example.com相关联。由于tun0具有全局域〜,因此所有其他请求都发送到10.8.0.1。由于启用了隐私VPN,因此什么也不会到达192.168.1.1,那将是一场隐私灾难。很简单,对吧?

如果您不使用隐私VPN,则不会有任何〜。域配置。在这种情况下,您的查询将转到具有+ DefaultRoute的所有接口。例如,如果从上述配置中删除了tun0,则不会将例如example.com的查询发送到我的路由器192.168.1.1,这很好,因为tun1是我的公司VPN,并且应该只接收与其自己的DNS相对应的DNS查询域。

systemd-resolved如何提出上述配置?没错我在上一节中写的所有内容均假定您使用的是NetworkManager,因为systemd-resolved实际上并未决定将DNS发送至何处。这是高级网络管理软件(通常是NetworkManager)的全部责任。如果您使用自定义VPN软件(不是NetworkManager VPN插件的任何软件),则该软件还负责配置systemd-resolved并与NetworkManager配合使用。

NetworkManager通常在配置systemd-resolved使其正常工作方面表现出色,因此大多数用户不需要进行任何更改。但是,如果您的DNS无法正常运行,并且您运行resolvectl并发现systemd-resolved的配置不是您想要的,请不要报告针对systemd-resolved的错误!而是针对NetworkManager报告一个错误(如果您确信确实存在错误)。

如果您不使用NetworkManager,仍可以使systemd-resolved随心所欲,但您自己一个人。它不会为您自己配置。

如果您在2020年12月阅读此书,则可能使用的是NetworkManager 1.26.4或更早版本。这里的情况略有不同,因为NetworkManager最近实现了主要的行为更改。以前,NetworkManager始终会配置〜。一个网络接口的域。这意味着systemd解析的DefaultRoute设置的值始终会被忽略,因为〜。优先。因此,NetworkManager完全不用理会DefaultRoute。我告诉过您,我在上面的示例中对输出进行了一些改动。实际上,NetworkManager 1.26.4已在我的tun1公司VPN上配置了+ DefaultRoute。这没有任何意义,因为它只应接收example.com的DNS,但以前没关系,因为以前总是〜。域在某些接口上。如果您不使用任何VPN,则您的以太网或Wi-Fi接口将收到〜。域。但是从1.26.6开始,NetworkManager现在仅配置〜。当您使用隐私VPN时,您可以选择“域”,因此DefaultRoute设置现在很重要。

在NetworkManager 1.26.6之前,您可以单独依靠resolvectl域查看DNS的去向,因为总会有〜。域。由于NetworkManager 1.26.6不再总是创建〜。域,将不再起作用。您需要改用resolvectl的完整输出,因为这将显示DefaultRoute设置,这一点现在很重要。

假设您的公司VPN是example.com。您希望对example.com的所有请求都可以由VPN来解决,因为NetworkManager会为其创建适当的路由域。但是您还希望VPN也可以解决对其他域(例如example.org)的请求。你是做什么?

大多数VPN协议都允许VPN告诉NetworkManager VPN应该解析哪些域。其他允许在导入到NetworkManager的连接配置文件中指定此设置。遗憾的是,并不是所有的VPN都能正确地做到这一点,因为对于传统的非拆分DNS而言,这无关紧要。更糟糕的是,GNOME系统设置中没有图形配置可解决此问题。确实应该有。但是现在,您必须使用nmcli来设置VPN连接配置文件的ipv4.dns-search和ipv6.dns-search属性。令人困惑的是,即使该设置显示为“搜索”,它也会创建一个路由域。希望您永远不必为此烦恼。如果这样做,请考虑与您的IT部门联系,要求他们修复VPN配置以正确声明其DNS路由域,因此您无需手动对其进行修复。 (有时这确实可行!)如果您发现需要公司VPN解决的其他域,则可能必须执行多次。

所谓“自定义VPN软件”,是指不是NetworkManager插件的任何VPN。这包括由VPN服务提供的专有VPN应用程序,以及由NetworkManager以外的其他程序调用时的打包软件,如openvpn或wg-quick。

如果您的自定义VPN软件损坏了,您可以报告VPN软件的错误,以寻求对systemd-resolved的支持,但是,如果可能的话,最好抛弃自定义软件并改为使用NetworkManager配置VPN。使用自定义VPN软件的确只有两个很好的理由:如果NetworkManager没有适合您公司VPN的插件,或者您需要使用Wireguard,而您的桌面尚不支持Wireguard。 (NetworkManager本身支持Wireguard,但GNOME尚不支持,因为Wireguard是特殊的,与其他VPN区别对待。欢迎您提供帮助。)

如果您使用NetworkManager来配置VPN(如桌面开发人员所希望的那样),则NetworkManager将负责配置systemd-resolved。 Fedora出厂时默认安装了多个NetworkManager VPN插件,因此绝大多数VPN用户都应该能够配置您的VPN

......