Linux 上配置 DNS 踩坑记

最近看到了一篇谁动了我的 DNS 解析?(重制版),突然想起自己上次在高铁上因为没有把 dns 改成路由器提供的 dns,导致无法找到上网认证的经历,于是决定好好配置一下 dns。

由于众所周知的原因,ISP 提供的 DNS 服务器通常不是很靠谱,因此我用 dnsmasq 和 dnscrypt-proxy 在本地跑了个 dns 服务器。然而,一些内网地址却只能通过网络接口的 dns 服务器提供解析(比如上网认证的页面)。因此,我们希望当查询 dns 时,可以先询问本地的 dns 服务器,如果返回错误再询问接口提供的 dns。

我目前的方法是在 NetworkManager.conf 中设置 dns=none,关闭 systemd-resolved,手动在 resolv.conf 中设置 dns 服务器为 dnsmasq 的监听地址。显然如果遇到的上网认证或者需要通过 VPN 访问内网设备之类的情况就会挂。

于是,配(zhe)置(teng) DNS 之旅就开始了。

NetworkManager

注意到 NetworkManager 可以配合 dnsmasq 使用,只需要将 dns 设置为 dnsmasq 即可。 编辑 /etc/NetworkManager/NetworkManager.conf

1
2
3
4
# Configuration file for NetworkManager.
# See "man 5 NetworkManager.conf" for details.
[main]
dns=dnsmasq
停掉 dnsmasq.service,将 /etc/dnsmasq.conf 软链接到 /etc/NetworkManager/dnsmasq.d/dnsmasq.conf,然后重启 NetworkManager.service。大功告成!本文就写到这里,感谢阅读。

还没结束!别忘了标题是什么!

dnsmasq 的分流和 hosts 的功能一切正常。然而,当我查询了几个我经常访问的域名时,dnsmasq 的返回和 dnscrypt-proxy 的返回值并不一样。

1
2
3
4
5
6
7
8
9
10
$ dig github.com @127.0.0.1
...
;; ANSWER SECTION:
github.com. 600 IN A 20.205.243.166
...
$ dig github.com @127.0.0.1 -p 5533 #dnscrypt 的端口
...
;; ANSWER SECTION:
github.com. 21 IN A 140.82.121.3
...
查阅 dnsmasq 的日志,翻过一大堆 cached github.com is xxx,找到:
1
2
3
May  9 22:24:38 dnsmasq[14956]: forwarded github.com to 127.0.0.1#5533
May 9 22:24:38 dnsmasq[14956]: forwarded github.com to 192.168.1.1
May 9 22:24:38 dnsmasq[14956]: forwarded github.com to fe80::1
此时我怀疑可能是配置文件写错了。检查配置文件,发现 127.0.0.1#5533 确实是唯一的服务器。网上有人说 dnsmasq 会把网络链接提供的 dns 通过 dbus 发送给 dnsmasq,dnsmasq 将这两个 dns 服务器与我指定的本地 dns 合并,同时向 \(3\) 个 dns 服务器询问。dnsmasq 会直接返回了较快返回的那个而因为本地 dns 最后用的是 cloudflare 的 doh,因此速度较慢,没有被 dnsmasq 使用。

查阅了互联网发现并没有设置优先级之类的选项。因此我抛弃了在 NetworkManager 中使用 dnsmasq 的想法。(还有一个原因是听说 NetworkManager 拉起来的 dnsmasq 会忽略部分配置文件,但不知道是真是假,我也懒得验证了)

systemd-resolved

有请下一位候选人!
systemd-resolved!

虽然之前配置 dnsmasq 时因为端口冲突直接关掉了,但其实让这两位共存也不难。 将 dnsmasq 改个端口:

1
2
3
4
$ vim /etc/dnsmasq.conf
...
port=5353
...
/etc/systemd/resolved.conf 中设置 dns 服务器:
1
2
[Resolve]
DNS=127.0.0.1:5353 [::1]:5353
此时去查了下 Man Page,上面有这么一句话:

DNS requests are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from systemd-networkd.service(8) or set at runtime by external applications.

看来这个也没办法满足我们的要求。看来这个问题目前没有解决方案,本文到此结束。

然而测试一下,神奇的事情发生了:

1
2
3
4
5
6
7
8
9
10
11
$ dig github.com 
...
;; ANSWER SECTION:
github.com. 600 IN A 20.205.243.166
...

$ dig github.com
...
;; ANSWER SECTION:
github.com. 22 IN A 140.82.121.4
...
第二次查询返回了 dnscrypt-proxy 给出的 ip。并且日志中也有相应的条目:
1
May 10 14:58:52 dnsmasq[1316]: reply github.com is 140.82.121.4
似乎在返回后 systemd-resolved 仍等待了所有 dns 服务器的恢复,然后将所有回复整合了。而且配置文件中的 dns 服务器优先级似乎要高于链接提供的 dns 服务器,完全符合我们的要求。

总之就是这么神奇的解决了。那么本文就这样结束了。


Linux 上配置 DNS 踩坑记
https://blogs.sving1024.top/posts/6757/
发布于
2025年5月10日
许可协议