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

JavaのNetworkInterfaceでgetName()メソッドを呼び出してもXP環境では文字化けして正しく表示できないばかりでなく、getByName()メソッドでは、通常Windowsで利用される"ローカル エリア接続"等では探すことが出来ません。
それで、自前でアドレス情報を取得したりインターフェースを探せるクラスを作ってみようと思います。


まず、C++でインターフェース情報を取得するクラスの作成から。
IPアドレスを保存するクラスとして
addrinfo.h

#include <windows.h>
#include <tchar.h>
#include <comdef.h>

#include <iphlpapi.h>
#define LOOPBACK_INTERFACE  IF_TYPE_SOFTWARE_LOOPBACK
#define IPADDR_PRIMARY      MIB_IPADDR_PRIMARY
#define IPADDR_DYNAMIC      MIB_IPADDR_DYNAMIC
#define DIRECT_ROUTE        MIB_IPROUTE_TYPE_DIRECT
#define INDIRECT_ROUTE      MIB_IPROUTE_TYPE_INDIRECT

#include <vector>
#include <string>
using namespace std;

typedef basic_string<_TCHAR>    String;

class AddrInfo;
typedef vector<AddrInfo>            address_list;

extern const String HOST_MASK;
extern const String GATEWAY_NET;
extern const String GATEWAY_MASK;

class AddrInfo {
private:
    static  String          getBcastAddr(DWORD ip, DWORD mask, DWORD type);

public:
    AddrInfo(const AddrInfo& info);
    AddrInfo(String address, String mask = HOST_MASK, String bcast = String(_T("")), int type = 0);
    AddrInfo();
    ~AddrInfo();

    String  getIpAddress();
    String  getNetMask();
    String  getBroadcastAddress();
    int     getIpType();
    bool    isPrimaryAddress();

    static  address_list    setAddressList(int ifIndex);

private:
    String  ipAddress;
    String  netMask;
    String  bcastAddr;
    int     ipType;
};

addrinfo.cpp

#include "addrinfo.h"

const String HOST_MASK =    String(_T("255.255.255.255"));
const String GATEWAY_NET =  String(_T("0.0.0.0"));
const String GATEWAY_MASK = String(_T("0.0.0.0"));

//  Copy Constructor
AddrInfo::AddrInfo(const AddrInfo& info) {
    ipAddress = info.ipAddress;
    netMask = info.netMask;
    bcastAddr = info.bcastAddr;
    ipType = info.ipType;
}

//  Constructor
AddrInfo::AddrInfo(String address, String mask, String bcast, int type) {
    ipAddress = address;
    netMask = mask;
    if (!bcast.empty()) {
        bcastAddr = bcast;
    }
    else {
        bcastAddr = address;
    }
    ipType = type;
}

//  Constructor
AddrInfo::AddrInfo() {
    ipType = 0;
}

//  Destructor
AddrInfo::~AddrInfo() {
}

/*
 *  IPアドレスを取得する
 *  param   : 無し
 *
 *  return  : String
 */
String AddrInfo::getIpAddress() {
    return ipAddress;
}

/*
 *  ネットワークマスクを取得する
 *  param   : 無し
 *
 *  return  : String
 */
String AddrInfo::getNetMask() {
    return netMask;
}

/*
 *  Broadcastアドレスを取得する
 *  param   : 無し
 *
 *  return  : String
 */
String AddrInfo::getBroadcastAddress() {
    return bcastAddr;
}

/*
 *  IPアドレスのタイプを取得する
 *  param   : 無し
 *
 *  return  : int
 */
int AddrInfo::getIpType() {
    return ipType;
}

/*
 *  IPアドレスがプライマリアドレスか確認する
 *  param   : 無し
 *
 *  return  : bool
 *            true  = プライマリアドレスである
 *            false = プライマリアドレスでない
 */
bool AddrInfo::isPrimaryAddress() {
    return ((ipType & IPADDR_PRIMARY) > 0) ? true : false;
}

/*
 *  IPアドレスとネットマスクからブロードキャストアドレスを取得する
 *  param   : IPアドレス(DWORD)
 *            ネットマスク(DWORD)
 *            IPタイプ(DWORD)
 *
 *  return  : String
 */
String AddrInfo::getBcastAddr(DWORD ip, DWORD mask, DWORD type) {
    DWORD bcast = (type == 1) ? 0xffffffff : 0x00000000;
    bcast ^= mask;
    DWORD network = ~bcast;
    network &= ip;
    bcast |= network;
    return String((_TCHAR*)_bstr_t(inet_ntoa(*(struct in_addr *)&bcast)));
}

/*
 *  指定したインターフェースに設定されたアドレスを取得する
 *  param   : インターフェースの番号(int)
 *
 *  return  : address_list
 */
address_list AddrInfo::setAddressList(int ifIndex) {
    address_list result;
    String ipaddress;
    String netmask;
    String bcastaddress;

    long retCode = NO_ERROR;
    DWORD dwSize = 0;
    GetIpAddrTable(NULL, &dwSize, 0);
    PMIB_IPADDRTABLE pIPAddrTable = (MIB_IPADDRTABLE *)malloc(dwSize);
    memset(pIPAddrTable, 0, dwSize);
    if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == NO_ERROR) {
        for (unsigned int num = 0; num < pIPAddrTable->dwNumEntries; num++) {
            if (ifIndex == pIPAddrTable->table[num].dwIndex) {
                ipaddress = String((_TCHAR *)_bstr_t(inet_ntoa(*(struct in_addr *)&pIPAddrTable->table[num].dwAddr)));
                netmask = String((_TCHAR *)_bstr_t(inet_ntoa(*(struct in_addr *)&pIPAddrTable->table[num].dwMask)));
                bcastaddress = getBcastAddr(pIPAddrTable->table[num].dwAddr, pIPAddrTable->table[num].dwMask, pIPAddrTable->table[num].dwBCastAddr);
                AddrInfo info = AddrInfo(ipaddress,
                                            netmask,
                                            bcastaddress,
                                            pIPAddrTable->table[num].wType);
                result.push_back(info);
            }
        }
    }
    free(pIPAddrTable);

    return result;
}

インターフェース情報を保存するクラスとして
ifinfo.h

#include <vector>
#include <string>
#include <sstream>
using namespace std;

#include "addrinfo.h"

typedef basic_string<_TCHAR>    String;

class IfInfo;
typedef vector<IfInfo>              interface_list;
typedef interface_list::iterator    if_iter;

class IfInfo {
private:
    static  interface_list  getInterfaceList();
    static  void            loadInterfaceInfo(IfInfo *if_table);
    static  String          getMacAddress(unsigned char *value, unsigned long len);

public:
    IfInfo(const IfInfo& info);
    IfInfo();
    ~IfInfo();

    unsigned long   getIndex();
    String          getName();
    String          getAdapterName();
    String          getDescription();
    String          getMacAddress();
    int             getType();
    int             getOpStatus();
    address_list    getIpAddressList();
    bool            isDhcpEnabled();
    bool            isRunning();

    static  interface_list      getIfList();
    static  IfInfo              findInterfaceByIndex(unsigned long index);
    static  IfInfo              findInterfaceByName(String ifname);

private:
    unsigned long   ifIndex;
    String          ifName;
    String          adapterName;
    String          description;
    String          ifAddress;
    int             ifType;
    int             opStatus;
    address_list    ipAddressList;
    bool            dhcpEnabled;
};

ifinfo.cpp

#include "ifinfo.h"
/*
 *  システムで利用可能なインターフェースの一覧を取得する
 *  param   : 無し
 *
 *  return  : interface_list
 */
interface_list IfInfo::getInterfaceList() {
    interface_list if_list;

    long retCode = NO_ERROR;
    DWORD dwSize = 0;

    GetIfTable(NULL, &dwSize, true);
    PMIB_IFTABLE pIfTable = (MIB_IFTABLE *)malloc(dwSize);
    memset(pIfTable, 0, dwSize);
    retCode = GetIfTable(pIfTable, &dwSize, true);
    if (retCode == NO_ERROR) {
        for (u_int i = 0; i < pIfTable->dwNumEntries; i++) {
            IfInfo if_table = IfInfo();
            MIB_IFROW pInterface = pIfTable->table[i];
            if_table.ifIndex = pInterface.dwIndex;
            basic_stringstream<_TCHAR> buf;
            buf << _bstr_t((char *)pInterface.bDescr);
            if_table.ifName = if_table.description = buf.str();
            if_table.ifType = pInterface.dwType;
            if_table.opStatus = pInterface.dwOperStatus;
            if_list.push_back(if_table);
        }
    }
    free(pIfTable);

    return if_list;
}

String IfInfo::getMacAddress(unsigned char *value, unsigned long len) {
    _bstr_t mac;
    for (u_int i = 0; i < len; i++) {
        if (i > 0)
            mac += _T(":");
        char code[3];
        sprintf(code, "%02x", value[i]);
        mac += code;
    }
    return String((_TCHAR *)mac);
}

//  interface_info
//  Copy Constructor
IfInfo::IfInfo(const IfInfo& info) {
    ifIndex = info.ifIndex;
    ifName = info.ifName;
    adapterName = info.adapterName;
    description = info.description;
    ifAddress = info.ifAddress;
    ifType = info.ifType;
    opStatus = info.opStatus;
    dhcpEnabled = info.dhcpEnabled;
    if (info.ipAddressList.size() > 0) {
        for (size_t i = 0; i < info.ipAddressList.size(); i++) {
            ipAddressList.push_back(info.ipAddressList[i]);
        }
    }
}

//  Constructor
IfInfo::IfInfo() {
}

//  Destructor
IfInfo::~IfInfo() {
}

/*
 *  インターフェースの詳細情報を設定する
 *  param   : インターフェーステーブル(IfInfoポインター)
 *
 *  return  : 無し
 */
void IfInfo::loadInterfaceInfo(IfInfo *if_table) {
    DWORD dwSize = 0;
    long retCode = NO_ERROR;
    if (GetAdaptersInfo(NULL, &dwSize) == ERROR_BUFFER_OVERFLOW) {
        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(dwSize);
        memset(pAdapterInfo, 0, dwSize);
        retCode = GetAdaptersInfo(pAdapterInfo, &dwSize);
        if (retCode == NO_ERROR) {
            PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
            while (pAdapter) {
                if (pAdapter->Index == if_table->ifIndex) {
                    if_table->adapterName = String((_TCHAR *)_bstr_t(pAdapter->AdapterName));
                    if_table->ifAddress = getMacAddress(pAdapter->Address, pAdapter->AddressLength);
                    if_table->ipAddressList = AddrInfo::setAddressList(if_table->ifIndex);
                    if_table->dhcpEnabled = pAdapter->DhcpEnabled ? true : false;
                    HKEY hkey = NULL;
                    _bstr_t adapter = _bstr_t(_T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"));
                    adapter += _bstr_t((char *)pAdapter->AdapterName);
                    adapter += _bstr_t(_T("\\Connection"));
                    int rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (_TCHAR *)adapter, 0, KEY_READ, &hkey);
                    if (rc == ERROR_SUCCESS) {
                        DWORD valueType = 0;
                        DWORD nameLen = 0;
                        rc = RegQueryValueEx(hkey, _T("Name"), 0, &valueType, NULL, &nameLen);
                        nameLen++;
                        char *buff = (char *)calloc(nameLen, sizeof(char));
                        rc = RegQueryValueEx(hkey, _T("Name"), 0, &valueType, (LPBYTE)buff, &nameLen);
                        RegCloseKey(hkey);
                        basic_stringstream<_TCHAR> buf;
                        buf << _bstr_t((_TCHAR *)buff);
                        if_table->ifName = buf.str();
                        free(buff);
                    }
                }
                pAdapter = pAdapter->Next;
            }
            free(pAdapterInfo);
        }
    }
}

/*
 *  インターフェースの名前を取得する
 *  param   : 無し
 *
 *  return  : String
 */
String IfInfo::getName() {
    return ifName;
}

/*
 *  インターフェースのアダプタ名を取得する
 *  param   : 無し
 *
 *  return  : String
 */
String IfInfo::getAdapterName() {
    return adapterName;
}

/*
 *  インターフェースの説明を取得する
 *  param   : 無し
 *
 *  return  : String
 */
String IfInfo::getDescription() {
    return description;
}

/*
 *  インターフェースのMACアドレスを取得する
 *  param   : 無し
 *
 *  return  : String
 */
String IfInfo::getMacAddress() {
    return ifAddress;
}

/*
 *  インターフェースの番号を取得する
 *  param   : 無し
 *
 *  return  : u_long
 */
u_long IfInfo::getIndex() {
    return ifIndex;
}

/*
 *  インターフェースのタイプを取得する
 *  param   : 無し
 *
 *  return  : int
 */
int IfInfo::getType() {
    return ifType;
}

/*
 *  インターフェースのステータスを取得する
 *  param   : 無し
 *
 *  return  : int
 */
int IfInfo::getOpStatus() {
    return opStatus;
}

/*
 *  インターフェースのアドレスリストを取得する
 *  param   : 無し
 *
 *  return  : address_list
 */
address_list IfInfo::getIpAddressList() {
    return ipAddressList;
}

/*
 *  インターフェースがDHCPに設定されているか確認する
 *  param   : 無し
 *
 *  return  : bool
 *            true  = DHCPである
 *            false = DHCPでない
 */
bool IfInfo::isDhcpEnabled() {
    return dhcpEnabled;
}

/*
 *  インターフェースが動作中か確認する
 *  param   : 無し
 *
 *  return  : bool
 *            true  = 動作中である
 *            false = 動作中でない
 */
bool IfInfo::isRunning() {
    return (opStatus == IF_OPER_STATUS_OPERATIONAL) ?  true : false;
}

/*
 *  システムで利用可能なインターフェースの一覧を取得する
 *  param   : 無し
 *
 *  return  : interface_list
 */
interface_list IfInfo::getIfList() {
    interface_list net_list = getInterfaceList();
    for (if_iter if_ent = net_list.begin(); if_ent != net_list.end(); if_ent++) {
        IfInfo::loadInterfaceInfo(&(*if_ent));
    }

    return net_list;
}

/*
 *  インターフェースの一覧からインターフェース番号の情報を取得する
 *  param   : インターフェース番号(u_long)
 *
 *  return  : IfInfo
 */
IfInfo IfInfo::findInterfaceByIndex(unsigned long index) {
    IfInfo if_table;

    interface_list net_list = getInterfaceList();
    for (if_iter if_ent = net_list.begin(); if_ent != net_list.end(); if_ent++) {
        if ((*if_ent).getIndex() == index) {
            IfInfo::loadInterfaceInfo(&(*if_ent));
            return *if_ent;
        }
    }

    return if_table;
}

/*
 *  インターフェースの一覧からインターフェース名の情報を取得する
 *  param   : インターフェース名(charポインター)
 *
 *  return  : IfInfo
 */
IfInfo IfInfo::findInterfaceByName(String ifname) {
    IfInfo if_table;

    interface_list net_list = getIfList();
    for (if_iter if_ent = net_list.begin(); if_ent != net_list.end(); if_ent++) {
        if ((*if_ent).getName().compare(ifname) == 0) {
            IfInfo::loadInterfaceInfo(&(*if_ent));
            return *if_ent;
        }
    }
    return if_table;
}

テストの為に次のプログラムを実行して確認。

#include <windows.h>

#include <string>
#include <iostream>
using namespace std;

#include <addrinfo.h>
#include <ifinfo.h>
using namespace penguin;

#ifdef  _UNICODE
#define COUT    wcout
#define CIN     wcin
#else
#define COUT    cout
#define CIN     cin
#endif  //  _UNICODE

void getAddress() {
    for (int i = 0; i < 256; i++) {
        address_list list = AddrInfo::setAddressList(i);
        for (size_t j = 0; j < list.size(); j++) {
            AddrInfo info = list.at(j);
            COUT << _T("Index : ") << i << _T("-") << info.getIpAddress() << endl;
        }
    }
}

void getInterface() {
    interface_list list = IfInfo::getIfList();
    for (size_t j = 0; j < list.size(); j++) {
        IfInfo info = list.at(j);
        COUT << _T("Index : ") << info.getIndex() << _T("-") << info.getDescription() << _T("-") << info.getName() << endl;
    }
    IfInfo intInfo = IfInfo::findInterfaceByName(String(_T("ローカル エリア接続 3")));
    COUT << _T("Index : ") << intInfo.getIndex() << _T("-") << intInfo.getDescription() << _T("-") << intInfo.getName() << endl;
}

int _tmain(int argc, _TCHAR* argv[]) {

    getAddress();
    getInterface();

    return 0;
}

このプログラムをベースにJNIでJavaからのアクセスクラスを作成します。