VPN 对端能 ping 通其他接口,是因为这些地址属于本机
本地路由表会把数据包送到主机拥有的任何地址,无论该地址在哪个接口上。转发设置从不参与这条路径。
WireGuard 客户端连上后,去 ping 一个完全属于另一个接口的地址,居然收到了回应。抓包显示请求只出现在隧道上。没有任何东西坏了,而那条被小心关掉的转发设置跟这件事毫无关系。这是两条在示意图上看着相似、在内核里完全不同的路径之间的对比。
一条路径替别人转发数据包;另一条则把数据包交给主机自己。
发给主机的数据包留在主机里
远端客户端把一个 IP 数据包发往主机拥有的某个地址。路由对那个数据包只问一个问题:这个目的地是本地的吗?主机持有的每个地址都会出现在本地路由表中,而 那张表会先于主表被查询,所以数据包进了主机自己的协议栈,而不是从另一个接口出去。回应在本地生成,又沿着隧道回去,因为查询就是从那里来的。
这就是全部机制。不发生转发,不牵涉接口状态变化,涉及的地址也不需要能从任何别的地方到达。
为什么 ip_forward 不适用
转发管的是那些必须从与进入时不同的接口离开的数据包。ping 主机自己从不走那条路:数据包在本地被消费,回应在本地生成。因此设置 net.ipv4.ip_forward=0 在这里什么都不会改变,转发链里的规则也永远看不到这些流量。正确的控制点在输入路径上,按入接口或来源加以限定。
所以,关掉转发就以为主机被隔离了,只会带来虚假的安全感。
去读那张做了决定的本地表
ip rule show 通常会报告一条优先级为零的规则,把所有查找先送到本地表;ip route show table local 则以本地作用域列出主机自己的地址。那张表也包含处于管理性 down、但配置仍在的接口上的地址。静态分配的 IPv4 地址通常能在链路断开后保留下来,正因如此,ping 一个已经 down 掉的网桥仍可能成功,让运维人员吓一跳。
IPv6 恰恰在这一点上不一样。链路断开时,它的地址通常会被撤销,除非设置了 keep_addr_on_down。要比较两个协议族,而不是假定一条规则能覆盖两者。
对端到底能到哪儿
从网段上路由器自身地址发回的应答,说明不了该网段后面的机器。通过这条路径,对端到不了另一个接口后面的主机;它只能到达路由器自己拥有的地址。要判断转发到底允不允许,得在另一台 LAN 主机上测服务,而不是 ping 路由器的地址。
把对端限制在绑定于隧道地址的服务上,是输入策略的问题。在隧道接口上放行想要的服务,并限制可以使用它的来源,因为数据包确实到达了那里。
也要检查你打算下线的地址。从接口上删除地址,比在一台过期地址上叠加防火墙规则更可靠。