理论上,在fakeip模式下,只要配置合理(在匹配到对应规则之前,前面的规则不会导致产生DNS解析请求),只有直连的请求才会在本地解析DNS,所有通过服务器的以及被拦截的请求不会在本地产生DNS解析请求记录。
clash在处理UDP请求时,会尝试寻找已经存在的socket进行复用,这个时候会对所有域名在本地查DNS缓存,缓存里没有的会进行DNS解析,导致了DNS泄露。
Chrome等浏览器,默认会尝试使用QUIC。第一次请求的时候本地的缓存里是查不到这个记录的,所以会在本地发起DNS解析的请求,导致浏览器查看的网址DNS泄露。
具体导致泄露的代码在tunnel.go里的handleUDPConn函数里的"local resolve UDP dns"部分,具体代码如下(已clash开源版代码为准):
```golang
// local resolve UDP dns
if !metadata.Resolved() {
ips, err := resolver.LookupIP(context.Background(), metadata.Host)
if err != nil {
packet.Drop()
return
} else if len(ips) == 0 {
packet.Drop()
return
}
metadata.DstIP = ips[0]
}
```
这段代码在最开始的地方,在分流代码之前,所以会对所有请求进行DNS解析(包括通过服务器连接的、被拦截的)。
检查了一下Clash.Meta的代码,相同的代码也存在,所以Clash.Meta也有相同的问题。根据作者的提交记录(见下面),代码是从premium版本同步过来的,所以盲猜premium版本也有此问题。
```git log
commit 3946d771e52fb72dfc91543dda8c785597622a9b
Author: Dreamacro <[email protected]>
Date: Sat Aug 13 13:07:35 2022 +0800
Feature: sync missing resolver logic from premium, but still net.IP on opensource
diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go
--- a/tunnel/tunnel.go
+++ b/tunnel/tunnel.go
@@ -183,1 +183,1 @@
- ip, err := resolver.ResolveIP(metadata.Host)
+ ips, err := resolver.LookupIP(context.Background(), metadata.Host)
```
解决方法:
第一种:在resolver种增加一个只查本地DNS缓存,不进行网络请求的查询函数来替换这里的resolver.LookupIP。由于clash已经删库了,所以只能自己进行。
第二种:没有能力自己改代码的mjj,可以在DNS的fallback-filter里指定敏感的网址只走国外的特定服务器(必须是加密的,不然也没用),这样就算本地多一次无用DNS查询,也不会导致DNS泄露给国内的DNS服务器。
第二种方法的缺点就是依然会多一次DNS请求,并且要持续维护这个列表。
第三种:浏览器直接关闭QUIC,chrome://flags/#enable-quic 这里设置
来源:hostloc
评论