使用smartdns和docker搭建私有防劫持dns服务

引言

最近在家使用移动宽带,使用的ISP DNS出现了DNS的污染,经常会将域名错误解析来劫持域名,十分烦恼。由于DNS本身使用的UDP协议是先到先得,也就是先应答的报文会被视为有效报文。研究了一下ISP的DNS抢答部署,发现是在光猫一级。最开始是希望使用chromium的DNS over https功能,但是还有个问题是其他的设备或者软件使用时,还是会被劫持。因此研究了一下,在windows上搭建一个私有的DNS服务。

我的需求大概是以下几点:

  1. 能够使用DNS over TLS/DNS over https作为上游

    这点非常重要,因为DNS抢答发生在光猫一级的时候,如果还使用UDP协议作为上游,也就意味着这一层私有DNS向上拿到的仍然是被劫持的结果。

  2. 方便部署

    这一点主要是为了方便迁移平台,因为我的目的是让所有使用的设备都能使用这个服务。而不需要对于不同平台弄不同的解决方案。

综合上面两点主要的需求,我找了几个比较热门的解决方案.其中最多人在用的应该是dnsmasq+dnscrypt。这种方案的好处显而易见,就是用户群体大,维护方便,相对来说不需要自己太多折腾。但是缺点是dnscrypt不支持指定ISPDNS,这样会使得CDN失效。这样对于访问速度而言伤害比较大。对此,幸运的找到了smartdns项目。它最符合我需求的一点就是

  1. 多DNS上游服务器
    支持配置多个上游DNS服务器,并同时进行查询,即使其中有DNS服务器异常,也不会影响查询。
  2. 返回最快IP地址
    支持从域名所属IP地址列表中查找到访问速度最快的IP地址,并返回给客户端,提高网络访问速度。
  3. 支持多种查询协议
    支持UDP,TCP,TLS, HTTPS查询,以及非53端口查询。

其他特性参见https://github.com/pymumu/smartdns

搭建过程

smartdns本身支持了很多部署方式例如deb包、ipk包路由器固件等等。在官方的部署方式中亦给出了WSL子系统的部署方式。并且给出了脚本来进行部署。但是我在尝试了WSL的子系统方式部署后,发现一个问题是,WSL由于隐藏了比较多的细节,或者说实现的比较复杂,出现问题之后比较难debug。因为之前本机部署redis服务的时候,在Windows下搭建了一个docker。因此就试着

1
docker search smartdns

然后就发现了ghostry/smartdns这个镜像。因为这个作者本身也是smartdns的使用者,于是将其打包成了镜像,并且上传到docker hub。

对于smartdns的docker搭建,因为有了这个镜像简单了很多,只需要:

1
2
3
4
5
6
7
//拉取镜像
docker pull ghostry/smartdns
//这两条命令是为了清除掉容器中已经有的同名镜像,防止出错。
docker container stop gsmartdns
docker container rm gsmartdns
//以后台模式运行在53端口,并且设置自动启动,这里也可以监听853或者5353实现自建DNS over TLS或者DNS over TCP等等。
docker run -d -p 53:53/udp --restart=always --name gsmartdns ghostry/smartdns

在上述命令运行成功之后,ghostry的docker镜像中原来就已经配置好了一份,但是没有包含被污染的ip列表,以及使用的上游DNS等等。这里上一份我自行修改之后的配置文件

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
conf-file blacklist-ip.conf
conf-file gfw.conf

bind [::]:53
bind :53
cache-size 4096
prefetch-domain yes
speed-check-mode tcp:80,tcp:443,ping
rr-ttl-min 60
rr-ttl-max 86400
log-level warn

#这两个是我的ISP提供的DNS 用于获取国内的CDN地址 可以换成自己的ISPDNS或者删除
server 211.141.90.68:53 -blacklist-ip -check-edns -group isp
server 211.141.85.68:53 -blacklist-ip -check-edns -group isp
#国内public dns 114 dnspod
server 114.114.114.114:53 -group chinapub
server 119.29.29.29:53 -group chinapub
#google
server 8.8.8.8 -blacklist-ip -group foreign
#cloudflare
server 1.0.0.1 -blacklist-ip -group foreign
#dot doh方式查询
server-tls 1.0.0.1 -group gfw
server-tls 8.8.4.4 -group gfw
server-https https://cloudflare-dns.com/dns-query -group gfw

其中blacklist-ip.conf文件我使用的是这一份blacklist-ip.conf,配置的参数含义参见https://github.com/pymumu/smartdns

在完成以上的配置步骤之后,就可以尝试将DNS改为127.0.0.1进行测试啦。

关于ISPDNS,记得对nameserver进行配置

参照

我的使用配置文件在 <../assets/blacklist-ip.conf> <../assets/gfw.conf> <../assets/config.conf> 需要的话可以自取