Monday, May 11, 2009

Wake On LAN (WOL) in C#

Stumble del.icio.us Reddit MyWeb! Facebook Google bookmark

I was looking for something to wake my remote machine on LAN or a different laptop connected in my network to wake up without having to press the power button again and again. There are some programs available but you have to pay for them. It's pretty easy to make a packet (so called magic packet) and broadcast it in the network. The packet contains the MAC address of the machine which has to be woken up. If that machine is in network and is connected via a LAN cable, it should wake itself up. So here is the program in C# which creates the magic packet and broadcasts it in the network. You might also like to check my post on Get MAC address from hostname or IP address to integrate this program and the other one together so you will just have to enter the hostname/IP address of the machine which you want woken up without worrying about it's MAC address. If you want just the exe, let me know via a comment here and I'll send you the executable.


    1 // No copyrights(c). Use as you wish!

    2 

    3 using System;

    4 using System.Globalization;

    5 using System.Text.RegularExpressions;

    6 using System.Net;

    7 using System.Net.Sockets;

    8 

    9 namespace Yours.Truly

   10 {

   11     // *************************************************************************

   12     /// <summary>

   13     /// A class to demonstrate Wake up on LAN. For this program to function, your

   14     /// machine must be setup to accept wake-up on LAN requests. Usually this

   15     /// option can set to "Enabled" state in boot(BIOS) options. You can see the

   16     /// set value by Rebooting your PC/Laptop and press F2 just after you power

   17     /// on your PC/Laptop. (you might have to keep pressing F2 until it comes up

   18     /// with boot options)

   19     /// </summary>

   20     /// <remarks>

   21     /// <para>

   22     /// For more information see http://support.microsoft.com/kb/257277 and

   23     /// http://en.wikipedia.org/wiki/Wake-on-LAN.

   24     /// </para>

   25     /// <para>For an in depth details please visit :

   26     /// http://en.wikipedia.org/wiki/Data_link_layer and

   27     /// http://en.wikipedia.org/wiki/Network_layer </para>

   28     /// </remarks>

   29     public sealed class WakeUpOnLan

   30     {

   31         // *********************************************************************

   32         /// <summary>

   33         /// Main entry point of the application.

   34         /// </summary>

   35         /// <param name="args">An array of command line arguments.</param>

   36         static void Main(string[] args)

   37         {

   38             bool wakeUp = true;

   39             while (wakeUp)

   40             {

   41                 Console.WriteLine("Enter the MAC address of the host to wake up " +

   42                     " on LAN (no space or hyphen(-). e.g. 0021702BA7A5." +

   43                     "Type Exit to end the program):");

   44                 string macAddress = Console.ReadLine();

   45 

   46                 StringComparer cp = StringComparer.OrdinalIgnoreCase;

   47                 if (cp.Compare(macAddress, "Exit") == 0) break;

   48 

   49                 //remove all non 0-9, A-F, a-f characters

   50                 macAddress = Regex.Replace(macAddress, @"[^0-9A-Fa-f]", "");

   51                 //check if mac adress length is valid

   52                 if (macAddress.Length != 12)

   53                 {

   54                     Console.WriteLine("Invalid MAC address. Try again!");

   55                 }

   56                 else

   57                 {

   58                     Wakeup(macAddress);

   59                 }

   60             }

   61         }

   62 

   63         // *********************************************************************

   64         /// <summary>

   65         /// Wakes up the machine with the given <paramref name="macAddress"/>.

   66         /// </summary>

   67         /// <remarks>

   68         /// <para>

   69         /// <note>

   70         /// <list type="number">

   71         /// <item> The motherboard must support Wake On LAN.</item>

   72         /// <item> The NIC must support Wake On LAN.</item>

   73         /// <item> There must be a wire connecting the motherboard's WOL port to

   74         /// the NIC's WOL port. Usually there always is a connection on most of

   75         /// the PCs.</item>

   76         /// <item> The Wake On LAN feature must be enabled in the motherboard's

   77         /// BIOS. Usually this is also enabled by default, but you might like to

   78         /// check again.</item>

   79         /// <item> The "Good Connection" light on the back of the NIC must be lit

   80         /// when the machine is off. (By default always good if you are not

   81         /// facing any network issues)</item>

   82         /// <item> Port 12287 (0x2FFF) must be open. (By default it should be

   83         /// open unless some antivirus or any other such program has changed

   84         /// settings.)</item>

   85         /// <item> Packets cannot be broadcast across the Internet.  That's why

   86         /// it's called Wake On Lan, not Wake On Internet.</item>

   87         /// <item> To find your MAC address, run the MSINFO32.EXE tool that is a

   88         /// part of Windows and navigate to Components > Network > Adapteror

   89         /// or simply type nbtstat -a &lt;your hostname &lt at command prompt.

   90         /// e.g. nbtstat -a mymachinename or nbtstat -A 10.2.100.213.

   91         /// .</item>

   92         /// </list>

   93         /// </note>

   94         /// </para>

   95         /// <para>You could also use my other blog on "Get MAC address" to simply

   96         /// integrate this program and my other program so you just have to input

   97         /// the hostname/IP address of the machine which you want woken up.</para>

   98         /// <para>See http://mycomponent.blogspot.com/2009/05/get-mac-address-in-c-from-ip.html

   99         /// </para>

  100         /// </remarks>

  101         /// <param name="macAddress">The MAC address of the host which has to be

  102         /// woken up.</param>

  103         private static void Wakeup(string macAddress)

  104         {

  105             WOLUdpClient client = new WOLUdpClient();

  106             client.Connect(

  107                     new IPAddress(0xffffffff),    //255.255.255.255  i.e broadcast

  108                     0x2fff); // port = 12287

  109             // Set the socketoptions

  110             if (client.IsClientInBrodcastMode())

  111             {

  112                 int byteCount = 0;

  113                 // buffer to be sent:

  114                 // 6 bytes each with 255 + 16 times mac each 6 bytes

  115                 byte[] bytes = new byte[102];

  116                 // The packet begins with 6 bytes trailer of FF bytes which is

  117                 // followed by 16 times repeated MAC address of the target device

  118                 // (i.e. the device that should be switched on). MAC Address is

  119                 // used as an identifier in the packet, because that is the only

  120                 // valuable identification that is available when the PC is not

  121                 // running. MAC Address is assigned by the manufacturer (it is

  122                 // a layer 2 - Data link layer identifier) and it stored in the

  123                 // flash memory of the network card itself, so the network card

  124                 // can perform the comparison very easily. It cannot use an IP

  125                 // address, because network card simply does not have one when

  126                 // PC is not running - IP address is a layer 3 - network layer

  127                 // identifier, which means it is assigned by the OS.

  128                 // You may also ask why the MAC address is repeated 16 times?

  129                 // As mentioned above the network card scans all packets that

  130                 // are coming in and it does not support any protocols of higher

  131                 // levels (TCP, HTTP, etc.) - it will literally go through all

  132                 // bytes in the packet and if it finds the "magic packet"

  133                 // sequence anywhere in the data or even a packet header, it

  134                 // will turn on the PC. Imagine that the packet did not repeat

  135                 // the MAC Address, so it would only utilise 6 bytes of FF and

  136                 // then 6 bytes of the MAC address. This 12 bytes combination

  137                 // may sooner or later appear in your network communication

  138                 // (in a file transfer, incoming email, a picture, etc.). 12

  139                 // bytes is just not enough, which is why the MAC address is

  140                 // repeated 16 times giving the packet solid 102 bytes. The

  141                 // probability that those 102 bytes will unintentionally appear

  142                 // in transferred data is exponentially lower (there are

  143                 // 256^102 different packets which should be safe enough).

  144 

  145                 // First 6 bytes should be 0xFF

  146                 for (int trailer = 0; trailer < 6; trailer++)

  147                 {

  148                     bytes[byteCount++] = 0xFF;

  149                 }

  150                 // Repeat MAC 16 times

  151                 for (int macPackets = 0; macPackets < 16; macPackets++)

  152                 {

  153                     int i = 0;

  154                     for (int macBytes = 0; macBytes < 6; macBytes++)

  155                     {

  156                         bytes[byteCount++] =

  157                             byte.Parse(macAddress.Substring(i, 2),

  158                             NumberStyles.HexNumber);

  159                         i += 2;

  160                     }

  161                 }

  162 

  163                 // Send wake up packet (the magic packet!)

  164                 int returnValue = client.Send(bytes, byteCount);

  165                 Console.WriteLine(returnValue + " bytes sent to " + macAddress +

  166                     Environment.NewLine + "Check if it's woken up. If not, try again!" +

  167                     Environment.NewLine);

  168             }

  169             else

  170             {

  171                 Console.WriteLine("Remote client could not be set in broadcast mode!");

  172             }

  173         } // end Wakeup

  174 

  175     } // end class WakeUpOnLan

  176 

  177     // *************************************************************************

  178     /// <summary>

  179     /// A <see cref="UdpClient"/> class to set the client to broadcast mode.

  180     /// </summary>

  181     /// <remarks>

  182     /// <para>

  183     /// This class just sets the SocketOption to

  184     /// <see cref="SocketOptionName.Broadcast"/> mode.

  185     /// </para>

  186     /// </remarks>

  187     public class WOLUdpClient : UdpClient

  188     {

  189         // *********************************************************************

  190         /// <summary>

  191         /// Initializes a new instance of <see cref="WOLUdpClient"/>.

  192         /// </summary>

  193         public WOLUdpClient() : base()

  194         {

  195         }

  196 

  197         // *********************************************************************

  198         /// <summary>

  199         /// Sets up the UDP client to broadcast packets.

  200         /// </summary>

  201         /// <returns><see langword="true"/> if the UDP client is set in

  202         /// broadcast mode.</returns>

  203         public bool IsClientInBrodcastMode()

  204         {

  205             bool broadcast = false;

  206             if (this.Active)

  207             {

  208                 try

  209                 {

  210                     this.Client.SetSocketOption(SocketOptionLevel.Socket,

  211                                             SocketOptionName.Broadcast, 0);

  212                     broadcast = true;

  213                 }

  214                 catch

  215                 {

  216                     broadcast = false;

  217                 }

  218             }

  219             return broadcast;

  220         }

  221 

  222     } // end class WOLUdpClient

  223 } // end namespace Yours.Truly



Continue >>

Get MAC Address in C# from IP Address/Hostname

Stumble del.icio.us Reddit MyWeb! Facebook Google bookmark

I was hoping to find something to get MAC address of a machine given its IP address or hostname. There could be multiple ways to do the same. But I thought I'll give the "nbtstat" a chance. nbtstat is a command in windows which gets you the details about protocol statistics and current TCP/IP connections using NBT (NetBIOS over TCP/IP). Here is a small program in C# which does the exact same thing: (If you want just the exe, let me know via a comment here and I'll send you the executable.)


    1 // No copyrights(c). Use as you wish!

    2 

    3 using System;

    4 using System.Diagnostics;

    5 using System.Net;

    6 using System.Net.NetworkInformation;

    7 using System.Runtime.InteropServices;

    8 using System.Text;

    9 

   10 namespace Yours.Truly

   11 {

   12     // *************************************************************************

   13     /// <summary>

   14     /// A class to get the MAC address from IP address. The same class can be

   15     /// modified a little to get the MAC address from the specified hostname.

   16     /// </summary>

   17     public class GetMacAddressFromIPAddress

   18     {

   19         /// <summary> Ping timeout (in ms) </summary>

   20         private const int PING_TIMEOUT = 1000;

   21 

   22         // *********************************************************************

   23         /// <summary>

   24         /// Initializes a new instance of <see cref="GetMacAddressFromIPAddress"/>.

   25         /// </summary>

   26         public GetMacAddressFromIPAddress()

   27         {

   28         }

   29 

   30         // *********************************************************************

   31         /// <summary>

   32         /// Gets the MAC address from specified <paramref name="IPAddress"/>

   33         /// using nbtstat in hyphen (-) separated format.

   34         /// </summary>

   35         /// <remarks>

   36         /// <para>

   37         /// The same class can be modified to accept hostname and then resolve

   38         /// the hostname to Ip address to get the MAC address or just pass "-a"

   39         /// argument to "nbtstat" to get the mac address from hostname. If you

   40         /// want to find the MAC address from only the IP address change the

   41         /// switch to "-A".

   42         /// </para>

   43         /// <para>

   44         /// The current program can resolve both hostname as well as IP address

   45         /// to MAC address. The "-a" argument can actually accept both IP address

   46         /// as well as hostname.

   47         /// </para>

   48         /// </remarks>

   49         /// <param name="ipAddress">The IP address or hostname for the machine

   50         /// for which the MAC address is desired.</param>

   51         /// <returns>A string containing the MAC address if MAC address could be

   52         /// found.An empty or null string otherwise.</returns>

   53         private string GetMacAddress(string ipAddress)

   54         {

   55             string macAddress = string.Empty;

   56 

   57             if (!IsHostAccessible(ipAddress)) return null;

   58             try

   59             {

   60                 ProcessStartInfo processStartInfo = new ProcessStartInfo();

   61                 Process process = new Process();

   62                 processStartInfo.FileName = "nbtstat";

   63                 processStartInfo.RedirectStandardInput = false;

   64                 processStartInfo.RedirectStandardOutput = true;

   65                 processStartInfo.Arguments = "-a " + ipAddress;

   66                 processStartInfo.UseShellExecute = false;

   67                 process = Process.Start(processStartInfo);

   68 

   69                 int Counter = -1;

   70 

   71                 while (Counter <= -1)

   72                 {

   73                     // Look for the words "mac address" in the output.

   74                     // The output usually looks likes this:

   75 

   76                     // Local Area Connection:

   77                     //Node IpAddress: [13.15.111.222] Scope Id: []

   78 

   79                     //           NetBIOS Remote Machine Name Table

   80 

   81                     //       Name               Type        Status

   82                     //    --------------------------------------------

   83                     //    SAMGLS0790W    <00>  UNIQUE      Registered

   84                     //    SAMPLS0790W    <20>  UNIQUE      Registered

   85                     //    NA            <00>  GROUP       Registered

   86 

   87                     //    MAC Address = 00-21-70-2B-A5-43

   88 

   89                     Counter =

   90                         macAddress.Trim().ToLower().IndexOf("mac address", 0);

   91                     if (Counter > -1)

   92                     {

   93                         break;

   94                     }

   95                     macAddress = process.StandardOutput.ReadLine();

   96                 }

   97                 process.WaitForExit();

   98                 macAddress = macAddress.Trim();

   99             }

  100             catch (Exception e)

  101             {

  102                 // Something unexpected happened? Inform the user

  103                 // The possibilities are:

  104                 // 1.That the machine is not on the network currently

  105                 // 2. The IP address/hostname supplied are not on the same network

  106                 // 3. The host was not found on the same subnet or could not be

  107                 //    resolved

  108                 Console.WriteLine("Failed because:" + e.ToString());

  109             }

  110 

  111             return macAddress;

  112         }

  113 

  114         #region Getting MAC from ARP

  115 

  116         [DllImport("iphlpapi.dll", ExactSpelling = true)]

  117         static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr,

  118             ref uint PhyAddrLen);

  119 

  120         // *********************************************************************

  121         /// <summary>

  122         /// Gets the MAC address from ARP table in colon (:) separated format.

  123         /// </summary>

  124         /// <param name="hostNameOrAddress">Host name or IP address of the

  125         /// remote host for which MAC address is desired.</param>

  126         /// <returns>A string containing MAC address; null if MAC address could

  127         /// not be found.</returns>

  128         private string GetMACAddressFromARP(string hostNameOrAddress)

  129         {

  130             if (!IsHostAccessible(hostNameOrAddress)) return null;

  131 

  132             IPHostEntry hostEntry = Dns.GetHostEntry(hostNameOrAddress);

  133             if (hostEntry.AddressList.Length == 0)

  134                 return null;

  135 

  136             byte[] macAddr = new byte[6];

  137             uint macAddrLen = (uint) macAddr.Length;

  138             if (SendARP((int) hostEntry.AddressList[0].Address, 0, macAddr,

  139                 ref macAddrLen) != 0)

  140                 return null;

  141 

  142             StringBuilder macAddressString = new StringBuilder();

  143             for (int i = 0; i < macAddr.Length; i++)

  144             {

  145                 if (macAddressString.Length > 0)

  146                     macAddressString.Append(":");

  147 

  148                 macAddressString.AppendFormat("{0:x2}", macAddr[i]);

  149             }

  150 

  151             return macAddressString.ToString();

  152         } // end GetMACAddressFromARP

  153 

  154         #endregion Getting MAC from ARP

  155 

  156         // *********************************************************************

  157         /// <summary>

  158         /// Checks to see if the host specified by

  159         /// <paramref name="hostNameOrAddress"/> is currently accessible.

  160         /// </summary>

  161         /// <param name="hostNameOrAddress">Host name or IP address of the

  162         /// remote host for which MAC address is desired.</param>

  163         /// <returns><see langword="true" /> if the host is currently accessible;

  164         /// <see langword="false"/> otherwise.</returns>

  165         private static bool IsHostAccessible(string hostNameOrAddress)

  166         {

  167             Ping ping = new Ping();

  168             PingReply reply = ping.Send(hostNameOrAddress, PING_TIMEOUT);

  169             return reply.Status == IPStatus.Success;

  170         }

  171 

  172         // *********************************************************************

  173         /// <summary>

  174         /// The netry point for the application.

  175         /// </summary>

  176         /// <param name="args">An array of command line arguments.</param>

  177         [STAThread]

  178         static void Main(string[] args)

  179         {

  180             bool macRequired = true;

  181             while (macRequired)

  182             {

  183                 Console.WriteLine("Enter the IP address for which mac address is " +

  184                                 "required:(Enter exit to quit the program.)");

  185                 string ipAddress = Console.ReadLine();

  186                 StringComparer cp = StringComparer.OrdinalIgnoreCase;

  187                 if (cp.Compare(ipAddress, "Exit") == 0) break;

  188 

  189                 GetMacAddressFromIPAddress getMacAddress =

  190                     new GetMacAddressFromIPAddress();

  191 

  192                 Console.WriteLine("Please wait while I try to find the MAC address...");

  193                 // You may also use the ARP table. Call GetMACAddressFromARP here

  194                 string MacAddress = getMacAddress.GetMacAddress(ipAddress);

  195 

  196                 Console.WriteLine(MacAddress);

  197             } // end while

  198         }

  199 

  200     } // end class GetMacAddressFromIPAddress

  201 

  202 } // end namespace Yours.Truly


Continue >>