循序渐进学习使用WINPCAP.docx
《循序渐进学习使用WINPCAP.docx》由会员分享,可在线阅读,更多相关《循序渐进学习使用WINPCAP.docx(34页珍藏版)》请在冰豆网上搜索。
![循序渐进学习使用WINPCAP.docx](https://file1.bdocx.com/fileroot1/2023-1/5/7757cf58-4a4e-4a63-89d4-945d20ea6bb2/7757cf58-4a4e-4a63-89d4-945d20ea6bb21.gif)
循序渐进学习使用WINPCAP
资料来源:
进入
WINPCAP的官方网站是http:
//www.winpcap.org/不过是英文的
一)winpcap驱动简介
winpcap(windowspacketcapture)是windows平台下一个免费,公共的网络访问系统。
开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。
它提供了以下的各项功能:
1>捕获原始数据报,包括在共享网络上各主机发送/接收的以及相互之间交换的数据报;
2>在数据报发往应用程序之前,按照自定义的规则将某些特殊的数据报过滤掉;
3>在网络上发送原始的数据报;
4>收集网络通信过程中的统计信息。
winpcap的主要功能在于独立于主机协议(如TCP-IP)而发送和接收原始数据报。
也就是说,winpcap不能阻塞,过滤或控制其他应用程序数据报的发收,它仅仅只是监听共享网络上传送的数据报。
因此,它不能用于QoS调度程序或个人防火墙。
目前,winpcap开发的主要对象是windowsNT/2000/XP,这主要是因为在使用winpcap的用户中只有一小部分是仅使用windows95/98/Me,并且M$也已经放弃了对win9x的开发。
最近正在学习PCAP,所以顺便把原文翻译出来和初学者一起进步。
高手勿看。
循序渐进学习使用WINPCAP
(一)
一些需要知道的细节描述(前言):
这一部分展示了如何使用WINPCAP-API的不同的功能,它作为一个使用指南被划分为一系列的课时来带领读者循序渐进的体会PCAP的程序设计的
魅力:
从简单的基本功能(如获取网卡的列表,数据包的捕获等)到统计和收集网络流量等高级功能。
在这里将提供一些简单但完整的代码作为参考:
所有的这些原代码都有和它相关的详细信息的连接以便单击这些功能和数据结构时能够即使跳转到相关的文献。
这些例子是用C语言写的,所以在学习之前首先要有一定的C语言的基础,当然PCAP作为一个网络底层的驱动,要想学好它也必须具备一定的网络方面的知识。
(一)得到网络驱动列表
用PCAP写应用程序的第一件事往往就是要获得本地的网卡列表。
PCAP提供了pcap_findalldevs()这个函数来实现此功能,这个API返回一个pcap_if结构的连表,连表的每项内容都含有全面的网卡信息:
尤其是字段名字和含有名字的描述以及有关驱动器的易读信息。
得到网络驱动列表的程序如下:
#include"pcap.h"
main()
{
pcap_if_t*alldevs;
pcap_if_t*d;
inti=0;
charerrbuf[PCAP_ERRBUF_SIZE];
/*这个API用来获得网卡的列表*/
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_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("(Nodescriptionavailable)\n");
}
if(i==0)
{
printf("\nNointerfacesfound!
MakesureWinPcapisinstalled.\n");
return;
}
/*Wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
}
有关这段程序的一些说明:
首先pcap_findalldevs()同其他的libpca函数一样有一个errbuf参数,当有异常情况发生时,这个参数会被PCAP填充为某个特定的错误字串。
再次,UNIX也同样提供pcap_findalldevs()这个函数,但是请注意并非所有的系统都支持libpcap提供的网络程序接口。
所以我门要想写出合适
的程序就必须考虑到这些情况(系统不能够返回一些字段的描述信息),在这种情况下我门应该给出类似"Nodescriptionavailable"这样的
提示。
最后结束时别忘了用pcap_freealldevs()释放掉内存资源。
原文如下:
Obtainingthedevicelist
ThefirstthingthatusuallyaWinPcapbasedapplicationneedsisalistofsuitablenetworkadapters.Libpcapprovidesthepcap_findalldevs()functionforthispurpose:
thisfunctionreturnsalinkedlistofpcap_ifstructures,eachofwhichcontainscomprehensiveinformationaboutanadapter.Inparticularthefieldsnameanddescriptioncontainthenameandahumanreadabledescriptionofthedevice.
Thefollowingcoderetrievestheadapterlistandshowsitonthescreen,printinganerrorifnoadaptersarefound.
#include"pcap.h"
main()
{
pcap_if_t*alldevs;
pcap_if_t*d;
inti=0;
charerrbuf[PCAP_ERRBUF_SIZE];
/*Retrievethedevicelist*/
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_findalldevs:
%s\n",errbuf);
exit
(1);
}
/*Printthelist*/
for(d=alldevs;d;d=d->next)
{
printf("%d.%s",++i,d->name);
if(d->description)
printf("(%s)\n",d->description);
else printf("(Nodescriptionavailable)\n");
}
if(i==0)
{
printf("\nNointerfacesfound!
MakesureWinPcapisinstalled.\n");
return;
}
/*Wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
}
Somecommentsaboutthiscode.
Firstofall,pcap_findalldevs(),likeotherlibpcapfunctions,hasanerrbufparameter.Thisparameterpointstoastringfilledbylibpcapwithadescriptionoftheerrorifsomethinggoeswrong.
Second,notethatpcap_findalldevs()isprovidedbylibpcapunderUnixaswell,butrememberthatnotalltheOSessupportedbylibpcapprovideadescriptionofthenetworkinterfaces,thereforeifwewanttowriteaportableapplication,wemustconsiderthecaseinwhichdescriptionisnull:
weprintthestring"Nodescriptionavailable"inthatsituation.
Notefinallythatwefreethelistwithpcap_freealldevs()oncewhenwehavefinishedwithit.
Let'strytocompileandrunthecodeofthisfirstsample.InordertocompileitunderUnixorCygwin,simplyissuea:
gcc-otestaprogtestprog.c-lpcap
OnWindows,youwillneedtocreateaproject,followingtheinstructionsinthe"UsingWinPcapinyourprograms"sectionofthismanual.However,IsuggestyoutousetheWinPcapdeveloper'spack(availableattheWinPcapwebsite,http:
//winpcap.polito.it),thatprovidesalotofproperlyconfiguredexampleapps,allthecodepresentedinthistutorialandalltheprojects,includesandlibrariesneededtocompileandrunthesamples.
Assumingwehavecompiledtheprogram,let'strytorunit.OnmyWinXPworkstation,theresultis
1.{4E273621-5161-46C8-895A-48D0E52A0B83}(RealtekRTL8029(AS)EthernetAdapter)
2.{5D24AE04-C486-4A96-83FB-8B5EC6C7F430}(3ComEtherLinkPCI)
Asyoucansee,thenameofthenetworkadapters(thatwillbepassedtolibpcapwhenopeningthedevices)underWindowsarequiteunreadable,sothedescriptionnearthemcanbeveryusefultotheuser.
循序渐进学习使用WINPCAP
(二)
获得已安装网络驱动器的高级信息
在第一章中演示了如何获得已存在适配器的静态信息。
实际上WinPcap同样也提供其他的高级信息,特别是pcap_findalldevs()这个函数返回的每个pcap_if结构体都同样包含一个pcap_addr结构的列表,他包含:
一个地址列表,一个掩码列表,一个广播地址列表和一个目的地址列表。
下面的例子通过一个ifprint()函数打印出了pcap_if结构的的所有字段信息,该程序对每一个pcap_findalldevs()所返回的pcap_if结构循环调用ifprint()来显示详细的字段信息。
#include"pcap.h"
#ifndefWIN32
#include
#include
#else
#include
#endif
voidifprint(pcap_if_t*d);
char*iptos(u_longin);
intmain()
{
pcap_if_t*alldevs;
pcap_if_t*d;
charerrbuf[PCAP_ERRBUF_SIZE+1];
/*获得网卡的列表*/
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_findalldevs:
%s\n",errbuf);
exit
(1);
}
/*循环调用ifprint()来显示pcap_if结构的信息*/
for(d=alldevs;d;d=d->next)
{
ifprint(d);
}
return1;
}
/*Printalltheavailableinformationonthegiveninterface*/
voidifprint(pcap_if_t*d)
{
pcap_addr_t*a;
/*Name*/
printf("%s\n",d->name);
/*Description*/
if(d->description)
printf("\tDescription:
%s\n",d->description);
/*LoopbackAddress*/
printf("\tLoopback:
%s\n",(d->flags&PCAP_IF_LOOPBACK)?
"yes":
"no");
/*IPaddresses*/
for(a=d->addresses;a;a=a->next){
printf("\tAddressFamily:
#%d\n",a->addr->sa_family);
/*关于sockaddr_in结构请参考其他的网络编程书*/
switch(a->addr->sa_family)
{
caseAF_INET:
printf("\tAddressFamilyName:
AF_INET\n");//打印网络地址类型
if(a->addr)//打印IP地址
printf("\tAddress:
%s\n",iptos(((structsockaddr_in*)a->addr)->sin_addr.s_addr));
if(a->netmask)//打印掩码
printf("\tNetmask:
%s\n",iptos(((structsockaddr_in*)a->netmask)->sin_addr.s_addr));
if(a->broadaddr)//打印广播地址
printf("\tBroadcastAddress:
%s\n",iptos(((structsockaddr_in*)a->broadaddr)->sin_addr.s_addr));
if(a->dstaddr)//目的地址
printf("\tDestinationAddress:
%s\n",iptos(((structsockaddr_in*)a->dstaddr)->sin_addr.s_addr));
break;
default:
printf("\tAddressFamilyName:
Unknown\n");
break;
}
}
printf("\n");
}
/* 将一个unsignedlong型的IP转换为字符串类型的IP*/
#defineIPTOSBUFFERS 12
char*iptos(u_longin)
{
staticcharoutput[IPTOSBUFFERS][3*4+3+1];
staticshortwhich;
u_char*p;
p=(u_char*)∈
which=(which+1==IPTOSBUFFERS?
0:
which+1);
sprintf(output[which],"%d.%d.%d.%d",p[0],p[1],p[2],p[3]);
returnoutput[which];
}
循序渐进学习使用WINPCAP(三)
-------打开网卡捕获数据包
现在我门已经知道了如何去获得网卡的信息现在就让我们开始真正的工作:
打开网卡并捕获数据流。
在这一节
里我们将写一个打印流经网络的每个数据包信息的程序。
打开网卡的功能是通过pcap_open_live()来实现的它
有三个参数snaplen promisc to_ms。
snaplen用于指定所捕获包的特定部分,在一些系统上(象xBSDandWin32等)驱动只给出所捕获数据包
的一部分而不是全部,这样就减少了拷贝数据的数量从而提高了包捕获的效率。
promisc指明网卡处于混杂模式,在正常情况下网卡只接受去往它的包而去往其他主机的数据包则被忽略
。
相反当网卡处于混杂模式时他将接收所有的流经它的数据包:
这就意味着在共享介质的情况下我门可以捕获
到其它主机的数据包。
大部分的包捕获程序都将混杂模式设为默认,所有我们在下面的例子里也将网卡设为混杂模式。
to_ms参数指定读数据的超时控制,超时以毫秒计算。
当在超时时间内网卡上没有数据到来时对网卡的读
操作将返回(如pcap_dispatch()orpcap_next_ex()等函数)。
还有,如果网卡处于统计模式下(请查看“统计和收集网络数据流一节”)to_ms还定义了统计的时间间隔。
如果该参数为0那么意味着没有超时控制,对网卡的读操作在没有数据到来是将永远堵塞。
如果为-1那么对网卡的读操作将立即返回不管有没有数据可读。
#include"pcap.h"
/*prototypeofthepackethandler*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);
main()
{
pcap_if_t*alldevs;
pcap_if_t*d;
intinum;
inti=0;
pcap_t*adhandle;
charerrbuf[PCAP_ERRBUF_SIZE];
/*获得网卡的列表*/
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_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("(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");
/*Freethedevicelist*/
pcap_freealldevs(alldevs);
return-1;
}
/*找到要选择的网卡结构*/
for(d=alldevs,i=0;