你加了一条路由推送,重启服务,重新连接,客户端的路由表却和之前一模一样。这可能是两件不同的事:服务器根本没加载你的修改,或者客户端根本没安装它收到的东西。除了症状相同,这两件事毫无共同之处,所以第一步是先弄清你遇到的是哪一种。

下面的比较从进程出发由内向外进行,因为进程是判断哪个文件在生效的唯一权威。

你编辑的文件与进程读取的文件

先看 unit 以及它生成的命令行。在 systemd 主机上,systemctl cat openvpn@server 会打印出 ExecStart 行,而实例 unit 通常根据实例名推导配置路径,所以以 openvpn@office 启动的守护进程,与以 openvpn@server 启动的进程读取的是不同文件。把这一点与正在运行进程的 argv 对照。配置管理工具还带来另一种丢失修改的方式:它可以把正确的文件写到 unit 从未提及的位置,使一次「绿色」的部署看起来毫无效果。

时间戳能很快给出结论:如果文件比进程启动时间更新,进程就不可能读过它。路由器固件带来第三种情况,因为许多型号把设置保存在闪存里,并在启动时重建配置,这使得直接编辑磁盘上的文件处在错误的层面。

服务器推送了什么,客户端又安装了什么

一条被推送的路由要通过两道过滤。在服务器上,它必须位于已加载的配置中,而不是在注释块里,或在名字对不上的客户端专属文件中。在客户端,必须启用 pull,并且没有任何 pull-filter 在丢弃该选项。以 4 级 verbosity 连接,读取客户端报告的已推送选项:如果路由出现在这份列表里,服务器已经尽责,是客户端选择不安装它。

客户端专属文件是常见的困惑来源。以证书 common name 命名的文件只向该客户端推送选项,只要差一个字符,推送就会静默停止,双方都不报错。服务器会记录连接时看到的 common name,所以请拿这个值与文件名对照,而不是与你以为的客户端名字对照。

被推送的前缀与回程路由是两个不同的问题

如果客户端为了保留本地上网路径而故意忽略 redirect-gateway,就会产生第二个不相干的缺口。服务器的探测能到达隧道地址,回包却始终不到,因为发往服务器隧道 IP 的应答被客户端普通的默认网关路由走了。这里的问题不在被推送的子网路由;真正缺失的是一条把发往服务器隧道网络的流量送回隧道设备的路由。

在客户端补上这条路由,可以修好对服务器发起探测的应答。它不能替代被推送的子网路由,反过来也一样,因为两者描述的是相反方向的流量。

对照两端的路由表

任何改动之后,重新连接,查看客户端路由表中被推送的前缀和隧道设备。然后做双向测试:从客户端到被推送子网中的一台主机,再从该主机回到客户端。路由存在却不承载流量,意味着三种情况之一:对端没有转发,防火墙丢弃了流量,或者回包无路可返。

把三个标识放在一起记录:配置路径、unit 或实例名,以及你测试时使用的客户端身份。

这三样东西能让下一次故障变成五分钟的检查,而不是又一轮排查,也是隧道交给别人负责时同事最需要的信息。

重启之后依然存在的路由问题,往往根本不是路由问题;故障位于你反复查看的那张表的上游。

相关文章