MS-WindowsのローカルIPアドレス、ブロードキャストアドレス、ネットマスクを取得するコード例
Makefileつきで、実行可能なコードになっているので、nmakeで簡単にコンパイルして、動かせます。
GNU/LinuxでのローカルIPアドレスの取得は以下の記事を参照してください。
MS-WindowsでのローカルIPアドレス、ブロードキャストアドレス、ネットマスクを取得するコード例を示します。探せば他にも見つかると思いますが、次の3パターンを一ヶ所にまとめて公開しておくのは役に立つこともあると思います。
- ローカルのネットワークデバイス(アダプタ)の列挙(ipconfig /all 相当)
- IPv4のローカルアドレス
- IPv6のローカルアドレス(*)
(*)コンパイルが通らない環境(IPv6未対応)もあるので、コメントアウトしています。
/* sample code: how to get the local network addresses
* 1. enumerate local network adapters
* 2. get local IPv4 address
* 3. get local IPv6 address (requires WinXP later)
*/
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iptypes.h>
#include <iphlpapi.h>
/*
* Do almost the same task as ipconfig /all
*/
static void enum_local_nic()
{
IP_ADAPTER_INFO adapterInfo;
PIP_ADAPTER_INFO pAdapterInfo = &adapterInfo;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
DWORD dwRetVal;
/* Make an initial call to GetAdaptersInfo to get
The necessary size into the ulOutBufLen variable */
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == ERROR_BUFFER_OVERFLOW) {
pAdapterInfo = malloc(ulOutBufLen); // XXX should be free
dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
}
if (dwRetVal == NO_ERROR) {
PIP_ADAPTER_INFO pAdapter;
for (pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) {
/* XXX take care of only the first IP address */
printf("address: %s\n", pAdapter->IpAddressList.IpAddress.String);
printf("netmask: %s\n", pAdapter->IpAddressList.IpMask.String);
printf("adapter name: %s\n", pAdapter->AdapterName);
printf("adapter description: %s\n", pAdapter->Description);
{
char *physic = malloc(3 * pAdapter->AddressLength);
char *pt = physic;
UINT i;
sprintf(pt, "%02X", pAdapter->Address[0]);
pt += 2;
for (i = 1; i < pAdapter->AddressLength; i++) {
sprintf(pt, "-%02X", pAdapter->Address[i]);
pt += 3;
}
printf("physical address: %s\n", physic);
free(physic);
}
}
}
}
static int is_unavail_addr(const struct sockaddr_in *sa)
{
if (sa->sin_addr.s_addr == 0) {
return TRUE;
}
if (sa->sin_family == AF_INET) {
if (sa->sin_addr.s_net == 0) {/* @see rfc3330 */
return TRUE;
}
if (sa->sin_addr.S_un.S_un_b.s_b1 == 169 && sa->sin_addr.S_un.S_un_b.s_b2 == 254) {/* @see rfc3330 (link local) */
return TRUE;
}
}
return FALSE;
}
/* derived from http://tangentsoft.net/wskfaq/intermediate.html#getipaddr */
static int get_local_address()
{
INTERFACE_INFO if_list[20];
unsigned long ret_bytes;
int num_if;
int n;
int ret = FALSE;
SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
if (sd == SOCKET_ERROR) {
return FALSE;
}
if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, NULL, 0, &if_list,
sizeof(if_list), &ret_bytes, NULL, NULL) == SOCKET_ERROR) {
closesocket(sd);
return FALSE;
}
closesocket(sd);
num_if = ret_bytes / sizeof(INTERFACE_INFO);
for (n = 0; n < num_if; ++n) {/* output for debug */
struct sockaddr_in *sa = (struct sockaddr_in*)&(if_list[n].iiAddress);
if (sa->sin_family == AF_INET) {
const char* addr_str = inet_ntoa(sa->sin_addr);
printf("Local IP address: %s[iiFlags:%x]\n", addr_str, if_list[n].iiFlags);
}
}
/* select better address */
for (n = 0; n < num_if; ++n) {
struct sockaddr_in *sa;
if (!(if_list[n].iiFlags & IFF_UP)) {
continue;
}
if (if_list[n].iiFlags & IFF_LOOPBACK) {
/* If there is a loopback address only, use it */
if (n != num_if - 1) {
continue;
}
}
sa = (struct sockaddr_in*)&(if_list[n].iiAddress);
if (is_unavail_addr(sa)) {
continue;
}
switch (sa->sin_family) {
case AF_INET:
printf("address %s\n", inet_ntoa(sa->sin_addr));
printf("netmask %s\n", inet_ntoa(((struct sockaddr_in*)&if_list[n].iiNetmask)->sin_addr));
ret = TRUE;
goto done;
case AF_INET6:
/* TODO */
goto done;
}
}
done:
return ret;
}
static int get_local_address_v6()
{
DWORD ret;
IP_ADAPTER_ADDRESSES addr[256];/* XXX */
ULONG len = sizeof(addr);
ret = GetAdaptersAddresses(AF_INET6, 0, NULL, addr, &len);
if (ret == ERROR_SUCCESS) {
IP_ADAPTER_ADDRESSES *padap = &addr[0];
do {
IP_ADAPTER_UNICAST_ADDRESS *uni = padap->FirstUnicastAddress;
if (!uni) {
continue;
}
do {
SOCKET_ADDRESS addr = uni->Address;
struct sockaddr_in6 *sa;
if (!(uni->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE)) {
continue;
}
sa = (struct sockaddr_in6*)addr.lpSockaddr;
// assert(sa->sin6_family == AF_INET6);
// int sz = 40;
// *ret_ip = apr_malloc(mp, sz);
// apr_inet_ntop(sa->sin6_family, &sa->sin6_addr, (char*)*ret_ip, sz);
return TRUE;
} while ((uni = uni->Next));
} while ((padap = padap->Next));
}
return FALSE;
}
static int init_winsock()
{
#define WSAHighByte 2
#define WSALowByte 0
int iVersionRequested = MAKEWORD(WSAHighByte, WSALowByte);
WSADATA wsaData;
return WSAStartup((WORD) iVersionRequested, &wsaData);
}
int main(int arg, char **argv)
{
enum_local_nic(); /* no need to call WSAStartup() */
init_winsock();
get_local_address();
// get_local_address_v6();
return 0;
}
以下がMakefileです。上記のファイル名をlocal-address.cとした場合、次のように実行してください。
> nmake local-address.exe > local-address
LIBS = wsock32.lib ws2_32.lib iphlpapi.lib
all : $(TESTS)
.c.exe :
$(CC) $(CFLAGS) /c $<
link /out:$@ $(LIBS) $(LDFLAGS) /subsystem:console $*.obj
.cpp.obj :
$(CC) $(CFLAGS) /c $<
link /out:$@ $(LIBS) $(LDFLAGS) /subsystem:console $*.obj