前一阵子服务器集群遇到些糟心事,raw.githubusercontent.com这个域被运营商默认DNS解析到0.0.0.0去了,中间有怪东西在动我的查询请求,导致一些这个依赖域名请求资源配置的服务炸完了,于是便下定决心自建DNS服务器。

在参考了多个DNS服务器软件后,我选择了AD Guard HomeAD Guard Home是一款网络级软件,用于隐私保护和广告拦截,但它本质上是一个DNS服务器,由Go语言编写,而且支持DoH(DNS over HTTPS)DoT(DNS over TLS)DoQ(DNS over QUIC)加密DNS协议。

如果你只是想用一些纯净的DNS,推荐使用公共的加密DNS,如果你有其他需求,例如DNS重写,域名自由,自定义过滤就推荐自己搭一个

另外分享下我自己搭的DNS服务器:dns.liteyuki.icu (支持TLS和QUIC,不支持普通UDP和HTTPS)

下文中ADG代指AD Guard Home

原理

在互联网的世界中,任何数据报都是通过IP地址来进行路由的,假如我们请求一个网站,在浏览器输入框输入网址后,第一步是解析这个域名对应的IP地址,这个过程我们称为DNS查询,拿到IP地址后才能进行发送操作。DNS服务器好比一个电话簿,记录了姓名对应的电话号码,我们可以通过电话号码直接联系到对方,但是我们只有对方名字时,我们就需要先在电话簿里面查询这个名字对应的电话号码才能进行拨号。

假如我们自己做一个电话簿,把一些黑名单(广告网址)域名添加进去,并返回不存在的『电话号码』,这样就可以达到一个广告拦截的效果,所以我们需要自建DNS服务器来实现这个功能。

安装AD Guard

使用此命令直接在主机上安装,你也可以根据需求参阅官方仓库README.md使用Docker部署

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -vbash

很快就可以部署好,部署好后根据控制台打印的IP地址,选择一个和当前网络接口对应的,在浏览器中访问对应IP的3000端口,根据引导完成安装,会配置到新端口,web面板端口随意选择。

如果提示53端口被占用,可以换一个网络接口监听(例如局域网IP),在Linux系统中,这通常是由于system-resolved在监听127.0.0.0上的53端口导致的。

记得开放53端口

配置上游DNS

进入设置>DNS设置

支持以下形式的DNS服务器,推荐使用加密的协议,多配置几个。

  1. 94.140.14.140, 2a10:50c0::1:ff: 常规 DNS(基于 UDP);

  2. 94.140.14.140:53, [2a10:50c0::1:ff]:53: 常规 DNS(通过 UDP,带端口);

  3. udp://unfiltered.adguard-dns.com: 常规 DNS(通过 UDP、主机名);

  4. tcp://94.140.14.140, tcp://[2a10:50c0::1:ff]: 常规 DNS(基于 TCP );

  5. tcp://94.140.14.140:53, tcp://[2a10:50c0::1:ff]:53: 常规 DNS(通过 TCP,带端口);

  6. tcp://unfiltered.adguard-dns.com: 常规 DNS(通过 TCP、主机名);

  7. tls://unfiltered.adguard-dns.com: 加密 DNS-over-TLS

  8. https://unfiltered.adguard-dns.com/dns-query: 加密 DNS-over-HTTPS

  9. h3://unfiltered.adguard-dns.com/dns-query: 带有强制 HTTP/3 的加密 DNS-over-HTTPS,不会回退到 HTTP/2 或更低版本;

  10. quic://unfiltered.adguard-dns.com: 加密 DNS-over-QUIC

  11. sdns://...: DNSCryptDNS Stamps 或者 DNS-over-HTTPS 解析器;

  12. [/example.local/]94.140.14.140: 指定为特定域名的上游服务器;

  13. [/example.local/]94.140.14.140 2a10:50c0::1:ff: 特定域名的多个上游服务器;

  14. # comment: 注释。

分享一下我自用的DNS。

https://223.5.5.5/dns-query
https://1.12.12.12/dns-query
tls://120.53.53.53
tls://8.8.8.8
tls://1.1.1.1

有三种查询模式,负载均衡,并行请求,最快IP。推荐并行请求,哪个先应答就返回哪个。

后备DNS服务器

这个可以添加一些,格式和上面一样,冲当备胎的。

Bootstrap DNS 服务器

自举DNS服务器用来充当DNS服务器域名的DNS服务器,它只能是纯IP地址的,听起来有点怪,当你的主要DNS服务器是域名的时候,这时候需要通过DNS查询来获取主要DNS服务器IP。比如,你配置了一个tls://mydns.com 作为上游DNS,上文说到,和服务器通信需要服务器IP,那么必然会有一次额外的DNS查询来查询这个DNS服务器域名的IP,如果它也使用主要DNS(mydns.com)来进行查询,那必然涉及到一个鸡生蛋,蛋生鸡的问题,所有域名DNS服务器都需要使用自举DNS服务器来进行首次查询。

添加DNS重写

如果你有需求的话,该功能位于过滤器>DNS重写中,例如把liteyuki.gov域名解析到自己的网站(通过SNI分流的),以实现域名自由,这样别人用你的DNS也可以访问这个网站。这个功能类似我们修改Unix主机的/etc/hosts文件,添加自定义解析记录,非常简单,在此就不说怎么操作了。

配置加密DNS

如果你的DNS服务器仅在内网工作,那么无需配置,如果你是在云服务器上部署的,那么建议使用加密的,这样可以避免DNS劫持污染篡改等问题。DoT(大部分安卓设备原生支持),DoQ(基于QUIC UDP,更快),DoH(不易区分DNS查询流量和HTTP流量,建立连接后非常快)。推荐搞个域名,域名证书申请比较方便,虽然IP也能,但是我不会。我使用的是Caddy证书自动化申请(本来是给https服务用的,但是也可以给加密DNS用),然后在ADG中填入Caddy证书和私钥的文件路径即可。然后按需开放端口。

  • DoT(853/TCP)

  • DoQ(853/UDP)

  • DoH(443/TCP)

  • H3(443/UDP)

让你的设备们都使用这个DNS

ADG在部署时就监听了指定网卡的53端口,若在同一个局域网中,你可以直接在系统配置中添加对应的DNS服务器IP;若是云服务器搭建的DNS,请参阅各个手机的配置,例如HyperOS中可以在设置>更多连接>专用DNS中填入你的域名(HyperOS默认支持DoT),这个域名指向你的DNS服务器IP。

在设备上配置加密DNS有很多种方法,可能有的原生不支持这个,但是可以通过使用软件DNS劫持实现,推荐一种我在用且比较方便的。我使用mihomo内核作为科学上网工具,并且工作在网络层(tun模式下为默认路由),它可以劫持DNS查询请求,并且本身支持多种DNS协议,大致工作原理就是,普通的DNS查询请求在经过mihomo时被劫持,mihomo使用我们配置的DNS服务器进行查询后返回给系统。可以参阅mihomo的DNS配置文档,如果使用了自己DNS里面独有的域名记录,记得在fallback-filter中过滤掉,不然会验证失败(因为权威DNS里面没有你自定义的DNS重写)。

最后

如果你使用了我的dns.liteyuki.icu 作为DNS服务器,可以访问https://ly.bot来验证它是否正常工作