네트워크 및 보안/pcap 파일 분석기 만들기 with C언어

[pcap 파일 분석기 만들기 wich C언어] 4. 패킷 분석기 예광탄 - IPv4 프로토콜 스택 분석

언제나휴일 2016. 5. 22. 10:29
반응형


4. 패킷 분석기 예광탄 - IPv4 프로토콜 스택 분석



안녕하세요. 언제나 휴일, 언휴예요.


지난 게시글에서는 pcap 포멧 파일을 로딩하여 ethernet 프로토콜 스택을 분석하는 예광탄을 만들어 보았어요.


이번에는 IPv4 프로토콜 스택 분석하는 부분을 작성할 거예요. 


빨간색으로 테두리 안에 있는 내용이 이번에 추가한 기능에 의해 출력하는 부분이예요.

패킷 분석기 예광탄 - IPv4 프로토콜 스택 분석 실행화면



현재 작성하는 것이 예광탄이긴 하지만 이미 작성한 부분만 보더라도 헤더 파일없이 소스 코드에만 작성하는 것은 장기적으로 보았을 때 효율이 떨어질 것 같아요. 이번에는 이제까지 작성한 것을 다시 한 번 살펴보면서 헤더 파일과 소스 파일로 구분하기로 할게요. 물론 아직까지는 프로그램 설계는 생략하며 소스 파일을 분할하지는 않을 거예요.


먼저 예광탄에서 사용자 정의 형식 부분은 ehpacket.h 파일에 작성할게요.


이번에 추가한 부분은 IPv4 헤더 부분이예요.


typedef struct _iphdr

{

 버전 정보와 헤더 길이가 4비트씩으로 구성하고 있으며 host byte order가 little endian이라는 가정에서 구조체에 두 개의 멤버의 순서를 바꾸었어요.  

    uchar  hlen : 4; //header length , 1 per 4bytes

    uchar  version : 4; //version , 4

그리고 TOS(Type of Service)라 불렀던 Service 멤버와 전체 길이와 패킷을 구분하기 위한 ID 멤버가 있습니다.

    uchar  service;

    ushort tlen; //total length

    ushort    id; //identification   

이어서 단편화 패킷인지 구분하고 단편화 패킷일 때 단편화 offsets인 멤버가 있어요.  

    ushort    frag;

#define DONT_FRAG(frag)   (frag & 0x40)

#define MORE_FRAG(frag)   (frag & 0x20)

#define FRAG_OFFSET(frag) (ntohs(frag) & (~0x6000))

그리고 경유할 수 있는 최대 라우터 수를 의미하는 TTL과 프로토콜(ICMP, IGMP, TCP, UDP, OSPF)와 체크섬이 있죠. 

    uchar ttl;//time to live

    uchar protocol;

    ushort checksum;

마지막으로 발신지 주소와 목적지 주소가 있습니다.

    uint src_address;

    uint dst_address;

}iphdr;


이제 소스 코드를 살펴보아요.


IPv4 프로토콜을 분석하여 출력하는 ViewIP 부분을 추가합시다.


IPv4 프로토콜 스택에서는 2바이트 단위 영역들의 체크섬을 통해 유효한 패킷임을 증명하는 필드가 있어요. 이를 위한 함수를 만들기로 해요.

ushort ip_checksum(ushort *base, int len);

void ViewIP(char *buf)

{

    IN_ADDR addr;

    iphdr *ip = (iphdr *)buf//패킷 버퍼를 ethernet 구조체 포인터로 형변환

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

먼저 발신지와 목적지 IPv4 주소를 출력하세요.

    addr.s_addr = ip->src_address;   

    printf("src:%s, ", inet_ntoa(addr));

 

    addr.s_addr = ip->dst_address;

    printf("dst:%s\n", inet_ntoa(addr));

 

헤더 길이는 단위가 4바이트입니다. 헤더 길이 필드의 값에 4를 곱하여 바이트 단위로 변환하여 출력합시다.

    printf("header length:%d bytes, ", ip->hlen * 4);

버전 정보, 전체 길이, 패킷 id를 출력하세요.

    printf("version:%d, ", ip->version);

    printf("total length:%d bytes\n", ntohs(ip->tlen));

    printf("id:%d, ", ntohs(ip->id));


단편화 정보는 먼저 단편화 하지 말아야 한다는 DF 값을 먼저 확인하여 출력합시다.

    if (DONT_FRAG(ip->frag))

    {

        printf("Don't Fragment\n");

    }

    else

    {

DF 값이 1일 때는 MF 값으로 같은 패킷 ID의 마지막 패킷인지 출력하세요. MF 값이 1이면 마지막 조각이 아니라는 의미이며 0이면 마지막 조각이라는 의미예요. 물론 단편화하지 않은 패킷도 MF값은 0입니다.

        if (MORE_FRAG(ip->frag) == 0)

        {

            printf("last fragment, ");

        }

단편화 offset도 출력하세요.

        printf("offset:%d "FRAG_OFFSET(ip->frag));

    }

체크섬을 계산하여 체크섬이 정확한지 오류가 있는지 출력하세요.

    if (ip_checksum((ushort *)bufsizeof(iphdr)) == 0)

    {

        printf("checksum is correct, ");

    }

    else

    {

        printf("checksum is not correct, ");

    }

ttl값과 프로토콜을 출력하세요. 

    printf("TTL:%d\n", ip->ttl);

    switch (ip->protocol)

    {

    case 1: printf("ICMP\n"); break;

    case 2: printf("IGMP\n"); break;

    case 6: printf("TCP\n"); break;

    case 17: printf("UDP\n"); break;

    case 89: printf("OSPF\n"); break;

    default: printf("Not support\n"); break;

    }

}

void ViewARP(char *buf)

{

    //to be defined

}


체크섬 계산은 다음과 같습니다.

ushort ip_checksum(ushort *baseint len)

{

    int nleft = len;

    int sum = 0;

    u_short *w = base;

    u_short answer = 0;

    while (nleft>1)

    {

        sum += *w;

        w++;

        nleft -= 2;

    }

 

    if (nleft == 1)

    {

        *(ushort *)(&answer) = *(uchar *)w;

        sum += answer;

    }

    sum = (sum >> 16) + (sum & 0xFFFF);

    sum += (sum >> 16);

    answer = ~sum;

    return (answer);

}


이제 실행해 보시고 잘못 작성한 부분은 수정하세요.


그럼 다음에 봐요.


모두 행복한 하루~


실습에 사용할 pcap 파일(다른 pcap 파일을 사용하셔도 무관합니다.)

demo.pcap


헤더 파일 및 소스 파일

ehpacket.h

Program.c


반응형