2016年11月5日 星期六

libpcap - Save frames to file(6)


libpcap能夠將封包儲存成檔案,可以之後用Wireshark或其他工具再打開。




函數pcap_dump*開頭的都是跟檔案處理有關的函數。


一樣用預設的device和打開它。
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, 1, errbuf);
if(!handle) {
    fprintf(stderr, "pcap_open_live(): %s\n", errbuf);
    exit(1);
}//end if


接著根據這個handle資訊再打開一個檔案處理的handle。
//open file handler
const char *filename = "saved.pcap";
pcap_dumper_t *dumper = pcap_dump_open(handle, filename);
if(!dumper) {
    fprintf(stderr, "pcap_dump_open(): %s\n", pcap_geterr(handle));
    pcap_close(handle);
    exit(1);
}//end if
    
printf("Saving to %s...\n", filename);

結構pcap_dumper_t *是檔案處理的handle,函數pcap_dump_open()負責打開一個檔案處理handle,第二個參數是要輸出的檔名,這邊用"saved.pcap"當作檔名。

函數pcap_dump_open()原型:
pcap_dumper_t *pcap_dump_open(pcap_t *p, const char *fname);
  • 返回值:成功傳回一個處理檔案的handle,失敗傳回NULL,錯誤訊息從pcap_geterr()取得。
  • 參數:p一個libpcap handle。fname檔案名稱。
  • 功能:打開一個可以處理封包檔案的handle。


用函數pcap_loop()來抓封包,抓1000個封包以及將處理檔案的handle:變數dumper傳入。
//start capture loop
if(0 != pcap_loop(handle, 1000, pcap_callback, (u_char *)dumper)) {
    fprintf(stderr, "pcap_loop(): %s\n", pcap_geterr(handle));
}//end if


接著來看callback部分
static int d = 0;
printf("\rNo.%5d captured", ++d);
fflush(stdout);

一樣將目前抓到第幾個封包列印出來,這邊用了\r,也就是說列印出來後再歸位(carriage return)一次,所以每次列印出來的東西會被下一次列印出來的蓋掉,視覺上就像是在原地遞增數量一樣。(等等看結果就知道了)

函數fflush()是將某個檔案指標內的buffer給清出來,因為之前的函數printf()本身有緩衝區(linux通常是4096,Mac OS X通常是8192),如果在緩衝區滿之前、遇到\n、檔案指標關閉或者程式結束前...等,都不會輸出。

\n也稱為行緩衝,這邊函數printf()並沒有用到,所以有可能並不會立即更新,所以呼叫函數fflush()強迫把stdout緩衝區內的資料清出來。


接著就把封包直接輸出到檔案內。
    //dump to file
    pcap_dump(arg, header, content);

只要呼叫函數pcap_dump(),就可以將封包塞到檔案內。

函數pcap_dump()原型:
void pcap_dump(u_char *user, const pcap_pkthdr *header, const u_char *content);
  • 參數:user處理檔案的handle(從pcap_dump_open()取得)。header封包的表頭資訊。content封包的內容。
  • 功能:將封包丟到檔案內。


抓完封包後,在關檔前還要處理一些事情。
//flush and close
pcap_dump_flush(dumper);
pcap_dump_close(dumper);
printf("\nDone\n");

函數pcap_dump_flush()先將緩衝區內的資料(封包)強迫清空到檔案內,再呼叫函數pcap_dump_close()關檔,雖然pcap_dump_flush()不是必要的,但是可以確保封包可以完全清空。

函數pcap_dump_flush()原型:
int pcap_dump_flush(pcap_dumper_t *p);
  • 返回值:成功傳回0,失敗傳回-1,錯誤訊息從pcap_geterr()取得。
  • 參數:p處理檔案的handle。
  • 功能:將處理檔案handle內的封包全部強迫清到檔案內。

函數pcap_dump_close()原型:
void pcap_dump_close(pcap_dumper_t *p);
  • 參數:p處理檔案的handle。
  • 功能:釋放處理檔案handle的資源。


最後關掉handle。
//free
pcap_close(handle);


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


執行結果(Mac OS X):
libpcap % ./save-to-file 
Sniffing: en0
Saving to saved.pcap...
No. 1000 captured
Done


執行結果(CentOS):
[root@tutu libpcap]# ./save-to-file 
Sniffing: eth0
Saving to saved.pcap...
No. 1000 captured
Done


結果檔案saved.pcap

剛好一千個封包。


Source code on Github

沒有留言:

張貼留言