libpcap/use_filter_capture_arp.c

抓封包的時候通常只會針對特定協定有興趣,可以從抓取的封包中解析協定再處理,但是效率較低。libpcap提供了核心層面的過濾器(BPF),而過濾器的表達式與Wireshark的Capture Filter相同(當然囉,因為都是以libpcap開發的)。

Source Code

//
//  use_filter_capture_arp.c
//  功能:只抓取ARP封包。
//  Created by 聲華 陳 on 2016/01/05.
//

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>

void pcap_callback(u_char *arg, const struct pcap_pkthdr *header, const u_char *content);

int main(int argc, const char * argv[]) {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *handle = NULL;
    bpf_u_int32 net, mask;
    struct bpf_program fcode;

    //open interface
    handle = pcap_open_live("en0", 65535, 1, 1, errbuf);
    if(!handle) {
        fprintf(stderr, "pcap_open_live: %s\n", errbuf);
        exit(1);
    }//end if

    //get network and mask
    if(-1 == pcap_lookupnet("en0", &net, &mask, errbuf)) {
        fprintf(stderr, "pcap_lookupnet: %s\n", errbuf);
        pcap_close(handle);
        exit(1);
    }//end if

    //compile filter
    if(-1 == pcap_compile(handle, &fcode, "arp", 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 code
    pcap_freecode(&fcode);

    //start capture loop
    if(0 != pcap_loop(handle, 2, pcap_callback, NULL)) {
        fprintf(stderr, "pcap_loop: %s\n", pcap_geterr(handle));
    }//end if

    //free
    pcap_close(handle);

    return 0;
}

void pcap_callback(u_char *arg, const struct pcap_pkthdr *header, const u_char *content) {
    static int d = 0;
    struct tm *ltime;
    char timestr[16];
    time_t local_tv_sec;

    local_tv_sec = header->ts.tv_sec;
    ltime = localtime(&local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);

    printf("No. %d\n", ++d);

    //print header
    printf("\tTime: %s.%.6d\n", timestr, header->ts.tv_usec);
    printf("\tLength: %d bytes\n", header->len);
    printf("\tCapture length: %d bytes\n", header->caplen);

    //print packet in hex dump
    for(int i = 0 ; i < header->caplen ; i++) {
        printf("%02x ", content[i]);
    }//end for
    printf("\n\n");
}

結果

libpcap % ./use_filter_capture_arp 
No. 1
    Time: 10:46:48.657125
    Length: 42 bytes
    Capture length: 42 bytes
ff ff ff ff ff ff 6c 40 08 bc ae 98 08 06 00 01 08 00 06 04 00 01 6c 40 08 bc ae 98 ac 10 57 7c 00 00 00 00 00 00 ac 10 40 01 

No. 2
    Time: 10:46:48.659438
    Length: 60 bytes
    Capture length: 60 bytes
6c 40 08 bc ae 98 2c 44 fd 7d f0 c1 08 06 00 01 08 00 06 04 00 02 2c 44 fd 7d f0 c1 ac 10 40 01 6c 40 08 bc ae 98 ac 10 57 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

程式只會抓取ARP封包。

分析

    //open interface
    handle = pcap_open_live("en0", 65535, 1, 1, errbuf);
    if(!handle) {
        fprintf(stderr, "pcap_open_live: %s\n", errbuf);
        exit(1);
    }//end if

一樣打開en0抓封包。


    //get network and mask
    if(-1 == pcap_lookupnet("en0", &net, &mask, errbuf)) {
        fprintf(stderr, "pcap_lookupnet: %s\n", errbuf);
        pcap_close(handle);
        exit(1);
    }//end if

利用pcap_lookupnet()取得Interface資訊,等等設定過濾器需要netmask


    //compile filter
    if(-1 == pcap_compile(handle, &fcode, "arp", 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 code
    pcap_freecode(&fcode);

首先使用pcap_compile()產生核心用的過濾器,第三個參數 是"arp"表示說只要ARP封包,這邊產生的過濾器類似於組合語言的結構儲存在變數fcode裡。

產生過濾器後再使用pcap_setfilter()將過濾器apply上去,最後記得要pcap_freecode()

這邊要注意的是,先pcap_compile()pcap_setfilter()才對,因為要先產生核心層看得懂的過濾器,才能夠使用。


    //start capture loop
    if(0 != pcap_loop(handle, 2, pcap_callback, NULL)) {
        fprintf(stderr, "pcap_loop: %s\n", pcap_geterr(handle));
    }//end if

抓取兩個封包就好。


    //free
    pcap_close(handle);

抓完封包一樣要釋放資源。


No. 1
    Time: 10:46:48.657125
    Length: 42 bytes
    Capture length: 42 bytes
ff ff ff ff ff ff 6c 40 08 bc ae 98 08 06 00 01 08 00 06 04 00 01 6c 40 08 bc ae 98 ac 10 57 7c 00 00 00 00 00 00 ac 10 40 01

輸出封包的內容,可以看得出來第13、第14個byte是08 06,這是ARP封包的意思(後面才會解析封包)。

結語

由核心層過濾封包效率較好,但是相對的過濾掉的封包就不會儲存下來,不過一般過濾掉的封包就是不要的,所以也沒什麼影響。

results matching ""

    No results matching ""