上篇文说了如何在 ImmortalWrt 上配置 HomeProxy,实际上 Sing-Box 支持的平台非常丰富,几乎可以说是全平台都支,所以趁着热乎劲,把 MacOS 上的 ClashMeta,也换成了 Sing-Box,这也是不得不做的事,之前提到过,因为我买的机场主坏了,不给我订阅链接了。
MacOS 上,Sing-Box 的客户端叫做 SFM.app,和 HomeProxy 不同的是,它的页面及其精简,甚至配置也要手搓 json 文件。在 AI 的加持下,这个也不是什么问题,我是直接把 HomeProxy 的配置发给了 OpenAI,让他给我改成 json 格式的,很快就好了。
接着又解决了关于版本的问题,新版本的 SFM.app 已经在用 1.13 的 Sing-Box,比 HomeProxy 在用的 1.11 新了很多个版本,很多字段已经不能再用了,同时又多了一些新的字段,送走一批,又迎来一批。
等到跑起来之后,一切照常运行,但仔细观察 Sing-Box 的日志之后,发现没有解析 DNS 的记录,既然已经设置了劫持所有 DNS 流量,那么这个就是不太正常的,查看当前所有 DNS 服务器:
1 | scutil --dns |
发现 Sing-Box 的 DNS 排在第二个,而排在第一的是 Tailscale 的 DNS,但是 Tailscale 的 DNS 是 scoped,也就是只针对其的 MagicDNS 的域名生效,如果不匹配,应该放行的才对,但实际上,Sing-Box 劫持到的流量已经是查询完域名 IP 后发起的请求了,使用 dig 命令查验,确实走的是 Tailscale 的 DNS,这个命令虽不精准,但这种情况大致无误。
正常来说,Tailscale 只需要解析 MagicDNS 对着的域名后缀,既然它全部劫持不放行,那么就不能再将它放在首选,于是就关闭了 Tailscale 的 MagicDNS 功能,这就导致其域名都无法解析。当手动在 Sing-Box 中增加 DNS 规则,将 MagicDNS 的域名都放行后,依旧无法解析,但是这时,DNS 请求的流量已经可以正常被 Sing-Box 劫持了,这个是好消息。
后经推测,大概是因为流量进入 Sing-Box 的虚拟网卡后,如果设置为直连,就会直接从网卡发出去,而正常来说,Tailscale 的流量必须都进到 Tailscale 创建的虚拟网卡,才能通过基于 wireguard 的虚拟内网发往目标服务器,这一点应该查下路由表就可以验证,但是到这里就放弃了,因为即便查清楚,这条路也不是最佳选择。
继续分析当前情况,不能启用 Tailscale 的 MagicDNS,但是却要用 Tailscale 的 DNS 解析其相关的域名,不能通过 Sing-Box 的 DNS 规则分流,要在流浪进到 Sing-Box 就分流出去。
于是,查了一下 MacOS 发起 DNS 请求时,是如何选择域名服务器的:
1 | 1. 是否命中 per-domain resolver |
方案就有了,通过 per-domain 分流:只需要给 Tailscale 配置一个单独的 resolver 文件:
1 | sudo mkdir -p /etc/resolver |
文件名就是要匹配的域名后缀,文件内容是 DNS 服务器的地址。如此配置后,Sing-Box 仍然可以正常劫持 DNS 请求流量,同时,Tailscale 也可以通过 MagicDNS 的域名正常请求。
这里还有一个问题,dig 命令并不会完整按照所有的顺序去选择 DNS 服务器,可以使用这种方式替换,虽然没有那么方便,单是结果是准确的:
1 | 先监听 53 端口,DNS 请求都是从这个端口发出: |
然后再尝试解析域名,根据 tcpdump 命令抓到的包,就知道请求发往真实的目标服务器地址:
1 | dns-sd -G v4v6 <hostname> |