0

Wake on LAN (WOL) Relay

In this article I discuss how to create a Wake On LAN (WOL) relay using an ESP8266 microcontroller, so that you can remotely power on the devices connected on your Local Area Network (LAN) via the Internet.

Note: Remotely waking up a device via the Internet is also known as WOW (Wake On Wide Area Network (WAN)), since the Internet is on the WAN.

In the article below I focus on my ‘real-world’ requirement to be able to remotely power on a Synology DS2411+ Network Attached Storage (NAS) server via the Internet. My Synology DS2411+ NAS server is connected to an APC 1500 Smart UPS, which is also connected to my LAN. I was surprised to learn that this UPS does not have any functionality in its Management Web Interface or Telnet/SSH server to support broadcasting WOL ‘magic packet’ to devices over the LAN. Therefore, if there is a power outage, the APC 1500 Smart UPS is able to communicate with the Synology DS2411+ NAS server so that it gracefully shuts down. However, the APC 1500 Smart UPS has no mechanism in place to regularly poll the Synology DS2411+ NAS server, and power it back on with a magic WOL packet once the power outage is resolved!

Wake-up on LAN (WOL) uses uses a magic packet that is broadcast over the LAN with a specified Media Access Control (MAC) address. Any device on your LAN can be powered on via the magic packet, if the following criteria is met:

  • the device contains a Network Interface Card (NIC) that supports WOL function (most modern NICs do support WOL)
  • the device’s operating system has the WOL function enabled on the NIC
  • the device’s NIC has the same MAC address that was broadcast in the magic packet

Typically, trying to use WOL via the Internet to remotely power on a device in your LAN is difficult to accomplish as many routers do not support WOL relay functionality. Some routers that do have the WOL relay functionality (such as my router from Bouyages Telecom), but it does not function. WOL uses either User Datagram Port (UDP) 9 or UDP 7. Port forwarding UDP 9 for example to one device on your network has the following issues:

  • not reliable as the device’s IP address to MAC address binding is lost with time
  • limited to the IP address of the device that you specified in the port forwarding rule
  • risky as you are opening up your LAN to the Internet, allowing anyone to flood your LAN with mulitple WOL requests

As the diagram below illustrates, using a WOL relay on an ESP8266 microcontroller resolves these issues above, as the WOL relay adds a layer of security (using a SecureON pass code), and allows you to remotely power on multiple devices with different MAC addresses.

Example WOL Relay Implementation
Example WOL Relay Implementation – Remotely waking up a Synology NAS server via the Internet

In the diagram above, we see the following:

  • Using a mobile iOS application such as Magic Packet, we specify a UDP port of choice, rather than the ‘well known’ UDP 7 or UDP 9 ports. The UDP port of choice is defined on the ESP8266, and the specified UDP port in the iOS application must match that defined on the ESP8266. In our example, we use UDP 50055.
    Note: some mobile network providers close all UDP ports lower than 1024 on their 3G/4G/5G mobile networks. Therefore, it is recommended to configure the WOL relay on the ESP8266 with a UDP port greater than 1024.
  • Using a mobile iOS application, we can define more than one ‘target’ MAC address, so we are able to remotely power on more that one ‘target’ device in the LAN, if required.
  • Using a mobile iOS application, we need to specify a SecureON pass code in order for the WOL magic packet to be broadcast within the LAN. The SecureON pass code is defined on the ESP8266 in integer values, and the specified SecureON pass code in the iOS application must match that defined on the ESP8266, typically defined in the hexadecimal equivalent. In our example, we define 654321 as the integer values for the SecureON pass code on the ESP8266, which translates to 36:35:34:33:32:31 or 36-35-34-33-32-31 or in the iOS application.
    Note 1: Not all iOS applications support the SecureON functionality. The following two iOS applications support the the SecureON functionality: Magic Packet and WakeUP – The Wake on LAN Tool.
    Note 2: The SecureON passcode format may vary on different iOS applications. The Magic Packet iOS application uses the hyphens (-) between the HEX values, whereas other iOS applications may use colons (:).
    Note 3: Instead of using an iOS application, you can use the following website to launch WOL over the Internet : https://www.depicus.com/wake-on-lan/woli. This website also supports the use of the SecureON passcode.

In the diagram above we see that the mobile iOS application is sending the magic packet to robert wisbey.net, which is resolved to the WAN IP address of my router using the noip.com dynamic DNS service. You could specify the WAN IP address of your Internet router instead. However, if your router’s WAN IP address changes regularly you cannot guarantee being able to access your router or your LAN remotely. I recommend using the noip.com dynamic DNS service, which resolve your router’s current WAN IP address to a fixed domain name of your choice. The noip.com dynamic DNS service provides both a free and paid service. If you choose to use one of their paid services, feel free my referral links within this paragraph along with the REFER20 promo code to obtain a 20% reduction.

The following C++ code can be used to create the WOL relay on the ESP8266:

#include <ESP8266WiFi.h>                  
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>

////////////////////////////////////////////////
// Class to Send/Receive UDP's:
////////////////////////////////////////////////
class BroadCastDeamon: public WiFiUDP {
  public:
  void PostUDP( const char *Packet, IPAddress ip, unsigned int destPort) {
     PostUDP(Packet, strlen(Packet), ip, destPort);
  }
  void PostUDP( const char *Packet, int len, IPAddress ip, unsigned int destPort) {
    WiFiUDP::beginPacket( ip, destPort);
    WiFiUDP::write(Packet, len);
    WiFiUDP::endPacket();
  }
  void BroadcastUDP( const char *Packet, unsigned int destPort) {
     BroadcastUDP(Packet, strlen(Packet), destPort);
  }
  void BroadcastUDP( const char *Packet, int len, unsigned int destPort ) {
    IPAddress broadcastIP = (uint32_t)WiFi.localIP() | (~(uint32_t)WiFi.subnetMask());
    PostUDP(Packet, len, broadcastIP, destPort);
  }  
  
  bool CheckReceived() {
    // if there's data available, read a packet and return length
    packetSize = parsePacket();
    if (packetSize)
    {
      //Serial.print("Received UDP packet from [");
      //Serial.print(broadcastUdp.remoteIP());
      //Serial.print("] : ");
      // read the packet into packetBufffer
      int len = read(packetBuffer, 255);
      packetBuffer[len] = 0;
      //Serial.println(packetBuffer);
      return true;
    }
    return false;
  }
  char *GetPacketData() {
    return packetBuffer;
  }
  int GetPacketSize() {
     return packetSize;
  }
  private:
   char packetBuffer[256]; //buffer to hold last packet retreived
   int  packetSize;
};

BroadCastDeamon WOLDeamon;

////////////////////////////////
// the configuration Part of the code:

// SecureOn for WOL has to be 6 hex bytes; Advice change the default.
byte SecureOn[7] = "654321"; // In most WOL apps that support SecureOn you have to enter the bytes in HEX format like this: "36:35:34:33:32:31" for "654321"
// Receiver Port for WOL packets forwarded by the router
unsigned int WOLPort=50055; // just some random choice in the free range. But make sure you forward UDP packets to this port in your router

// Enter your own WLAN credentials
char wlanSSID[]="Your Wifi LAN SSID";
char wlanPWD[]="Your Wifi LAN Password";


void setup() {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting the WOL Gateway "); 
  while (!ConnectToNetwork(wlanSSID, wlanPWD)) {
    delay(2000);
  }
  WOLDeamon.begin(WOLPort);
}



void loop() {
    HandleWOLReceived(SecureOn);
    delay(10);
}

bool ConnectToNetwork(char *wlanSSID, char *wlanPWD )  {
  int timeout=0;
  bool succes=false;
  WiFi.mode(WIFI_STA);
  Serial.print("Connecting SSID: ");
  Serial.println(wlanSSID);
  WiFi.begin(wlanSSID, wlanPWD);
  while (WiFi.status() != WL_CONNECTED && timeout < 10)
  {
      delay(1000);
      timeout++;
  }
  if (WiFi.status() == WL_CONNECTED) {
     Serial.println();
     Serial.print("Connected, IP address: ");
     Serial.println(WiFi.localIP());
     succes=true;
  }
  else {
    Serial.println("Connecting to SSID Failed ");
  }
  // printWifiMode();
  return succes;
}



#define WOL_SECURE_PACKET_SIZE 108
bool HandleWOLReceived (byte *pwd) {
  if (WOLDeamon.CheckReceived() && WOLDeamon.GetPacketSize() == WOL_SECURE_PACKET_SIZE) {
     byte *pPrefix = (byte *)WOLDeamon.GetPacketData();
     byte *pPWD = pPrefix + 102; // start position of the SecureOn
     // check if it is has both a valid WOL prefix (6 times FF) and that it contains the defined SecureOn password
     for (int i=0; i<6; i++) {
       if (pPrefix[i] != 255 || pPWD[i] != pwd[i]) {
         Serial.println("INVALID WOL packet received");
         return false;
       }
     }
     // Broadcast WOL packet on local LAN
     Serial.println("Valid WOL packet received");
     WOLDeamon.BroadcastUDP(WOLDeamon.GetPacketData(), WOL_SECURE_PACKET_SIZE, 7); // accidently used for WOL (official for echo)
     WOLDeamon.BroadcastUDP(WOLDeamon.GetPacketData(), WOL_SECURE_PACKET_SIZE, 9); // (un)official WOL port
  }
  return true;
}

Note: in the C++ code above, the WiFi credentials are generic, 654321 has been used for the SecureON passcode, and 50055 has been used for the UDP listening port. Change these four configuration parameters according to your needs.

Once the C++code has been written to the ESP8266 and it is connected to your LAN, you can monitor the serial port via Arduino to see the IP address it initially obtained from your router.

Example Arduino Serial Output When Connected to the ESP8266 Microcontroller Running the WOL Relay C++ Code
Example Arduino Serial Output When Connected to the ESP8266 Microcontroller Running the WOL Relay C++ Code

On your router, you can identify the ESP8266 that is functioning as the WOL relay, and determine its MAC address. On your router’s DHCP server you must define assign the MAC address of the ESP8266 functioning as the WOL relay with a static IP address (e.g. 192.168.1.5).

DHCP Server Static IP Address Settings
DHCP Server Static IP Address Settings

Once the static IP address has been defined for the ESP8266 functioning as the WOL relay in the DHCP table on your router, you must port forward the UDP port that you had defined on the ESP8266 (e.g. 50055) to that static IP address.

Port Forwarding to ESP8266 WOL Relay
Port Forwarding to ESP8266 WOL Relay

The following video illustrates the WOL relay functioning as expected, remotely powering on (waking up) a Synology NAS server over the Internet. I hope this article has been of help to anyone who has needed to remotely power on (wake up) any devices in the LAN via the Internet.