Clash TUN 模式下的 DNS 泄露排查:我以为全局代理就安全了
为什么开了虚拟网卡,运营商还是能看到你访问了什么?

前几天给 Windows 上的 Clash 开启了 TUN 模式,想着终于可以不用给每个应用单独配置代理,全局流量都走虚拟网卡,彻底解决部分应用不走系统代理的问题。
开了之后测试了一下,访问境外网站都正常,速度也没问题,以为这下万事大吉了。直到昨天偶然想起要做一下隐私检测,打开 browserleaks 的 DNS 检测页面,结果一眼就看到了红色的警告:存在 DNS 泄露。

也就是说,我以为所有流量都走了代理,结果我的 DNS 请求,还是有一部分发到了运营商的 DNS 服务器上——他们清清楚楚地知道我访问了哪些网站,哪怕我开了代理。
最开始我怀疑了什么
第一反应当然是:Clash 的配置写错了?
我打开 Clash 的配置文件,反复检查 DNS 部分的配置:enable: true 开了,default-nameserver 也配了,listen 也没错,TUN 模式的 enable 也是 true,stack 用的是 system,应该没问题啊?
是不是 TUN 模式没生效?我去看了下网络适配器,Clash 的虚拟网卡确实是存在的,ipconfig 看一下,地址也没错,Clash 面板里的连接也都是走的代理,那为什么 DNS 会漏出去?

我甚至怀疑是不是机场的问题,是不是代理服务器本身把我的 DNS 请求转发出去了?换了个机场试了试,结果还是一样,检测还是有泄露。那肯定不是机场的问题。
哪些表象其实是误导
最误导我的,就是“TUN 模式是全局代理,所有流量都会走虚拟网卡”这个想当然的认知。
我一直以为,开了 TUN 之后,Windows 上所有的网络包,不管是 TCP 还是 UDP,都会被 Clash 的虚拟网卡接管,然后转发到代理服务器。那 DNS 请求是 UDP 包啊,怎么会漏出去?
而且我看了下,Clash 的面板里,也没有看到对应的 DNS 请求的日志,也就是说,这些泄露的 DNS 请求,根本就没经过 Clash,直接从我的物理网卡发出去了?
这就奇怪了,TUN 模式不是已经把所有流量都接管了吗?为什么还会有流量直接走物理网卡?
我看到了什么关键证据
我开始翻 Windows 的网络设置,想看看是不是有什么奇怪的地方。
打开网络适配器的高级设置,看接口的跃点数(Interface Metric),哦,这里发现了问题:我的物理网卡的接口跃点数是 25,而 Clash 的 TUN 虚拟网卡的跃点数,默认是 35。
哦,原来如此!Windows 的 DNS 客户端,在发 DNS 请求的时候,不是看你的流量走哪个网卡,而是看网络适配器的优先级——它会优先用跃点数更低的网卡的 DNS 服务器!
也就是说,哪怕 TUN 模式接管了你的流量,Windows 的 DNS 客户端,在解析域名的时候,还是会先把 DNS 请求发到物理网卡的 DNS 服务器(也就是运营商的 DNS),因为物理网卡的优先级更高!
然后我再去看 DNS 检测的结果,果然,泄露的那几个 DNS 服务器,就是我运营商的本地 DNS。

这就是关键:Windows 的 DNS 查询策略,和我们想的不一样,它不是跟着流量走的,而是跟着网卡的优先级走的。
真正根因是什么
搞清楚了,根因其实是 Windows 系统的 DNS 客户端的工作逻辑:
Windows 的 DNS 客户端,会根据网络适配器的接口跃点数(Interface Metric)来排序,优先使用优先级更高(跃点数更小)的网卡的 DNS 服务器,来发送 DNS 查询请求。
而 Clash 的 TUN 虚拟网卡,默认安装的时候,会被分配一个比较高的跃点数,比物理网卡的要大。所以,Windows 的 DNS 客户端,永远会优先用物理网卡的运营商 DNS 来发请求,这些请求根本就不会经过 Clash 的虚拟网卡,直接从物理网卡发出去了,这就导致了 DNS 泄露。
哪怕 TUN 模式已经接管了后续的 TCP/UDP 流量,但是 DNS 查询这一步,已经提前泄露了。
最终修复方案是什么
搞清楚根因之后,修复就很简单了,只需要调整网络适配器的优先级,把 Clash 的 TUN 虚拟网卡的跃点数改得比物理网卡的小,让 Windows 的 DNS 客户端优先用 TUN 网卡的 DNS。
具体步骤:
- 打开 Windows 的「设置」->「网络和 Internet」->「高级网络设置」->「更多网络适配器选项」
- 找到 Clash 的 TUN 虚拟网卡(一般名字叫
Clash TUN或者类似的),右键点击「属性」 - 双击「Internet 协议版本 4 (TCP/IPv4)」,点击「高级」
- 取消勾选「自动跃点」,然后把「接口跃点数」改成 10(比你物理网卡的小就行,比如物理网卡是25,那10就够了)
- 确定保存,然后重启一下 Clash 的 TUN 模式
除此之外,还有两个辅助的配置,可以彻底避免这个问题:
- 在 Clash 的配置里,把 DNS 的
listen改成 0.0.0.0:53,然后把系统的 DNS 服务器改成 127.0.0.1,这样所有的 DNS 请求都会交给 Clash 来处理。 - 关闭 Windows 的「多播名称解析」和「LLMNR」,避免这些本地网络的解析请求泄露。
改完之后,再去检测,DNS 泄露的警告消失了,所有的 DNS 请求都走了代理,这下终于彻底安全了。

这次排查最值得记住的经验是什么
这次排查给我最大的教训就是:永远不要想当然地认为工具会帮你搞定一切。
TUN 模式听起来是全局代理,但是它管的是流量的转发,管不了 Windows 系统本身的网络栈的逻辑。不同的操作系统,网络层的处理逻辑是不一样的,Windows 的 DNS 策略,和 Linux、macOS 都不一样,不能用其他系统的经验来套。
还有,隐私保护这件事,真的是细节拉满,你以为你开了代理,开了 VPN,开了 TUN,但是只要有一个小细节没注意到,比如网卡的优先级,就可能导致你的隐私全部泄露。
最后,不管你用什么代理工具,定期做一下 DNS 泄露、IP 泄露的检测,真的很有必要,很多时候你以为没问题,其实早就漏了。
梦行志