如何禁用systemd-resolved并使用dnsmasq解析DNS?

Ubuntu 16.10+ 使用 systemd-resolved 作为 DNS 解析器。
我更喜欢 16.04 使用的设置,即使用 dnsmasq 作为解析器。
在 16.10+ 版本上,特别是在 17.04 上,我该如何做到这一点?

也许这个链接可以帮到你:https://askubuntu.com/questions/1032450/add-dnsmasq-for-cached-fast-resolution-and-keep-systemd-resolved-18-04 - cmak.fr
为什么我们需要一个解析器呢?干嘛不直接使用1.1.1.1或者8.8.8.8作为解析器呢? - recolic
2@recolic 缓存,防止某些记录被解析(广告、追踪器等),为您自己的记录定义新的顶级域名,速度 - NeuronButter
4个回答

dnsmasq软件包仍然可在16.10和17.04版本中获得。

  1. 在禁用systemd-resolved之前,安装dnsmasq和依赖项(或至少下载它们的软件包):

    sudo apt-get install dnsmasq
    
  2. 禁用systemd-resolved并验证dnsmasq是否正在运行:

    sudo systemctl stop systemd-resolved
    sudo systemctl disable systemd-resolved
    
    systemctl status dnsmasq
    
  3. dnsmasq进行个性化设置。应用您的设置后,重新启动dnsmasq

    sudo systemctl stop dnsmasq
    sudo systemctl start dnsmasq
    
在第二步完成之后,直到第三步完成之前,您可能没有一个可用的系统解析器。您可能需要重新启动网络子系统(或者简单地重新启动)以使dnsmasq与默认配置一起正常工作。在我的测试中,将已知的DNS服务器添加到/etc/dnsmasq.conf并重新启动dnsmasq就足以使其在liveCD环境中正常工作。

1很棒的答案,似乎是唯一的解决方案,当禁用NetworkManager不可接受时! - bogl
3对我来说,这是一个很好的答案,但也需要根据@blabla的回答采取额外的步骤,将dns=dnsmasq配置添加到/etc/NetworkManager/NetworkManager.conf文件中。 - Roberto Tyley
我也是。在与systemd-resolved和unbound纠缠不清后,切换到dnsmasq在Ubuntu 17.10上解决了问题。不过,我确实需要使用blabla的补充。 - Alberto L. Bonfiglio
在苦苦挣扎了几天后,这个方法解决了问题。非常感谢。 - Andre Nickatina

除了@quixotic的回答之外:
请确保您在/etc/NetworkManager/NetworkManager.conf中有以下内容:
[main]
dns=dnsmasq

如果你需要添加它,就像这样重新启动NetworkManager:
sudo systemctl restart NetworkManager

而且 /etc/resolv.conf 需要是一个指向 /var/run/NetworkManager/resolv.conf 的符号链接。可以这样完成

sudo rm /etc/resolv.conf; sudo ln -s /var/run/NetworkManager/resolv.conf /etc/resolv.conf

实际上,我将其设置为dns=default,这样就可以正常工作了,因为我是通过NetworkManager定义的名称服务器,而不是在dnsmasq中定义的;这对我来说很有效 - NM通过系统托盘从KDE的NM配置中获取名称服务器的设置。顺便说一下,我在家庭网络上使用固定IP。 - pbhj
1这一步对我来说是@quixotic答案的必要补充(Ubuntu 17.04,完全安装,非LiveCD)。 - Roberto Tyley

对于(X)Ubuntu 18.04(请参阅我在stackexchange上的回答)。
这是它的副本(我应该复制一份吗?)
这是(X)Ubuntu 18.04 Bionic的解决方案。
安装dnsmasq sudo apt install dnsmasq 禁用端口53上的systemd-resolved监听器(不要触碰/etc/systemd/resolved.conf,因为升级时可能会被覆盖)。
$ cat /etc/systemd/resolved.conf.d/noresolved.conf 
[Resolve]
DNSStubListener=no

重新启动它
$ sudo systemctl restart systemd-resolved

(或者通过$ sudo systemctl disable systemd-resolved.service完全禁用它)

删除 /etc/resolv.conf 并重新创建。这很重要,因为 resolv.conf 默认是一个指向 /run/systemd/resolve/stub-resolv.conf 的符号链接。如果不删除符号链接,在重新启动时,systemd 会覆盖该文件(即使我们已经禁用了 systemd-resolved!)。此外,NetworkManager(NM)会检查是否为符号链接以检测 systemd-resolved 的配置。

$ sudo rm /etc/resolv.conf
$ sudo touch /etc/resolv.conf

禁用NM覆盖/etc/resolv.conf文件(虽然手册中描述了rc-manager选项,但它并不起作用):
$ cat /etc/NetworkManager/conf.d/disableresolv.conf 
[main]
dns=none

重新启动它:
$ sudo systemctl restart NetworkManager

告诉dnsmasq使用NM的resolv.conf文件。
$ cat /etc/dnsmasq.d/nmresolv.conf 
resolv-file=/var/run/NetworkManager/resolv.conf

重新启动它:
$ sudo systemctl restart dnsmasq

使用dnsmasq进行解析:
$ cat /etc/resolv.conf 
# Use local dnsmasq for resolving
nameserver 127.0.0.1

根据systemd-resolved的手册,systemd-resolved通过三种不同的接口提供名称解析服务:
1. "总线上公开的完整功能API systemd-resolved" 2. "本地DNS存根侦听器, IP地址为127.0.0.53,位于本地回环接口上" 3. 根据RFC3493定义以及相关解析器函数(包括gethostbyname(3)),使用glibc getaddrinfo(3) API。这个API得到广泛支持,不仅限于Linux平台。目前它无法公开DNSSEC验证状态信息,并且只支持同步操作。此API由glibc名称服务切换(nss(5))支持。为了让glibc的NSS解析器函数通过systemd-resolved解析主机名,需要使用glibc NSS模块nss-resolve(8)。
看起来前两个接口不会干扰正常的DNS解析,问题很可能出现在第三个接口。
nss-resolve的手册中:

要激活NSS模块,请在/etc/nsswitch.conf文件中以"hosts:"开头的行中添加"resolve"。具体来说,建议将"resolve"放在/etc/nsswitch.conf的"hosts:"行中的较早位置(但在"files"或"mymachines"条目之后),紧接着是"dns"条目(如果存在),然后是"[!UNAVAIL=return]",以确保DNS查询始终通过systemd-resolved(8)路由,如果该服务正在运行,但如果此服务不可用,则通过nss-dns路由。

所以需要做的是在/etc/nsswitch.conf的"host:"行中使"dns"位于"resolve"之前。然后getaddrinfo应该简单地遵循/etc/resolv.conf。

这个解决方案只是防止systemd-resolved处理所有DNS解析请求,并不限于特定的网络管理器。它还确保LLMNR和mDNS服务正常运行。

(我对Linux下的名称解析工作不太熟悉,也不确定我从这些手册中理解的是否正确。如果我有什么错误,请指出。谢谢 :))