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

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

我们需要从互联网唤醒内部 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给网络中的任何设备:

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

    arp -i ethLAN --set 192.168.0.254 FF:FF:FF:FF:FF:FF
    
  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
    

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

答案3

我发现关于 Serverfault 的这个问题

但我没有设法通过我的路由器获得这样的广播流量。 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 对你来说应该足够了

相关内容