02 augustus 2011

Wake on LAN

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 // needed for Arduino versions later than 0018
#include
#include // 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->param("test");
}

#
# Return HTML page
#
sub returnHtml {
# redirect to the Cube
print "Content-type: text/html\n\n";

if ($test) {
print "<html><head><title>Wake on LAN</title></head>\n";
print "<body bgcolor=\"#CCCCCC\">\n";
print "<hr size=5 width=75%><p>\n";
print "<center><h1>Server at IP adres \"$destAddr\" has been sent a wakeup msg</h1></center>\n";
print "<hr size=5 width=75%>\n";
print "</body></html>\n";
}
else {
print "<meta HTTP-EQUIV=\"REFRESH\" content=\"2; url=$hostURL/gallery3\">\n";
print "<html><body>You are being redirected to $hostURL...</body></html>\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: $port\n";

# 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

Geplaatst op 02 augustus 2011 11:32 | Comments (0)