[OBSOLETED] Ubuntu 18.04.1 上配置 DNSCrypt + DNSSEC 的本地 DNS 服务器

Re:Linked
本文距离最后更新已超过 180 天。其中的内容可能已经不准确或者完全错误。

折腾 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。

1
2
3
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。加两行:

1
2
User=root
Group=root

然后:

1
2
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 项目。

1
2
3
4
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

然后在 dnscrypt-proxy.toml 中把 forwarding_rules 改为:

1
forwarding_rules = 'dnscrypt-proxy-forwarding-rules.txt'

然后:

1
2
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 相关的东西,例如:

1
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 补充:

缓存

1
2
[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 的话,在界面上配置一下:

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


评论