iphlpapi.dll の GetIpNetTable API を使用しARPリストを取得しIPアドレス、MACアドレス、タイプを表示するコンソールアプリケーションのC#サンプルコードを公開しました。
GetIpNetTable API を使用し取得したARPテーブル情報を表示するC#サンプルコードを以下に記します。
説明に関してはコメントを参照してください。
using System.Runtime.InteropServices;
namespace ARPList
{
internal class Program
{
// GetIpNetTable 関数 (iphlpapi.h): https://learn.microsoft.com/ja-jp/windows/win32/api/iphlpapi/nf-iphlpapi-getipnettable
[DllImport("iphlpapi.dll", EntryPoint = "GetIpNetTable")]
static extern int GetIpNetTable(IntPtr pIpNetTable, ref int pdwSize, bool bOrder);
[StructLayout(LayoutKind.Sequential)]
struct MIB_IPNETROW
{
[MarshalAs(UnmanagedType.U4)]
public uint dwIndex;
[MarshalAs(UnmanagedType.U4)]
public uint dwPhysAddrLen;
[MarshalAs(UnmanagedType.U1)]
public byte mac0;
[MarshalAs(UnmanagedType.U1)]
public byte mac1;
[MarshalAs(UnmanagedType.U1)]
public byte mac2;
[MarshalAs(UnmanagedType.U1)]
public byte mac3;
[MarshalAs(UnmanagedType.U1)]
public byte mac4;
[MarshalAs(UnmanagedType.U1)]
public byte mac5;
[MarshalAs(UnmanagedType.U1)]
public byte mac6;
[MarshalAs(UnmanagedType.U1)]
public byte mac7;
[MarshalAs(UnmanagedType.U4)]
public uint dwAddr;
[MarshalAs(UnmanagedType.U4)]
public uint dwType;
}
private const int SUCCESS = 0;
private const int ERROR_INSUFFICIENT_BUFFER = 0x007A;
private const uint MIB_IPNET_TYPE_OTHER = 1;
private const uint MIB_IPNET_TYPE_INVALID = 2;
private const uint MIB_IPNET_TYPE_DYNAMIC = 3;
private const uint MIB_IPNET_TYPE_STATIC = 4;
static void Main(string[] args)
{
int result;
int requestBuffSize = 0;
// ARPテーブル格納用のメモリエリアを確保する
// 格納メモリ不足の ERROR_INSUFFICIENT_BUFFER が返却され、requestBuffSize に必要なメモリサイズが返却される
// ERROR_INSUFFICIENT_BUFFER 以外が返却された場合は処理を中止する
// GetIpNetTable: https://learn.microsoft.com/ja-jp/windows/win32/api/iphlpapi/nf-iphlpapi-getipnettable
result = GetIpNetTable(IntPtr.Zero, ref requestBuffSize, true);
if (result != ERROR_INSUFFICIENT_BUFFER)
{
Console.Error.WriteLine("GetIpNetTable API Error:" + result);
Environment.Exit((int)result);
}
try
{
// Marshal.AllocCoTaskMem: https://learn.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.marshal.alloccotaskmem
IntPtr resultBuff = Marshal.AllocCoTaskMem(requestBuffSize);
// 確保した格納用メモリを引数に設定し GetIpNetTable API を実行する
// 0(SUCCESS)以外が返却された場合は処理を中止する
result = GetIpNetTable(resultBuff, ref requestBuffSize, true);
if (result != 0)
{
Environment.Exit(result);
}
// ARPエントリ数が0の場合、処理を終了する
int entries = Marshal.ReadInt32(resultBuff);
if (entries == 0)
{
Environment.Exit(0);
}
// GetIpNetTable API から返却された MIB_IPNETTABLE.dwNumEntries DWORD分を移動
// MIB_IPNETTABLE: https://learn.microsoft.com/en-us/windows/win32/api/ipmib/ns-ipmib-mib_ipnettable
IntPtr currentPtr = IntPtr.Add(resultBuff, sizeof(Int32));
// 取得したARP情報を格納するListオブジェクトを準備
List<MIB_IPNETROW> arpTableList = new List<MIB_IPNETROW>();
for (int i = 0; i < entries; i++)
{
// List<MIB_IPNETROW> に追加
arpTableList.Add((MIB_IPNETROW)Marshal.PtrToStructure(currentPtr, typeof(MIB_IPNETROW)));
// 次のデータの先頭に移動
currentPtr = IntPtr.Add(currentPtr, Marshal.SizeOf(typeof(MIB_IPNETROW)));
}
// メモリの解放
Marshal.FreeHGlobal(resultBuff);
// 取得したARPテーブルからMACアドレス、IPアドレスの表示する
foreach (var item in arpTableList)
{
//IPアドレス
Byte[] b = BitConverter.GetBytes(item.dwAddr);
string ip = string.Format("{0}.{1}.{2}.{3}", b[0], b[1], b[2], b[3]);
string mac = string.Format("{0:x2}-{1:x2}-{2:x2}-{3:x2}-{4:x2}-{5:x2}", item.mac0, item.mac1, item.mac2, item.mac3, item.mac4, item.mac5);
// TYPE
// MIB_IPNET_TYPE:https://learn.microsoft.com/en-us/windows/win32/api/ipmib/ns-ipmib-mib_ipnetrow_lh
string type = string.Empty;
switch (item.dwType)
{
case MIB_IPNET_TYPE_OTHER:
type = "OTHER";
break;
case MIB_IPNET_TYPE_INVALID:
type = "INVALID";
break;
case MIB_IPNET_TYPE_DYNAMIC:
type = "DYNAMIC";
break;
case MIB_IPNET_TYPE_STATIC:
type = "STATIC";
break;
}
Console.WriteLine("| {0,-15} | {1} | {2,-7} |", ip, mac, type);
}
}
catch (Exception e)
{
Console.Error.WriteLine("Exception thrown:" + e.Message);
Environment.Exit(1);
}
}
}
}
マルチキャストアドレスも表示されていますね。
ネットワーク上のARPキャッシュの情報が表示されました。
以上、GetIpNetTable API を使ってARPテーブル情報を表示するC#サンプルコードでした。