#author("2023-04-22T17:21:05+09:00","","")

#author("2023-04-22T17:23:26+09:00","","")
#navi(../)
*ARPテーブルを取得し表示するサンプル・GetIpNetTable API [#z9b3d394]
iphlpapi.dll の GetIpNetTable API を使用しARPリストを取得しIPアドレス、MACアドレス、タイプを表示するコンソールアプリケーションのC#サンプルコードを公開しました。~

#contents

* 関連記事 [#ka7de2a8]
-[[IPv4からMACアドレス取得するSendARP()APIを使ってみる>.NET/IPv4からMACアドレス取得する・SendARP]]

* 参考サイト [#fa1ec922]
- c# get arp cache~
https://gist.github.com/invictus-0x90/2e1ebcfefd8d7478e695131b88ce2926
- SIN@SAPPOROWORKSの覚書 ARPテーブルの取得 (C#)(F#)~
https://furuya02.hatenablog.com/entry/20111107/1399766912
- Microsoft GetIpNetTable 関数 (iphlpapi.h)~
https://learn.microsoft.com/ja-jp/windows/win32/api/iphlpapi/nf-iphlpapi-getipnettable
- Microsoft MIB_IPNETTABLE structure (ipmib.h)~
https://learn.microsoft.com/en-us/windows/win32/api/ipmib/ns-ipmib-mib_ipnettable
- Microsoft MIB_IPNETROW_LH structure (ipmib.h)
- Microsoft MIB_IPNETROW_LH structure (ipmib.h)~
https://learn.microsoft.com/en-us/windows/win32/api/ipmib/ns-ipmib-mib_ipnetrow_lh

* 動作確認環境 [#qc949720]
- Windows 10 ver.22H2
- .NET6.0
- Visual Studio 2022

* C#サンプルコード [#e6de880e]
GetIpNetTable API を使用し取得したARPテーブル情報を表示するC#サンプルコードを以下に記します。~
説明に関してはコメントを参照してください。

#ref(Program.cs)
 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);
             }
         }
     }
 }

* 実行結果 [#d1174116]
マルチキャストアドレスも表示されていますね。~
ネットワーク上のARPキャッシュの情報が表示されました。
#br
#ref(01.png)


以上、GetIpNetTable API を使ってARPテーブル情報を表示するC#サンプルコードでした。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS