浏览器 HTTPS 成功而 SSTP 失败的原因
SSTP 在 443 端口的 TLS 内部运行,但它不是网页请求。请把 TCP、TLS 身份、SSTP 交换和 PPP 认证作为独立阶段分别测试。
浏览器通过 HTTPS 打开 VPN 主机名毫无问题,而 SSTP 客户端仍然拒绝连接。这两件事并不矛盾。SSTP 把 TLS 当作外层传输,然后在这条连接内部运行自己的请求和 PPP 载荷,因此页面成功加载只能证明一件很窄的事:主机在 443 端口回答了 GET。客户端问的是另一个问题,服务器对它的回答可能很糟。
页面能打开,隧道却建不起来
人们喜欢用浏览器测试,因为它快,随后就把结果当成服务器可达且配置正确的证据。它只是关于地址栏所打开路径的一次 GET 的证明,仅此而已。VPN 会话在同一次 TLS 握手之后才开始,但发出的是 网页永远不会使用的方法和路径。所以浏览器拿到 200 并不能说明 SSTP 端点是否存在。
把这两个观察分开,排查范围就缩小了。传输和证书链是通的,而它们之上的协议交换某处不通。这跟端口坏了或证书过期是不同的问题,需要不同的证据。
SSTP 客户端实际发送什么
客户端用 SSTP_DUPLEX_POST 方法向 /sra_{GUID}/ 路径发送 HTTP 请求,随后把连接主体保持为承载 PPP 帧的双向流。符合规范的服务器会回答 HTTP/1.1 200,并不再像 Web 服务器那样行事。其他任何情况都是特征:405 或 404 表示端点不存在,301 或 302 表示有东西在重定向请求,而立即出现的 FIN 表示代理或服务器关闭了流。
所以目标必须是 SSTP 服务器,而不是临时加上 TLS 证书的 Web 服务器。方法、路径和长时间保持的主体都是协议要求,反向代理无法仅靠配置补上。一个能完美转发普通 HTTPS 的代理,仍可能拒绝它不认识的方法。
代理或 Web 服务器在哪里打断流
中间设备在转发任何内容之前会检查 HTTP 请求行,带有非常规路径的自定义方法可能过不了它的规则。有些设备照常提供普通页面,却拒绝或中断隧道,于是客户端报告的是先建立后死掉的连接,而不是干净的拒绝。另一些设备接受请求,然后施加 PPP 保活撑不过的主体或空闲超时。两者从客户端看完全一样,所以失败的阶段比错误文本更重要。
让网站和 SSTP 共用 443 端口是路由选择,并不是承诺每一跳都以同样方式处理两种会话。如果路径上有负载均衡器、防火墙或 TLS 终结器,在动 VPN 配置之前先把它们列入嫌疑名单。
分别测试各阶段
按顺序执行检查,并在第一个失败处停下,因为每个阶段排除的层次不同。下面的 TLS 探测把证书身份与 SSTP 的任何行为分开。把主机名换成你自己的端点,读取它打印的 subject 和证书链。
openssl s_client -connect vpn.example.com:443 -servername vpn.example.com
然后把剩下的证据对应到各阶段,而不是从客户端报错去猜。下面的表格就是写进工单的检查清单,其中的特征能区分一种失败和下一种。
| Stage | What it proves | Failure signature |
|---|---|---|
| TCP to 443 | A listener exists and the path is open | Timeout or connection refused |
| TLS with SNI | The certificate matches the name you use | Name mismatch or untrusted chain |
| SSTP_DUPLEX_POST exchange | The endpoint is an SSTP server | 405, 404, 301 or an early FIN |
| PPP authentication | The user credential was accepted | Auth failure after a 200 response |
| Inner routing | A permitted destination is reachable | Tunnel up, no reply from the target |
在工单里记录最后一个成功的阶段,而不是写“无法连接”。MS-SSTP 规范记录了 TLS 握手之后的请求和 PPP 交换,也解释了为什么浏览器测试无法替代其中任何一个。
先身份,后 PPP
TLS 身份和 PPP 认证是先后关系,不是二选一,把它们混为一谈会把人引向错误的服务器设置。客户端先校验服务器证书及其预期用途,然后 PPP 协商自身状态,并用质询-应答方式或 EAP 认证用户。证书问题产生的错误与被拒绝的密码不同,两种错误都不描述对方覆盖的阶段。
把主机名换成地址,或点过证书警告,等于删掉了本可定位失败阶段的检查,而不是修复它。保留警告并读它。当 HTTP 交换从未走到 SSTP 行为时,也不要去重置 PPP 密码,因为凭据从未被索要过。