Contents

조회 수 10469 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
앞장에서 설명한 패킷 캡쳐 순서를 간략하게 요약하면 다음과 같다.

- 연결된 장치명을 구해 낸다.
char * pcap_lookupdev(char * errbuf); 


- 장치명을 이용해서 해당 장치의 ID를 획득한다.(장치를 연다.)
pcap_t * pcap_open_live(char * device,int snaplen,int promisc,int to_ms, char * ebuf);


- 열린 장치로 부터 패킷이 오길 기다리다 패킷이 도착하면 캡쳐한다.(대기 시간및 캡처 방식은 장치를 열대 설정)
u_char * pcap_next(pcap_t * p,struct pcap_pkthdr * h)


- 이더넷 구조체를 이용해서 이더넷 정보를 읽어 낸다.
struct ether_header * header;


- 장치 ID를 사용해서 열린 장치의 닫는다.
pcap_close(pcap_t * p);

pcap_next()를 통해 캡처한 패킷의 데이타를 사용해서 이더넷 정보를 구하기 위해 구조체를 이용해서 값을 구할수 있는데 이더넷 해더의 마지막 값인 ether_type을 통해 다음에 있을 프로토콜의 타입을 알수 있다.

struct ether_header
{
   u_int8_t  ether_dhost[ETH_ALEN]; //목적지 장치의 주소(물리주소) ETH_ALEN 은 6이다.
   u_int8_t  ether_shost[ETH_ALEN]; //출발지 장치의 주소(물리주소)
   u_int16_6 ether_type;            //프로토콜 ID를 나타낸다.
}

프로토콜의 타입은 /usr/include/net/ethernet.h 에  이더넷 구조체와 함께 정의 되어 있으며 다음과 같다.

ETHERNET_PUP     0x0200   /*Xerox PUP*/
ETHERNET_IP      0x0800   /*IP*/
ETHERNET_ARP     0x0806   /*Address resolution*/
ETHERNET_REVARP  0x8035   /*Reverse ARP*/

와 같이 정의 되어 있으며 이더넷 정보를 담은 구조체를 header라 가정 하면 header->ether_type의 값과 위값을 비교 해서 프로토콜의 타입을 알아 낼수 있다.
여기서 주의 할점은 header->ether_type의 값은 네트워크 바이트인 빅인디안 방식이기 때문에 리틀엔디안 방식을 사용하는 인텔 CUP에서는 리틀 엔디안 방식으로 변형후 비교를 해야한다.
네트워크 바이트 오더를 호스트 바이트 오더인 리틀 엔디안을 변형 시켜주는 함수인 ntohs()를 사용해서 변형 할수 있다. ntohs함수의 기능은 man 페이지를 이용해서 알수 있다.

변형후 에는 다음과 같이 케이스문을 사용하거나  if문을 사용는 등의 비교를 할수 있게 된다. 

switch( ntohs( header->ether_type ) )
{
    case ETHERNET_PUP:
        break;
    case ETHERNET_IP:
        break;
    중략
}

- 아이피 헤더 정보 분석
이더넷 헤더의 프로토콜 타입이 IP 인 경우라면 패킷의 이더넷 다음부분에는 IP 헤더정보가 오게 된다.
IP 헤더는 이더넷과 마찬가지로 헤더 구조체가  존재하며 구조체의 내용은 다음과 같으며 구조체와 프로토콜 타입에 대한 정의는 
/usr/include/netinet/in.h 에 프로토콜에 타입에 대한 정의가 되어 있으며 /usr/include/netinet/ip.h 에 IP구조체가 정의 되어 있다.
ip 구조체의 내용은 다음과 같으며 리틀엔디안과 빅 엔디안의 구조체 맴버가 다르게 설정 되어 있다는 것을 볼수 있다.

struct ip
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ip_hl:4;    /* header length */
    unsigned int ip_v:4;    /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int ip_v:4;    /* version */
    unsigned int ip_hl:4;    /* header length */
#endif
    u_int8_t ip_tos;      /* type of service */
    u_short ip_len;      /* total length */
    u_short ip_id;      /* identification */
    u_short ip_off;      /* fragment offset field */
#define  IP_RF 0x8000      /* reserved fragment flag */
#define  IP_DF 0x4000      /* dont fragment flag */
#define  IP_MF 0x2000      /* more fragments flag */
#define  IP_OFFMASK 0x1fff    /* mask for fragmenting bits */
    u_int8_t ip_ttl;      /* time to live */
    u_int8_t ip_p;      /* protocol */
    u_short ip_sum;      /* checksum */
    struct in_addr ip_src, ip_dst;  /* source and dest address */
  }; 

읽어 들이 패킷정보를 IP구조체가 가리키게 하기 위해선 이더넷 헤더 크기만큼을 이동 해야 한다.

사용예는 다음과 같다.
pcap_next를 통해 구한 패킷의 시작 주소에서 이더넷 해더 만큼을 이동하면 그만이다.

struct ip * IPheader;
IPheader = (IP*)(date+sizeof(struct ether_header));

이후 부턴 IPheader 의 맴버를 통해 IP헤더의 내용을 구할수 있게 된다.

IP헤더는 다음과 같은 내용으로 구성 되어 있다.

VER(버전)                  구조체맴버 =>    IPheader->ip_v
버전을 나타내는 필드로서 IPv4 패킷일 경우에는 4가 들어가고 IPv6일 경우에는 6이 들어가게 된다. 현재는 거의 4를 사용하기 때문에 4로 설정되어 있지만 향후 6이 많이 생기게 되면 6으로 포기될 부분이다.

HLEN (헤더 길이)          구조체맴버 =>    IPheader->ip_hl
IP헤더 길이를 나타내는 필드며 길이는 보통 옵션의 유무에 따라서 20~60바이트 까지로 가변적이다. 이러한 헤더의 길이는 워드 단위로(4바이트) 나누어 나타내며 헤더의 길이가 20바이트라면 20/4 = 5 이기때문에 HLEN의 값은 5가 된다.

Total length(전체 길이)   구조체맴버 =>    IPheader->ip_len
헤더와 데이터 길이를 포함한 전체 길이를 바이트 단위로 나타낸다.
16비트 크기이기 때문에 65535바이트 까지 표현할 수 있지만 네트워크의 물리적 NIC에 의해 제한 받는다.
일반적으로 사용하는 이더넷은 1500 바이트가 최대 이며 46바이트가 최소이다.
참고로 물리 매체에 따라 최대로 보낼수 있는 데이터그램 크기를 MTU(Maximum Transfer Unit)라 부르는데 각 물리 매체에 따른 MTU는 아래와 같다.

  네트워크                      MTU
hyperchannel                  65535
16Mbps token ring(IBM)        17914
4Mbps token ring(IBM)          464
ATM                           9180
FDDI                          4352
Ethernet                      1500
X.25                           576

Identification(식별자)        구조체맴버 =>    IPheader->ip_id

Identification필드는 패킷의 유일한 식별자로서 각각의 IP패킷을 유일하게 구분해 준다.
특히 패킷이 단편화 되었을때 사용되는 부분으로써 어떤 원본의 일부임을 나타내는지를 알리는 부분이기도 하다.
단편화란 물리 매체마다 전송 패킷의 길이가 달라 해당 매체에 맞게 자르는 것을 말하는데 다음에 있을 Flags비트를 이용해서 이 단편화를 하지 못하게 설정할수 있다.
이렇게 설정되어 단편화 되지 못하게 한다면 이패킷은 그곳에서 폐기되며 폐기되었다는 정보를 출발지로 보내게 된다.

Flags(플래그)        구조체맴버 =>    IPheader->ip_off

IPheader->ip_off의 상위 3비트가 Flags 비트이며 3비트중 제일 처음오는 비트는 사용되지 않으며 두번째 오는 비트(Do not fragment)가 1이라면 해당 패킷에 대해서는 단편화할 수 없다는 표시다.
마지막 비트는 More fragment 비트로 이비트가 1로 설정되었다면 패킷이 단편화 되었는데 아직 끝이 아니라는 의미다.

Fragmentation offset(단편화 오프셋)      구조체맴버 =>    IPheader->ip_off
IPheader->ip_off의 상위 3비트를 제외한 나머지 13비트가 단편화 오프셋에 해당된다.

단편화 오프셋은 패킷이 단편화 되었을 때 단편화 순서를 설정하는 부분이다.
1400바이트 짜리 패킷이 최대 데이타 크기 512바이트의 세 개의 패킷으로 단편화 되었다면 단편화 오프셋의 값은 데이터 시작부분의 값에 8을 나눈 값이 된다.
예를 들어 첫번째 단편화 패킷은 데이터의 0바이트 부터 시작하기 때문에 0/8 = 0의 결과에 따라 단편화 오프셋 필드의 값은 0이되고 두번째 패킷은 512 바이트 부터 시작하기 때문에 512/8 = 64의 결과에 따라 64가 된다. 

Time to live(수명)           구조체맴버 =>    IPheader->ip_ttl
Time to live는 줄여서 TTL이라 부르는데 , TTL 값은 패킷이 네트워크 내에서 영원히 떠돌아 다니지 않도록 하기위해 패킷의 생존 기간을 설정하기 위한 필드이다. 처름 설정된 TTL값이 라우터또는 호스트를 하나씩 지나갈때마다 1씩 감소하여 0이되면 해당 패킷을 받은 라우터는 패킷을 버리고 발신지로 ICMP패킷을 보내준다.

Protocol(프로토콜)             구조체맴버 =>    IPheader->ip_p
IP패킷이 담고 있는 데이터가 어떤 프로토콜인지 나타내는 필드다. 해당 프로토콜 분석을 위해서는 
/usr/include/netinet/in.h 내에 정의되어 있는 값을 비교 하면 된다.

Header checksum(헤더 체크섬)   구조체맴버 =>    IPheader->ip_sum
IP 패킷의 헤더가 정상적인지 검사하는 데 사용되는 체크섬 값이 설정된 필드다. 패킷을 받는 목적지 호스트는 체크섬을 확인하여 결과가 다르다면 패킷을 버린다.

Source IP Adderss와 Destination IP Address(발신지 IP와 목적지 IP)
구조체맴버 =>    IPheader->ip_src, IPheader->ip_dst
목적지와 출발지의 IP가 설정되어 있으며 헤더 분석을 위해 값을 보기 위해선 inet_ntoa(IPheader->ip_src)
를 사용해서 네트워크 바이트 오더인 아이피를 .표기 방식으로 바꾸어 문자로 변형해 준후 문자열로 출력하면 확인 할수 있다.

- 패킷 분석을 위한 구조체 사용
패킷의 내용을 분석 하기위해선 구조체의 맴버를 이용해야 하는데 패킷이 네트워크 바이트 오더인 빅엔디안 방식이기 때문에 호스트 오더형인 리틀엔디안으로 변형후 출력하거나 비교 해야 한다. 2바이트 형인 맴버들은 ntohs함수를 사용해 변형해 주어야 하며 IP같은 경우는 inet_ntoa함수를 사용해 변형해 주어야 한다.

변형해 주어야 하는 맴버로는 ip_src,ip_dstip_len,ip_id,ip_off,ip_sum 이 있다.
ip_off 같은 경우 상위 3비트와 하위 13비트를 분리해야 하므로 /usr/include/netinet/ip.h 에 정의 되어 있는 마스크 값을이용해서 &연산을 해서 원하는 값을 비교 할수 있다.

[출처] pcap 을 이용한 패킷 분석( IP 해더 분석 )|작성자 자의누리

?

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
73 System/OS [linux] 프로그램 설치방법 (내공쌓기) hooni 2003.04.23 13788
72 System/OS [linux] 간단한 vi편집기 사용 명령 hooni 2003.04.23 13809
71 System/OS [linux] 기본 명령어 (내공쌓기) hooni 2003.04.23 14676
70 System/OS [linux] 리눅스 활용 팁^^ hooni 2003.04.23 14991
69 System/OS [linux] vi 편집기 간단한 명령과 환경설정 hooni 2003.04.23 11657
68 Develop [unix] 쉘 스크립트 예제 모음 hooni 2003.04.23 15269
67 Develop [linux] 쉘 스크립트를 이용한 BBS hooni 2003.04.23 10295
» Develop [c] pcap을 이용한 패킷 분석 ㅎㅎ hooni 2003.04.23 10469
65 Develop [js] 스크롤을 포함한 마우스 위치 찾는 코드 hooni 2003.04.23 8754
64 Develop [js] 쿠키(cookie)에 대한 설명과 예제.. hooni 2003.04.23 8579
63 Develop [php] URL/URI 관련 환경변수 hooni 2003.04.23 9457
62 Develop [js] 자바스크립트로 응용프로그램 실행 ㅎㅎ hooni 2003.04.23 10074
Board Pagination Prev 1 ... 88 89 90 91 92 93 94 95 96 97 ... 99 Next
/ 99