외로운 Nova의 작업실

c 소켓프로그래밍 공부 - 7(도메인으로 ip요청) 본문

Programming/C

c 소켓프로그래밍 공부 - 7(도메인으로 ip요청)

Nova_ 2022. 3. 24. 19:52

안녕하세요, 오늘은 지난 시간에 이어 DNS와 관련된 함수를 배워보도록하겠습니다.

먼저 DNS란 Domain Name System의 약자로 IP를 문자(Name)으로 알 수 있게 해주는 시스템입니다.

컴퓨터의 세계에서 통신은 잘 알다시피 IP로 진행을 합니다.

다만 이 IP는 사람이 잘 기억하지못합니다.

예를들어 구글 서버의 IP는 142.250.199.68입니다.

만약 DNS가 없었다면 우리는 구글링을 할때 항상 142.250.199.48을 쳐서 구글서버에 요청을 보낼것입니다.

그렇다면 질문하겠습니다. google을 외우기 편할까요? 아니면 142.250.199.48이 외우기 편할까요?

사람이라면 문자를 배웠다면 당연히 google이 편합니다.

이처럼 사람들이 편리하게 서버를 찾고 통신하기 위해 DNS라는 시스템을 만들었습니다.

실제로 우리가 URL에 www.naver.com  을 치고들어갈때, 우리의 컴퓨터는 먼저 DNS서버를 찾습니다.

그리고는 DNS서버에서 네이버의 ip를 알아옵니다.

그 다음에서야 실제로 ip와의 연결을 진행합니다.

우리는 모르고있었지만 컴퓨터 세계에선 여러가지 일들이 벌어지고있습니다.

 

소켓프로그래밍에서도 마찬가지입니다.

코드 짤때 sockaddr.sin_addr.s_addr = www.naver.com   을 입력하면 당연히 안됩니다.

www.naver.com 을 DNS서버에게 물어봐서 ip주소를 를 얻어온다음 구조체 멤버에 넣어야합니다.

 

이번시간에는 DNS에게 ip를 요청하고 ip를 받아오는 함수를 배워보도록 하겠습니다.

아래는 DNS에게 ip를 요청하고 ip를 받아오는 함수입니다.

struct hostent* gethostbyname(const char* name);
//name의 ip주소를 hostent 구조체에 넣어서 구조체를 반환한다.

//아래는 hostent구조체의 정의
struct hostent{
    char* h_name; 	  	  //official name
    char* h_aliases[]; 	  //한 ip에 등록된 여러가지 도메인 이름이 있어서 이들을 저장하는 멤버
    int h_addrtype; 	  //host address type ex)AF_INET IPv4
    int h_length; 		  //address length 반환된 ip주소의 길이
    char* h_addr_list[]   //한 도메인에 여러가지 ip들이 있어서 이들을 저장하는 멤버
}
//단 코드에서 구조체를 직접 만들지못하고 hostent* 포인터 변수로 참조만 할 수 있다.

위 함수를 쓰면 되긴하는데 사용자가 버퍼오버플로우를 일으킬 수 있기때문에 아래와 같은 함수로 대체하도록 요즘은 권하고있습니다.

#inlcude <ws2tcpip.h>
//도메인 네임으로 ip를 얻어오는 함수
int getaddrinfo(char* hostname, char* service, struct addrinfo* hint, struct addrinfo **result)
//정상작동하면 0을 반환하고 아니면 다른걸 반환한다.
//아래는 함수인자 설명
//char* hostname : ip를 받아올 호스트이름 문자열
//char* service : 포트번호 문자열, 보통 https포트는 80번 포트이다.
//struct addrinfo* hint : 받아올 주소의 유형을 설정한 구조체
//struct addrinfo **result : 유형대로 받아온 주소를 넣을 구조체의 포인터의 포인터

//아래는 addrinfo 구조체의 정의이다
struct addrinfo{
    int ai_flags;				//추가적인 옵션을 정의할때 사용함
    int ai_familiy; 			//address family를 나타냄 AF_INET, AF_INET6, AF_UNSPEC등등
    int ai_socktype; 			//socket_type을 나타냄 SOCK_STRAM, SOCK_DGRAM
    int ai_protocol;			//특정 프로토콜을 나타냄 IPPROTO_TCP 등등
    socklen_t ai_addrlen;		//socket주소인 ai_adrr의 길이를 나타냄
    char* aicanonname; 			//canonical name을 나타냄
    struct sockaddr *ai_addr;	//SOCKADDR 구조체 포인터
    struct addrinfo *ai_next 	//다음addrinfo 데이터에대한 포인터
}


//아래는 addrinfo구조체 메모리의 초기화 함수
freeaddrinfo(struct addrinfo *res); 
//사용후 초기화를 하지않으면 메모리 누수현상이 발생한다(사용하지않으면서 메모리가 차있는 현상)

 

이 함수를 통해서 ip주소를 출력하고싶어서 아래와 같은 코드를 짯습니다.

#include <stdio.h>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <string.h>

int main(int argc, char* argv[]) {

	struct addrinfo hint; //힌트를 담을 구조체 선언
	struct addrinfo *result; //결과값을 담을 구조체 포인터 선언
	int check = 0; //getaddrinfo함수의 반환형을 담을 변수
	int address = 0;

	memset(&hint, 0, sizeof(hint));
	hint.ai_family = AF_INET;
	hint.ai_socktype = SOCK_STREAM;

	check = getaddrinfo("www.naver.com", "80", &hint, &result);

	printf("naver의 ip주소 : %d", ((SOCKADDR_IN*)&(result->ai_addr))->sin_addr.s_addr);

	freeaddrinfo(result);


}

하지만 에러가 나타났습니다.

아래는 에러 사진입니다.

읽기 엑세스 위반이라고 뜨면서 안됩니다..

뭐가 문제인지 잘모르겠습니다..

해결방법에대해서 내일 이어서 해결해볼까합니다.

혹시라도 해결방법을 알고계신분은 댓글로 알려주시면 감사하겠습니다.

Comments