To enable wake-on-LAN over the Internet, the open hardware platform Arduino is used.

Not all routers support wake-on-LAN from the Internet to LAN. This depends on whether you can configure the ARP cache and send or forward a WOL broadcast package.

To support WOL, in this case on an Apple TimeCapsule, an Arduino Ethernet Pro board is used. Thus having a low-power device (Arduino) listening for WOL.

Both the Arduino board and machine to wake-up are connected via Ethernet to the TimeCapsule. The Arduino is powered using the TimeCapsule USB port.

The Arduino is programmed to listen for wake-up packets and, if any received, send a broadcast wake-up packet.

Here a Perl CGI script is used to first send a WOL packet to the Arduino and then redirect to the domain of the server just woken up. Of course, this assumes the script to be on an other, on-line, server. For other applications, e.g. remote desktop, you can just send the WOL packet from a terminal session.

The following code is run on the Arduino:

/*
* WakeUpCube
*
* 2011-07-28 JvO, New sketch
*
* Reference links:
* http://arduino.cc/en/Reference/ServerConstructor
* http://arduino.cc/forum/index.php?topic=62185.0
*
* Derived from Arduino WakeMyPc
*   Ricardo Dias
*   http://ricardo-dias.com/
*
* This sketch sends the "magic packet" to wake up
* a PC on Local Area Network [when a push-button
* is pressed.]
*/
#include <SPI.h>  // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <Udp.h>  // UDP library from: bjoern@cs.stanford.edu 12/30/2008
// Arduino configuration
byte arduinoMAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Ethernet shield MAC address
byte arduinoIP[] = { 10, 0, 1, 203 };
byte gatewayIP[] = { 10, 0, 1, 1 };
byte subnetMask[] = { 255, 255, 255, 0 };
unsigned int localPort = 9; // local port to listen on
// the IP broadcast and wake-up target MAC address
byte targetIp[] = { 10, 0, 1, 255 }; // LAN broadcast address 10.0.1.255
int targetPort = 9;
byte targetMAC[] = { 0x00,0x12,0x34,0x56,0x78,0x90 }; // MAC address of the machine to wake-up
// these two variables are set when a packet is received
byte remoteIp[4];        // holds received packet's originating IP
unsigned int remotePort; // holds received packet's originating port
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet,
char replyBuffer[] = "acknowledged";       // a string to send back
// serial connection speed
const int serialBaudRate = 9600;
// Initialisation
void setup() {
// initialize the ethernet device
Ethernet.begin( arduinoMAC, arduinoIP, gatewayIP, subnetMask );
// initialize server
Udp.begin( localPort );
}
// Main LOOP
void loop() {
delay(1000);
// if there's data available, read a packet
int packetSize = Udp.available(); // note that this includes the UDP header
if(packetSize) {
packetSize = packetSize - 8; // subtract the 8 byte header
// read the packet into packetBufffer and get the senders IP address and Port number
Udp.readPacket( packetBuffer, UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort );
// send the wake-up packet
sendPkt();
}
}
// Send the wake-up on LAN message (aka magic packet)
void sendPkt() {
byte all[102];
int i, c1, j=0;
// the 'magic packet' consists of 6 times 0xFF followed
// by 16 times the hardware address (MAC)
for( i = 0; i < 6; i++, j++ ) {
all[j] = 0xFF;
}
for( i = 0; i < 16; i++ ) {
for( c1 = 0; c1 < 6; c1++, j++ ) {
all[j] = targetMAC[c1];
}
}
Udp.sendPacket( all, 102, targetIp, targetPort );
}

The Perl CGI script to send the WOL package and redirect to the server:

#!/usr/bin/perl
###################################################
# Send Wakeup On LAN broadcast message and redirect
#
# usage: http://yourURL/cgi/wakeup.cgi
# test: http://yourURL/cgi/wakeup.cgi?test=1
#
# 25 july 2011, JvO, New script version 0.1
###################################################
use CGI;
use CGI::Carp qw( fatalsToBrowser ); # pass errors to the browser
use Socket;
use POSIX;
$query = CGI::new();
&getParms;   # Get parameters
&sendWOL;    # Send Wakeup on LAN
&returnHtml; # Return result page
#
# Set params
#
sub getParms {
$destAddr = "192.168.10.20";    # Destination IP Adres
$destMAC  = "de:ad:be:ef:fe:ed"; # Ethernet Pro MAC address
$hostURL = "http://your.url.here"; # the URL to redirect to
$port     = 9;
# Remove colons
$destMAC =~ tr/://d;
$test = $query-&gt;param("test");
}
#
# Return HTML page
#
sub returnHtml {
# redirect to the Cube
print "Content-type: text/htmlnn";
if ($test) {
print "&lt;html&gt;&lt;head&gt;&lt;title&gt;Wake on LAN&lt;/title&gt;&lt;/head&gt;n";
print "&lt;body bgcolor="#CCCCCC"&gt;n";
print "&lt;hr size=5 width=75%&gt;&lt;p&gt;n";
print "&lt;center&gt;&lt;h1&gt;Server at IP adres "$destAddr" has been sent a wakeup msg&lt;/h1&gt;&lt;/center&gt;n";
print "&lt;hr size=5 width=75%&gt;n";
print "&lt;/body&gt;&lt;/html&gt;n";
}
else {
print "&lt;meta HTTP-EQUIV="REFRESH" content="2; url=$hostURL/gallery3"&gt;n";
print "&lt;html&gt;&lt;body&gt;You are being redirected to $hostURL...&lt;/body&gt;&lt;/html&gt;n";
}
}
sub sendWOL {
# Magic packet is 6 bytes of FF followed by the MAC address 16 times
my $magic = ("xff" x 6) . (pack('H12', $destMAC) x 16);
# create socket handle and connect
socket($sh, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "Socket could not be created. Reason: $!n";
connect($sh, sockaddr_in($port, inet_aton($destAddr))) or die print $runlog "Socket connect failed: $! host: $destAddr port: $portn";
# send the wakeup packet
print $sh $magic;
close($sh);
}

The TimeCapsule is set to forward WOL packages, using the Airport configuration program “Advanced” option (sorry for the screenprint being in Dutch):

Airport_forward.png