Already read it all? use: Update History
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:
- 6 Bytes Header which is nothing but 6 bytes of 0xff.
- 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(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:
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!
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).
IP_ADAPTER_INFO AdapterInfo;
DWORD dwBufLen = sizeof(AdapterInfo);
DWORD dwStatus = GetAdaptersInfo(&AdapterInfo,&dwBufLen);
ASSERT(dwStatus == ERROR_SUCCESS);
PIP_ADAPTER_INFO pAdapterInfo = (&AdapterInfo);
pAdapterInfo->Address;
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:
- To be able to turn on a PC based on its IP instead of MAC.
- 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.
- Power On
- 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:
- Creates a UDP socket.
- Creates a magic packet.
- Broadcasts the packet.
CAsyncSocket s;
BYTE magicP[102];
...
for (int i=0;i<6;i++)
magicP[i] = 0xff;
for (i=0;i<6;i++) {
magicP[i+6] = HexStrToInt(macAddr.Mid(i*2,2));
}
for (i=0;i<15;i++) memcpy(&magicP[(i+2)*6],&magicP[6],6);
...
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