VPN 已连接,但某个应用上不了网?检查它的代理设置
隧道建立后,某个浏览器或工具仍可能继续使用旧代理。在更换服务器之前,先比较系统、应用和环境三处的设置。
你的隧道已经建立,状态页面显示握手正常,但有一个应用仍然什么都加载不出来。这个应用很可能还在把请求发给更早的中间层:系统代理、扩展程序、设备管理下发的配置文件,或者只有它自己的进程会读取的代理变量。更换 VPN 服务器不会碰到那项设置,这也解释了为什么同一台机器上的其他应用一切正常。从出问题的应用向外排查,在代理的问题弄清楚之前不要动隧道。
代理设置属于哪一层
有四个地方可以声称对应用的请求拥有权力,通常最窄的那一层获胜。操作系统持有全局代理和一个可选自动配置 URL;浏览器可以遵循它、覆盖它,或把控制权交给某个扩展程序;命令行工具读取自己的环境;托管策略可以在变更之后把上面任何一项重新钉回去。在动手修改之前,先确定哪一层说了算,因为清错层的效果看起来像是一次成功的修复,却会在下次登录时回来。
比较两个应用时,用同一个普通网站,而不是只有 VPN 才能打开的测试页。如果浏览器失败而终端下载成功,说明问题不在操作系统,差异在浏览器配置文件或其扩展程序里。如果两个都失败,但同一台机器上的第二个用户账户成功,说明这项设置是按用户区分的。这个比较只需要一分钟,却能排除大部分猜测。
读取每个工具实际使用的值
修改之前先打印配置,并把确切的代理字符串复制到可以还原的地方。对命令行工具来说,shell 变量是最快的检查,因为 VPN 客户端通常不会动它们。
env | grep -i -E 'http_proxy|https_proxy|all_proxy|no_proxy'
scutil --proxy
gsettings get org.gnome.system.proxy mode
netsh winhttp show proxy
只执行与眼前平台对应的那一行,然后读取输出中的主机、端口和凭据。像 http://proxy.corp.example:8080 这样的值意味着工具会为每个请求询问该主机,而空结果意味着它直接连接,真正的故障在别处。把输出贴进工单之前,先遮住用户名和密码部分,因为这些字符串是有效凭据的次数远比人们以为的多。
自带代理引擎的工具需要自己的证据。提高详细程度后,Curl 会说明它做出的决定,这比从环境去猜更可靠;同一个标志还能看出名称解析发生在本地还是在代理上。
清除覆盖设置,并重新测试同一个请求
只改一层,然后重复那个失败的确切请求,因为换一个 URL 什么都证明不了。先清除当前 shell 中的环境变量,因为这项改动可逆,也不会弄断隧道:
unset http_proxy https_proxy all_proxy
curl -v --max-time 10 https://example.com 2>&1 | grep -i -E 'uses proxy|connected to|http/'
如果详细输出仍然声称存在代理,说明环境并不是权威。往上走一层,而不是继续叠加覆盖设置。
在 macOS 上,确认没有自动配置文件在提供该值,然后关闭服务代理并确认更改。在 Windows 上要记住,WinHTTP 设置与按用户的浏览器设置是两个不同的对象,所以干净的命令行工具可能与仍指向旧服务器的浏览器共存。扩展程序同样值得怀疑:代理扩展只能改写某一个配置文件的请求,而这正是只影响一个浏览器、不影响其他任何东西的故障形态。
确认修复在重新启动后仍然有效
只在你编辑过的终端里生效的设置不算修好。从桌面启动器重新打开该应用,注销后再登录,观察旧代理是否会回来。
两项检查把真正的修复与临时的区分开,两者都应报告直连或预期的值。在干净环境中运行,可以看出被剥离的进程是否仍会读取系统设置。
env -i /usr/bin/curl -sS -o /dev/null -w '%{http_code} %{remote_ip}
' https://example.com
networksetup -getwebproxy "Wi-Fi"
如果重启后旧值回来了,来源就是某个托管策略或配置文件在重新应用它,而该策略的所有者必须移除这个例外。全程保持证书验证开启,否则拦截流量的代理在你关闭检查的那一刻就显得已经解决。最后把移除的值和日期写进笔记,让下一个人能分清有意的代理和被遗忘的代理。