getifaddrs를 이용한 네트워크 인터페이스 정보 구현
- 최초 작성일: 2023년 3월 10일 (금)
목차
소개
리눅스 환경에서는 네트워크 인터페이스 정보를 가져오기 위해 ifconfig나 ip 명령어를 사용할 수 있다. 그러나 프로그래밍 방식으로는 getifaddrs 함수를 사용하여 더 효율적으로 정보를 얻을 수 있다.
기본 구현 - 리눅스
Wi-Fi 인터페이스의 IP 주소를 가져오는 기본적인 구현이다.
#include <iostream>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vector>
#include <cstring>
std::vector<std::string> get_wifi_ips() {
std::vector<std::string> ips;
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1) {
std::cerr << "Failed to get network interface information.\n";
return ips;
}
for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET &&
strstr(ifa->ifa_name, "wlan") != nullptr) {
struct sockaddr_in *addr = (struct sockaddr_in *) ifa->ifa_addr;
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr->sin_addr, ip_str, INET_ADDRSTRLEN);
ips.push_back(ip_str);
}
}
freeifaddrs(ifaddr);
return ips;
}
실행 결과:
동작 원리:
- 초기화
- getifaddrs 함수로 네트워크 인터페이스 정보를 가져온다
- 실패 시 빈 벡터를 반환한다
- 인터페이스 검색
- 모든 인터페이스를 순회하며 Wi-Fi 인터페이스를 찾는다
- AF_INET(IPv4) 주소 체계만 처리한다
- “wlan” 문자열이 포함된 인터페이스만 선택한다
- IP 주소 변환
- inet_ntop 함수로 IP 주소를 문자열로 변환한다
- 변환된 주소를 벡터에 저장한다
확장 구현 - 모든 인터페이스
모든 네트워크 인터페이스의 상세 정보를 출력하는 확장 구현이다.
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <linux/if_link.h>
#include <string.h>
int main() {
struct ifaddrs *ifaddr, *ifa;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
// Wi-Fi IP 주소 검색
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) {
continue;
}
if (strcmp(ifa->ifa_name, "wlan0") == 0) {
struct sockaddr_in* addr = (struct sockaddr_in*)ifa->ifa_addr;
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN);
printf("Wi-Fi IPv4 Address: %s\n", ip);
break;
}
}
// 모든 인터페이스 정보 출력
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) {
continue;
}
int family = ifa->ifa_addr->sa_family;
printf("%-8s %s (%d)\n",
ifa->ifa_name,
(family == AF_PACKET) ? "AF_PACKET" :
(family == AF_INET) ? "AF_INET" :
(family == AF_INET6) ? "AF_INET6" : "???",
family);
if (family == AF_INET || family == AF_INET6) {
int s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
printf("\t\taddress: <%s>\n", host);
}
}
freeifaddrs(ifaddr);
return 0;
}
실행 결과:
주요 기능:
- Wi-Fi 주소 검색
- wlan0 인터페이스의 IPv4 주소를 찾아 출력한다
- 다른 Wi-Fi 인터페이스 이름을 사용할 경우 수정이 필요하다
- 전체 정보 출력
- 모든 네트워크 인터페이스의 정보를 출력한다
- 인터페이스 이름, 주소 체계, IP 주소를 표시한다
크로스 플랫폼 구현
윈도우와 리눅스 환경에서 모두 동작하는 구현이다.
#include <iostream>
#include <string>
#include <vector>
#ifdef _WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#else
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#endif
std::vector<std::string> getWiFiIPAddresses() {
std::vector<std::string> ipAddresses;
#ifdef _WIN32
ULONG family = AF_INET;
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
ULONG bufferSize = 15000;
PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES *)malloc(bufferSize);
if (pAddresses == NULL) {
return ipAddresses;
}
ULONG ret = GetAdaptersAddresses(family, flags, NULL, pAddresses, &bufferSize);
if (ret != NO_ERROR) {
free(pAddresses);
return ipAddresses;
}
for (PIP_ADAPTER_ADDRESSES pCurr = pAddresses; pCurr; pCurr = pCurr->Next) {
for (PIP_ADAPTER_UNICAST_ADDRESS pUni = pCurr->FirstUnicastAddress;
pUni; pUni = pUni->Next) {
if (pUni->Address.lpSockaddr->sa_family == AF_INET) {
sockaddr_in *sa_in = (sockaddr_in *)pUni->Address.lpSockaddr;
char strBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(sa_in->sin_addr), strBuffer, INET_ADDRSTRLEN);
ipAddresses.push_back(strBuffer);
}
}
}
free(pAddresses);
#else
struct ifaddrs *ifAddrStruct = NULL;
getifaddrs(&ifAddrStruct);
for (struct ifaddrs *ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) {
void *addr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, addr, addressBuffer, INET_ADDRSTRLEN);
ipAddresses.push_back(addressBuffer);
}
}
if (ifAddrStruct != NULL) {
freeifaddrs(ifAddrStruct);
}
#endif
return ipAddresses;
}
구현 세부사항:
- Windows 환경
- GetAdaptersAddresses API를 사용한다
- IP_ADAPTER_ADDRESSES 구조체로 정보를 가져온다
- 모든 유니캐스트 주소를 처리한다
- Linux 환경
- getifaddrs 함수를 사용한다
- ifaddrs 구조체로 정보를 가져온다
- IPv4 주소만 처리한다
- 공통 사항
- inet_ntop 함수로 IP 주소를 문자열로 변환한다
- 결과를 vector
으로 반환한다
결론
네트워크 인터페이스 정보를 가져오는 방법은 운영체제별로 다른 API를 사용해야 한다. 윈도우에서는 GetAdaptersAddresses를, 리눅스에서는 getifaddrs를 사용하여 구현할 수 있다. 이 코드는 두 환경에서 모두 동작하는 크로스 플랫폼 솔루션을 제공하며, 필요에 따라 특정 인터페이스나 주소 체계만 필터링하여 사용할 수 있다.