循序渐进学习使用WINPCAP一.docx
- 文档编号:22790588
- 上传时间:2023-04-28
- 格式:DOCX
- 页数:47
- 大小:32.27KB
循序渐进学习使用WINPCAP一.docx
《循序渐进学习使用WINPCAP一.docx》由会员分享,可在线阅读,更多相关《循序渐进学习使用WINPCAP一.docx(47页珍藏版)》请在冰豆网上搜索。
循序渐进学习使用WINPCAP一
循序渐进学习使用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"这样的提示。
循序渐进学习使用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()来实现的它有三个参数snaplenpromiscto_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;i
/*打开选择的网卡*/
if((adhandle=pcap_open_live(d->name,//设备名称
65536, //portionofthepackettocapture.
//65536grantsthatthewholepacketwillbecapturedonalltheMACs.
1, //混杂模式
1000, //读超时为1秒
errbuf //errorbuffer
))==NULL)
{
fprintf(stderr,"\nUnabletoopentheadapter.%sisnotsupportedbyWinPcap\n");
/*Freethedevicelist*/
pcap_freealldevs(alldevs);
return-1;
}
printf("\nlisteningon%s...\n",d->description);
/*Atthispoint,wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
/*开始捕获包*/
pcap_loop(adhandle,0,packet_handler,NULL);
return0;
}
/*对每一个到来的数据包调用该函数*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data)
{
structtm*ltime;
chartimestr[16];
/*将时间戳转变为易读的标准格式*/
ltime=localtime(&header->ts.tv_sec);
strftime(timestr,sizeoftimestr,"%H:
%M:
%S",ltime);
printf("%s,%.6dlen:
%d\n",timestr,header->ts.tv_usec,header->len);
}
一旦网卡被打开,就可以调用pcap_dispatch()或pcap_loop()进行数据的捕获,这两个函数的功能十分相似不同的是pcap_dispatch()可以不被阻塞,而pcap_loop()在没有数据流到达时将阻塞。
在这个简单的例子里用pcap_loop()就足够了,而在一些复杂的程序里往往用pcap_dispatch()。
Oncetheadapterisopened,thecapturecanbestartedwithpcap_dispatch()orpcap_loop().Thesetwofunctionsareverysimilar,thedifferenceisthatpcap_dispatch()isgrantedtoreturnwhentheexpireswhilepcap_loop()doesn'treturnuntilcntpacketshavebeencaptured,soitcanblockforanarbitraryperiodonafewutilizednetwork.pcap_loop()isenoughforthepurposeofthissample,whilepcap_dispatch()isnormallyusedinmorecomplexprogram.
这两个函数都有返回的参数,一个指向某个函数(该函数用来接受数据如该程序中的packet_handler)的指针,libpcap调用该函数对每个从网上到来的数据包进行处理和接收数据包。
另一个参数是带有时间戳和包长等信
息的头部,最后一个是含有所有协议头部数据报的实际数据。
注意MAC的冗余校验码一般不出现,因为当一个桢到达并被确认后网卡就把它删除了,同样需要注意的是大多数网卡会丢掉冗余码出错的数据包,所以WinPcap一般不能够捕获这些出错的数据报。
刚才的例子里从pcap_pkthdr中提取出了每个数据报的时间戳和长度并在显示器上打印出了他们。
循序渐进学习使用WINPCAP(四)
这节的例子很象先前的一章(获得网卡的高级信息)但是这一节中是用pcap_next_ex()来代替pcap_loop()来捕获数据包。
基于回调包捕获机制的pcap_loop()在某些情况下是不错的选择。
但是在一些情况下处理回调并不特别好:
这会使程序变的复杂并且在象多线程或C++类这些情况下它看起来到象一块绊脚石。
在这些情况下pcap_next_ex()允许直接调用来接收包,它的参数和pcap_loop()相同:
有一个网卡描述副,和两个指针,这两个指针会被初始化并返回给用户,一个是pcap_pkthdr结构,另一个是接收数据的缓冲区。
下面的程序我门将循环调用前一节的例子中的回掉部分,只是把它移到了main里面了。
#include"pcap.h"
main()
{
pcap_if_t*alldevs;
pcap_if_t*d;
intinum;
inti=0;
pcap_t*adhandle;
intres;
charerrbuf[PCAP_ERRBUF_SIZE];
structtm*ltime;
chartimestr[16];
structpcap_pkthdr*header;
u_char*pkt_data;
/*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-1;
}
printf("Entertheinterfacenumber(1-%d):
",i);
scanf("%d",&inum);
if(inum<1||inum>i)
{
printf("\nInterfacenumberoutofrange.\n");
/*Freethedevicelist*/
pcap_freealldevs(alldevs);
return-1;
}
/*Jumptotheselectedadapter*/
for(d=alldevs,i=0;i
/*Opentheadapter*/
if((adhandle=pcap_open_live(d->name,//nameofthedevice
65536, //portionofthepackettocapture.
//65536grantsthatthewholepacketwillbecapturedonalltheMACs.
1, //promiscuousmode
1000, //readtimeout
errbuf //errorbuffer
))==NULL)
{
fprintf(stderr,"\nUnabletoopentheadapter.%sisnotsupportedbyWinPcap\n");
/*Freethedevicelist*/
pcap_freealldevs(alldevs);
return-1;
}
printf("\nlisteningon%s...\n",d->description);
/*Atthispoint,wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
/*此处循环调用pca
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 循序渐进 学习 使用 WINPCAP