Domain Name을 IP 주소로 변환하기 (Domain Name Resolution)

작성자 : 김문규
최초 작성일 : 2009. 1.22

1. 들어가며
이번 과제에서 HTTP request의 Referer(레퍼러)를 체크해서 전송 객체 인증을 해야 했습니다. 물론 정해진 프로토콜로 전송 객체의 실제 주소를 암호화해서 보내주고 있었습니다. 그런데, referer 정보는 domain name을 그대로 포함한 채로 전달되는 경우가 많습니다.
그래서, domain name을 DNS 서버를 통해서 resolution 할 필요가 있었습니다.
그리고, 저는 2절에서 소개할 코드를 사용했습니다.

2. 아주 유용한 실전 예제 코드

/* gethostbyname.cpp : Defines the entry point for the console application.
*/
#include <stdio.h>
#ifdef WIN32
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib");
#elif UNIX
#include <netdb.h>   
#include <sys/socket.h>   
#include <arpa/inet.h>   
#include <netinet/in.h>
#endif
int getHostIP(char *domain)
{
 int ret = 0;
 struct hostent *pHost;
 struct in_addr *pAddr;

#ifdef WIN32
 WSADATA wsaData;
 ret = WSAStartup(WINSOCK_VERSION, &wsaData);
 if(ret != 0){
  printf("WSAStartup() failed, error code = %d\n", ret);
  return 300006;
 }
#endif

// 알파벳으로 시작하는 이름일 경우에는 domain name으로 간주합니다.
 if( ((domain[0] > 'A')&&(domain[0] < 'Z')) || ((domain[0] > 'a')&&(domain[0] < 'z')) ) { 
  pHost = gethostbyname(domain);
  if(pHost == NULL){
#ifdef WIN32
   ret = WSAGetLastError();
#endif
   printf("Error in gethostbyname(), error code = %d\n", ret);
   goto HANDLE_ERROR;
  }
  else{
   printf("Official name of the host is: '%s'\n", pHost->h_name);   
   while(*pHost->h_addr_list != NULL){
     pAddr = reinterpret_cast<in_addr *>(*(pHost->h_addr_list));
     printf("%s\n", inet_ntoa(*pAddr));
     pHost->h_addr_list++;
   }

  }
#ifdef WIN32 
  ret = WSACleanup();
  if(ret != 0){
   ret = WSAGetLastError();
   printf("WSACleanup() failed, error code = %d\n", ret);
   goto HANDLE_ERROR;
  }
#endif
  return 0;
 }
else if( (domain[0] > '0')&&(domain[0] < '9') ) { // 첫글자가 숫자일 경우에는 decimal notation으로 표현된 ip 주소라고 가정
  printf("%s\n", domain);
  return 0;
 } else goto HANDLE_ERROR;
HANDLE_ERROR:
#ifdef WIN32
 WSACleanup();
#endif
 return ret;
}
int main(int argc, char **argv)
{
 getHostIP("www.naver.com");
    return 0;
}

적색으로 표시한 것이 핵심이에요~
실제로는 gethostbyname 이라는 함수와 struct hostent,  struct in_addr를 조작해서 결과를 얻어내게 됩니다. 이에 대한 자세한 내용은 아래와 같습니다.

struct hostent {
        char    *h_name;        /* 호스트의 공식 이름 */
        char    **h_aliases;    /* 별칭 리스트 */
        int     h_addrtype;     /* 호스트 주소 타입 */
        int     h_length;       /* 주소의 길이 */
        char    **h_addr_list;  /* 주소 리스트 */
}
#define h_addr  h_addr_list[0]  /* 구 버전과의 호환을 위해 */

struct in_addr {
  union {
    struct {
      u_char s_b1,s_b2,s_b3,s_b4;
    } S_un_b;
    struct {
      u_short s_w1,s_w2;
    } S_un_w;
    u_long S_addr;
  } S_un;
}

#include <netdb.h>
extern int h_errno;
struct hostent *gethostbyname(const char *name);

3. 마치며
네트워크 관련 프로그래밍은 할 때 마다 헷갈립니다. 아무래도 동그라미 쳐 가면서 외워야 겠습니다. ^^