Wake-on-LAN with Go
Doing stuff remotely is pretty awesome. Nothing is cooler than banging a bunch of keys on a terminal, to result in the machine 3 feet away roar to life. Yes, it is within my reach, but hey where is the fun in that?!?
The process by which one might remotely power-on a machine (on the same LAN) is referred to as Wake-on-LAN (WOL)
. This process involves sending a specific payload over the local area network that a target machine is connected to. This payload is encoded with the MAC Address of the target machine.
It is also possible to wake machines not directly in your LAN, but this topic is out of the scope of this post. There are many security implications of allowing machines to be woken up via a network broadcast, therefore most machines will expose a setting in their BIOS to enable or disable remote power on.
How does it work?
Assuming that the Wake-on-LAN
settings have been enabled in a machine’s BIOS, and said machine has a MAC address of 00:11:22:33:44:55
, we can power this machine on by sending a Magic Packet
encoded with its MAC address.
These packets are not protocol specific, and therefore can be sent using just about any network protocol. However, these are typically sent as a UDP Packet
.
Show me the Magic!
A Magic Packet is defined as any payload that contains the following pattern:
- 6 bytes of
0xFF
- 16 repetitions of the target’s 48-bit MAC address (16 * 6 bytes)
Note that the relevant part of the Magic Packet is 6 + (16 * 6) = 102 bytes. The payload however can be larger, as long as the above pattern can be found.
Time to get coding. Lets define our packet:
Initializing a Magic Packet
Since the only real “input” to a MagicPacket is a valid MAC address, it should make sense to have a convenience function to create, initialize and inject the MAC address into a new MagicPacket.
First some globals. Here we call out the delims which might separate the bytes of a MAC Address, and a Regex to match for valid MAC Addresses:
To convert a MAC Address string into a net.HardwareAddr
, we can use net.ParseMAC()
. Once we have our set of bytes, all we need to do is fill our MagicPacket.
Awesome, now we can do something like this to get a MagicPacket from a MAC Address:
This produces:
Put that in a pipe!
We now have a nicely formed MagicPacket, all we need to do is send this data out as a UDP broadcast. This basically involves converting the MagicPacket into a []byte which we can then feed into a UDP connection that we will form.
Wrapping up
We looked at defining a bunch of bytes to form a MagicPacket, then we went about initializing the packet based on a given input MAC address. Then we explored using the net package
to send a bunch of bytes as a UDP broadcast to wake our target machine.
I hope this was somewhat useful. If this was interesting, and you want to check out a more complete, command line version of this utility - take a look at: sabhiram/go-wol
.