DNS

1 背景 #

在此之前主要使用的代理软件如下:

  • V2RayN:macOS下 V2Ray GUI 客户端,主要解决浏览器使用问题
  • Proxifier:搭配使用,使不支持代理的工具/命令等使用代理,如终端上执行curl www.google.com走代理

V2RayN 使用了 PAC 模式,V2RayN 中使用的 v2ray-core 路由配置是全局配置,通过 PAC 列表控制哪些域名走这个全局代理

Proxifier上设置了相关规则,设置了 curl 访问 www.google.com 时走代理


由于 V2RayN 目前项目已经不再维护,同时目前市面上的 V2Ray GUI 程序都无法满足个人的一些特定需求,最终放弃了 GUI 客户端的使用,改直接使用 v2ray-core,其中使用了ByPassMainlandGFWList2种路由:

  • ByPassMainland:即所有非geoip:cn的请求都走代理,配置如下:
  • GFWList: 即所有在 GFW 列表中的站点走代理,配置如下:

2 问题 #

终端上执行 curl www.google.com,发现不论路由是 ByPassMainland 还是 GFWListcurl都无法正确返回

查看 V2Ray 日志,发现请求到 V2Ray 时 Proxifier 已经将域名解析成了IP,本地设置的 DNS 服务器为8.8.8.8,因为 DNS 污染的缘故所以无法正确返回

个人遂打算系统性的解决 DNS 污染这个问题,调研出了以下几种解决方案,几种方案各有取舍,需要结合需求使用

3 方案 #

3.1 Proxifier #

可以通过 Proxifier 的DNS - Resolve hostnames through proxy功能实现

在调整 Proxifier 设置后,发现只有在 ByPassMainland 路由模式下,才能正确返回,为了解释这一现象,查阅相关资料理解了 Proxifier 通过代理解析域名的工作机制

3.1.1 Fake-IP #

GFW 不仅对某些特定的 IP 进行了阻断,还对相当一部分域名采取了 DNS 污染。简单来说,就是通过域名解析到的 IP 是错误的,所以我们还需要对 DNS 请求进行代理。但每次请求如果都是先请求远程服务器 DNS,再返回解析结果,客户端再请求,再代理,这样一来二去就极大浪费了时间。于是,Fake-IP 技术出现了。

所谓 Fake-IP,也就是虚假的IP。每次 DNS 请求,如果匹配了当前 Proxifer 设置的代理规则,会被Proxifer 软件劫持,并立刻返回一个0.*.*.*样式的虚假IP。于此同时,Proxifier 会向代理发送DNS 请求,通过代理向8.8.8.8发送查询www.google.comA 记录,将获取到的真实IP虚假IP做映射保存在自己的表中,后续面向虚假IP的链接会被 Proxifier 对应的真实IP替换(DestOverride)

为什么在ByPassMainland路由模式下,curl www.google.com才能正确返回,但GFWList路由模式不行,因为发向8.8.8.8的DNS查询请求在ByPassMainland路由模式下会被proxy而不是direct,能够通过代理获取到真实IP而不是污染后的结果

3.1.2 优缺点 #

该模式优点在于节省了等待 DNS 从代理获取真实IP的时间,缺点是由于返回了虚假IP,污染了本地DNS 缓存,在退出 Proxifer 软件后,会导致对应的网络问题

3.2 国外DoH/DoT #

使用国外 DoT(DNS over TLS)/DoH(DNS over HTTPS)也可以解决 DNS 污染问题

3.2.1 Cloudfare DoH #

$ cloudflared --version
$ cloudflared proxy-dns --port 5555

$ dig +short @127.0.0.1 -p5555 google.com A
142.250.191.68
$ dig +short @127.0.0.1 -p5555 baidu.com A
www.a.shifen.com.
www.wshifen.com.
104.193.88.123
104.193.88.77
这里发现通过国外 DoH 解析到的104.193.88.77为百度在国外的IP

可以参看:https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/dns-over-https-client/

3.2.2 优缺点 #

可以看到DNS能够正确解析了,但是缺点明显

  • 无DNS分流,所有DNS请求会跑到国外转一圈,延迟高
  • 国内CDN不友好问题,如果国内网站在国外使用了CDN服务,会绕道到国外访问

3.3 国内域名分流 #

3.3.1 DNSmasq + dnsmasq-china-list #

DNSmasq也可以用SmartDNS等替代

dnsmasq-china-list 这类分流方案的核心是维护一个常用的国内域名列表,当查询列表内域名的IP时,DNS服务器选用国内DNS查询,其它情况下,使用国外DNS查询

这种方案下:
DNSmasq + dnsmasq-china-list 用于处理DNS请求,V2Ray 用于处理代理

3.3.2 优缺点 #

由于V2Ray使用的是v2ray-rules-datdomain-list-community来判断站点和IP是否来自国内是否要直连,而DNS解析使用的是dnsmasq-china-list,二者并不一致,可能会出现以下情况:

  • 国内DNS解析出国内IP后走代理
  • 国外DNS解析出国外IP后直连

不考虑是否能实现的情况下,解决不一致的方案思路有以下几种:

  • 让 DNS 服务器使用 V2Ray 的domain-list-community
  • 让V2Ray使用dnsmasq-china-list
  • 让 V2Ray 和 DNS 服务器都用v2ray-rules-dat

下面介绍的V2Ray DNS方案就是让 V2Ray 也作为DNS服务器,以解决DNS请求和代理时不一致的问题

3.4 V2Ray DNS #

Kitsunebi 的作者在 《漫谈各种黑科技式 DNS 技术在代理环境中的应用》中介绍了通过 Dokodemo 入站协议和 DNS 出站协议开放 V2Ray DNS 的方法,可以让 V2Ray 作为 DNS服务器

该方法的核心思想是使用 Dokodemo 入站协议接收 DNS 请求流量,转发至 DNS 出站协议。而 DNS 出站协议会拦截AAAAA的 DNS 查询并交由 V2Ray 内置 DNS 处理,从而返回查询结果;除此之外的查询流量,会根据 Dokodemo 的配置发送至目标 DNS 服务器

3.4.1 配置 #

具体配置如下

配置的主要含义是:

  • 发往本地53端口的AAAAA记录的DNS 请求会被拦截
  • 如果待查询域名匹配 geosite:cn,则使用国内阿里云的223.5.5.5查询
  • 如果待查询域名匹配 geosite:geolocation-!cn,即为常见的非国内站点的域名,则使用国外https+local://1.1.1.1/dns-query进行查询,local表示DNS查询请求不会被routing路由模块处理,由本地直接发出
  • 如果都不满足上述,则使用114.114.114.114进行查询
  • AAAAA之外的查询流量,会根据Dokodemo的配置发送至目标223.5.5.5服务器

其他配置参看:https://www.v2fly.org/en_US/config/dns.html#dnsobject

3.4.2 优缺点 #

优点是 DNS 分流,同时避免了 国内 DNS 解析出国内 IP 后走代理/国外 DNS 解析出国外 IP 后直连 的情况,缺点是由于 DNS 协议的复杂性,V2Ray DNS 并不是一个专门的 DNS 服务器,目前仅只支持AAAAA记录,查询TXT得到的结果仍然是污染后的结果,如果只关心AAAAA记录的准确性,则该缺点可忽略

3.5 CoreDNS + V2Ray DNS #

CoreDNS 作为 frontend,将A和AAAA记录的请求和其他类型请求分开,V2Ray DNS作为backend专门处理A和AAAA记录的请求

3.5.1 配置 #

可以使用view插件,将A和AAAA记录的请求和其他类型请求分开,Corefile如下:

注意修改V2Ray inbounds监听端口为5301

3.5.2 优缺点 #

优点是比较理想的解决了DNS污染问题,缺点是引入了新的CoreDNS组件,加长了请求链路,增加了复杂性

4 总结 #

总结一下针对 DNS 污染的解决方案:

  • Proxifier利用了Fake-IP,简单,会污染本地DNS
  • 国外DoH/DoT一刀切无DNS分流,准确,慢
  • dnsmasq-china-list国内域名分流,简单,存在偶发不一致情况
  • V2Ray DNS能DNS分流,暂无法解决除A和AAAA记录的其他请求
  • CoreDNS + V2Ray DNS较为理想的解决方案,复杂