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


8

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

我的想法:

  • 外部计算机向公共IP地址发出WOL(局域网唤醒)数据包(内部带有正确的MAC)
  • 在路由器上打开了正确的端口(例如1234),将数据重定向到Linux机器
  • Linux盒将UDP单播数据包转换为广播数据包(内容完全相同,只有目标地址被修改为255.255.255.255或192.168.0.255)
  • 多播数据包到达每个NIC,所需的计算机现在处于唤醒状态

为此,一个非常简单的netfilter规则是:
iptables --table nat --append PREROUTING --in-interface eth+ --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.255

las 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(如何?)

广播数据包不只是发送到广播地址的数据包。套接字有一个标志,称为SO_BROADCAST。我试图弄清楚iptables如何修改它。
lgeorget

@lgeorget:iptables与so套接字无关。
Bertrand SCHITS

确实。我在找的地方不对。iptables必须在某处有一个选项,以允许它发送广播数据包。
lgeorget

1
您是否尝试过iptables --table nat --append PREROUTING --in-eth eth + --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.0?
lgeorget

@lgeorget:感谢您的想法。但结果相同。我更新了问题
Gregory MOUSSAT 2013年

Answers:


12

socat是杀手级工具。在您的初始化脚本中放置以下内容:

socat -u -T1 UDP-LISTEN:1234,fork 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秒。
255.255.255.255比192.168.0.255更通用。允许您仅复制粘贴而无需考虑当前的网络结构。警告:这可能会将广播的数据包发送到每个接口。

如您所见,我注意到WOL可以在任何端口上工作。我想知道这是否可靠。许多文档仅讨论端口
0、7 和9。这允许使用非伪端口,因此可以socat与user一起运行nobody

感谢lgeorget Hauke LagingGregory MOUSSAT参与了此回答。
随意添加细节。


我尝试过,但是问题是无论第一个数据包到达什么,UDP-LISTEN都会在套接字到达后关闭套接字。请改用UDP-RECV。
lgeorget

没问题 您使用了“ fork”选项?我在man UDP-RECV合并数据包中看到。我不知道这意味着什么。UDP-RECVFROM没有表现出这种行为,但这可能是一个错误。
Bertrand SCHITS 2013年

是的,我用了“叉子”。我尝试了一个socat和两个netcat进程(一个将数据包发送到socat,另一个用于接收广播数据包)。使用UPD-LISTEN,socat模拟连接,并在最后关闭套接字。对于UDP-RECV,它使用UDP的默认无连接行为。来自socat man:“通常,套接字连接将以shutdown(2)结束,即使套接字被多个进程共享,它也会终止套接字。”
lgeorget

2
那么socat将在所有接口上广播吗?
Hauke Laging

1
@lgeorget:“ echo'dummy'| nc -u -q 0 127.0.0.1 1234”与-UDP-LISTEN完美配合。我可以运行几次。但是我对-UDP-RECV和-UDP-RECVFROM有问题:数据包以最大链接速率广播,直到socat被杀死。您是否对tcpdump看到了同样的问题?
Bertrand SCHITS 2013年

3

根据定义,广播流量将发送到本地计算机。这意味着该数据包被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接口上将您的Wake-On-Lan UDP taffic传输到此虚拟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设备上使用此技巧来通过手机远程唤醒我的机器。


从互联网接收到的数据包不会广播。这就是为什么问题是“将UNICAST转换为BROADCAST”的原因
Gregory MOUSSAT,2015年

2

在Serverfault上发现了这个问题

我没有设法通过路由器获得这样的广播流量。DNATted数据包甚至都没有到达我的FORWARD链。也许有一些奇怪的内核选项不允许这样做。

但是ARP的想法很有趣。我想应该在OUTPUT中附带一条规则,该规则禁止将数据包发送到该地址,以便仅通过转发的流量才能到达该地址。


1

索卡特OpenWRT

Socat已经被作为答案了,但是在具有动态WAN地址的平台OpenWRT上,所陈述的答案对我不起作用。

我的目标是将WAN接口UDP端口9的单播UDP局域网唤醒数据包转发到192.168.20.255上广播的子网。

坏了(iptables)

我也尝试过iptables,但是每次我添加以255结尾的规则时,使用以下命令打印时,该规则都会变成目标地址为0.0.0.0的糊状:

iptables -t nat -L

我相信iptables不能像单播到广播转换那样多路复用流量。

不好(伪造的arp条目)

伪造arp条目还不错,因为数据包到达了以太网段上的每个人,但是它具有以下缺点

  • 您“使用”一个IP地址
  • 即使您得到它,WoL数据包中的目标IP还是错误的,因为MAC地址全都是FFFF ...
  • 如果网络上的某人使用该IP地址,则可能会发生IP故障。
  • 它是以太网广播,而不是IP广播。

注意:这可以通过arp命令或ip neigh命令。

好的

如前一个答案所示,socat是坏蛋。但是,以前的解决方案我遇到了一些问题。

  1. 当UDP广播目标为255.255.255.255时,我的socat没有转发流量。我通过将广播子网限制为我使用的更安全的子网来避免了这种情况。
  2. 当我将绑定地址设置为0.0.0.0时,由于流量从LAN反弹回socat,我遇到了广播风暴。我首先通过绑定到公共ddns来解决了此问题,但这并不理想,因为ddns可能不可用,而我的动态分配的IP地址也需要更改。

我能够绑定到0.0.0.0(所有地址),并通过添加iptables规则来阻止传入的广播从LAN侧反弹回socat,从而避免了广播风暴。除了用于在UDP端口9上接受流量的iptables规则和用于对其进行日志记录的iptables规则外,除了socat命令之外,我们还获得以下三个规则。

iptables -I input_wan_rule -p udp --dport 9 -j ACCEPT -m comment --comment "firewall entry to allow udp port 9 to socat"
iptables -I input_wan_rule -p udp --dport 9 -j LOG --log-prefix 'Received MAGIC PACKET on udp/9'
iptables -I input_lan_rule -p udp --dport 9 -d 192.168.20.0/24 -j DROP -m comment --comment "block broadcast from bouncing back to socat to avoid storm"

killall socat 2>/dev/null
socat -u -T1 UDP-LISTEN:9,bind=0.0.0.0,fork UDP-DATAGRAM:192.168.20.255:9,broadcast &

对于OpenWRTer,将其粘贴/etc/firewall.user并发行/etc/init.d/firewall restart就足够了。

恭喜,您现在应该可以从网络上的任何地方为网络使用WoL。


0

实际上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的内核应该已经足够了

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.