?
知道如何獲取適配器的信息了,那我們就開始一項(xiàng)更具意義的工作,打開適配器并捕獲數(shù)據(jù)包。編寫一個(gè)程序,將每一個(gè) 通過(guò)適配器的數(shù)據(jù)包 打印出來(lái)。
?
打開設(shè)備的函數(shù)是? pcap_open() 。
(Open a generic source in order to capture / send (WinPcap only) traffic.)
pcap_t* pcap_open ( const char * source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth * auth, char * errbuf )
?
· snaplen 制定要捕獲數(shù)據(jù)包中的哪些部分。 在一些操作系統(tǒng)中 (比如 xBSD 和 Win32), 驅(qū)動(dòng)可以被配置成 只捕獲數(shù)據(jù)包的初始化部分 : 這樣可以減少應(yīng)用程序間復(fù)制數(shù)據(jù)的量,從而提高捕獲效率。本例中,我們將值定為65535,它比我們能遇到的最大的MTU還要大。因此,我們確信我們總能收到完整的數(shù)據(jù)包。
· flags : 最最重要的flag是用來(lái)指示適配器是否要被設(shè)置成 混雜模式 。 一般情況下,適配器只接收發(fā)給它自己的數(shù)據(jù)包, 而那些在其他機(jī)器之間通訊的數(shù)據(jù)包,將會(huì)被丟棄 。 相反,如果適配器是混雜模式,那么不管這個(gè)數(shù)據(jù)包是不是發(fā)給我的,我都會(huì)去捕獲。也就是說(shuō),我會(huì)去捕獲所有的數(shù)據(jù)包。 這意味著在一個(gè)共享媒介(比如總線型以太網(wǎng)),WinPcap能捕獲其他主機(jī)的所有的數(shù)據(jù)包。 大多數(shù)用于數(shù)據(jù)捕獲的應(yīng)用程序都會(huì)將適配器設(shè)置成混雜模式 ,所以,我們也會(huì)在下面的范例中,使用混雜模式。?
· read_timeout(to_ms): 指定 讀取數(shù)據(jù)的超時(shí)時(shí)間 ,以毫秒計(jì)(1s=1000ms)。在適配器上進(jìn)行讀取操作(比如用 pcap_dispatch() 或 pcap_next_ex() ) 都會(huì)在 to_ms 毫秒時(shí)間內(nèi)響應(yīng),即使在網(wǎng)絡(luò)上沒有可用的數(shù)據(jù)包。 在統(tǒng)計(jì)模式下 , to_ms 還可以用來(lái)定義 統(tǒng)計(jì)的時(shí)間間隔 。 將 to_ms 設(shè)置為0意味著沒有超時(shí),那么如果沒有數(shù)據(jù)包到達(dá)的話,讀操作將永遠(yuǎn)不會(huì)返回。 如果設(shè)置成-1,則情況恰好相反,無(wú)論有沒有數(shù)據(jù)包到達(dá),讀操作都會(huì)立即返回。
- Returns:
- A pointer to a 'pcap_t' which can be used as a parameter to the following calls ( pcap_compile() and so on) and that specifies an opened WinPcap session. In case of problems, it returns NULL and the 'errbuf' variable keeps the error message.
- Warning:
-
The source cannot be larger than PCAP_BUF_SIZE.
The following formats are not allowed as 'source' strings:
- rpcap:// [to open the first local adapter]
- rpcap://hostname/ [to open the first remote adapter]?
?
?
int pcap_dispatch ( pcap_t * p, int cnt, pcap_handler callback, u_char * user )
?
Collect a group of packets.?
?
int pcap_loop ( pcap_t * p, int cnt, pcap_handler callback, u_char * user )
?
Collect a group of packets.
?
pcap_dispatch()與pcap_loop()的區(qū)別:
當(dāng)適配器被打開,捕獲工作就可以用 pcap_dispatch() 或 pcap_loop() 進(jìn)行。 這兩個(gè)函數(shù)非常的相似, 區(qū)別就是 pcap_ dispatch() 當(dāng)超時(shí)時(shí)間到了(timeout expires)就返回 (盡管不能保證) ,而 pcap_loop() 不會(huì)因此而返回 ,只有當(dāng) cnt 數(shù)據(jù)包被捕獲,所以,pcap_loop()會(huì)在一小段時(shí)間內(nèi),阻塞網(wǎng)絡(luò)的利用。 pcap_loop() 對(duì)于我們這個(gè)簡(jiǎn)單的范例來(lái)說(shuō),可以滿足需求,不過(guò), pcap_dispatch() 函數(shù)一般用于比較復(fù)雜的程序中。
這兩個(gè)函數(shù)都有一個(gè) 回調(diào) 參數(shù), packet_handler 指向一個(gè)可以接收數(shù)據(jù)包的函數(shù) 。 這個(gè)函數(shù)會(huì)在收到每個(gè)新的數(shù)據(jù)包并收到一個(gè)通用狀態(tài)時(shí)被libpcap所調(diào)用 ( 與函數(shù) pcap_loop() 和 pcap_dispatch() 中的 user 參數(shù)相似),數(shù)據(jù)包的首部一般有一些諸如時(shí)間戳,數(shù)據(jù)包長(zhǎng)度的信息,還有包含了協(xié)議首部的實(shí)際數(shù)據(jù)。 注意:冗余校驗(yàn)碼CRC不再支持,因?yàn)閹竭_(dá)適配器,并經(jīng)過(guò)校驗(yàn)確認(rèn)以后,適配器就會(huì)將CRC刪除,與此同時(shí),大部分適配器會(huì)直接丟棄CRC錯(cuò)誤的數(shù)據(jù)包,所以,WinPcap沒法捕獲到它們。
上面的程序?qū)⒚恳粋€(gè)數(shù)據(jù)包的時(shí)間戳和長(zhǎng)度從 pcap_pkthdr 的首部解析出來(lái),并打印在屏幕上。
請(qǐng)注意,使用 pcap_loop() 函數(shù)可能會(huì)遇到障礙,主要因?yàn)樗苯佑蓴?shù)據(jù)包捕獲驅(qū)動(dòng)所調(diào)用。因此,用戶程序是不能直接控制它的。另一個(gè)實(shí)現(xiàn)方法(也是提高可讀性的方法),是使用 pcap_next_ex() 函數(shù)。有關(guān)這個(gè)函數(shù)的使用,請(qǐng)看 ( 不用回調(diào)方法捕獲數(shù)據(jù)包 ).
?
struct pcap_pkthdr{ timeval ts // time stamp bpf_u_int32 caplen // length of portion present bpf_u_int32 len // length this packet (off wire) };
Detailed Description
Header of a packet in the dump file.
Each packet in the dump file is prepended with this generic header. This gets around the problem of different headers for different packet interfaces.?
?

1 #include " pcap.h " 2 #pragma comment(lib, "wpcap.lib") 3 #pragma comment(lib, "Packet.lib") 4 #pragma comment(lib, "wsock32.lib") 5 6 7 #include " pcap.h " 8 9 /* packet handler 函數(shù)原型 */ 10 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char * pkt_data); 11 12 main() 13 { 14 pcap_if_t * alldevs; 15 pcap_if_t * d; 16 int inum; 17 int i= 0 ; 18 pcap_t * adhandle; 19 char errbuf[PCAP_ERRBUF_SIZE]; 20 21 /* 獲取本機(jī)設(shè)備列表 */ 22 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == - 1 ) 23 { 24 fprintf(stderr, " Error in pcap_findalldevs: %s\n " , errbuf); 25 exit( 1 ); 26 } 27 28 /* 打印列表 */ 29 for (d=alldevs; d; d=d-> next) 30 { 31 printf( " %d. %s " , ++i, d-> name); 32 if (d-> description) 33 printf( " (%s)\n " , d-> description); 34 else 35 printf( " (No description available)\n " ); 36 } 37 38 if (i== 0 ) 39 { 40 printf( " \nNo interfaces found! Make sure WinPcap is installed.\n " ); 41 return - 1 ; 42 } 43 44 printf( " Enter the interface number (1-%d): " ,i); 45 scanf( " %d " , & inum); 46 47 if (inum < 1 || inum > i) 48 { 49 printf( " \nInterface number out of range.\n " ); 50 /* 釋放設(shè)備列表 */ 51 pcap_freealldevs(alldevs); 52 return - 1 ; 53 } 54 55 /* 跳轉(zhuǎn)到選中的適配器 */ 56 for (d=alldevs, i= 0 ; i< inum- 1 ;d=d->next, i++ ); 57 58 /* 打開設(shè)備 */ 59 if ( (adhandle= pcap_open(d->name, // 設(shè)備名 60 65536 , // 65535保證能捕獲到不同數(shù)據(jù)鏈路層上的每個(gè)數(shù)據(jù)包的全部?jī)?nèi)容 61 PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式 62 1000 , // 讀取超時(shí)時(shí)間 63 NULL, // 遠(yuǎn)程機(jī)器驗(yàn)證 64 errbuf // 錯(cuò)誤緩沖池 65 ) ) == NULL) 66 { 67 fprintf(stderr, " \nUnable to open the adapter. %s is not supported by WinPcap\n " , d-> name); 68 /* 釋放設(shè)備列表 */ 69 pcap_freealldevs(alldevs); 70 return - 1 ; 71 } 72 73 printf( " \nlistening on %s...\n " , d-> description); 74 75 /* 釋放設(shè)備列表 */ 76 pcap_freealldevs(alldevs); 77 78 /* 開始捕獲 */ 79 pcap_loop(adhandle, 0 , packet_handler, NULL); 80 81 return 0 ; 82 } 83 84 85 /* 每次捕獲到數(shù)據(jù)包時(shí),libpcap都會(huì)自動(dòng)調(diào)用這個(gè)回調(diào)函數(shù) */ 86 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char * pkt_data) 87 { 88 struct tm * ltime; 89 char timestr[ 16 ]; 90 time_t local_tv_sec; 91 92 /* 將時(shí)間戳轉(zhuǎn)換成可識(shí)別的格式 */ 93 local_tv_sec = header-> ts.tv_sec; 94 ltime=localtime(& local_tv_sec); 95 strftime( timestr, sizeof timestr, " %H:%M:%S " , ltime); 96 97 printf( " %s,%.6d len:%d\n " , timestr, header->ts.tv_usec, header-> len); 98 }
*結(jié)果:
時(shí)間戳(精確到微妙),包長(zhǎng)度;
?
timeval
The? timeval ?structure is used to specify time values. It is associated with the Berkeley Software Distribution (BSD) file Time.h.
struct timeval { long tv_sec; // seconds long tv_usec; // and microseconds };
Members
- tv_sec
- Time value, in seconds.
- tv_usec
- Time value, in microseconds.?
?
localtime
Converts a time value and corrects for the local time zone.
struct tm *localtime( const time_t *timer );
?
?
struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag */ };
?
?
?
asctime, _wasctime
Converts a? tm? time structure to a character string.
char *asctime( const struct tm * timeptr ); wchar_t *_wasctime( const struct tm *timeptr );
?
Return Value
asctime ?returns a pointer to the character string result;? _wasctime ?returns a pointer to the wide-character string result. There is no error return value.
?
?
time
Gets the system time.
time_t time( time_t *timer );
?
?
?
strftime, wcsftime
Format a time string.
size_t strftime( char *strDest, size_t maxsize, const char *format, const struct tm * timeptr ); size_t wcsftime( wchar_t *strDest, size_t maxsize, const wchar_t *format, const struct tm *timeptr );
?
Return Value
strftime ?returns the number of characters placed in? strDest ?if the total number of resulting characters, including the terminating null, is not more than? maxsize .
wcsftime ?returns the corresponding number of wide characters. Otherwise, the functions return 0, and the contents of? strDest ?is indeterminate.
?
?
void
pcap_freealldevs ( pcap_if_t * alldevsp )
Free an interface list returned by? pcap_findalldevs() . ?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
