你连上隧道,运行 ip route,发现原来的默认网关还在那里。下一个念头是客户端没能接管路由,于是你手动删除默认路由,结果彻底断网。那条记录本来就该保留。使用 redirect-gateway def1 时,OpenVPN 会安装两条更具体的路由,它们优先于普通默认路由,而不是取代它。旧网关留在原处,只是不再承载你正在测试的流量。

def1 到底做了什么

该标志会添加 0.0.0.0/1 和 128.0.0.0/1,两者都指向隧道。0.0.0.0/1 覆盖首字节为 0 到 127 的所有地址,128.0.0.0/1 覆盖 128 到 255,因此每个 IPv4 目的地都有一条比旧默认路由更具体的匹配。决定哪条路由胜出的是前缀长度,而不是度量值。

保留原默认路由是有意为之。客户端不必记住自己替换了什么,也不会改写承载它自身到 VPN 服务器连接的那条路由。断开时它会移除两条半路由,路由表恢复原状。

为什么用 /1 而不是 /0

路由选择的是最长匹配前缀,而不是最低度量值,所以无论默认路由的度量值是多少,/1 都胜过 /0。两条半路由都必要,因为一条 /1 只覆盖一半空间;如果只有 0.0.0.0/1,则 128.0.0.0 及以上的一切仍走旧默认路由,于是出现有些网站能通、有些不能的奇怪症状。

调高或调低旧默认路由的度量值毫无作用,另一个接口上度量值更低的默认路由也抢不走流量。前缀长度优先决定,只有前缀相同时才比较度量值。

读一张真实的路由表

已连接的主机可以同时显示这三条记录:隧道承载两条半路由,原网关仍在列表中。这些地址只是示例,不是要照抄的配置,因为接口名、隧道拓扑和额外路由因平台和客户端而异。

default via 192.168.50.1 dev wlan0
0.0.0.0/1 via 10.8.0.1 dev tun0
128.0.0.0/1 via 10.8.0.1 dev tun0

关键在关系:两条具体的半路由位于一条通用默认路由之上。旧网关那一行还在,因为没有任何东西取代它。

检查数据包实际走的路由

更具体的路由仍可能胜出:某段私有地址范围或本地子网的路由,或者 VPN 服务器自身的地址,都比 /1 更长。隧道需要一条通往其服务器的外部路径,把这条连接再送回隧道会立刻把它弄断。在 Linux 上,与其用眼睛读表,不如直接问内核:对你关心的目的地运行 ip route get,它会打印选中的路由、接口和源地址。如果配置了策略路由,也要检查规则,因为规则可能在查询主表之前就选中另一张表。

如果只有部分 IPv4 出问题,先确认两条半路由都已安装,再查找与故障目的地匹配的例外。删除旧默认路由不是修复办法,它还会移除客户端干净拆除隧道所需的那条路由。

def1 没有涵盖什么

两条 IPv4 记录对 IPv6 只字未提:有 IPv6 连接的主机会继续使用自己的默认路由,直到有东西单独重定向该协议族,这就是双栈网络中部分流量看似绕过隧道的原因。其他客户端和网络管理器实现全隧道路由的方式不同,它们的路由表不会一致。这里描述的 def1 行为属于 OpenVPN 文档中记载的标志,而不是机器上的每个 VPN。

终止开关回答的是另一个问题:隧道断开时机器会做什么。路由优先级决定隧道在线时流量去向,它不决定之后防火墙做什么。工作顺序:读表,确认两条半路由都在,对故障目的地运行 ip route get,检查策略规则,然后单独看 IPv6。把旧默认路由留在原处。

相关文章