본문 바로가기

C++/Pcap

pcap_open_live 함수

[1. 원형]

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

 

void pcap_close(pcap_t *p)

 

pcap_t* pcap_loop(pcap_t* p, int cnt, pcap_handler callback, u_char* user)

 

void(* pcap_handler)(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)


[2. 설명]

  • pcap_open_live()
    네트워크 상 패킷을 캡쳐하기 위한 descriptor 를 개방할 때 사용 됨.

    device: 패킷을 캡쳐할 네트워크 디바이스 이름
              리눅스 2.2 이상 커널에서 "any" 또는 NULL 을 사용 한 경우 모든 인터페이스로부터 패킷을 캡쳐 할 수 있다.

    snaplen: 캡쳐하기 위한 최대 바이트 수를 명시한다.
                캡쳐된 바이트 수 보다 적은 값이 주어지면, 해당 바이트까지만 캡쳐된 데이터로 제공 됨
                보통 65535 를 명시하면 모든 패킷에 대해서 캡쳐가 가능함

    promisc: 해당 디바이스를 promiscuous mode 로 개방한다.
                다만, device 이름을 "any" 혹은 NULL 로 명시한 경우, 해당 옵션은 무시된다.

    to_ms: read timeout 을 ms 단위로 명시한다.
             모든 플랫폼에서 지원되지 않을 수 있다.
             0 은 보통 패킷이 도착할 때 까지 기다리는 것을 의미한다.

    함수 호출에 실패한 경우 NULL 이 반환되며, ebuf 에 에러 메시지가 저장된다.

  • pcap_close()
    pcap_open_live() 로 인해 생성된 pcap_t 자료구조에 대한 자원해제를 진행한다.

  • pcap_loop()
    pcap_dispatch() 와 유사하나 다른점은 명시된 개수만큼의 패킷을 읽을 때 까지 유지함.
    read timeout 발생 시에 종료되지 않음.

    p: pcap_open_live() 로 인해 개방된 descriptor 의 주소를 전달

    cnt: 읽을 패킷 개수 명시
          0 이하의 값이면 영원히 읽는다.

    pcap_handler: callback 함수를 명시

    user: 보통 NULL 을 전달함

    에러 발생 시 -1 을 리턴
    pcap_breakloop() 로 종료된 경우 -2 를 리턴
    cnt 만큼 패킷을 읽었을 경우 0 을 리턴한다.

  • pcap_handler 
    pcap_dispatch() 또는 pcap_loop() 이 호출된 경우, 캡쳐된 패킷이 전달 되는 함수의 원형

    struct pkt_header 는 프로토콜에 관련된 헤더가 아닌, capture 된 패킷의 메타 정보 (timestamp, length)
    pkt_data 는 실제 캡쳐된 패킷의 raw data (파싱이 안된 데이터)

[3. 예제]

 

 

#include "pcap.h"
void packet_handler(u_char* param,
const struct pcap_pkthdr* header,
const u_char* pkt_data)
{
printf("caplen: %d\n", header->caplen);
printf("len: %d\n\n", header->len);
}
int main(int argc, char** argv)
{
pcap_t* adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t* alldevs;
pcap_if_t* d;
int i = 0;
int no;
if (pcap_findalldevs(&alldevs, errbuf) < 0) {
printf("pcap_findalldevs error\n");
return 1;
}
for (d = alldevs; d != NULL; d = d->next) {
printf("%d : %s\n", ++i, (d->description) ? (d->description) : (d->name));
}
printf("number : ");
scanf("%d", &no);
for (d = alldevs, i = 0; d != NULL; d = d->next) {
if (no == ++i) {
break;
}
}
if (d == NULL) {
printf("there is no dev\n");
pcap_freealldevs(alldevs);
}
else {
// non-promiscous mode
adhandle = pcap_open_live(d->name, 65535, 0, 1000, errbuf);
if (adhandle == NULL) {
printf("pcap_open_live error %s\n", errbuf);
pcap_freealldevs(alldevs);
return -1;
}
printf("Start: packet capture\n");
pcap_freealldevs(alldevs);
const int ret = pcap_loop(adhandle, 5, packet_handler, NULL);
printf("return of pcap_loop: %d\n", ret);
pcap_close(adhandle);
}
return 0;
}

 

리눅스의 경우 일반 사용자가 위 코드를 실행 시 아래와 같은 에러가 발생할 수 있다.

pcap_open_live error ens33: You don't have permission to capture on that device (socket: Operation not permitted)

 

따라서 보통 관리자 권한으로 실행해야 한다. 

'C++ > Pcap' 카테고리의 다른 글

pcap_dispatch 와 기타 함수 들  (0) 2022.03.09
pcap_lookupnet 함수  (0) 2022.03.06
pcap_findalldevs 함수  (0) 2022.03.06
pcap 개발 환경 설정  (0) 2022.03.06