笔记本接入家里的 Wi-Fi,客户端三秒就连上,而同一份配置一小时后在酒店却失败。这中间没有任何更新。带着客户一起梳理这件事,主要是知道哪个错误属于哪个阶段,因为有用的信息在客户端打印的代码里,而不在“它失败了”这个事实里。按顺序做完下面四步,你就能知道拒绝你的是名字、数据包、端口还是策略。

把错误码当作阶段,而不是结论

在隧道出现之前,客户端要经过三个彼此独立的里程碑。它解析服务器名字,从网络上的某个东西得到回应,并协商安全关联。每个里程碑都有自己的失败信息,尤其是 Windows,一旦你知道代码属于哪个阶段,它给出的不同代码就非常丰富。

What the client saysStage that failedFirst thing to run
868, name did not resolveDNS, before any packet leaves for the serverResolve-DnsName vpn.example.net
721 or 806, remote computer did not respondOuter protocol filtered, typically GRE or UDPA capture on the local interface
809, server not respondingA device in the path is dropping the outer flowThe same capture, from a second network
789, security layer errorThe security exchange started and was rejectedCertificate 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 在酒店不稳”不是。而且它保证下个月还会再浪费同一个小时。

相关文章