Though I’m aware that a computer can be configured to wake up when it receives a specific LAN packet, I’ve not used the feature until now. I was motivated to do so after a few incidents when I had driven to the office and realized that I had forgotten to push my code from a computer that was at home. It has happened before, in which case I would remote into the computer and perform a push. But a few times that this happened, the computer had already gone to sleep, and I had to persuade someone to press a key on the keyboard to wake it up.
It has happened more than once. I decided it was time to do something about it. The first couple of things that I needed to do were to ensure that the Wake On Lan (WOL) feature was turned on in the BIOS. How this is done may vary from one computer to another. I also needed to get the MAC address for my computer’s active network adapter. Traditionally, WOL has been a feature for wired network adapters only. This is fine for me, since my desktop computers are all on wired connections. From a PowerShell terminal, the MAC addresses for all of the network adapters can be viewed with the command GET-NETADAPTER.The output looks like the following.
PS C:\Users\joel> get-netadapter
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Bluetooth Network Conn... Bluetooth Device (Personal Area Netw... 11 Disconnected 23-55-D8-7B-36-B1 3 Mbps
Ethernet Realtek PCIe GbE Family Controller 7 Disconnected 70-36-BC-23-44-66 0 bps
Wi-Fi Intel(R) Wi-Fi 6E AX211 160MHz 5 Up 23-55-D8-7B-36-AD 400 Mbps
The Packet Structure
The structure of the WOL packet is simple. We only need to build this packet and send it over a UDP broadcast message. The packet is 102 bytes in length. The first 6 bytes are just 0xFF repeated 6 times. The rest of the bytes of the packet are the MAC address repeated 16 times. Once the packet is build, it must be sent on a broadcast message. The reason that we send it via a broadcast message is the target computer might not even have an IP address, since it isn’t turned on. Sending it to all computers on a subnet ensures that our target computer will receive the message.
Building Packet in C++
std::vector<BYTE> MacAddressToByteArray(std::wstring macAddress)
{
std::vector<BYTE> macAddressBytes;
std::wstring macAddressPart;
for (size_t i = 0; i < macAddress.size(); i++)
{
if (macAddress[i] == L':')
{
macAddressBytes.push_back((BYTE)std::stoi(macAddressPart, nullptr, 16));
macAddressPart.clear();
}
else
{
macAddressPart.push_back(macAddress[i]);
}
}
macAddressBytes.push_back((BYTE)std::stoi(macAddressPart, nullptr, 16));
return macAddressBytes;
}
void SendWOL(std::vector<BYTE> macAddress)
{
std::vector<BYTE> magicPacket;
for (size_t i = 0; i < 6; i++)
{
magicPacket.push_back(0xFF);
}
for (size_t i = 0; i < 16; i++)
{
for (size_t j = 0; j < macAddress.size(); j++)
{
magicPacket.push_back(macAddress[j]);
}
}
BroadcastMessage(magicPacket);
}
void SendWOL(std::wstring macAddress) {
auto bytes = MacAddressToByteArray(macAddress);
SendWOL(bytes);
}
Building the Packet in C#
static void SendWOL(IEnumerable<byte> MACAddress)
{
byte[] packet = new byte[102];
for (int i = 0; i < 6; i++)
packet[i] = 0xFF;
for (int i = 0; i < 102-6; i ++)
{
packet[i + 6] = MACAddress.ElementAt(i%6);
}
UdpClient client = new UdpClient();
client.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
client.Send(packet, packet.Length, new IPEndPoint(IPAddress.Broadcast, 9));
}
static void SendWOL(String MACAddress)
{
var parts = MACAddress.Split(new char[] { ':', '-' });
if (parts.Length != 6)
return;
byte[] mac = new byte[6];
for (int i = 0; i < 6; i++)
mac[i] = Convert.ToByte(parts[i], 16);
SendWOL(mac);
}
static List<String> GetMacAddressList(String[] args)
{
List<String> retVal = new List<String>();
foreach (var arg in args)
{
if (MacAddressRegex.IsMatch(arg))
retVal.Add(arg);
}
return retVal;
}
Sending the Packet
The packet must be broadcast on UDP. We use broadcast because the computer doesn’t have an IP address that can be used for sending a unicast message directly to it. It doesn’t matter what port the message is sent on. But we will use Port 9 since many routers are configured to allow UDP traffic on that port. In the C# code, broadcasting the package is simple. It can be be done in three lines.
UdpClient client = new UdpClient();
client.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
client.Send(packet, packet.Length, new IPEndPoint(IPAddress.Broadcast, 9));
The C++ code is using WinSock2 for network communication. Using it is more involved than using the UDPClient object in .Net, but it isn’t complex. We create a datagram socket object, and then enable its broadcast option. We set the target port to 9, and specify its target address is the UDP broadcast address (255.255.255.255). Then we send the data through the port.
bool BroadcastMessage(std::vector<BYTE> message)
{
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
printf("Socket creation failed.\n");
WSACleanup();
return false;
}
BOOL broadcast = TRUE;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(broadcast)) < 0) {
printf("Error in setting Broadcast option.\n");
closesocket(sock);
WSACleanup();
return false;
}
sockaddr_in broadcastAddr;
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_port = htons(9); // Use your desired port
broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST;
if (sendto(sock, (char*)(message.data()), message.size(), 0, (sockaddr*)&broadcastAddr, sizeof(broadcastAddr)) < 0) {
printf("Broadcast message send failed.\n");
closesocket(sock);
WSACleanup();
return false;
}
closesocket(sock);
return true;
}
Downloading the Executable
I’ve made the executables for both the C++ and the C# code available for download on GitHub. You will find it in the bin folder. There are both signed and unsigned versions available. I made a signed version because one of the computers I intend to use this on is a corporate managed machine that gives less trust to unsigned executables. I can avoid some headaches and paperwork by having a signed executable.
Program Invocation
Not shown in the above source code is that the C++ and C# programs can both accept the MAC address from the command line. Invoking the program with the mac address as the argument to the program will result in it sending a WOL signal to that MAC address. More than one MAC address can be passed to the program.
Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.
Mastodon: @j2inet@masto.ai
Instagram: @j2inet
Facebook: @j2inet
YouTube: @j2inet
Telegram: j2inet
Twitter: @j2inet
One thought on “Building a Wake On Lan Packet”