2017年1月20日 星期五

libpcap - Get stats(16)


libpcap可以讀取一些數據供讀取,像是封包掉的資訊。




一樣開啟預設的device,然後隨意抓個封包,timeout訂在5000毫秒,過濾器用"tcp or udp"。
    char errbuf[PCAP_ERRBUF_SIZE];
    char *device = NULL;

    //get default interface name
    device = pcap_lookupdev(errbuf);
    if(!device) {
        fprintf(stderr, "pcap_lookupdev(): %s\n", errbuf);
        exit(1);
    }//end if

    printf("Sniffing: %s\n", device);

    //open interface
    pcap_t *handle = pcap_open_live(device, 65535, 1, 5000, errbuf);
    if(!handle) {
        fprintf(stderr, "pcap_open_live(): %s\n", errbuf);
        exit(1);
    }//end if
    
    //generate bpf filter
    bpf_u_int32 net, mask;
    struct bpf_program fcode;

    //get network and mask
    if(-1 == pcap_lookupnet(device, &net, &mask, errbuf)) {
        fprintf(stderr, "pcap_lookupnet(): %s\n", errbuf);
        mask = PCAP_NETMASK_UNKNOWN;
    }//end if
    
    //compile filter
    if(-1 == pcap_compile(handle, &fcode, "tcp or udp", 1, mask)) {
        fprintf(stderr, "pcap_compile(): %s\n", pcap_geterr(handle));
        pcap_close(handle);
        exit(1);
    }//end if
    
    //set filter
    if(-1 == pcap_setfilter(handle, &fcode)) {
        fprintf(stderr, "pcap_pcap_setfilter(): %s\n", pcap_geterr(handle));
        pcap_freecode(&fcode);
        pcap_close(handle);
        exit(1);
    }//end if
    
    //free bpf code
    pcap_freecode(&fcode);
    
    //start capture
    int capture = 0;
    pcap_dispatch(handle, -1, pcap_callback, (u_char *)&capture);

其中變數capture是用來記錄目前抓到幾個封包了。


而callback只是單純紀錄抓到幾個封包了,要小心指標轉型。
static void pcap_callback(u_char *arg, const struct pcap_pkthdr *header, const u_char *content) {
    int *capture = (int *)arg;
    (*capture)++;
    return;
}//end pcap_callback


函數pcap_stats()可以抓取一些數據出來。
    //get stat
    struct pcap_stat ps;
    if(pcap_stats(handle, &ps) != 0) {
        fprintf(stderr, "pcap_stats(): %s\n", pcap_geterr(handle));
    }//end if
    else {
        printf("Receive: %d\n", capture);
        printf("Receive by filter: %d\n", ps.ps_recv);
        printf("Drop by kernel: %d\n", ps.ps_drop);
        printf("Drop by interface: %d\n", ps.ps_ifdrop);
    }//end else

要注意的是成員ps_recv是原本的封包數量,變數capture則是被過濾後命中條件的封包數量。

函數pcap_stats()原型:
int pcap_stats(pcap_t *p, struct pcap_stat *ps);
  • 回傳值:成功傳回0,失敗傳回-1,錯誤訊息從pcap_geterr()取得。
  • 參數:p一個libpcap handle。ps數據結果指標。
  • 功能:取得目前數據,不能用在檔案。

結構struct stat宣告:
/*
 * As returned by the pcap_stats()
 */
struct pcap_stat {
 u_int ps_recv;  /* number of packets received */
 u_int ps_drop;  /* number of packets dropped */
 u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */
#ifdef WIN32
 u_int bs_capt;  /* number of packets that reach the application */
#endif /* WIN32 */
};


編譯:
libpcap % gcc -I/usr/local/opt/libpcap/include -Wall -std=gnu99 -L/usr/local/opt/libpcap/lib -lpcap  get-stat.c -o get-stat


執行結果:
libpcap % ./get-stat
Sniffing: en0
Receive: 343
Receive by filter: 358
Drop by kernel: 0
Drop by interface: 0

在這timeout前總共358個封包接收到,343個封包符合"tcp or udp"條件,0個被丟棄。

Source code on Github


沒有留言:

張貼留言