VPN 上 Wake-on-LAN 失效?修复 ARP 表项
魔术包能穿过隧道,但路由器的 ARP 表项过期后会直接丢弃它们。比较三条投递路径,然后永久固定 MAC 地址。
关机后立刻发一个唤醒包,电脑会起来;第二天早上同样的命令却毫无反应。VPN 配置没有任何改动,端口转发也仍指向正确的地址。差别在于时间:路由器的邻居表已经忘了这台睡着的机器,因此没有 MAC 地址可以写进帧。真正的原因是表项过期,而不是隧道,这解释了 VPN 上大多数 Wake-on-LAN 失败。
第一次能唤醒,下一次就不行
路由器转发到私有地址时,要先在邻居表里查目标。机器运行期间它会回应 ARP,映射因此保持新鲜。一旦关机,就没有人应答,表项几分钟后老化,之后发往该地址的帧会被丢弃,尽管 IP 和端口转发仍然有效。
这个规律能告诉你属于哪种故障。 从来唤不醒的情况指向投递环节:端口错误、目标错误,或者防火墙在包到达 LAN 之前就把它丢掉。唤醒一次成功、随后几小时都失败,指向邻居表项。一直正常、直到 DHCP 租约变化才出问题,指向地址分配,用保留地址即可解决。
在动 ARP 之前,先确认地址是稳定的。如果睡着的机器在租约到期后拿到新地址,那么为旧地址固定的邻居表项会同时变得永久而无效。先设好 DHCP 保留,让地址在重启后保持不变。
魔术包需要网络提供什么
载荷很简单:六个 0xFF 字节,后接目标 MAC 地址重复十六次,共 102 字节,通常发往 UDP 端口 9。在扁平 LAN 上它以广播形式发出,每个端口都能收到,关机的网卡也能认出自己的地址。
经过 VPN 时,包以单播发往私有地址,或以子网定向广播的形式到达路由器。单播情况下,路由器必须先把目标解析成 MAC 地址才能把帧放到 LAN 上,而主机睡眠时恰恰就是这一步失败。
有些工具发往端口 7 而不是 9,有些设备默认屏蔽定向广播。这些属于投递故障,不是 ARP 故障,所以改邻居表之前先检查目标和端口。
通往睡眠主机的三条路径
把帧送上 LAN 有三种可行做法,正确选择取决于你能控制什么。
| Method | What it needs | Where it breaks |
|---|---|---|
| Subnet-directed broadcast | A wake tool that accepts a broadcast address and a router that forwards it | Broadcast filtering, or a tool that only takes a MAC |
| Helper on the LAN | An always-on host such as the VPN server | No suitable host, or the host cannot reach the target VLAN |
| Permanent neighbour entry | Router shell access and the target MAC | NIC replacement or address change |
有常开主机时优先用它,因为它在链路上广播,不需要路由器做例外。路由器已允许且唤醒工具支持地址时,选择定向广播。两者都不可用、而你能在路由器上执行命令时,选择静态表项。
这三种方式并不互斥。永久表项也能让单播路径扛过睡眠,当 VPN 客户端只能发往特定地址时很有用。
把邻居表项设为永久
在带 Linux shell 的路由器上,一条命令就能固定映射。这里的值属于示例 LAN,必须换成你自己的:
ip neigh replace 192.168.50.23 lladdr 3c:7c:3f:12:9a:4e dev br0 nud permanent
ip neigh show dev br0 | grep 192.168.50.23这个 nud permanent 状态会让表项在 ARP 超时后依然保留,并在机器关机时用于转发。第二条命令用来证明表项存在,并显示它属于哪个接口;在带独立访客网桥或 VLAN 的路由器上,这一点很重要。
用固件提供的任意钩子让它扛过重启:/jffs/scripts 里放脚本、在充当网关的 Linux 服务器上用 systemd oneshot 单元、在 systemd-networkd 里写 Neighbor= stanza,或者在本地工具会读取的 /etc/ethers 里加一条记录。在 shell 里敲的命令下次重启就消失,这正是本来好用的修复突然失效最常见的原因。
从外网测试,并知道什么时候该撤掉
让机器睡眠,至少等十分钟,足够任何动态表项过期。然后从 VPN 客户端发出唤醒请求,同时观察路由器两侧:
tcpdump -ni tun0 udp port 9
tcpdump -ni br0 ether proto 0x0806 or udp port 9第一次抓包证明包从隧道进来了,第二次证明路由器把帧放到了 LAN 上。有效的魔术包是 102 字节、MAC 重复出现,所以长度和目标都要看。如果帧已经离开 LAN 网桥而机器仍不启动,剩下的问题在设备侧:快速启动、深度睡眠,或者切断网卡供电的 BIOS 设置。
换网卡时要删掉表项,把机器挪到别的地址时要更新它。永久映射是刻意的例外,而没人记得的例外,正是将来某台笔记本收到本该发给退役台式机的帧的原因。