远程唤醒 Wake-on-LAN
七月 18, 2025 [network] #wol #network #ethernet #router远程唤醒 Wake-on-LAN
原理
WOL 通过发送 Magic Packet 唤醒目标计算机。Magic Packet 是一个广播帧,由以下组成:
- 6 字节的
0xFF(全 1) - 目标 MAC 地址重复 16 次
- 共 102 字节
通过 UDP 端口 7 或 9(默认)发送,也可以是二层帧(EtherType 0x0842)。
关机状态下网卡(NIC)保持低功耗待机,监听 Magic Packet,收到后触发开机。
Linux 被唤醒端配置
# 查看是否支持 WOL
ethtool eth0 | grep -C 3 -i wake
# Supports Wake-on: pumbg 表示支持
# Wake-on: d d=禁用, g=已开启
# 开启 WOL
ethtool -s eth0 wol g
WOL 选项含义:
| 值 | 含义 |
|---|---|
| d | 禁用 |
| p | 物理活动唤醒 |
| u | 单播消息唤醒 |
| m | 多播(组播)消息唤醒 |
| b | 广播消息唤醒 |
| a | ARP 唤醒 |
| g | Magic Packet 唤醒 |
| s | 带密码的 Magic Packet 唤醒 |
推荐使用 g(Magic Packet),避免路由器广播误唤醒。
确保重启后自动开启
方法一:添加到 /etc/rc.local:
/sbin/ethtool -s eth0 wol g
方法二:创建 systemd 服务:
[Unit]
Description=Enable Wake On Lan
[Service]
Type=oneshot
ExecStart=/usr/sbin/ethtool --change enp3s0 wol g
[Install]
WantedBy=basic.target
发送 Magic Packet
# wakeonlan(UDP,无需 root)
apt install wakeonlan
wakeonlan <MAC-address>
wakeonlan -i 192.168.1.255 <MAC> # 指定广播地址
wakeonlan -i 192.168.1.255 -p 4242 <MAC> # 指定端口
# etherwake(二层帧,需 root)
apt install etherwake
sudo etherwake <MAC-address>
sudo etherwake -i eno1 <MAC-address> # 指定接口
抓包验证
# 监听 Magic Packet(UDP 端口 9)
sudo tcpdump -vvnn -i eno1 'ether dst host ff:ff:ff:ff:ff:ff and udp port 9'
# 监听二层帧 WOL
sudo tcpdump -vvnn -i eno1 'ether[12:2] == 0x0842'
# Wireshark 过滤
udp.port == 9 or udp.port == 7 or eth.type == 0x0842
WOL 报文类型总结
| 工具 | 以太网地址 | IP 层地址 | 协议 |
|---|---|---|---|
| wakeonlan | 单播 | 单播/网段广播/255.255.255.255 | UDP |
| etherwake | 单播/广播 | 无(纯二层) | EtherType 0x0842 |
| Windows WOL App | 广播 | 网段广播 + 255.255.255.255 | UDP |
公网唤醒
必要条件
- 公网 IP 或 DDNS
- 路由器端口转发:将外网端口映射到目标机器的 IP:9(UDP)
- ARP 绑定:路由器中绑定目标机器的 MAC-IP,防止关机后 ARP 表丢失
常见失败原因
- 路由器端口转发不支持映射为广播地址(如华为路由只支持已获取 IP 的设备)
- 路由器在设备关机后检测到 MAC 下线,ARP 绑定失效,丢包
- 源地址经 DNAT(端口转发)后变为公网 IP,某些网卡/NIC 对单播 Magic Packet 的处理不一致
绕行方案
通过内网一台始终在线的机器(如 NAS)作为跳板,由 NAS 发送 wakeonlan 命令唤醒目标机器。
WOL 报文发送方式对比
| 方式 | 优点 | 缺点 |
|---|---|---|
| 单播 | 安全、低带宽 | IP 变化后失效 |
| 子网广播 | 兼容性好、成功率高 | 需要路由器支持;仅 IPv4;安全性低 |
其他远程开机方案
- 智能插座 + BIOS "通电自动开机":最简单,适用于任何机器
- PCI-E 开机卡:通过 WiFi 发送开机信号,需 PCIE 插槽带电
- 短接 POWER SW 跳线:通过外部设备短接主板的电源跳线
示例 Python 脚本
import socket
def wol(mac: bytes):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
magic = b'\xff' * 6 + mac * 16
s.sendto(magic, ('<broadcast>', 7))
wol(b'\x00\x15\xB2\xAA\x5B\x00')