IP 주소와 도메인 이름 사이에서의 변환을 수행하는 시스템을 가리켜 'DNS'라 하며 그 중심에는 DNS서버가 있다.
IP주소 대신 기억하기도 좋고 표현하기도 좋은 형태의 도메인 이름이라는 것을 IP주소에 부여를 함.(ex -> www.naver.com)
도메인 이름은 해다 서버에 부여된 가상의 주소이지 실제 주소가 아니기 때문에 가상주소를 실제 주소로 변환하는 과정을 거쳐서 그 사이트에 접속을 하게 됨
모든 컴퓨터에는 디폴트 DNS서버의 주소가 등록이 되어있고 이것을 통해 도메인 이름에 대한 IP주소 정보를 얻게 됨.
이렇듯 DNS는 계층적으로 관리되는 일종의 분산 데이터베이스 시스템.
IP주소를 계속 유지하는 것은 쉬운일이 아님-> 따라서 도메인 이름에 비해 상대적으로 변경 확률이 높으므로 프로그램을 작성 시, 도메인 이름을 근거로 IP주소를 얻어온 다음에 서버에 접속을 하는 방식으로 프로그램을 짜면 편리함.
#include <netdb.h>
struct hostent* gethostbyname(const char* hostname);
-> 성공 시 hostent 구조체 변수의 주소 값, 실패 시 NULL포인터 반환
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
}
h_name
공식 도메인 이름이라는 것이 저장
h_aliases
하나의 IP에 둘이 상의 도메인 이름을 지정하는 것이 가능하기 때문에 해당 메인 페이지에 접속할 수 있는 다른 도메인 이름의 지정이 가능하고, 이 h_aliases를 통해서 얻을 수 있다.
h_addrtype
IPv4뿐만 아니라 IPv6까지 지원을 하기 때문에 h_addr_list로 반환된 IP주소의 주소체계에 대한 정보를 이 멤버를 ㅌ오해 반환함
h_length
IPv4의 경우 4바이트이므로 4가, IPv6의 경우에는 16바이트이므로 16이 저장됨.
h_addr_list
이것이 가장 중요한 멤버. 이 멤버를 통해서 도메인 이름에 대한 IP주소가 정수의 형태로 반환된다. 하나의 도메인 이름에 대응하는 IP를 여러개 둘 수 있고 이것을 통해 모든 IP의 주소정보를 얻을 수 있다.
gethosbyname.c
#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);
}
마지막의 host->h_addr_list를 출력하는 부분에서 inet_ntoa함수를 사용하는데 그 이유는 h_addr_list가 가리키는 것이 문자열 포인터 배열이며 이것이 실제 가리키는 것이 문자열의 주소 값이 아닌 in_addr 구조체 변수의 주소값이다. 따라서 형변환 및 inet_ntoa함수의 호출을 동반한다.
#include <netdb.h>
struct hostnet * gethostbyaddr(const char* addr, socklen_t len, int family);
- addr : ip주소를 지니는 in_addr 구조체 변수의 포인터 전달.
- len : 첫 번째 인자로 전달된 주소정보의 길이,
- family : 주소체계 정보 전달.
gehostbyaddr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.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;
struct sockaddr_in addr;
if(argc!=2)
{
printf("Usage: %s <IP>\n", argv[0]);
exit(1);
}
memset(&addr, 0 ,sizeof(addr));
addr.sin_addr.s_addr = inet_addr(argv[1]);
host=gethostbyaddr((char*)&addr.sin_addr, 4, AF_INET);
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);
}
inet_addr로 dotted-decimal notation을 빅 엔디안 32비트 값으로 변환한뒤 후에 host->h_addr_list를 가져올 대, 다시 inet_ntoa와 형변환을 하여 출력
#include <winsock2.h>
struct hostent * gethostbyname(const char * name);
struct hostent * gethostbyaddr(const char * addr, int len, int type);
리눅스와 함수적인 것에서 차이가 없음
gethostbyname_win.c
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
void ErrorHandling(char* message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
int i;
struct hostent* host;
if (argc != 2)
{
printf("Usage: %s <addr> \n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error!");
host = gethostbyname(argv[1]);
if (!host)
ErrorHandling("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);
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]));
WSACleanup();
return 0;
}
void ErroHandling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
gethostbyaddr_win.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
void ErrorHandling(char* message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
int i;
struct hostent* host;
SOCKADDR_IN addr;
if (argc != 2)
{
printf("Usage : %s <IP> \n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error!");
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = inet_addr(argv[1]);
host = gethostbyaddr((char*)&addr.sin_addr, 4, AF_INET);
if (!host)
ErrorHandling("gethos... 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]));
WSACleanup();
return 0;
}
void ErroHandling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}