11.2 网络统计的幕后11.2.1工作模式
WinPcap的驱动程序提供了下面四种工作模式,以满足不同的应用需求。
1.捕获模式(mode=PACKET_MODE_CAPT)
该模式是正常的数据包捕获模式,是默认的工作模式。在该模式下,网络上传输的数据包将被复制到应用程序中。
2.统计模式(mode=PACKET_MODE_STAT)
该模式统计网络流量或网络状态信息。相对于捕获模式,统计模式对系统性能的影响非常低。
在该模式下,如果调用PacketReceivePacket函数将返回在一个精确的时间间隔内网络流量的统计信息。该信息数据的结构如图11-4所示。
图 11-4 统计模式返回数据的结构
返回的数据包含有两个64位(8字节)的计数器:代表符合预先设定过滤器条件的数据包的个数(PacketsAccepted)与字节数(BytesAccepted)。如果没设置过滤器,则对所有的数据包进行计数。
统计采样的时间间隔默认为1s,但是可以通过PacketSetReadTimeout函数将其设置为任意其他的值(精度为1ms)。
在该模式下,如果调用pcap_stats与pcap_stats_ex函数将返回pcap_stat结构体,该结构体储存了网络的状态信息。
3.转储模式(mode=PACKET_MODE_DUMP)
在这种模式下,驱动程序以libpcap格式将所捕获的数据包存储到磁盘中。该模式比捕获数据包再存储的方式快很多。函数PacketReceivePacket不返回数据。如果应用程序通过PacketSetBPF函数设置了过滤器,就只有符合过滤条件的数据包会被存储到磁盘中。
4.统计转储模式(mode=PACKET_MODE_STAT_DUMP)
该模式的定义如下:
defne PACKET_MODE_STAT_DUMP MODE_DUMP|MODE_STAT
由上述代码可知,该模式是统计模式与转储模式的组合,可以在转储的同时执行信息统计。该模式下,驱动程序以libpcap格式将数据包存储到磁盘中,这与转储模式一样。同时按照一个精确的时间间隔,PacketReceivePacket函数以与统计模式类似的方式返回网络流量的统计值与转储到文件的数据量。
该模式下,PacketReceivePacket函数返回的统计信息数据的结构如图11-5所示。
图 11-5 统计转储模式返回数据的结构
返回的数据包含有三个64位(8字节)的计数器:符合预先设定的过滤器数据包的个数(PacketsAccepted)、数据包字节数(BytesAccepted),以及存储到文件的有效数据量(DumpSize,包括头信息)。
11.2.2 模式设置函数
模式设置的主要函数调用关系如图11-6所示。
图 11-6 模式设置的主要函数调用关系
1.wpcap.dll库中相应接口函数的实现
pcap_setmode函数将NPF的工作模式设置为参数mode所指定的模式,其原型如下:
int pcap_setmode(pcap_t*p,int mode);
如果pcap_setmode函数设置成功则返回0,表示统计从设置之时开始;如果出现错误则返回-1。
该函数的具体实现代码如下:
int pcap_setmode(pcap_t*p,int mode)
{
return p->setmode_op(p,mode);
}
static int pcap_activate_win32(pcap_t*p)
{
p->setmode_op=pcap_setmode_win32;
}
/设置驱动的工作模式/
static int pcap_setmode_win32(pcap_t*p,int mode)
{//调用Packet.dll库的PacketSetMode函数
if(PacketSetMode(p->adapter,mode)==FALSE)
{//工作模式不正确
return-1;
}
return 0;
}
2.Packet.dll库中相应接口函数的实现
PacketSetMode函数用于设置NPF的工作模式,其原型如下:
BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode)
上述函数中,参数AdapterObject指向一个_ADAPTER结构体,描述当前的适配器。参数mode描述需要设置的工作模式。
如果PacketSetMode函数设置成功则返回非0值。
该函数的具体实现代码如下:
BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode)
{
DWORD BytesReturned;
BOOLEAN Result;
if(AdapterObject->Flags==INFO_FLAG_NDIS_ADAPTER)
{//调用DeviceIoControl函数设置操作模式
Result=(BOOLEAN)DeviceIoControl(
AdapterObject->hFile,BIOCSMODE,&mode,4,
NULL,0,&BytesReturned,NULL);
}
else
{
Result=FALSE;
}
return Result;
}
3.驱动程序中相应的函数
NPF_IoControl函数的BIOCSMODE命令码用来设置工作模式,相关的主要代码如下:
/*
*#defne BIOCSMODE 7412
*设置工作模式,#MODE_CAPT为默认模式
*/
case BIOCSMODE:
/检查输入参数的合法性/
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
/获得需要设置的工作模式/
mode=*((PULONG)Irp->AssociatedIrp.SystemBuffer);
if(mode&MODE_DUMP)
{//当前版本,内核转储模式不被支持
SET_FAILURE_INVALID_REQUEST();
break;
}
if(mode==MODE_CAPT)//捕获模式
{
Open->mode=MODE_CAPT;
SET_RESULT_SUCCESS(0);
break;
}
else if(mode==MODE_MON)
{//当前版本,该模式不被支持
……
}
else
{
if(mode&MODE_STAT){//统计模式
Open->mode=MODE_STAT;
NdisAcquireSpinLock(&Open->CountersLock);
//统计计数清零
Open->Nbytes.QuadPart=0;
Open->Npackets.QuadPart=0;
NdisReleaseSpinLock(&Open->CountersLock);
//超时值,永不超时
if(Open->TimeOut.QuadPart==0)
Open->TimeOut.QuadPart=-10000000;
}
if(mode&MODE_DUMP){//转储模式,也可能为转储统计模式
Open->mode|=MODE_DUMP;
}
SET_RESULT_SUCCESS(0);
break;
}
SET_FAILURE_INVALID_REQUEST();
break;
}