route 接受 Wi-Fi 接口名,毫无怨言地退出,而主机依然不可达。没有任何损坏;路由中的关系本身就是错的:接口标志说明目标位于哪条链路,而不是说明哪个路由器应接收发往别处目标的流量。命令之所以成功,是因为它在语法上有效,而不是因为它描述了一条可用的路径。

这一区别决定了 VPN 旁边的路由例外是真正生效,还是只是看起来合理。

接口是出口,下一跳是交接

在地址为 192.168.50.20 的 Mac 上、路由器位于 192.168.50.1 时,同一链路上的另一台机器可以直接到达。帧以那台机器为目的地址并放到网线上。不涉及任何路由器,限定于接口的路由表达的正是这一点。把远端换成另一栋楼里的主机,同一条命令就失去了意义。Mac 没有可放到网线上的第二层地址,因此接口标志没有可描述的对象。

链路以外的目标则不同。Mac 无法把发往第二层不可达主机的帧放到网线上;它把数据包交给能够到达的路由器。因此路由需要网关,而网关本身必须在所连链路上可达。

对链路以外的目标使用接口标志,等于让 macOS 把这个目标当作在网线上。内核随后无法为其解析第二层地址,数据包被丢弃,错误信息里没有任何有用的内容。

接口标志究竟声明了什么

Apple 的路由参考定义了用于可直接到达、无需中间人的目标的接口形式。这是关于链路模型的陈述,而不是偏好使用哪个适配器。通过 Wi-Fi 到达互联网主机仍需要该 Wi-Fi 链路上的路由器,路由必须写明它。

接口作用域是另一个属性。它把路由与特定接口关联,用于作用域判断,例如适用哪个源地址,但它并不会为接口自身无法到达的目标创造可达性。这两个属性回答的是不同的问题。

这就是命令可能被接受、出现在表中却仍然失败的原因。内核并不验证你的意图;它记录你声明的内容,而声明就是目标在链路上。无声的成功之后无声地丢弃是预期结果,而不是缺陷。在责怪网络之前,先把这条声明读给自己听。

链路外目标所需的路由

对于经由 LAN 路由器到 198.51.100.25 这类文档地址的核准路径,预期的关系是目标、下一跳 192.168.50.1,以及到达该下一跳的 LAN 接口。接口由下一跳查找隐含得出,而不是由 route 命令强制指定。

在 macOS 上,只读检查是 route -n get 198.51.100.25。把网关和接口两行一起看,确认网关是 Mac 真正能到达的地址。不同子网上的网关,或自上次网络变更后已消失的网关,会产生一条看起来正确却不转发任何流量的路由。

不要在长期有效的指令里写死 en0。接口名会随适配器、扩展坞和 VPN 客户端变化,而写错接口名的路由失败时,很容易被误读为更广泛的网络故障。

替换之前先读取当前选择

在添加任何东西之前,先查看系统已经选了什么、为什么。这个输出会告诉你流量是走隧道、走 LAN 路由器还是哪里都不去,并给出变更后用于比较的基线。没有它,你无法判断新路由是否生效。

然后检查地址族。为 IPv4 添加的路由对 IPv6 目标毫无作用,而同时解析到两个地址族的服务可能看起来时通时断。路由表和解析器回答的是不同问题,两者都必须与预期路径一致。

最后请记住,路由是一种选择,而不是许可。受管的 VPN 配置文件或客户端过滤器即使路由表指向直连路径,仍然可以禁止它,所以要用实际应用来测试,而不是假定表项成功就意味着排查结束。

隧道与策略会改变形态

点对点接口是另一种情况。隧道可以在没有以太网式网关地址的情况下承载路由,这并不自动算错。要应用接口真实的链路模型,而不是把 Wi-Fi 的例子推广到你看到的每一条表项。

对于变更请求,写下目标、核准的网络路径、当前网关和接口,以及预期由谁维护这个例外。所有者很重要,因为在提示符下敲的一次性路由不是策略,下一次重连就会把它抹掉。

如果要求是「在 VPN 开启时到达这台主机」,诚实的答案通常是通过本地路由器的特定主机路由,由拥有该接口的网络管理器安装。如果要求是「直接到达任何目标」,那么这个要求本身就需要先做策略评审,而不是先要一条 route 命令。

相关文章