16

I am trying write a function that takes a single IP address as a parameter and queries that machine on my local network for it's MAC address.

I have seen many examples that get the local machine's own MAC address, however none (I've found) that seem to query a local network machine for it.

I know such a task is achievable as this Wake on LAN scanner software scans the local IP range and returns MAC address/Hostname of all on machines.

Can anyone tell me where I'd get started trying to write a function to achieve this in C#? Any help would be appreciated. Thanks

EDIT:

As per Marco Mp's comment below, have used ARP tables. arp class

Gga
  • 4,311
  • 14
  • 39
  • 74
  • Not sure if it works, but with a quick google search I found this library which should do the trick: [http://www.tamirgal.com/blog/post/ARP-Resolver-C-Class.aspx](http://www.tamirgal.com/blog/post/ARP-Resolver-C-Class.aspx) – Marco Mp Oct 09 '12 at 15:00
  • Thank you, I believe I've read ARP tables to be inconsistent and was wondering if there was a way to 'ping' for the MAC address. – Gga Oct 09 '12 at 15:04
  • 2
    I **think** that if you do a regular ping (or otherwise try to contact) the IP address it will cause ARP tables to refresh (otherwise the network stack would not be able to contact the machine in the first place); of course this will (if at all) work only if the desired machine is online. I don't think you can get reliable results for offline IP addresses, specially if you have dynamically assigned IPs. I'm not a network expert though, so I might be wrong (trying to think with you on the problem). – Marco Mp Oct 09 '12 at 15:09
  • Thanks, ARP tables were the way to go. Had a bit of difficulty with the example in first comment so have posted alternative. Cheers – Gga Oct 09 '12 at 15:28
  • Try this nice and clean solution: http://stackoverflow.com/a/37155004/6229375 – Dominic Jonas May 11 '16 at 06:50
  • Possible duplicate of [How do I obtain the physical (MAC) address of an IP address using C#?](https://stackoverflow.com/questions/187894/how-do-i-obtain-the-physical-mac-address-of-an-ip-address-using-c) – Wai Ha Lee Nov 13 '18 at 08:30

5 Answers5

23
public string GetMacAddress(string ipAddress)
{
    string macAddress = string.Empty;
    System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
    pProcess.StartInfo.FileName = "arp";
    pProcess.StartInfo.Arguments = "-a " + ipAddress;
    pProcess.StartInfo.UseShellExecute = false;
    pProcess.StartInfo.RedirectStandardOutput = true;
      pProcess.StartInfo.CreateNoWindow = true;
    pProcess.Start();
    string strOutput = pProcess.StandardOutput.ReadToEnd();
    string[] substrings = strOutput.Split('-');
    if (substrings.Length >= 8)
    {
       macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2)) 
                + "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6] 
                + "-" + substrings[7] + "-" 
                + substrings[8].Substring(0, 2);
        return macAddress;
    }

    else
    {
        return "not found";
    }
}

Very late edit: In open souce project iSpy (https://github.com/ispysoftware/iSpy) they use this code, which is a little nicer

  public static void RefreshARP()
        {
            _arpList = new Dictionary<string, string>();
            _arpList.Clear();
            try
            {
                var arpStream = ExecuteCommandLine("arp", "-a");
                // Consume first three lines
                for (int i = 0; i < 3; i++)
                {
                    arpStream.ReadLine();
                }
                // Read entries
                while (!arpStream.EndOfStream)
                {
                    var line = arpStream.ReadLine();
                    if (line != null)
                    {
                        line = line.Trim();
                        while (line.Contains("  "))
                        {
                            line = line.Replace("  ", " ");
                        }
                        var parts = line.Trim().Split(' ');

                        if (parts.Length == 3)
                        {
                            string ip = parts[0];
                            string mac = parts[1];
                            if (!_arpList.ContainsKey(ip))
                                _arpList.Add(ip, mac);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogExceptionToFile(ex, "ARP Table");
            }
            if (_arpList.Count > 0)
            {
                foreach (var nd in List)
                {
                    string mac;
                    ARPList.TryGetValue(nd.IPAddress.ToString(), out mac);
                    nd.MAC = mac;    
                }
            }
        }

https://github.com/ispysoftware/iSpy/blob/master/Server/NetworkDeviceList.cs

Update 2 even more late, but I think is best because it uses regex that checks better for exact matches.

public string getMacByIp(string ip)
{
    var macIpPairs = GetAllMacAddressesAndIppairs();
    int index = macIpPairs.FindIndex(x => x.IpAddress == ip);
    if (index >= 0)
    {
        return macIpPairs[index].MacAddress.ToUpper();
    }
    else
    {
        return null;
    }
}

public List<MacIpPair> GetAllMacAddressesAndIppairs()
{
    List<MacIpPair> mip = new List<MacIpPair>();
    System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
    pProcess.StartInfo.FileName = "arp";
    pProcess.StartInfo.Arguments = "-a ";
    pProcess.StartInfo.UseShellExecute = false;
    pProcess.StartInfo.RedirectStandardOutput = true;
    pProcess.StartInfo.CreateNoWindow = true;
    pProcess.Start();
    string cmdOutput = pProcess.StandardOutput.ReadToEnd();
    string pattern = @"(?<ip>([0-9]{1,3}\.?){4})\s*(?<mac>([a-f0-9]{2}-?){6})";

    foreach (Match m in Regex.Matches(cmdOutput, pattern, RegexOptions.IgnoreCase))
    {
        mip.Add(new MacIpPair()
        {
            MacAddress = m.Groups["mac"].Value,
            IpAddress = m.Groups["ip"].Value
        });
    }

    return mip;
}
public struct MacIpPair
{
    public string MacAddress;
    public string IpAddress;
}
online Thomas
  • 8,864
  • 6
  • 44
  • 85
10
using System.Net;
using System.Runtime.InteropServices;

[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(int DestIP, int SrcIP, [Out] byte[] pMacAddr, ref int PhyAddrLen);

try
{
    IPAddress hostIPAddress = IPAddress.Parse("XXX.XXX.XXX.XX");
    byte[] ab = new byte[6];
    int len = ab.Length, 
        r = SendARP((int)hostIPAddress.Address, 0, ab, ref len);
    Console.WriteLine(BitConverter.ToString(ab, 0, 6));
}
catch (Exception ex) { }

or with PC Name

try
      {
           Tempaddr = System.Net.Dns.GetHostEntry("DESKTOP-xxxxxx");
      }
      catch (Exception ex) { }
      byte[] ab = new byte[6];
      int len = ab.Length, r = SendARP((int)Tempaddr.AddressList[1].Address, 0, ab, ref len);
        Console.WriteLine(BitConverter.ToString(ab, 0, 6));
user8338498
  • 101
  • 1
  • 3
  • This is the best example for my current need. This does have one drawback in that it assumes IPv4 only. Also, in .Net Framework 4.7.2, IPAddress.Address is deprecated. Use this as a replacement: uint ipAddress = BitConverter.ToUInt32(hostIPAddress.GetAddressBytes(), 0); Again, this ASSUMES IPv4 and will not work with IPv6. – stricq Jan 19 '19 at 21:44
2

Just a better performing version of the accepted method.

    public string GetMacByIp( string ip )
    {
        var pairs = this.GetMacIpPairs();

        foreach( var pair in pairs )
        {
            if( pair.IpAddress == ip )
                return pair.MacAddress;
        }

        throw new Exception( $"Can't retrieve mac address from ip: {ip}" );
    }

    public IEnumerable<MacIpPair> GetMacIpPairs()
    {
        System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
        pProcess.StartInfo.FileName = "arp";
        pProcess.StartInfo.Arguments = "-a ";
        pProcess.StartInfo.UseShellExecute = false;
        pProcess.StartInfo.RedirectStandardOutput = true;
        pProcess.StartInfo.CreateNoWindow = true;
        pProcess.Start();

        string cmdOutput = pProcess.StandardOutput.ReadToEnd();
        string pattern = @"(?<ip>([0-9]{1,3}\.?){4})\s*(?<mac>([a-f0-9]{2}-?){6})";

        foreach( Match m in Regex.Matches( cmdOutput, pattern, RegexOptions.IgnoreCase ) )
        {
            yield return new MacIpPair()
            {
                MacAddress = m.Groups[ "mac" ].Value,
                IpAddress = m.Groups[ "ip" ].Value
            };
        }
    }

    public struct MacIpPair
    {
        public string MacAddress;
        public string IpAddress;
    }
Mauro Sampietro
  • 2,739
  • 1
  • 24
  • 50
0

With SharpPCap, It will work on Windows & Linux

public string getMacAdress(string ip){
        LibPcapLiveDeviceList devices = LibPcapLiveDeviceList.Instance;//list all your network cards
        ARP arp = new ARP(devices[0]);//select the first network card by default
        IPAddress ip = IPAddress.Parse(ip);
        PhysicalAddress macAdress = arp.Resolve(ip);
        return macAdress.ToString();
}
Chopchop
  • 2,899
  • 18
  • 36
-2

As per Marco Mp's comment above, have used ARP tables. arp class

Gga
  • 4,311
  • 14
  • 39
  • 74
  • 1.Your Question asks for "to get an IP and find MAC Address" and it demands ARP instead of RARP(get MAC and return IP/host which you are currently using).How you ended-up here? 2.The site you're referring is using wrong definiton of process(MAC to IP is RARP instead of ARP)... –  Khan Feb 25 '15 at 17:33