因為已經知道如何獲取適配器的信息,所以可以打開適配器并捕獲數據包。將每一個通過適配器的數據包打印出來。
打開設備的函數是 pcap_open()。 在一些操作系統中 (比如 xBSD 和 Win32), 驅動可以被配置成只捕獲數據包的初始化部分: 這樣可以減少應用程序間復制數據的量,從而提高捕獲效率。將值定為65535,它比我們能遇到的最大的MTU還要大。因此,總能收到完整的數據包。
flags: 最最重要的flag是用來指示適配器是否要被設置成混雜模式。 一般情況下,適配器只接收發給它自己的數據包, 而那些在其他機器之間通訊的數據包,將會被丟棄。 相反,如果適配器是混雜模式,那么不管這個數據包是不是發給我的,我都會去捕獲。也就是說,我會去捕獲所有的數據包。 這意味著在一個共享媒介(比如總線型以太網),WinPcap能捕獲其他主機的所有的數據包。 大多數用于數據捕獲的應用程序都會將適配器設置成混雜模式,所以,我們也會在下面的范例中,使用混雜模式。
to_ms 指定讀取數據的超時時間,以毫秒計(1s=1000ms)。在適配器上進行讀取操作(比如用 pcap_dispatch() 或pcap_next_ex()) 都會在 to_ms 毫秒時間內響應,即使在網絡上沒有可用的數據包。 在統計模式下,to_ms 還可以用來定義統計的時間間隔。 將 to_ms 設置為0意味著沒有超時,那么如果沒有數據包到達的話,讀操作將永遠不會返回。 如果設置成-1,則情況恰好相反,無論有沒有數據包到達,讀操作都會立即返回。
// 4002.cpp : 定義控制臺應用程序的入口點。
//
#include "stdafx.h"
#include "pcap.h"
/* packet handler 函數原型 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
int _tmain(int argc, _TCHAR* argv[])
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
/* 獲取本機設備列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* 打印列表 */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* 釋放設備列表 */
pcap_freealldevs(alldevs);
return -1;
}
/* 跳轉到選中的適配器 */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
/* 打開設備 */
if ( (adhandle= pcap_open(d->name, // 設備名
65536, // 65535保證能捕獲到不同數據鏈路層上的每個數據包的全部內容
PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式
1000, // 讀取超時時間
NULL, // 遠程機器驗證
errbuf // 錯誤緩沖池
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 釋放設備列表 */
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d->description);
/* 釋放設備列表 */
pcap_freealldevs(alldevs);
/* 開始捕獲 */
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
/* 每次捕獲到數據包時,libpcap都會自動調用這個回調函數 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm *ltime;
char timestr[16];
time_t local_tv_sec;
/* 將時間戳轉換成可識別的格式 */
local_tv_sec = header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
}


當適配器被打開,捕獲工作就可以用 pcap_dispatch() 或 pcap_loop()進行。 這兩個函數非常的相似,區別就是 pcap_ dispatch() 當超時時間到了(timeout expires)就返回 (盡管不能保證) ,而 pcap_loop() 不會因此而返回,只有當 cnt 數據包被捕獲,所以,pcap_loop()會在一小段時間內,阻塞網絡的利用。pcap_loop()對于我們這個簡單的范例來說,可以滿足需求,不過, pcap_dispatch() 函數一般用于比較復雜的程序中。
這兩個函數都有一個 回調 參數, packet_handler指向一個可以接收數據包的函數。 這個函數會在收到每個新的數據包并收到一個通用狀態時被libpcap所調用 ( 與函數 pcap_loop() 和 pcap_dispatch() 中的 user 參數相似),數據包的首部一般有一些諸如時間戳,數據包長度的信息,還有包含了協議首部的實際數據。 注意:冗余校驗碼CRC不再支持,因為幀到達適配器,并經過校驗確認以后,適配器就會將CRC刪除,與此同時,大部分適配器會直接丟棄CRC錯誤的數據包,所以,WinPcap沒法捕獲到它們。
上面的程序將每一個數據包的時間戳和長度從 pcap_pkthdr 的首部解析出來,并打印在屏幕上。
注意事項:
項目-->**屬性(alt+F7)
配置屬性-->清單工具-->輸入和輸出-->嵌入清單-->否
項目-->**屬性(alt+F7)
配置屬性-->C/C++-->常規-->附加包含目錄-->(include)
項目-->**屬性(alt+F7)
配置屬性-->鏈接器-->常規-->附加庫目錄-->(lib)
項目-->**屬性(alt+F7)
配置屬性-->鏈接器-->輸入-->附加依賴項-->補充“;Packet.lib;wpcap.lib”
項目-->**屬性(alt+F7)
配置屬性-->C/C++-->預處理器-->預處理器定義-->補充“;HAVE_REMOTE”
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。