Wireshark可以在擷取封包時候做過濾,也可以在抓完後封包顯示特定的封包,前者叫做capture filter,後者叫做display filter;而後者是Wireshark的功能,前者則是libpcap本身的功能,那如果在libpcap中讀取儲存的pcap的想要再使用過濾器的話,libpcap提供了user space的過濾方式,語法一模一樣,只是在user space上做過濾。
首先從命令列讀取過濾器表達式。
const char *filter = ""; if(argc == 2) { filter = argv[1]; }//end if
預設過濾器沒有表示不用過濾任何東西,但是當變數
argc
等於2時候,表示命令列有傳參數進來,所以就修改變數filter
指向的位置。然後開啟之前儲存的saved.pcap檔案。
char errbuf[PCAP_ERRBUF_SIZE]; const char *filename = "saved.pcap"; pcap_t *handle = pcap_open_offline(filename, errbuf); if(!handle) { fprintf(stderr, "pcap_open_offline(): %s\n", errbuf); exit(1); }//end if printf("Open: %s\n", filename);
接著將過濾器表達式轉成過濾器,使用函數
pcap_compile()
。//compile filter struct bpf_program fcode; if(-1 == pcap_compile(handle, &fcode, filter, 1, PCAP_NETMASK_UNKNOWN)) { fprintf(stderr, "pcap_compile(): %s\n", pcap_geterr(handle)); pcap_close(handle); exit(1); }//end if if(strlen(filter) != 0) { printf("Filter: %s\n", filter); }//end if
因為是開啟一個檔案,並不知道netmask是什麼,所以用marcos
PCAP_NETMASK_UNKNOWN
。接著就跟一般抓封包方法一樣讀取封包。
int total_amount = 0; int total_bytes = 0; while(1) { struct pcap_pkthdr *header = NULL; const u_char *content = NULL; int ret = pcap_next_ex(handle, &header, &content); if(ret == 1) { if(pcap_offline_filter(&fcode, header, content) != 0) { total_amount++; total_bytes += header->caplen; }//end if match }//end if success else if(ret == 0) { printf("Timeout\n"); }//end if timeout else if(ret == -1) { fprintf(stderr, "pcap_next_ex(): %s\n", pcap_geterr(handle)); }//end if fail else if(ret == -2) { printf("No more packet from file\n"); break; }//end if read no more packet }//end while
當ret==1時候,表示讀取到封包了,接著使用函數
pcap_offline_filter()
來過濾,當回傳值不等於0時表示該封包符合過濾條件。if(ret == 1) { if(pcap_offline_filter(&fcode, header, content) != 0) { total_amount++; total_bytes += header->caplen; }//end if match }//end if success
函數
pcap_offline_filter()
原型:int pcap_offline_filter(const struct bpf_program *program, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);
- 回傳值:符合過濾條件傳回非0數值,不符合傳回0。
- 參數:program過濾器。pkt_header封包的表頭指標。pkt_data封包內容指標。
- 功能:在user space空間上做封包過濾。
這個函數不是只能用在檔案的情況,因為他的功能就是在user space上做過濾,所以即使封包是從一個device抓上來的也可以過濾,當然速度會比較慢。
編譯:
libpcap % gcc -I/usr/local/opt/libpcap/include -Wall -std=gnu99 -L/usr/local/opt/libpcap/lib -lpcap offline-filter.c -o offline-filter
執行結果:
libpcap % ./offline-filter Open: saved.pcap No more packet from file Read: 1000, byte: 232946 bytes libpcap % ./offline-filter arp Open: saved.pcap Filter: arp No more packet from file Read: 4, byte: 168 bytes libpcap % ./offline-filter "tcp or udp" Open: saved.pcap Filter: tcp or udp No more packet from file Read: 937, byte: 228256 bytes libpcap % ./offline-filter "tcp and udp" Open: saved.pcap pcap_compile(): expression rejects all packets
記得當過濾器表達式有空白時,要用雙引號包起來;最後一個剛好是不符合邏輯的一個條件,因為並不會有任何封包同時為TCP和UDP。
Source code on Github
沒有留言:
張貼留言