How to Wake on LAN (WoL) using C#

.NET programming topics
Post Reply
User avatar
Saman
Lieutenant Colonel
Lieutenant Colonel
Posts: 828
Joined: Fri Jul 31, 2009 10:32 pm
Location: Mount Lavinia

How to Wake on LAN (WoL) using C#

Post by Saman » Thu Mar 11, 2010 1:40 am

Lately I came across a requirement for an ability to remotely turn on computers in our company. Couple of team members (including me...) tend to work from home sometimes so they leave their PCs running when they leave the office so the next day they could access it over Remote Desktop. Do you spot a problem already? To be honest I did not realise this was a problem either ... until an electricity bill came in. The workstation PCs are running nonstop (no one really bothers to switch them off, what if they did not go to the office tomorrow ...), which obviously has very negative impact on the electricity consumption in our office.

So it was clear we need to do something about it. One can switch off a PC using Remote Desktop very easily (you can do it directly from Start menu), but having ability to switch off a computer remotely is useless unless you can then remotely switch on the computer again. And that is where Wake on LAN finds its place.

Magic Packet
Wake On LAN (sometimes referred as WOL or WoL) is a marketing term used for ability to bring computer out of Stand-By mode by sending it a special packet, called "Magic Packet".

When you shutdown Windows, all modern ATX-power based PCs do not switch off completely. Instead they enter a Stand-By mode, which means RAM, CPU and hard drives are switched off, but motherboard itself and a network card are still powered. To determine if your network card supports WOL, shut down your PC and check the Link LED on the network card - if it is still active, your network card is still powered and should support Wake on LAN.

Even though a PC is shut down, the network card is listening on the data layer (usually Ethernet) level and scans incoming packets for special character sequence. If it detects the sequence, it will turn on the PC. This sequence, called Magic Packet, has following structure:
magicpacket.png
magicpacket.png (3.47 KiB) Viewed 5265 times
Follow up:
The packet begins with 6 bytes trailer of FF bytes which is followed by 16 times repeated MAC address of the target device (i.e. the device that should be switched on). MAC Address is used as an identifier in the packet, because that is the only valuable identification that is available when the PC is not running. MAC Address is assigned by the manufacturer (it is a layer 2 identifier) and it stored in the flash memory of the network card itself, so the network card can perform the comparison very easily. It cannot use an IP address, because network card simply does not have one when PC is not running - IP address is a layer 3 identifier, which means it is assigned by the OS.

You may also ask why the MAC address is repeated 16 times - it looks like unnecessary data duplication. Well it is not. As mentioned above the network card scans all packets that are coming in and it does not support any protocols of higher levels (TCP, HTTP, etc.) - it will literally go through all bytes in the packet and if it finds the "magic packet" sequence anywhere in the data or even a packet header, it will turn on the PC. Imagine that the packet did not repeat the MAC Address, so it would only utilise 6 bytes of FF and then 6 bytes of the MAC address. I can guarantee you that this 12 bytes combination will sooner or later appear in your network communication (in a file transfer, incoming email, a picture, etc.). 12 bytes is just not enough, which is why the MAC address is repeated 16 times giving the packet solid 102 bytes. The probability that those 102 bytes will unintentionally appear in transferred data is exponentially lower (there are 256^102 different packets which should be safe enough).

Broadcasting Magic Packet
So to switch on a PC through Wake on LAN it should be enough to somehow get a packet including the "magic packet" sequence to the device that I want to switch on. Since we know that the network card is scanning all incoming packets, it is not really important which type of packet I will send as long as it reaches the device.

Since I want to be able to switch on any device in my LAN, the best "container" for the magic packet sequence is an UDP broadcast packet. UDP is a TCP/IP service without any guarantee for delivery, however it does require any handshake like TCP, so a packet can be sent without "opening a connection". UDP broadcast packet is a special type of UDP packet sent to IP address 255.255.255.255 which tells every switch in the way to send this packet to every port so effectively this packet should reach each device in local network, which is exactly what we need from our Magic Packet.
wakeonlanpacketspreading.png
wakeonlanpacketspreading.png (58.68 KiB) Viewed 5265 times
The source device will broadcast the magic packet to IP 255.255.255.255 and this packet will be spread in local network. Routers are set not to transfer broadcast messages, so the target device must be placed before any router. The broadcast packet will eventually reach the target device, which will detect its MAC address in the packet and will turn on itself.

C# Implementation
Now we now how everything works so putting everything together in the form of C# code should be just a piece of cake. At first, we need to create the magic packet:

Code: Select all

byte[] macAddress = new byte[] {0x00, 0xe1, 0xff, 0x65, 0x23, 0x10}; 

//Construct the packet 
List<byte> packet = new List<byte>(); 

//Trailer of 6 FF packets 
for (int i = 0; i < 6; i++) 
packet.Add(0xFF); 

//Repeat 16 time the MAC address (which is 6 bytes) 
for (int i = 0; i < 16; i++) 
packet.AddRange(macAddress);


Now we have the packet data, so we just need to send it inside UDP packet. For this purpose the UdpClient class from System.Net.Sockets will come handy:

Code: Select all

//Send the packet to broadcast address 
UdpClient client = new UdpClient(); 
client.Connect(IPAddress.Broadcast, 7); //Any UDP port will work, but 7 is my lucky number ... 
client.Send(packet.ToArray(), packet.Count); 
Obtaining MAC Address
The code above assumes that you already know MAC address of the device that you want to turn on. There are several ways how you can obtain the MAC address of target device. You can obviously run the command ipconfig /all on directly on the PC and look for the Physical Address entry of your network adapter.

But since we are talking about doing stuff remotely, I will show you how you can get a MAC address remotely. We will use ARP protocol to obtain MAC address by given IP address or hostname. The main purpose of ARP protocol is to translate an IP address into MAC address which is exactly what we need. We will use Windows API function called SendARP for this purpose:

Code: Select all

DWORD SendARP( 
__in IPAddr DestIP, 
__in IPAddr SrcIP, 
__out PULONG pMacAddr, 
__inout PULONG PhyAddrLen 
); 
The method accepts destination IP address (DestIP parameter) and it will fill array of 6 bytes (pointed by pMacAddr parameter) which represents the MAC address of the device. To call this method from .NET, we will use PInvoke call:

Code: Select all

[DllImport("iphlpapi.dll", ExactSpelling = true)] 
static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen); 

static byte[] GetMACAddress(string hostNameOrAddress) 
{ 
IPHostEntry hostEntry = Dns.GetHostEntry(hostNameOrAddress); 
if (hostEntry.AddressList.Length == 0) 
  return null; // We were not able to resolve given hostname / address 

byte[] macAddr = new byte[6]; 
uint macAddrLen = (uint)macAddr.Length; 
if (SendARP((int)hostEntry.AddressList[0].Address, 0, macAddr, ref macAddrLen) != 0) 
  return null; // The SendARP call failed 

return macAddr; 
}

Putting it all together
Now we have everything ready to switch on a PC remotely, except for the target PC itself. On most systems, the Wake On LAN is disabled by default, so you need to enable it. First and foremost, you need to check your BIOS to make sure that Wake On LAN is enabled. Name of this entry will be different depending on your motherboard manufacturer, but it will be most likely located in Power Management of your BIOS.

As a next step, you need to enable the WOL for specified network card directly inside Windows. Open your Device Manager (go to Control Panel, select System, go to Hardware tab and click on Device Manager button) and select the network card which will receive the magic packet. In the Power Management tab, select "Allow this device to bring this computer out of standby", as shown on the following picture:
enablingnic.png
enablingnic.png (29.4 KiB) Viewed 5265 times
Click OK and you are ready your brand new Wake On LAN feature.

The end of the story
The reason why I underwent all this WOL pain was the ability to remotely turn on and off PCs in our office (and to protect the environment and our electricity bills) so you may wonder how I solved it. Basically I made a simple web site which lists our workstation computers in the office. This web site runs on our server in the office (which has to run 24/7) and if you want to turn on your PC you would just go to that site and click on "Wake Up" button which then sends a Magic Packet to the PC.
wolmanager.png
wolmanager.png (100.74 KiB) Viewed 5265 times
Full source code
WakeOnLanWeb.zip
(35.29 KiB) Downloaded 578 times
Database script
database.zip
(1.57 KiB) Downloaded 464 times
Post Reply

Return to “.NET Programming”