OpenWrt使用Docker搭建国内外分流DNS服务器
为什么要国内外DNS分流
由于不可描述的原因,使用国内DNS服务器解析国外域名时,可能会返回错误的IP地址。
目前有很多种解决方法。
使用国外DNS服务器这个还是会被污染
使用国外DoH、DoT技术基本上无法访问
通过代理使用国外DNS服务器
可行,但是慢
那么,能不能国内域名使用国内的DNS服务器,国外域名使用国外的DNS服务器呢?
答案是可以的,其实网上有多种解决方案,我这里介绍其中一种。
DNS服务器
TechnitiumSoftware的DnsServer是一个由C#编写的开源DNS服务器,支持Windows、Linux系统,有Docker镜像。
你问我为什么选它,我的答案是,因为我会C#
这个DNS服务器本身是没有分流功能的,但是其支持插件,我为其编写了一个分流插件
当检测到域名是的国外的时候(配置的列表),直接用国外的DNS服务器解析
先使用默认DNS服务器(一般配置国内的几个DNS服务器)解析
解析出来后,判断IP地址是不是非法的(配置的列表,里面一般是内网网段以及GFW喜欢设置的网络黑洞网段)
不是非法的,再通过GEO数据库,判断IP地址是不是国内的
如果是非法的或者不是国内的,再使用国外的DNS服务器解析一遍
可以配置使用代理访问国外DNS服务器,一般都要使用代理
源码地址:TechnitiumSoftware/DnsServer: Technitium DNS Server (github.com)
插件源码地址:Kation/DnsServer: Technitium DNS Server (github.com)
前置条件
废话不多说,以我家里的网络环境为例,搞它
由于我还不会制作OpenWrt的插件,所以先用Docker来运行DNS服务器
OpenWrt需满足
OpenWrt安装了Docker插件
安装了内核模块kmod-macvlan
Docker网络配置
如果你的网络启用了IPv6,那么请先到这里,把“IPv6 ULA”前缀记下,一般是OpenWrt自动生成的

然后我们进入Docker的网络管理界面,点击“新建”

网络名称不能重复
驱动器选择“MAC VLAN”
基设备选择OpenWrt本地网桥,一般为“br-lan”
模式默认保持桥接
子网输入一个新的网段,不能与现有网段重复
网关输入该网段内的一个IP,为本OpenWrt设备的IP地址
IP范围与子网相同即可
如果使用了IPv6网络,则勾选“启用IPv6”
IPv6子网,我的IPv6 ULA地址是“fdbf:6008:a32f::/48”,在a32f后,添加一个不重复网段,例如我的239,48掩码改为64,我的例子为“fdbf:6008:a32f:239::/64”,注意冒号不能少也不能多。
IPv6网关将/64改为1即可,我的例子为“fdbf:6008:a32f:239::/1”

OpenWrt网络配置
点击菜单里的接口时,会弹出一个对话框,点击“继续”,此时会看到新增了一个网络“DOCKER_你的Docker网络名称”

如果没有使用IPv6,则不需要更多配置,跳到下一步骤。
点击编辑新的网络,在IPv6地址栏里填入创建Docker网络时填入的网关地址,点击保存。

然后在路由管理界面的静态IPv6路由选项卡点击“添加”。

接口选择对应生成的Docker接口
目标填入创建Docker网络时的IPv6子网
网关填入创建Docker网络时的IPv6网关

保存后,OpenWrt的网络就配置好了
部署DNS服务器
创建数据存储文件夹
在开始部署前,先确定你的OpenWrt数据存储位置
如果你的OpenWrt装有Diskman插件,进入Disk man管理界面,查看挂载点

可以看到,我的OpenWrt内有一块nvme固态硬盘,其中有个118G的分区,挂载在路径/mnt/storage上
没有Diskman的话,通过ssh或在线终端功能连入OpenWrt,执行lsblk命令

同样能看到一个118G的分区,挂载在路径/mnt/storage上
通过ssh或在线终端功能连入OpenWrt,执行命令
执行cd /mnt/storage进入挂载点
执行mkdir dnsserver创建数据文件夹

使用OpenWrt界面部署,不支持IPV6
在Docker的容器管理界面点击新增

容器名称填入不重复的名称,例如dnsserver
Docker镜像填入technitium/dns-server:latest
重启策略选择Always
网络选择上文中新创建的macvlan网络
IPv4地址填写的IP地址必须属于网络子网
环境变量填入TZ=Asia/Shanghai
绑定挂载填入上文创建的数据文件夹路径,加上“:/etc/dns”,我这里为“/mnt/storage/dnsserver:/etc/dns”

点击提交即可拉取镜像并创建出DNS服务器容器
使用控制台命令部署,支持IPv6
由于OpenWrt的Docker管理界面添加容器时不能指定IPv6地址,所以只能通过ssh或在线终端功能连入OpenWrt,使用命令行执行命令添加容器
--name参数为容器名称
--net参数改为上文新创建的macvlan网络名称
--ip参数改为你的网络子网IP地址
--ip6参数改为你的网络IPv6子网IP地址,不能为网关地址
-v参数中的“/mnt/storage/dnsserver”替换为上文创建的数据文件夹路径
docker run
-d
--name='dnsserver'
--net='app'
-e TZ="Asia/Shanghai"
--restart=always
--ip 192.168.239.1
--ip6 fdbf:6008:a32f:239::2
-v '/mnt/storage/dnsserver':'/etc/dns':'rw'
technitium/dns-server
执行命令即可拉取镜像并创建出DNS服务器容器
容器启动完毕后,你应该能在电脑上ping通IP地址

配置DNS服务器
在浏览器内输入容器IP地址,加上端口号5380进入DNS服务器管理界面

关闭DNS校验
由于不可描述的原因,取消勾选Enable DNSSEC Validation

修改默认DNS服务器
填入几个国内常用的DNS服务器
例如119.28.28.28、119.29.29.29、223.5.5.5

如果你填写了多于2个的DNS服务器地址,那么改一下并发查询数

安装分流插件
先到https://github.com/Kation/DnsServer/releases下载最新的插件压缩包
然后到App选项卡点击Install按钮

App Name随便填
App Zip File选择刚才下载的压缩包
点击Install进行安装

安装好后在列表页点击Config按钮进行配置

将内容替换为自己的配置,点击Save保存

配置说明
这里可能不是最新的配置说明,最新配置说明请看下载页
重点关注nameServers配置,如果你的代理服务器仅支持常规端口,请只配置Https类型的DNS服务器
proxy配置改为你的代理服务器
什么值得买的JSON展示太丑了,大家去看下载页的示例
测试DNS
配置完毕后,可以在电脑上使用nslookup命令测试DNS服务器工作是否正常

可以看到,已经正常返回结果
使用国内DNS服务器的结果

修改下发的DNS服务器地址
最后一步,修改OpenWrt的接口下发的DNS服务器地址为容器IP地址
如果你不是使用OpenWrt作为DHCP服务器,请自行设置,你应该会的
在OpenWrt接口修改界面,DHCP选项填入“6,你的容器IP地址”

如果使用了IPv6,还需要修改IPv6的DNS服务器地址
在通告的IPv6 DNS服务器填入容器的IPv6地址

好了,到此全部配置完毕,家里的设备都能正常解析DNS地址了
结语
有人可能要问,既然都有代理了,为什么不用代理提供的DNS服务?比如OpenClash
我这么做当然是有原因的
OpenClash提供的DNS服务会有点问题,无法指定使用国内的DNS服务器来解析代理服务器地址
指定国外DNS服务器的话,解析代理服务器地址需要连上代理,然而代理服务器地址还没解析出来,就……
而且用OpenClash的DNS解析,国内某些手机APP的DNS解析有时候好慢,非常影响体验,收到来自老婆的“关爱”
现在用了DNS分流就简单了,OpenClash直接配置本地DNS劫持为停用,只干代理的活
作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~

nknk
校验提示文案
值友5056829547
校验提示文案
zj2012ss
校验提示文案
囧小叔
校验提示文案
dongfeng555
校验提示文案
lu161513
校验提示文案
愚以为
校验提示文案
clamp2nd
校验提示文案
RobinVP
校验提示文案
删我帖者菊花残
校验提示文案
删我帖者菊花残
校验提示文案
RobinVP
校验提示文案
clamp2nd
校验提示文案
愚以为
校验提示文案
nknk
校验提示文案
lu161513
校验提示文案
囧小叔
校验提示文案
zj2012ss
校验提示文案
值友5056829547
校验提示文案
dongfeng555
校验提示文案