桥接热点上的手机从某处获得地址和网关,而那并不是 Pi 的默认路由。修改 Pi 的默认路由只会改变 Pi 自己流量的去向。手机仍然使用被告知的网关,而当该网关位于远端 LAN 时,它的帧只是穿过网桥。两个消费者,两个决定。把两者分开,就能解释大多数“Pi 本身正常、热点却没有互联网”的报告。

两台设备,两个不同的网关决定

Pi 有自己的 IP 协议栈和自己的默认路由。手机也有自己的 IP 协议栈和自己的默认路由。

ConsumerWho chooses its gatewayWhat carries the traffic
Phone on the bridged APThe remote LAN router, delivered in its client configurationAn Ethernet frame toward that router crosses the AP and TAP bridge
Pi's encrypted connectionThe travel uplink's route toward the VPN peerThe Pi sends its own outer transport packets over the underlay

这张表就是全部模型。手机的网关是远端 LAN 上的地址,它的帧在第 2 层被转发到那台路由器。Pi 的默认路由只关乎 Pi 自己的外部传输,而该传输必须经旅行上行链路到达 VPN 对端。

网桥转发帧,不做数据包路由

Linux 网桥按目的 MAC 转发以太网帧,端口之间仅此而已。手机发往远端路由器 MAC 的帧被交换到 TAP 端口,跨过隧道而不触碰 Pi 的路由表。所以 Pi 的默认路由坏掉时手机仍可能正常工作,也所以正确的默认路由无法修复被发错网关的手机。

TAP 承载以太网帧,可以成为网桥端口。TUN 承载 IP 数据包,不能。如果你的设计把两者互换,网桥就不是网桥,后面的内容也不适用。

决定由谁分配手机的租约

DHCP 选项 3 是路由器选项,它告诉客户端其子网应使用哪个网关。当远端 LAN 的 DHCP 服务器是唯一分配者时,手机拿到远端网关,设计是自洽的。当旅行侧的其他设备先应答时,手机拿到本地网关,它的上网流量走旅行上行链路,而它访问远端 LAN 的流量则完全没有路径。

该广播域只运行一个分配者,并记录它分配了什么。

即使 Pi 从同一份租约取得地址,它也是另一种情况。要有意识地决定是否安装租约提供的路由,因为导入的远端默认路由可能把 Pi 自己的 VPN 传输拖进它想维持的隧道里。使用 systemd-networkd 时,这个决定是 DHCP 段中的 UseRoutes=;使用 dhclient 时,则是请求列表中的 routers 选项。

把上行链路留在桥接 LAN 之外

承载 Pi 外部 VPN 连接的接口不能成为网桥端口。一旦成为,加密传输就被交换进扩展 LAN,隧道最终承载自己的外层数据包,失败方式看起来像丢包而不是环路。也要明确保留 AP 能力与网桥支持。station 模式下的无线接口通常不能做网桥端口,因为 802.11 头部没有空间放网桥所需的第二个 MAC 地址。

定义 扩展广播域、一份地址规划,以及你真正需要的帧过滤。允许 Pi 上的 VPN 监听者,并不等于让每个桥接客户端都能访问 Pi 的管理服务。这些是彼此独立的规则,把它们当成一件事,正是热点悄悄变成敞开大门的途径。

出问题时把四件事分开测

当手机无法到达远端 LAN 时,四个观察可以分离原因。按这个顺序执行,并在第一个失败处停下。

ip route show default
bridge link show
ip -4 neigh show dev br0
tcpdump -ni br0 arp or icmp

先看租约:手机是否持有远端子网上的地址和网关?然后看网桥,确认 AP 端口与 TAP 端口都在转发。接着读邻居表,因为远端路由器条目未解析意味着帧发出去了却无人应答。最后在手机 ping 时观察网桥上的帧,这能告诉你故障是否根本在 IP 之下。

完成后记录每台设备各自拥有哪条默认路由。一行文档就能把“本地还是远端出口”变成有意识的客户端决定,而网桥参考也值得放在旁边。

相关文章