최상단

컨텐츠

[WinpCap] winpcap 예제..basic_dump.c 분석~!//

글 정보

Category
컴퓨터 이야기
2007. 6. 24. 11:20

본문

며칠전 패킷분석을 많이 했었다는 글을 올리면서..
winpcap 예제들을 주석을 달아서 올려야겠다는 생각을 했습니다.

그 첫번째로 가장 기초가 되는 basic_dump.c 파일을 간단하게 분석했습니다.
완전 초보자가 본다고 생각하고.......

대학교 2학년때 처음 봤을 때는 뭐가 뭔지 하나도 몰랐었는데..
역시 그때 문제는 winpcap이 어렵기 보다....
제가 C를 못해서 그랬던거 같군요;;;...하하...
지금 보니...잘 설계된 라이브러리군요..ㅜㅜ;하하..
하긴...5년전이야기 입니다..-0-;;

시작합니다~~~~


#include "pcap.h"

/* prototype of the packet handler */
// pcap 라이브러리에서 패킷이 도착하면 호출해줄 함수의 프로토타입입니다.
// 즉, 패킷이 도착하면 packet_handler라는 함수가 콜백으로 호출됩니다~~
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];
       
        /* Retrieve the device list */
        // pcap_findalldevs 함수는 시스템이 가지고 있는 모든 네트웍 인터페이스에
        // 대한 정보를 Linked List형태로 생성하여 List의 첫번째 노드의
        // 주소를 첫번째 인자에 넣어 반환해 줍니다.
        if(pcap_findalldevs(&alldevs, errbuf) == -1)
        {
                fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
                exit(1);
        }
       
        /* Print the list */
        // Linked List 이므로 순차적으로 하나씩 검색하면 됩니다.
        // 첫번째의 값은 alldevs에 저장되어 있을 것이고
        // 다음 인터페이스 정보를 담고있는 노드는 alldevs의 next란 놈이 가지고 있겠죠?
        // 마지막 노드의 next는 NULL값을 가집니다
        // 모든 인터페이스를 순회하며 정보를 출력합니다.
        //
        // 참고!
#if 0
        typedef struct pcap_if pcap_if_t;
        struct pcap_if {
                struct pcap_if *next;
                char *name;    
                char *description;  
                struct pcap_addr *addresses;
                u_int flags;        
        };
        typedef struct pcap_addr pcap_addr_t;
        struct pcap_addr {
                struct pcap_addr *next;         // 하나의 인터페이스가
                                                // 여러개의 주소를 가질수 있기 때문에
                                                // 이 부분 역시 리스트입니다.
                struct sockaddr *addr;          
                struct sockaddr *netmask;  
                struct sockaddr *broadaddr;
                struct sockaddr *dstaddr;  
        };
#endif
        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");
                return -1;
        }
       
        // 사용할 인터페이스가 무엇인지 입력 받습니다.
        printf("Enter the interface number (1-%d):",i);
        scanf("%d", &inum);
       
        if(inum < 1 || inum > i)
        {
                printf("\nInterface number out of range.\n");
                /* Free the device list */
                pcap_freealldevs(alldevs);
                return -1;
        }
       
        /* Jump to the selected adapter */
        // Single Linked List이므로 처음부터 순회하며
        // 선택된 인터페이스를 찾아냅니다.
        for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
       
        /* Open the device */
        /* Open the adapter */
        // pcap_open_live를 사용하여 해당 인터페이스를 Open합니다.
        // 아래에서 Promiscuous mode란 자기 MAC주소가 아닌 패킷들까지 다 받아들이는 모드를 말합니다.
        if ((adhandle= pcap_open_live(d->name, // name of the device
                                 65536,             // portion of the packet to capture.
                                                // 65536 grants that the whole packet will be captured on all the MACs.
                                 1,         // promiscuous mode (nonzero means promiscuous)
                                 1000,              // read timeout
                                 errbuf         // error buffer
                                 )) == NULL)
        {
                fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
                /* Free the device list */
                pcap_freealldevs(alldevs);
                return -1;
        }
       
        printf("\nlistening on %s...\n", d->description);
       
        /* At this point, we don't need any more the device list. Free it */
        // 선택된 인터페이스를 pcap_open_live를 통해 열고 그것을 제어하기 위한 Handle을 받았으므로
        // 더 이상 인터페이스에 대한 정보가 필요없습니다.
        // 즉, pcap_findalldevs를 통해 생성되었던 Linked List가 삭제되어야겠죠?..
        // pcap_freealldevs를 통해 Linked List를 지웁니다~
        pcap_freealldevs(alldevs);
       
        /* start the capture */
        // pcap_loop 함수를 호출하게 되면
        // winpcap라이브러리가 무한루프(혹은 정해진 숫자만큼)를 돌면서 패킷이 감지되면
        // 세번째 인자에 해당하는 함수를 호출해줍니다.
        // 즉, 패킷이 도착하면 packet_handler라는 함수가 호출됩니다.
        // pcap_loop의
        // 첫번째 인자 : pcap_open_live를 통해 할당받은 Handler!
        // 두번째 인자 : 얼마만큼의 패킷을 받고 종료될 것인가?.. 0이면 무한루프.
        // 세번째 인자 : 패킷이 도착시 callback해줄 함수(즉..실행될 함수)
        // 네번째 인자 : ???? 모르겠네요.ㅡㅜ
        pcap_loop(adhandle, 0, packet_handler, NULL);
       
        pcap_close(adhandle);
        return 0;
}


/* Callback function invoked by libpcap for every incoming packet */
// 패킷이 유입되었을 때 winpcap에 의해서 호출되는 함수입니다.
//
// u_char *param : 사용자가 정의한 파라미터 값이 넘어옵니다. 아마도 pcap_loop의 마지막 인자값이 아닐까 생각되네요~//
// const struct pcap_pkthdr *header : 캡쳐된 패킷의 정보를 가지고 있는 구조체입니다.
// struct pcap_pkthdr {
//      struct timeval ts;              // 패킷이 캡쳐된 시간입니다.
//      bpf_u_int32 caplen;             // 캡쳐된 패킷의 길이
//      bpf_u_int32 len;                // 실제 패킷의 길이..
//      // caplen과 len이 두가지의 길이 정보가 있는 것은 실제 패킷의 길이에 상관없이
//      // winpcap에서 패킷을 특정 길이만큼만 끊어 캡쳐할 수 있기 때문입니다
//      // pcap_open_live()함수에서 최대 저장 길이를 지정할 수 있습니다.
//};
// const u_char *pkt_data               // 캡쳐된 패킷의 시작 주소.
//                                      // 일반적인 환경에서 가장 앞 부분에는 ethernet header가 붙어있겠죠?
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
        // 아래 내용은 단순히 시간을 출력하고 패킷의 길이를 출력해주는 부분입니다.
        // winpcap과 큰 관련이 없기에 생략~~
        struct tm *ltime;
        char timestr[16];
        time_t local_tv_sec;
       
        /* convert the timestamp to readable format */
        local_tv_sec = header->ts.tv_sec;
        ltime=localtime(&local_tv_sec);
        strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
       
        printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
       
}

행여나 혹시나 궁금한게 있으시면// 질문 남겨주세요..
찾아서라도............쿨럭.;ㅋㅋ

트랙백과 댓글 여닫기

TOP