如何在 Linux 上区分 VPN 推送的路由与静态路由
随隧道一起出现的网段可能来自三个源头。对比路由表,检查度量值,然后修复那个反复重新装回它的源头。
隧道一建立,笔记本上就出现一条前缀,于是感觉像是 VPN 装的。也许真是,但同样的结果也可能来自连接时运行的客户端脚本、列出该子网的连接配置,或者一条一直存在、直到接口出现后才开始生效的静态路由。选错源头,路由就会在每次清理后回来,下一个人再重复一遍同样的修复。下面的步骤在动手改动之前先把这三种情况分开。
第 1 步:说清是哪套机制在安装前缀
不同协议提供可达性的方式不同,把它们统称为通告会掩盖区别。OpenVPN 服务端通过控制通道推送 route 指令,客户端除非被 pull 过滤器拦住,否则就会安装。WireGuard 配置在本地列出允许的前缀,客户端既用它做加密密钥路由,也用它添加路由。IPsec 隧道与对端协商流量选择器,内核再根据这些选择器安装路由。
读任何路由表之前,先确认你的隧道用的是哪一种。连接时推送的路由不是路由协议的通告,也不承诺该前缀在远端后面可达。把机制记在前缀旁边,因为它决定了修复该落在哪里。
第 2 步:跨越一次连接对比路由表
在隧道关闭时保存主路由表,升起隧道,再保存一次,然后比较两次抓取结果。新出现的内容属于连接生命周期,保留不变的内容属于本地配置。
用 ip route show table main > /tmp/route-down.txt 抓取,连接后再抓一次。如果站点使用 IPv6,对 ip -6 route 也照做,因为那里缺失的前缀会产生看起来与路由无关的故障。
第 3 步:读度量值,而不只是看有没有
同一条前缀可以有两条条目共存,内核会选度量值更低的那条。度量值为 50 的静态路由会一直压过度量值为 100 的推送路由,即使两条都看得见——所以「路由在那里」和「流量在用它」是两句不同的话。
用 ip route get 10.20.5.7 直接问内核,读出它报告的网络接口。如果路由表里有隧道路由,流量却从物理网卡出去,那解释它的是度量值或前缀长度,而不是 VPN 客户端。分别对一台你确知在隧道后面的主机和一台你确知不在后面的主机重复查询,差别就能说明分流是否符合预期。
第 4 步:找出活得比隧道更久的条目
静态路由按设计会在断开后继续存在,陈旧条目正是从这里来的。指向已不存在接口的持久路由会悄悄吞掉一个子网;指向被复用接口名的路由,则可能在重启后把私有流量送出错误的门。
在发行版实际使用的位置检查持久侧:可能是 systemd-networkd 单元、NetworkManager 配置,也可能是客户端 up 目录里的脚本。用 ip route del 修好活动路由表,只撑到下一次连接。把这次删除当作对假设的验证,而不是修复本身。
如果远端给出的覆盖范围不对,应当向运营方提出,而不是把一切都过滤掉。丢弃所有推送设置,同时也会丢掉配置所依赖的 DNS 和分流隧道策略。
第 5 步:在归咎客户端之前先确认回程路径
对站点到站点或隧道后面的子网,远端需要有回到你客户端地址的路由,并且网关要开启转发。单向路径看起来和客户端路由故障一模一样,只不过握手和出站报文都成功了。
反向路径过滤在 Linux 网关上又加了一层陷阱。从与路由预测不同的接口到达的回复会被严格模式丢弃,经两家运营商的不对称路径会稳定触发它。判断是不是过滤造成的,要看网关而不是客户端上的丢弃计数。
第 6 步:测试资源,而不是 ping
选定路由正确之后,打开真正的资源并确认回程流量。ping 回复只证明一个方向的路径,对服务本身什么也说明不了;在缓存连接上应答的服务证明得更少。
然后在重连之后再走一遍整套检查。这套顺序的价值在于它能预测下一次连接会怎样,所以对比结果和度量值都该写进工单。