Win32API IPHLPAPI ARPテーブルにエントリを追加する CreateIpNetEntry

ARPテーブルにエントリを追加するには、CreateIpNetEntry関数を使用する。


CreateIpNetEntry関数のプロトタイプは以下の通り。

DWORD CreateIpNetEntry(
  __in  PMIB_IPNETROW pArpEntry
);


CreateIpNetEntry関数の引数に用いられるMIB_IPNETROW構造体は、iprtrmib.h に以下のように定義されている。

typedef struct _MIB_IPNETROW
{
    DWORD        dwIndex; //ネットワークアダプタのインデックス
    DWORD        dwPhysAddrLen; //物理アドレス長
    BYTE         bPhysAddr[MAXLEN_PHYSADDR]; //物理アドレス
    DWORD        dwAddr; //IPv4アドレス(ネットワークバイトオーダ)
    DWORD        dwType; //ARPエントリの種類
} MIB_IPNETROW, *PMIB_IPNETROW;



MIB_IPNETROW構造体のdwIndexは、GetAdaptersInfo関数により取得したIP_ADAPTER_INFO構造体のIndexメンバの値を指定する。ネットワークアダプタが複数ある場合、2番目以降のアダプタ情報にアクセスするためには、GetAdaptersInfo関数を呼び出し後、IP_ADAPTER_INFO構造体のNextメンバを用いて線形リストを手繰っていく必要がある。



IP_ADAPTER_INFO構造体の定義は以下の通り。

//
// ADAPTER_INFO - per-adapter information. All IP addresses are stored as
// strings
//

typedef struct _IP_ADAPTER_INFO {
    struct _IP_ADAPTER_INFO* Next;
    DWORD ComboIndex;
    char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
    char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
    UINT AddressLength;
    BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
    DWORD Index;
    UINT Type;
    UINT DhcpEnabled;
    PIP_ADDR_STRING CurrentIpAddress;
    IP_ADDR_STRING IpAddressList;
    IP_ADDR_STRING GatewayList;
    IP_ADDR_STRING DhcpServer;
    BOOL HaveWins;
    IP_ADDR_STRING PrimaryWinsServer;
    IP_ADDR_STRING SecondaryWinsServer;
    time_t LeaseObtained;
    time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;


第5引数のdwTypeは、iprtrmib.h に以下のように定義されている。ARPテーブルにエントリを追加する際には、静的ARPエントリとする必要があり、dwTypeにはMIB_IPNET_TYPE_STATIC を指定する。

#define    MIB_IPNET_TYPE_OTHER        1
#define    MIB_IPNET_TYPE_INVALID        2
#define    MIB_IPNET_TYPE_DYNAMIC        3
#define    MIB_IPNET_TYPE_STATIC        4




  • 複数のアダプタが存在する場合、以下のようにしてIP_ADAPTER_INFO構造体のリストを手繰ることで2番目以降のアダプタ情報にアクセスできる
  • #include <windows.h>
    #include <stdio.h>
    #include <winsock.h>
    #include <iphlpapi.h>
    
    #pragma comment(lib, "wsock32.lib")
    #pragma comment(lib, "iphlpapi.lib")
    
    int main(int argc, _TCHAR* argv[])
    {
      PIP_ADAPTER_INFO pAdapterInfo;
      ULONG uiOutBuffLen;
    
      //GetAdaptersInfoの第1引数にNULLを渡して、アダプタ情報を
      //取得するために確保するメモリサイズをuiOutBuffLenに取得する
      if (GetAdaptersInfo(NULL, &uiOutBuffLen) != ERROR_BUFFER_OVERFLOW) {
        puts("GetAdaptersInfo for get buffer length failed.");
        return 1;
      }
    
      //アダプタ情報を格納するためのメモリを確保
      if ( (pAdapterInfo = (IP_ADAPTER_INFO *)malloc(uiOutBuffLen)) == NULL) {
        puts("malloc failed.");
        return 1;
      }
    
      //アダプタ情報を取得
      if (GetAdaptersInfo(pAdapterInfo, &uiOutBuffLen) != NO_ERROR) {
        puts("GetAdaptersInfo failed.");
        return 1;
      }
    
      //複数のアダプタがある場合、IP_ADAPTER_INFO構造体の線形リストを
      //手繰ってコンソールに表示する
      do {
        printf("Adapter Index: %d\n", pAdapterInfo->Index);
      } while (pAdapterInfo = pAdapterInfo->Next);
      
      //メモリ解放
      free(pAdapterInfo);
    	
      return 0;
    }



  • CreateIpNetEntry関数の使用例は以下の通り。

  • 以下の例では、「IPアドレス:192.168.1.100, MACアドレス:99-99-99-99-99-99」という有り得ないARPエントリをARPテーブルに追加している。

    #include <windows.h>
    #include <stdio.h>
    #include <winsock.h>
    #include <iphlpapi.h>
    
    #pragma comment(lib, "wsock32.lib")
    #pragma comment(lib, "iphlpapi.lib")
    
    int main(int argc, _TCHAR* argv[])
    {
      PIP_ADAPTER_INFO pAdapterInfo;
      ULONG uiOutBuffLen;
    
      //GetAdaptersInfoの第1引数にNULLを渡して、アダプタ情報を
      //取得するために確保するメモリサイズをuiOutBuffLenに取得する
      if (GetAdaptersInfo(NULL, &uiOutBuffLen) != ERROR_BUFFER_OVERFLOW) {
        puts("GetAdaptersInfo for get buffer length failed.");
        return 1;
      }
    
      //アダプタ情報を格納するためのメモリを確保
      if ( (pAdapterInfo = (IP_ADAPTER_INFO *)malloc(uiOutBuffLen)) == NULL) {
        puts("malloc failed.");
        return 1;
      }
    
      //アダプタ情報を取得
      if (GetAdaptersInfo(pAdapterInfo, &uiOutBuffLen) != NO_ERROR) {
        puts("GetAdaptersInfo failed.");
        return 1;
      }
    
      //ARPエントリの設定
      MIB_IPNETROW ArpEntry;
      ArpEntry.dwIndex = pAdapterInfo->Index;//アダプタインデックスをMIB_IPNETROWのdwIndexメンバに設定する
      ArpEntry.dwAddr = inet_addr("192.168.1.100");//IPアドレス(ネットワークバイトオーダ)
      BYTE PhysicalAddress[6] = {0x99, 0x99, 0x99, 0x99, 0x99, 0x99};//物理アドレス
      ArpEntry.dwPhysAddrLen = 6;//物理アドレス長
      ArpEntry.dwType = MIB_IPNET_TYPE_STATIC;//静的ARPエントリ
      memcpy(ArpEntry.bPhysAddr, PhysicalAddress, 6);//物理アドレスをMIB_IPNETROWのbPhysAddrメンバにコピー
    
      //ARPテーブルにARPエントリを追加
      DWORD dwRet = CreateIpNetEntry(&ArpEntry);
      switch (dwRet) {
        case NO_ERROR:
          puts("NO_ERROR");
          break;
    
        case ERROR_ACCESS_DENIED:
          puts("ERROR_ACCESS_DENIED");
          break;
    
        case ERROR_INVALID_PARAMETER:
          puts("ERROR_INVALID_PARAMETER");
          break;
    
        case ERROR_NOT_SUPPORTED:
          puts("ERROR_NOT_SUPPORTED");
          break;
    
        default:
          printf("default: LastError - %d\n", GetLastError());
          break;
      }
      
      //メモリ解放
      free(pAdapterInfo);
    	
      return 0;
    }



  • 実行結果

  • プログラムを実行後、コマンドプロンプトから「arp -a」で、以下のようにARPテーブルに「IPアドレス:192.168.1.100, 物理アドレス:99-99-99-99-99-99」というARPエントリが追加される (プログラムは管理者権限で実行する必要がある。ここでの実行環境は、Windows Vista)。




  • ARPテーブルをクリアする

  • ARPテーブルをクリアするためには、FlushIpNetTable関数を用いる。

    FlushIpNetTable関数のプロトタイプは、以下の通り。

    DWORD FlushIpNetTable(
      __in  DWORD dwIfIndex //ネットワークアダプタのインデックス
    );



    唯一の引数であるdwIfIndexは、CreateIpNetEntryと同様にGetAdaptersInfo関数により取得したIP_ADAPTER_INFO構造体のIndexメンバの値を指定する。複数のアダプタが存在する場合は、上記の例のようにIP_ADAPTER_INFO構造体のNextメンバを用いて線形リストを手繰ることにより、2番目以降のアダプタにアクセスすることができる。



    FlushIpNetTableの使用例は、以下の通り。

    #include <windows.h>
    #include <stdio.h>
    #include <winsock.h>
    #include <iphlpapi.h>
    
    #pragma comment(lib, "wsock32.lib")
    #pragma comment(lib, "iphlpapi.lib")
    
    int main(int argc, _TCHAR* argv[])
    {
      PIP_ADAPTER_INFO pAdapterInfo;
      ULONG uiOutBuffLen;
    
      //GetAdaptersInfoの第1引数にNULLを渡して、アダプタ情報を
      //取得するために確保するメモリサイズをuiOutBuffLenに取得する
      if (GetAdaptersInfo(NULL, &uiOutBuffLen) != ERROR_BUFFER_OVERFLOW) {
        puts("GetAdaptersInfo for get buffer length failed.");
        return 1;
      }
    
      //アダプタ情報を格納するためのメモリを確保
      if ( (pAdapterInfo = (IP_ADAPTER_INFO *)malloc(uiOutBuffLen)) == NULL) {
        puts("malloc failed.");
        return 1;
      }
    
      //アダプタ情報を取得
      if (GetAdaptersInfo(pAdapterInfo, &uiOutBuffLen) != NO_ERROR) {
        puts("GetAdaptersInfo failed.");
        return 1;
      }
      
      //ARPテーブルをクリア
      FlushIpNetTable(pAdapterInfo->Index);
      
      //メモリ解放
      free(pAdapterInfo);
    
      return 0;
    }



    参考
    http://msdn.microsoft.com/en-us/library/aa365866(VS.85).aspx
    http://msdn.microsoft.com/en-us/library/aa365905(VS.85).aspx