If you ping the IP addresss, then the MAC address for that IP will be
stored in an ARP table on your machine. You can see this by typing
"ARP -a" at a command prompt. You can access this table through an API
call to GetIPNetTable() in the IpHlpApi.dll. I'm not sure if the
IP-MAC address will be on your server if someone hits your web
application, but if it's not you can just ping the IP address since you
do have that information and then the MAC should be in the ARP table on
your machine. Here is the C# code needed to pull the MAC out of the
table by IP address.
//Setup
#region GetIpNetTable interop
// The max number of physical addresses.
const int MAXLEN_PHYSADDR = 8;
// Define the MIB_IPNETROW structure.
[StructLayout(LayoutKind.Sequential)]
struct MIB_IPNETROW
{
[MarshalAs(UnmanagedType.U4)]
public int dwIndex;
[MarshalAs(UnmanagedType.U4)]
public int dwPhysAddrLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXLEN_PHYSADDR)]
public byte[] bPhysAddr;
[MarshalAs(UnmanagedType.U4)]
public int dwAddr;
[MarshalAs(UnmanagedType.U4)]
public int dwType;
}
// Declare the GetIpNetTable function.
[DllImport("IpHlpApi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern int GetIpNetTable(
IntPtr pIpNetTable,
[MarshalAs(UnmanagedType.U4)]
ref int pdwSize,
bool bOrder);
// The insufficient buffer error.
const int ERROR_INSUFFICIENT_BUFFER = 122;
#endregion
/// <summary>
/// Pulls the MAC address for a given IP address out of the ARP table
on the machine executing this code.
/// </summary>
/// <param name="ip">IP address to lookup</param>
/// <returns>The MAC address for the given IP address or null if the
MAC is not found.</returns>
public string ResolveMAC(string ip)
{
// The number of bytes needed.
int bytesNeeded = 0;
// The result from the API call.
int result = GetIpNetTable(IntPtr.Zero, ref bytesNeeded, false);
// Call the function, expecting an insufficient buffer.
if (result != ERROR_INSUFFICIENT_BUFFER)
{
// Throw an exception.
throw new Win32Exception(result);
}
// Allocate the memory, do it in a try/finally block, to ensure
// that it is released.
IntPtr buffer = IntPtr.Zero;
try
{
// Allocate the memory.
buffer = Marshal.AllocCoTaskMem(bytesNeeded);
// Make the call again. If it did not succeed, then
// raise an error.
result = GetIpNetTable(buffer, ref bytesNeeded, false);
// If the result is not 0 (no error), then throw an exception.
if (result != 0)
{
// Throw an exception.
throw new Win32Exception(result);
}
// Now we have the buffer, we have to marshal it. We can read
// the first 4 bytes to get the length of the buffer.
int entries = Marshal.ReadInt32(buffer);
// Increment the memory pointer by the size of the int.
IntPtr currentBuffer = new IntPtr(buffer.ToInt64() +
Marshal.SizeOf(new int()));
// Allocate an array of entries.
MIB_IPNETROW[] table = new MIB_IPNETROW[entries];
// Cycle through the entries.
for (int index = 0; index < entries; index++)
{
// Call PtrToStructure, getting the structure information.
table[index] = (MIB_IPNETROW) Marshal.PtrToStructure(new
IntPtr(currentBuffer.ToInt64() + (index *
Marshal.SizeOf(typeof(MIB_IPNETROW)))), typeof(MIB_IPNETROW));
}
byte[] macBytes = null;
for (int i = 0; i < entries; i++)
{
string tableIP = String.Format("{0}.{1}.{2}.{3}",
table.dwAddr & 0x000000ff,
(table.dwAddr & 0x0000ff00) >> 8,
(table.dwAddr & 0x00ff0000) >> 16,
(table.dwAddr & 0xff000000) >> 24);
if(tableIP == ip)
{
macBytes = table.bPhysAddr;
break;
}
}
string mac = "";
for(int i = 0; i < 6; i++)
{
string hexTet = macBytes.ToString("X", new NumberFormatInfo());
if(hexTet.Length == 1)
{
hexTet = "0" + hexTet;
}
mac += hexTet;
if(i < 5)
{
mac += ":";
}
}
return mac;
}
catch
{
return null;
}
finally
{
// Release the memory.
Marshal.FreeCoTaskMem(buffer);
}
}