(原创)WinpCap的详解(三)
接著WinpCap詳解(二),這篇博客主要來討論一下,堆文件的處理以及簡單發(fā)送數(shù)據(jù)包。
1、處理脫機堆文件
我們將學(xué)習(xí)如何處理捕獲到文件中的數(shù)據(jù)包。 WinPcap提供了很多函數(shù)來將網(wǎng)絡(luò)數(shù)據(jù)流保存到文件并讀取它們 -- 本講將教你如何使用這些函數(shù)。我們還將看到如何使用WinPcap內(nèi)核堆特性來獲取一個高性能的堆。
堆文件的格式是libpcap的一種。這種格式中,包含了被捕捉到的包的二進制數(shù)據(jù),并且,這種格式是許多網(wǎng)絡(luò)工具所使用的一種標(biāo)準(zhǔn),這些工具包括WinDump,Etheral和Snort。
保存數(shù)據(jù)包到堆文件
首先,讓我們看一下如何將一個數(shù)據(jù)包寫成libpcap的格式。
接下來的例子講從一個選定的接口捕獲數(shù)據(jù)包,并且將它們保存到用戶指定的文件中。
這里pcap_dump_t和pcap_dump一樣的東西,表示的是libpcap存儲文件的描述符,對用戶來說也是不透明的。
這里的pcap_findalldevs_ex()函數(shù)是pcap_findalldevs()的擴展。這里我列出他的英文解釋吧,翻譯起來還不是很好,看英文比較容易了。
This function is a superset of the old 'pcap_findalldevs()', which is obsolete, and which allows listing only the devices present on the local machine. Vice versa, pcap_findalldevs_ex() allows listing the devices present on a remote machine as well. Additionally, it can list all the pcap files available into a given folder. Moreover, pcap_findalldevs_ex() is platform independent, since it relies on the standard pcap_findalldevs() to get addresses on the local machine.
pcap_dump_open(pcap_t* p,const char* name)打開一個堆文件,第二個參數(shù)是文件的名字,第一個參數(shù)是已經(jīng)打開的適配器描述符。
#include "pcap.h"
/* 回調(diào)函數(shù)原型 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;
/* 檢查程序輸入?yún)?shù) */
if(argc != 2)
{
printf("usage: %s filename", argv[0]);
return -1;
}
/* 獲取本機設(shè)備列表 */
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;
}
/* 跳轉(zhuǎn)到選中的適配器 */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
/* 打開適配器 */
if ( (adhandle= pcap_open(d->name, // 設(shè)備名
65536, // 要捕捉的數(shù)據(jù)包的部分
// 65535保證能捕獲到不同數(shù)據(jù)鏈路層上的每個數(shù)據(jù)包的全部內(nèi)容
PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式
1000, // 讀取超時時間
NULL, // 遠程機器驗證
errbuf // 錯誤緩沖池
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 釋放設(shè)備列表 */
pcap_freealldevs(alldevs);
return -1;
}
/* 打開堆文件 */
dumpfile = pcap_dump_open(adhandle, argv[1]);
if(dumpfile==NULL)
{
fprintf(stderr,"\nError opening output file\n");
return -1;
}
printf("\nlistening on %s... Press Ctrl+C to stop...\n", d->description);
/* 釋放設(shè)備列表 */
pcap_freealldevs(alldevs);
/* 開始捕獲 */
pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
return 0;
}
/* 回調(diào)函數(shù),用來處理數(shù)據(jù)包 */
void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
/* 保存數(shù)據(jù)包到堆文件 */
pcap_dump(dumpfile, header, pkt_data);
}
從堆文件中讀取數(shù)據(jù)包
既然我們有了可用的堆文件,那我們就能讀取它的內(nèi)容了。 以下代碼將打開一個WinPcap/libpcap的堆文件,并顯示文件中每一個包的信息。文件通過 pcap_open_offline() 打開,然后,我們通常使用 pcap_loop() 來有序獲取數(shù)據(jù)包。你可以看到,從脫機文件中讀取數(shù)據(jù)包和從物理接口中接收它們是很相似的。
這個例子還會介紹另一個函數(shù):pcap_createsrcsrc()。這個函數(shù)用于創(chuàng)建一個源字符串,這個源字符串以一個標(biāo)志開頭,這個標(biāo)志會告訴WinPcap這個源的類型。比如,使用"rpcap://"標(biāo)志來打開一個適配器,使用"file://"來打開一個文件。如果 pcap_findalldevs_ex() 已經(jīng)被使用,那么這部是不需要的,因為其返回值已經(jīng)包含了這些字符串。然而,在這個例子中,我們需要它。因為文件的名字來自于用戶的輸入。
2、發(fā)送數(shù)據(jù)包
盡管從 WinPcap 的名字上看,這個庫的目標(biāo)應(yīng)該是數(shù)據(jù)捕捉(Packet Capture),然而,它也提供了針對很多其它有用的特性。在其中,我們可以找到一組很完整的用于發(fā)送數(shù)據(jù)包的函數(shù)。
請注意:原始的libpcap庫是不支持發(fā)送數(shù)據(jù)包的,因此,這里展示的函數(shù)都屬于是WinPcap的擴展,并且它們不能運行于Unix平臺下。
使用 pcap_sendpacket() 發(fā)送單個數(shù)據(jù)包
下面的代碼展示了發(fā)送一個數(shù)據(jù)包的最簡單的方式。打開適配器以后,調(diào)用 pcap_sendpacket() 來發(fā)送手工制作的數(shù)據(jù)包。 pcap_sendpacket() 的參數(shù)有一個要包涵發(fā)送數(shù)據(jù)的緩沖區(qū),緩沖的長度,以及用來發(fā)送數(shù)據(jù)的適配器。注意,緩沖數(shù)據(jù)將直接發(fā)送到網(wǎng)絡(luò),而不會進行任何加工和處理。這就意味著應(yīng)用程序需要創(chuàng)建一個正確的協(xié)議首部,來使這個數(shù)據(jù)包更有意義。
#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>
void main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
u_char packet[100];
int i;
/* 檢查命令行參數(shù)的合法性 */
if (argc != 2)
{
printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);
return;
}
/* 打開輸出設(shè)備 */
if ( (fp= pcap_open(argv[1], // 設(shè)備名
100, // 要捕獲的部分 (只捕獲前100個字節(jié))
PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式
1000, // 讀超時時間
NULL, // 遠程機器驗證
errbuf // 錯誤緩沖
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
return;
}
/* 假設(shè)在以太網(wǎng)上,設(shè)置MAC的目的地址為 1:1:1:1:1:1 */
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;
/* 設(shè)置MAC源地址為 2:2:2:2:2:2 */
packet[6]=2;
packet[7]=2;
packet[8]=2;
packet[9]=2;
packet[10]=2;
packet[11]=2;
/* 填充剩下的內(nèi)容 */
for(i=12;i<100;i++)
{
packet[i]=i%256;
}
/* 發(fā)送數(shù)據(jù)包 */
if (pcap_sendpacket(fp, packet, 100 /* size */) != 0)
{
fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(fp));
return;
}
return;
}
這里面只是簡單的數(shù)據(jù)發(fā)送,還有更復(fù)雜的隊列發(fā)送,由于現(xiàn)在不需要用到這一塊,所以就不看這一部分了,因為我只需要發(fā)送簡單的命令,不需要大量的數(shù)據(jù)發(fā)送,這里就不再講下去啦,如果想更深入的了解WinpCap的功能,推薦一個好的網(wǎng)站,http://www.ferrisxu.com/WinPcap/html/modules.html,這個網(wǎng)站里面有很多關(guān)于WinpCap的東西,可能里面有很多更新的東西,還值得大家以后共同學(xué)習(xí),本人就學(xué)習(xí)這么多啦!
總結(jié)
以上是生活随笔為你收集整理的(原创)WinpCap的详解(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP 下载图片文件并压缩文件成zip
- 下一篇: 油价有望迎今年第3次下调:加满一箱油或便