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
沒有留言:
張貼留言