본문 바로가기

네트워크/리눅스 기반 강의

2010년 12월 15일 수요일 인터넷 주소 변환 & 도메인네임으로 IP주소 알아내기

인터넷 주소 변환
#include <stdio.h>
#include <arpa/inet.h>

int main()
{
  char *addr="1.2.3.4";
  struct sockaddr_in addr_inet;
  if(!inet_aton(addr, &addr_inet.sin_addr))
  {
    printf("Conversion error");
  }
  printf("unsigned long address(network ordered : %x \n", addr_inet.sin_addr);
  return 0;
}
#include <arpa/inet.h>
인터넷 주소 표현 방식에는 도메인 네임, 32비트 IP주소, 십진수(dotted decimal)등 3가지 방식이 있다.
바이트 순서에는 호스트 바이트 순서와 네트웤 바이트 순서 두가지가 있다. 호스트 바이트 순서는 Little-Endian방식과 Big-Endian방식 두가지가 있는데 인텔(80x86)계열이 Little-Endian방식을 사용한다. 네트워크 바이트 순서는 High-order바이트부터 전송하기로 정했다. big-Endian방식과 동일하다. 인텔CPU는 Little-Endian방식이므로 네트워크에 전송할경우 같은값이아닌 반대값이 나오게된다.(1234보내면 3412로 나옴) 그래서 전송을 하기전에 바이트 순서를 함수로 이용하여 바꾸어 주어야된다. 함수는 다음과 같다.
htonl() ☜ host to network 변환(4바이트 unsigned long형)
htons() ☜ host to network 변환(2바이트 unsigned short형)
ntohl() ☜ network to host 변환(4바이트 unsigned long형)
ntohs() ☜ network to host 변환(2바이트 unsigned short형)
※ 주의사항 : 바이트 순서를 맞추는 것이 필요하 경우는 IP주소나 포트번호등의 숫자를 네트워크로 전송할대이며 텍스트나 문서, 바이너리 파일등 일반 사용자 데이터는 변환이 필요없다. 이유는 일반 데이터는 메모리에 저장되었다가 바이트 단위로 메모리 앞 주소부터 차례대로 전송되며 수신측도 차례대로 저장하기 때문이다.

inet_addr() ☜ 32비트 IP주소로 변환시 사용(01111111 00000000 00000000 00000001 이런 식)
inet_aton() ☜ 위와 같으나 addr은 32비트 IP주소를 리턴하는데 이녀석은 두번째 인자로 소켓주소의 포인터를 리턴
inet_ntoa() ☜ IP주소를 dotted decimal로 변환시 사용(127.0.0.1 이런 식)

gethostbyname() 함수로 도메인 네임으로 IP주소 알아내기
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
  struct hostent *myhost;
  struct in_addr myinaddr;  // IP 주소를 저장할 구조체
  int i;
  
  if(argc < 2)
  {
    printf("사용법 : %s host_name\n", argv[0]);
    return 0;
  }

  /* 호스트 이벤트 구조체 구하기 */
  myhost = gethostbyname(argv[1]);
  if(myhost == 0)
  {
    printf("host error\n");
    return 0;
  }

  /* 호스트 이름 출력 */
  printf("official host name : %s \n", myhost->h_name);
  i=0;

  /* 호스트 별명 출력 */
  while(myhost->h_aliases[i] != NULL)
  {
    printf("aliases name : %s\n", myhost->h_aliases[i]);
    i++;
  }

  /* 호스트 주소 타입 출력 */
  printf("host address type : %d\n", myhost->h_addrtype);

  /* 호스트 주소 길이 출력 */
  printf("host address length : %d\n", myhost->h_length);
  
  /* 호스트 주소를 dotted decimal 형태로 출력 */
  i=0;
  while(myhost->h_addr_list[i] != NULL)
  {
    myinaddr.s_addr=*((u_long*)(myhost->h_addr_list[i]));
    printf("IP address : %s \n", inet_ntoa(myinaddr));
    i++;
  }
  return 0;
}#include <netdb.h>
gethostbyname() 함수는 도메인 네임 h_name을 스트리밍 형태로 입력으로 받고 그 이름에
해당하는 호스트의 각종 정보를 가지고 hostent 구조체의 포인터를 리턴한다.
gethostbyaddr() 함수는 IP주소를 포함하고 있는 구조체 in_addr의 포인터와 주소길이, 타입을
입력하여 해당 호스트의 정보를 가지고 있는 hostent 구조체의 포인터를 리턴한다. 아래는 구조체
struct hostent {
char *h_name;        // 호스트 이름
char **h_aliases;    // 호스트 별명
int h_addrtype;      // 호스트 주소의 종류(AF_INET=2 등등등..)
int h_length;        // 주소의 크기(바이트 단위며 IPv4에서는 4임)
char **h_addr_list;  // IP주소 리스트
};
#define h_addr h_addr_list[0]  // 첫번째 주소