libpcap是一個抓取網絡數據報文的C語言函數庫,使用這個庫能夠很是方便的抓取網絡上的報文,方便咱們分析通過咱們設備上的各類報文;
使用libcap庫編譯時都要在後面加上-lpcap選項網絡
這個函數就是用來探測網絡接口的,它會返回第一個合適的網絡接口字符串指針,若是出錯則在errbuf中返回,長度至少是PCAP_ERRBUF_SIZE。tcp
#include <pcap.h> #include <stdio.h> #include <stdlib.h> int main() { char errBuf[PCAP_ERRBUF_SIZE], * devStr; devStr = pcap_lookupdev(errBuf); if (devStr) printf("success: device: %s\n", devStr); else { printf("error: %s\n", errBuf); exit(1); } return 0; }
注意這個函數是返回第一個合適的網絡接口字符串,個人主機第一個合適的網絡接口爲 vibir0端口,在這個虛擬端口下沒有辦法抓到包,於是要找到指定的端口要要循環遍歷端口後,進行選擇特定網卡端口ide
char * get(){ pcap_if_t *alldevs; pcap_if_t *d; int i=0; char errbuf[PCAP_ERRBUF_SIZE]; /* 獲取本地機器設備列表 */ if (pcap_findalldevs( &alldevs, errbuf ) == -1) { fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); exit(1); } for(d= alldevs; d != NULL; d= d->next) { printf("%d. %s\n", ++i, d->name); } //獲取指定的設備 char getPort[32]; gets(getPort); for(d= alldevs; d != NULL; d= d->next) {if(strcmp(d->name,getPort)==0) { printf("%d. %s", ++i, d->name); break; } } return d->name; }
要捕獲報文,在探測到接口以後咱們還要打開它,該函數會返回指定接口的pcap_t類型指針,後面的全部操做都要使用這個指針;函數
參數一:device是第一步探測到的接口的字符串;工具
參數二:snaplen是對於每一個數據包,從開頭要抓多少個字節,咱們能夠設置這個值來只抓每一個數據包的頭部,而不關心具體的內容。典型的以太網幀長度是1518字節,但其餘的某些協議的數據包會更長一點,但任何一個協議的一個數據包長度都必然小於65535個字節;oop
參數三:promisc指定是否打開混雜模式(Promiscuous Mode),0表示非混雜模式,任何其餘值表示混合模式。若是要打開混雜模式,那麼網卡必須也要打開混雜模式,可使用以下的命令打開例如eth0混雜模式:
ifconfig eth0 promisc;優化
參數四:to_ms指定須要等待的毫秒數,超過這個數值後,第3步獲取數據包的這幾個函數就會當即返回。0表示一直等待直到有數據包到來;spa
參數五:用來返回錯誤信息;.net
釋放網絡接口,用於關閉pcap_open_live()獲取的pcap_t的網絡接口對象並釋放相關資源;指針
該函數收到一個包就馬上返回,返回值爲NULL表示沒有收到包;
第一個參數是第2)個函數pcap_open_live返回的指針,第二個參數記錄了報文長度等,其結構也能夠在pcap.h裏查看到;
第一個參數是第2)個函數pcap_open_live返回的指針,第二個參數是須要抓的數據包的個數,一旦抓到了cnt個數據包,pcap_loop當即返回。負數的cnt表示pcap_loop永遠循環抓包,直到出現錯誤;第三個參數是一個回調函數指針,形式以下:void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet) 第一個參數是pcap_loop的最後一個參數,第二個參數是收到的數據包的pcap_pkthdr結構,第三個參數是數據包數據;
和pcap_loop()很是相似,它同時還受pcap_open_live()的第4個參數to_ms控制超時返回時間;
#include <pcap.h> #include <time.h> #include <stdio.h> #include <stdlib.h> void processPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet) { int *count = (int *)arg; printf("Packet Count: %d\n", ++(*count)); printf("Received Packet Size: %d\n", pkthdr->len); printf("Payload:\n"); for(int i=0; i < pkthdr->len; ++i) //print { printf("%02x ", packet[i]); if ((i + 1) % 16 == 0) { printf("\n"); } } printf("\n\n"); return; } int main() { char errBuf[PCAP_ERRBUF_SIZE], * devStr; devStr = pcap_lookupdev(errBuf); if (devStr) printf("success: device: %s\n", devStr); else { printf("error: %s\n", errBuf); exit(1); } /* open a device, wait until a packet arrives */ pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf); if (!device) { printf("error: pcap_open_live(): %s\n", errBuf); exit(1); } int count = 0; /*Loop forever & call processPacket() for every received packet.*/ pcap_loop(device, -1, processPacket, (u_char *)&count); pcap_close(device); return 0; }
libpcap捕獲報文是把通過的報文複製一份,當接口上報文數量很大時,抓取報文很是的佔用系統資源,經過過濾數據包來捕獲數據包,既能夠過濾掉咱們不想要的報文,又能夠提升效率;
設置過濾條件,就是過濾表達式;
舉例:
src host 192.168.1.177,dst port 80,not tcp等;
fp是一個傳出參數,存放編譯後的bpf,str是過濾表達式,optimize是否須要優化過濾表達式,metmask簡單設置爲0便可;
fp就是前一步pcap_compile()的第二個參數;
struct bpf_program filter; pcap_compile(device, &filter, "tcp", 1, 0); pcap_setfilter(device, &filter);
捕獲到數據包以後,一般就是對數據包的分析,具體的報文分析方法要依據網絡協議詳細分類並展開處理,這裏不作討論。咱們能夠暫時把捕獲到的數據包保存到文件中,稍後再由分析報文的程序或者工具來具體分析;libpcap庫提供了保存爲pcap類型的函數,很是方便,保存以後就能夠用Wireshark直接打開了,若是想保存爲純粹的數據包,咱們也能夠用C語言的文件操做,直接把數據包以二進制的形式保存到文件中;
函數返回pcap_dumper_t類型的指針,file是文件名,能夠是絕對路徑,例如:/home/iona/packet.pcap;
用來關閉pcap_dump_open打開的文件,入參是pcap_dump_open返回的指針;
刷新緩衝區,把捕獲的數據包從緩衝區真正拷貝到文件;
輸出數據到文件,與pcap_loop的第二個參數回調函數void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet) 形式徹底相同,能夠直接當pcap_loop的第二個參數;
#include <pcap.h> #include <time.h> #include <stdio.h> #include <stdlib.h> void processPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet) { pcap_dump(arg, pkthdr, packet); printf("Received Packet Size: %d\n", pkthdr->len); return; } int main() { char errBuf[PCAP_ERRBUF_SIZE], * devStr; devStr = pcap_lookupdev(errBuf); if (devStr) printf("success: device: %s\n", devStr); else { printf("error: %s\n", errBuf); exit(1); } /* open a device, wait until a packet arrives */ pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf); if (!device) { printf("error: pcap_open_live(): %s\n", errBuf); exit(1); } /*open pcap write output file*/ pcap_dumper_t* out_pcap; out_pcap = pcap_dump_open(device,"pack.pcap"); /*Loop forever & call processPacket() for every received packet.*/ pcap_loop(device, 20, processPacket, (u_char *)out_pcap); /*flush buff*/ pcap_dump_flush(out_pcap); pcap_dump_close(out_pcap); pcap_close(device); return 0; }