How to enumerate devices on a network from c# and .NET? - c#

I am writing a Windows desktop app that communicates with my DSLR camera via Wireless network (WLAN). I need a way to scan the network and find the camera by its MAC address or other identifying information. Nirsoft Wireless Network Watcher displays information about each device on my network. (Specifically: 'IP Address', 'Device Name', 'MAC Address', 'Network Adapter Company', etc.) Does .NET provide a way to retrieve this information from C#?

You can check out the following blog where someone already wrote a code for something like this.
https://www.maniuk.net/2016/08/get-ip-address-by-mac-address-in-csharp.html
This uses the command line arp command as an external process. I have tested it and seems to be working ok. As the code stands the mac address has to be in the format aa-bb-cc-dd-ee-ff
Alternatively, there is a Nuget Package called ArpLookup.
https://www.nuget.org/packages/ArpLookup/
With this one, you have to provide the IP Address and it will return the mac address. So you would have to enumerate through your IP range and return the one that matches the mac address.
Something like this:
private static async Task<string> GetIPFromMAC(string macAddress)
{
var ping = new Ping();
var start = BitConverter.ToInt32(new byte[] { 1, 0, 168, 192 }, 0);
var end = BitConverter.ToInt32(new byte[] { 254, 0, 168, 192 }, 0);
for (var i = start; i <= end; i++)
{
var bytes = BitConverter.GetBytes(i);
var ipAddress = new IPAddress(new[] {bytes[3], bytes[2], bytes[1], bytes[0]});
var reply = ping.Send(ipAddress, 200);
if (reply == null || reply.Status == IPStatus.TimedOut) continue;
var mac = await Arp.LookupAsync(ipAddress);
if (macAddress == mac.ToString()) return ipAddress.ToString();
}
return string.Empty;
}
You need to replace the values in start and end with your IP range and then you can call the code like this.
var ip = GetIPFromMAC("aabbccddeeff").Result;

Related

How to write data to USB HID device in Android with only a single input endpoint

I have a USB HID device that I would like to communicate with. I am successfully doing so on Windows using the HidSharp library (link: https://github.com/treehopper-electronics/HIDSharp). My Windows application is developed using the .NET Framework 4.5, C#, and Visual Studio.
I now want to communicate with this same USB HID device from an Android tablet instead of from the Windows desktop. I am encountering some problems doing so. When I have the device plugged in to my tablet, it reports a single interface with a single "read" endpoint. Here is what is reported to me:
Interface #0
Class: Human Interaction Device (0x3)
Endpoint: #0
Address : 0x81 (10000001)
Number : 1
Direction : Inbound (0x80)
Type : Intrrupt (0x3)
Poll Interval : 1
Max Packet Size: 64
Attributes : 000000011
As you can see, it only reports a single endpoint, which is an inbound endpoint. I need to be able to output simple commands to this device, which I was able to do so successfully on Windows using HidSharp.
HidSharp abstracted everything into a single "stream" object that you could read from and write to. Using the Android APIs, there isn't a single "stream" object, but rather there seem to be 3 different ways of reading/writing: bulk transfer, control transfer, and USB Request. I've tried sending out data using all 3, but with seemingly no success.
Any suggestions on what to do? Is there a reason why I could send out data to this device on Windows, but seemingly cannot do so from Android? Is there a way to use a single endpoint as both a read and a write endpoint? Is there something that I am just obviously missing and not understanding?
I am using Xamarin as my development environment (C#, Visual Studio 2017). Since code is always helpful, here is how I am connecting to the device:
int VendorID = 0x04d8;
int ProductID = 0x2742;
UsbManager USB_Manager = null;
UsbDevice USB_Device = null;
UsbDeviceConnection DeviceConnection = null;
UsbInterface DeviceInterface = null;
UsbEndpoint OutputEndpoint = null;
UsbEndpoint InputEndpoint = null;
//Grab the Android USB manager and get a list of connected devices
var USB_Manager = MyMainActivity.ApplicationContext.GetSystemService(Android.Content.Context.UsbService) as Android.Hardware.Usb.UsbManager;
var attached_devices = USB_Manager.DeviceList;
//Find the device in the list of connected devices
foreach (var d in attached_devices.Keys)
{
if (attached_devices[d].VendorId == VendorID && attached_devices[d].ProductId == ProductID)
{
USB_Device = attached_devices[d];
break;
}
}
//Assuming we found the correct device, let's set everything up
if (USB_Device != null)
{
for (int j = 0; j < USB_Device.InterfaceCount; j++)
{
DeviceInterface = USB_Device.GetInterface(j);
for (int i = 0; i < DeviceInterface.EndpointCount; i++)
{
var temp_ep = DeviceInterface.GetEndpoint(i);
if (temp_ep.Type == Android.Hardware.Usb.UsbAddressing.XferInterrupt)
{
if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.In)
{
InputEndpoint = temp_ep;
}
if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.Out)
{
OutputEndpoint = temp_ep;
}
}
}
}
//Request permission to communicate with this USB device
UsbReceiver receiver = new UsbReceiver();
PendingIntent pending_intent = PendingIntent.GetBroadcast(Game.Activity, 0, new Android.Content.Intent(UsbReceiver.ACTION_USB_PERMISSION), 0);
IntentFilter intent_filter = new IntentFilter(UsbReceiver.ACTION_USB_PERMISSION);
Game.Activity.RegisterReceiver(receiver, intent_filter);
USB_Manager.RequestPermission(USB_Device, pending_intent);
bool has_permission = USB_Manager.HasPermission(USB_Device);
var device_connection = USB_Manager.OpenDevice(USB_Device);
device_connection.ClaimInterface(DeviceInterface, true);
DeviceConnection = device_connection;
}
Next, here is how I attempt to read from the device:
//3 methods of attempting to read from the device
//Method 1:
byte[] inpt = new byte[64];
var request = new UsbRequest();
request.Initialize(DeviceConnection, InputEndpoint);
var byte_buffer = ByteBuffer.Allocate(64);
request.Queue(byte_buffer, 64);
DeviceConnection.RequestWait();
byte_buffer.Rewind();
for(int i = 0; i < 64; i++)
{
inpt[i] = (byte) byte_buffer.Get();
}
//Method 2:
byte[] inpt = new byte[64];
DeviceConnection.BulkTransfer(InputEndpoint, inpt, inpt.Length, 1000);
//Method 3:
byte[] inpt = new byte[64];
DeviceConnection.ControlTransfer(UsbAddressing.In, 0, 0, 0, inpt, 64, 1000);
And finally, here is how I attempt to write data to this device:
//Method 1:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.BulkTransfer(OutputEndpoint, output_msg, output_msg.Length, 30);
//Method 2:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.ControlTransfer(UsbAddressing.Out, 0, 0, 0, output_msg, output_msg.Length, 1000);
//Method 3:
byte[] output_msg; //This variable is assigned elsewhere in the code
var write_request = new UsbRequest();
write_request.Initialize(DeviceConnection, OutputEndpoint);
var byte_buffer_write = ByteBuffer.Wrap(output_msg);
request.Queue(byte_buffer_write, output_msg.Length);
DeviceConnection.RequestWait();
"OutputEndpoint" is typically null because there is no output endpoint, so I often replace "OutputEndpoint" with "InputEndpoint", but with no success.
Any help would be greatly appreciated! Thanks!!!
You are dealing with HID devices which means you should do Interrupt Transfers.
In Android, you should use UsbRequest to perform Interrupt Transfers (as it does Asynchronous NonBlocking IO).
The endpoints are unidirectional and can be used for both inbounds and outbound (but not at the same time)
If the endpoint is inbound then submit the Urb using UsbRequest and queue as you tried before but using empty buffer with expected bufferLength.
The RequestWait will return UsbRequest Object back upon completion.
If the usbRequest.getEndPoint().getDirection() is inbound then your buffer variable will be updated with read buffer from the device.
If the usbRequest.getEndpoint().getDirection() is outbound then you should pass your buffer to write data to the device

C++ raw socket sniffer cannot capture incoming TCP packets on Windows 10

Core part of code is as below.
Actually, the code is copied from https://github.com/ECToo/world-opponent-network/blob/fbb35876ae26006606d07b6297d557bd53234066/%20world-opponent-network/TitanApi/Samples/ServerTest%20-%20Copy/Sniffer/main.cpp
The code can capture UDP both incoming/outgoing packets and TCP outgoing packets, but cannot capture any TCP incoming packets on Windows10.
however, it works quite well on Windows XP.
sniffer = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
if (sniffer == INVALID_SOCKET) {
printf("Failed to create raw socket.\n");
return 1;
}
memset(&dest, 0, sizeof(dest));
memcpy(&dest.sin_addr.s_addr, local->h_addr_list[in], sizeof(dest.sin_addr.s_addr));
dest.sin_family = AF_INET;
dest.sin_port = 0;
printf("\nBinding socket to local system and port 0 ...");
if (bind(sniffer, (struct sockaddr *)&dest, sizeof(dest)) == SOCKET_ERROR) {
printf("bind(%s) failed.\n", inet_ntoa(addr));
return 1;
}
printf("Binding successful");
//Enable this socket with the power to sniff : SIO_RCVALL is the key Receive ALL ;)
j = 1;
printf("\nSetting socket to sniff...");
if (WSAIoctl(sniffer, SIO_RCVALL, &j, sizeof(j), 0, 0, (LPDWORD)&in, 0, 0) == SOCKET_ERROR) {
printf("WSAIoctl() failed.\n");
perror("Error:");
return 1;
}
printf("Socket set.");
//Begin
printf("\nStarted Sniffing\n");
printf("Packet Capture Statistics...\n");
StartSniffing(sniffer); //Happy Sniffing
//End
closesocket(sniffer);
WSACleanup();
Then, I tried https://www.netresec.com/?page=RawCap which is written in C#, same result as C++ code.
At last, I tried raw socket in python, it works quite well on Win10.
import socket
from struct import *
host = '10.0.0.18'
# create a raw socket and bind it to the public interface
socket_protocol = socket.IPPROTO_IP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
# we want the IP headers included in the capture
#sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
while True:
packet = sniffer.recvfrom(65565)
#packet string from tuple
packet = packet[0]
#take first 20 characters for the ip header
ip_header = packet[0:20]
#now unpack them :)
iph = unpack('!BBHHHBBH4s4s' , ip_header)
version_ihl = iph[0]
version = version_ihl >> 4
ihl = version_ihl & 0xF
iph_length = ihl * 4
total_len = iph[2]
ttl = iph[5]
protocol = iph[6]
s_addr = socket.inet_ntoa(iph[8]);
d_addr = socket.inet_ntoa(iph[9]);
if protocol == 6:
print 'Length : ' + str(total_len) + ' Source Address : ' + str(s_addr) + ' Destination Address : ' + str(d_addr)
Quite strange, is there any mistake I made for the C++ code?

how to achieve AddressFamily in winRT

I am searching something replacement of System.Net.Sockets.AddressFamily.InterNetwork. I found HostName but unable to find something that can do like AdressFamily does. Actually, I am converting following code in winRT. I know winRT supports Windows.Networking.Sockets etc. Please describe some solution.
The code is,
if (System.Net.Sockets.AddressFamily.InterNetwork == _address.AddressFamily && _address.AddressFamily == address.AddressFamily)
{
long longLocal = BitConverter.ToInt32(_address.GetAddressBytes(), 0);
long longNetMask = BitConverter.ToInt32(_netmask.GetAddressBytes(), 0);
long longRemote = BitConverter.ToInt32(address.GetAddressBytes(), 0);
}
_address is also IPAdress
Well AddressFamily does not directly supports WinRT/Metro project so what you need to do is check the ipAddress information like this
using Windows.Networking;
using Windows.Networking.Sockets;
HostName serverHost = new HostName("www.contoso.com");
StreamSocket clientSocket = new Windows.Networking.Sockets.StreamSocket();
// Try to connect to the remote host
await clientSocket.ConnectAsync(serverHost, "http");
var ipAddress = clientSocket.Information.RemoteAddress.DisplayName
To check your condition use _address.Type == HostNameType.Ipv4 then do something but make sure that GetAddressBytes do not exist in HostName class so for that you need to write your own function to convert an ipAddress into bytes.

Unable to read from Serial Port using C# Mono (RaspberryPi)

I'm attempting to write a C# library which looks at all available USB serial ports on a Raspberry Pi so that I can enumerate, identify and communicate with a set of Arduinos connected to the Pi via a USB hub.
I am able to make this work on my windows machine (several Arduinos connected to my desktop computer) and have even been able to make it work on my Pi however, I am struggling to understand how to generalize the fix.
If I attempt to run the program by itself on the Pi, I am able to open the serial port and send data however, I cannot receive anything from the Arduinos: I get timeout exceptions. I understand that Mono's implementation of SerialPort is limited and I must use SerialPort.ReadByte() instead of Readline() and the data received events (my solution is based on code from HowToSystemIOPorts). My Serial port enumeration is using a method outlined in another stack exchange response here.
My timeout is currently set to 4 seconds, which is several orders of magnitude longer than I expect to receive the message.
After a lot of googling, I came across mention of using minicom to initialize the serial port here, which to my surprise allowed me to receive data from the Arduino. The biggest drawback is that I need to initialize the port using minicom and leave the process opening each time I boot the Pi. I also can't seem to figure out how to make this work with multiple Arduinos.
Here is what I have tried so far:
Updated the Pi firmware and software to their latest versions
Attempted to use both an Arduino MEGA 2560 R3 and Arduino UNO
Changed the owner of the tty* ports (ttyACM0 and ttyUSB0 in this case) to both my user and group
Successfully configured the port via minicom, left the process running and start the program and read/wrote data. A manual process which only seems to work for one Arduino at a time
Successfully run the program in Windows without fault
Verified the Arduinos are recognized by the Pi running "dmesg | grep tty"
Here is what I hope to solve:
Automatic setup/initialization of the Arduino serial ports. Whether through a shell script run before the main program or within Mono code so that the code below can run as intended.
Here is my connection code:
public bool StartArduinoComms()
{
string[] ports = GetPortNames();
foreach (string port in ports)
{
mLogger.LogMessage(ProsthesisCore.Utility.Logger.LoggerChannels.Arduino, string.Format("Found serial port {0}", port));
}
bool foundCorrectArduino = false;
var idPacket = new ArduinoMessageBase();
idPacket.ID = ArduinoMessageValues.kIdentifyValue;
string jsonOutput = Newtonsoft.Json.JsonConvert.SerializeObject(idPacket);
foreach (string port in ports)
{
SerialPort serialPort = new SerialPort(port, kArduinoCommsBaudRate);
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
//Only check unopened ports
if (!serialPort.IsOpen)
{
serialPort.Open();
//Disable telemtry just incase
var toggle = new { ID = ArduinoMessageValues.kTelemetryEnableValue, EN = false };
string disableTelem = Newtonsoft.Json.JsonConvert.SerializeObject(toggle);
serialPort.Write(disableTelem);
//Discard any built up data
serialPort.DiscardInBuffer();
serialPort.Write(jsonOutput);
serialPort.ReadTimeout = kIDTimeoutMilliseconds;
string response = string.Empty;
for (int i = 0; i < kNumRetries; ++i)
{
try
{
//This is guaranteed to timeout if not configured through minicom
response = ReadLine(serialPort);
break;
}
//Catch case where the serial port is unavailable. MOve to next port
catch (TimeoutException)
{
continue;
}
}
if (!string.IsNullOrEmpty(response))
{
//Perform response validation
}
else
{
//Got no response
}
if (!foundCorrectArduino)
{
serialPort.Close();
}
}
}
return foundCorrectArduino;
}
/// <summary>
/// From https://stackoverflow.com/questions/434494/serial-port-rs232-in-mono-for-multiple-platforms
/// </summary>
/// <returns></returns>
private static string[] GetPortNames()
{
int p = (int)Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (p == 4 || p == 128 || p == 6)
{
string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
foreach (string dev in ttys)
{
//Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
{
serial_ports.Add(dev);
}
}
}
else
{
serial_ports.AddRange(SerialPort.GetPortNames());
}
return serial_ports.ToArray();
}
Have a look at stty command. It will let you set/read teminal settings
http://linux.about.com/od/lna_guide/a/gdelna38t01.htm will give a rundown on it's use.
It would be easier to call out to than minicom, and the settings stay on the device.
I have done something like the same as you before.
I had to read and write data through USB Serial adapter, and didnt use minicom.
It may not be god code but i found that inorder to read the data I could create a new thread and have that check for data, my code include a lot of stuff but basicly i did this:
System.Threading.Thread newThread;
newThread = new System.Threading.Thread(this.check_get_data);
and the check_get_data method
public void check_get_data ()
{
byte tmpByte = 0;
while (m_objSerialPort.BytesToRead != 0) {
tmpByte = (byte)m_objSerialPort.ReadByte ();
DoSomethingWithByte(tmpByte);
Thread.Sleep(20);
}
}
this is currently running with two usbserials. dont know if it helps but hope you find your solution

Wake on LAN using C#

What's the best way going forward to implement Wake on LAN using C#?
The functionality is needed for machines in a LAN environment (and not over the internet). The method needs to be robust enough to take care of firewalls and other such issues. Also, for systems not supporting this functionality, or having it disabled, is there an alternative?
The primary objective - wake up machines (from shutdown/hibernate state) over the LAN - this is to be programmed using C#.
Please guide.
PS: I've come across the following:
http://blog.memos.cz/index.php/team/2008/06/12/wake-on-lan-in-csharp
http://community.bartdesmet.net/blogs/bart/archive/2006/04/02/3858.aspx
http://www.codeproject.com/KB/IP/cswol.aspx
However, I'm new to this and hence couldn't figure if the solutions were comprehensive enough. If someone could recommend following either of the above articles, that'd help.
Very old question, I know, but still valid. Since I didn't see any C# in the accepted answer, I wrote my own 'Wake On Lan' code.
My goal was to make a universal and easy Wake On Lan class that:
works with ipv4, ipv6 and dual-stack.
works with one or multiple network cards (NICS) connected to different networks (both computers).
works with macaddress in any standard hex format.
works using multicast (broadcast is buggy in Windows when using multiple NICs and is not supported when using ipv6).
How to use:
All you need, is the MAC address of the wired nic on the computer you wish to wake up. Any standard hex representation will do. Then call the code like this:
string mac = "01-02-03-04-05-06";
await WOL.WakeOnLan(mac);
Here's the class:
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
public static class WOL
{
public static async Task WakeOnLan(string macAddress)
{
byte[] magicPacket = BuildMagicPacket(macAddress);
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where((n) =>
n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up))
{
IPInterfaceProperties iPInterfaceProperties = networkInterface.GetIPProperties();
foreach (MulticastIPAddressInformation multicastIPAddressInformation in iPInterfaceProperties.MulticastAddresses)
{
IPAddress multicastIpAddress = multicastIPAddressInformation.Address;
if (multicastIpAddress.ToString().StartsWith("ff02::1%", StringComparison.OrdinalIgnoreCase)) // Ipv6: All hosts on LAN (with zone index)
{
UnicastIPAddressInformation unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
u.Address.AddressFamily == AddressFamily.InterNetworkV6 && !u.Address.IsIPv6LinkLocal).FirstOrDefault();
if (unicastIPAddressInformation != null)
{
await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
break;
}
}
else if (multicastIpAddress.ToString().Equals("224.0.0.1")) // Ipv4: All hosts on LAN
{
UnicastIPAddressInformation unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
u.Address.AddressFamily == AddressFamily.InterNetwork && !iPInterfaceProperties.GetIPv4Properties().IsAutomaticPrivateAddressingActive).FirstOrDefault();
if (unicastIPAddressInformation != null)
{
await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
break;
}
}
}
}
}
static byte[] BuildMagicPacket(string macAddress) // MacAddress in any standard HEX format
{
macAddress = Regex.Replace(macAddress, "[: -]", "");
byte[] macBytes = new byte[6];
for (int i = 0; i < 6; i++)
{
macBytes[i] = Convert.ToByte(macAddress.Substring(i * 2, 2), 16);
}
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
for (int i = 0; i < 6; i++) //First 6 times 0xff
{
bw.Write((byte)0xff);
}
for (int i = 0; i < 16; i++) // then 16 times MacAddress
{
bw.Write(macBytes);
}
}
return ms.ToArray(); // 102 bytes magic packet
}
}
static async Task SendWakeOnLan(IPAddress localIpAddress, IPAddress multicastIpAddress, byte[] magicPacket)
{
using (UdpClient client = new UdpClient(new IPEndPoint(localIpAddress, 0)))
{
await client.SendAsync(magicPacket, magicPacket.Length, multicastIpAddress.ToString(), 9);
}
}
}
How it works:
The code works by enumerating all network cards that are 'up' and connected to your network (that's usually just one). It will send out the 'magic packet' to all your connected networks using multicast, which works with both ipv4 and ipv6 (don't worry about flooding your network, it's only 102 bytes).
To work, the computer, you want to wake up, must have a wired connection (wireless computers can't be woken up, since they aren't connected to any network, when they are off). The computer, that sends the packet, can be wireless connected.
Firewalls are usually no problem, since the computer is off and hence the firewall is not active.
You must make sure that 'Wake on lan' is enabled in the computer's BIOS and on the network card.
Update for .Net 6 (and a bug fix):
Fixed a bug, where if Ipv6 was functioning on the computer that sends the packet but not on the one, that should be awakened, then it would not try Ipv4 (this is fixed in the code above).
Here's the code that works on .Net 6 (borrowed some of #Oskar Sjôberg's code) - implicit usings turned on:
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
public static class WOL
{
public static async Task WakeOnLan(string macAddress)
{
byte[] magicPacket = BuildMagicPacket(macAddress);
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where((n) =>
n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up))
{
IPInterfaceProperties iPInterfaceProperties = networkInterface.GetIPProperties();
foreach (MulticastIPAddressInformation multicastIPAddressInformation in iPInterfaceProperties.MulticastAddresses)
{
IPAddress multicastIpAddress = multicastIPAddressInformation.Address;
if (multicastIpAddress.ToString().StartsWith("ff02::1%", StringComparison.OrdinalIgnoreCase)) // Ipv6: All hosts on LAN (with zone index)
{
UnicastIPAddressInformation? unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
u.Address.AddressFamily == AddressFamily.InterNetworkV6 && !u.Address.IsIPv6LinkLocal).FirstOrDefault();
if (unicastIPAddressInformation != null)
{
await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
}
}
else if (multicastIpAddress.ToString().Equals("224.0.0.1")) // Ipv4: All hosts on LAN
{
UnicastIPAddressInformation? unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
u.Address.AddressFamily == AddressFamily.InterNetwork && !iPInterfaceProperties.GetIPv4Properties().IsAutomaticPrivateAddressingActive).FirstOrDefault();
if (unicastIPAddressInformation != null)
{
await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
}
}
}
}
}
static byte[] BuildMagicPacket(string macAddress) // MacAddress in any standard HEX format
{
macAddress = Regex.Replace(macAddress, "[: -]", "");
byte[] macBytes = Convert.FromHexString(macAddress);
IEnumerable<byte> header = Enumerable.Repeat((byte)0xff, 6); //First 6 times 0xff
IEnumerable<byte> data = Enumerable.Repeat(macBytes, 16).SelectMany(m => m); // then 16 times MacAddress
return header.Concat(data).ToArray();
}
static async Task SendWakeOnLan(IPAddress localIpAddress, IPAddress multicastIpAddress, byte[] magicPacket)
{
using UdpClient client = new(new IPEndPoint(localIpAddress, 0));
await client.SendAsync(magicPacket, magicPacket.Length, new IPEndPoint(multicastIpAddress, 9));
}
}
For the WOL problem you have to clarify three problems to get it to work:
Send a WOL over the ethernet cable
Configure your PC to listen for such
a packet and wake up
Make sure the packet will come from
sender to receiver (firewall,
gateways, etc.)
As you already found on the net there are existing several solutions for the first problem programmed in C# (and after skimming your links, I would start with the first one).
The second one is something you can only achieve by configuring your network adapter. Just open the device manager and take a look into the properties of your network adapter, if such an option exists and if you can enable it. This can't be programmed, due to the fact that every network adapter has another implementation of that function and how it can be enabled.
The third problem can't also be solved by C#. It is a pure network problem, where you have to configure your router, gateways, ids-systems, etc. to allow such a packet and let it flow from sender to receiver. Due to the fact, that a WOL packet is always a broadcast packet (dest-ip 255.255.255.255) it won't leave your local network and will always be dropped from router, gateways or any other bridge between to networks (e.g. vpns, etc.).
Last but not least, I will just remind you, that the first problem can be divided into some smaller packets but as far as I could see these problems are all capped by the links you provided.
I was trying Poul Bak´s answer but was unable to wake my target computer. After verifying that a third party application, WakeMeOnLan in fact was able to wake my target computer, I wrote this code that worked for me:
void SendWakeOnLan(PhysicalAddress target)
{
var header = Enumerable.Repeat(byte.MaxValue, 6);
var data = Enumerable.Repeat(target.GetAddressBytes(), 16).SelectMany(mac => mac);
var magicPacket = header.Concat(data).ToArray();
using var client = new UdpClient();
client.Send(magicPacket, magicPacket.Length, new IPEndPoint(IPAddress.Broadcast, 9));
}
Usage:
Simply by passing in the target computers mac address like so:
SendWakeOnLan(PhysicalAddress.Parse("0A-0B-0C-0D-0E-0F"));
I think the main difference between this answer and Poul Bak´s answer is that this code is using broadcast over IPv4 instead of multicast on IPv4/IPv6, and maybe my network equipment is not handling/setup to do multicast correctly.

Categories

Resources