UDP to Broadcast – How to Transform a UDP Unicast Packet

broadcastiptableswake-on-lan

We need to wake-up some computers on our internal LAN, from the Internet.
We have a somewhat closed router, with very few ways to configure it.
I'd like to use netfilter (iptables) to do this because it doesn't involve a daemon or similar, but other solutions are okay.

What I have in mind:

  • the external computer issues a WOL (Wake-On-LAN) packet to the public IP address (with the correct MAC inside)
  • the correct port is open on the router (say 1234), redirecting the data to a Linux box
  • the Linux box transforms the UDP unicast packet into a broadcast packet (exact same content, only destination address is modified to 255.255.255.255 or 192.168.0.255)
  • the multicast packet comes to every NIC, and the desired computer is now awake

For that, a very simple netfilter rule is:
iptables --table nat --append PREROUTING --in-interface eth+ --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.255

Alas netfilter seems to ignore transformation to broadcast. 192.168.0.255 and 255.255.255.255 gives nothing. Also tested with 192.168.0.0 and 0.0.0.0
I used tcpdump to see what happens:
tcpdump -n dst port 1234
13:54:28.583556 IP www.xxx.yyy.zzz.43852 > 192.168.0.100.1234: UDP, length 102

and nothing else. I should have a second line like:
13:54:28.xxxxxx IP www.xxx.yyy.zzz.43852 > 192.168.0.255.1234: UDP, length 102

If I redirect to a non-multicast address, everything is okay. I have the 2 expected lines. But obviously this don't work for WOL.

Is there a way to tell netfilter to issue broadcast packets?

Other methods I think about:

  • use iptables to match the desired packets, log them, and use a daemon to monitor the log file and fire the broadcast packet
  • use iptables to redirect the desired packets to a local daemon, which fires the broadcast packet (simpler)
  • use socat (how?)

Best Answer

socat is a killer utility. Put this somewhere in your init scripts:

socat -u -T1 UDP-LISTEN:1234,fork,range=<ip address of source>/32 UDP-DATAGRAM:255.255.255.255:5678,broadcast

Some users have problems with UDP-LISTEN, so using UDP-RECV seems better (warning: could send the broadcast packets in an endless loop):

socat -u UDP-RECV:1234 UDP-DATAGRAM:255.255.255.255:5678,broadcast
  • fork allows socat to keep listening for next packets.
  • T1 limits the life of forked subprocesses to 1 second.
  • range makes socat listen only to packets coming from this source. Assuming this is another computer than the one where socat is running, this helps that socat does not listen to its own broadcast packets which would result in an endless loop.
  • 255.255.255.255 is more general than 192.168.0.255. Allowing you to just copy-paste without thinking about your current network structure. Caveat: this probably sends the broadcasted packets to every interface.

As you, I noticed WOL works with whatever port. I wonder if this is reliable. Lots of documents only talk about ports 0, 7 and 9.
This allow to use a non-pivileged port, so you can run socat with user nobody.

Thanks to @lgeorget @Hauke Laging and @Gregory MOUSSAT to have participated to this answer.

Related Question