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
#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; }
以下の例では、「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テーブルをクリアするためには、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