Simple Wake-on-LAN Wrapper Script
Our home network includes a number of Linux-based systems and one Apple iMac. Because the Mac hosts all of our family photos, and because printing from a Mac to a Linux printer is a headache, it made the most sense for us to connect the printer directly to the Mac. However, this creates an issue when printing from one of the other computers: if the Mac is asleep, the shared printer does not respond to requests.
The workaround is simple: get up, walk over to the Mac, and hit the space bar or click the mouse to wake up the machine before trying to print. But we don’t want to get up, so we’ll issue a Wake-on-LAN packet to the Mac instead, using **wakeonlan**.
**wakeonlan** is a simple Perl script written by Jose Pedro Oliveira and maintained by Ico Doornekamp. It is available from the repositories for most Linux distributions. The script broadcasts “magic packets” over the network that are read by WOL-compatible interfaces. If the interface recognizes its own MAC address in the magic packet, the interface signals the host machine to “wake up.”
Sure, it’s a neat trick, but we have to know the destination machine’s MAC address. So we can either make MAC address flash cards for our LAN, or we can write a wrapper script to find the MAC address for us and issue the packet.
### Finding the MAC Address ###
To find the MAC address we can use **arp**, a standard Linux utility, to read the local host’s ARP cache. The ARP cache is an important part of any Ethernet network–it stores a table of every known host on the network by IP and MAC address. Essentially, it serves as the local host’s “address book,” making sure requests to a given IP address are sent to the appropriate network interface. Most of the time, this translation is done in the background while the user remains happily oblivious. But Wake-on-LAN packets are special, and they need our help to get to where they’re going.
The output of **arp** looks something like this:
$ arp Address HWtype HWaddress Flags Mask Iface server ether ab:cd:ef:01:23:45 C eth0 bobs-machine ether 11:22:33:44:55:66 C eth0 arpeggio ether 56:45:34:23:12:01 C eth0 My-iMac.domain ether c8:2a:14:ff:ff:ff C eth0 My-iMac.local ether e4:ce:8f:00:00:00 C eth0
We’re interested in the third column–the MAC address–of the machine called `My-iMac`. Because the iMac’s Ethernet and Wi-Fi interfaces are both enabled, the same hostname shows up twice (albeit with different domains). We’re only interested in the Ethernet interface, which, fortunately, shows up first (the output of **arp** does not tell us which is which–in my case, I know this because I’ve set up static DHCP leases on my home network–finding this out may require some digging or trial and error). This means that we can write our script to search for the first line matching the hostname, then to extract the third column from that line. We accomplish this using **grep** and **awk**, respectively.
$ arp | grep -i -m1 imac My-iMac.domain ether c8:2a:14:ff:ff:ff C eth0 $ arp | grep -i -m1 imac | awk ‘{print $3}’ c8:2a:14:ff:ff:ff
For this discussion we’ll bypass a detailed explanation of the **grep** and **awk** commands. See the Linux man pages for details.
Now that we have a command line string that finds the right MAC address, we can write our script.
### The Script ###
Below is our Wake-on-LAN wrapper script, saved in a file named **wol**:
#!/bin/sh
MACADDR=`arp | grep -i -m1 $1 | awk ‘{print $3}’` wakeonlan $MACADDR
All we’ve done is taken our command line string and replaced the hostname search string (`imac`) with the variable `$1`, which is interpreted by the shell as the first argument passed to the script by the user. This way we can use the same script to send WOL packets to any machine on the network. Executing the script looks like this:
<br /> $ ./wol imac<br />
There. Wasn’t that easier than getting up and hitting the space bar?
### Further Reading ###
- [Wake-on-LAN at Wikipedia](http://en.wikipedia.org/wiki/Wake-on-LAN)
- [ARP cache: What is it and how can it help you?](http://www.petri.co.il/csc_arp_cache.htm)