logo.gif (2519 bytes)

电脑学习
COMPUTER STUDY
1999年 第6期 No.6 1999

qklogo.gif (1030 bytes)

基于BPF和LIBPCAP库的包捕获应用系统的设计

钱丽萍 李亚萍 高光来

摘 要 包捕获和包分析是网络管理中使用的基本技术。它可用于网络测试、重构端到端的会话及监测网络运行状况等。本文分析了多种包捕获机制,着重探讨了BPF技术,介绍了一个用于用户层包捕获的系统独立的API接口Libpcap库,给出了利用BPF和Libpcap设计基于包捕获的应用程序的应用框架。
关键词 网络管理 包捕获 BPF libpcap

The Implementation of Packet Capture Application Systems based on BPF and libpcap

Qian Liping Li Yaping Gao Guanglai

  Abstract: Packet capture and packet analysis is one of the basic technologies used in network management. It is utilized in network testing, reconstructing end-to-end sessions and monitoring the status of network. This paper analyzed some packet capture mechanisms with emphasis on BPF technique. It then introduced libpcap librarya system-independent interface for user-level packet capture and described the general model of packet capture applications based on BPF and libpcap.
  Key words: network management packet capture BPF libpcap


  随着Internet应用的迅速发展,网络管理人员对Internet的运行状况和流通信息进行监测显得十分必要。包捕获和包分析是网络管理中使用的基本技术,可用于网络测试(如校验网络设置)、重构端到端的会话(如监视网络连接的安全工具)及监测网络负载等。通过对捕获的数据包进行分析,可以实时了解网络的使用情况(如响应时间、丢包率、某一时段的网络负载及平均负载),发现网络运行的瓶颈以及分析网络数据包中携带的非法内容等。用于实现将网卡设置成混杂模式而捕获网段上所有数据包的技术即称为包捕获技术,实现包捕获功能的工具称为嗅包器(sniffer)。
1 常见的包捕获技术
  包捕获机制是依赖于操作系统的,这种机制下嗅包器复制一个包,而不将其从系统的TCP/IP栈中移去。Linux系统为用户提供了一种工作在数据链路层的套接字SOCK-PACKET。这种套接字绕过系统协议栈直接从网卡驱动程序读取数据,所以用户用这种套接字可以直接获取数据链路层的原始数据包。如果先用Linux下的设备管理函数ioctl把网卡设置成侦听状态,用户就能用此套接字捕获流经所在子网的所有数据包。这种方法缺点是效率较低。在其他操作系统上也有类似的工具,如:WIN95和DOS环境下,可通过vpacket.vxd网卡驱动程序来捕包;SunOS中有NIT接口;在DEC的Ultrix环境下有Ultrix Packet Filter;在SGI的IRIX中有SNOOP;另外还有BSD的BSD Packet Filter(BPF)。其中BPF是一种效率较高、应用广泛的包捕获工具。常用的包捕获机制如表1所示。

表1 常用的包捕获机制

包捕获机制 系 统 平 台 备   注
BPF BSD系列 Berkeley Packet Filter
DLPI Solaris, HP-UX SCO Openserver Data Link Provider Interface
NIT SunOS 3 Network Interface Tap
SNOOP IRIX   
SNIT SunOS 4 Streams Network
Interface Tap
SOCK-PACKET Linux   
LSF >=Linux 2.1.75 Linux Socket Filter
Drain IRIX 用于窃听系统丢弃的包
2 BPF技术
  BPF是BSD Packet Filter的简称,目前UNIX平台上多数嗅包工具(如tcpdump、sniffit、NFR等)都是基于BPF开发的。通常网卡驱动程序接收到一个数据包后,将其提交给系统的协议栈。如果有进程用BPF进行网络侦听,网卡驱动程序会先调用BPF,复制一份数据给BPF的过滤器,过滤器则根据用户定义的规则决定是否接收此数据包。再判断这个数据包是否是发给本机的,如果不是发给本机的,则网卡驱动程序从中断返回,继续接收数据;如果这个数据包是发给本机的,驱动程序会再把它提交给系统的协议栈,然后返回。BPF的工作机制如图1所示。

0601.gif (6960 bytes)

图1 BPF结构原理

  UNIX系统严格区分核心地址空间和用户地址空间,用户的应用进程不能访问核心地址空间。由于网络监测器作为用户层进程运行,而网卡驱动程序工作在核心地址空间中,所以要提供用户层的接口就要把数据从核心地址空间复制到用户地址空间,这样做系统负担很大,当网络太忙或机器速度太慢时会发生丢包。为改进性能出现了包缓冲和包过滤机制。
  在SunOS的NIT中,收集来的数据包先复制到过滤器的缓冲区中,再进行过滤,故不论用户进程是否需要,每个数据包至少要作一次内存复制。Linux的SOCK-PACKET不作任何缓冲,且无内核过滤,在网络负载较大时效率很低。BPF在核心设置了过滤器,在核心中及早对数据包进行过滤,只将用户需要的数据提交给用户进程,减少了数据传送量。每个BPF都有一个缓冲区,如果过滤器判断接收某个包,BPF就将它复制到相应的缓冲区中暂存起来,等收集到足够多的数据后再一起提交给用户进程,这样减少了“read”系统调用,提高了效率。
  BPF还改进了过滤方式。目前基本的过滤规则表达方式有两种:一种是布尔表达树,另一种是BPF使用的有向无圈控制流图(Directed Acyclic Control Flow Graph 简称CFG)。树型过滤器的设计是围绕一个基于栈的过滤求值程序,它把控制规则布尔表达式及相关数据先压入栈,再逐步弹出,并计算结果。而BPF使用基于寄存器的过滤求值程序,比树型过滤器的快20倍。BPF还使用了一种简单的缓冲策略,使得在同一硬件上BPF的性能较SUN的NIT快约100倍。BPF过滤器和缓冲器是经过优化的,用户可用BIOCSBLEN ioct1() 增加缓冲区长度。
3 libpcap库
  libpcap 是劳伦斯伯克利国家实验室网络研究组开发的UNIX平台上的一个包捕获函数库,其源代码可从ftp://ftp.ee.lbl.gov/libpcap.tar.Z获得。它是一个独立于系统的用户层包捕获的API接口,为低层网络监测提供了一个可移植的框架。libpcap支持基于BPF体系的过滤机制(虽然也有其他支持内核过滤的包捕获接口),目前仅对BPF使用内核过滤,在没有BPF的系统中,所有的数据包都会被读入用户空间。libpcap的编译和安装参见其INSTALL文件。其主要函数有:
1.pcap-t *pcap-open-live();用于获得一个包捕获描述符。
2.char *pcap-lookupdev();返回一个适于pcap-open-live()和pcap-lookupnet()函数使用的指向网络设备的指针。
3.int pcap-lookupnet();用于判断与网络设备相关的网络号和掩码。
4.int pcap-dispatch()或int pcap-loop();收集和处理数据包。
5.void pcap-dump();将一个包输出到由pcap-dump-open()打开的保存文件中。
6.int pcap-compile();用于将过滤规则字符串编译成一个内核过滤程序。
7.int pcap-setfilter();设定一个过滤程序。
8.int pcap-datalink();返回数据链路层类型,如10M以太网、SLIP、PPP、FDDI、ATM、IEEE802.3等。
9.void pcap-close();关闭关联文件并回收资源。
4 基于BPF和libpcap的包捕获系统
  BPF包捕获技术提供了基于内核的过滤和缓冲,在高速高负载网络中可获得较好的性能。而libpcap作为一个通用可移植的包捕获API函数库,提供了对BPF的内在支持,它们的结合可以设计出高效的包捕获应用系统。基于BPF和libpcap的包捕获系统框架如图2所示。

0602.gif (8454 bytes)

图2 基于libpcap的包捕获系统框架

  在初始化完毕后,应用程序利用libpcap的pcap-dispatch()或pcap-loop()捕获数据链路层的数据包。这两个函数作用类似,仅以pcap-dispatch()为例介绍其工作原理。其函数原形为:pcap-dispatch(pcap-t *p, int cnt, pcap-handler callback, u-char *user);此函数返回读取的包数,当读到文件的EOF时返回0;返回-1表出错,此时可用pcap-perror或pcap-geterr函数来显示出错文本。
  参数cnt指定在返回前须处理的最大包数,cnt为-1则处理在一个缓冲区中接收的所有数据包;cnt为0表处理所有数据包直至发生一个错误(或遇到EOF)。callback指定了一个可用三个参数调用的例程,这三个参数包括:一个u-char指针(从pcap-dispatch()函数传递得到),一个指向pcap-pkthdr结构的指针(它位于真正的网络头和数据之前)和一个长度。callback一般设计成对所捕获的数据包进行分析的例程,如根据数据链路层类型选择数据包、打印数据包内容、实施信息匹配过滤等。所以基于BPF和libpcap设计包捕获分析系统,只需要集中设计此callback例程即可。
5 结束语
  包捕获是进行网络活动监测、负载和流量分析等网管活动中使用的基本技术,其性能直接影响到对网络运行状况和流通信息的监测,特别是在大型网络环境中,更要求包捕获模块能够快速高效地工作。我们在Linux环境上实现了一个邮件监测系统,其底层采用BPF捕获网络中服务端口号为25(发送邮件)或110(接收邮件)的数据包,pcap-loop()函数的callback参数设计为这样的处理函数:如果发现邮件来自非法地址或邮件内容中包含非法的字符串,则记录下此邮件的信息供后继处理,否则忽略。通过在网络上加入干扰数据包及加大网络负载进行实验,没有发生丢包现象,系统运行良好。

作者简介:钱丽萍,高光来 内蒙古大学计算机系讲师(呼和浩特 010021)
     李亚萍 哈尔滨工业大学计算机信息网络中心工程师(150001)

参考文献

1 McCanne, V.Jacobson. The BSD Packet Filter: A New Architecture for User-level Packet Capture. Proc. 1993 Winter USENIX Conference, San Diego. CA. Available at:ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z
2 Steven M.Bellovin.Packets Found on Internet. Computer Communication Review. 1993, (6): 1-6

收稿日期:1999-07-08