VPN 在家能连上,到了酒店 Wi-Fi 却超时
同一台笔记本、同一个账号、不同的网络。把错误码当成阶段来读,先核对名字,再在改动任何设置前抓取外层数据包。
笔记本接入家里的 Wi-Fi,客户端三秒就连上,而同一份配置一小时后在酒店却失败。这中间没有任何更新。带着客户一起梳理这件事,主要是知道哪个错误属于哪个阶段,因为有用的信息在客户端打印的代码里,而不在“它失败了”这个事实里。按顺序做完下面四步,你就能知道拒绝你的是名字、数据包、端口还是策略。
把错误码当作阶段,而不是结论
在隧道出现之前,客户端要经过三个彼此独立的里程碑。它解析服务器名字,从网络上的某个东西得到回应,并协商安全关联。每个里程碑都有自己的失败信息,尤其是 Windows,一旦你知道代码属于哪个阶段,它给出的不同代码就非常丰富。
| What the client says | Stage that failed | First thing to run |
|---|---|---|
| 868, name did not resolve | DNS, before any packet leaves for the server | Resolve-DnsName vpn.example.net |
| 721 or 806, remote computer did not respond | Outer protocol filtered, typically GRE or UDP | A capture on the local interface |
| 809, server not responding | A device in the path is dropping the outer flow | The same capture, from a second network |
| 789, security layer error | The security exchange started and was rejected | Certificate and proposal settings on both ends |
其中两个代码意味着网络是无辜的。789 表示数据包在流动,只是两端在加密上谈不拢,这是你可以在家修好的配置问题。868 表示根本不需要有数据包发出去,所以在名字解析之前,隧道设计毫无意义。把代码归到正确的阶段,比任何抓包都省时间,因为它告诉你后面三步里哪一步可以跳过。
如果客户端不是 Windows,就要相应地留有余地。第三方客户端会把其中大部分都压缩成“连接失败”,所以接下来两步完全不依赖这条信息。
先核对名字,再怪隧道
酒店和机场的网络会不断劫持 DNS,而用门户地址作答的解析器所产生的失败,看起来与服务器已死一模一样。把本地解析器的说法与公共解析器的说法对比一下:
Resolve-DnsName vpn.example.net -Type A
nslookup vpn.example.net 1.1.1.1
ipconfig /all | findstr /i "DNS Servers"
如果两个答案不同,你就在被牵引,在这一点解决之前,其余诊断都是白费。尤其是门户地址会欣然接受 TCP 连接然后卡住,所以用浏览器测试时,它看起来就像防火墙拦截。
现在确认你要到达的地址就是正在使用的那个。有些客户端会把上一次解析结果缓存到配置的整个生命周期,所以 DNS 变化之后重连,仍然会去旧地址。重测之前要把客户端彻底关掉,而不是在同一个窗口里按断开再连接。
找出哪一个外层数据包消失了
隧道有一条完全属于你和服务器之间路径的外层流,中间设备分类并丢弃的正是这条流。在客户端上抓它,然后把能用的网络和失败的网络作对比。在 Windows 上,内置抓包就够做第一次观察:
pktmon filter remove
pktmon filter add -p 500 -t UDP
pktmon start --capture --pkt-size 128
pktmon stop
pktmon etl2txt PktMon.etl
你要看的是数据包到底有没有发出去,以及有没有东西回来。只出不回,说明路径或远端把它们丢了;完全出不去,说明客户端根本没走到发送那一步,这就又回到名字解析或本地防火墙策略上。
在手机热点上重复同样的测试。这是你手上最有信息量的对比,因为它在保持笔记本、客户端和凭据完全不变的同时,把酒店里的每个盒子都从路径上移走。如果隧道在热点上起来了,就别再盯着服务器。如果在那里也失败,那就是客户端或账号的问题,网络从来不是原因。
更换一种传输方式并重测
一旦知道外层流被丢弃,实际的问题就是网络到底允许哪条流。大多数受限网络会放行出站 TCP 443,因为不放行它们自己就无法运作,所以把监听改到那里是常见的答案。在 OpenVPN 上,在服务器端改动之前,这只是客户端侧的开关:
openvpn --config corp.ovpn --proto tcp-client --remote vpn.example.net 443 --verb 4
IPsec 客户端在自己的设置面板里有对应的开关,通常称为“IPsec over TCP”或 NAT 穿透。改它同样是一种诊断:如果隧道在 TCP 上能起来、在 UDP 上却死掉,你就证明了网络过滤 UDP,也就找到了以后每次去那个站点都需要的设置。
不要一上来就动路由器功能。在酒店网络里关掉状态检测或洪水防护本来就轮不到你,而在自己的设备上,那是拿真实的防护去换一台笔记本。记下是哪个设置改变了结果,然后把它改回去,再去找网络本来就允许的传输方式。
在第二个网络上验证同一配置
在关闭工单之前,要证明这项改动在离开大楼之后仍然成立。用原来的设置回到原来的网络重连,抓下最初三十秒,并确认客户端达到与热点上相同的状态:
pktmon filter add -p 443 -t TCP
pktmon start --capture
Get-VpnConnection -Name "Corp" | Select-Object ConnectionStatus, TunnelType, ServerAddress
最后那条命令揭示的区分值得保留:配置可以报告隧道已连接,而内部路由却是错的,那会变成“VPN 起来了却什么都用不了”这个另一篇文章。如果改动之后隧道类型变了,那这份配置就不是你测过的那份。
最后,把结论写到下一个人会看的地方。“公司配置在这个站点需要 TCP 443,UDP 500 被酒店过滤”是一句同事可以据以行动的话。“VPN 在酒店不稳”不是。而且它保证下个月还会再浪费同一个小时。