2.4.4 WinPcap内核驱动的主要功能

NPF能够执行许多操作,包括数据包捕获、数据包发送、网络统计及数据包转储到磁盘等。下面简要地介绍这些操作。

1.数据包捕获

NPF最重要的功能是执行数据包的捕获。在一个捕获过程中,驱动程序将利用一个网络接口卡嗅探数据包,并把数据包完整无缺地传送给用户层应用程序。捕获过程依赖下列两个主要组件:

(1)数据包过滤器

数据包过滤器决定是否将到来的数据包接收并复制到一个应用程序中。大多数使用NPF的应用程序,拒收的数据包比需接收的数据包多得多。由此可知,如果要获得通用的、较好的性能,关键是选用一个通用的、有较高效率的数据包过滤器。

数据包过滤器实际上是一段代码,也就是一个返回值为布尔型的函数。对一个数据包而言,如果函数的结果值为true,将复制数据包到应用程序中,如果是false,则将数据包丢弃。NPF数据包过滤器有一点复杂,因为它不仅决定数据包是否应该保留,同时还决定应该保留的字节数。

NPF驱动程序所采用的过滤器源于BSD数据包过滤器(BPF)。过滤使用的虚拟机能够执行过滤程序,该过滤程序采用的是伪汇编指令,并且是在用户空间创建的。应用程序会采用一个用户定义的过滤表达式(例如获得所有的UDP数据包)并利用wpcap.dll将该表达式编译为一段BPF格式的程序代码(例如,如果数据包是IP,同时协议类型字段值为17,则返回true)。接着应用程序使用命令码为BIOCSETF的IOCTL调用把该段代码传给内核驱动程序NPF。到此为止,该过滤器对进来的所有数据包执行过滤,并只接收遵循过滤条件的数据包。

为了提高性能,NPF不再采用传统解决方案的解释器方式来执行过滤器。NPF执行过滤器的过程如下:在使用过滤器之前,NPF把过滤器伪汇编指令给JIT编译器,该编译器再把它转换成一个本地80x86的函数。当一个数据包被捕获时,NPF调用该本地函数,而不是调用解释器来处理过滤,这使得处理过程更快。

(2)环形缓冲区

存储在缓冲区的数据包都带有一个数据包头,它包括如时间戳、包大小等信息。此外,为了提高应用程序访问数据的速度,数据包之间填充了一些空白区块以实现字操作对齐与便于读写的目的。为了使配置更具灵活性,在运行的时候内核与用户空间缓冲区的设置也能够被改变,而Packet.dll与wpcap.dll库则提供了实现该功能的接口函数。在单个读操作中,能从NPF复制一组数据包到应用程序,因为最小化了读的次数,所以提高了性能。当一个新的数据包到来时,如果缓冲区已满,该数据包将被丢弃,就会造成丢包。

用户缓冲区的大小非常重要,因为它决定了在单个系统调用内,能够从内核空间复制到用户空间的最大数据量。同时在单个调用中需要复制的最小数据量也非常重要(只有内核缓冲区的数据量达到这个量后才会执行复制)。一方面,如果将用户缓冲区设置为一个很大的数值,内核把数据复制到用户层之前,需要等待较多的数据包到来。这保证了少量的系统调用,也就是低的处理器占用。对诸如嗅探器的应用程序来说这是一个很好的设置。另一方面,一个小的数值意味着只要应用程序准备好接收数据包了,内核就复制数据包。对于实时应用程序(如ARP重定向器或网桥)这是极好的设置,这些应用都需要内核做出很好的响应。出于以上考虑,要求NPF具有一个可配置的灵活性,允许用户在最好的效率与最好的响应度(或任何中间情况)之间做出选择。

wpcap.dll库包括两个系统调用,可用来设置读超时时间与单个调用中内核复制到应用程序所需的最小数据量。默认状态下,读超时时间为1 s,内核与应用程序之间数据复制的最小数量为16 KB。

2.数据包发送

NPF允许把原始数据包发送到网络上。为了发送数据,用户层应用程序会在NPF设备上执行一个WriteFile系统调用。该数据被发送到网络上时,并不会对数据作任何协议封装,因此应用程序将不得不构建每个数据包的不同协议头。不过,应用程序不需要生成帧检验序列(Frame Check Sequence,FCS)。FCS通常由网络适配器硬件计算,并在发送到网络前自动添加到了数据包的尾部。

正常情况下,网络数据包的发送率并不是非常高的,因为每个数据包都需要一个系统调用。为了解决这个问题,WinPcap添加了使用一次写系统调用就能把单个数据包发送多次的功能。通过IOCTL调用,用户层应用程序能够设置单个数据包发送的次数。例如,如果该值设为1000,那么应用程序所写的每个原始数据包在内核驱动程序中都将会重复发送1000次。应用该功能可生成高速网络流量,上下文切换的负荷将不再出现,因此性能显著变好。

3.网络统计

WinPcap提供一个内核空间的模块,能够对网络流量进行简单的统计,该模块的实现思想如图2-3所示。统计信息不需要复制数据包到应用程序就能被收集,从统计模块中获取统计结果简化了接收与显示过程,这就避免了将统计的大部分工作耗费在内存与CPU上。

统计模块由一个分类器与一个计数器(紧接该分类器)组成。NPF过滤器提供一种可配置方式来针对网络流量的一个子集进行统计。数据包经过过滤器到达计数器,计数器保存了一些变量,如数据包的数目与过滤器接收到的字节的数量,并根据网络所接收数据包的数据来更新这些变量。在每个固定时间点上,这些变量被传递给用户层的应用程序,用户可以配置该时间间隔。在该统计模式下,内核与用户空间中都无须分配缓冲区。

4.数据包转储到磁盘

WinPcap具有把数据包转储到磁盘的能力,可以在内核模式下把网络数据直接存储到磁盘上。

图2-5中所示黑色实线箭头表示的就是在传统方式下把数据包存储到磁盘的过程。每个数据包都会被复制几次。正常情况下,在转储的过程中会分配4个缓冲区:一个供捕获驱动程序使用,一个供应用程序保持所捕获的数据使用,一个供应用程序写文件所用的stdio库函数(或类似函数)使用,最后一个供文件系统使用。

2.4.4 WinPcap内核驱动的主要功能 - 图1

图 2-5 数据包捕获与转储

当NPF的内核空间网络流量转储特性被激活时,驱动程序可直接访问文件系统,图2-5中所示虚线箭头表示的就是把数据包在内核中直接存储到磁盘的过程。在这个过程中,只有两个缓冲区与一次复制是必须的,而系统调用次数则彻底减为零,因此性能显著提高了。

为了兼容,当前的转储功能采用了现在广泛使用的libpcap/tcpdump文件格式来存储数据包。

为了有选择地存储数据包,也可以使用过滤器,以便在转储之前就对网络流量进行过滤。