一条 SSTP 连接失败时有两种表现,在用户看来几乎一样,但两者的修复落在不同层。超时意味着某项必需的交换从未完成;证书错误意味着身份材料已经送达并被拒绝。把后者当成前者,就会去查从来不是问题的防火墙和密码。能区分两者的证据就在客户端自己的日志里,前提是你在动手之前先读它。

两种失败,两套交换

SSTP 在形似 HTTPS 的会话里承载隧道,所以它能在只放行 443 的网络中存活。客户端完成 TLS 握手,用协议特有的方法发出 HTTP 请求,然后隧道在这条流里运行。这些步骤中任何一步失败都会终止连接,只有后面的步骤才涉及凭据。

这个顺序就是诊断。如果 TLS 握手从未完成,就没有任何凭据被发出,重置密码自然无效。如果握手完成之后卡住,说明身份已被接受,是请求路径上的某个环节拒绝了它。如果握手以校验报错失败,说明服务器答复了,而客户端不接受所听到的内容。三种结局,三个层次。

日志行通常会写明你处在三者中的哪一种,所以值得在第一次改动之前把它记下来。

超时意味着某个阶段从未完成

先从名称解析和 TCP 可达性查起,因为那里的超时和后面的超时看起来完全一样。端口检查工具报告 443 开放,只能证明有监听者接受了连接,证明不了更多。

下一个嫌疑对象是路径而不是主机。代理和能识别应用的防火墙有时会拒绝 SSTP 使用的请求方法,或者丢弃一条长时间保持打开的流,而这两种行为在客户端看来都像超时。同一主机提供的普通 HTTPS 页面能正常打开,隧道方法却被拒绝,所以用浏览器访问端点几乎证明不了什么。要区分这两种情况,请从没有代理的网络里测试。

Test-NetConnection vpn.example.com -Port 443
netsh http show sslcert
Get-WinEvent -LogName 'Microsoft-Windows-RasSstp/Operational' -MaxEvents 20

在对方任何回应之前就超时,并不能说明账号有问题,此时改密码只会多出一个变量。

证书错误意味着身份被拒绝

这里服务器确实答复了,所以网络是通的,问题转到身份上。把 客户端拨号用的名字 与证书实际声明的名字作比较,再核对有效期和签发链。

客户端不信任的私有 CA 与过期证书产生同一类错误,时钟偏差数小时也一样。直接用裸地址拨号会制造新的不匹配,因为证书声明的是名字而不是地址。在受管部署中,向管理员索取既定的信任配置,而不是接受错误页面提供的替换根证书。修好根因之前,校验保持开启。

openssl s_client -connect vpn.example.com:443 -servername vpn.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
w32tm /query /status

TLS 阶段一旦通过就保持原样,因为事后回退会掩盖到底是哪次改动修好了隧道。

两者容易混淆的地方

两种失败都表现为连接起不来,而且都出现在用户改动了无关设置之后。正是这种巧合让错误的修法在一段时间内显得合理。

两个习惯可以把它们分开。动手改配置之前先抓取客户端日志,把最初状态保留下来。每次只改一层,让下一次结果归属于已知变量。端口检查工具和浏览器都只是局部观察,不是完整序列,也都替代不了客户端自己的报告。这两个习惯都不花成本,而且都能缩短排查。

证书问题和可达性问题被分开记录,是有原因的。

用真实客户端复测,然后再往里查

具体修正到位之后,用真正的 SSTP 客户端和真实配置文件重试,而不是用浏览器标签页。

rasdial "Corp SSTP" /disconnect
rasdial "Corp SSTP" user '*'
Get-VpnConnection -Name "Corp SSTP" | Select-Object ServerAddress, TunnelType, AuthenticationMethod

如果会话能连上而资源仍然失败,隧道就不再是嫌疑对象:转向路由、DNS 和服务访问。那是另一场排查,证据也不同。保留已经工作的 TLS 和认证阶段,可以避免它变成第一场的重复。把失败的那个阶段写进工单,否则下一个人又要从头开始。

相关文章