Playing with Wake-On-Lan (WOL)

Pre-req:
+ Must have php5 with –enable-sockets

What is a magic packet?
It’s a udp packet sent through the broadcast address to all servers on the network (ie, all servers serviced by the broadcast address). It’s called magic, because the format of the message is so strange. A mac address looks like this, 00:30:1B:BA:FA:47, it’s a series of 6 hexidecimal numbers. The magic packet message is a 6 char header, then the mac address, converted to a character sequence, repeated 16 times.

Consider the mac: 00:30:1B:BA:FA:47. Let’s dissect this. Look in your ascii and iso_8859-1 tables to see what each char is:
00 = NUL ‘\0’
30 = 0
1B = ESC
BA = MASCULINE ORDINAL INDICATOR
FA = LATIN SMALL LETTER U WITH ACUTE
47 = G

The way you craft the message in PHP is:
$hw_addr = chr( hexdec(00) ) . chr( hexdec(30) ) . chr( hexdec(1B) ) . chr( hexdec(BA) ) . chr( hexdec(FA) ) . chr( hexdec(47) );
$msg = str_repeat(chr(255),6) . str_repeat($msg, 16);

So, it’s chr(255) 6 times, followed by the mac address converted to a string 16 times. Weird, eh? Yeah, well, somehow, this is an industry standard. Most modern computers ship with ability to Wake-On-Lan (WOL) via the magic packet method. The computer is powered down, but the NIC card is listening for broadcast packets. It parses each incoming packet, when it finds a magic packet that matches it’s mac address, it powers the server on.

Here is a little class that you can use to send WOL magic packets. I got the premise from the PHP web site. I am using this in a production environment to wake up servers to be provisioned. Works great.

Wol.class.php:
<?php

class Wol
{
private $mac;
private $bcast;

public function __construct($mac, $bcast)
{
// Get static array loaded:
$this->mac = strtoupper(trim($mac));
$this->bcast = trim($bcast);
}

public function wol($port=7)
{
$mac = $this->mac;
if (!preg_match(“/^[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}$/”,$mac,$maccheck))
{
echo “Warning, Mac isn’t formated right: $macn”;
return false;
}
$addr_byte = preg_split(“/:/”,$maccheck[0]);

$hw_addr = ”;
for ($a=0; $a < 6; $a++)//Changing mac adres from HEXEDECIMAL to DECIMAL
$hw_addr .= chr(hexdec($addr_byte[$a]));

$msg = str_repeat(chr(255),6);
for ($a = 1; $a <= 16; $a++)
$msg .= $hw_addr;

$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
if ($s == false) {
echo “Error creating socket!n”;
echo “Error code is ‘”.socket_last_error($s).”‘ – ” . socket_strerror(socket_last_error($s));
return false;
}
else {
// setting a broadcast option to socket:
$opt_ret = socket_set_option($s, 1, 6, TRUE);
if($opt_ret <0) {
echo “setsockopt() failed, error: ” . strerror($opt_ret) . “n”;
return false;
}
print “Sending Magic Packet to {$this->mac} on broadcast {$this->bcast}n”;
if(socket_sendto($s, $msg, strlen($msg), 0, $this->bcast, $port)) {
print “SUCCESSn”;
socket_close($s);
return true;
}
else {
echo “FAILEDn”;
return false;
}
}
return false;
}
}

?>

And, to use the Class:

#!/usr/bin/php
<?php
require_once(“Wol.class.php”);

#$mac = “00:30:1B:BA:FA:47”;
#$bcast = “208.109.29.255”;
$mac = $argv[1];
$bcast = $argv[2];

$wol = new Wol($mac, $bcast);
$wol->wol();
?>

Note: if you are crossing vlan’s, you’ll need the destination vlan to have this in it’s config:

ip directed-broadcast

In other words, log in to your switch, and change configuration of the destination vlan:
conf t
interface vlan<vlan#>
ip directed-broadcast
end
write mem

Comments are closed.