斐讯N1 – dnsmasq+chinadns+unbound实现无污染智能DNS

此前DNS方案:

  • 已经基于redsocks实现TCP全局翻墙
  • 已经搭建过unbound并TCP upstream到8.8.8.8
  • TCP流量通过ipset过滤掉了境内IP,只对非大陆IP翻墙

此方案的原理是所有的DNS解析都是经过unbound的TCP转发,同时TCP流量又会被redsocks拦截翻墙;

其缺点是:

  • 所有DNS解析都翻墙,很慢
  • 国内域名在墙外解析可能得到网站的境外CDN IP,导致按IP访问时依旧被iptables拦截翻墙到境外。

因此,必须解决DNS的智能解析问题,也就是国内域名国内解,国外域名国外解。

本次技术方案的整体架构:dnsmasq -> 本机chinadns -> 本机unbound。

利用chinadns

这是一个非常简短的C语言项目,源码很简单:https://github.com/shadowsocks/ChinaDNS

它是一个只支持UDP协议的DNS服务器,其工作原理是:

  • 加载一份大陆IP网段的数据到内存。(数据源:https://www.apnic.net/ 组织,可以说非常精确)
  • 配置1个国内的DNS服务器,配置1个国外的DNS服务器。(国内or国外的判断依据仍旧是上面的大陆IP网段文件)
  • 同时向2个DNS服务器发起UDP请求,谁先返回就先对谁进行判断:
    • 国内DNS返回了国内IP,那么直接使用这个IP作为客户端返回值。
    • 其他情况则使用国外DNS返回的IP。

chinadns依赖了2个很重要的客观事实:

  • 国内DNS服务器返回快,一旦解析到的是国内IP则可以立即返回客户端,因此解决了国内域名的解析加速。
  • 国内DNS解析国外域名返回的污染IP通常还是一个国外IP(只不过是错误的),因此国内DNS解析到国外IP可以直接忽视,等待国外DNS返回正确国外IP即可。

利用dnsmasq

为啥不直接让chinadns对外提供DNS服务呢?因为chinadns程序太简单了,只是实现了DNS双发解析的特殊能力。

我一开始也没有用dnsmasq,然而发现安卓设备上的谷歌全家桶app都提示:”无法联网”,然而网页都可以打开,这让我非常纳闷。

经过搜索得知,谷歌app访问的域名是独立的,并且国内谷歌框架的域名还是.cn后缀的:

services.googleapis.cn

这个域名在国内DNS解析会得到一个国内的IP,并且是被污染过的,所以chinadns也是无法识别出这种case的。

因此,我需要最前面放一个支持高级策略配置的dns服务器,直接配置services.googleapis.cn的正确的IP进去,这样就免得走后续的chinadns解析流程了。

整体搭建流程

让dnsmasq监听53端口,chinadns监听在530端口,原先的unbound换到531端口。

代理关系是:dnsmasq –(udp)–> chinadns –(udp)–> unbound –(tcp)–> 8.8.8.8。

其中,chinadns配置国内dns为114.114.114.114,配置国外dns为127.0.0.1:531(也就是本机的unbound),这样就可以复用unbound的TCP翻墙解析和缓存能力,同时chinadns搞定国内域名高速解析的需求。

之所以127.0.0.1被chinadns视为国外dns,是因为chinadns判断dns服务器是国内还是国外也是基于大陆IP网段,而127.0.0.1不在大陆网段文件内,因此很巧妙的被算作了国外DNS服务器。

调整unbound配置

首先改一下/etc/unbound/unbound.conf,把监听地址修改为127.0.0.1:531:

然后systemctl restart unbound重启一下即可。

部署chinadns

下载chinadns源码并编译安装:

然后执行如下命令从apnic组织下载一份最新的大陆IP段列表,生成chnroute.txt文件:

然后把chinadns二进制以及上述chnroute.txt文件分别放到:

然后创建systemd配置文件:

然后注册并启动该service即可:

部署dnsmasq

安装:

配置/etc/dnsmasq.conf,确保如下配置相同:

  • 前2行用于禁止dnsmasq从/etc/resolv.conf中获取nameserver地址。
  • 第3行默认用chinadns作为上游dns,但是对于特例则直接走unbound翻墙解析。

下载googlehosts解决google全家桶的DNS污染特例,否则很有可能安卓手机之类的打不开谷歌全家桶:

项目地址:https://github.com/googlehosts

只需要下载里面的dnsmasq.conf:https://github.com/googlehosts/hosts/blob/master/hosts-files/dnsmasq.conf

里面按照dnsmasq的配置格式指定了谷歌全家桶的各种特例解析,我们只需要把它放到如下目录,dnsmasq就会自动加载生效了:

然后启动dnsmasq:

验证

如果你已经按照我此前的博客将斐讯N1的DNS指向了自身的话,那么现在直接dig测试即可,都可以瞬间返回:

 

关于斐讯N1作为翻墙网关以及电视盒子的一系列教程到此为止,祝大家玩的愉快。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~