3-4. 도메인 이름 시스템(DNS)과 이름 변환 함수
01. 도메인 이름 시스템
1) 도메인 이름(Domain name)
→ IP 주소처럼 호스트나 라우터의 고유한 식별자로 사용함.
- IP 주소보다 기억하고 사용하기 쉬움
- TCP/IP 프로토콜에서 Domain name
- TCP/IP 프로토콜은 내부적으로 숫자 형태의 IP주소를 기반하여 동작하므로, 사용자가 입력한 도메인 이름을 반드시 IP 주소로 변환해야 한다.
- 예시를 보면, www.example.com의 실제 주소는 2620:0:2d0:200:10인것을 확인할 수 있다.
2) 도메인 이름 서버(DNS)
→ 도메인 이름과 IP 주소의 변환 정보는 인터넷에 존재하는 여러 DNS가 관리한다.
- 한 DNS 서버가 모든 정보를 갖고 있지 않다는 점에서 일종의 분산 데이터베이스라고 할 수 있다.
02. Domain Name (도메인 이름) ↔ IP 주소 변환 함수
1) gethostbyname() : 도메인이름 → IP주소(네트워크 바이트 정렬)
→ 도메인 name을 주면, IP address를 준다.
/* 도메인 이름 IP 주소(네트워크 바이트 정렬) */
struct hostent *gethostbyname (
const char *name // 도메인 이름
);
반환 : hostent형 구조체 포인터
- 리턴
- hostent 구조체형 포인터
2) gethostbyaddr() : IP주소(네트워크 바이트 정렬) → 도메인 이름
→ IP address를 주면, 도메인 이름을 준다.
struct hostent *gethostbyaddr (
const char *addr, // IP 주소(네트워크 바이트 정렬)
int len, // IP 주소의 길이
int type // 주소 체계(AF_INET 또는 AF_INET6)
);
반환 : hostent형 구조체 포인터
- 리턴
- hostent 구조체형 포인터
3) hostent 구조체
typedef struct hostent {
char* h_name; // official name of host (공식 도메인 이름)
char** h_aliases; // alias list (공식 도메인 외 별명들)
short h_addrtype; // host address type ( 주소 체계)
short h_length; // length of address ( IP 주소 길이 4 or 16)
char** h_addr_list; // list of addresses (IP주소 리스트)
#define h_addr h_addr_list[0] // address, for backward compatibility
} HOSTENT;
- 자료형
- h_name: 공식 도메인 이름(official domain name)
- h_aliases: 한 호스트가 공식 도메인 이름 외에 다른 이름을 여러 개 가질 수 있는데, 이를 별명(alias name)이라고 한다. 호스트가 여러 별명을 가진 경우, 이 포인터를 따라가면 모든 별명을 얻을 수 있다.
- h_addrtype: 주소 체계를 나타내는 값이다. (
AF_INET
또는AF_INET6
) - h_length: IP 주소의 길이(바이트 단위)이다. 4(IPv4)또는 16(IPv6)이 저장된다.
- h_addr_list: 네트워크 바이트 정렬된 IP 주소이다. 한 호스트가 여러 IP 주소를 가진 경우 이 포인터를 따라가면 모든 IP 주소를 얻을 수 있다. 특정 호스트에 접속할 때는 일반적으로 첫번째 IP 주소만 사용하기 때문에
h_addr_list[0]
에 접근하는데, 매크로를 통해 재정의된h_addr
을 사용하면 편하다.
- h_aliases (별명) 와 h_addr_list (IPaddress) (IP)부분의 마지막이
NULL
임을 확인할 수 있다.
03. 사용자 정의 함수
4) GetIPAdd() : 도메인 이름 → IPv4 주소
// 도메인 이름 -> IPv4 주소
BOOL GetIPAddr(char *name, IN_ADDR *addr)
{
//getthostbyname을 호출해 HOSTENT 구조체형 포인터를 얻는다.
HOSTENT *ptr = gethostbyname(name); //도메인 이름을 주면, ip 주소가 담긴 구조체를 return 한느것
if(ptr == NULL){
err_display("gethostbyname()");
return FALSE;
}
if(ptr->h_addrtype != AF_INET) //IPv4가 아니면, FALSE
return FALSE;
//IP주소를 복사한후 TRUE를 리턴한다
//복사받을 메모리, 복사할 메모리, 복사할 데이터 길이
memcpy(addr, ptr->h_addr, ptr->h_length); //H_lenth 길이만큼 읽으면, 4byte만큼 주소를 읽게 될 것
return TRUE;
}
- memcpy첫번째 인자 void* dest**두번째 인자 const void* source**세번째 인자 size_t num
- = 복사할 데이터(값)의 길이(바이트 단위)
- = 복사할 메모리를 가리키고 있는 포인터
- = 복사 받을 메모리를 가리키는 포인터
- void* memcpy (void* dest, const void* source, size_t num)
5) GetDomainName() : IPv4주소 → 도메인 이름
// IPv4 주소 -> 도메인 이름
BOOL GetDomainName(IN_ADDR addr, char *name, int namelen)
{
//gethostbyaddr() 함수를 호출해 HOSTENT 구조체형 포인터를 얻는다.
HOSTENT *ptr = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); //IP주소를 주면, 도메인 이름을 얻어옴.
if(ptr == NULL){
err_display("gethostbyaddr()");
return FALSE;
}
if(ptr->h_addrtype != AF_INET)
return FALSE;
//도메인 이름을 복사한 후 TRUE를 리턴한다.
// 복사받을곳, 복사할곳, 복사할길이
strncpy(name, ptr->h_name, namelen); //H_name이 정식 이름, name에 카피한다. 길이는 namelen만큼.
return TRUE;
}
04.실습
#pragma comment(lib, "ws2_32")
#include <winsock2.h>
#include <stdio.h>
//#define TESTNAME "www.example.com" //이부분을 실제 있는 주소로 바꾸면 실제 도메인 이름까지 확인 가능하다. (www.google.com)
#define TESTNAME "www.google.com"
// 소켓 함수 오류 출력
void err_display(char *msg)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
printf("[%s] %s", msg, (char *)lpMsgBuf);
LocalFree(lpMsgBuf);
}
// 도메인 이름 -> IPv4 주소
BOOL GetIPAddr(char *name, IN_ADDR *addr)
{
HOSTENT *ptr = gethostbyname(name);
if(ptr == NULL){
err_display("gethostbyname()");
return FALSE;
}
if(ptr->h_addrtype != AF_INET)
return FALSE;
memcpy(addr, ptr->h_addr, ptr->h_length);
return TRUE;
}
// IPv4 주소 -> 도메인 이름
BOOL GetDomainName(IN_ADDR addr, char *name, int namelen)
{
HOSTENT *ptr = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
if(ptr == NULL){
err_display("gethostbyaddr()");
return FALSE;
}
if(ptr->h_addrtype != AF_INET)
return FALSE;
strncpy(name, ptr->h_name, namelen);
return TRUE;
}
int main(int argc, char *argv[])
{
WSADATA wsa;
if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 1;
printf("도메인 이름(변환 전) = %s\n", TESTNAME);
// 도메인 이름 -> IP 주소
IN_ADDR addr;
if(GetIPAddr(TESTNAME, &addr)){ //실제 DNS 서비스처럼 해주는 것이다.
// 성공이면 결과 출력
printf("IP 주소(변환 후) = %s\n", inet_ntoa(addr));
// IP 주소 -> 도메인 이름
char name[256];
if(GetDomainName(addr, name, sizeof(name))){ //실제 DNS 서비스처럼 해주는 것이다.
// 성공이면 결과 출력
printf("도메인 이름(다시 변환 후) = %s\n", name);
}
}
WSACleanup();
return 0;
}
'Computer Science > TCP&IP 소켓 프로그래밍' 카테고리의 다른 글
3-3. IP 주소 변환 함수 ( inet_addr, inet_ntoa, WASAddressToString, WSAStringToAddress) (0) | 2023.11.25 |
---|---|
3-2. 바이트 정렬 함수(빅 엔디안, 리틀엔디안, htons, ntohs) (0) | 2023.11.13 |
3-1. 소켓 주소 구조체 다루기 (SOCKADDR, IN_ADDR, sockaddr_in, (0) | 2023.11.13 |
1-2. 소켓(socket)의 개념 (윈도우 소켓) (0) | 2023.09.26 |
댓글