WOL through the internet - solution!

I sometimes work from home and need to turn on my office computer. I used to VPN to a server and then send a magic packet from there to wake my computer. I thought it would be great to just do it remotely from the internet using an Ethernet shield.

Looking for the readily available solutions, nothing I found actually gave me what I wanted, so I pieced together some of this and some of that and came up with a solution that works for me.

Again, most of this stuff is other peoples work that they shared, I only found a way to make it work together. It’s mostly commented out in the sketch, with the only last bit of helpful information is that you will need to forward port 8888 (or change the port number in the sketch) to the IP of your Ethernet shield, forwarding both TCP and UDP. You will need to do this in your router.

Here’s the code - It’s a little rough around the edges, and when time permits, I will put in some options for waking up different computers on the network, and also cleaning up the web interface.

/* This sketch is used to send WOL Magic Packets to turn on a computer
 * in a remote LAN through the internet, so you can Remote Desktop to it.  
 * This example assumes that you're familiar with the basics
 * of the Ethernet library (particularly with setting MAC and
 * IP addresses) and with the basics of Webduino. If you
 * haven't had a look at the HelloWorld example you should
 * probably check it out first.  Most of this is not my work,
 * I just pieced a few sketches together for my personal use
 * and I am sharing this because I was not able to find a complete
 * solution for my own needs. */

/* you can change the authentication realm by defining
 * WEBDUINO_AUTH_REALM before including WebServer.h */
 
#define WEBDUINO_AUTH_REALM "My Website"

#include <SPI.h>
#include <Ethernet.h>
#include <WebServer.h>
#include <Utility\Socket.h>
int Authenticated = 0;

/* CHANGE THIS TO YOUR OWN UNIQUE VALUE.  The MAC number is
 * on the sticker on the bottom of the Ethernet shield */
static byte g_abyMyMacAddress[] = { 0x00, 0xB2, 0xDA, 0x0D, 0x89, 0x7F };

/* CHANGE THIS TO MATCH YOUR HOST NETWORK.  Most home networks are in
 * the 192.168.0.XXX or 192.168.1.XXX subrange.  Pick an address
 * that's not in use and isn't going to be automatically allocated by
 * DHCP from your router. */
static IPAddress g_MyIPAddress(192,168,0,102);

/* This is the MAC of the computer that you want to wake up */
static byte g_TargetMacAddress[] = {0x00,0x24,0x21,0xD5,0x20,0xA1};

/* This is the number of magic packets to send.  Normally 1 is enough,
 * but we're sending 5 in this example*/
int npackets = 5;

/* This creates an instance of the webserver.  By specifying a prefix
 * of "", all pages will be at the root of the server. */
#define PREFIX ""
WebServer webserver(PREFIX, 80);

/* Do not change the "Y" Value */
int Y = npackets;

void defaultCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  server.httpSuccess();
  if (type != WebServer::HEAD)
  {
    P(helloMsg) = "<h1>Welcome Home </h1><a href=\"private.html\">Click here to log in.</a>";
    server.printP(helloMsg);
  }
}


void privateCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  /* if the user has requested this page using the following credentials
   * username = user
   * password = user
   * sent the WOL packets
   *
   * the credentials have to be concatenated with a colon like
   * username:password
   * and encoded using Base64 - this should be done outside of your Arduino
   * to be easy on your resources
   *
   * in other words: "dXNlcjp1c2Vy" is the Base64 representation of "user:user"
   *
   * if you need to change the username/password dynamically please search
   * the web for a Base64 library */
  if (server.checkCredentials("dXNlcjp1c2Vy"))
  
  {
    server.httpSuccess();
    if (type != WebServer::HEAD)
    
    {
Authenticated = 1;
    }
  }
  
  else
  {
    Authenticated = 0;
    server.httpUnauthorized();
    }
    
    if (Authenticated == 1)
    do
    {
    SendWOLMagicPacket(g_TargetMacAddress);
    npackets = (npackets -1);
    delay (1000);
    P(helloMsg) = "<h1>Magic Packets sucessfully sent</h1></a>";
    server.printP(helloMsg);
        }
    while (npackets > 0);
    Authenticated = 0;
    npackets = Y;
}
void SendWOLMagicPacket(byte * pMacAddress)
{
  // The magic packet data sent to wake the remote machine. Target machine's
  // MAC address will be composited in here.
  const int nMagicPacketLength = 102;
  byte abyMagicPacket[nMagicPacketLength] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  byte abyTargetIPAddress[] = { 255, 255, 255, 255 }; // don't seem to need a real ip address.
  const int nWOLPort = 9;
  const int nLocalPort = 80; // to "listen" on 

  
  // Compose magic packet to wake remote machine. 
  for (int ix=6; ix<102; ix++)
    abyMagicPacket[ix]=pMacAddress[ix%6];
  
  if (UDP_RawSendto(abyMagicPacket, nMagicPacketLength, nLocalPort, 
  abyTargetIPAddress, nWOLPort) != nMagicPacketLength)
  {}
}

int UDP_RawSendto(byte* pDataPacket, int nPacketLength, int nLocalPort, byte* pRemoteIP, int nRemotePort)
{
  int nResult;
  int nSocketId; // Socket ID for Wiz5100

  // Find a free socket id.
  nSocketId = MAX_SOCK_NUM;
  for (int i = 0; i < MAX_SOCK_NUM; i++) 
  {
    uint8_t s = W5100.readSnSR(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) 
	  {
      nSocketId = i;
      break;
    }
  }

  if (nSocketId == MAX_SOCK_NUM)
    return 0; // couldn't find one. 

  if (socket(nSocketId, SnMR::UDP, nLocalPort, 0))
  {
    
    nResult = sendto(nSocketId,(unsigned char*)pDataPacket,nPacketLength,(unsigned char*)pRemoteIP,nRemotePort);
    close(nSocketId);
    
  } else
    nResult = 0;

  return nResult;
}
void setup()
{
  Ethernet.begin(g_abyMyMacAddress, g_MyIPAddress);
  webserver.setDefaultCommand(&defaultCmd);
  webserver.addCommand("index.html", &defaultCmd);
  webserver.addCommand("private.html", &privateCmd);
  webserver.begin();
}

void loop()
{
  char buff[64];
  int len = 64;

  /* process incoming connections one at a time forever */
  webserver.processConnection(buff, &len);
}

I added an option to send multiple packets and a confirmation that the packets were sent. I changed the code above to reflect that change.

Seems like not a very secure office environment if you can do things like that from home.

Really? how do you figure?

You do need a username and password to send the WOL packet, and that's only to turn the computer on. Then you need a VPN connection to the remote computer.

The most "harm" anyone can do is to turn on the computer and burn up some electricity. It's no less secure than having your computer on for everyday computing.

I suppose. Except for all the goverment firewalls where I work.