前言

为什么要写这篇文章呢?简而言之,咱回到了教育网,可以说是很糟糕的网络环境了,于是想调教下它

为什么要加密 DNS

域名系统(Domain Name System),是把我们想访问的域名翻译成 IP 的系统,这是一个发明于 1983 年的系统,当时的互联网还很小,设计时未考虑现代安全性的需要。DNS 使用 TCP 和 UDP 端口 53 进行明文传输,这使得传输路径上的任何人包括 ISP 都可能监听、阻断、劫持、篡改 DNS 查询请求,比如某省联通,有很长一段时间,总是把我每天打开的第一个未加密的 HTTP 页面劫持到 10010,又比如某些 DNS 服务商,劫持查询请求,打包贩卖用户浏览记录,投放精准广告早已是摆在了明面上
参考
Cloudflare Blog - DNS Encryption Explained
蓝点网 - 为什么总是弹广告:看完这些,你还敢用114DNS吗?
蓝点网 - 这就是为什么要启用加密DNS服务 泰国运营商泄露83亿条用户访问记录
根据网络安全相关法规,互联网服务提供商(ISP)必须保留日志,对于教育网,更是有额外的审计系统,包括限制路由器和终端数、实名认证上网、详细日志保留半年以上。所以教育网用户其实是格外没有隐私的,我的看法是,至少,我们应该有知情权,本文也是因此而作
起因是那天闲着没事,将 WLAN 自动获得的 DNS 改成了自定义,结果直接断网了,无论改成国内外 DNS 都会断,搜索了下,这是 53 端口白名单了,大概是为了将流量牵引到内部缓存,也可能也是为了防止未经认证的用户通过 53 端口连接到外部服务器来免费上网。甚至于 ping 1.1.1.1 1ms,这是把 1.1.1.0/24 配到内网了啊…干出这种事的国内外都不少,好在 1.0.0.1 是正常的

怎样加密 DNS

HTTPS(安全超文本传输​​协议)是 HTTP(超文本传输​​协议)的扩展,也可称作 HTTP over TLS,曾发布过的版本有 SSL 1.0/2.0/3.0,TLS 1.0/1.1/1.2/1.3,TLS 相关内容我会在下一篇文章中详细讲述。虽然所有的 SSL 版本都已被弃用,但 SSL(安全套接层) 这个名称还是保留了下来并常与 TLS(传输层安全性协议) 混用

加密 DNS 最初的工作是 DNSSEC(域名系统安全扩展),需要对 .org .com 等区域及根区进行签名,同时不仅需要网络运营商在递归解析器中专门启用,还要域名所有者在区域权威服务器中启用,所以至今也没有获得广泛支持,且其对于中间网络设备进行的监听仍然没有抵御能力。另外还有 DNSCrypt 协议,用自己的方法实现了加密 DNS,且与 DNSSEC 兼容,但我没怎么接触过,故以上两种暂且不谈

重点是接下来的两种 DNS 加密方式,DoT 和 DoH,前者即 DNS over TLS,采用 TLS 在 853 端口发出加密的 DNS 请求,后者即 DNS over HTTPS,如平时访问网页般使用 HTTPS 协议在 443 端口发出加密的 DNS 请求。但是,DoT 使用了非常规端口 853,甚至有人称之为 DoT 的原罪,因为封掉 853 即可,主流的意向包括我自己都更喜欢 DoH,因为基于 HTTP,可以自然而然的受益于 H2/QUIC 所带来的优化,也可以很好的隐藏在网页后面,同时还易于部署

但各地网络环境不同,我建议可以都使用一段时间再选出适合自己的,比如我现在是教育网 CERNET2 IPv6,使用 [2606:4700:4700::1111]:443(这个是 Cloudflare DNS 的 IPv6 地址),延迟才 90ms,并且稳定的一批,完全不像 1.0.0.1:443 那样几乎无法使用。对,我也是最近才发掘出 IPv6 的神奇
下面介绍具体的工具或方法(注:以下内容均在非代理环境下实验)

Simple DNSCrypt

V2EX - 有什么 Win 上的 DoH/DoT 的防污染 DNS 方案吗?
简单搜索后在 V2EX 上得知这款开源的工具,如名字所言一样,的确是很 Simple 的一个工具,内置了 DNSSEC、DNSCrypt、DoH 和上百个 DNS 服务器,不论是大公司如 Cloudflare DNS、Google DNS、NextDNS 还是个人搭建的服务,基本都囊括进去了。可以根据服务器支持的协议,服务器是否过滤内容,服务器是否记录日志来筛选,如果使用默认设置(DNSSEC、DNSCrypt、DoH 全支持,且服务器不过滤内容、不记录日志),大约还剩下六十多个
Simple DNSCrypt 使用起来确实很简单,但和上面帖子中题主反馈的一样,访问国内网站极大概率会被解析到海外 CDN(如果不使用 ECS 的话),开个百度都要转圈十秒,使用体验实在太差,只得卸载
注:这里要分辨一下,DNSSEC 是指域名系统安全扩展,而 ECS 则是在发送解析请求时附上自己的 subnet,以便获得更近的 CDN 节点

YogaDNS

此软件是在某个博客上看到的,的确是很方便易用的工具,支持 DNSSEC、DNSCrypt 和 DoH,还可以自定义域名规则,以达到分流解析和广告拦截的效果。但是稍经搜索,有用户(包括我)顾虑的是:

  • There’s no Privacy Policy on their website/网站上没有隐私政策
  • It’s not open-source/不开源

甚至开发商的资料都不怎么搜索得到,只知道这是一家俄罗斯公司,于是我选择再找寻下别的解决方法。对于读者,还请自己斟酌是否应该使用 YogaDNS,我个人是比较不推荐的
2020.09.06 更新:
在两天前,开发商 Initex LLC 发布了他们的隐私政策,有需要可以自行去查看

V2▢▢▢

然后我想到的就是这个复杂的网络工具,由于各种因素,不作过多介绍。使用它的 Dokodemo-door、DNS 协议和路由模块,可以简单而灵活的实现 DNS 分流解析、远程解析、广告拦截和 DoH,不放配置了,但至少在 Cloudflare ESNI Checker 里的结果是完全没问题的,前三项都是绿色
然而这毕竟是一款主要用于▢▢的工具,非要在无代理环境下使用好像不是很顺手(当然也有可能是我配置的不对),如各种间歇性断网,页面部分区域加载不出来(?)等等,故放弃单独作为加密 DNS 解决方法使用

mos-chinadns

2020.11.26 更新:
mos-chinadns 已于近日更名为 mosdns,趁此我也把这部分更新一下。新重构的 mosdns 开始走插件化了,唉,明明已经很好用了,又得重新学习了
主要内容有:替换项目的名称、修订部分描述、增加我的分流规则、增加 Linux 系统使用方法
2020.12.05 更新:
我错了,这并不是更名,重构的 mosdns 继续保持了 mos-chinadns 所有特性,但配置文件不兼容,且配置方式有很大的改变,所以我还是把这部分的标题改回来吧。这部分会存档,供参阅,但不会再更新了

2022年更新:
才发现 mos-chinadns 已经删库(两年没用了不知道),以下部分文字已完全失去参考意义,但方法是相通的,有兴趣的读者请转到 mosdns

先附上项目地址:https://github.com/IrineSistiana/mos-chinadns
同样是在 V2EX 上看到的,也是我最终使用的方案
V2EX - 请问有没有 win10 能用的解决 dns 污染的工具
真心地,赞美开发者,因为 mos-chinadns 的使用体验真的不能再舒服了,跟着详尽的 Wiki 指示,简单下载好 winse 就可以使用了(甚至开发者还提到了 YogaDNS 并指出其很方便但非开源)
mos-chinadns 实现的几个特性实在太棒了

  • TCP、DoT和DoH协议无需每次请求都进行握手。使绝大部分请求延时和UDP一样低
  • 基于IP和域名黑白名单的分流策略。用户可自由配置,实现多种分流方式,如:多条线路分流、IP+域名混合分流、抢答式分流、链式分流等
  • 数据文件与配置文件独立。支持极简格式一行一条的IP和域名表。也支持v2ray的geoip.datgeosite.dat规则文件。方便更新和共用
  • 没有依赖,无需编译。使用默认配置文件和列表解压即可运行。Windows平台还有一键管理脚本

如作者所言,默认配置已经是 99.9% 本地 CDN 友好,但那些我特别喜欢的点非得讲出来不可

自带的配置文件已配置好两个名为 localremote 的上游,分别指向 alidns 和 Cloudflare DNS,因为目前配置了 IP 证书,且能直接使用 IP 查询的 DoH 好像就这两个,腾讯尚在公测中的 DNSPod 都并未配置 IP 安全证书,这点是我比较纠结的,因为要全局接管系统 DNS,并且修改了系统 DNS 为 127.0.0.1[::1],那最好我们使用的 DoH 能直接通过 IP 访问查询(我怕引起死循环)。同时 DNSPod 的 DoT 和 DoH 还在公测,我测试时 Local DNS 全国乱飞,时而北京时而广州(当然解析速度还是很快的,据官方说是后端 ECS 分配递归出口,故解析出来的线路和区域与 Local DNS 无关)

甚至默认配置的 Cloudflare DNS 使用了 1.0.0.1,这是都考虑到我无法使用 1.1.1.1 了吗

开发者实在过于贴心,以至于我对配置的修改仅仅是给 localremote 都添加了一条拦截广告域名的规则,这里要注意一点,本地规则中 domain: "deny:./reject-list.txt|accept:./chn_domain.list|accept:./google-cn.txt|deny_all" 广告域名要放在国内域名之前,原因仔细想想应该就知道,如果上一条策略命中了,就不会匹配下一条策略了,而 reject-list.txt 中包含 ad.exampledomain.com,chn_domain.list 中包含 exampledomain.com,我也是用了一段时间才突然想明白。而 reject-list.txt,取自 AdGuard DNS Filter、EasyList、EasyListChina 等仓库,共计四万多条,实现 DNS 级别的广告屏蔽和跟踪器拦截(当然,mos-chinadns 的域名表不支持也不可能支持 Adblock Plus 语法,不能更精准的拦截广告链接,建议配合 uBlock Origin 一同使用)

Windows 下使用开发者提供的 Shell 脚本,将 mos-chinadns 注册为服务并启动,启动后在 Cloudflare ESNI Checker 检查,与 V2▢▢▢ 同样的三绿一红,说明运行正常

还有就是开发者建议一周更新一次国内域名和 IP 列表,并提供了两种方式,一是使用命令行下载,但要用到 wget 和 awk,对于 Windows 用户比较繁琐,二是使用开发者提供的 python3 脚本。

根据网络状况,脚本运行时间在五秒钟到五分钟不等,只要不报连接超时,请耐心等待。在解决了 DNS 污染问题后我测试是可以直连 raw.githubusercontent.com 的,如果出现连接超时,可以尝试为 PowerShell 设置临时代理(仅在当前命令行窗口有效),或者尝试使用手机热点更新

最后一个问题,在使用 V2▢▢▢ 和 mos-chinadns 时都出现了,About Chrome 检查更新页面会显示无法连接到互联网,同时浏览器的页面翻译也不能工作了,我仔细想了想,并搜索了下 chn_domain.list,里面是没有 Chrome 更新和页面翻译相关的域名的,这就导致了被 1.0.0.1 解析后返回的海外 IP 很有可能是无法访问的。知道了原因,我打开了某网络调试工具,再打开 Chrome 更新页面并随便点进一个英文页面点击翻译,结束调试,抓到的域名有四个
ssl.gstatic.comupdate.googleapis.comtranslate.googleapis.commtalk.google.com
经查询,最后一个大概是 GCM 域名,于是添加前三个到 local 的域名列表中,再测试,更新和页面翻译都恢复了
如果还有别的需求或者使用 Apple 设备想连接国内服务,请考虑把下面列表中的网址加入到 local 中:Google-cn 域名Apple-cn 域名。顺便一提,开发者在某次提交中更新了脚本,已经默认附带 Google-cn 和 Apple-cn 了

注意此时 Chrome 仅仅是能够检查更新,想下载更新还是会卡住,我就是在这里又被坑了一下,需要把 tools.google.comdl.google.com 也加入 local。与其这么麻烦,倒不如把上面的、尚可达的、有大陆加速效果的域名全部加入本地解析算了

2020.09.24 更新:
最近发现开发者更新了 1.5 版本,支持请求重定向了,对默认配置文件也做了比较大的修改,例如将 Cloudflare DNS 切换到了 Google DNS,还优化了配置的逻辑,将 localremote 上游与 server 服务器拆分,再以 tag 的形式添加,还更新了 Wiki,贴出了示例配置,提供了更大的自由度,所以与我上面描述有出入的地方,还请以最新的 GitHub 页面为准哦。顺带开发者还新开了一个仓库,用 GitHub Actions 每周自动更新 IP 和域名列表,方便不想自己更新列表的普通用户
2020.10.26 更新:
1.5.5 版本更新了,完成了开发者自己提的 Issue,现已支持 geoip.dat 和 geosite.dat 规则文件,这下 chn_domain、chn_ip、reject-list、google-cn、tld-cn、geolocation-!cn... 全部 ALL IN 了,只要以类似 geoip.dat:tag 的形式添加进去就可以了,这意味着路由规则的配置比之前简易、准确了许多。其实不管怎么更新,跟随着详尽的 Wiki,我相信任何人都能轻松的配置好自己的规则,在这里也放下我的部分配置吧,稳定自用很长时间了,可以直接拿去用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
upstream:
local:
server: "aliyun"
policies:
query:
unhandlable_types: "deny"
domain: "deny:./geosite.dat:category-ads-all|accept:./geosite.dat:google-cn|accept:./geosite.dat:cn|deny"
reply:
error_rcode: "deny"
cname: "accept:./geosite.dat:cn"
without_ip: "deny"
ip: "accept:./geoip.dat:cn|deny"
remote:
server: "flare"
policies:
query:
unhandlable_types: "accept"
domain: "deny:./geosite.dat:category-ads-all|deny:./geosite.dat:cn|accept"
reply:
error_rcode: ""
cname: "accept"
without_ip: ""
ip: "accept"

Linux 系统使用方法

写这部分的初衷是自己也摸索了一段时间的 Linux 了,想反馈一下成果,比起大牛们,我这里介绍的还只是皮毛
系统:Debian GNU/Linux 10 (buster) x86_64

1
2
3
4
5
6
7
8
9
10
11
12
13
# 进入 FHS 所推荐的存放自己引入的第三方软件的目录
cd /usr/local/bin
# 下载。嗯,没错,这就是 mos-chinadns 最后一个可执行版本了
wget https://github.com/IrineSistiana/mos-chinadns/releases/download/v1.5.6/mos-chinadns-linux-amd64.zip
# 解压
unzip mos-chinadns-linux-amd64.zip
# 然后可以删掉自带的域名列表,自己下载 geoip.dat/geosite.dat 代替之
# 编辑配置文件,Ctrl+K 可以快速删除整行
nano config.yaml
# 由于这里还是更名之前的版本,故重命名一下
# mv mos-chinadns mosdns
# 赋予执行权限
chmod u+x mos-chinadns

到这里基本工作已经做完,./mos-chinadns 就可以运行了,但我们还得添加守护进程让 mos-chinadns 在后台运行

1
nano /etc/systemd/system/mos-chinadns.service

把我学习了半天 systemd 写的 service 配置复制进去

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=mos-chinadns - high performance DNS shunt and DoH/DoT client
Documentation=https://github.com/IrineSistiana/mos-chinadns/wiki
After=network.target

[Service]
# User=mos-chinadns 若要以非 root 用户启动,修改这里,并修改相关文件权限
ExecStart=/usr/local/bin/mos-chinadns -c config.yaml -dir2exe
Restart=on-failure
RestartSec=10s

[Install]
WantedBy=multi-user.target

想到还有 OpenRC 和 systemd 之争,我就头大,Linux 要学习的东西真是太多了

1
2
3
4
5
6
7
8
9
10
11
# 然后重载下 systemd 配置
systemctl daemon-reload
# 之后就可以自由的控制 mos-chinadns 运行了
# 启动
systemctl start mos-chinadns
# 停止
systemctl stop mos-chinadns
# 重启
systemctl restart mos-chinadns
# 查看日志
journalctl -u mos-chinadns

其实这里把配置文件和 geoip.dat/geosite.dat 都放到 /usr/local/bin 也是不符合 FHS 的,不过反正自己随便玩玩,就随便啦(

尚未尝试过的几种解决方案

2020.10.26 更新:
这部分本来是写在 mos-chinadns 之前的,趁着今天更新,就挪到后面来并稍微讲讲吧

这几个开源工具,大多是路由器或 Linux 友好,对于我这个菜鸟来讲还是有点难,而且前段时间也挺忙的,以后有机会试过了再更新吧…
这里首先讲个广泛认可(?)的结论,仅依靠域名进行国内外分流,是不太可靠的,而 IP 数据库则是相对稳定的,且有许多现成的轮子可融合使用,按 IP 段的分流准确率是相当高的

Dnsmasq:无 GitHub 数据

不支持 Windows,且貌似不支持 IP 二次分流,ipset 是啥我暂时还没搞懂,可能需要配合其它软件一起使用。但其有个附属项目 dnsmasq-china-list,是由肥猫 Felix Yan 维护的。这份域名列表是众多项目的上游,准确度应该是已知最高的了。Felix Yan 不仅维护了这份列表,数十年来也一直在为 Arch、Deepin 等等发行版打包、维护,甚至十年前就在压片组(u2?)压片,是无论在任何方面都值得我称一声前辈的人

dnscrypt-proxy:GitHub 6.5k star

作为自成一体的 DNSCrypt 协议发明者,同时兼容 DoH,dnscrypt-proxy 用起来还挺不错,文档很详细,其独有的 DNSCrypt 协议是一大亮点,不依赖于 TLS,通信效率更高。如果作为 mos-chinadns 的上游使用,应该是个不错的选择

CoreDNS:GitHub 6.5k star

CoreDNS 作为 k8s 集群内的 DNS 服务器存在,以插件的形式添加功能,配置起来可以极其简单

1
2
3
4
5
//监听 53 端口并把所有请求转发到 1.0.0.1
.:53 {
forward . 1.0.0.1:53
log
}

也可以很复杂,加密、缓存、日志、转发、负载均衡、分流 CoreDNS 都能做,但总觉得易用度没那么好,我看过几篇文章都是写脚本定期往配置里更新域名列表,而且开发者估计也不会想到有人会把几万个域名塞进来作分流,没有针对性地优化查找效率。但是,可以配合 mos-chinadns 的分流一起使用,mos-chinadns 监听 53,将上游设为 CoreDNS,由 CoreDNS 向外请求,可以有更强大的功能组合

AdGuardHome:GitHub 5k star

该有的功能都有,Windows 上可以跑,而且有 localhost web 管理界面,可以很清晰的看到今天查询了那些域名,拦截了多少广告,很适合一般人使用,有机会还蛮想试试这个的,但比较消耗资源,而且我现在越来越推崇使用配置文件而不是用鼠标点点点了,只需要保存好自己的配置文件,以后不管是更新还是换设备,将软件下载、解压,配置文件扔进去就可以使用了
回收前言,我认为基于 IP 规则的二次分流是必需的,但我真的不确定这几个工具是否支持,但也有可能只是我不会用罢了,如有清楚的人,请务必指出,好让我更正自己的错误过了一段时间,我才感觉自己的想法太理想了,准确的说,在代理环境中基于 IP 规则的二次分流才是必需的,而 DNS 这种东西,如果注重隐私,直接做成白名单就好了

尾声

首先鸣谢上方所有项目的开发者与参与人员
有人问费那么大劲折腾 DNS 真的有用吗?这个问题不难回答,至少,现在能直连 raw.github、DuckDuckGo 和几乎所有(?)使用 Cloudflare CDN 但被 DNS 污染了的网站,我也为自己和后续有需要的人留下了一份记录,该如何理解这份记录,还交予读者,如果在使用时发生一些意料之外的情况,恕本站难以承担责任
最后的最后,贴出一些额外的文章,供读者参考
关于公共 DNS 的选择:
GitHub - curl/doh
Sukka’s Blog - 如何选择适合的公共 DNS?
大佬的进阶文章:
wzyboy’s blog - 搭建 Pi-Hole 为网上冲浪保驾护航

不知不觉这一篇文章就写了一万多字了,能写点东西,还蛮有趣的
本文就到这里吧,拜拜~