介紹程序模塊前,這一節再復習一下WinPcap
WinPcap開發一個嗅探器的主要步驟如下:
(1)獲取嗅探設備
WinPcap提供了pcap_findalldevs_ex() 函數來實現這個功能: 這個函數返回一個pcap_if 結構的鏈表,每個這樣的結構都包含了一個適配器的詳細信息:
1 /* 獲取本地機器設備列表 */ 2 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1) 3 { 4 fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); 5 exit(1); 6 }
(2)打開設備,建立嗅探會話
打開設備的函數是 pcap_open() ,snaplen 制定要捕獲數據包中的哪些部分,flag是用來指示適配器是否要被設置成混雜模式,to_ms 指定讀取數據的超時時間,以毫秒計:
1 /* 打開設備 */ 2 if ( (adhandle= pcap_open(d->name, // 設備名 3 65536, // 65535保證能捕獲到不同數據鏈路層上的每個數據包的全部內容 4 PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式 5 1000, // 讀取超時時間 6 NULL, // 遠程機器驗證 7 errbuf // 錯誤緩沖池 8 ) ) == NULL) 9 { 10 fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); 11 /* 釋放設備列表 */ 12 pcap_freealldevs(alldevs); 13 return -1; 14 }
(3)設置過濾器
用來過濾數據包的函數是 pcap_compile() 和 pcap_setfilter(),pcap_compile() 它將一個高層的布爾過濾表達式編譯成一個能夠被過濾引擎所解釋的低層的字節碼,pcap_setfilter() 將一個過濾器與內核捕獲會話向關聯。當 pcap_setfilter() 被調用時,這個過濾器將被應用到來自網絡的所有數據包,並且,所有的符合要求的數據包 (即那些經過過濾器以後,布爾表達式為真的包) ,將會立即復制給應用程序:
1 compile the filter 2 if (pcap_compile(adhandle, &fcode, "ip and tcp", 1, netmask) < 0) 3 { 4 fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n"); 5 /* 釋放設備列表 */ 6 pcap_freealldevs(alldevs); 7 return -1; 8 } 9 10 set the filter 11 if (pcap_setfilter(adhandle, &fcode) < 0) 12 { 13 fprintf(stderr,"\nError setting the filter.\n"); 14 /* 釋放設備列表 */ 15 pcap_freealldevs(alldevs); 16 return -1; 17 }
(4)捕獲網絡數據包
pcap_loop()函數是基於回調的原理來進行數據捕獲,這是一種精妙的方法,並且在某些場合中,它是一種很好的選擇。 然而,處理回調有時候並不實用 -- 它會增加程序的復雜度,特別是在擁有多線程的C++程序中。可以通過直接調用pcap_next_ex() 函數來獲得一個數據包:
1 pcap_next_ex( adhandle, &header, &pkt_data)
返回值的意義如下:
(5)處理網絡數據包
(6)釋放設備列表
void pcap_freealldevs(pcap_if_t * * alldevs // 前面獲取的設備列表)
其流程大致可以概括為這樣:
下一節 MFC+WinPcap編寫一個嗅探器之四(獲取模塊)