你有一台 Pi、一个可用的出站 VPN 配置,以及两台需要经它上网的设备。决定整个搭建的不是照哪篇教程做,而是你需要多少隔离。单端口让 Pi 与这些设备并排放在路由器 LAN 上,充当额外的网关;第二个端口则可以把它放进一个只有 Pi 能出网的分段。此后的一切——DHCP、防火墙范围、DNS、掉线时的处理——都由这个选择推出来。

两种方案真正的区别在哪

两种设计都在做路由。区别在于网线上还挂着谁,以及策略出错时会发生什么。

Layout A: Pi on the ISP LANLayout B: dedicated client port
CablingOne Ethernet port, existing switch portTwo interfaces: uplink plus a separate LAN port
Can a client bypass the Pi?Yes, by using the ISP router as its gatewayNo, unless the device has another radio or link
Who hands out addressesThe ISP router, with a per-client setting or a DHCP optionThe Pi, on its own LAN interface only
Blast radius of a mistakeAny LAN host, if a rule is too broadThe attached segment
Good fit forOne laptop, a console, a temporary test clientAppliances, always-on boxes, untrusted devices

真正的轴是隔离。方案 A 只是建议性的:设备若无视 DHCP 下发的网关而自己选路由器,仍能工作,只是没有加密。方案 B 由拓扑强制,因为没有别的下一跳可选。

方案 A:Pi 作为现有 LAN 上的额外网关

假设 ISP 路由器是 192.168.50.1,Pi 是 192.168.50.2,选定的客户端指向 Pi。关键在于两股不同的包流共用一条网线。客户端的内部包到达 Pi 后必须从隧道出去;Pi 自己发往 VPN 对端的加密包必须从同一条网线去路由器。两者在同一接口上反向而行,需要不同的处理。

用已安装的网络管理器给 Pi 配地址,不要用会和它抢设备的旧式接口文件配方。然后配置客户端:在单台设备上设静态网关,或用 DHCP 保留把 192.168.50.2 作为路由器下发。不要为两台设备就改掉路由器的整个 DHCP 范围,也不要假设客户端会尊重这个选项——要验证。

弱点在结构上,无法修补。该分段里任何客户端都能指向 192.168.50.1 以明文出网,而一台带第二个接口或蜂窝无线电的设备会彻底离开你的强制路径。如果那句话对相关设备不可接受,答案就已经有了:用方案 B。

方案 B:独立端口把设备关在里面

这里 Pi 在上行链路上保留 192.168.50.2、网关为 192.168.50.1,并在第二个接口上取 10.20.0.1/24 给接入的设备。此时 Pi 是一台双网路由器,而接入分段只有一条出口。

在承诺之前把范围与其他一切核对:隧道自己的子网、其他站点间前缀,以及通过 VPN 能到达的一切。与远端 LAN 冲突的 10.20.0.0/24 会带来那个要花一晚上才能定位的半可用结果。如果第二个端口是 USB 适配器,确认它受支持,并在网络管理器里钉住它的名字,以免重启后重新排序挪动你的 LAN 地址。

只在那个接口上运行 DHCP 监听。在上行链路上应答的服务器会与 ISP 路由器竞争,把你分段的地址发给家里其余部分。把它绑定到 LAN 接口,限制在声明的范围内,并让 Pi 自己的地址留在池外。

转发、转换,以及故障时关闭的规则

四件事常被说成一件,其实不是。打开转发(net.ipv4.ip_forward=1)只是告诉内核可以在接口之间搬包;它本身不授权任何东西,也不保证任何路径。选择出口是路由决策。允许这个包是 forward 链上的策略决策。改写它的源是 postrouting 决策。只做第一件的搭建,会得到一台乐于把客户端流量从上行链路送出去的 Pi。

把许可限制在你想要的源和流量应使用的接口上,并把回程路径和 Pi 自身需要的目标包含进来。如果提供方不把你的 LAN 前缀路由回来,再在隧道出口做转换。nftables 手册把转发、本地出站和源转换当作彼此独立的操作,这才是这里正确的思维模型。

常见的故障是物理接口上一条宽泛的 masquerade 规则。于是流量从 ISP 路径到达互联网,而从客户端一侧看,它完全像一条正常工作的 VPN。这什么也证明不了。把转换绑定在声明的出口上,并把规则留在主机已经在用的防火墙里,而不是新增一套会清空共享 postrouting 链的竞争规则。

然后处理隧道不在的情况。安装宽泛默认路由的客户端配置,也意味着隧道掉线时普通默认路由可能回来,客户端流量悄悄退回上行链路。在 退回明文不可接受时,forward 策略必须在 VPN 路由已消失的状态下明确拒绝客户端到上行链路的流量。要把它写成拒绝规则,而不是假设。Pi 自己到 VPN 对端的加密传输是独立的 local-output 流,必须保持允许,否则隧道永远回不来。

DNS 与 IPv6 需要各自的答案

如果客户端把 Pi 当作解析器,它们会打到一个本地监听者,Pi 再发起新的查询。这个上游查询走的是 Pi 自己的路由,而不是你为客户端写的 forward 规则,因此仅经隧道的客户端路径加上一个直接出网的解析器,就是一条没有任何报错的泄漏。要有意识地决定:是让解析器经隧道到达,还是接受某个本地解析器直连,并让 Pi 自己的出站策略与这个决定一致。

IPv6 又是另一种情况。为 IPv4 写的 forward 规则对 IPv6 毫无限制,而上行链路上的路由器通告可能给 Pi、并通过它给接入分段一条绕过你策略的第二默认路由。要么按同样的原则给 IPv6 一条自己的受保护路径,要么在客户端分段上明确限制它并说明这一点。

在依赖边界之前先测试它

只有在四项各自独立的检查之后才接受这个设计,因为那个诱人的单一测试——在某台客户端上打开浏览器——在多种坏掉的状态下都会通过。

确认一台真实客户端能经隧道上网,再确认同一台客户端在隧道断开时上不了网。确认 DNS 解析可用,且查询从你设想的地方出去。确认隧道重启后 Pi 自己的传输仍然可用,并且恢复不需要重启机器。最后检查一台你没有选中的设备:在方案 A 中它应照常工作,在方案 B 中它在该分段里根本不应存在。

  • 两个端口加一条拒绝规则给出强制;一个端口加一个 DHCP 选项只给建议。
  • 在错误接口上做转换看起来像成功,其实不是。
  • Pi 自己的流量、DNS 和 IPv6 各自需要一个决定,而不是一个推断。

相关文章