Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Wake On LAN (WOL)

4.90/5 (127 votes)
27 Jul 2007CPOL11 min read 10   27.1K  
This article will describe steps required to power on remote machines in a local area network.

Already read it all? use: Update History

AllSamples

Before you start

You'll need a background of computers, Networks, Socket Programming, VC++(MFC) before reading this article.

Introduction

The problem is to find a way to turn on other machines in a local area network, from our machine which might or might not be the Server. The Solution is known as Wake On LAN. WakeOnLan (or for short just WOL) is a mechanism with which a network Interface Card (NIC) could turn a machine on by receiving a special packet through the LAN.

Acknowledgements

  • I searched the whole web (well, CodeProject) and was unable to find anything about WOL in C++. That was why after discovering the mechanism I decided to Dis-cover it to others. This is my first article and I hope it will be helpful.
  • English is not my native language, so sometimes it might be easier to understand the code itself rather than my descriptions
  • Thanks a lot to Khalid Shaikh and his nice article on: Three ways to get your MAC address Thanks a lot to José Pedro Oliveira and his nice article on: Wake On lan - Mini HOWTO.
  • Sentences written in italic copied directly from other articles.

How does it work

While your computer is Turned Off, The Network Interface Card remains on and looks forward to hearing a message! More accurately, a packet does, which is called a magic packet. Whenever the card receives information, a magic packet tries to switch on the computer. This packet must contain a certain byte-sequence, but can be encapsulated in any kind of packet (IPX, IP, anything). So the mechanism relies on the Hardware's ability, and that's why we need some ingredients!

Hardware requirements

Both motherboard and NIC must support WOL. If you have a built-in NIC with WOL support, it's almost done! But many PCI NICs come with a connector and a wire, which has to be connected to the motherboard's WOL connector. After these, your power supply and OS must support WOL. And finally, you should enable Wake-On-LAN in your systems BIOS (or whatever called). That's it.

Magic Packet

I'm not sure, but it seems that the name comes from AMD. I did not do a search but José Pedro Oliveira (second link above) says that there is more documentation about the protocol in their web site. As I mentioned above, you need to send a special packet in your LAN network, so that the remote computer will receive it and wake up. This so-called Magic packet consists of the following parts:

  1. 6 Bytes Header which is nothing but 6 bytes of 0xff.
  2. 16*6 Bytes Data. To produce data you'll need to repeat remote computers MAC (Media Access Control) Address 16 times. Look at the below figure:

Magic Packet Architecture

Magic Packet(With Secure On Password)

(This part added on an update on: 2005/09/03. Note that 'PowerOn' sample has been updated in all downloads either. [as well as executables!])

Some clients require a password in the packet to be turned on, otherwise they simply won't! This password is also known as SecureOn, and will be attached at the end of the packet. In this case, a packet will look something like this:

Magic Packet SecureOn Architecture

So we have six cells, each capable of saving an integer number between 0 and 255(Just like MAC bytes).

What's MAC address and how to obtain it

MAC stands for Media Access Control, and is a unique 48-bit (6 Bytes) hexadecimal number assigned to a NIC when it is manufactured. And it is unique; you'll not find two NICs with the same MAC Address in the world. The first three octets (24 bits) are known as the Organizationally Unique Identifier (OUI) and identifies its manufacturer. It means the MAC address of all cards of a company that say X start with a particular fixed number at the beginning. I'm not sure if this address is just assigned to Ethernet Cards or any other types of network Interface or equipment. This address is typically written as six colon/dash-separated hexadecimal numbers.

In Microsoft Windows (98 SE and above, perhaps winipcfg.exe ) there's a tool called ipconfig.exe which could be used to obtain a MAC address. Ipconfig refers to this address as Physical Address. In order to see the MAC address of your NIC, just type this in the command line: ipconfig /all.

There are several alternative ways of finding a MAC address, like looking for an ARP table (if any exists! or it has any entries), ifconfig (just in Linux), netstat, GetMAC (XP), all of which are enough to be a topic for a new article!

ommand line - ipconfig/all

So let's come back to our subject! For example, and according to the above figure, you should send a packet like : ff-ff-ff-ff-ff-ff 02-00-4c-4f-4f-50 02-00-4c-4f-4f-50 ... 02-00-4c-4f-4f-50 to the computer with the above MAC address to turn it on. But the question is: "How to obtain this address in your app".

To be honest, before Googling the web I tried to do a disassembly on ipconfig.exe and I found GetAdaptersAddresses and some other functions between the functions it uses which comes from iphlpapi.dll. I guess this is the key to our problem! Then I searched the web and found an article on CodeGuru. You could find a link to this article at the top of this page. I just selected his third way which is: GetAdaptersInfo but since I was unable to compile it (it needed some header files and a lib (iphlpapi.lib) which could only be found in MS VC++ .NET), I changed it in order to be able to compile it with my compiler (VC++ 6.0).

C++
// Allocate information for NIC
IP_ADAPTER_INFO AdapterInfo;
// Save memory size of buffer
DWORD dwBufLen = sizeof(AdapterInfo);
// Call GetAdapterInfo
DWORD dwStatus = GetAdaptersInfo(&AdapterInfo,&dwBufLen);
// Verify return value is valid
ASSERT(dwStatus == ERROR_SUCCESS);
// Contains pointer to current adapter info
PIP_ADAPTER_INFO pAdapterInfo = (&AdapterInfo);
pAdapterInfo->Address;//Is the MAC Address of our NIC

//for a more acurate implementation and my modifications, 
//Please see the demo project.

We have the address, but still have the problem of sending data to a switched off computer! The solution is to broadcast a UDP packet. Did this already? Add a new feature to your local network project: Turn On All Network Machines. Did not do this already? Take a look at the demo project -PowerOn.

Remote MAC finder & ARP

After publishing this article on 2005/08/29, I found out that most readers wanted two major features:

  1. To be able to turn on a PC based on its IP instead of MAC.
  2. To be able to turn on a PC over the Internet!

Thanks to Mr. Tupack Mansur, and other readers who created this temptation in my heart! (See discussion and comments below)

Based on the above demands, I started another project: Remote MAC finder (third project to download), which is designed to find the MAC of a computer which we have it's IP or Host Name. Why I didn't upgrade old PowerOn project? Just to keep it simple.

I could do something with the second request if I was IEEE! The problem is that to send a packet over the internet, routers need an IP address, but a turned off machine has not need one, so there is not any way to address a remote machine.

As far as I know, routers will remove broadcast packets from the Internet, so don't think about it. One way would be to send a WOL packet to your LAN router which might or might not support this. An internally broadcast address like 192.168.1.255 must forwarded.

Two other methods might be using telnet (wol up) directly or indirectly by 'Remote Desktop' to an always on machine and turning on others from there(Thanks to an anonymous reader who described his solution.).

Remote MAC Finder works based on ARP. If you already know ARP protocol, you can ignore this next part, but since I'm still a beginner in Networks, Programming ,and even worse, self-educated (my university did not teach me these things), there might be mistakes and it will be greatly appreciated if you help to correct me. Thank you.

ARP

ARP(RFC 826) stands for Address Resolution Protocol. Although all host machines and network tools use unique IP addresses, but any IP packet will cross the first layer of TCP/IP model before going to channel. This first layer is called the Network Interface Layer. The Network Interface layer will work just with a physical address known as MAC. Any IP packet containing an IP address will be placed in a Data Field(Payload) of the first layer frames and a header containing a MAC address of the destination will be added later. In other words, each machine is a network which has a packet to send to another, and should know both destination's MAC and IP addresses.

Network interfaces will also recognize packets on the net, containing their MAC address and will take them for further processing. But what if a computer in a network doesn't have its peer MAC address? This is what ARP was created for. The duty of ARP is to broadcast a packet over a network. This packet actually asks: "Any one whose IP address is (say) '192.168.1.5', What is it's MAC address?". Broadcasted packets will be received by all Network machines, and as soon as a machine sees its own IP in the packet will send a reply to the requester and places its MAC address in the reply packet. In order to increase ARP speed, each time a machine finds a MAC address corresponding to an IP, the protocol will save these numbers in a table in main memory. The table is called ARP cache. So one way of finding the MAC of a remote computer is by enumerating IP's from this table and when a match is found, taking it's MAC.

But the problem is that the life of this table (ARP Cache) is too small (we should exclude routers, I guess). (My test on Windows XP SP1 was about 2 Minutes!) Some commands will update entries of this table. I found that the function gethostbyaddr does that. So I first call this function both to retrieve HostName, and IP of remote machine, and update the ARP table. Then I use GetIpNetTable to enumerate IPs and find an appropriate MAC.

But this process is not always reliable! The reason is that with this mechanism, an attack could be shaped :ARP Spoofing! I don't know much a lot about how it works, but it might be a good idea for an administrator to think about it! That's why I say it's not always reliable.

Using the code

(added upon update: I did not have the chance to test the new uploaded 'PowerOn' to see how it works with a password. It would be appreciated if anyone does can tell if his/her test was successful. Thank you.

I did not provide any C++ classes, because I didn't want to hide such easy stuff from readers and write a class for one function!

There are two demos included in this article.

  1. Power On
  2. MAC Finder

In the PowerOn demo I tried to turn on a computer in our LAN network, using the mechanism I described above. The job is completed in two functions OnPowerOn() and HexStrToInt(CString hexStr). The second function's job is to convert a hex string say "E9" to an integer value, 233 in our example. It uses the strtol function to do the duty.

The OnPowerOn does the following:

  1. Creates a UDP socket.
  2. Creates a magic packet.
  3. Broadcasts the packet.
C++
    //Socket to send magic packet
    CAsyncSocket s;
    //Buffer for packet
    BYTE magicP[102];

...

    //Fill in magic packet with 102 Bytes of data
    //Header
    //fill 6 Bytes with 0xFF
    for (int i=0;i<6;i++)
        magicP[i] = 0xff;
    //First 6 bytes (these must be repeated!!)
    //fill bytes 6-12
    for (i=0;i<6;i++) {
        //Get 2 charachters from mac address and convert it to int to fill
        //magic packet
        magicP[i+6] = HexStrToInt(macAddr.Mid(i*2,2));
    }

    //fill remaining 90 bytes (15 time repeat)
    for (i=0;i<15;i++) memcpy(&magicP[(i+2)*6],&magicP[6],6);

...    
    //Broadcast Magic Packet, Hope appropriate NIC will take it ;)
    s.SendTo(magicP,102,atol(m_port));

MAC Finder

At first I thought I couldn't add the following project, but thought more and decided to do it because you might want to find a MAC automatically, and probably give the found address to your peer (TCP socket) application in a LAN, and use it later! Whatever you want to do, this might be helpful.

I used Mr. Khalid Shaikh's code, but his code was not 'compileable' in my VC++ 6.0, so I found the appropriate DLL where the function had been located and used MSDN to reproduce the needed structures (hope this is not a copyright problem) and then used a pointer to the function and LoadLibrary to get the function. It seems that the function is added as a resource to the DLL (it's not documented) so we can't use GetModuleHandle. I tested the result on MS Windows 98, Me, 2K, XP(SP1). It worked fine! All the processes is done in a function named GetMacAddress(). This function is called in OnInitDialog of MAC Finder.

Most Interesting part of the story

There was a very interesting point I encountered, while working with MACs! Look at the above MAC address (in the figure). It's the MAC of a Microsoft loopback adapter. Since I do not have 2 (or more) computers, I tested my network applications (bot PowerOn) using this NIC. Look carefully at its MAC address:02-00-4c-4f-4f-50, and try converting numbers to characters using ASCII standard. What do you see? : 02= :) 00= blank 4C= L 4F= O 50= P = > Microsoft Loop back Adapter's MAC address is :) LOOP

Who decided on these numbers, that's the mystery!

Update History

First published 2005/08/29

Update #1 2005/09/02

  • Added SecureOn password to 'PowerOn'.
  • Added SecureOn description
  • photos and downloads updated.

Update #2 2005/09/20

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)