“Thismeansthatonsharedmedia(likenon-switchedEthernet),WinPcapwillbeabletocapturethepacketsofotherhosts.”
我理解为:如果在通过没有交换功能的集线器连接的网络上,只要把网卡设置为混杂(promiscuous)模式,winpcap能够捕获到其他主机通信的数据包。如果是具有交换功能的集线器连接的网络winpcap还能管用吗?这个在后边的实习中将会进行试验。
试验程序2:
/*
*截获数据包的试验。先打印出所有网络适配器的列表,然后选择
*想在哪个适配器上截获数据包。然后通过pcap_loop()函数将截获
*的数据包传给回调函数packet_handler()处理。
*通过该程序初步了解了使用winpcap截获数据包的步骤以及一些在
*截获数据包时非常重要的函数和结构体。
*2006-1-26
*/
#include<pcap.h>
#include<remote-ext.h>
/*Prototypeofthepackethandler*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);
intmain(){
pcap_if_t*alldevs;
pcap_if_t*d;
intinum;
inti=0;
pcap_t*adhandle;
charerrbuf[PCAP_ERRBUF_SIZE];
/*Retrievethedeviceslistonthelocalmachine*/
if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_findalldevs:%s\n",errbuf);
exit(1);
}
/*Printthelist*/
for(d=alldevs;d;d=d->next)
{
/*Printname*/
printf("%d.%s",++i,d->name);
/*Printdescription*/
if(d->description)
{
printf("(%s)\n",d->description);
}
else
{
printf("(Nodescriptionavailable)\n");
}
}
if(i==0)
{
printf("\nNointerfacesfound!MakesureWinpcapisinstalled.\n");
return-1;
}
/*Selectanadapter*/
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<inum-1;d=d->next,++i);
/*Openthedevice*/
if((adhandle=pcap_open(d->name,/*nameofthedevice*/
65536,/*portionofthepackettocapture*/
/*65535guaranteesthatthewholepacketwillbecapturedonallthelinklayers*/
PCAP_OPENFLAG_PROMISCUOUS,/*promiscuousmode*/
1000,/*readtimeout*/
NULL,/*authenticationontheremotemachine*/
errbuf/*errorbuffer*/
))==NULL)
{
fprintf(stderr,"\nnabletoopentheadapter.%sisnotsupportedbyWinpcap\n",d->name);
/*Freethedeviceslist*/
pcap_freealldevs(alldevs);
return-1;
}
printf("\nlisteningon%s...\n",d->description);
/*Atthispoint,wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
/*startthecapture*/
pcap_loop(adhandle,0,packet_handler,NULL);
return1;
}
/*Callbackfunctioninvokedbylibpcapforeveryincomingpacket*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data){
structtm*ltime;
chartimestr[16];
/*convertthetimestamptoreadableformat*/
ltime=localtime(&header->ts.tv_sec);
strftime(timestr,sizeof(timestr),"%H:%M:%S",ltime);
printf("%s,%.6dlen:%d\n",timestr,header->ts.tv_usec,header->len);
}
函数1:
pcap_t*pcap_open(constchar*source,
intsnaplen,
intflags,
intread_timeout,
structpcap_rmtauth*auth,
char*errbuf
)
为捕获/发送数据打开一个普通的源。pcap_open()能够替代所有的pcap_open_xxx()函数,它隐藏了不同的pcap_open_xxx()之间的差异,所以程序员不必使用不同的open函数。
source:的是包含要打开的源名称的以’\0’结尾的字符串。源名称得包含新的源规范语法(SourceSpecificationSyntax),并且它不能为NULL。为了方便的使用源语法,请记住:(1)pcap_findalldevs_ex()返回的适配器(网卡)可以直接被pcap_open()使用;(2)万一用户想传递他自己的源字符串给pcap_open(),pcap_createsrcstr()可以创建正确的源标识。
snaplen:需要保留的数据包的长度。对每一个过滤器接收到的数据包,第一个‘snaplen’字节的内容将被保存到缓冲区,并且传递给用户程序。例如,snaplen等于100,那么仅仅每一个数据包的第一个100字节的内容被保存。简言之就是从每一个包的开头到snaplen的那段内容将被保存。
flags:保存一些由于抓包需要的标志。Winpcap定义了三种标志:
lPCAP_OPENFLAG_PROMISCUOUS:1,它定义了适配器(网卡)是否进入混杂模式(promiscuousmode)。
lPCAP_OPENFLAG_DATATX_UDP:2,它定义了数据传输(假如是远程抓包)是否用UDP协议来处理。
lPCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定义了远程探测器是否捕获它自己产生的数据包。
read_timeout:以毫秒为单位。readtimeout被用来设置在遇到一个数据包的时候读操作不必立即返回,而是等待一段时间,让更多的数据包到来后从OS内核一次读多个数据包。并非所有的平台都支持readtimeout;在不支持readtimeout的平台上它将被忽略。
auth:一个指向’structpcap_rmtauth’的指针,保存当一个用户登录到某个远程机器上时的必要信息。假如不是远程抓包,该指针被设置为NULL。
errbuf:一个指向用户申请的缓冲区的指针,存放当该函数出错时的错误信息。
返回值是一个’pcap_t’指针,它可以作为下一步调用(例如pcap_compile()等)的参数,并且指定了一个已经打开的Winpcap会话。在遇到问题的情况下,它返回NULL并且’errbuf’变量保存了错误信息。
函数2:
intpcap_loop(pcap_t*p,
intcnt,
pcap_handercallback,
u_char*user
)
收集一群数据包。pcap_loop()与pcap_dispatch()类似,但是它会一直保持读数据包的操作直到cnt包被处理或者发生了错误。当有活动的读超时(readtimeout)时它并不返回。然而,对pcap_open_live()指定一个非0的读超时(readtimeout),当发生超时的时候调用pcap_dispatch()来接收并处理到来的所有数据包更好。Cnt指明了返回之前要处理数据包的最大数目。如果cnt为负值,pcap_loop()将一直循环(直到发生错误才停止)。如果出错时返回-1;如果cnt用完时返回0;如果在任何包被处理前调用pcap_breakloop()来中止循环将返回-2。所以,如果程序中使用了pcap_breakloop(),必须准确的来判断返回值是-1还是-2,而不能简单的判断<0。
函数3:
hypedefvoid(*pcap_handler)(u_char*user,
conststructpcap_pkthdr*pkt_header,
constu_char*pkt_data)
接收数据包的回调函数原型。当用户程序使用pcap_dispatch()或者pcap_loop(),数据包以这种回调的方法传给应用程序。用户参数是用户自己定义的包含捕获会话状态的参数,它必须跟pcap_dispatch()和pcap_loop()的参数相一致。pkt_hader是与抓包驱动有关的头。pkt_data指向包里的数据,包括协议头。
结构体1:
structpcap_pkthdr{
structtimevalts;
bpf_u_int32caplen;
bpf_u_int32len;
}
ts:时间戳
cpalen:当前分组的长度
len:数据包的长度