输入任意标题、正文关键词或分类开始搜索

按 Esc 关闭,按 Enter 查看完整页面

/ 程序员

Mac 排错实录:为什么一个叫「自动代理发现」的开关,会让你的 Tailscale 频频超时?

排查 macOS 上 Shadowrocket 内置 Tailscale 频繁报错请求超时的全过程:定位 NSURLSession 阻塞在 WPAD 代理自动发现(-1003)的底层机制,以及一键终端修复命令。

1. 起因与结论先行

今天在 macOS 上折腾 Shadowrocket 的内置 Tailscale 模块时,碰到了一个非常奇怪的现象:同样的 Tailscale 账号和节点配置,在 iPhone 上能够秒连,但在 Mac 上状态始终卡在「未连接」。

打开 Shadowrocket 的 VPN 诊断日志,每次启动内置 Tailscale 模块,5 秒后都会抛出一模一样的报错:

failed to fetch control server key: 请求超时。
control server key fetch failed

先给结论:问题不在代理节点,也不在 Tailscale 服务端,而是 macOS 的 Wi-Fi 设置里默认开启了「自动代理发现」(Auto Proxy Discovery / WPAD)。

在家庭 Wi-Fi 或热点环境下,开启这个选项会导致 macOS 的底层网络库(NSURLSession)在发起握手前,强行在局域网内寻找并不存在的 PAC 代理脚本。这一阶段恰好会白白阻塞 5 秒直到报错,从而把 Tailscale 客户端的公钥获取请求硬生生拖到超时。

在终端执行一行命令将其关闭后,Tailscale 瞬间恢复毫秒级连接:

networksetup -setproxyautodiscovery Wi-Fi off

2. 核心认知:为什么之前的思路走不通

排查初期,我按常规经验试了两个方向,但都走了弯路:

  1. 怀疑是 Tailscale Auth Key 过期:在 Tailscale 控制台检查密钥状态,虽然旧 Key 确实需要保持有效,但此时连服务器公钥都没拉下来,根本还没走到服务端校验 Key 的阶段。
  2. 怀疑是 DNS 虚拟 IP 污染:Shadowrocket 通常会将域名解析为 198.18.x.x 的保留地址用于路由接管。我在配置中给 controlplane.tailscale.com 加上了 always-real-ip,DNS 也确实拿到了公网 IP,但启动仍然固定在 5 秒后超时。
  3. 命令行 curl 正常,迷惑性极强:在终端单独执行 curl https://controlplane.tailscale.com/key,几乎瞬间就能拿到响应,甚至在普通浏览器里访问也畅通无阻。

为什么命令行 curl 能通,而 Shadowrocket 内置的 Tailscale 却报超时?

关键在于运行上下文的不同:普通 curl 走的是标准用户态进程网络栈;而 Shadowrocket 在 macOS 上是以 MacPacketTunnel(Network Extension)系统扩展运行的,其内部初始化 Tailscale 时调用了系统的 NSURLSession。

通过读取 macOS unified log 的详细日志,终于捕获到了真凶:

MacPacketTunnel: proxy:start_resolve
MacPacketTunnel: unresolved proxies, waiting for resolution
MacPacketTunnel: nw_proxy_resolver_create_parsed_array [C11.1.1 proxy pac] Evaluation error: NSURLErrorDomain: -1003

请求刚发出去,根本还没碰到底层 TCP 握手,就被系统拦下来去执行 WPAD 代理自动发现了。在普通宽带环境下,局域网根本没有配置 WPAD 服务器,系统只能干等 5 秒超时,抛出 -1003 错误后才放弃。而 Tailscale 获取公钥的超时预算刚好也是 5 秒,直接被整整耗死。


3. 完整复现步骤

如果你也遇到了类似的神秘 5 秒超时,可以通过以下确定性步骤进行检查与修复。

Step 1: 检查 Wi-Fi 的自动代理发现状态

打开终端,执行:

networksetup -getproxyautodiscovery Wi-Fi

如果输出为:

Auto Proxy Discovery: On

说明该网络接口开启了自动代理探测。

Step 2: 命令行关闭自动代理发现

无需重启电脑,直接在终端执行:

networksetup -setproxyautodiscovery Wi-Fi off

再次核对状态:

networksetup -getproxyautodiscovery Wi-Fi
# 预期输出:Auto Proxy Discovery: Off

Step 3: 重载模块验证效果

回到 Shadowrocket 中,将 Tailscale 模块重新开关一次。查看诊断日志,原先卡顿 5 秒的环节瞬间变为:

tailscale_client_new: initialised
tailscale: connected to network

状态立即变为“已连接”,整个握手耗时从超时失败变为毫秒级通过。


4. 踩坑记录与排错清单

现象 / 假象真实原因正确应对
终端 curl 顺畅,但应用内部请求超时curl 不一定触发系统的 WPAD 异步代理查找,而 Extension / App 内的 NSURLSession 严格遵循系统代理查找流程不要只用 curl 下结论,排查 Extension 问题需结合系统 unified log
怀疑是本地代理软件把流量阻断了WPAD 是「向局域网索取代理脚本」的协议,与本地运行的 HTTP/SOCKS 代理并不冲突关闭 WPAD 仅停止局域网广播,现有代理分流规则不受任何影响
报错 invalid key 与超时混杂之前可能存在过期 Auth Key 与 WPAD 超时的双重问题叠加先解决网络层的 5 秒超时,再核对 Tailscale 控制台有效的 Reusable Auth Key

5. 小结与适用边界

  • 最佳适用场景:个人 MacBook、家用网络、移动办公热点,以及本机常驻 Shadowrocket、Surge 或 Clash 等分流工具的开发环境。在这些场景下,系统默认的「自动代理发现」不仅毫无用处,反而经常成为阻断特定网络组件(尤其是 Network Extension)的隐形杀手,保持 Off 是最推荐的设定。
  • 不适用场景:部分跨国企业或大型高校内网,若网络管理员明确通过 DHCP Option 252 统一下发内部代理分流策略,则关闭后可能会导致部分内网资源无法访问。即便是这类环境,通常也建议由管理员直接提供固定的 PAC URL(自动代理配置)手动填入,而不是开启全网广播发现。