TCP 443 是一条带前提的退路,并不是能让隧道穿过任何过滤器的伪装。只有当服务商已经在该端口公布 TCP 监听,且路径能容忍长时间保持的连接时,它才有用。两者缺一,它通常就以超时的形式失败,而超时很少说明缺的是哪一个。是否要切换需要问三个问题,其中只有一个与端口号有关。

端口号不等于传输承诺

端口只是给端点起个名字;TCP 把它变成有序的字节流;OpenVPN 决定这条流里跑的是什么。同一个端口号上的 Web 服务器用的是完全不同的应用结构,所以共用 443 端口只是让两者在过滤器眼里相似,仅此而已。端口号是过滤器读取的线索,而不是改变数据包内容的属性。因为共用端口就把两者当成一回事,正是这里大部分混淆的根源。

中间设备很少对一个端口做出简单的允许或拒绝。许多会检查最初的几个字节,一些会锁定目标,还有一些会重置开得太久的连接。这就是同一个配置在一个网络里能用、在另一个网络里却超时的原因,也是退路值得作为受支持选项来测试、而不该当作承诺来信的原因。当过滤器检查流量时,端口号只是它最先看到的东西。

先确认监听,再动配置

服务器必须在该端口上配置好 TCP,客户端配置也必须请求同样的传输方式。把 UDP 配置改写成请求 TCP 并不会创造出监听,由此产生的超时与直接丢弃该端口的防火墙无法区分。服务商提供自己的 TCP 配置时就下载它,因为有些服务为每种传输分别公布端点和身份设置。手工编辑适合受控测试,却是不擅长猜测服务商意图的方式。

这种对应关系的两端都写在配置里,OpenVPN 项目的链路选项文档记录了两者。最小的一对长这样:

# server: accept TCP on this port
proto tcp-server
port 443
# client: request the same transport
proto tcp
remote vpn.example.com 443

三个条件决定这条退路是否划算

第一个条件是服务商根本提供这种传输;没有它,其他都不重要。第二个条件是路径能维持长时间的会话,因为有些网络会重置一直开着的连接,而不是干脆封掉端口。第三个条件是这条退路究竟是有意的例外,还是在掩盖一个你还没修好的故障。

每个条件都有廉价的检查办法。任何一处失败,从客户端看来都一样:

ConditionHow to check itWhat a failure decides
The server offers TCPThe operator's profile list, or a listening-socket check on the serverNo client-side edit can help
The path keeps long sessionsA test connection left open for an hourReconnects will look like server faults
The fallback is deliberateA change record naming the UDP faultThe underlying fault stays invisible

在比较各种传输方式之前,先完成任何强制门户的登录。尚未放行你设备的网络会同时阻断两种传输,那时的比较测的是门户而不是隧道。登录、确认普通浏览可用,然后才开始测试。

你要接受的代价:TCP 套 TCP

TCP 会重传丢失的报文段并保持它们的顺序。当同样使用 TCP 的应用跑在 TCP 隧道里时,两层恢复机制对同一次丢包作出反应,正是这种相互作用让隧道在有丢包的路径上显得很慢。症状是延迟和抖动,而不是干净利落的失败,这就很容易把责任推给远端。下结论之前,先从客户端在两种传输下各测一次。

UDP 避免了这种嵌套,这也是服务商更偏爱它、只把 TCP 当作备选的主要原因。稳定的 TCP 连接仍然比连不上的 UDP 连接更有用,所以比较的是两种真实代价,而不是好选项与坏选项。比较时保持设备和接入网络不变,否则结果描述的就是错误的变量。

有些客户端功能只针对一种传输有文档,所以退路配置可能悄悄丢掉你依赖的行为。在把 TCP 配置当作简单替换之前,先读一下该项的传输要求。

换一种传输也碰不到的故障

过期的证书仍然需要检查时钟或续期,被拒绝的账户仍然需要正确的凭据。保留服务商提供的服务器身份校验,因为一个熟悉的端口号不能证明任何人。端口有回应,只说明有东西在监听。

如果隧道起来了、目标仍然不通,剩下的问题在于连接之后的路由或名称解析,而不是传输。顺着这条路走,别在端口之间打转,一个下午就是这样没的。配置只告诉你该试哪种传输,从不告诉你 UDP 路径为什么失败。

相关文章