基于 Surge 的 DNS 优化指南

September 27, 2023

要获得良好的网络冲浪体验,DNS 设置是至关重要的。本文主要介绍如何使用 Surge 来提高 DNS 隐私和安全性,特别是在复杂的网络环境下,并分享一些经验,其中的原理也可以应用到诸如 Clash、Shadowrocket、Quantumult X 之类的软件。

Host 配置

Host 配置决定了你访问一个域名时 surge 如何解析这个域名的 DNS 记录,想获得高效安全的 DNS 解析体验,首先需要先根据你所处的网络环境配置合适的 Host 规则,先看一个配置示例:

[Host]
local.example.net = 127.0.0.1
local.xxx.net = 1.1.1.1

*xxxx-inc.com = server:system
*example*.com = server:system

*.* = server:https://223.6.6.6/dns-query

各种规则可以总结归类为三个梯队,优先级从上到下:

  1. 本地开发测试域名:直接将域名绑定到指定 IP
  2. 企业内部域名:用系统 DNS 解析(server:system),以保障可用性
  3. 公网域名:排除上述两种之后,剩下的就是一些公网域名了,可以考虑用 DNS Over HTTPS 或脚本自定义解析

需要注意的是,如果遇到配置了 /etc/hosts 不生效,可以检查对应域名是否在 surge 配置里指定了其他服务器解析,有时候会导致冲突。解决方案:

  • 可以把 /etc/hosts 里的内容挪到 surge 配置里
  • 或者关闭系统代理,只开启增强模式
  • 也可以使用 skip-proxy 配置项将对应域名加进去,这样就不走系统代理了
  • 如果在命令行里声明了 http_proxy 之类的变量,执行 curl 的时候需要指定 --noproxy '*' 参数避免将请求发送给 Surge

希望后续 surge 能优化这个点,提供更直观的配置。

减少本地 DNS 解析

对于希望走代理的请求,应该尽量避免它们在本地触发 DNS 解析,最好将你常用的需要代理的网站加到 surge 的规则列表中,例如:

[Rule]
DOMAIN-SUFFIX,google.com,📡 Proxy
DOMAIN-SUFFIX,x.com,📡 Proxy

如果你有大量域名需要代理,可以使用 Surge 提供的 rule-set 或者 domain-set 将这些规则和域名维护到单独的文件中,通过 URL 来引用和自动更新,例如:

# 自定义代理域名
RULE-SET,https://ruleset.example.com/proxy.txt,📡 Proxy

# GitHub 项目维护的代理域名
DOMAIN-SET,https://cdn.jsdelivr.net/gh/Loyalsoldier/surge-rules@release/proxy.txt,📡 Proxy

按照上述设置后,访问这些域名将不会在本地触发 DNS 解析,请求会直接发送到代理服务器,由它负责 DNS 解析,这样既可以提升隐私也可以获得更好的 DNS 解析结果。

好的 surge 配置应该尽量避免在前面的规则触发 DNS 解析,将需要触发 DNS 的规则尽量放置的末尾,下面是一个示例:

DOMAIN-SUFFIX,github.com,📡 Proxy
PROCESS-NAME,go-ipfs*,📡 Proxy
USER-AGENT,Figma,📡 Proxy

IP-CIDR,66.197.128.0/17,📡 Proxy,no-resolve

IP-CIDR,23.246.0.0/12,DIRECT
RULE-SET,LAN,DIRECT
GEOIP,CN,DIRECT
  1. 域名、UA、ProcessName 等不需要触发 DNS 解析的规则放第一梯队
  2. 包含 no-resolve 参数的规则不会触发 DNS 解析,可以放第二梯队,
  3. 最后是 IP-CIDR、LAN、GEOIP 这些必须触发 DNS 解析的规则

解决 Surge 增强模式和企业 VPN 冲突

很多大型企业内部都有自己研发的 VPN 客户端(基于 TUN 模式),当你在公司外通过企业 VPN 访问内部域名通常需要特殊设定优化才能避免和 Surge 冲突。

本文接下来使用 10.x.x.x 作为企业内网 DNS IP 示例。

[General]
# 10.x.x.x 换成企业内网的固定 DNS 服务器(如果有的话)用于兜底
dns-server = system, 10.x.x.x
# 企业内部域名确保返回真实的 IP,这样才能被企业 VPN 的 TUN 路由表匹配到。
always-real-ip =  %INSERT% *.your-corp.com

[Host]
# 将内网 DNS 管理的 zone 直接指定用内网 DNS 服务器解析
*your-corp.com = server:10.x.x.x

注意:尽量避免使用 surge 的 tun-excluded-routes 配置,如果你把公司内网IP段加入到这个配置,有可能引发和企业 VPN 的冲突或者各种兼容性问题。

例如 10.x.x.x 是你的企业内网 DNS IP,如果你将其加到 surge 的 tun-excluded-routes 配置里:

tun-excluded-routes = 10.x.x.x/32

重启 surge 后,查看路由表就会发现这个 IP 被 surge 又插入了一遍,你再 ping 这个 IP 就发现 ping 不通了(即使开了企业 VPN),因为此时它是走 192.168.10.1 这个家庭网关出口的自然访问不通了。

netstat -rn -f inet | grep 10.x
10.x.x.x      192.168.10.1       UGHS                  en0
10.x.x.x/32   10.2.x.x           UGSc                utun5

下面是一些辅助命令,如果配置过程遇到问题可以结合这些命令排查。

确定内网 DNS 服务器,可以使用下面的命令:(先关闭 surge 增强模式。)

scutil --dns
DNS configuration (for scoped queries)

resolver #1
  search domain[0] : router.home
  nameserver[0] : 10.x.x.x
  if_index : 15 (en0)
  flags    : Scoped, Request A records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

resolver #2
  nameserver[0] : 198.18.0.2
  if_index : 38 (utun4)
  flags    : Scoped, Request A records
  reach    : 0x00000002 (Reachable)

找到上面 nameserver[0] 后面的 IP,用 dig 测试能否解析内网域名:

dig your-corp.com @10.x.x.x

找到可以解析出正确 IP 的那个 namesever 就是内网 DNS 服务器。当然一般内网都有固定的 IP 段,可以辅助判断。

开启企业 VPN 之后可以通过以下命令查看哪些 IP 段会走企业 VPN 出口:

netstat -rn -f inet

下面示例中,10.2.x.x 就是企业VPN的网关地址,10.x.x.x/32,9.x.x.x/32 这些 IP 段是企业内网IP。

Routing tables

Internet:
Destination        Gateway            Flags               Netif Expire
default            link#38            UCSg                utun4
default            192.168.10.1       UGScIg                en0
8.x.x.x/28         10.2.x.x           UGSc                utun5
9.x.x.x/32         10.2.x.x           UGSc                utun5
10.x.x.x/32        10.2.x.x           UGSc                utun5

查看所有的 TUN 设备:

ifconfig | grep -B3 -A5 utun

更多参考

如果你喜欢我的内容,请考虑请我喝杯咖啡☕吧,非常感谢🥰 。

If you like my contents, please support me via BuyMeCoffee, Thanks a lot.