📜 ⬆️ ⬇️

Wake on Lan Telegram bot

After the opening of the API bots for Telegram, their population began to grow rapidly. I decided to keep up and get my own to be able to remotely turn on the computer. C # was chosen for development, and Azure was chosen as the hosting.

Task

Write a bot that can send "magic packets" to turn on the computer to the specified address and port.

Note: the article does not consider getting a token for a bot and deploying a site on Azure. These questions are easily answered on Habré or Google.

A bit of theory and network settings


To turn on the computer will use the technology Wake on Lan . Since the bot will be in the cloud, we need to send the packet to an external address. In this regard, you need to make sure that the package eventually got into the local network and reached the desired network card. To do this, forward the port on the router:
')


Why port 7 and such an address?
Usually, to turn on a computer on a local network using Wake on Lan, you need to send a “magic packet” to the broadcast address of the local network, to port 7 / UDP (in some cases other ports can be used). When the network card receives “its” packet, it sends a signal to turn on the computer.

A packet consists of a set of bytes in the following order: the first 6 bytes are zero, then there is a sequence of bytes from the MAC address of the network card, which is repeated 16 times. Actually, it is for the MAC address of the network card and understands that it is necessary to turn on her computer.

We will form such a packet and send it to our external address (for example, to the address of the home router), after which the packet will have to be routed to the broadcast address of the local network.

In my case, port 7 is forwarded (accessible from the Internet) to the broadcast network address (10.10.10.255).


Write the code


To work with the bot API, the Telegram.Bot library was chosen. For updates, we will use the option with a webhuk . In this case, each message or event that the bot will receive will be sent to the specified URL.

As a hosting, it was decided to use Azure, as it is suitable in all respects:

To begin with, we create a class that will return us an object for working with the bot:

public static class Bot { private static Api _bot; /// <summary> ///  ,     ///   -  ///   /// </summary> public static Api Get() { if (_bot != null) return _bot; _bot = new Api(Config.BotApiKey); _bot.SetWebhook(Config.WebHookUrl); return _bot; } } 

Settings get out of the class Config
Config.cs
 public static class Config { /// <summary> ///        /// </summary> private static readonly NameValueCollection Appsettings = ConfigurationManager.AppSettings; /// <summary> ///     /// </summary> public static string BotApiKey { get { return Appsettings["BotApiKey"]; } } /// <summary> /// URL,         /// </summary> public static string WebHookUrl { get { return Appsettings["WebHookUrl"]; } } } 


Now we need to form and send a packet. The WakeOnLan class will be responsible for this.

 /// <summary> ///   ""      /// </summary> public static class WakeOnLan { public static void Up(string ip, string mac, int? port = null) { var client = new UdpClient(); var data = new byte[102]; for (var i = 0; i <= 5; i++) //    -  data[i] = 0xff; var macDigits = GetMacDigits(mac); if (macDigits.Length != 6) throw new ArgumentException("Incorrect MAC address supplied!"); const int start = 6; for (var i = 0; i < 16; i++) //       for (var x = 0; x < 6; x++) data[start + i * 6 + x] = (byte)Convert.ToInt32(macDigits[x], 16); client.Send(data, data.Length, ip, port ?? 7); //   } private static string[] GetMacDigits(string mac) //  MAC { return mac.Split(mac.Contains("-") ? '-' : ':'); } public static bool ValidateMac(string mac) //     MAC  { return GetMacDigits(mac).Length == 6; } } 


We form packets and are able to send. It remains to teach the bot to respond to the command, for example, / wol.
For simplicity, a command with parameters is implemented, i.e. the user will have to enter something like
/wol 1.2.3.4 01:02:03:04:05:06 7

in order to send the packet to the address 1.2.3.4, to port 7 and wake up the computer with the MAC address 01: 02: 03: 04: 05: 06

 public async void Handle(Message message) { var text = message.Text.Split(' '); if (text.First() != "/wol") return; switch (text.Count()) { case 1: case 2: await _bot.SendTextMessage(message.Chat.Id, " : /wol 1.2.3.4 01:02:03:04:05:06 7"); break; default: if (!WakeOnLan.ValidateMac(text[2])) await _bot.SendTextMessage(message.Chat.Id, " MAC "); else { try { WakeOnLan.Up(text[1], text[2], GetPort(text)); await _bot.SendTextMessage(message.Chat.Id, " !"); } catch (Exception) { await _bot.SendTextMessage(message.Chat.Id, "  :("); } } break; } } /// <summary> ///     /// </summary> private static int? GetPort(IReadOnlyList<string> text) { int port; if (text.Count == 4 && int.TryParse(text[3], out port)) return port; return null; } 

Great, it remains only to create a controller that will receive updates from the bot:
 public class MessageController : ApiController { [Route(@"api/message/wol")] public OkResult Post([FromBody]Update value) { Task.Run(() => new Handler().Handle(value.Message)); return Ok(); } } 

After “filling” the application in Azure, we check the bot :


References:
WoL bot in Telegram
GitHub project
API bots Telegram
Library Telegram.Bot (GitHub)

Source: https://habr.com/ru/post/265305/


All Articles