客户端连接后获得 10.50.0.200,却无法访问 10.50.0.20 上的服务器,尽管两个地址都位于同一个 /24 中。这种配置背后的信念是:来自 LAN 前缀的地址会让客户端成为 LAN 的一部分。事实并非如此。客户端位于点对点链路上,服务器认为目的地是本地,而缺失的一环是没有人发送的邻居应答。

迷思:相同前缀意味着相同网段

地址前缀告诉主机哪些目的地可以直达、哪些需要路由器。它并不告诉主机目的地是如何物理连接的,也绝不保证目的地能够回答链路层请求。这是两个不同的问题,由主机上不同的表来回答。掩码回答第一个,邻居表回答第二个,而从 VPN 一侧看,只有第一个在你的控制之下。

当服务器向 10.50.0.200 发送数据时,它把目的地与自己的掩码比较,判定该地址为 on-link,然后向本地网段询问拥有它的硬件地址。该请求从 Ethernet 接口发出,而 VPN 客户端并不在那里收听。

客户端配置中的任何东西都无法从它这一侧解决这个问题。应答路径取决于 LAN 上是否有设备替客户端应答,或者取决于客户端是否拥有服务器不认为是本地的地址。

本地主机实际上如何处理这个地址

这种行为很容易观察,也值得在改动任何东西之前观察一下。在 LAN 主机尝试访问客户端之后,查看它的邻居表:一条不完整或失败的条目就是全部诊断。那一行还告诉你,故障是本网段内的,而不是隧道里的某处。

ip neigh show 10.50.0.200
ip route get 10.50.0.200
arping -I eth0 -c 3 10.50.0.200

路由查询会通过 Ethernet 接口把目的地报告为 on-link,这正是问题所在。如果在 VPN 会话保持期间邻居条目一直不完整,你就确认了缺失的一环是链路层解析,而不是路由或防火墙策略。

从另一个子网的主机上做同样的检查并比较。通过路由器访问客户端的主机根本不需要邻居条目,而这个差别就是缩小版的设计决策。

proxy ARP 如何提供下一跳

proxy ARP 让网关代替它能通过另一个接口到达的目的地来回答链路层请求。LAN 主机收到一个硬件地址,把帧发给网关,网关再把数据包转发进 VPN 会话。从主机的角度看,客户端就好像在网关后面。客户端配置没有任何改变。

MikroTik 的 RouterOS ARP 文档描述了针对借用所连 LAN 地址空间的拨入客户端的这种用法。该机制是对邻居解析的修复,它能工作是因为网关确实位于两条路径上。

这与把客户端桥接进 LAN 并不相同。网关仍然必须把数据包转发到正确的活动会话,它的路由和防火墙策略仍然必须允许该服务。proxy ARP 改变的是谁回答邻居请求,而不是谁被允许通信。

仔细阅读平台对模式名称的区分。RouterOS 将 proxy-arp 与 local-proxy-arp 分开,后者处理从同一接口进出的流量。它们不是可以互换的拼写,不加区分地同时启用并不是捷径。

proxy ARP 不能给你的东西

它不提供广播或多播发现。需要通过广播查找服务的客户端仍然会失败,因为网关把单播转发进会话,并不会让客户端成为 LAN 广播域的成员。依赖广播的发现协议,正是借用地址设计里“一件事能用、另一件不能用”这类报告的常见来源。

它不保留该地址。如果借用的地址也出现在 DHCP 池或静态分配中,两台设备可能得到同一个地址,结果取决于时序。成功登录并不是保留。

它也不能免除与 LAN 所有者协调的必要。一条让地址规划所有者意外的 proxy ARP 条目,就是一个等着在安静星期发生的支持事件。

与单独路由的地址池比较

另一种做法是给 VPN 客户端自己的前缀,让 LAN 主机路由到那里。这样服务器会把 off-link 应答发给自己的网关,网关把前缀路由到 VPN 端点,LAN 网段上根本不需要邻居解析。与借用地址外加 proxy 应答相比,这涉及的可动部件更少。

这种设计更容易推理,也更容易审计,因为客户端范围与 LAN 范围明显分开。它的代价是一条路由、一条返回路径和一条访问规则,也就是 proxy ARP 设计在更不显眼的地方同样需要的东西。

要有意识地而不是偶然地在两种模型之间做选择。proxy ARP 修复一种特定关系;路由地址池则让这种修复变得不必要。把选了哪一种以及为什么写下来,下一个人就不必从一条失败的邻居条目里重新发现它。

相关文章