PPP 的 peer 地址还是 VPN 端点:哪一个写进 via
比较把 PPP 接口读作子网与把 inet 和 peer 读作一条链路两端这两种理解,并看看策略表能够接受哪一个下一跳。
PPP 接口上的一行就能解决 VPN 主机上大部分的选路争论:内侧地址,以及印在它旁边的 peer。把这一对读成一个小型子网,你就会去找一个并不存在的网关。把它读成一条链路的两端,下一跳就显而易见了。这里的比较就是在这两种读法之间,因为之后建立的每一张表都会继承你所选的那一种。至于外侧的 VPN 端点,两者都不做任何决定。
一行接口的两种读法
取一个接口报告 inet 10.64.3.9 peer 10.64.3.1/32 的会话。子网读法把 10.64.3.9 当成 /32 孤岛上的一台孤立主机,然后去找一台路由器以抵达它之外的任何地方。由于链路上唯一的另一个地址就是 peer,这种读法最终会提议把 10.64.3.9 自己当作网关,这是循环的。
端点读法是有文档依据的那一种。在点到点接口上,peer 指的是那条链路远端的地址,因此 10.64.3.1 才是可用的下一跳,而 10.64.3.9 永远只是源地址。
这个差别决定了 via 里能写什么。把本地地址写在那里,会产生一条内核无法解析到邻居的路由,于是该条目要么通不过校验,要么一边吞掉流量一边在列表里看起来完全健康。peer 之所以可用,是因为它是链路上真实存在的目的地。两种读法在外侧 VPN 端点上是一致的:那是完全独立的身份,通过底层网络抵达,而不是通过它所终结的隧道。
会话已经安装了什么
在编写自己的表之前,先把链路带来的一切打印出来。受支持的 PPP 集成通常会在建立会话时安装一条设备路由和一条 peer 路由,这两条记录已经编码了正确的读法。
ip -4 addr show dev ppp0
ip route show dev ppp0
ip route show table main | head -n 5
像 10.64.3.1 dev ppp0 proto kernel scope link src 10.64.3.9 这样的设备路由不携带网关,因为接口本身就是路径。用 via 指名 peer 的路由是另一个对象,生命周期不同,会话断开时就会消失。把两种形式之一复制进持久表,却不检查它是如何被重新安装的,就是一条原本可用的隧道在重连后丢掉路由的常见原因。
比较这两份列表,而不是相信记忆。如果 peer 路由存在于 main 中,而你的附加表是空的,你就学到了地址行从未告诉你的东西。
规则和表是两个独立的决定
选择一张表和填充它是相互独立的步骤,而这里的比较之所以要紧,是因为调试时这两件事经常被混为一谈。一条把打标流量送往表 100 的规则,如果表 100 里没有匹配的路由就什么也不做;一张填充良好的表,如果没有规则指向它也无法到达。
半个默认路由不是默认路由。单独一条 0.0.0.0/1 只覆盖 IPv4 空间的下半部分,所以想要捕获一切的策略还需要配对的 128.0.0.0/1,或者真正的 default。读一份能用的配置、只复制两半中的一半,正是人们最终得到一条只在某些目的地上才出问题的路由环的原因。
对必须留在 LAN 上的地址保留有意的例外,并决定当查找在所选表中什么也找不到时会发生什么。一条显式的兜底路由比一张空表更容易推理,空表会返回不可达的结果,使应用看起来像是坏了,而不是被路由错了。
向查找提出你的应用所提的问题
ip route get 解析一条路径;ip route show 列出已存储的条目,两者可能不一致,而谁也没错。要把源上下文包含进去,因为基于源的规则只有在查找携带源的时候才会匹配。
ip route get 198.51.100.23 from 10.64.3.9
ip route get 198.51.100.23 from 10.64.3.9 iif ppp0
ip -4 rule show
第一条命令是从主机一侧提出的问题。第二条加入了入口接口,更接近被转发流量所经历的情形,而答案往往指向另一张表。两个目的地都不是真实可用的测试服务;198.51.100.23 是文档用地址,所以请换成你有权探测的主机。
即使一次正确的查找也只证明选择了一条路径。它没有说明对端是否接受流量,也没有说明回应能否按同样的推理返回。
比较翻转之处
主机流量和被转发的流量不只是进行不同的查找;它们在回程上会遇到不同的过滤。Linux 应用反向路径校验时,取所有接口与接收接口设置中更严格的那一个,所以改变某一个接口的值可能没有可见效果。基于标记的路由又加入了 src_valid_mark 关系,标记必须匹配,源才会被视为有效。
如果在出站路由看起来正确时回应消失了,先读取有效值再动手,并且只在有明确策略理由时才修改它们。
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.ppp0.rp_filter
sysctl net.ipv4.conf.all.src_valid_mark
依据证据在两种设计之间选择:如果应用绑定到 PPP 地址,一条源规则加一张保存 peer 路由的表就够了。如果这台主机为它后面的 LAN 转发,就还需要入口上下文与回程路径一致。当二者不一致时,修正路由的归属,而不是放松整台机器的校验。