Going slightly green - Wake on LAN from ASP.NET

I'm often torn between the desire to switch my PC off when I'm not using it as an attempt to perform some token gesture towards being green (every little helps) and the desire to leave it on so that I can access it remotely from where ever I happen to be.

Wouldn't it be handy if you could allow your PC to sleep automatically but somehow have the ability to wake it up without having to push the power button in the rare event that I would like to use it when I'm nowhere near it?  Turns out there is - however it isn't new, it's just only recently that I've been bothered/driven to investigate this (delete as appropriate) and have been pleasantly surprised as to how easy it is to make it work and how reliably it seems to work.

Most PCs with modern motherboards support Wake On LAN, which is why when your PC goes to standby or hibernates there is still a link light on the network card - it is still awake and waiting for packet to arrive which would require it to signal the PC to wake.  The packet it's looking out for is known as the magic packet and is specially laid to make it easy for the little brain on board the network card to spot it while the CPU and rest of the PC is turned off.

The Magic Packet is 102 bytes long made up of a 6 byte header of all 0xFF followed by the target computer's MAC address sixteen times (6 bytes each) and is sent out using UDP.

image

We can build and send one of these from C# reasonably easily using the UdpClient class:

/// <summary>
    /// Send a magic packet
    /// </summary>
    /// <param name="macAddress"></param>
    public static void Wake(byte[] macAddress)
    {
        // A Wake on LAN magic packet contains a 6 byte header and
        // the MAC address of the target MAC address (6 bytes) 16 times
        byte[] wolPacket = new byte[17 * 6];

        MemoryStream ms = new MemoryStream(wolPacket, true);

        // Write the 6 byte 0xFF header
        for (int i = 0; i < 6; i++)
        {
            ms.WriteByte(0xFF);
        }

        // Write the MAC Address 16 times
        for (int i = 0; i < 16; i++)
        {
            ms.Write(macAddress, 0, macAddress.Length);
        }

        // Broadcast the magic packet
        UdpClient udp = new UdpClient();
        udp.Connect(IPAddress.Broadcast, 0);
        udp.Send(wolPacket, wolPacket.Length);
    }

 

Note, by using a UDP Broadcast the sender and recipient must be on the same subnet, otherwise you'll have to teach your router what's going on.

This then leads to the question of how to obtain the MAC address of the remote computer.  If you are sat in front of it you can run ipconfig /all at a command line to get the address:

Ethernet adapter Local Area Connection:

   Connection-specific DNS Suffix  . : imeta.co.uk
   Description . . . . . . . . . . . : Broadcom NetXtreme 57xx Gigabit Controller
   Physical Address. . . . . . . . . : 00:1C:23:27:CE:C0
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : ... etc

 

Now we have a string with the MAC address we can wake that machine up from someplace else:

 

public static void Wake(string macAddress)
{
    Wake ( macAddress.Split(':').Select(c => byte.Parse(c, NumberStyles.HexNumber)).ToArray() );
}

 

However, if I don't want to have to run a command on the local computer to wake it up remotely I can ask it over the network what its MAC address is using a protocol called ARP.  ARP is used to find out which MAC address currently owns a particular IP address.

So given the I know the name of the remote PC, I'd like to be able to discover the MAC address and wake it up.  Unfortunately there is no managed class for generating and sending ARP requests, we need to make use of a native DLL:

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

/// <summary>
/// Summary description for ARP
/// </summary>
public static class Arp
{
    public static byte[] GetMACAddress(string hostNameOrAddress)
    {
        IPHostEntry hostEntry = Dns.GetHostEntry(hostNameOrAddress);

        byte[] macAddr = new byte[6];
        uint macAddrLen = (uint)macAddr.Length;

        // Find the first IPV4 address for that host
        IPAddress ipAddress = hostEntry.AddressList.First<IPAddress>(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);

        byte[] addressBytes = ipAddress.GetAddressBytes();
        int address = BitConverter.ToInt32(addressBytes, 0);

        if (NativeMethods.SendARP(BitConverter.ToInt32(addressBytes, 0), 0, macAddr, ref macAddrLen) != 0)
        {
            return null;
        }

        return addressBytes;
    }
}

 

Great, so now given the name of a PC we can use DNS to lookup it's IP address, send an ARP request to obtain its MAC address and then wake up the remote computer using a Magic Packet?  Sorted?  No... ARP tells you which MAC address currently owns an IP address, when a computer is in standby it doesn't have an IP address - so it doesn't need to respond to ARP requests.

While understandable, this is a real shame as it means if a remote computer is asleep there is no means of obtaining it's MAC address; you can only find a computers MAC address if the computer is on!

In order to produce a useful system to wake up PCs when they're asleep the system needs to know ahead of time which machines I'm likely to want to wake.  By creating a little ASP.NET application we can register the machines that are likely to sleep while they're awake and store the MAC address so that we have it handy when it's asleep.  By placing this application on a central server everyone can register their computers on it and there is one central place to visit to turn them back on again:

image

Clicking the add computer button will use the hostname string that I've entered, obtain the MAC address for it and squirrel it away into a database.  If the remote machine isn't on at the moment it can't be added to the collection until it is.  However once my PC has been added we can then view the machines I've added and wake any machines of mine that are asleep:

image

By clicking on the "Wake up" link, the asp.net page can use the MAC address stored in the database to create a magic packet and wake the PC up.  We can also do some little touches like pinging the machine as the page loads and tailoring the icons and links available; there's no point waking a machine that's awake!

image

 

When my computer is awake it shows up as online:

image

 

So now are we finished?  Almost!  The web application now has everything it needs to make it work, however if you try it the remote PC probably won't wake up, as Wake-On-LAN is not enabled by default! You need to enable it in your BIOS and in Windows. 

In the BIOS it will probably be under power management or similar, like this example:

image

... and then the driver for the network card needs to be taught what's going on.  Locate your network card under Device Manager, and click properties and Power Management and then check "Allow this device to wake the computer"

image

And finally, it seem to help if you tell the network card to expect a Magic Packet as the wake-up signal rather than a ping or any other type of packet:

image

And now we're done!  Your PC should now wake when instructed to by a magic packet!

So that was a lot of heart-ache, why bother?  A quick burst of maths demonstrates the scale of the cost savings that are possible through a bit of green IT:  Working on the assumption that an idle desktop computer pulls 150w at idle, it means that a powered on PC will burn 1 KWh every 6 hours 40 minutes.  For a PC on 24/7 that's 25.2 KWh per week or 1,310 KWh per year.  Assuming a rough price of 10p per KWh a single PC costs £131 per year to run 24/7.  Now how many PC's do you have around the place?  Two? Five?  Maybe a hundred (£13,100 per year) - a thousand maybe?  

By making the PC's switch to standby the figures change, let's say each one is on  9AM till 6PM, 5 days a week, 48 weeks of the year (people go on hols!).  The PC is on for 9 hours a day, 2,160 hours per year which consumes 324KWh, which costs £32.40.   A saving of just shy of a hundred pounds per PC per year - assuming the cost of electricity remains constant, and that's probably the worst assumption I've made so far!  As the cost of energy goes up, the savings will increase proportionally too. 

It's probably worth factoring in the amount of time that the PC is on standby into the equation, as they are still pulling some current:  if the PC is on for 2,160 hours per year, it is off or on standby for 4,200.  Assuming a draw of 5w in that state it will consume 21KWh over the year - costing £2.  I think the case for the savings still holds!

At iMeta we have this live now on our intranet site (http://intranet/wake for iMeta people) but it's probably something that anyone who leaves a desktop PC on 24/7 should consider setting up.

 

Credits: Thanks go to Bart and Lukas that got me down the road to this solution!

 

26/11/08 Update:  This solution and the source are available to download

20 Comments Filed Under [ Green IT ]

Comments

# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar What about WMI, this product appears to indicate its a method for finding a MAC from an IP

http://software.techrepublic.com.com/abstract.aspx?docid=351523
Left by James Allderidge on 8/5/2008 1:29 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar True, however the WMI method requires you to authenticate and have rights on the remote computer. Of course, also only works with Windows targets!
Left by Neil on 8/5/2008 4:56 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar this seems brilliant to me - but why the killjoys? mentoring is the solution, neil
Left by james sale on 8/20/2008 5:47 PM
# Staying awake - Turning your PC into an Insomniac
Gravatar Staying awake - Turning your PC into an Insomniac
Left by Neil Rees's Blog on 9/2/2008 1:47 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Hello,
thank you for posting this. I just have one question - how would this need to be modified if i want to use this over a remote server? I've already configured my router to forward UDP packets to the pc i want to wake up.

Would i just modify this line:
udp.Connect(IPAddress.Broadcast, 0); to send to a specific IP address?
Left by Ian Lipsky on 11/17/2008 10:02 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar i'm getting an error on the Wake routine :
public static void Wake(string macAddress)
{
Wake(macAddress.Split(':').Select(c => byte.Parse(c, NumberStyles.HexNumber)).ToArray());
}

Error i get is CS1525: Invalid expression term '>'

Also, in vs2008, the 'select' word is highlighted in red with the error "can not resolve symbol select".
Left by Ian Lipsky on 11/17/2008 11:22 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Hi Ian,

You can't change the udp.Connect to take the IP address of the target machine, don't forget when the machine is asleep it doesn't have an IP address - so you need to wake it via a broadcast packet.

You'll also need to configure your router to pass broadcasts from one network to another, rather than just packets for a particular host.

As for the errors, are you targetting .net 3.5, that function uses Linq and it sounds like you are either not using .net 3.5 or you've missed the 'using System.Linq'. The conversion from string to byte array can easily be rewritten if you don't want to use Linq:

byte[6] macArr = new byte[6]();
string[6] pieces = macAddress.Split(":");
for (int i = 0; i<6; i++)
{
macArr[i] = byte.Parse(pieces[i], NumberStyles.HexNumber);
}

Wake(macArr);

** I've just typed that in - it hasn't been near a compiler!!

Cheers,

Neil.

Left by Neil Rees on 11/17/2008 11:50 PM
# Always get Unable to obtain MAC address
Gravatar Is there specific access needed to [Add Computer]? I attached the MDF on a SQL Server.
Left by Peter on 12/9/2008 10:29 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar
You'll need to make sure the identity the website is running as has execute permissions on all the stored procedures in the database.

However - if it's saying "Unable to obtain MAC address" it's not made it that far, it's encountered a problem looking up the MAC address. This is normally one of two things:

* DNS is not working - it first needs to convert the hostname that you are adding to an IP address and needs to talk to a DNS server to do that. Out of interest when you go to the "Add computer" page does it populate the name with a host name or an IP address? If it's got an IP address in there it does indicate a DNS problem, as it tries to do a reverse DNS lookup first to get your hostname.

* No reply to ARP broadcast - if it did get the IP address, there was no response to the ARP broadcast. This may indicate that the DNS database is out of date? The IP address is on a different subnet to the server? There's a firewall in between the server and the client? Is the PC that's being added turned on - it won't reply if it's currently on standby?

I'll tidy up the error handling in that area in the next release to be a bit more specific as to what is going wrong.

Neil
Left by nrees on 12/10/2008 9:30 AM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Great and useful tool with only one problem; it doesnt wake up machines when they are off. It only wakes them up when they are sleeping.

This code wakes them up when off, but not when sleeping:
http://www.depicus.com/wake-on-lan/woli.aspx

You would save even more money on electricity if the machine is shutdown rather than sleeping.

Could you not query the DHCP server every time to get the latest IP address and MAC address used? That would save the machine needing to be on to retrieve the details.
Left by Bhozar on 12/10/2008 2:01 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar It can wake a powered off PC with no problem, it's down to whether the PC leaves it's network card energised whilst powered off. If it leaves the card powered on, it can power it up.

I did investigate querying the DHCP database, however it's not (easily) possible to remotely query it using a windows DHCP server, and using ARP and DNS standard protocols means this application can run in many different infrastructures.
Left by nrees on 12/10/2008 2:09 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Interesting that you say it powers on PC's that are off, as I have been unable to get it to do that with 4 different PC's so far, but that other more basic script does power them on.

Perhaps its because the other script broardcasts the magic packet to 10.1.1.255, rather than just the specific IP address.
Left by Bhozar on 12/11/2008 12:20 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar When trying to wake a machine from powered off, you are at the mercy of the BIOS on the PC as to when or if it will wake.

I've tested this solution with a Dell Precision 390 and that will wake from powered off in response to a magic packet. The magic packet isn't sent to a specific IP address, it's sent to the network broadcast address. (so all stations will receive it). Might be worth trying a different port number for the broadcast - it shouldn't make any difference, but I have heard of occaisons where it has.
Left by nrees on 12/11/2008 3:40 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar I've been struggling with this. The app works but all computers show up as being registered as Network Service instead of the Authenticated user. The app pool is setup with Network Service, should this be changed?
Left by Brent McCraney on 5/12/2009 7:56 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Hi Brent, are your users and the web server on a windows domain?

It sounds like the web server has not authenticated your users and is using it's own identity. Can you make sure that you have Anonymous access disabled in IIS and that Windows Integrated Authentication is turned on and see if that fixes it.
Left by Neil Rees on 5/14/2009 4:36 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Yes they are on a Windows 2000 domain. I have disabled Anonymous access on the IIS eb site and have checked off Integrated Auth as well. It is possible that some of the components were installed before the server was on a domain. Do you think that would break it?
Left by Brent McCraney on 5/14/2009 6:45 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar 'checked off Integrated Auth' - you'll need this ON.

Other things for you to try are to point IE at http://servername rather and not http://servername.domain.com and see if that makes any difference.
Left by Neil Rees on 5/18/2009 10:20 AM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Your blog has helped me understand WOL a bit better & I've been experimenting with creating a WOL utility using VB 2008 Express Edition.

If I understand how to use Udpclient class, it defaults to non-broadcast mode unless you specifically set broadcast mode as true directly or in-directly by using IPAddress.Broadcast as your code does in the Udpclient.Connect statement.

I have found that the UDP unicast mode to a PC in a different subnet using simply a name or IP address method will work to wake-up a PC (Dell Precision 390's) if their Bios & OS NIC settings are configured properly as you describe & providing that the switch/router allows the traffic & maintains the MAC address in it's lookup table.

The utility I created successfully started the PC's yesterday & I discovered today that the PC's cannot be sent the WOL MP once the IP/MAC address has aged out of our Cisco switches (we have a multi-subnet environment). We confirmed this by manually power cycling the PC & when it was powered down again my utility once again was able to wake the PC up only until the MAC aged out again.

Directed subnet broadcasts (eg. x.x.x.255 for Class C) may be usable as a workaround to today's finding and/or would be a required alternate method if DHCP address was reassigned but again appear to depend on switch/router configuration, I have to check with another department - so far my tests show this doesn't appear to be supported under present configuration either. B^(
Left by R. Frampton on 8/12/2009 2:30 AM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Thanks for the article. I can go a bit green too!
Left by Junkie on 11/11/2009 9:55 PM
# re: Going slightly green - Wake on LAN from ASP.NET
Gravatar Hey! Great and useful tool, thank you very much. One thing, if you have more then one NIC in the server, verify on which interface the WOL Packet will be sent. in my case i have to deactivate the unused NIC and then works fine. I can boot also computers that are shutdown. Regards, dominic
Left by domi on 6/18/2010 5:03 PM

Leave Your Comment

Title*
Name*
Email (never displayed)
 (will show your gravatar)
Url
Comment*

Please add 3 and 4 and type the answer here:

Preview Your Comment.