笔记本从办公 Wi-Fi 切到手机热点,隧道还多撑了几秒,随后流量停住,而接口仍声称已连接。在服务器上,状态列表依旧显示旧的公网地址。这正是 float 存在的场景,也是人们期待它做到远超其实际能力的事情的场景。把边界搞清楚,就能把一次莫名其妙的卡顿变成要么改一行配置、要么彻底换一条排查路线。

float 放松什么,又从不放松什么

通常会话会一直与它开始时使用的外部地址和端口通信,来自其他任何地方的包都被丢弃。float 选项在对端已经证明过自己之后解除这条严格绑定,于是发生变化的源映射可以继续沿用同一会话,而不是被丢弃。密码学校验没有任何改变:密钥、证书以及任何 HMAC 保护都严格保持配置的样子。

这是逐包的判断,而不是关于谁能连接的策略。一台陌生机器从新地址发来包,并没有证明任何东西,它的包会像其他未认证流量一样被丢弃。只有通过会话自身认证的流量才能移动记录中的对端地址,这正是可以在客户端漫游的环境中放心保持 float 开启的原因。

它也不涉及内层隧道。被移动的外部地址 并不会重新分配隧道地址,不会改变地址池,也不会让对端获得新的访问权限。在隧道内部,移动前后使用的是同一身份和同一批下推路由。漫游同样不会重新协商数据通道,所以已协商的加密套件和密钥继续沿用。

让会话移动的那个包必须通过认证

按常规方式向配置好的远端发起会话,映射发生变化后由 float 负责处理。移动运营商在流量中途重新编号、NAT 网关改写端口映射,或者笔记本切换上行链路,产生的形态都一样:来自新四元组的已认证包,落到仍相信旧地址的会话上。

当有人问 float 是否生效时,有用的证据是一次完成的握手,以及随后被接受的源地址变化,而不是一行只讲地址的日志。把新旧两个外部地址与存活下来的会话对应起来,再确认流量确实继续穿过了隧道。

如果会话不是移动而是直接死掉,那么来自新地址的包很可能没通过认证,或者根本没到达。从客户端看两种情况一模一样。在服务器上,抓一次公网接口的包,就能在动任何配置之前分辨出是哪一种。

端点发现是完全独立的机制

float 不会按定时器解析域名,也不跟踪动态 DNS 记录。如果服务器主机名开始解析到新地址,空闲的客户端没有理由察觉,也没有来自新端点的包可供认证。那个问题属于重连逻辑、客户端自身的重试行为以及 DNS,而不属于 float。

再添加一次该选项,也无法弥补没有通往新地址的路由。当对端保持沉默时它同样帮不上忙,因为沉默的对端永远不会发出那个能移动任何东西的已认证包。

下层防火墙同样有发言权。只放行旧外部端点的规则会在 OpenVPN 看到变化后的地址之前就把它挡掉,任何客户端配置都修不好这一点。把允许地址的生命周期当作独立任务来审视;把规则放宽到任意来源,是用一个小问题换一个大问题。

当 NetworkManager 掌管配置文件

命令行配置文件和导入的连接是两套独立配置,改其中一个不会碰到另一个。在断定该选项不受支持之前,先确认保存下来的配置文件实际用的是哪种插件类型,以及它的值存放在哪里。检查或修改任何东西时,真正起作用的标识符是配置文件的 UUID。

要检查保存下来的连接,而不是最初的导入文件。如果当前生效的管理器从未应用过,.ovpn 文件里残存的一行什么都证明不了;一个没有对应选项复选框的编辑器,也不能说明协议不具备该能力。

不要为了让程序具备某种行为而去给打包的插件打补丁,尤其不要用为某个无关组件历史版本编写的 diff。如果已安装的集成确实无法表达该设置,正确的做法是使用受支持的配置文件,或采用部署负责人批准的另一种客户端路径。

去证明这次切换,而不是假定它

按故障发生的方式做测试。连接、确认隧道内有流量、强制外部地址变化,然后检查三件事:会话仍然存在、记录的对端地址已经移动、真实请求仍然到达目的地。少于这三条的都只是部分答案。

测试时保留可用的恢复通道,因为漫游实验经常把正在操作的机器困住。串口控制台或带外路径能把一次失败的测试变成五分钟的恢复,而不是跑一趟现场。

最后,只描述你实际演练过的那种情形。会话期间地址变更成功,并不能证明 DNS 迁移、另一种客户端实现或重建后的配置文件会有同样的表现。link-options 文档精确说明了该选项的适用范围;你的测试记录应当写明你实际覆盖了其中哪一部分。

相关文章