记一次DNS配置错误事件

  为方便日常使用,并能够在 Linux 下畅玩 Dead or Alive: Xtreme Venus Vacation,本人在之前进行了 *** (以下简称米哈游代理,请注意,本文使用的是 Meta 内核) TUN 模式的相关配置。然而,25 年 3 月 5 日晚,当我高兴的打开 CF 准备进行一场激情四射的 Div 3 VP 时——Chrome 显示找不到 IP 地址。经过几个小时的排查,最终把问题定位到了米哈游内核的 dns 配置文件部分,并写下本文,介绍问题的具体原因和解决方案。

DNS 配置简介

  Linux 内核提供了一种名为 TUN 的虚拟网卡设备,使得用户能够处理三层数据包,进行流量代理。米哈游内核提供了基于 TUN 的虚拟网卡模式,可以在 config.yaml 中进行设置。
  一般来说,在配置 TUN mode 时,需要进行 DNS 配置,以应对不同的域名解析需求 (如使用国内的 DNS 解析国内网站,使用国外的服务器解析国外网站以获得更准确的结果)。在米哈游代理的 dns 模块中有这样一些配置选项:

  • enhanced-mode: DNS 处理模式,本文默认采用 redir-host 而非 fake-ip
  • prefer-h3: 倾向使用 HTTP3
  • respect-rules: 在向 DNS 发送请求报文时是否使用 rules 中的规则进行分流,仅在 proxy-server-nameserver 非空时可开启,且不建议与 prefer-h3 一起使用
  • default-nameserver: 用于解析其他 DNS 服务器域名的 DNS 服务器,必须是 IP,可以使用加密
  • proxy-server-nameserver: 用于解析 proxies 配置项中代理服务器域名的 DNS 服务器,可选项
  • nameserver: 默认的解析域名服务器
  • fallback: 后备域名解析服务器
  • fallback-filter: 过滤条件,满足条件的使用 fallback 进行解析
    • geoip: 是否使用 GeoIP 进行判断
    • geoip-code: 国家代码缩写,默认值为 CN,不匹配该国家代码的 IP 均视为被污染 (即使用 fallback DNS)
    • geosite: 匹配到该部分的域名被视为被污染,使用 fallback 进行解析
    • ipcidr: 匹配到这一部分网段的 IP 被视为被污染,使用 fallback 进行解析;240.0.0.0/4 是一个常用的屏蔽网段,被 DNS 屏蔽的网站将会返回到这个网段上

  以下是米哈游代理处理域名解析的流程图 (图源官方文档)

flowchart TD Start[客户端发起请求] --> rule[匹配规则] rule --> Domain[匹配到基于域名的规则] rule --> IP[匹配到基于 IP 的规则] Domain --> |域名匹配到直连规则|DNS IP --> DNS[通过 *** DNS 解析域名] Domain --> |域名匹配到代理规则|Remote[通过代理服务器解析域名并建立连接] Cache --> |Redir-host/FakeIP-Direct 未命中|NS[匹配 nameserver-policy 并查询 ] Cache --> |Cache 命中|Get Cache --> |FakeIP 未命中,代理域名|Remote NS --> |匹配成功| Get[将查询到的 IP 用于匹配 IP 规则] NS --> |没匹配到| NF[nameserver/fallback 并发查询] NF --> Get[查询得到 IP] Get --> |缓存 DNS 结果|Cache[(Cache)] Get --> S[通过 IP 直接/通过代理建立连接] DNS --> Redir-host/FakeIP Redir-host/FakeIP --> |查询 DNS 缓存|Cache

  根据流程图,我们可以规定一种常见的使用方法 (大部分包含分流的 DNS 配置均采用下面范式),以实现域名解析的分流:

  • 填写一个一定可用的 default-nameserver 进行 DNS 服务器域名的解析,一般采用国内 DNS
  • 对于国内域名,使用默认 nameserver 项进行解析,一般采用国内 DNS
  • 填写对应的 fallback-filter 项,使得国外域名均被视为污染项,并重新使用 fallback 中定义的 DNS 服务器进行解析,一般采用国外 DNS

  米哈游内核在确定了向 nameserverfallback 组发送解析请求后,向同组内的各个 DNS 服务器同时发起请求,并选择相应最快的有效请求作为结果。
  实际上,DNS 服务器也是一种“服务器”,所以在访问 DNS 服务器的时候,我们也可以选择使用代理服务器来访问 DNS 服务器,注意,在使用代理服务器访问 DNS 服务器时,必须要先设置 proxy-server-nameserver,或者确保选择的代理服务器本身是不需要解析的 IP 地址,否则会出现鸡生蛋、蛋生鸡的问题。
  根据米哈游内核官方手册和 Github 上的示例配置可知,在访问某一 DNS 服务器时,若未进行特殊配置,默认使用出口网卡发起请求,这意味着如果无法在国内访问设定的所有 DNS 服务器,则域名解析将会失败,并在浏览器中返回未找到 IP 的错误提示。
  若要开启对特定的 DNS 服务器的代理访问,可以使用附加参数进行指定,指定的对象是网卡 (接口)/代理组/RULES,其中 RULES 代表按照路由规则进行代理连接,等同于对单个 DNS 服务器配置开启 respect-rules,参数使用 # 与原地址进行连接,如 '8.8.8.8#RULES';当指定的附加参数无效时,将会回退到出口网卡发送解析请求。

DNS 加密查询

  DoT (DNS over TLS) 和 DoH (DNS over HTTPS) 是两种常见的 DNS 加密查询技术,其端口号分别为 853 和 443。通过 DoT 和 DoH 加密的 DNS 查询服务能够避免被中间用户监听,防止隐私泄漏。
  然而,出于一些特殊的原因,国内用户可以“安全”地使用国内 DNS 的 DoT 和 DoH 功能,而无法使用国外 DNS 的相关功能,这也是本次事件的直接原因。
  在上面的 DNS 配置中,每一项服务器配置均可以使用 udp、tcp、DoT、DoH 四种类型,其 URL 协议前缀分别为 udp:// (默认,可省略)、tcp://tls://https://

事件经过

  5 日晚,在访问 codeforces.com 时,浏览器显示“找不到对应的 IP 地址”,对于所有的境外网站均无法找到对应 IP,国内网站均可以正常使用:

  原始的配置文件如下:

dns:
  enable: true
  use-hosts: true
  use-system-hosts: true
  respect-rules: false
  listen: 0.0.0.0:1053
  ipv6: false
  default-nameserver:
    - 223.5.5.5
    - 223.6.6.6
    - 119.29.29.29
    - tcp://223.5.5.5
    - tcp://223.6.6.6
    - tcp://119.29.29.29
  enhanced-mode: redir-host
  nameserver:
    - 114.114.114.114
    - tcp://223.5.5.5
    - tcp://223.6.6.6
    - tls://dns.google:853
    - tls://8.8.8.8:853
    - tls://8.8.4.4:853
    - tls://dns.alidns.com
    - tls://223.5.5.5
    - tls://223.6.6.6
    - tls://1.12.12.12
    - https://dns.google/dns-query
    - https://8.8.8.8/dns-query
    - https://8.8.4.4/dns-query
    - https://dns.alidns.com/dns-query
    - https://223.5.5.5/dns-query
    - https://223.6.6.6/dns-query
    - https://1.12.12.12/dns-query
  fallback:
    - tls://8.8.4.4
    - tls://1.1.1.1
    - https://8888.google/dns-query
    - https://1.0.0.1/dns-query
    - https://doh.opendns.com/dns-query
  proxy-server-nameserver:
    - https://doh.pub/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4
tun:
  enable: true
  stack: system
  auto-route: true
  auto-redirect: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53
  device: utun0
  strict-route: true

  本人使用的系统使用 systemd-resolved (/etc/systemd/resolved.conf) 进行域名解析,其配置如下:

[Resolve]
DNS=127.0.0.1
FallbackDNS=114.114.114.114
DNSStubListener=no

  显然,向 53 号端口请求的所有域名解析被米哈游内核提供的 dns-hijack 劫持,并交给正在 1053 号端口的服务处理。这是一个典型的分流解析配置,国内网站使用 nameserver 中的 DNS 服务器进行解析,而国外网站使用 fallback 进行解析,同时,default-nameserver 均为国内 DNS,以确保能够正确分流。

  使用 ip route show 查看默认路由表,虚拟网卡 utun0 有相应的路由规则,正常:

  使用 dig 命令发送 DNS 解析请求,返回 SERVFAIL,该返回码表明 DNS 服务器不可用或者不存在

  以上测试均在 TUN mode 打开,米哈游内核 DNS 解析器打开,systemd-resolve 使用米哈游内核 DNS 解析器情况下完成。调回正常设置后,浏览器报错变为“响应时间过长”,不再出现“无法找到 IP 地址”。

为何出现找不到 IP 地址?

  如果细看 fallback 中的 DNS 配置项会发现,里面只使用了谷歌公共 DNS 和 CF 公共 DNS,并未使用其他小众 DNS,且这两者在国内是可以正常使用的。对 fallback 配置项进行调整:

  1. 添加 8.8.8.8udp://8.8.8.8: 解析正常
  2. 添加阿里云 DNS 服务器 (四种类型中任意一种): 解析正常
  3. 添加其他国外 DNS 服务器的 DoT 和 DoH 服务: 无论添加多少,都无法正常解析
  4. 关闭米哈游内核 DNS 功能,使用 systemd-resolved 默认配置进行解析: 解析正常

  于是答案呼之欲出——无法在没有代理的情况下访问 DoT 或 DoH 国外 DNS,具体原因尚未明确,可能是由于笔者当地正册更改引起的。
  为了验证猜想,我们需要使用代理节点进行 DNS 查询。故使用官方文档中提到的附加参数 #RULES#策略组,并将策略组选择为可以正常使用的代理节点。经测试,经过代理后可以正常使用国外的 DoT 和 DoH 服务。

解决方案

附加参数 (不推荐)

  可以使用附加参数 #RULES#策略组,但有以下缺点:

  • 对每个 DNS 服务器都要写入附加参数,较为繁琐
  • 节点供应商给出的配置文件中配置组常带有 Unicode 表情字符,yaml 可以正常解析,但打字较为不便
  • 选择的策略组必须时刻保持可用状态,否则会使得无法进行域名解析,在没有安装本地 Dashboard 的机器上尤为不便

使用 respect-rules 选项

  开启 respect-rules 选项后,DNS 服务器也会通过配置中的 rules 来进行分流,无需对每个 DNS 都写一个附加参数,缺点如下:

  • 不建议和 prefer-h3 一起使用
  • 与附加参数相同,rules 分配到的策略组需要时刻保持可用状态,否则无法进行域名解析,对无本地 Dashboard 的用户不友好

fallback 配置项中写入国内可用的 DNS 服务器

  选择国内的 DNS 服务器如阿里云等 (非加密、DoT、DoH 均可用),对于大部分国外网站都能够进行正常解析,缺点如下:

  • 国内 DNS 服务器可能屏蔽部分国外网站

使用非加密的国外 DNS 服务器

  放弃使用 DoT 和 DoH 服务,直接使用 udp 协议的国外 DNS 服务器,缺点如下:

  • DNS 请求明文传输,失去安全性

  对于国内外的 DNS 服务器汇总可以参考网友整理,个人修改后的配置如下 (国内 DNS 均使用加密,国外不使用加密),可供参考

ipv6: false
external-ui: ui
external-ui-url: "https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip"
hosts:
  time.facebook.com: ntp.sjtu.edu.cn
  time.android.com: ntp.sjtu.edu.cn
dns:
  enable: true
  prefer-h3: true  # 优先使用 HTTP3
  use-hosts: true
  use-system-hosts: true
  respect-rules: false  # 是否对 DNS 请求使用 Rules 进行分流
  listen: 0.0.0.0:1053
  ipv6: false
  default-nameserver:  # 用于解析 DNS 服务器的 DNS 服务器, 可以使用加密
    - 114.114.114.114  # 114 DNS
    - 223.5.5.5        # AliDNS
    - 223.6.6.6        # AliDNS
    - 119.29.29.29     # DNSPod
    - tcp://223.5.5.5
    - tcp://223.6.6.6
    - tcp://119.29.29.29
  enhanced-mode: redir-host
  nameserver:  # 默认的 DNS 服务器, 用于解析国内域名
    - 114.114.114.114       # 114 DNS
    - tls://dns.alidns.com  # AliDNS
    - tls://223.5.5.5       # AliDNS
    - tls://223.6.6.6       # AliDNS
    - tls://dot.pub         # DNSPod
    - https://dns.alidns.com/dns-query
    - https://223.5.5.5/dns-query
    - https://223.6.6.6/dns-query
    - https://doh.pub/dns-query
  fallback:  # 回滚 DNS 服务器, 用于解析国外域名
    - 8.8.8.8          # Google
    - 8.8.4.4          # Google
    - 1.1.1.1          # Cloudflare
    - 1.0.0.1          # Cloudflare
    - 208.67.222.222   # OpenDNS
    - 208.67.220.220   # OpenDNS
    - 9.9.9.9          # Quad9
    - 149.112.112.112  # Quad9
    - 77.88.8.8        # Yandex
    - 77.88.8.1        # Yandex
    - 84.200.69.80     # DNS.Watch
    - 84.200.70.40     # DNS.Watch
    - 216.146.35.35    # Oracle
    - 216.146.36.36    # Oracle
    - tls://8.8.8.8
    - tls://8.8.4.4
    - tls://1.1.1.1
    - tls://1.0.0.1
    - tls://208.67.222.222
    - tls://208.67.220.220
    - tls://dns.quad9.net
    - tls://common.dot.dns.yandex.net
    - tls://77.88.8.8
    - https://dns.google/dns-query
    - https://cloudflare-dns.com/dns-query
    - https://1.1.1.1/dns-query
    - https://doh.opendns.com/dns-query
    - https://dns.quad9.net/dns-query
    - https://common.dot.dns.yandex.net/dns-query
    - https://77.88.8.8/dns-query
  # direct-nameserver:
  #   - system
  # direct-nameserver-follow-policy: false
  fallback-filter:
    geoip: true
    geoip-code: CN
    # geosite:  # 开启此项可能无法使用本地 Dashboard
    #   - gfw
    ipcidr:
      - 240.0.0.0/4
tun:
  enable: true
  stack: system
  auto-route: true
  auto-redirect: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53
  device: utun0
  strict-route: true

笔者非网络相关专业人士,如文中有错误,欢迎在评论区指正,感谢!

posted @ 2025-03-06 19:45  miyou379  阅读(659)  评论(0)    收藏  举报