将 UDP 单播数据包转换为广播?

Gre*_*SAT 8 iptables wake-on-lan broadcast

我们需要从 Internet 唤醒我们内部 LAN 上的一些计算机。
我们有一个有点封闭的路由器,配置它的方法很少。
我想使用 netfilter (iptables) 来执行此操作,因为它不涉及守护进程或类似程序,但其他解决方案也可以。

我的想法是:

  • 外部计算机向公共 IP 地址发出 WOL(Wake-On-LAN)数据包(内部具有正确的 MAC)
  • 路由器上打开了正确的端口(比如 1234),将数据重定向到 Linux 机器
  • Linux box将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(如何?)

Ber*_*ITS 12

socat是一个杀手级的工具。把它放在你的 init 脚本中:

socat -u -T1 UDP-LISTEN:1234,fork,range=<ip address of source>/32 UDP-DATAGRAM:255.255.255.255:5678,broadcast
Run Code Online (Sandbox Code Playgroud)

一些用户对 UDP-LISTEN 有问题,因此使用 UDP-RECV 似乎更好(警告:可能会无限循环发送广播数据包):

socat -u UDP-RECV:1234 UDP-DATAGRAM:255.255.255.255:5678,broadcast
Run Code Online (Sandbox Code Playgroud)
  • fork允许socat继续侦听下一个数据包。
  • T1 将分叉子进程的生命周期限制为 1 秒。
  • range品牌socat只能听由这个来源的数据包。假设这是另一台计算机而不是socat正在运行的计算机,这有助于socat不侦听自己的广播数据包,这将导致无限循环。
  • 255.255.255.255比 更通用192.168.0.255。让您无需考虑当前的网络结构,只需复制粘贴即可。警告:这可能会将广播的数据包发送到每个接口。

和你一样,我注意到 WOL 可以与任何端口一起使用。我想知道这是否可靠。许多文档只讨论端口
0、7和 9。这允许使用非特权端口,因此您可以socat使用 user运行nobody

感谢@lgeorget @Hauke Laging 和@Gregory MOUSSAT 参与了这个回答。

  • socat 会在所有接口上广播吗? (2认同)

小智 5

根据定义,广播流量的目的地是本地计算机。这意味着数据包被 DNAT 到 192.168.0.255,然后内核看到该数据包并确定它的目的地是路由器本身,因此您将在 INPUT 链中看到该数据包。路由器(和任何其他设备)会认为 192.168.0.255 数据包是发往自己的,并且不会进一步转发它们。广播数据包不是按设计路由/转发的。

对于提到的 ARP 技巧,有一个很好的解决方法。您将“失去”一个IP地址。我将在此示例中使用虚拟设备192.168.0.254- 请记住不要分配192.168.0.254给网络中的任何设备:

  1. 在 LAN 接口上为您永远不会用于任何计算机的 IP 地址创建静态 ARP 条目:

    arp -i ethLAN --set 192.168.0.254 FF:FF:FF:FF:FF:FF
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将 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
    
    Run Code Online (Sandbox Code Playgroud)

这非常适合 WOL 数据包。此解决方法也适用于基于 Linux 内核的产品,例如 Mikrotik 设备和 openwrt 设备。我在 Mikrotik 设备上使用这个技巧,用手机远程唤醒我的机器。