IP 주소와 도메인 이름 사이의 변환

도메인 이름을 이용해서 IP 주소 얻어오기

#include <netdb.h>

struct hostent * gethostbyname(const char * hostname);
// 성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환

해당 함수는 hostent 구조체 변수에 담겨서 반환되는데, 이 구조체는 다음과 같이 정의되어 있다.

struct hostent
{
    char * h_name;          // official name
    char ** h_aliases;      // alias list
    int h_addrtype;         // host address type
    int h_length;           // address length
    char ** h_addr_list;    // address list
}

위의 구조체 정의를 보니, IP정보만 반환되는 것이 아니라, 여러가지 다른 정보들도 덤으로 반환되는 것을 알 수 있다. 복잡하게 생각하지 않아도 된다. 도메인 이름을 IP로 변환하는 경우에는 h_addr_list만 신경써도 된다.

  • h_name: 공식 도메인 이름(Ofiicial domain name)이 저장된다.
  • h_alias: 하나의 IP에 매핑된 다른 여러 도메인 이름의 별칭리스트를 반환한다.
  • h_addrtype: IPv4만 아니라 IPv6도 지원한다. IPv4의 경우는 AF_INET이 저장된다.
  • h_length: 함수호출의 결과로 반환된 IP주소의 크기가 담긴다. IPv4는 4바이트, IPv6는 16바이트이다.
  • h_addr_list: 이 멤버를 통해서 도메인 이름에 대한 IP주소가 정수의 형태로 반환된다. 접속자가 많은 서버는 여러 IP주소를 둬서 부하를 분산시킨다.

gethostbyname

다음은 간단한 예제를 보이겠다.

예제

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int i;
    struct hostent *host;
    if(argc != 2)
    {
        printf("Usage : %s <addr>\n", argv[0]);
        exit(1);
    }
    
    host = gethostbyname(argv[1]);
    if(!host)
        error_handling("gethost... error");
    
    printf("Official name: %s \n", host->h_name);
    for(i = 0 ; host -> h_aliases[i] ; i++)
        printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
    printf("Address type: %s \n",
           (host -> h_addrtype == AF_INET)? "AF_INET":"AF_INET6");
    for(i = 0 ; host -> h_addr_list[i] ; i++)
        printf("IP addr %d: %s n", i+1,
               inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

💡 구조체 hostent의 멤버 h_addr_list가 가리키는 배열이 in_addr의 포인터 배열이 아닌, char형 포인터 배열인 이유는, IPv4만 지원하는 것이 아니기 때문이다.
void포인터 배열로 선언되지 않은 이유는 void형 포인터가 표준화되기 이전에 정의되었기 때문이다.

gethostbyaddr

#include <netdb.h>

struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family);
// 성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환
  • addr: IP주소를 지니는 in_addr 구조체 변수의 포인터 전달, IPv4 이외의 다양한 정보를 전달받을 수 있도록 일반화하기 위해서 매개변수를 char형 포인터로 선언.
  • len: 첫 번째 인자로 전달된 주소정보의 길이, IPv4의 경우 4, IPv6의 경우 16
  • family: 주소체계 정보 전달. IPv4의 경우 AF_INET, IPv6의 경우 AF_INET6 전달.

해당 함수의 예제는 생략한다.

윈도우 기반의 gethostbyname, gethostbyaddr

#include <winsock2.h>

struct hostent * gethostbyname(const char * name);
// 성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환
#include <winsock2.h>

struct hostent * gethostbyaddr(const char * addr, int len, int type);
// 성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환