我们需要从互联网唤醒内部 LAN 上的一些计算机。
我们有一个有点封闭的路由器,配置它的方法很少。
我想使用 netfilter (iptables) 来执行此操作,因为它不涉及守护进程或类似的,但其他解决方案也可以。
我的想法是:
- 外部计算机向公共 IP 地址(内部包含正确的 MAC)发出 WOL(LAN 唤醒)数据包
- 路由器上打开了正确的端口(例如 1234),将数据重定向到 Linux 盒子
- Linux盒子将UDP单播数据包转换为广播数据包(内容完全相同,只是目标地址修改为255.255.255.255或192.168.0.255)
- 多播数据包到达每个网卡,并且所需的计算机现在已唤醒
为此,一个非常简单的 netfilter 规则是:
iptables --table nat --append PREROUTING --in-interface eth+ --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.255
唉,netfilter 似乎忽略了广播的转换。 192.168.0.255 和 255.255.255.255 没有给出任何信息。还用 192.168.0.0 和 0.0.0.0 进行了测试,
我使用 tcpdump 来看看会发生什么:
tcpdump -n dst port 1234
13:54:28.583556 IP www.xxx.yyy.zzz.43852 > 192.168.0.100.1234: UDP, length 102
没有别的。我应该有第二行,例如:
13:54:28.xxxxxx IP www.xxx.yyy.zzz.43852 > 192.168.0.255.1234: UDP, length 102
如果我重定向到非多播地址,一切都会好起来。我有 2 条预期的行。但显然这对 WOL 不起作用。
有没有办法告诉netfilter发出广播数据包?
我想到的其他方法:
- 使用 iptables 匹配所需的数据包,记录它们,并使用守护程序监视日志文件并触发广播数据包
- 使用 iptables 将所需的数据包重定向到本地守护程序,该守护程序会触发广播数据包(更简单)
- 使用socat(如何?)
答案1
socat
是一个杀手级实用程序。将其放在初始化脚本中的某个位置:
socat -u -T1 UDP-LISTEN:1234,fork,range=<ip address of source>/32 UDP-DATAGRAM:255.255.255.255:5678,broadcast
有些用户对 UDP-LISTEN 有问题,因此使用 UDP-RECV 似乎更好(警告:可能会无限循环地发送广播数据包):
socat -u UDP-RECV:1234 UDP-DATAGRAM:255.255.255.255:5678,broadcast
fork
允许socat
继续侦听下一个数据包。T1
将分叉子进程的生命周期限制为 1 秒。range
只监听socat
来自该源的数据包。假设这是另一台计算机而不是正在运行的计算机socat
,这有助于socat
不侦听自己的广播数据包,这会导致无限循环。255.255.255.255
比 更通用192.168.0.255
。让您只需复制粘贴,无需考虑当前的网络结构。注意:这可能会将广播数据包发送到每个接口。
正如你一样,我注意到 WOL 适用于任何端口。我不知道这是否可靠。许多文档仅讨论端口 0、7 和 9。
这允许使用非特权端口,因此你可以socat
以用户身份运行nobody
。
感谢@lgeorget @Hauke Laging 和@Gregory MOUSSAT 参与了这个答案。
答案2
根据定义,广播流量的目的地是本地计算机。这意味着数据包被 DNAT 到 192.168.0.255,然后内核看到该数据包并确定它的目的地是路由器本身,因此您将在 INPUT 链中看到该数据包。路由器(和任何其他设备)会认为 192.168.0.255 数据包是发往自己的,并且不会进一步转发它们。广播数据包不是按设计路由/转发的。
对于提到的 ARP 技巧,有一个很好的解决方法。您将“失去”一个IP地址。我将在此示例中使用虚拟设备192.168.0.254
- 请记住不要分配192.168.0.254
给网络中的任何设备:
在 LAN 接口上为您永远不会用于任何计算机的 IP 地址创建静态 ARP 条目:
arp -i ethLAN --set 192.168.0.254 FF:FF:FF:FF:FF:FF
将 WAN 接口上的 LAN 唤醒 UDP 流量 DNAT 到此虚拟 IP 地址:
iptables --table nat --append PREROUTING --in-interface ethWAN --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.254
这非常适合 WOL 数据包。此解决方法也适用于基于 Linux 内核的产品,例如 Mikrotik 设备和 openwrt 设备。我在 Mikrotik 设备上使用这个技巧,用手机远程唤醒我的机器。
答案3
但我没有设法通过我的路由器获得这样的广播流量。 DNATted 数据包甚至没有到达我的 FORWARD 链。也许有一些奇怪的内核选项不允许这样做。
但 ARP 的想法很有趣。我想这应该伴随着 OUTPUT 中的一条规则,该规则禁止数据包发送到该地址,以便仅通过转发的流量才能到达该地址。
答案4
实际上netfilter不能做任何广播,路由机制来做这个。
但它默认会丢弃所有转发的广播。
在最近的 Linux 内核(大约版本 5.0)中转发定向 UDP 广播成为可能
需要修改bc_forwarding
广播网络接口参数:
sudo sysctl -w net.ipv4.conf.eth1.bc_forwarding=1
(注意:似乎是net.ipv4.conf选项。全部.bc_forwarding 不起作用)
所以现在,内核大约 5.0 + iptables 对你来说应该足够了