折腾 DNSCrypt(+DNSSEC)之旅。系统版本 Ubuntu 18.04.1 LTS(即 bionic)。不过估计也适用于 Ubuntu 17.04 和 17.10。
此解决方案可以满足日常需求,但不是特别稳定,而且会降低解析速度,故不太建议用于生产环境。
Outvi 才疏学浅,对 Linux 系统配置不太了解,对文档的解读也可能有误差故以下内容可能不准确,欢迎指正。
若只是需要在 Firefox 上使用 DNS-over-TLS (和 DNSSEC),可直接使用其自带的 TRR(Trusted Recursive Resolver)。 配置方法: Mozilla Wiki (英文) / jszbug.com(中文)
修改 DNS 这事……
从 17.04 开始,Ubuntu 的 DNS 解析不再靠那个 NetworkManager 操作的 dnsmasq 了,而是交给了 systemd。自此呢,许多 Ubuntu 的本地 DNS 服务器方案都不准确了(不过 GNOME/KDE 界面的设置应该没问题)。咱就先铺垫一下。
如何修改系统默认 DNS?修改 resolved.conf
根据 man resolved.conf
的说法,把 DNS 设定写到 /etc/systemd/resolved.conf
。同时为了防止本地 dnscrypt-proxy 的问题,也指定了一个后备 DNS。
DNS=127.0.0.54
FallbackDNS=9.9.9.9
(其余略)
如果也要折腾 DNSSEC 的话,把下面的 DNSSEC 也改一下。可能是因为 DNSSEC 并不是很普及,我个人在强行开启 DNSSEC 的时候体验很差(大多数域名不能解析)。建议先不要设置为 DNSSEC=true
,而改为DNSSEC=allow-downgrade
。
考虑到是本地 DNS 服务器,而且 dnscrypt-proxy 已经有缓存功能了,可以在 resolved.conf 中指定 Cache=false
。(虽然有可能这就是默认选项)
部分程序(例如 dig)可能不会按照 systemd-resolved 的配置工作,所以 resolv.conf 也需要按照下文设置的 DNS 服务器 IP 改一下。systemd 基本不管 resolv.conf,所以还是“自己动手,丰衣足食”吧。
dnscrypt-proxy
,启动!
dnscrypt-proxy 的安装请参阅文档。
配置呢,按这里的 Setting up dnscrypt-proxy (general guidelines)
填写就可以。
我修改了的地方:
listen_addresses
改为在resolved.conf
中写的那个地址(例如listen_addresses = ['127.0.0.54:53']
)server_names
从列表里找几个舒服的写吧,反正会自动选择最快的。ignore_system_dns = true
,因为你自己就是系统 DNS。这里吐槽 Google 的 DNSCrypt 服务器的配置(sdns://...)用的是域名(dns.google.com)而不是 IP。- 后面基本上不用改了。
sudo service dnscrypt-proxy start
,跑起来吧。如果出错记得检查一下端口占用和配置文件格式。
一个你可能会遇到的问题:
权限不够,53 端口监听不了?
改 /lib/systemd/system/multi-user.target.wants/dnscrypt-proxy.service
。加两行:
User=root
Group=root
然后:
sudo systemctl daemon-reload #重新加载下配置
sudo services dnscrypt-proxy restart
差不多了。dig white.ac.cn @127.0.0.54
测试一下,应该有了。
小补充:dnsmasq-china-list
把所有的域名都通过 dnscrypt-proxy 进行解析会使 CDN 无法发挥出它的能力。虽然我们有 edns-client-subnet
,但这玩意的支持依然不是很广泛,而且 dnscrypt-proxy 似乎没有这个功能,所以我们需要手动处理。这里我们用到了 felixonmars 大佬的 dnsmasq-china-list 项目。
git clone https://github.com/felixonmars/dnsmasq-china-list.git --depth=1 cd dnsmasq-china-list make dnscrypt-proxy sudo cp dnscrypt-proxy-forwarding-rules.txt /etc/dnscrypt-proxy/dnscrypt-proxy-forwarding-rules.txt
shell
然后在 dnscrypt-proxy.toml 中把 forwarding_rules
改为:
forwarding_rules = 'dnscrypt-proxy-forwarding-rules.txt'
然后:
sudo systemctl daemon-reload #重新加载下配置
sudo services dnscrypt-proxy restart
DNSSEC
有些 DNSCrypt 服务器是支持 DNSSEC 的。当连接到这些服务器的时候(当然你也可以通过在 DNSCrypt 的配置文件中写 require_dnssec = true
来只使用那些支持 DNSSEC 的服务器)dig paypal.com +dnssec @127.0.0.54
,你将可以看到一些 DNSSEC 相关的东西,例如:
paypal.com. 593 IN RRSIG A 5 2 300 20180901094929 20180802084929 11811 paypal.com. hJxmJDkNgD6w1Qep+wq7izH87CbL1rvb6Ftcd9xHCcImtpvRFin6hQIM QmcMT8empxN6eBvnn/++Ujt1QQ2tAQGmHpGmurcALjAHBZkN3otwXLvq 135WJB/5pISk6Qt3aW2k4YCGg/nIQ76uw5FA0rUbMrO/raT0R2nUeDMk PZs=
而对于那些 DNSSEC 验证失败的 DNS 记录而言,例如 dig sigfail.verteiltesysteme.net +dnssec @127.0.0.54
,回复将是空的(不过在关闭 DNSSEC 之后又会有回复)。
dig 可以通过 +dnssec
来启用 DNSSEC 验证。至于系统层面上的 DNSSEC 验证,systemd-resolve
本来有一个比较优雅的方案(resolved.conf
中设置 DNSSEC=true
,然后各种东西应该已经配置好了),不过我在 DNSSEC=true
之后,系统完全解析不出结果。dig 没问题,估计是因为 DNSSEC 验证全都不通过。即使手动把根信任锚加入了 dnssec-trust-anchors.d
之后也没有效果。原因未知,也有可能是我的网络问题(折腾 DNSCrypt + DNSSEC 时使用的网络不太好用)。过段时间找一个稳定点的网络再测试。
9/26 补充:
缓存
[WARNING] /etc/dnscrypt-proxy/public-resolvers.md: open example.tmp: read-only file system
[WARNING] /etc/dnscrypt-proxy/public-resolvers.md.minisig: open example.tmp: read-only file system
改一下缓存地址吧...本来想着写到 /var/cache 里某个位置,查看的时候发现其实文件夹已经建立好了,遂把两个缓存文件夹位置分别改一下:
cache_file = '/var/cache/dnscrypt-proxy/cache-public-resolvers.md'
以及
cache_file = '/var/cache/dnscrypt-proxy/cache-opennic-servers.md'
结果
systemd-resolve --status
可以看到各个连接所使用的 DNS 解析方案。man resolved.conf
提到,per-link 设定会优先于系统级设定,所以如果看到你的连接上使用的 DNS 并不是本地的 DNS 的话,在界面上配置一下:

KDE UI Setting
之后重新连接,就能看到效果了。