无桥的 TAP:带路由上行链路的虚拟网段
TAP 设备是以太网段,而不是网桥。给它一个地址,在它与办公网前缀之间路由,并有意识地保持广播范围。
TAP 把以太网帧交给操作系统,这比大多数远程访问设计所需的能力更多,但比网桥少。内核可以给它地址、经它路由并为之设置防火墙,而无需将其接入任何物理网段。这种安排值得先理解:一个隔离的虚拟以太网段,其服务器充当通往真实局域网的路由器。它在隧道内提供二层行为,在隧道外提供普通 IP 转发,这是两个不同的承诺。其余部分是构建、路由、回程路径和回滚。
构建隔离网段
在 Linux 上,该接口需要三条命令:创建它、启动它、给它一个位于你所设想网段内的地址。选择一个不与办公局域网冲突的前缀并写下来,因为冲突在某个本不该存在的主机应答之前是看不见的。
ip tuntap add dev tap0 mode tap
ip link set tap0 up
ip addr add 10.77.0.1/24 dev tap0
这里没有任何东西需要网桥,也没有任何东西阻止以后添加一个。 内核的 TUN/TAP 文档描述了这个接口本身;是否加入网桥以及转发策略,是你随后做出的独立决定。
跨边界路由
启用转发,在转发链中放行这两个前缀,并添加一条通往办公网前缀的路由,以局域网路由器为下一跳。随后 VPN 一侧把发往办公网的流量作为自己的网关交给服务器,服务器则以自身而非网桥的身份转发这些数据包。关闭转发功能的 TAP 接口,是一个只在本地应答、越不过自身的网段,这正是常见的半成品状态。之后检查两侧的接口计数器,因为局域网一侧接收计数上升而发送计数持平,意味着转发链发生了丢弃,而不是路由有问题。
把路由和防火墙规则作为同一次变更来写,因为任何一项单独实施,都会造成客户端看来像路由故障的状态。
决定回程路径
要么局域网路由器学到一条回到 VPN 前缀的路由,要么服务器在出口处转换源地址。地址转换让回程路径变得简单,却破坏了源身份,因此目的端日志会为背后每个客户端显示服务器的地址。被路由的前缀保留了身份,但可能需要在你不管理的设备上做改动。
有意识地选择,而不是看哪个输入更快。单条被路由的前缀通常比地址转换更干净,而地址转换通常好过为一间实验室去教一台无人管理的路由器认识新前缀。
有意识地保持广播范围
在虚拟网段内部,DHCP、发现和邻居通告的表现与交换机上相同,因为它是一条链路。跨过被路由的边界就不一样了,所以办公网 DHCP 和服务发现需要明确的设计,而不能假设 TAP 自带这些能力。接口类型并不是为住在别处的服务做中继的。
这才是选择 TAP 的诚实理由:虚拟网段上确实有东西需要链路本地行为。如果没有任何东西需要,带被路由前缀的 TUN 设备更小,出故障时要解释的也更少。
验证,然后写回滚
从 VPN 客户端 ping 局域网路由器、ping 一台主机,并通过 TCP 打开一个重要的服务。然后检查计数器和转发链,因为从远处看,策略导致的丢弃恰恰像缺失的路由。回滚是构建的反向操作,应在开始前写进变更记录:移除路由、移除地址、删除接口。
如果需求确实是跨越两处的单一以太网段,网桥才是诚实的答案,也是影响范围不同的另一种设计。如果需求是可达性,带路由上行链路的隔离网段就能完成任务,日后需要解释的也更少。