两个配置都已连接,其中一个正悄悄承载本该属于另一个的流量。Linux 主机可以毫不费力地同时运行两个 OpenVPN 客户端。它做不到的是替你决定哪个进程可以占用哪个前缀。这个决定必须在第二条隧道建立之前做出,而不是在某个资源停止响应之后。

从第二条链路必须完成的工作开始

一个配置通往办公室、另一个通往实验室时,两条隧道都要在线,且任何一条都不能占用全部流量。某个必须从第二个配置出去的顽固应用需要的是策略规则,而不是第二条默认路由。备用链路同一时间只需一条隧道运行,因此备用不该随机器启动。

这是三种不同的配置,之所以混淆,是因为三者开头都一样:再加一个配置并成功连接。先写下打算采用的布局,再按它配置。一句意图说明能省下一小时的抓包。

systemctl list-units --type=service 'openvpn-client@*'
ip -4 route show default

第一条命令列出正在运行的实例,包括在管理器之外手动启动的实例。第二条打印当前的默认路由主张,这就是你之后必须解释的状态。

重叠的地址池先于路由出问题

两台服务器会乐意从同一个 10.8.0.0/24 分配地址。于是客户端在一个前缀里持有两个接口,没有任何东西说明哪个目标属于哪一边,结果看起来像路由故障,实际上却是编号故障。重新给地址池编号只需改一次配置;之后再怎么绕路由都要搭上一个周末。加路由之前先检查地址池。

也要看本地 LAN。一个编号为 192.168.1.0/24 的家庭 LAN 若被某条隧道一并暴露,也会产生同样的歧义,症状是主机名能解析、连接却永远建不起来。在打印路由之前,这看起来像名称解析故障。

ip -4 addr show
ip route show table all | grep -E '10\.|192\.168\.'

动客户端之前,先把两份输出与两个服务器配置对照。如果前缀重叠,就停下来重新编号,因为再多次重启也无法把它们分开。

给每个配置自己的单元,给每个前缀一个归属者

每个配置都有自己的实例名和配置文件,因此名为 office 的实例加载 office.conf,名为 lab 的实例加载 lab.conf。要通过服务管理器确认这层对应关系,而不是相信目录列表,因为 drop-in 可能改变实际加载的文件。对应关系搞错,你调的就是没在运行的那个配置。

然后确定由谁安装路由。当服务器推送互不兼容的路由集时,要么拒绝推送、自己列出前缀,要么让一个配置保留默认路由,用策略规则引导另一个。两个进程都安装默认路由,最终只会有一个沉默的赢家,而且没有任何书面记录。

systemctl cat [email protected]
grep -E 'route-nopull|pull-filter|redirect-gateway' /etc/openvpn/client/lab.conf

第一条显示该单元以及任何改变其参数的重写。第二条显示这个配置到底是否接受推送路由,而这正是决定后续一切的那个开关。

标记让回包留在它到达的接口上

当每条隧道服务不同来源时,回包可能从错误的链路离开,连接在第一个包之后就断了。可行的模式是:按入接口给到达的包打标记,在回包上恢复该标记,并给每个标记一张带各自默认网关的表。

通常必须对受影响的接口放宽反向路径过滤,因为回包确实可能从主表永远不会选择的链路到达。标记要收窄,绝不能捕获隧道自身加密后的流量,否则隧道会把自己送进自己里面。

ip rule show
ip route show table 101
sysctl net.ipv4.conf.all.rp_filter

添加新规则之前先读现有规则。优先级重复和被遗忘的表,就是标记策略看起来完全无效的常见原因。

停掉一条链路来证明隔离

两条隧道都在线时,记录每个接口的地址、每条隧道后面某台主机的路由,以及一个不相关目标所走的路径。要向内核查询查找结果,而不是只读一张表,因为一张表永远显示不了最终决定。

然后停掉一个实例,观察它的接口和路由消失,而另一个继续工作。幸存者出现中断,说明两者仍共用某个设备名、路由或防火墙规则,而没有人把它们分开。

把停掉的配置恢复,重复同样的检查。如果隧道只在重启后的第一次启动能存活,你看到的是生命周期缺陷,而不是路由设计。

相关文章