简体   繁体   中英

How to get mac-address from a remote computer, same network, at linux, using .Net Core

I already have tools that can identify the Mac-Address of the devices in my network, as long as the 'server' or the application is running in Windows and .NET Framework.
I'm using:

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace Tools
{
    /// <summary>
    /// Ferramentas para rede local
    /// </summary>
    public static class NET
    {
        private static string _erro;
        public static string ErrorMessage { get { return _erro; } }
        [DllImport("iphlpapi.dll", ExactSpelling = true)]
        public static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);
        /// <summary>
        /// Recupera o MAC Address de um equipamento na rede local baseado em seu IP
        /// </summary>
        /// <param name="ip">IP em formato string (Ex: 192.168.0.10)</param>
        /// <returns>String com o MAC Address no formato XX-XX-XX-XX-XX</returns>
        public static string TryGetMacAddress(string ip)
        {
            try
            {
                IPAddress IP = IPAddress.Parse(ip);
                byte[] macAddr = new byte[6];
                uint macAddrLen = (uint)macAddr.Length;
                if (SendARP((int)IP.Address, 0, macAddr, ref macAddrLen) != 0)
                {
                    _erro = "Não foi possível executar comando ARP";
                    return String.Empty;
                }
                string[] str = new string[(int)macAddrLen];
                for (int i = 0; i < macAddrLen; i++)
                    str[i] = macAddr[i].ToString("x2");
                return string.Join("-", str);
            }
            catch (Exception e)
            {
                _erro = e.Message;
            }
            return String.Empty;
        }
        /// <summary>
        /// Dado um ip que pertença ao equipamento, o MAC Address será dado 
        /// </summary>
        /// <param name="ip">IP que pertença ao equipamento</param>
        /// <returns>string com os bytes separados por hífen</returns>
        public static string GetMyMacAddress(string ip)
        {
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface adapter in nics)
            {
                foreach (UnicastIPAddressInformation unip in adapter.GetIPProperties().UnicastAddresses)
                {
                    if (unip.Address.AddressFamily == AddressFamily.InterNetwork)
                    {
                        if (unip.Address.ToString() == ip)
                        {
                            PhysicalAddress address = adapter.GetPhysicalAddress();
                            return BitConverter.ToString(address.GetAddressBytes());
                        }
                    }
                }
            }
            return null;
        }
    }
}

The way to get Mac-Address from the machine itself is to use the NetworkInterface .NET class (in use at GetMyMacAddress(string ip) method). To try to get Mac-Address from another device on the local network is to use the arp command.
To call it in Windows I have to import a system dll: [DllImport ("iphlpapi.dll", ExactSpelling = true)]
It references: public static external int SendARP(int DestIP, int SrcIP, byte [] pMacAddr, ref uint PhyAddrLen);
And to use it here: SendARP ((int) IP.Address, 0, macAddr, ref macAddrLen)

As I'm porting the .NET Core application to run on a Raspberry PI 3 on Linux, I want to know how to do the same process on Linux (is this the correct way to do it on that system?).

The NetworkInterface class also exists in the .NET Core, under the System.Net.NetworkInformation namespace.

But how do I get Mac-Address from an IP of another machine (on Linux with .NET Core)?

Based on https://pt.stackoverflow.com/a/250164/48585 , I wrote this helpers:

using System.Diagnostics;    
///FOR LINUX
        public static string Bash(string cmd)
        {
            var escapedArgs = cmd.Replace("\"", "\\\"");

            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/bash",
                    Arguments = $"-c \"{escapedArgs}\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                }
            };
            process.Start();
            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return result;
        }
    ///FOR WINDOWS
    public static string CMD(string cmd)
        {
            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "cmd.exe",
                    Arguments = $@"/c {cmd}",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                }
            };
            process.Start();
            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return result;
        }

Ping class to make a test before ask mac-address

private static StringBuilder _erro = new StringBuilder();
public static string ErrorMessage { get { return _erro.ToString(); } }
public static bool Ping(string ipOrName, int timeout = 0, bool throwExceptionOnError = false)
        {
            bool p = false;
            try
            {
                using (Ping ping = new Ping()) //using System.Net.NetworkInformation; (.NET Core namespace)
                {
                    PingReply reply = null;
                    if (timeout > 0)
                        reply = ping.Send(ipOrName, timeout);
                    else
                        reply = ping.Send(ipOrName);
                    if (reply != null)
                        p = (reply.Status == IPStatus.Success);
                    //p = Convert.ToInt32(reply.RoundtripTime);
                }
            }
            catch (PingException e)
            {
                _erro.Append(e.Message);
                _erro.Append(Environment.NewLine);
                if (throwExceptionOnError) throw e;
            }
            catch (Exception ex)
            {
                _erro.Append(ex.Message);
                _erro.Append(Environment.NewLine);
            }
            return p;
        }

Then, I use this tools:

    public static string TryGetMacAddressOnLinux(string ip)
    {
        _erro.Clear(); 
        if (!Ping(ip))
            _erro.Append("Não foi possível testar a conectividade (ping) com o ip informado.\n");
        string arp = $"arp -a {ip}";
        string retorno = Bash(arp);
        StringBuilder sb = new StringBuilder();
        string pattern = @"(([a-f0-9]{2}:?){6})";
        int i = 0;
        foreach (Match m in Regex.Matches(retorno, pattern, RegexOptions.IgnoreCase))
        {
            if (i > 0)
                sb.Append(";");
            sb.Append(m.ToString());
            i++;
        }
        return sb.ToString();
    }

For Windows, just change Regex pattern to (([a-f0-9]{2}-?){6}) and change string retorno = Bash(arp); to string retorno = CMD(arp); or use the method mentioned in question. I'm using it like that on Raspberry Pi3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM