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:
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.
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.