为什么强制门户会挡住你的 VPN,以及如何重新登录
公共 Wi-Fi 在你设备上连一个数据包都还没发出时就完成了授权。门户会丢弃什么、你的 VPN 为什么误报,以及让你重新连上的顺序。
在开放网络中,接入点并不会直接把数据包交给互联网。上层的策略点会检查你的设备是否已获授权,在授权之前几乎所有流量都会被丢弃。你的 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 租约,或重新关联到另一个接入点。计时器一到,会话表里的记录就消失,授权前的规则集就回到登记时的样子。
已建立的隧道常常能活到看起来还很健康。保活消息还在往外发,而客户端是否注意到取决于它如何处理没有回应的流量,所以路径消失后状态灯可能还会绿一会儿。随后隧道掉线,每次重连都在同样的被封锁端口上失败。
到那一刻,客户端的错误会告诉你卡在哪一阶段,只要你仔细读:
| Symptom | What it means | Next check |
|---|---|---|
| Handshake times out with no reply | Pre-authorization drop on UDP | Load any HTTP page and see whether the portal appears |
| Immediate TLS error on 443 | The portal answered your TCP connection | Authorize, then retry the same profile |
| Authentication rejected | Your credentials reached the server | The network is fine, so treat this as an account problem |
| Connects, then drops repeatedly | Session or lease churn | Watch 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 配置文件之前先重新检查门户。