循序渐进学习使用WINPCAP七x
更新时间:2022-09-28 09:09:59 阅读: 评论:0
循序渐进学****使用WINPCAP(七)
通过以前的学****我门已经熟悉了从网卡上捕获数据包,现在我门将学****如何处理数据包。WINPCAP为我们提供了很多API来将流经网络的数据包保存到一个堆文件并读取堆的内容。这一节将讲述如何使用所有的这些API。这种文件的格式很简单,但包含了所捕获的数据报的二进制内容,这种文件格式也是很多网络工具如WinDump,Ethereal还有Snort等的标准。关于如何将数据包保存到文件:首先我们看看如何以LIBPCAP的格式写数据包。
下面的例子演示了如何从指定的接口上捕获数据包并将它们存储到一个指定的文件。
#include"pcap.h"
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,
constu_char*pkt_data);/*定义处理数据的函数原型*/
intmain(intargc,char**argv)
{
pcap_if_t*alldevs;
pcap_if_t*d;
intinum;
inti=0;
pcap_t*adhandle;〃定义文件句柄
charerrbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t*dumpfile;
/*检查命令行参数是否带有文件名*/
if(argc!=2)
{printf("usage:%sfilename",argv[0]);
return-1;
}
/*获得驱动列表*/
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_findalldevs:%s\n",errbuf);
exit(1);
}
/*打印list*/
for(d=alldevs;d;d=d->next)
{
printf("%d.%s",++i,d->name);
if(d->description)printf("(%s)\n",d->description);
elprintf("(Nodescriptionavailable)\n");
}
if(i==0)
{printf("\nNointerfacesfound!MakesureWinPcapisinstalled.\n");return-1;
}
printf("Entertheinterfacenumber(1-%d):",i);scanf("%d",&inum);
if(inum<1||inum>i)
{printf("\nInterfacenumberoutofrange.\n");pcap_freealldevs(alldevs);/*Freethedevicelist*/return-1;
}
/*跳转到指定的网卡*/for(d=alldevs,i=0;i<inum-1;d=d->next,i++);
/*Opentheadapter*/
if((adhandle=pcap_open_live(d->name,//nameofthedevice65536,//portionofthepackettocapture.65536grants//thatthewholepacketwillbecapturedonalltheMACs.1,//promiscuousmode1000,//readtimeouterrbuf//errorbuffer))==NULL)
{fprintf(stderr,"\nUnabletoopentheadapter.%sisnotsupportedbyWinPcap\n");pcap_freealldevs(alldevs);/*Freethedevicelist*/return-1;
}
/*打开文件*/
dumpfile=pcap_dump_open(adhandle,argv[1]);if(dumpfile==NULL)
{
fprintf(stderr,"\nErroropeningoutputfile\n");return-1;
}
printf("\nlisteningon%s...\n",d->description);
/*Atthispoint,wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
/*循环捕获数据并调用packet_handler函数把数据存储到堆文件*/pcap_loop(adhandle,0,packet_handler,(unsignedchar*)dumpfile);return0;
}
/*Callbackfunctioninvokedbylibpcapforeveryincomingpacket*/
voidpacket_handler(u_char*dumpfile,conststructpcap_pkthdr*header,constu_char*pkt_data)
{/*此函数功能将数据报存储到堆文件*/pcap_dump(dumpfile,header,pkt_data);
}
正如你看到的那样,该程序的结构非常类似与以前的例子,区别是:一旦打开网卡就调用pcap_dump_open()来打开一个堆文件,该调用将堆文件和某个网卡相关联。packet_handler()内部通过调用pcap_dump()来将捕获的数据报存储到堆文件。pcap_dump()
的参数和packet_handler()—样,所以用起来比较方便。
从堆文件读数据包:下面我们来看如何从堆文件读取数据内容。下面的代码打开了一个堆文件并打印了其中的每个包内容。pcap_open_offline()用来打开一个堆文件,之后用pcap_loop()来循环从文件中读取数据。你能发现读取脱机的数据几乎和实时的从网卡上读取一摸一样。
#include"pcap.h"#defineLINE_LEN16
voiddispatcher_handler(u_char*,
conststructpcap_pkthdr*,constu_char*);
intmain(intargc,char**argv)
{
pcap_t*fp;
charerrbuf[PCAP_ERRBUF_SIZE];
if(argc!=2)
{
printf("usage:%sfilename",argv[0]);return-1;
}
/*打开一个存储有数据的堆文件*/
if((fp=pcap_open_offline(argv[1],errbuf))==NULL){
fprintf(stderr,"\nErroropeningdumpfile\n");return-1;
}
//读取数据直到遇到EOF标志。pcap_loop(fp,0,dispatcher_handler,NULL);
return0;
}voiddispatcher_handler(u_char*temp1,conststructpcap_pkthdr*header,
constu_char*pkt_data)
{
u_inti=0;
/*printpkttimestampandpktlen*/
printf("%ld:%ld(%ld)\n",header->ts.tv_c,header->ts.tv_uc,header->len);
/*Printthepacket*/
for(i=1;(i<header->caplen+1);i++)
{printf("%.2x",pkt_data[i-1]);if((i%LINE_LEN)==0)printf("\n");
}
printf("\n\n");
}
下面的代码具有一样的作用,只不过是用pcap_next_ex()来代替pcap」oop()循环读取数据而已。
#include"pcap.h"
#defineLINE_LEN16
intmain(intargc,char**argv)
{
pcap_t*fp;
charerrbuf[PCAP_ERRBUF_SIZE];
structpcap_pkthdr*header;
u_char*pkt_data;
u_inti=0;
intres;
if(argc!=2)
{printf("usage:%sfilename",argv[0]);return-1;
}
/*Openacapturefile*/
if((fp=pcap_open_offline(argv[1],errbuf))==NULL)
{fprintf(stderr,"\nErroropeningdumpfile\n");return-1;
}
/*Retrievethepacketsfromthefile*/
while((res=pcap_next_ex(fp,&header,&pkt_data))>=0){
/*printpkttimestampandpktlen*/printf("%ld:%ld(%ld)\n",header->ts.tv_c,header->ts.tv_uc,header->len);
/*Printthepacket*/
for(i=1;(i<header->caplen+1);i++){
printf("%.2X",pkt_data[i-1]);
if((i%LINE_LEN)==0)printf("\n");}
printf("\n\n");
}
if(res==-1)
{printf("Errorreadingthepackets:%s\n",pcap_geterr(fp));
}
return0;
用pcap_live_dump将数据写到文件
WinPcap的最新版本提供了一个进一步的方法来将数据包存储到磁盘,就是使用pcap」ive_dump()函数。该函数需要三个参数:一个文件名,和一个该文件允许的最大长度,还有一个参数是该文件所允许的最大包的数量。对这些参数来说0意味着没有最大限制。
注:我们可以在调用pcap_live_dump()前设置一个过滤器来定义哪些数据报需要存储。pcap_live_dump()是非阻塞的,所以它会立刻返回:数据的存储过程将会异步的进行,直到文件到达了指定的最大长度或最大数据报的数目为止。应用程序能够用pcap」ive_dump_ended()来等检查是否数据存储完毕,如果你指定的最大长度参数和数据报数量为0,那么该操作将永远阻塞。
pcap」ive_dump()和pcap_dump()的不同从设置的最大极限来说就是性能的问题。pcap」ive_dump()采用WinPcapNPF驱动来从内核级的层次上向文件中写数据,从而使内存拷贝最小化。显然,这些特点当前在其他的操作系统下是不能够实现的,pcap_live_dump()是WinPcap所特有的,而且只能够应用于Win32环境.