局域网主机与 VPN 客户端之间的可达性问题,往往要追溯到地址规划本身。给这台主机一个 10.0.100.0/22 的接口,它就会把 10.0.100.0 到 10.0.103.255 的每个地址都视为直连,包括悄悄放在 10.0.101.0/24 的客户端地址池。应答永远不会交给路由器,因为从主机的角度看,根本没有路由器参与。数据包被发往一个邻居,并在链路上索要。

这一机制背后是一整类报告:隧道已建立,服务器也有路由,局域网主机却仍然到不了客户端。

吞掉 /24 的 /22

把前缀当作范围来读,而不是当作字符串。一个 /22 含 1024 个地址,而 10.0.100.0/22 覆盖 10.0.100.0 到 10.0.103.255,因此位于 10.0.101.0/24 的地址池完全落在其中。这个错误能通过评审,是因为地址池的前几个八位组与局域网的前几个八位组看起来不同,只有第三个八位组才暴露了包含关系。在宣布两者分开之前,先把两个范围用数字写出来。

同样的包含关系也可能反过来出现。一个因为当前无人使用而看似空闲的地址池,仍可能落在某个站点路由器宣告的前缀之内,而地址规划是唯一能说明这一点的文档。

直连意味着 ARP,而不是路由

当一台拥有 /22 接口的主机发往 10.0.101.25 时,内核会把目的地址与该接口的前缀比较,并发现匹配。数据包于是变成邻居查找,而不是被路由,在以太网上邻居查找就是针对该地址的 ARP 请求。如果该地址属于位于路由网关之后的 VPN 客户端,局域网上没有任何主机拥有它,请求便无人应答,数据包被丢弃。隧道没有过错,客户端也始终看不到这些流量。

这就是为什么故障看起来不对称,而且偶尔间歇出现。VPN 主机常常能到达局域网,因为它自己的路由指向正确方向;而局域网主机无法应答,任何缓存了过期 ARP 表项的东西都会让症状闪烁。

TUN、TAP 以及各自承载什么

TUN 设备承载 IP 数据包,TAP 设备承载以太网帧。路由式 TUN 链路不需要承载 ARP 也能提供 IP 可达性,这正是上面那个无人应答的请求属于预期现象、而非故障的原因。带刻意网桥的 TAP 可以扩展广播域并让 ARP 工作,但它改变了客户端能看到什么,要求两端支持相同的帧格式,而且是对网络模型的重新设计,而不是对重叠前缀的修复。为了治好地址规划错误而把路由式部署换成 TAP,是用一个小问题换一个大问题。

在下结论之前,先记录 ARP 请求出现在哪里、由哪个系统发出。发送方告诉你的是它对目的地的判断,而不是隧道做了什么。

设计一个不可能重叠的地址池

选择一个位于所有已连接前缀和所有宣告的站点前缀之外的地址池,然后再加上让它在两个方向都可达的路由。规划中未使用部分的 10.8.0.0/24 这样的范围很容易推理,需要访问它的局域网会得到一条指向 VPN 服务器的静态路由。分配、宣告路由、允许的源地址和防火墙规则要一起改,因为它们描述的是一套设计,而不是四个设置。

服务器上的 Source NAT 可以把地址池隐藏在局域网可路由的地址之后,这是正当的迁移工具。但它也改写了源地址,于是局域网失去了把连接归属到具体客户端、以及按客户端应用规则的能力。

验收时,请使用真实客户端实际分配的地址,以及来自局域网主机的真实应用请求,然后确认应答走的是规划中的网关,而不是链路。

相关文章