服务器说它推送了路由,客户端说它已连接,而目标地址依然不可达。正是三种原因造成了这副景象。添加路由在设备存在之前就执行了,客户端缺少修改路由表的权限,或者某条策略要求客户端忽略推送的选项。

从外部看它们一模一样,却需要不同的修复方式。请在做出路由决定的位置阅读客户端日志。

证明路由是不存在,而不只是坏掉

首先要证明路由不存在,而不是坏掉。在 Linux 上,ip route show dev tun0 会列出客户端在隧道设备上安装了哪些内容。在 Windows 上,route print 或 Get-NetRoute 以表格形式显示同样的内容。

路由存在却不转发流量是另一个问题。这会把排查引向转发和防火墙规则,而不是路由安装。

时序:添加在设备存在之前就执行了

客户端在控制通道建立、并且配置好接口之后,才会解析服务器的 PUSH_REPLY。也只有到那时,它才用平台提供的机制去改动路由表。Linux 走 netlink,Windows 使用需要提升令牌的 API。脚本或客户端如果在读到配置时就立即添加路由,就可能在 TUN/TAP 设备出现之前运行,内核会拒绝这次添加。

同一个竞争解释了为什么手写的路由能用而自动添加的不能:等你写入时,接口早已启动。

route-delay 就是为这种情况准备的,而 route-up 指定一个在接口和路由配置完成之后运行的脚本。把依赖隧道地址的路由放进那个钩子,而不是放在早期阶段。

权限:谁可以修改路由表

修改 Windows 路由表需要提升的令牌。普通用户启动的 GUI 可以通过服务设置适配器地址,却依然无法添加路由。此时日志显示的是类似拒绝访问的错误,而不是推送缺失。

以管理员身份启动 GUI,或使用基于服务的客户端,会改变这个结果。在不带所需令牌的情况下启动客户端的计划任务不会。

在改动任何东西之前,先确认客户端实际以哪个账户运行。版本和服务模式决定了哪些原因有可能成立,所以请把两者都记录在路由输出旁边。

策略:推送的路由可以被有意丢弃

route-nopull 会让客户端忽略服务器推送的路由,包括推送的默认路由,而隧道地址仍然被接受。推送的 DNS 和 DHCP 选项也会被同一条指令丢弃。这样的客户端并没有故障;它期待在自己配置里看到显式的路由行。

route-noexec 是另一种控制:它彻底阻止客户端执行路由变更。客户端无法映射的拓扑也可能产生类似结果,路由会被记录为被拒绝而不是被添加。请阅读报告决定的那一行日志,而不是猜测三者中哪一个成立。然后再检查实际生效的配置文件,因为导入器或管理工具可能添加了用户从未编辑过的选项。

在文本编辑器里看起来干净的配置文件,运行时仍可能携带被添加的指令。

对比推送列表与路由表

连接之后,把服务器的推送列表放在客户端的路由表旁边。在 Linux 上就是 ip route show dev tun0;在 Windows 上则是 route print 或 Get-NetRoute。如果路由不存在,先修复安装。如果路由存在而流量失败,就转向转发和防火墙策略。

记录客户端版本、运行账户,以及是否基于服务。这三点能告诉下一个人哪些原因已被排除。

相关文章