본문 바로가기
  • AI (Artificial Intelligence)
Skills/Network

WIreShark 구현 (4) - IP 헤더 출력구현

by 로샤스 2014. 5. 9.

4. IP 헤더 출력 구현

 

네트워크 계층에 운영되는 IP 프로토콜에는 목적지 위치를 알려주는 고유한 32비트주소 값이 있으며 이를 IP주소라고 한다.

 

IP 헤더는 이더넷헤더 다음에 오게된다.

 

IP헤더에 사용되는 필드

 

 

 

1) Version : IP 버전 

 

2) Header Length : 헤더 길이 정보를 담고 있으며, 단 마지막 필드인 Options 값에 따라 길이가 가변적일 수 있다. 단위는 32비트워드 단위이며, 최소 5에서 최대 15가 될 수 있다.

최소 5인 경우는 고정크기 20바이트(바이트기준 32/8 = 4가 된다. 고로 5로 표기된 경우는 5 *4 = 20바이트를 의미한다.)를 가지며 최대 15인 경우에는 헤더길이가 60바이트가 된다.

 

3) Type Of Service : 서비스 종류를 나타내며, 왼쪽의 3비트는 우선권 필드 이며 다음 3비트는 플래그 비트를 나타낸다. 우선권 필드는 000에서 111번가지 7개를 사용하여 우선권을 정의할 수 있다. 플래그 비트는 D(Delay), T(Throughput), R(Reliability)로 라우터가 사용하는 정보이나 현재는 사용하지 않고 있다.

 

4) Total Length : 헤더와 데이터의 길이를 합한 값이며 최대 65,535바이트가 사용 될 수 있다.

 

5) Identification : 전송할 최대 사이즈를 초과하여 분할된 경우, 분할되기 전, 어떤 패킷에 속한 것인지를 구분하기 위한 고유번호가 할당, 즉 동일한 패키에서 분할된 패킷들은 동일한 ID 값을 가진다.

 

6) Flag : 분할된 추가 패킷이 있다는 것을 알려주며, 해당 정보를 바탕으로 수신측에서는 재조합을 통해 원래의 패킷으로 구성한다.

- 0비트 : 예약 필드로 무저건 0으로 세팅되어야 한다.

- 1비트 : DF(Don't Fragment)비트라고 하며, 분할된 패킷이 없는 경우에 세팅된다.

- 2비트 : MF(More Fragment) 비트라고 하며, 하나의 데이터에서 분할된 조각들은 마지막 조각을 제외하고는 해당 비트를 설정하여 분할된 패킷이 더 있음을 알린다

 

7) Fragment Offset : 수신지에서 재배열하는 과정에서 각 조각의 순서를 파악하는데 사용된다.

 

8) Time to Live : 패킷수명을 제한하기 위해 데이터그램이 통과하는 최대홉수를 지정할 수 있다.

 

9) Protocol : IP헤더에 따라올 상위 프로토콜을 지정하는 것으로 TCP, UDP, ICMP 등을 확인 할 수 있다.

 

10) Header  Checksum : 헤더의 오류를 검증하기 위해 사용

 

11) Source Address : 송신자 IP주소

 

12) Destination Address : 수신자 IP 주소

 

13) Option : 새로운 시럼 혹은 헤더 정보에 추가 정보를 표기 하기위해 설계됨

 

/usr/include/netinet/ip.h

 

 

 

 

 

소스 : ip_header.c

목적 : 이더넷 헤더의 IP 헤더출력

 

 #include <pcap/pcap.h>

#include <stdlib.h>

 

typedef struct mac_address {

u_char byte1;

u_char byte2;

u_char byte3;

u_char byte4;

u_char byte5;

u_char byte6;

}mac;

 

 

#define ETHER_ADDR_LEN 6

struct ether_header

{

u_char ether_dhost[ETHER_ADDR_LEN];

u_char ether_shost[ETHER_ADDR_LEN];

u_short ether_type;

}eth;

 

typedef struct ip_address

{

u_char byte1;

u_char byte2;

u_char byte3;

u_char byte4;

}ip_address;

 

typedef struct ip_header

{

u_char ip_leng:4;

u_char  ip_version:4;

u_char tos; // Type of service 

u_short tlen; // Total length 

u_short identification; // Identification

u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)

u_char ttl; // Time to live

u_char proto; // Protocol

u_short crc; // Header checksum

ip_address saddr; // Source address

ip_address daddr; // Destination address

u_int op_pad; // Option + Padding

}ip_header;

 

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

 

main()

{

pcap_if_t *alldevs;

pcap_if_t *d;

int inum;

int i=0;

pcap_t *adhandle;

char errbuf[PCAP_ERRBUF_SIZE];

u_int netmask;

char packet_filter[] = ""; // 사용자가 원하는 프로토콜 필터 정보를 넣을 수 있는 공간

struct bpf_program fcode; // 특정 프로토콜만을 캡쳐하기 위한 정책정보 저장

 

/*

  네트워크 디바이스 목록을 가져온다.

  alldevs에 리스트 형래토 저장되며, 에러시 errbuf에 에러 내용을 저장한다.

  에러시 에러문을 출력하고 프로그램 종료

*/

if(pcap_findalldevs(&alldevs, errbuf) == -1)

{

fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);

exit(1);

}

 

/*

  pcap_findalldevs()함수를 이용하여 네트워크 디바이스정보를 출력한다.

*/

for(d=alldevs; d; d=d->next)

{

printf("%d. %s", ++i, d->name);

if (d->description)

printf(" (%s)\n", d->description);

else

printf(" (No description available)\n");

}

 

 

if(i==0)

{

//printf("\nNo interfaces found! Make sure WinPcap is installed.\n");

printf("\nNo interfaces found! Make sure LiPcap is installed.\n");

return -1;

}

 

/*

  캡쳐할 네트워크 디바이스를 선택한다.

*/

printf("Enter the interface number (1-%d):",i);

scanf("%d", &inum);

 

/* 입력값의 유효성 판다. */

if(inum < 1 || inum > i)

{

printf("\nAdapter number out of range.\n");

 

pcap_freealldevs(alldevs);

return -1;

}

 

/* 사용자가 선택한 장치 목록을 선택 */

for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

 

/* 실제 네트워크 디바이스 오픈 */

/*                   디바이스명, 최대캡쳐길이, 모든패킷캡쳐, read time, 에러내용 저장변수 */

if((adhandle= pcap_open_live(d->name, 65536, 1,  1000,  errbuf )) == NULL)

{

fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);

pcap_freealldevs(alldevs);

return -1;

}

 

/*

  패킷 필터링 정책을 위해 pcap_compile()함수 호출

  사용자가 정의한 필터링 룰을 bpf_program 구조체에 저장하여 특정 프로토콜 패킷만 수집

*/

if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )

{

fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");

pcap_freealldevs(alldevs);

return -1;

}

 

/*

  pcap_compile() 함수내용을 적용하기 위해  pcap_setfilter() 함수가 사용된다.

*/

if (pcap_setfilter(adhandle, &fcode)<0)

{

fprintf(stderr,"\nError setting the filter.\n");

pcap_freealldevs(alldevs);

return -1;

}

 

// 디바이스 정보 출력

printf("\nlistening on %s...\n", d->description);

 

// 해제

pcap_freealldevs(alldevs);

 

/*

  pcap_loop() 함수를 호출하여 선택한 디바이스를 반복적으로 패킷을 캡쳐하는 역할을 한다.

adhandle : 할당받은 디바이스 특성

0 : 무한르프 

packet_handler는 이더넷 헤더를 출력하는 함수

*/

pcap_loop(adhandle, 0, packet_handler, NULL);

 

return 0;

}

/*

   packet_handler() 함수 이더넷 헤더를 출력하기 위한 내용을 정의.

 */

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)

{

/*

  이더넷 헤더에서 ether_type(상위프로토콜 정보)은 이더넷 헤더 다음에 오는 프로토콜을 알려주는 값

*/

#define IP_HEADER 0x0800

#define ARP_HEADER 0x0806

#define REVERSE_ARP_HEADER 0x0835

 

// int 형의 ptyep변수 선언

unsigned int ptype;

 

/*

  mac 구조체와 동일한 형태를 srcmac, destmac  

  (srcmac 송신자의 MAC주소를 저장.)

  (destmac 수신자의 MAC주소를 저장.)

*/

mac* destmac;

mac* srcmac;

 

/*

  목적지 MAC주소를 저장할 수 있는 구조체인 destmac에 pkt_data(수집된 패킷정보가 저장되어 있으며,

  제일 앞은 이더넷 헤더의 시작위치)를 저장.

*/

destmac = (mac*)pkt_data;

 

/*

  발신자 MAC주소를 담을 수 있는 공간인 srcmac에 수집된 데이터의 시작시점인

  pkt_data에서 6바이트 더한 값을 저장. 즉 송신자의 MAC주소가 저장

*/

srcmac = (mac*)(pkt_data + 6);

 

/* 이더넷 헤더 정보를 담을 수 있는 공간인 ether_header구조체를 eth라고 별칭하였다. */

struct ether_header* eth;

 

/* 이더넷 헤더정보를 eth에 저장 */

eth=(struct   ether_header*)pkt_data;   

 

/* 다음에 따라오는 프로토콜 정보를 ntohs()함수에 넣어 변환을 시킨후 ptype에 저장 */

ptype=ntohs(eth->ether_type);  

 

/* 구조체 ip_header를 ih로 별칭한다. */

ip_header *ih;

 

/* ih에 IP헫 정보를 저장한다. */

ih = (ip_header *)(pkt_data + 14);

 

printf("*************** Ethernet Frame Header *****************\n");

printf("\n");

printf("\n");

/* 발신지 MAC주소 출력 */

printf("Destination Mac Address : %02x.%02x.%02x.%02x.%02x.%02x \n",

destmac->byte1,

destmac->byte2,

destmac->byte3,

destmac->byte4,

destmac->byte5,

destmac->byte6 );       

printf("\n");

/* 수신자 MAC 주소 출력 */

printf("Source Mac Address      : %02x.%02x.%02x.%02x.%02x.%02x \n",

srcmac->byte1,

srcmac->byte2,

srcmac->byte3,

srcmac->byte4,

srcmac->byte5,

srcmac->byte6 );

printf("\n");

 

/* 다음 프로토콜 정보 출력*/

if(ntohs(eth->ether_type) == IP_HEADER)

{

printf("Upper Protocol is IP HEADER(%04x)\n",ptype);

}

else if (ntohs(eth->ether_type) == ARP_HEADER)

{

printf("Upper Protocol is ARP HEADER(%04x)\n",ptype);

}

else if (ntohs(eth->ether_type) == REVERSE_ARP_HEADER)

{

printf("Upper Protocol is REVERSE ARP HEADER(%04x)\n",ptype);

}

else

{

printf("Upper Protocol is Unknown(%04x)\n",ptype);

}

 

 

printf("\n");

 

/* IP헤더에서 버전과 헤더 길이를 출력 */

if(ntohs(eth->ether_type) == IP_HEADER)

{

 

printf("********************** IP Header ***********************\n");

printf("\n");

printf("\n");

printf("ip versioin is %d\n",ih->ip_version);

printf("\n");

printf("ip lengh is %d\n",(ih->ip_leng)*4);

printf("\n");

/* 

  IP헤더에서 목적지 및 발신지 IP정보를 가리키고 있는 필드인

  daddr, sadder의 정보를 이용하여 출력

*/

printf("Destination IP Address : %d.%d.%d.%d \n",

ih->daddr.byte1,

ih->daddr.byte2,

ih->daddr.byte3,

ih->daddr.byte4 );       

printf("\n");

printf("Source IP Address : %d.%d.%d.%d \n",

ih->saddr.byte1,

ih->saddr.byte2,

ih->saddr.byte3,

ih->saddr.byte4 );

printf("\n");

/*

  IP헤더 구조체에 필드 proto를 확인하면, IP헤더 다음에 따라오는 프로토콜 정보를 얻을 수 있다.

  이를 이용하여 헤당 프로토콜를 출력

*/

if(ih->proto == 0x06)

{

printf("Upper Protocol is TCP\n");

printf("\n");

}

else if(ih->proto == 0x11)

{

printf("Upper Protocol is UDP\n");

printf("\n");

}

else if(ih->proto == 0x01)

{

printf("Upper Protocol is ICMP\n");

printf("\n");

}

else 

{

printf("Upper Protocol is Unknown\n");

printf("\n");

}

}

else

{

printf("******************* NO IP Header *********************\n");

printf("\n");

printf("\n");

}

printf("*******************************************************\n");

printf("\n");

printf("\n");

printf("\n");

printf("\n");

printf("\n");

 

}


 

실행

gcc ip_header.c -lpcap

sudo ./a.out

 

- 결과 -

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

출처 : http://blog.naver.com/hjs20613?Redirect=Log&logNo=140188632025

 

 

 

 

댓글