ネットワークインターフェースの情報を取得する

ネットワークプログラミングを行なっていると、ネットワークインターフェースの数や、それぞれに関する情報を知りたくなってくると思います。 ここでは、それらの情報を取得する方法を説明します。

サンプルコード

ネットワークインターフェースのリストは、GetInterfaceInfo()関数を利用して取得できます。


#include <stdio.h>

#include <winsock2.h>
#include <iphlpapi.h>

int
main()
{
 int i;
 PIP_INTERFACE_INFO pInfo = NULL;
 ULONG ulOutBufLen = 0;
 DWORD dwRetVal = 0;

 /* 変数 ulOutBufLen に必要なサイズを取得 */
 if (GetInterfaceInfo(NULL, &ulOutBufLen)
       == ERROR_INSUFFICIENT_BUFFER) {
   pInfo = (IP_INTERFACE_INFO *) malloc (ulOutBufLen);
 }

 /* 実際にデータを取得する */
 dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);

 if (dwRetVal == NO_ERROR ) {
   printf("Number of Adapters: %ld\n\n", pInfo->NumAdapters);

   for (i=0; i<pInfo->NumAdapters; i++) {
     printf("Adapter Name: %ws\n", pInfo->Adapter[i].Name);
     printf("Adapter Index: %ld\n", pInfo->Adapter[i].Index);
     printf("\n");
   }
 } else {
   printf("GetInterfaceInfo failed.\n");
   LPVOID lpMsgBuf;
		
   if (FormatMessage(
           FORMAT_MESSAGE_ALLOCATE_BUFFER | 
           FORMAT_MESSAGE_FROM_SYSTEM | 
           FORMAT_MESSAGE_IGNORE_INSERTS,
           NULL,
           dwRetVal,
           MAKELANGID(LANG_NEUTRAL,
                      SUBLANG_DEFAULT), /* Default language */
           (LPTSTR) &lpMsgBuf,
           0,
           NULL ))  {
     printf("Error: %s", lpMsgBuf);
   }

   LocalFree( lpMsgBuf );
 }

 return 0;
}

サンプルコード実行例

上記コードをコンパイルして出来たものを実行すると、以下のようになります。


C:> a.exe
Number of Adapters: 2

Adapter Name: \DEVICE\TCPIP_{22EXXC3D-F01D-4231-AE59-C23EXXXX6C66}
Adapter Index: 2

Adapter Name: \DEVICE\TCPIP_{4E7XX61B-836C-49AB-8B02-775BXXXX7352}
Adapter Index: 3

GetInterfaceInfo()が利用する構造体

上記サンプルを見ていると、やはりIP_INTERFACE_INFOの中身がどういうものか気になると思います。 GetInterfaceInfo()が使っているIP_INTERFACE_INFOは以下のように宣言されています。


typedef struct _IP_ADAPTER_INDEX_MAP {
  ULONG Index;
  WCHAR Name[MAX_ADAPTER_NAME];
} IP_ADAPTER_INDEX_MAP, *PIP_ADAPTER_INDEX_MAP;

typedef struct _IP_INTERFACE_INFO {
  LONG NumAdapters;
  IP_ADAPTER_INDEX_MAP Adapter[1];
} IP_INTERFACE_INFO, *PIP_INTERFACE_INFO;

ネットワークインターフェースのリストを取得する2

Adapter Nameで出てきた文字列は、ipconfigで出てくる名前とは違います。 これはこれで使い道があるのですが、このままではどれがどれだかわからないので、次は人間にわかりやすい名前を出す方法を説明したいと思います。

サンプルコード

インターフェースのDescriptionは、GetIfEntry()を使うと取得できます。 以下にGetIfEntry()を使う例を示します。


#include <stdio.h>

#include <winsock2.h>
#include <iphlpapi.h>

int
main()
{
 DWORD i;
 PMIB_IFTABLE ifTable;
 MIB_IFROW MibIfRow;
 DWORD dwSize = 0;
 DWORD dwRetVal = 0;

 /*
  * GetIfEntry()を使う前にエントリ数を
  * 取得するためにGetIfTable()を使っています
  */

 /* GetIfTable()で必要になるサイズを取得 */
 if (GetIfTable(NULL, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
   ifTable = (MIB_IFTABLE *) malloc (dwSize);
 }

 /* 実際にGetIfTable()を使う */
 if ((dwRetVal = GetIfTable(ifTable, &dwSize, 0)) == NO_ERROR) {
   if (ifTable->dwNumEntries > 0) {
     printf("Number of Adapters: %ld\n\n", ifTable->dwNumEntries);
     for (i=1; i<=ifTable->dwNumEntries; i++) {
       MibIfRow.dwIndex = i;
       if ((dwRetVal = GetIfEntry(&MibIfRow)) == NO_ERROR) {
         printf("Description: %s\n", MibIfRow.bDescr);
       }
     }
   }
 } else {
   printf("GetIfTable failed.\n");
   LPVOID lpMsgBuf;
		
   if (FormatMessage( 
           FORMAT_MESSAGE_ALLOCATE_BUFFER | 
           FORMAT_MESSAGE_FROM_SYSTEM | 
           FORMAT_MESSAGE_IGNORE_INSERTS,
           NULL,
           dwRetVal,
           MAKELANGID(LANG_NEUTRAL,
                      SUBLANG_DEFAULT), // Default language
           (LPTSTR) &lpMsgBuf,
           0,
           NULL ))  {
     printf("Error: %s", lpMsgBuf);
   }

   LocalFree( lpMsgBuf );
 }

 return 0;
}

サンプルコード実行例

上記コードをコンパイルして出来たものを実行すると、以下のようになります。


C:> a.exe
Number of Adapters: 3

Description: MS TCP Loopback Interface
Description: Intel (R) PRO/100 VE Network Connection
Description: 3Com Fast Ethernet Network Connection

GetIfTable()が利用する構造体

上記サンプル中で利用している、MIB_IFTABLEとMIB_IFROWは以下のように宣言されています。


typedef struct _MIB_IFROW {
  WCHAR wszName[MAX_INTERFACE_NAME_LEN];
  DWORD dwIndex;
  DWORD dwType;
  DWORD dwMtu;
  DWORD dwSpeed;
  DWORD dwPhysAddrLen;
  BYTE bPhysAddr[MAXLEN_PHYSADDR];
  DWORD dwAdminStatus;
  DWORD dwOperStatus;
  DWORD dwLastChange;
  DWORD dwInOctets;
  DWORD dwInUcastPkts;
  DWORD dwInNUcastPkts;
  DWORD dwInDiscards;
  DWORD dwInErrors;
  DWORD dwInUnknownProtos;
  DWORD dwOutOctets;
  DWORD dwOutUcastPkts;
  DWORD dwOutNUcastPkts;
  DWORD dwOutDiscards;
  DWORD dwOutErrors;
  DWORD dwOutQLen;
  DWORD dwDescrLen;
  BYTE bDescr[MAXLEN_IFDESCR];
} MIB_IFROW, *PMIB_IFROW;

typedef struct _MIB_IFTABLE {
  DWORD dwNumEntries;
  MIB_IFROW table[ANY_SIZE];
} MIB_IFTABLE, *PMIB_IFTABLE;

IPv6基礎検定

YouTubeチャンネルやってます!