从 IPsec 网关向远端发起 ping,收不到回应,于是断定隧道坏了,而网关背后的每个工作负载其实都在正常收发流量。这两个结果并不矛盾。在网关上发起的 ping 是源地址在本机的数据包,网关会从自己的路由表中选择源地址。这个选择可能与真实站点流量使用的地址不同,从而改变哪条策略匹配、哪条回程路由生效。在从结果中读出任何结论之前,先确定这个测试要证明什么。

ping 能回答的三类不同问题

第一个问题是:从这台主机出发,远端到底能不能到达。第二个问题是:隧道的选择器或基于路由的策略是否放行来自某个特定源的流量。第三个问题是:从网关背后的工作负载转发的流量能否端到端正常工作。一条命令无法同时回答这三个问题,而把它们区分开的正是源地址。

先选定问题。否则一次失败的 ping 就会成为你原有假设的证据。

网关为什么选了一个你没预料到的地址

当你 ping 一个目的地时,本地协议栈会从与该目的地匹配的路由中选择源地址。在基于路由的隧道上,这个源地址可能是 隧道接口的链路地址,在很多站点设计中,它是为点对点跳选定的 169.254.x.x 地址对。这些地址的存在是为了让链路工作;它们不会在远端作为应用源网段被通告。

因此远端可能收到来自一个没有回程路由的地址的 echo 请求,或者来自一个没有任何选择器匹配的地址。隧道可以是健康的,而 ping 仍然失败,这正是本文所说的假阴性。

有意识地选择源地址

在可控的 Linux 网关上,选择一个已经在本机分配的源地址: ping -c 4 -I 10.30.0.1 10.40.0.20。这里的地址只是示例,请换成网关真实的内部地址和真实的远端目的地,并确认你选的源地址属于这台设备、且被站点策略放行。

不要借用工作负载的地址来做测试。冒充一台并未分配给网关的主机,会产生没人能复现的结果,在某些协议栈上还会以看似隧道故障的方式失败。

要看回程路径,而不只是请求

确认究竟是哪个源地址到达了远端目的地,包括途中任何有意做的转换。然后检查远端到该源地址的回程路由,以及放行它的选择器或策略。带着意外源地址到达的请求,是路由和策略问题,不是密码学问题。

这里抓包比再 ping 一次更有用:它能显示远端看到的源地址,而那个地址才是回应必须到达的地方。

然后再测工作负载

决定性的测试是从网关背后一台普通主机 ping 远端网关背后的一台普通主机。这会检验网关的转发角色、真实的应用源地址和真实的回程路径,而用户关心的正是这条流。

在笔记里把结果分开记:从网关本机的可达性、对所选源地址的策略放行,以及被转发的流量。成功固定源地址的 ping 是有用的证据,说明隧道确实承载了东西;但它不能证明每条转发的流都能工作。而一个自动选择、无法到达的网关源地址,也不能证明站点隧道已经中断。

不要为了得到一个诊断答案就为 169.254.0.0/16 添加一条笼统的路由。那是用一个有误导性的测试换来一个永久的理由路由决策,下一个人会在没有背景的情况下继承它。

相关文章