數據類型bpf_u_int32實際上就是u_int的一個別名,還有吧bpf_int32實際上就是int的別名。當然這個int是32位的,如果操作系統對int的定義不是4字節,bpf_int32就對應另外一種類型,總之,bpf_u_int32就是一個32位的無符號整型。
關鍵函數:
int pcap_lookupnet(const char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf)
用於獲取網卡的網絡號和子網掩碼。其中device參數是網卡名,netp 和maskp表示將要獲得的網絡號和子網掩碼,都是以網絡字節序存放的,比如一個IP為10.108.20.0,那么netp中存放的這個地址就是:1338378。轉換成二進制就是:
00000000 00010100 01101100 00001010
這個數在內存中的存在形式就是:
低地址----------------------------------------》高地址
00001010 01101100 00010100 00000000
對應每個字節的十進制就是:
10 108 20 0
網絡字節序和主機字節序比較容易混亂(大端表示和小端表示)。
網絡字節序采用大端表示,就是數據的高位要存放到低地址。
而大多數主機字節序采用小端表示(也有采用大端表示的主機字節序),就是數據的低位放到低地址。
比如無符號整型1338378,的二進制表示為:
數據的高位----------------------------》數據的低位
00000000 00010100 01101100 00001010
所以采用小端表示的主機字節序時,內存中存放的形式為:
低地址----------------------------------------》高地址
00001010 01101100 00010100 00000000
errbuf存放錯誤信息。失敗返回-1
errbuf的大小可以定義為:PCAP_ERRBUF_SIZE
pcap_t *pcap_open_live(const char *device, int snaplen,int promisc, int to_ms, char *errbuf)
用於打開網絡設備,返回一個pcap_t結構體的指針。
幫助文檔中的說法是:用於獲取一個數據包捕獲的描述符,以便用來查看網絡上的數據包。device是網卡名稱。snaplen表示捕獲的最大字節數,如果這個值小於被捕獲的數據包的大小,則只顯示前snaplen位(實驗表明,后面為全是0),通常來講數據包的大小不會超過65535。promisc表示是否開啟混雜模式。 to_ms 表示讀取的超時時間,毫秒為單位,就是說沒有必要看到一個數據包這個函數就返回,而是設定一個返回時間,這個時間內可能會讀取很多個數據包,然后一起返回。如果這個值為0,這個函數一直等待足夠多的數據包到來。errbuf用於存儲錯誤信息。
int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask)
用於編譯字符串str成為一個過路程序,program參數是一個指向bpf_program結構體的指針,這個參數由函數pcap_compile()填充。optimize參數用於控制是否采用最優化的結果。netmask用於指定IPv4的網絡子網掩碼,這個參數僅僅在檢查過濾程序中的IPv4廣播地址時才會使用。
int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
用於指定一個過濾器程序,fp是一個指向bpf_program結構體的指針,通常是pcap_compile返回的結果。p通常是pcap_open_live()函數返回的結果。
int pcap_dispatch ( pcap_t * p, int cnt, pcap_handler callback, u_char * user );
這個函數用於收集和加工數據包。cnt指定用於加工的數據包的最大數量,超過了這個數量函數就會返回。當讀取一個實時捕獲的時候,一次僅有一個數據包的緩沖區被讀取,所以處理的數據包的個數有可能少於cnt個。當cnt的值為-1時,會處理到達一個緩沖區的所有數據包,或者(如果不是實時捕獲而是處理一個pcap文件)會處理文件中所有的數據包。 callback指定了一個回調函數。這個回調函數有三個參數:一個u_char類型的指針,這個參數是通過pcap_dispatch()函數傳遞的(應該是提供用戶使用的), 一個指向pcap_pkthdr結構體常量的指針。這個結構體含有三個域,
struct pcap_pkthdr
{
struct timeval ts; ts是一個結構struct timeval,它有兩個部分,第一部分是1900開始以來的秒數,第二部分是當前秒之后的毫秒數。表示數據包捕獲的時間。
bpf_u_int32 caplen; 表示抓到的數據長度
bpf_u_int32 len; 表示數據包的實際長度
}
第二個域是一個u_char常量的指針,指向的一個數據包的前caplen個字節。
成功返回0,失敗返回-1可以用pcap_perror來打印錯誤信息。
注意:當讀取一個實時捕獲時,當讀取超時時pcap_dispatch()函數沒有必要返回。
pcap_loop()函數和pcap_dispatch()用法相似。
int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)
這個函數當讀取超時時也不會返回。
void pcap_close ( pcap_t * p );
用於關閉pcap_open_live()獲取的包捕捉句柄,釋放相關資源。
一個典型的過程:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <pcap.h> #include <arpa/inet.h> #include <unistd.h>//getopt #include <sys/types.h>//u_char void get_packet(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet) { // prase_packet(packet, pkthdr->len); } int main(int argc,char* argv[]) { char* device=NULL; char ch; //getopt() // if((ch = getopt(argc,argv,"d:"))==-1) { printf("no options!!!\n"); exit(1); } optind=1; while ((ch = getopt(argc, argv, "d:")) != -1) { switch (ch) { case 'd': if(optarg!=NULL) { if( ( device = (char*)malloc(strlen(optarg) ) ) !=NULL)//remeber to free { strcpy(device,optarg); //printf("%s\n",device); } else { printf("malloc error\n"); exit(1); } } else { exit(1); } break; case '?': default: printf("Unknown option: %c\n",(char)optopt); exit(1); } } //capture if(!device) { printf("no device\n"); exit(1); } char errBuf[PCAP_ERRBUF_SIZE]; //error Buff // struct pcap_pkthdr packet; The header that pcap gives us pcap_t *phandle; //network interface bpf_u_int32 netp, maskp; //網絡號和子網掩碼 char *net, *mask; struct bpf_program fcode; struct in_addr addr; //look up device network addr and mask //獲取網絡參數 if(pcap_lookupnet(device, &netp, &maskp, errBuf)==-1) { printf("get net failure\n"); exit(1); } addr.s_addr = netp; printf("%u\n",netp); net = inet_ntoa(addr); printf("network: %s\n", net); addr.s_addr = maskp; mask = inet_ntoa(addr); printf("mask: %s\n", mask); //open network device for packet capture phandle = pcap_open_live(device, 65535, 1, 500, errBuf); if(NULL == phandle) { printf("open %s failure\n", device); perror(errBuf); exit(1); } char* filterString="ether src D8:5D:4C:36:76:83 or ether dst D8:5D:4C:36:76:83"; if(pcap_compile(phandle,&fcode,filterString,0,maskp)==-1) { fprintf(stderr,"pcap_compile: %s\n",pcap_geterr(phandle)); exit(1); } if(pcap_setfilter(phandle,&fcode)==-1) { fprintf(stderr,"pcap_setfilter: %s\n",pcap_geterr(phandle)); exit(1); } pcap_loop(phandle, -1, get_packet, NULL); //close device pcap_close(phandle); return 0; }
如果您覺得對您有幫助,請點贊哦^^。
