SmartDNS 分流加速

书接上回,在服务器部署 AdGuardHome 之后,我们在全平台用上了带广告过滤的加密 DNS
但是,如文章最后Q/A所言: 加密的 DNS 并不能解决污染问题。

  • Q:使用 AdGuardHome 可以完全避免 DNS 污染吗?
  • A:显然不可以。经过上文配置流程不难发现 AdGuardHome 本质上只是中转,DNS 污染在上游就存在。但至少你可以选择相对干净的 DNS,这已经是极大的提升了。

有聪明的小朋友就想到,既然 污染在上游就存在 那么我更换成 无污染 的上游不就从根源解决问题了吗?
如果你这样做,污染确实可以解决,但是国内的域名访问却会变得相当慢。 慢并不是 DNS 服务器慢(事实上 google、cf DNS 用 tls 直连速度都还不错,更别说加上乐观缓存了) 真正慢的是我们访问解析得到的 IP 慢。 这里涉及一些 递归 DNS 和 CDN 的知识,简单理解为 谷歌远在大洋彼岸,无法对中国大陆域名做到准确解析

那么铺垫了这么老些,总算是该扯到正题上了
一边是污染,另一边是不准确,那有没有什么两全其美的方案呢?

👻 我全都要.jpg 我全都要

方案选择

全都要的方案就是分流,如下图,在 AdGuardHome 之前在加一层,作为其上游,负责对不同的 DNS 请求进行分流, 分别解析大陆地址和非大陆地址
dns-shunt.png

用于分流的这一层,要求也很简单,即支持域名分流的本地DNS服务,几个推荐的组件如下:

dnsmasq

c语言实现的 DNS 和 DHCP服务器。资历相当老,被集成在大多数 Linux发行版中

SmartDNS

go语言实现的高性能 DNS 服务器,以速度著称,支持多种协议并行请求

MosDNS

go语言实现的 DNS 转发器

安装

选定方案后即可开始安装了,本例中以 SmartDNS 为例,为了便于维护迁移,推荐使用 Docker Compose 进行管理

DockerCompose 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
version: "3"
networks:
  app-tier:
    ipam:
      config:
        - subnet: 172.30.0.0/24
services:
  smartdns:
    image: pikuzheng/smartdns:latest
    container_name: smartdns
    restart: always
    volumes:
      - ./smartdns:/etc/smartdns
    environment:
      - TZ=Asia/Shanghai
    networks:
      app-tier: 
        ipv4_address: 172.30.0.2

如上 DockerCompose 文件示例,配置了 smartDNS 服务,需要注意的是指定网络并为 smartDNS 配置固定IP,防止每次容器重启IP变化, 此外,AdGuardHome 服务也应该位于此网络下

SmartDNS 配置

在启动 SmartDNS 之前,需要编写其配置文件 smartdns.conf 示例如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
conf-file  /etc/smartdns/china.domain.smartdns.conf

bind-tcp [::]:53
bind [::]:53
tcp-idle-time 3
cache-size 4096
prefetch-domain yes
serve-expired yes
serve-expired-ttl 0
speed-check-mode none
rr-ttl-min 60
rr-ttl-max 86400
log-level warn

# Bootstrap DNS 用于解析 DNS 服务器的域名
server https://146.112.41.2/dns-query -bootstrap-dns

# ----- Default Group -----
# 默认使用的上游 DNS 组
# OpenDNS 非常规 443 端口、支持 TCP 查询
server-tcp 208.67.220.220:443
# OpenDNS 的 IP DoH
server-https https://146.112.41.2/dns-query
# TWNIC 的 IP DoH
server-https https://101.101.101.101/dns-query
# 你也可以配置其它 DNS 作为上游

# ----- Domestic Group: domestic -----
# 仅用于解析 dnsmasq-china-list 列表中的域名
# 腾讯 DNSPod IP DoT
server-tls 1.12.12.12:853 -group domestic -exclude-default-group
server-tls 120.53.53.53:853 -group domestic -exclude-default-group
# 阿里 IP DoT
server-tls 223.5.5.5:853 -group domestic -exclude-default-group
server-tls 223.6.6.6:853 -group domestic -exclude-default-group
# 114 DNS、使用 TCP 查询
server-tcp 114.114.114.114 -group domestic -exclude-default-group
server-tcp 114.114.115.115 -group domestic -exclude-default-group
# CNNIC 公共 DNS、仅支持 UDP 查询
server 1.2.4.8 -group domestic -exclude-default-group
server 210.2.4.8 -group domestic -exclude-default-group

在配置文件中,指定了两个上游 DNS 分组,没有 -group 为默认分组,另一个为 domestic 分组,不难看出 domestic 用于解析中国大陆域名。 那么 SmartDNS 是如何知道哪个域名位于中国大陆呢?

这就需要借助 felixonmars/dnsmasq-china-list 了。 它是一组开源的,覆盖了绝大部分中国大陆的域名的 dnsmasq 配置文件,也可以通过预定义的 Makefile 生成供 unbound、bind9、dnscrypt-proxy、SmartDNS、AdGuardHome、coredns 使用的配置文件。

示例命令如下,指定生成的配置使用 domestic 分组,并且开启了测速模式

1
make SERVER=domestic SMARTDNS_SPEEDTEST_MODE=tcp:80 smartdns-domain-rules

使用 conf-file 将生成的配置引入主配置文件中,也即示例配置的第一行;最后将配置文件 smartdns.conf 拷贝到正确的路径下, 如果使用上文中的 docker-compose 配置,那么它应该位于映射出的 ./smartdns 路径下;如果是直接在物理机上安装,那么其应位于 /etc/smartdns

使用与测试

完成上述步骤后,就可以启动 SmartDNS 首次启动建议将 log-level 设置为 info 以方便测试是否运行无误,测试命令也很简单:

1
nslookup www.baidu.com 172.30.0.2

从左往右依次为 命令名、待解析的域名、使用的 DNS 服务器
注意: 如使用了 Docker 需要先进入容器或保证位和 SmartDNS 于同一网络;如使用除 53 以外的端口需加上端口号

测试无误后,进入 AdGuardHome 仪表盘,设置 -> DNS设置,将第一项 上游 DNS 服务器 更改为前面配置的 SmartDNS IP地址,保存即可

Q/A

  • Q:使用 SmartDNS + AdGuardHome 可以完全避免 DNS 污染吗?
  • A:不绝对,但是可以最大程度避免,这主要取决于 分流配置 够不够准确 以及 SmartDNS 中 上游 DNS 是否存在污染
     
  • Q:速度不理想怎么办?
  • A:一般来说,启用了 SmartDNS 缓存 和 AdGuardHome 乐观缓存,速度可以达到 0.x毫秒级别,如果有速度问题,建议结合日志从链路起点开始逐步排查

部分内容参考自:Sukka’s Blog-我有特别的 DNS 配置和使用技巧