수업/Network Programming

[Network Programming] Domain Name System(DNS)

hw-ani 2023. 5. 28. 19:08

Domain Name이란?

IP 주소를 대신해 사용할 수 있는 주소이다.

IP 주소를 사용해 서버에 접속하는 것은 번거롭다. 매번 IP 주소 12자리 숫자를 외울 수도 없고, IP는 꽤 변동이 심하기 때문에 서버의 IP가 변경될 때마다 컴파일을 다시해야할 수도 있다.

따라서 간단하게 www.naver.com  처럼 Domain name을 IP 주소 대신 사용할 수 있게하는 것이다.

물론 이 Domain name이 실제 접속에 사용되는 주소는 아니고, Domain name을 IP로 변환해서 접속한다.

 

 

DNS Server란?

위에서 말했듯 Domain name을 IP로 변환하는 과정이 있어야하는데, DNS 서버가 바로 Domain Name을 IP로 변환해주는 서버이다. DNS는 일종의 분산 데이터베이스 시스템이다.

Domain name을 이용해서 서버에 접속하려고 한다면, 접속 이전에 DNS server에 해당 Domain name의 IP 주소를 묻고 거기서 얻은 IP 주소를 이용해서 서버에 접속한다.

 

 

 


gethostbyname

#include <netdb.h>

struct hostent * gethostbyname(const char * hostname);

Domain name을 인자로 받아서, 해당 도메인의 서버 정보를 hostent 구조체 변수에 채워서 반환해주는 함수이다.

인자로 Domain name을 문자열 형태로 전달한다.

 

성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL pointer를 반환한다.

 

 

이 함수가 반환하는 struct hostent는 아래와 같이 선언된다.

struct hostent {
    char * h_name;         //공식 도메인 이름
    char ** h_aliases;     //별칭 도메인 이름
    int h_addrtype;        //반환할 IP의 유형, IPv4를 반환하면 AF_INET이 들어감
    int h_length;          //반환된 IP의 정보 크기, IPv4면 4, IPv6이면 16이 들어감
    char ** h_addr_list;   //IP의 주소 정보, 둘 이상일 경우 모두 반환
}

 

h_aliases와 h_addr_list 멤버는 이중포인터 형태를 띄고 있다. 왜냐하면 이 둘은 두가지 이상의 정보가 들어갈 수도 있기 때문이다. h_addrtype은 문자열의 1차원 배열이고, h_addr_list는 struct in_addr의 1차원 배열이다. 정확히 말하자면, h_addr_list는 IPv4 유형의 주소일때 in_addr 배열이다. polymorphism을 위해 일단 char**로 처리하는 것 같다.

 

 

 

 

 

gethostbyname Example

host = gethostbyname(argv[1]);  //Domain name으로 서버 정보 가져오기
if (!host) error_handling("gethost... error");

//print Official name
printf("Official name: %s\n", host->h_name);

//print Aliases
for (int i=0; host->h_aliases[i]; i++)
    printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);

//print Address 유형
printf("Address type: %s\n", (host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");

//print IP 주소 정보
for (int 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]));

 

Aliases를 프린트할때 host->h_aliases[i]의 끝은 NULL 이란 점을 이용해서 반복문을 돌린다.

또 제일 마지막에 IP 주소 정보를 프린트할 때 inet_ntoa를 쓴다는 것을 알 수 있다. 왜냐하면 h_addr_list가 char** type이긴하지만, 위에서 말했듯 이 경우엔 struct in_addr type의 일차원 배열이기 때문이다.

 

 

 

 

 


gethostbyaddr

#include <netdb.h>

struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family);

위 함수는 Domain name으로 서버 정보를 가져왔다면, 이번엔 IP 주소로 서버 정보를 가져오는 함수이다. 따라서 마찬가지로 struct hostent의 포인터를 반환한다.

첫번째 인자로 IP 주소를 지니는 in_addr 구조체 변수의 주소를 전달한다. IPv4 외에 다양한 정보를 받을 수 있도록 char * 로 일반화 돼있는 것이다.

두번째 인자로 첫번째 인자 안에 있는 주소 정보의 길이를 byte 단위로 전달한다. IPv4라면 4, IPv6이라면 16을 전달한다.

세번째 인자로 address family 정보를 전달한다. IPv4라면 AF_INET, IPv6이라면 AF_INET6을 전달한다.

 

성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL pointer를 반환한다.

 

 

 

struct hostent * type을 반환 받는 것이 같으므로 예제 코드는 생략. 인자를 어떻게 주는지만 좀 다르고 출력하는 부분은 위 예시와 같음.

하나 짚을만한건, in_addr 구조체 변수에 데이터를 넣을 때 sin_addr.s_addr과 sin_zero 멤버에만 데이터를 넣고 나머지 port나 family에는 데이터를 넣지 않는다는 것이다. 아마 IP 주소만 이용해서 데이터를 받아오니까 다른건 안채워도 되나보다. 이런 식으로 하니까 세번째 인자도 필요하겠네.