在开放网络中,接入点并不会直接把数据包交给互联网。上层的策略点会检查你的设备是否已获授权,在授权之前几乎所有流量都会被丢弃。你的 VPN 客户端把这种沉默读成服务器已死。它很少明说这一点:WireGuard 把握手一次次发向虚空,OpenVPN 报告连接超时,IKEv2 则以错误 809 返回,说远端服务器没有响应。

门户到底控制了什么

强制门户是两件粘在一起的东西:策略决策点和重定向器。当你的设备关联并取得 DHCP 租约时,网络会把你置于授权之前的状态。

这个状态是一组防火墙规则。它通常放行 DNS,并允许到一份很短的 portal 主机列表的 HTTP 或 HTTPS,其余全部丢弃。白名单就是那座有围墙的花园,它几乎从不包含 VPN 端点。

这些丢弃没有一个是客气的。发往 VPN 服务器的包是被丢弃而不是被拒绝,所以客户端既收不到 ICMP unreachable 也收不到 TCP reset,只收到没有回应。视厂商而定,重定向器可能用指向登录页的跳转回应 80 端口,而 443 端口会被丢弃或劫持。跳转很容易识别,因为它带的是普通 HTTP 响应;443 上的劫持则需要一张你的浏览器会拒绝信任的证书。

授权本身通常绑定设备的 MAC 地址,有时绑定租到的 IP,并存在于一张带计时器的会话表里。登录会创建一条记录。放行你流量的那条防火墙规则只在记录存在期间存在,所以整个问题之后会再次出现,而你这边什么都没变。

为什么 VPN 握手还没开始就死了

每个协议有自己的传输方式,授权前的防火墙会以不同方式破坏每一种。Windows 和 iOS 上的 IKEv2 走 UDP 500 和 UDP 4500;这些端口上的丢弃表现为 809,或在分别报告各阶段的客户端上表现为类似域名解析的失败。走 UDP 1194 的 OpenVPN 会一直停在连接中,直到超时。走 TCP 443 的 OpenVPN 是有意思的情况,因为门户可能先完成 TCP 握手,再用自己的跳转页回应,于是你看到的是 TLS 错误而不是超时。

WireGuard 把机制展示得最清楚。它按设计只有 UDP,没有 TCP 备用通道,所以丢弃未知 UDP 的防火墙会彻底移除传输。客户端继续以越来越长的间隔发送握手初始化,并报告一个永远完不成的握手。那条消息里没有一处提到 Wi-Fi,也没有任何暗示要你打开浏览器。

平台会抢在你的 VPN 之前感知状态。Windows 会取一个已知 URL 来决定是否显示登录提示,Android 会请求一个本应返回 204 No Content 的端点,Apple 设备会打开一个小型的强制网络窗口。这些探测能生效,是因为门户用跳转而不是预期的正文来回应。同样的行为也解释了为什么门户看起来完全健康、而你的隧道已经死了:探测和隧道是按不同的规则判定的。

会话过期到底重置了什么

场所会因为与你的 VPN 账户无关的原因让会话过期:空闲超时、会话最长时长、新的 DHCP 租约,或重新关联到另一个接入点。计时器一到,会话表里的记录就消失,授权前的规则集就回到登记时的样子。

已建立的隧道常常能活到看起来还很健康。保活消息还在往外发,而客户端是否注意到取决于它如何处理没有回应的流量,所以路径消失后状态灯可能还会绿一会儿。随后隧道掉线,每次重连都在同样的被封锁端口上失败。

到那一刻,客户端的错误会告诉你卡在哪一阶段,只要你仔细读:

SymptomWhat it meansNext check
Handshake times out with no replyPre-authorization drop on UDPLoad any HTTP page and see whether the portal appears
Immediate TLS error on 443The portal answered your TCP connectionAuthorize, then retry the same profile
Authentication rejectedYour credentials reached the serverThe network is fine, so treat this as an account problem
Connects, then drops repeatedlySession or lease churnWatch the portal timer and the lease time

有一个细节会误导人:当会话绑定在 MAC 地址上时,重新加载登录页可能没用。你必须断开关联再重新加入,门户才会看到一次新的授权尝试,而不是已经过期的那次。

先登录,再把隧道架起来

有效的顺序是:授权设备、证明路径、启动 VPN、证明隧道,然后恢复你平时的封锁。最后一步很重要,因为到达门户所需的临时状态,正是终止开关存在要防止的状态。

带隧道外封锁选项的桌面客户端必须暂停,好让门户页面加载,并且在这段隧道外的窗口里应关闭敏感应用;这是本地流量在无保护状态下外出的唯一时段。受管理的常开设备应使用其所有者公布的流程,而不是由你去掉策略。如果门户弹出证书警告,停下来:接受它会把会话送进场所的拦截代理,而那个代理能读到你发送的一切。在 Android 上,常开 VPN 下的锁定会在隧道建立前阻断流量,有些构建无法把门户流量排除在外;如果你的做不到,就使用场所的备用接入或另一台设备,而不是让锁定保持关闭。Apple 的按需规则可以写成在探测成功前拒绝隧道,而这正是你在酒店网络里想要的行为。

用手上已有的工具按顺序验证。在隧道之前,运行探测并让请求头和正文都可见,观察你的 VPN 传输是否收到任何回应:

curl -sS -D - http://captive.apple.com/hotspot-detect.html -o -
sudo tcpdump -ni any 'udp port 500 or udp port 4500 or udp port 1194'

在授权之前,普通门户会给两种回应之一:一个 Location 指向登录页的 302,或一个正文就是门户页的 200。记下你拿到的是哪一种。登录前的跳转不是失败;是门户在告诉你该去哪里。门户报告成功之后,重复那条命令,期待一个正文正好是 Success 这个词的 200。正是这个字符串让探测有意义。如果你从未登录时主机就正常回应,这个网络里就没有拦截门户。抓包里,授权前的丢弃是发出去却什么都不回来的包,而可用的路径会在大约一秒内对同一条流给出回应。连上去,然后重复抓包。

门户说可以之后隧道仍然失败

登录成功不等于传输被放行。很多场所放行门户和普通浏览,却完全封锁 UDP,于是 WireGuard 和走 UDP 的 OpenVPN 坏掉,而 TCP 443 能用。如果 TCP 443 能过而 UDP 不能,那是场所的策略,不是你配错的客户端,所以换传输方式,或者接受这个限制继续用。之后重连仍然失败,就保留确切的错误;它点明了你卡住的阶段。

其他故障在设备上。仍绑定在旧 MAC 上的会话、带自己租约的第二块 Wi-Fi 网卡,或者缓存了门户证书例外的客户端,都可能在一次干净的重新授权之后继续失败。断开关联、重新授权,在动客户端设置之前先试一次。如果你想要所观察组件背后的架构,RFC 8952 值得一读。

如果门户本身拒绝授权,问题在账户或设备分配上,没有任何 VPN 设置能修好它。改 VPN 的出口国家不会重置场所的本地接入状态;那张表绑定在你的设备上,而不是你选的服务器上。去问场所的运营方并给他们时间,因为他们要看的是会话表。

下次出行前记下三件事:把门户页当作第零步、为你随身带的每台设备记下暂停封锁的步骤,以及一条你真正测过的备用传输。当十分钟前还能用的隧道再次停下时,把它当成已过期的授权,在动 VPN 配置文件之前先重新检查门户。

相关文章