2. 패킷을 캡쳐하기 위한 libpcap의 fuction

	int main(int argc, char *argv[])
	{
		................
		................

        if (device == NULL ) {
            if ( (device = pcap_lookupdev(ebuf) ) == NULL) {
                perror(ebuf);           
                exit(-1);
            }
        }
        
        pd = pcap_open_live(device, snaplen, PROMISCUOUS, 1000, ebuf);
        if(pd == NULL) {
            perror(ebuf);          
            exit(-1);
        }
        
        i = pcap_snapshot(pd);
        if(snaplen < i) {
            perror(ebuf);                            
            exit(-1);
        }
        
        if(pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
            perror(ebuf);
            exit(-1);
        }
        
        setuid(getuid());
        
        if(pcap_compile(pd, &fcode, filter_rule, 0, netmask) < 0) {
            perror(ebuf);
            exit(-1);
        }
        
        if(pcap_setfilter(pd, &fcode) < 0) {
            perror(ebuf);
            exit(-1);
        }
        
        fflush(stderr);
        
        printer = lookup_printer(pcap_datalink(pd));
        pcap_userdata = 0;
        
        if(pcap_loop(pd, packetcnt, printer, pcap_userdata) < 0) {
            perror("pcap_loop error");
            exit(-1);
        }
        
        pcap_close(pd);
		exit(0);
	}
    

2.1. pcap_lookupdev()

device = pcap_lookupdev(ebuf);

네트웍 디바이스를 가져오는 함수입니다. 패킷을 잡으려면 네트웍 디바이스를 지정해야 겠죠? 가능한 다비이스중 가장 번호가 낮은 디바이스를 가져오게 됩니다. 리눅스라면 eth0이겠죠... 다른 디바이스를 통해 패킷을 캡쳐하려면 이 함수를 사용하지 않고 프로그램의 입력으로 디바이스명을 가져오면 됩니다.

2.2. pcap_open_live()

pd = pcap_open_live(device, snaplen, PROMISCUOUS, 1000, ebuf);

위 함수는 실제 기기를 열어주는 기능을 하는 것으로 snaplen는 패킷당 저장할 바이스 수, 실제 datalink계층부터 패킷의 크기를 계산하여 원하는 부분만을 얻어오면 되는 것입니다. 헤더정보만을 보고싶은데 쓸데없이 데이타까지 받을 필요는 없겠죠. 데이터까지 보고싶으면 snaplen를 크게 하면 됩니다. PROMISCUOUS는 1이며 네트웍 디바이스에 오는 모든 패킷을 받겠다는 의미입니다. 이 모드를 자세하게 설명하면 Ethernet은 모든 패킷이 broadcasting되며 일단 모든 네트웍 디바이스는 동일 네트웍내의 다른 호스트의 패킷도 일단 접하게 됩니다. 그러나, 네트웍 디바이스는 기본적으로 자신의 패킷만을 받게끔 되어있습니다. 그러므로 다른 호스트의 패킷은 버리게 되는 것입니다. 그러나 promiscuous모드로 디바이스 모드를 바꾸게 되면 모든 패킷을 받아들이게 되는 것입니다. 모든 네트워크 모니터링 프로그램들은 모두 이 모드를 사용하게 됩니다. 세 번째 인자는 패킷이 버퍼로 전달될 때 바로 전달되는 것이 아니라 위에서 명시한 시간을 넘겼을 때나 버퍼가 다 채워졌을 때 응용프로그램으로 전달되는 것입니다.

2.3. pcap_lookupnet()

pcap_lookupnet(device, &localnet, &netmask, ebuf)

열려진 패킷 캡쳐 디바이스에 네트웍 주소와 서브넷 마스크를 넘겨줍니다.

2.4. pcap_compile()

pcap_compile(pd, &fcode, filter_rule, 0, netmask)

정해진 필터룰에 의해 필터 프로그램을 컴파일하게 되는데 우리가 원하는 패킷은 필터룰을 주어야만 원하는 패킷만을 얻을 수 있습니다. 실제 tcpdump에서 사용하는 필터룰이 여기에서 쓰입니다. 예를 들면 "tcp port 80" 입니다.

자세한 필터룰에 대한 설명은 tcpdump의 메뉴얼을 보면 알 수 있습니다.

2.5. pcap_setfilter()

pcap_setfilter(pd, &fcode)

위는 앞서 컴파일한 필터 프로그램을 지정해 주는데 사용됩니다. 이렇게 하여 원하는 패킷을 얻을 준비를 하게 됩니다.

2.6. pcap_datalink()

printer = lookup_printer(pcap_datalink(pd));

위는 패킷 캡쳐 디바이스의 datalink계층의 종류를 넘겨 받아 이에 따른 적절한 함수포인터를 할당하게 됩니다.

2.7. pcap_loop()

pcap_loop(pd, packetcnt, printer, pcap_userdata)

실제 패킷을 잡아서 실행할 함수를 지정해 주는 함수입니다. packetcnt의 수만큼 패킷을 잡아서 잡을 때 마다 해당 패킷을 printer가 포인터하는 함수에게 전달하고 함수를 수행하게 됩니다.

packetcnt를 0으로 지정하면 무한대로 함수를 실행합니다.

2.8. pcap_next()

함수형 포인터를 사용하지 않고 함수를 호출할 때마다 패킷을 리턴해주는 함수로 앞의 pcap_datalink()와 pcap_loop()를 대체할 수 있습니다.

사용예는 응용부분4절에서 참고하십시오.