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?)
  • A broadcast packet is not just a packet sent to a broadcast address. There is a flag for sockets called SO_BROADCAST. I'm trying to figure out how iptables can modify it. – lgeorget Jun 1 '13 at 13:01
  • @lgeorget: iptables is not related to so sockets. – Bertrand SCHITS Jun 1 '13 at 13:08
  • Indeed. I'm not looking at the right place. There must be an option somewhere for iptables to allow it to send broadcast packets. – lgeorget Jun 1 '13 at 13:17
  • 1
    Have you tried iptables --table nat --append PREROUTING --in-interface eth+ --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.0 ? – lgeorget Jun 1 '13 at 13:25
  • @lgeorget: thanks for the idea. But same result. I update the question – Gregory MOUSSAT Jun 1 '13 at 14:00
up vote 10 down vote accepted

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

socat -u -T1 UDP-LISTEN:1234,fork 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 allow to keep socat listening for next packets.
T1 limit life of forked subprocesses to 1 second.
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 send the broadcasted packets to every interfaces.

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-pivilegied port, so you can run socat with user nobody.

Thanks to lgeorget Hauke Laging and Gregory MOUSSAT to have participated to this answer.
Fell free to add details.

  • I tried that but the problem is that UDP-LISTEN will close the socket after the first packet has arrived, no matter the fork. Use UDP-RECV instead. – lgeorget Jun 1 '13 at 13:07
  • No problem here. You used the "fork" option ? I see in the man UDP-RECV merge packets. I have no idea about what it means. UDP-RECVFROM doesn't exhibit this behviour, but it may be an error in the man. – Bertrand SCHITS Jun 1 '13 at 13:22
  • Yes, I used the 'fork'. I tried with a socat and two netcat processes (one to send packets to socat, the other to receive the broadcast packets). With UPD-LISTEN, socat simulates a connection, and closes the socket at the end. With UDP-RECV, it uses the default connection-less behaviour of UDP. From socat man: "Normally, socket connections will be ended with shutdown(2) which terminates the socket even if it is shared by multiple processes." – lgeorget Jun 1 '13 at 13:28
  • 2
    Is socat going to broadcast on all interfaces then? – Hauke Laging Jun 1 '13 at 13:50
  • 1
    @lgeorget: "echo 'dummy' | nc -u -q 0 127.0.0.1 1234" works perfectly with -UDP-LISTEN. I can run it several times. But I have problems with -UDP-RECV and -UDP-RECVFROM: the packets are broadcasted at maximum link rate until socat is killed. Do you see the same problem with tcpdump ? – Bertrand SCHITS Jun 1 '13 at 13:53

Broadcast traffic by definition is destined to local machine. This means the packet gets DNAT'ed to 192.168.0.255 and then the kernel sees the packet and decides that it's destined to the router itself, so you will see this packet in the INPUT chain. The router (and any other device) will think that 192.168.0.255 packets are destined for itself and will not forward them further. Broadcast packets are not routed/forwarded by design.

There is a great workaround with the mentioned ARP trick. You will "lose" one IP address. I'll use dummy 192.168.0.254 in this example -- remember to never assign 192.168.0.254 to any devices in your network:

  1. Create a static ARP entry on LAN interface for the IP address you will never use for any machine:

    arp -i ethLAN --set 192.168.0.254 FF:FF:FF:FF:FF:FF
    
  2. DNAT your Wake-On-Lan UDP taffic on the WAN interface to this dummy IP address:

    iptables --table nat --append PREROUTING  --in-interface ethWAN --protocol udp --destination-port 1234 --jump DNAT --to-destination 192.168.0.254
    

This works perfect for WOL packets. This workaround also works on products which are based on the Linux kernel, like Mikrotik devices and openwrt devices. I use this trick on Mikrotik devices to wake my machine remotely with my cell phone.

  • The packets received from the internet are not broadcast. This is why the question is "Transform UNICAST to BROADCAST" – Gregory MOUSSAT Mar 17 '15 at 13:15

I found this question on Serverfault.

I didn't manage to get such broadcast traffic through my router though. The DNATted packets didn't even arrive at my FORWARD chain. Maybe there is some strange kernel option which disallows that.

But the ARP idea is interesting. I guess that should be accompanied by a rule in OUTPUT which forbids packets to this address so that it can be reached with forwarded traffic only.

Socat OpenWRT

Socat has already been stated as an answer, however the stated answer did not work for me on my platform, OpenWRT, with a dynamic WAN address.

My goal is to forward unicast UDP wake-on-lan packets from UDP port 9 of the WAN interface to a subnet broadcast on 192.168.20.255.

The broken (iptables)

I too tried with iptables, but everytime I add a rule that ends in 255, the rule is turned into mush with destination address 0.0.0.0 when I print with:

iptables -t nat -L

I believe iptables isn't capable of multiplexing traffic, as required in a unicast to broadcast conversion.

The bad (faking arp entries)

Faking arp entries is not so bad, because the packets get to everyone on the ethernet segment, but it has the following disadvantages

  • You "consume" an IP address
  • The destination IP in the WoL packet is wrong, even though you get it 'cause the MAC address is all FFFF...
  • An IP malfunction may occur if someone on the network uses that IP address.
  • It is an Ethernet broadcast, and not an IP broadcast.

Note: This may be done with the arp command or ip neigh command.

The good

socat, as indicated by the previous answer, is badass. The previous socat answer, however, I ran into a few issues with it.

  1. My socat didn't forward traffic when the UDP broadcast destination was 255.255.255.255. I avoided this by restricting the broadcast subnet to the one I use is probably safer.
  2. When I set the bind address to 0.0.0.0, I ran into a broadcast storm due to traffic bouncing back into socat from my LAN. I first solved this by binding to my public ddns, however this is not ideal because ddns may not be available and my dynamically assigned IP address my change.

I was able to bind to 0.0.0.0 (all addresses) and avoid the broadcast storm by adding an iptables rule to block incoming broadcast from bouncing back into socat from the LAN side. This rule, in addition to an iptables rule to accept traffic on UDP port 9, and an iptables rule to log it we get the following three rules in addition to the socat command.

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 &

For the OpenWRTers, pasting this into /etc/firewall.user and issuing /etc/init.d/firewall restart is sufficient.

Congratulations, you should now have WoL working for your network from anywhere on the web.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.