libpcap体现的不是捕捉技术上的难点,而是对细节的控制上,对跨平台代码的编写上,对过滤机制的优化上。
大象的命门是在脚筋,也就是支撑的地方。 很显然,得先对接口的流动和他的数据结构有个了解。而且在这套库里面看到了好多人的代码和自己的功能说明,感觉着一种合作开放的精神。
剪枝删节,将其中linux部分提了出来,涉及到的文件大概有:
inet.c fad-getad.c pcap-linux.c pcap-int.h pcap.c
整个的大概结构是,查找设备,确定设备,过滤条件的嵌入,套接字的创建,网卡的设置,包的捕获。
查找设备:用到的函数有pcap_lookupdev()-pcap_findalldevs()-getifaddrs()-add_addr_to_iflist()//inet.c fad_getad.c
该函数是将所找到的设备信息用连表连接起来,设备号小的在前,因此通常是eth0.
数据结构为struct pcap_if{},//pcap.h
打开网络设备:2。0以后的linux内核版本用新的协议簇PF_PACKET来实现。早期是(SOCK_PACKET)他的形式可以是SOCK_RAW和SOCK_DGRAM。RAW是原始数据,DGRAM是对数据包进行加工,把数据包的链路层头部去掉,使用sockaddr_ll来保存。在两种情况下RAW不可用:某些类型设备数据链路层头部不可用,当捕捉为any时,为了是包过滤机制在所有类型数据包上正常工作,要求所有数据使用相同数据链路头部。
pcap-linux.c
pcap_open_live();用到的数据结构是pcap_t,//pcap-int.h,这是一个比较重要的参数,主要包括对socket的描述,和一些底层上的设置。比如缓冲区大小,设备类型,边界对齐等,对应的函数指针,可更改的链路数,BPF过滤代码是否能使用等。
pcap_stat stat;//pcap.h,捕捉状态结构,包括是否过滤,接受包的数目,丢弃的数目等。
在函数内部有new和old两种版本,分别对2.0前后的版本创建socket.而在其内部的选择上,又涉及到对是否支持链路层头部结构的判断,最后将网卡设为混杂模式,创建socket
在这一层中,libpcap提供的用户程序接口是pcap_next()//pcap.c,通过跟踪可发现,它最后是调用pcap_read_packet//pcap-linux.c接收。接收完后做的工作如下:偏移量设置,为了给伪数据链路层留出空间,接着要修正长度,判断是否有用内核级的包过滤,最后填充捕获时间/长度/时间,对包数据累加。
完成以上两个步骤,发现最关键两个步骤就是找设备的函数,和socket的创建。但是通过查看源代码可知,作者在跨平台,细节处理,包通用的完善性上做了很多很多的工作,这无一不给我们提供了一个很好的学习尺度。
接下来是对过滤机制的描述:
这个我想是最有难点的地方了,一些算法不做描述,查看pcap-bpf.h,gencode.c,optimize.c,grammar,c,scanner.c
用到的特性有这么几个:因为在捕捉时,是先经过捕捉,然后把控制权再给数据链路,这样就直接在内核缓冲内进行过滤。而在算法是上使用BPF包过滤机制,算法上很复杂,使用伪机器码的方式,类似于汇编语言。如果是以后做到类似多重判断跳转之类的可以参考里面的无环控制流图CFG的实现.
个人认为该库很大一部分研究价值除了跨平台编写,还有就是对linux底层过滤器的调用使用。