TCPIP

2013.06.26_IP헤더구조_

성엽이 2013. 6. 26. 09:35


   ▶ IP헤더구조.

 

(1) Version인터넷 프로토콜 버전으로 IPv4 일 경우 4, IPv6 일 경우 (ex: IPLv4 -> Lv4이기때문에 이진수로 0100 ) 

(2) Header Length: IP 프로토콜 헤더의 길이 ( 4bit ) ( 20byte(4byte 짜리 5개 이므로) 5개를 이진수로 0101 ) 

 

그래서 보통 4 5 로 나옴.


(3) Type Of Service 교환하는 데이터의 종류에 따라 지연 통신효율신뢰성의 우선순위를 지정할 수 있음

                            데이터그램에기대되는 QoS(Quality of Service)를 지시하는 8비트 코드

                            우선권(Precedence)필드(3비트), TOS(Type-Of-Service) 필드(4 비트), 예약 필드(1 비트)

                            우선권 필드는 패킷의우선순위 정의

                            TOS 필드는 최소 지연최대 처리량최대 신뢰성최소 비용을 나타내는 필드, 4비트 중 한비트만1


(4) Total Length : IP의 프로토콜 헤더에 계속되는 데이터도 포함한 IP 패킷의전체길이 (이더넷MTU 1500 byte)

                        옥텟으로나타낸 헤더와 데이터 필드를 포함한 전체 데이터그램의길이


(5) Identification 상위 계층으로부터 각 IP데이터그램을분별하기 위한 식별번호 (패킷이단편화 됐을때사용하는 부분)

(6) Flags : IP데이터그램이분할(Fragment)에 관한 정보를 나타냄

               첫번째비트 사용안함두 번째 비트 : Do not fragment, 세 번째 비트 : More fragment

(7) Fragment Offset 각 프래그먼트의원 데이터에 있어서의 위치를 바이트 단위로 나타냄

 

(8) TTL : Time To Live의 약자로 통과가능한 라우터의남은 수를 나타냄라우터를경유할 때마다 이 값이 하나씩 줄어든다.

            데이터그램이폐기되기 전 인터넷에 얼마동안존속할 수 있는지를 지시하는 값

            각 라우터에의해 감소된다. (값이 0이 되면 데이터그램은 폐기)


(9) Protocol Type 데이터에 포함되는 상위 프로토콜 (TCP:6, UDP:17)의 를 나타냄

                            데이터그램과관련된 상위 계층 프로토콜을 식별
                            
- 1 = ICMP 메시지를 운반
                            
- 6 = TCP 세그먼트를 운반
                            
- 17 = UDP 사용자 데이터그램을운반


(10) Header Checksum : IP 프로토콜 헤더 자체의 내용이 바르게 교환되고 있는가를 점검

                                전송 도중 헤더가 손상되지 않았음을 보장하기 위하여 수신된 패킷내IP 헤더 자체를 검사하는데 사용.


(11) Source IP Address 발신지의 IP Address


(12) Destination IP Address 수신지의 IP Address

 

(13) Option경로배정 및 보안 등과 같은 제어 기능에 사용되는 40 bytes 까지의 부가 정보



 ▶ P_CAP : Packet 을 건져서 정보를 알수 있는 함수.

#include<stdio.h>

#include<pcap/pcap.h>

#include<netinet/ether.h>

#include<netinet/ip.h>


void HexaView(unsigned char *ucP, unsigned int isize);

int L2_IP(void *);


int main()

{

char errbuf[PCAP_ERRBUF_SIZE];

char *cpNIC_Name;

pcap_t *st_Des;

unsigned char uc_data[1500];

//u_char *const

struct pcap_pkthdr st_info;  // 패킷을 가져왔을때의 정보를 저장 : 패킷 헤더.

struct ether_header *stEth; // 헤더 구조체 포인터.


// 네트워크 카드를 찾는 함수. pcap 함수.

// 장치를 찾다가 에러가 생기면 버퍼에 에러메세지를 저장을 해준다.

cpNIC_Name = pcap_lookupdev(errbuf);


if( 0 == cpNIC_Name )

{

printf("Error : %s\n", errbuf);

return 0;

}


printf("==========================================================================\n");

printf("==============================Packet Analyze==============================\n");

printf("==========================================================================\n");

printf("== NIC Name       : [%s]\n",cpNIC_Name);


// pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)


// int snaplen > 1500 MTU(Max Transmission Unit:최대로 전송할수 있는 유닛 단위),

// Ethernet의 최대단위 1500 byte


// int promisc '난잡한' , 1일때 어떠한 패킷이든 다 건져옴.

// 0일때 promisc를 OFF 시키고 내컴퓨터에서 건져옴.


// pcap_open_live 함수는 블로킹함수로 그 대기시간을 적는다. 단위는 ms (ex:1분 = 60000)

// errbuf 에러버퍼

st_Des = pcap_open_live(cpNIC_Name, 1500, 1, 0, errbuf);


if( 0 == st_Des )

{

printf("Error : %s\n", errbuf);

return 0;

}


// 메모리 카피 : 1500byte만큼의 크기를 pcap으로 건져 온 데이터를 uc_data 에 넣어주겠다.

memcpy(uc_data, pcap_next(st_Des, &st_info), sizeof(uc_data));


stEth =(struct ether_header *)uc_data; // 구조체를 가르킴.


printf("==                         Source      ->     Destination\n");            

/* source ether addr    */

printf("== MAC Address    : [%02X:%02X:%02X:%02X:%02X:%02X]->",

stEth->ether_shost[0],

stEth->ether_shost[1],

stEth->ether_shost[2],

stEth->ether_shost[3],

stEth->ether_shost[4],

stEth->ether_shost[5]);


/* destination eth addr */

printf("[%02X:%02X:%02X:%02X:%02X:%02X]\n",

stEth->ether_dhost[0],

stEth->ether_dhost[1],

stEth->ether_dhost[2],

stEth->ether_dhost[3],

stEth->ether_dhost[4],

stEth->ether_dhost[5]);

//printf("----- %s\n",ether_ntoa( (struct ether_addr *)stEth->ether_shost) );

//구조체를 직접 찝어줘서 ether_host (LAN 장치번호)를 알수있다.

/* packet type ID field */

printf("== Packet type    : ");

switch(ntohs(stEth->ether_type))

{

case ETHERTYPE_PUP:

printf("Xerox PUP\n");

break;

case ETHERTYPE_IP:

printf("IP\n");

L2_IP(uc_data+14); // IP Header 의 위치.

break;

case ETHERTYPE_ARP:

printf("Address resolution\n");

break;

case ETHERTYPE_REVARP:

printf("Revers ARP\n");

break;

default :

printf("Unknown %04X\n",ntohs(stEth->ether_type));

break;

}


HexaView(uc_data, 64);


pcap_close(st_Des);


return 0;

}


// Layer 2 의 IP 안에 구조파악.

int L2_IP(void *vp)

{

struct ip *st_IP = vp; // IP 헤더.

printf("== IP Version     : IPv%d\n",

(st_IP->ip_v));

printf("== IP Header size : %d bytes\n",

(st_IP->ip_hl)*4);

// Type of Service를 출력. 

printf("== Type of Service: LOWDELAY        [%s]\n",

( 0 == ((st_IP->ip_tos) & IPTOS_LOWDELAY) ? "NO" : "YES" )   );

printf("==                : Throughput      [%s]\n", 

( 0 == ((st_IP->ip_tos) & IPTOS_THROUGHPUT) ? "NO" : "YES" )   );


printf("==                : Reliability     [%s]\n",

( 0 == ((st_IP->ip_tos) & IPTOS_RELIABILITY) ? "NO" : "YES" )   );


printf("==                : Low Cost        [%s]\n",

( 0 == ((st_IP->ip_tos) & IPTOS_LOWCOST) ? "NO" : "YES" )   );


printf("==                : Min Cost        [%s]\n",

( 0 == ((st_IP->ip_tos) & IPTOS_MINCOST) ? "NO" : "YES" )   );

// Total Length 출력

printf("== Total Length   : %d bytes\n",

ntohs(st_IP->ip_len));


printf("== Identification : %04X\n",

ntohs(st_IP->ip_id));


printf("== Flag           : More Fragment   [%s]\n",

( 0 == ((st_IP->ip_off) & IP_MF) ? "NO" : "YES" )   );


printf("== Flag           : Don't Fragment  [%s]\n",

( 0 == ((st_IP->ip_off) & IP_DF) ? "NO" : "YES" )   );


return 0;

}

void HexaView(unsigned char *ucP, unsigned int isize)

{

int iCnt;

int iloop;


printf("----------------------------------------"

"----------------------------------\n");

printf("Address  \t\t\tHexa\t\t\t      ASCII\n"); 

printf("\t ");



for(iCnt=0 ; iCnt <= 15 ; iCnt++)

{

printf("%02X ", iCnt);

}


putchar('\n');


printf("----------------------------------------"

"----------------------------------\n");


if( 0 == isize%16 )

{

isize = isize / 16;

}

else

{

isize = (isize/16) + 1;

}


for(iloop=0; iloop < isize; iloop++)

{

printf("%08X ", ucP); 


for( iCnt=0 ; iCnt <= 15 ; iCnt++)

{

printf("%02X ", *(ucP+iCnt));

}


for( iCnt=0 ; iCnt <= 15 ; iCnt++ )

{

if(0 == *(ucP+iCnt))

{

printf(".");

}

else if( 32 > *(ucP+iCnt))

{

printf(".");

}

else if( 127 < *(ucP+iCnt))

{

printf(".");

}

else

{

printf("%c", *(ucP+iCnt)); 

}

}

putchar('\n');

ucP = ucP + 16;

}

}

 : 출력 화면



: vi ~/.bashrc




: IP 구조체 



: ip_v:4 같은 경우는 8bit 중에 4bit 만 쓰겠다는 명령어. ip_hl 도 마찬가지.

: ip_v    = IP Version -> 4bit +

: ip_hl   = Header Length -> 4bit +

: ip_tos = Type of Service -> 8bit +

: ip_len = Total Length -> 16bit  = 32bit = 4byte 를 가짐.

: ip_id   = Identification -> 16bit

: ip_off  = Flag -> 3bit

[출처] IP 헤더 구조|작성자 착한꽁치