使用Mosdns进行DNS分流

自开源EasyMosdns项目以来,很多用户已经在服务器上自建了无污染DNS,然而当DNS服务器并非在内网时,并不能获取最佳的解析速度。

这里讲解一下家用的分流策略,适合已经在使用无污染DNS的用户加速解析。


【DNS分流】

第一种是本地自建DNS,在IP分流的逻辑处理上,默认使用支持ECS的海外DNS分流,当返回国内IP时,使用国内DNS再次解析提升精准度,这就是EasyMosdns v2版本的设计思路;

第二种是本地只做国内域名规则的命中,其余域名分流交给有分流功能的无污染DNS处理,下面给出mosdns的配置文件:

# EasyMosdns Client v3.0
log:
    file: "./mosdns.log"
    level: error

data_providers:
  - tag: chinalist
    file: ./rules/china_domain_list.txt
    auto_reload: true
  - tag: cdncn
    file: ./rules/cdn_domain_list.txt
    auto_reload: true

plugins:
  # 乐观缓存的插件
  - tag: cache
    type: cache
    args:
      size: 5000
      compress_resp: true
      lazy_cache_ttl: 86400
      cache_everything: true
      lazy_cache_reply_ttl: 3

  # IP反查缓存的插件
  - tag: reverse_lookup
    type: reverse_lookup
    args:
      size: 1000
      ttl: 3600
      handle_ptr: true

  # 调整TTL的插件
  - tag: ttl_long
    type: ttl
    args:
      minimal_ttl: 600
      maximum_ttl: 86400

  # 转发AliDNS的插件
  - tag: forward_alidns
    type: fast_forward
    args:
      upstream:
        - addr: "223.5.5.5"

  # 转发DNSPod的插件
  - tag: forward_dnspod
    type: fast_forward
    args:
      upstream:
        - addr: "tls://1.12.12.12:853"
          enable_pipeline: true

  # 转发远程服务器的插件
  - tag: forward_remote
    type: fast_forward
    args:
      upstream:
        - addr: "tls://8.8.4.4:853"
          enable_pipeline: true

  # 转发分流服务器的插件
  - tag: forward_apad_pro
    type: fast_forward
    args:
      upstream:
        - addr: "https://doh.apad.pro/dns-query"
          bootstrap: "119.29.29.29"
          enable_http3: false

  # 匹配本地域名的插件
  - tag: query_is_local_domain
    type: query_matcher
    args:
      domain:
        - "provider:chinalist"

  # 匹配CDN域名的插件
  - tag: query_is_cdn_cn_domain
    type: query_matcher
    args:
      domain:
        - "provider:cdncn"

  # 主要的运行逻辑插件
  - tag: main_sequence
    type: sequence
    args:
      exec:
        # 缓存
        - reverse_lookup
        - cache

        # 本地域名与CDN域名处理
        - if: "(query_is_local_domain) || (query_is_cdn_cn_domain)"
          exec:
            - primary:
                # 优先用AliDNS解析
                - forward_alidns
              secondary:
                # 超时用DNSPod解析
                - forward_dnspod
              fast_fallback: 50
              always_standby: true
            - _return

        # 剩下的域名处理
        - primary:
            # 优先用分流服务器解析
            - forward_apad_pro
          secondary:
            # 超时用远程服务器解析
            - forward_remote
          fast_fallback: 500
          always_standby: false
        - ttl_long

servers:
  - exec: main_sequence
    timeout: 5
    # 监听地址配置
    listeners:
      - protocol: udp
        addr: "0.0.0.0:53"
      - protocol: tcp
        addr: "0.0.0.0:53"

其中china_domain_list.txt、cdn_domain_list.txt两个规则文件可以在项目https://github.com/pmkol/easymosdns/tree/rules 中获取。

如果已经使用了smartdns、adguard home等DNS软件,可以将mosdns做为后端,以实现更多功能,当然也参考mosdns的分流思路使用这些软件直接分流。


【思路讲解】

对于绝大多数拥有分流功能的DNS程序而言:

核心逻辑一般会先判断国内域名,命中后使用国内公共DNS解析;

然后再去解析其余域名,根据解析IP的地理位置进行DNS分流,如果IP属于中国大陆则直接返回结果,反之则使用海外DNS再次解析后返回结果。

【思考一】

命中国内域名的处理很好理解,但当其余域名使用IP分流时,想获取一个域名的IP,首先要对这个域名进行解析,这时需要使用哪个DNS对域名进行第一次解析呢?

按照上述的DNS分流逻辑,很明显需要使用国内公共DNS完成首次解析,速度才是最快的,因为即使有DNS污染,解析出的污染结果并不包含中国大陆IP,所以只需要使用无污染的DNS重新查询这些结果,即可解决DNS污染问题。

事实上绝大部分DNS分流及代理工具的IP白名单分流也正是这样实现的。

【思考二】

以www.google.com的解析过程举例,首先请求国内公共DNS,获取到了一个污染结果75.126.115.192,这个结果不是中国大陆IP,所以需要去请求无污染DNS,最终获取到正确的解析结果。

那么问题来了,国内公共DNS记录了你对www.google.com的查询,也就是说国内运营商知道你访问了谷歌,而且查询两次DNS也降低了解析效率。

为了解决这个问题,代理域名黑名单出现了,命中黑名单的域名会直接使用无污染DNS查询,这也是代理工具比较常用的方法。

【思考三】

新的问题出现了,那就是黑名单的覆盖率,当进行DNS泄露测试时,会发现同时存在国内与海外的DNS,证明发生了DNS泄露,而且有些被污染的域名并不一定在黑名单中。

简单暴力的思路出现了,放弃IP分流,直接将非国内域名全部使用无污染DNS解析不就好了。

然而这仅在理论上可行,实际上部分域名的解析效果并不会很好,因为无污染DNS需要去请求海外公共DNS,即使是国内的无污染DNS也都是转发海外公共DNS实现的,延迟问题或许还可以在本地使用乐观缓存方案解决,可解析精准度问题呢?

在国内特殊的网络环境下,直接请求53端口的海外公共DNS是会被劫持污染的,所以一般是通过DoH或DoT来访问,抛开丢包、阻断这些可能遇到的问题不谈,即使可以直连使用,此时会发现解析结果全部到了海外地区。

对于一般的海外域名而言,这并不会影响什么,但对于有国内节点的域名,还不在国内规则列表中的域名,将会解析出一个海外的IP,导致访问速度变慢。

这时一些DNS支持ECS的作用就体现出来了,最常用的就是谷歌DNS,对于大多数域名而言,的确可以解决上述问题,然而并不是所有域名都可以使用ECS进行解析优化,最典型的就是使用Akamai厂商CDN服务的域名。

使用 nslookup www.microsoft.com 8.8.8.8 命令在国内主机上测试,会发现返回了香港IP,说明谷歌DNS的ECS功能并未对该域名生效,当换成国内公共DNS时,会发现返回了距离较近的国内IP,当然这里只是用微软官网的域名举例,实际上这个域名会被绝大多数国内域名规则收录,并不会出现访问速度变慢的问题,但这证明单纯使用海外支持ECS的公共DNS进行分流虽然可行但并不完全可靠。

额外提一下Cloudflare的Gateway服务,只需要拿几个国内拥有CDN的域名测试下精准度,以及感受下解析的延迟,就知道答案了。

如何更优雅的实现DNS分流,参考本文前面给出的两种DNS分流方案即可。