libpcap是Packet Capture library的英文缩写,即数据包捕获函数库,该库提供的C函数接口用于捕获经过指定网络接口(通过将网卡设置为混杂模式,可以捕获所有经过该网络接口的数据包)的数据包。
著名的TCPDUMP就是在Libpcap的基础上开发而成的,Libpcap提供的接口函数主要实现和封装了与数据包的采集、构造、发送等有关的功能。
Libpcap面向上层应用,提供了用户级别的网络数据包捕获接口,在系统部署时充分考虑到应用程序的可以移植性。
Libpcap主要有如下功能:
(1)数据包捕获
捕获流经本网卡的所有原始数据包,甚至对交换设备中的数据包也能够进行捕获,本功能是嗅探器的基础。
(2)自定义数据包发送
构造任意格式的原始数据包,并发送到目标网络,本功能是新协议验证、甚至攻击验证的基础。
(3)流量采集与统计
对所采集到的网络中的流量信息进行按照新规则分类,按指标进行统计,并输出到指定终端。利用这项功能可以分析目标网络的流量特性。
(4)规则过滤
Libpcap自带规则过滤功能,并提供脚本编程接口,能够按照用户编程的方式对已经采集到的数据包进行过滤,以便提高分析的性能。
Libpcap的应用范围:
由于拥有强大的功能,当前基于Libpcap的应用比较广泛,有很多Unix上的流量相关的网络系统都是基于Libpcap的,它的一些典型应用如下:
(1)网络协议分析器
Libpcap应用最多的就是网络协议分析器,也可以称之为网络嗅探。
(2)网络流量发生器
网络流量发生器也是Libpcap的一大应用,它是基于Libpcap的数据构造与发送功能,可以有针对性的构造各种形式的数据包,并执行发送工作,这样的组合便构成了网络流量的产生工具。
(3)网络入侵检测系统
网络入侵检测系统(IDS)是发现网络入侵行为的关键,利用Libpcap所提供的数据包捕获功能,可以进一步开发出IDS。
(4)网络扫描器
这是基于Libpacp的数据包构造与发送功能。当前最著名的网络扫描器Tcpdump就是基于Libpcap开发而成的。
(5)其他安全工具
利用Libpacp可以设计出其他的网络安全工具。
不过有一点要提醒:Libpacp只是提供网络数据包的监测以及发送功能,并不提供控制层面的服务,类似于防火墙那种数据包过滤的功能,Libpcap是无法实现的。
Libpcap工作原理介绍
Libpcap是Unix/Linux平台下的网络数据包捕获数据库。它是一个独立于系统的用户级数据包捕获API接口,为底层网络监测提供了一个可以移植的框架。
(1) 工作原理
一个包捕获机制包含三个主要部分,分别是面向底层的包捕获引擎,面向中间层的数据包过滤器,面向应用层的用户接口。
Linux操作系统对于数据包的处理流程是从底到上的方式,依次经历网络接口卡、网卡驱动层、数据链路层、IP层、传输层,最后到达应用程序。
Libpcap也是基于这种原理,Libpcap的捕获机制并不影响Linux操作系统中网络协议栈对数据包的处理。
对应用程序而言,Libpcap包捕获机制只是提供了一个统一的API接口,用户只需要按照相关的编程流程,简单地调用若干函数就可以捕获到感兴趣的数据包。
具体来说,Libpcap库主要由三个部分组成,网络分接头、数据包过滤器和用户API。
(1)网络分接头
网络分接头(Network Tap)是一种链路层旁路机制,负责采集网卡数据包。
(2) 数据包过滤器
数据包过滤器(Packet Filter)是针对数据包的一种过滤机制,在Libpcap中采用BPF(BSD Packet Filter)算法对数据包执行过滤操作,这种算法的基本思想就是基于规则匹配,对伊符合条件的额数据包进行放行。
(3)用户API
用户API是Libpcap面向上层应用程序提供的编程接口,用户通过调用相关的函数实现数据包的捕获或者发送。
具体来说,Libpcap的工作原理可以描述为,当一个数据包到达网卡时,Libpcap利用创建的套接字从链路层驱动程序中获得该数据包的拷贝,即旁路机制,同时通过Tap函数将数据包发给BPF过滤器。
BPF过滤器根据用户已经定义好的过滤过则对数据包进行逐一匹配,若匹配成功则放入内核缓冲区,并传递给用户缓冲区,匹配失败则直接丢弃。如果没有设置过滤规则,所有的数据包都将放入内核缓冲区,并传递给用户缓冲区。
其具体的工作流程如下图所示:
抓包流程
理解了Libpcap的工作原理,下面将介绍如何利用Libpcap库进行数据包的捕获。其具体的编程流程如下:
(1) 网络设备查找
网络设备查找的目的就是发现可用的网卡,它的实现函数是pcap_lookupdev(),如果当前有多个网卡,它会返回一个网络设备名指针列表。
(2) 打开网络设备
利用第一步的返回值,用户可以决定Libpcap实用哪个网卡,当然打开这个网络设备的函数是pcap_open_live(),它返回用于捕获网络数据包的数据包捕获描述字。对于此网络设备的任何操作都要基于这个描述字。
(3) 获取网络参数
利用pcap_lookupnet()函数,可以获得指定网络设备的IP地址和子网掩码,当然这个步骤并不是必须,但是为了显示的完整性,有时候还是需要标记这些参数。
(4) 编译过滤策略
Libpcap的一个功能就是提供数据包过滤,即只采集符合规则的数据包,此项功能由函数pcap_compile()来实现,这个函数的作用即使将用户指定的过滤策略编译到过滤程序中。
(5) 设置过滤器
这是上步骤的继续,pcap_setfilter()函数用于设置上一步骤配置好的过滤器,当然要注明一点,步骤4和步骤5也不是必须的,如果不采用过滤,意味着程序会抓到所有的网络数据包。
(6) 利用回调函数捕获数据包
Libpcap提供的是一种回调的机制来获取数据包,可以采用pcap_loop()和pcap_dispatch()函数来抓取数据包,当然,也可以调用pcap_next和pcap_next_ex()函数来完成同样的工作。
若数据包捕获到之后,应用程序就可以采用相应的方式进行数据包解析,分析其中感兴趣的信息,当然分析工作往往是整个程序的关键。
(7) 关闭网络设备
当应用程序工作完毕时,可以调用pcap_close()函数关闭网络设备,释放资源。
具体工作流程如下所示:
Libpcap库主要函数说明
函数名称:pcap_t *pcap_open_live(char *device, int snaplen, intpromisc, int to_ms, char *ebuf)
函数功能:获得用于捕获网络数据包的数据包捕获描述字。
参数说明:device参数为指定打开的网络设备名。snaplen参数定义捕获数据的最大字节数。promisc指定是否将网络接口置于混杂模式。to_ms参数指*定超时时间(毫秒)。ebuf参数则仅在pcap_open_live()函数出错返回NULL时用于传递错误消息。
函数名称:pcap_t *pcap_open_offline(char *fname, char *ebuf)
函数功能:打开以前保存捕获数据包的文件,用于读取。
参数说明:fname参数指定打开的文件名。该文件中的数据格式与tcpdump和tcpslice兼容。”-“为标准输入。ebuf参数则仅在pcap_open_offline()函数出错返回NULL时用于传递错误消息。
函数名称:pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)
函数功能:打开用于保存捕获数据包的文件,用于写入。
参数说明:fname参数为”-“时表示标准输出。出错时返回NULL。p参数为调用pcap_open_offline()或pcap_open_live()函数后返回的pcap结构指针。fname参数指定打开的文件名。如果返回NULL,则可调用pcap_geterr()函数获取错误消 息。
函数名称:char *pcap_lookupdev(char *errbuf)
函数功能:用于返回可被pcap_open_live()或pcap_lookupnet()函数调用的网络设备名指针。参数说明:如果函数出错,则返回NULL,同时errbuf中存放相关的错误消息。
函数名称:int pcap_lookupnet(char *device, bpf_u_int32*netp,bpf_u_int32 *maskp, char *errbuf)
函数功能:获得指定网络设备的网络号和掩码。
参数说明:netp参数和maskp参数都是bpf_u_int32指针。如果函数出错,则返回-1,同时errbuf中存放相关的错误消息。
函数名称:int pcap_dispatch(pcap_t *p, int cnt,pcap_handlercallback, u_char *user)
函数功能:捕获并处理数据包。
参数说明:cnt参数指定函数返回前所处理数据包的最大值。cnt=-1表示在一个缓冲区中处理所有的数据包。cnt=0表示处理所有数据包,直到产生以下错误之一:读取到EOF;超时读取。callback参数指定一个带有三个参数的回调函数,这三个参数为:一个从pcap_dispatch()函数传递过来的u_char指针,一个pcap_pkthdr结构的指针,和一个数据包大小的u_char指针。如果成功则返回读取到的字节数。读取到EOF时则返回零值。出错时则返回-1,此时可调用pcap_perror()或pcap_geterr()函数获取错误消息。
函数名称:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback,u_char *user)
函数功能:功能基本与pcap_dispatch()函数相同,只不过此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。而如果为pcap_open_live()函数指定了一个非零值的超时设置,然后调用pcap_dispatch()函数,则当超时发生时pcap_dispatch()函数会返回。cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误。
函数名称:void pcap_dump(u_char *user, struct pcap_pkthdr*h,u_char *sp)
函数功能:向调用pcap_dump_open()函数打开的文件输出一个数据包。该函数可作为pcap_dispatch()函数的回调函数。
函数名称:int pcap_compile(pcap_t *p, struct bpf_program *fp,char*str, int optimize, bpf_u_int32 netmask)
函数功能:将str参数指定的字符串编译到过滤程序中。
参数说明:fp是一个bpf_program结构的指针,在pcap_compile()函数中被赋值。optimize参数控制结果代码的优化。netmask参数指定本地网络的网络掩码。
函数名称:int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
函数功能:指定一个过滤程序。
参数说明:fp参数是bpf_program结构指针,通常取自pcap_compile()函数调用。出错时返回-1;成功时返回0。
函数名称:u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
函数功能:返回指向下一个数据包的u_char指针。
函数名称:int pcap_datalink(pcap_t *p)
函数功能:返回数据链路层类型,例如DLT_EN10MB。
函数名称:int pcap_snapshot(pcap_t *p)
函数功能:返回pcap_open_live被调用后的snapshot参数值。
函数名称:int pcap_is_swapped(pcap_t *p)
函数功能:返回当前系统主机字节与被打开文件的字节顺序是否不同。
函数名称:int pcap_major_version(pcap_t *p)
函数功能:返回写入被打开文件所使用的pcap函数的主版本号。
函数名称:int pcap_minor_version(pcap_t *p)
函数功能:返回写入被打开文件所使用的pcap函数的辅版本号。
函数名称:int pcap_stats(pcap_t *p, struct pcap_stat *ps)
函数功能:向pcap_stat结构赋值。成功时返回0。这些数值包括了从开始捕获数据以来至今共捕获到的数据包统计。如果出错或不支持数据包统计,则返回-1,且可调用pcap_perror()或pcap_geterr()函数来获取错误消息。
函数名称:FILE *pcap_file(pcap_t *p)
函数功能:返回被打开文件的文件名。
函数名称:int pcap_fileno(pcap_t *p)
函数功能:返回被打开文件的文件描述字号码。
函数名称:void pcap_perror(pcap_t *p, char *prefix)
函数功能:在标准输出设备上显示最后一个pcap库错误消息。以prefix参数指定的字符串为消息头。
函数名称:char *pcap_geterr(pcap_t *p)
函数功能:返回最后一个pcap库错误消息。
函数名称:char *pcap_strerror(int error)
函数功能:如果strerror()函数不可用,则可调用pcap_strerror函数替代。
函数名称:void pcap_close(pcap_t *p)
函数功能:关闭p参数相应的文件,并释放资源。
函数名称:void pcap_dump_close(pcap_dumper_t *p)
函数功能:关闭相应的被打开文件。