libpcap学习笔记
libpcap函数

libpcap函数1)ioctl函数定义ioctl()函数非常庞杂,它可以控制各种文件的属性。
ioctl函数原型为:int ioctl(int handle,int cmd[,int *argdx,int argcx]);2)socket函数定义常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据包式Socket(SOCK_DGRAM)。
流式是一种面向连接的Socket,针对面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,针对无连接的UDP服务应用。
Socket函数原型为:int socket(int domain, int type,int protocol);3)recvfrom()函数定义用recvfrom()函数来实现接收数据包,recvfrom()是具备“阻塞式I/O”特性的函数,能够在没有数据包到达的情况下暂时挂起等待,直至接收到数据包后,再激活转入下一步处理。
recvfrom()函数的原型为:int recvfrom(SOCKET s,char FAR *buf,int len,int flags,structsockaddr FAR *from,int *fromlen);本函数从已连接套接口上接收数据,并捕获数据发送源的地址。
对于SOCK_STREAM类型的套接口,最多可以接收缓冲区大小个数据。
如果套接口被设置为线内接收带外数据(选项为 SO_OOBINLINE),且有带外数据未读入,则返回带外数据。
应用程序可通过调用ioctlsocket()的SOCATMARK命令来确定是否有带外数据待读入。
对于SOCK_STREAM类型套接口,忽略from和fromlen参数。
因为面向连接的话不用再指定地址了。
4)一些“字节顺序”转换函数因为网络和主机采用的存储字节时内存顺序安排方式的差异,就存在“字节顺序”的问题。
在网络环境下存储时,高位字节存放在内存的起始位置,而低字节则存放在较高的位置。
网络数据包的获取与libpcap应用

载波监听
指在以太网中的每个站点都具有同等的权利, 指在以太网中的每个站点都具有同等的权利,在传输自己 的数据时,首先监听信道是否空闲,如果空闲, 的数据时,首先监听信道是否空闲,如果空闲,就传输自 己的数据,如果信道被占用,就等待信道空闲。 己的数据,如果信道被占用,就等待信道空闲。 冲突检测 为了防止发生两个站点同时监测到网络没有被使用时而产 生冲突。以太网采用广播机制 广播机制, 生冲突。以太网采用广播机制,所有与网络连接的工作站 都可以看到网络上传递的数据。 都可以看到网络上传递的数据。
数据包接收过程
二、以太网
以太网最初是由XEROX公司研制 并且在 公司研制,并且在 以太网最初是由 公司研制 并且在1980年由数据 年由数据 设备公司DEC(DIGIAL EQUIPMENT CORPOR ATION)、 设备公司 、 INTEL公司和 公司和XEROX公司共同使之规范成形。后来它被作 公司共同使之规范成形。 公司和 公司共同使之规范成形 802.3标准为电气与电子工程师协会 IEEE)所采纳。 标准为电气与电子工程师协会( 为802.3标准为电气与电子工程师协会(IEEE)所采纳。 以太网是最为流行的网络传输系统之一。 以太网是最为流行的网络传输系统之一。以太网的基本 特征是采用一种称为载波监听多路访问 冲突检测CSMA/CD 载波监听多路访问/冲突检测 特征是采用一种称为载波监听多路访问 冲突检测 (Carrier Sense Multiple Access/ Collision Detection)的 的 共享访问方案。 共享访问方案。
TCP/IP与以太网 TCP/IP与以太网
以太网和TCP/IP可以说是相辅相成的。 可以说是相辅相成的。 以太网和 可以说是相辅相成的 以太网在一二层提供物理上的连线,使用48位的 以太网在一二层提供物理上的连线,使用 位的MAC地址 地址 位的 TCP/IP工作在上层,使用 位的 地址 工作在上层, 位的IP地址 工作在上层 使用32位的 两者间使用ARP和RARP协议进行相互转换。 协议进行相互转换。 两者间使用 和 协议进行相互转换
Libpcap网络抓包(linux C)

1. 入门使用篇本篇讲述如何抓包最简单的libpcap抓包程序只要有以下几句就可以了char ebuf[PCAP_ERRBUF_SIZE];pcap_t *pd = pcap_open_live("eth0", 68, 0, 1000, ebuf);建立libpcap捕捉句柄,若出错,ebuf返回错误字串.ebuf可以为NULL(以后同)struct bpf_program fcode;pcap_compile(pd, &fcode, NULL, 1, 0);添写过滤规则串fcode,可以为空(即第三个参数,格式在后面讲到)pcap_setfilter(pd, &fcode);给pd 设置上过滤规则pcap_loop(pd, 10, eth_printer, NULL);主循环,开始抓包,共抓10个(由第二个参数指定),抓到包后就进入函数eth_printerpcap_close(pd);结束这个就是最简单的程序了,其中还有个不明,在pcap_loop参数eth_printer的类型是pcap_handler,pcap_handler定义如下: typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,const u_char *);当然要包含#include "pcap.h"编译要加上-lpcap至于怎么得到libpcap,还有安装,我就不费话了本文版权所有:doggy(chaujy@) 欢迎转载2. 使用进阶篇刚才我们对程序的要求是能编译通过,能运行成功现在我们让这个程序实用点吧2.1 其它几个函数介绍这几个函数的特点是简单但无关紧要现在我们隆重退出char * pcap_lookupdev ( char * errbuf );这个函数就是查找本机上的网络接口设备,我机器上就返回"eth0",在pcap_open_live之前用,没什么意思吧,反正我是不爱用它int pcap_lookupnet(char *, bpf_u_int32 *, bpf_u_int32 *, char *);第一个参数就是pcap_lookupdev返回的接口名,二三参数都是32位无符号数, 分别是IP网段和掩码,最后那个参数还是ebufint pcap_datalink(pcap_t *);它返回你的网络类型,如DLT_EN10MB 就是10M以太网int pcap_snapshot(pcap_t *);返回最长抓多少字节,就是我们在pcap_open_live中第二个参数设置的int pcap_stats(pcap_t *, struct pcap_stat *);计数,共抓了多少过滤掉了多少,看看struct pcap_stat的定义就明白了struct pcap_stat {u_int ps_recv; /* number of packets received */u_int ps_drop; /* number of packets dropped */u_int ps_ifdrop; /* drops by interface XXX not yet supported */};int pcap_major_version(pcap_t *);int pcap_minor_version(pcap_t *);版本号,你有用么?我的eth_printer如下void eth_printer(u_char * user, const struct pcap_pkthdr * h, const u_char * p) {printf("I get one packet! ");}简单吧:*)2.2 现在的程序(C++)文件名p.cxx#ifdef __cplusplusextern "C" {#endif#include#ifdef __cplusplus}#endifvoid printer(u_char * user, const struct pcap_pkthdr * h, const u_char * p){printf("I get one packet! ");/* 哈哈,我都想喝一杯庆祝一下了! */}#define DEFAULT_SNAPLEN 68/* 别问我为什么是68,我从tcpdump看来的*/int main(){char ebuf[PCAP_ERRBUF_SIZE];char *device = pcap_lookupdev(ebuf);bpf_u_int32 localnet, netmask;pcap_lookupnet(device, &localnet, &netmask, ebuf);printf("%u.%u.%u.%u", localnet&0xff, localnet>>8&0xff,localnet>>16&0xff, localnet>>24&0xff); /*本地IP网段号*/printf(":%d.%d.%d.%d ", netmask&0xff, netmask>>8&0xff,netmask>>16&0xff, netmask>>24&0xff); /*本地IP掩码*/struct pcap_t *pd = pcap_open_live(device, DEFAUL T_SNAPLEN, 0, 1000, ebuf);if(pcap_datalink(pd) == DLT_EN10MB)printf("10Mb以太网");struct bpf_program fcode;pcap_compile(pd, &fcode, NULL, 1, 0);pcap_setfilter(pd, &fcode);pcap_loop(pd, 10, printer, NULL);struct pcap_stat stat;pcap_stats(pd, &stat);printf("recv %d, drop %d. ", stat.ps_recv, stat.ps_drop);pcap_close(pd);}#gcc p.cxx -lpcap#./a.out166.111.168.0:255.255.252.010Mb以太网I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!recv 10, drop 0.#重要提示: libpcap 程序需要root权限2.3 出错处理象其它库一样,libpcap 也有自己的错误处理机制基本上每个函数都有返回值,出错时返回值<0,另外有如下函数void pcap_perror(pcap_t *, char *);char *pcap_strerror(int);char *pcap_geterr(pcap_t *);前两个和perror() strerror() 用法相同,最后一个也很简单在pcap_t 中有一个成员存了错误字串struct pcap {...char errbuf[PCAP_ERRBUF_SIZE];};所以......于是我们在刚才的程序中加上错误处理先加一个函数#includeint err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);vfprintf(stderr, fmt, ap);va_end(ap);exit(-1);}之后处理每个函数的异常,在成功建立捕捉句柄pcap_t *pd前,使用ebuf参数char *device = pcap_lookupdev(ebuf);if(device == NULL)err_quit("%s", ebuf);有了句柄pd后if(pcap_compile(pd, &fcode, NULL, 1, 0) < 0)err_quit("%s", pcap_geterr(pd));注意不是每个函数都是出错返回<0pcap_datalink(pd)和pcap_snapshot(pd)等可不要这么处理2.4 参数初步研究前面使用各函数时,并没有具体说明每个函数的意义,现在来探讨一下pcap_t * pcap_open_live(char *device, int snaplen, int promisc,int to_ms, char *ebuf)device指定设备,snaplen指定最长抓多少字节,ebuf出错信息,前面都说过promisc指出是否设置为混杂模式(不懂?我也不懂,整个网都听还有什么安全性可言) to_ms设置超时时间,单位millisecondsint pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)cnt为要抓的包数,pcap_loop在正常时抓cnt个包后返回,异常时返回值<0user是要传入callback()的数据,例如我们把上面的程序修改几行file://pcap_loop(pd, 10, printer, NULL);pcap_loop(pd, 10, printer, (u_char*)pd);再在printer()内加pcap_stat stat;pcap_stats((pcap_t*)user, &stat);printf("recv %d, drop %d. ", stat.ps_recv, stat.ps_drop);再编译运行后输出为166.111.168.0:255.255.252.010Mb以太网recv 1, drop 0.recv 2, drop 0.recv 3, drop 0.recv 4, drop 0.recv 5, drop 0.recv 6, drop 0.recv 7, drop 0.recv 8, drop 0.recv 9, drop 0.recv 10, drop 0.recv 10, drop 0.int pcap_compile(pcap_t *p, struct bpf_program *program,char *buf, int optimize, bpf_u_int32 mask)该函数用于解析过滤规则串buf,填写bpf_program结构.optimize为1表示对过滤规则进行优化处理netmask指定子网掩码buf的格式比较复杂int pcap_setfilter(pcap_t *handle, struct bpf_program *filter)把pcap_compile()构造的filter设置到handle上。
libpcap原理及优化

相比libpcap1.0之前版本,共享内存缓存队列减少了一次数据包拷贝和调 用recvmsg、退出内核态的系统开销,因此有较大的性能提升
Libpcap原理及优化
Mail : Author : panda-bob
Linux数据包处理流程
具体的Linux数据包处理流程如图 1所示。数据包从网卡经过内核最终 到达用户空间的应用程序,其中经过 三次处理:中断服务、软中断和应用 程序。使用三个缓存:DMA、包队列 和插口。在网卡驱动中存在运行时内 存分配,从内核到用户态时存在一次 内存拷贝。
限制系统数据包的捕获处理能力可能原 因
① 处理流程单一:整个处理流程串行化,其处理能力受限于整个流程的 任何一处“短板”。在多核架构系统中这样的处理方式无法发挥并行 优势,存在极大的资源浪费。
② 高中断服务负荷:由于采用每接收一个数据包就产生一次中断的方式, 当数据包以很高的速率到达时,即使最快的处理器也会被持续的中断 服务请求占用而无法处理数据包,从而导致数据包丢失。
PACKET套接字的两大核心模块
1、BPF(berkeley packet filter)过滤器 BPF根据用户设置的过滤规则计算应该接收的数据包长度值,如果该值比数
据包的长度小,那么数据包将会被截短.特别地,如果该值为0,数据包会被 PACKET套接字丢弃而直接返回协议栈进行网络层的处理.BPF在Linux中,BPF被 用于内核进行数据包过滤,以减小提交给应用程序的数据包的包数和字节数,提 高系统性能。 2、缓存队列(BufferQ)
libpcap主要函数及过程详解

libpcap主要函数及过程详解/uid-21556133-id-120228.htmllibpcap(Packet Capture Library),即数据包捕获函数库,是Unix/Linux平台下的⽹络数据包捕获函数库。
它是⼀个独⽴于系统的⽤户层包捕获的API接⼝,为底层⽹络监测提供了⼀个可移植的框架。
⼀、libpcap⼯作原理libpcap主要由两部份组成:⽹络分接头(Network Tap)和数据过滤器(Packet Filter)。
⽹络分接头从⽹络设备驱动程序中收集数据拷贝,过滤器决定是否接收该数据包。
Libpcap利⽤BSD Packet Filter(BPF)算法对⽹卡接收到的链路层数据包进⾏过滤。
BPF算法的基本思想是在有BPF监听的⽹络中,⽹卡驱动将接收到的数据包复制⼀份交给BPF过滤器,过滤器根据⽤户定义的规则决定是否接收此数据包以及需要拷贝该数据包的那些内容,然后将过滤后的数据给与过滤器相关联的上层应⽤程序。
libpcap的包捕获机制就是在数据链路层加⼀个旁路处理。
当⼀个数据包到达⽹络接⼝时,libpcap⾸先利⽤已经创建的Socket从链路层驱动程序中获得该数据包的拷贝,再通过Tap函数将数据包发给BPF过滤器。
BPF过滤器根据⽤户已经定义好的过滤规则对数据包进⾏逐⼀匹配,匹配成功则放⼊内核缓冲区,并传递给⽤户缓冲区,匹配失败则直接丢弃。
如果没有设置过滤规则,所有数据包都将放⼊内核缓冲区,并传递给⽤户层缓冲区。
⼆、libpcap的抓包框架pcap_lookupdev()函数⽤于查找⽹络设备,返回可被pcap_open_live()函数调⽤的⽹络设备名指针。
pcap_open_live()函数⽤于打开⽹络设备,并且返回⽤于捕获⽹络数据包的数据包捕获描述字。
对于此⽹络设备的操作都要基于此⽹络设备描述字。
pcap_lookupnet()函数获得指定⽹络设备的⽹络号和掩码。
pcap_compile()函数⽤于将⽤户制定的过滤策略编译到过滤程序中。
tcpdump原理之利用libpcap实现抓包

tcpdump原理之利用libpcap实现抓包tcpdump原理之利用libpcap实现(转载请标明出处,请勿用于商业用途)/linux_embedded/article/details/8826429Linux下赫赫有名的抓吧工具tcpdump,想必使用过的人都十分的清楚。
但是,其实现的原理却很少人提及过,今天就tcpdump的实现原理做简单的介绍。
tcpdump 首先利用libpcap工具,将linux网络栈中的数据包抓取上来,然后,tcpdump在按照用户的需求完成数据包的分析工作。
下面就如何通过libpcap实现数据包的抓取做简单的介绍。
开始:libpcap的使用方式首先,我们需要了解一下pcap 嗅探器使用的一般布局,下面分为几个部分简单介绍。
1.首先我们需要定义我们需要使用的网络接口。
在linux下,我们一般会定义eth0或ethx。
在BSD下,可能是xl1。
我们可以把网络接口定义为字符串,或者可以通过pcap获得可用的网络接口的名字。
2.初始化pcap。
现在,我们可以将我们将要监听的网络设备告诉pcap。
如果有需要的话,我们可以使pcap同时监听多个网络接口。
我们可以通过“文件句柄”来区分不同的网络接口,就像我们打开文件进行文件的读取、写入一样,我们必须定义区分我们的监听“回话”,否则我们没有办法区分不同的监听对象(网络设备)。
3.如果我们仅仅想监听特殊的网络数据(例如,我们想监听TCP 业务,或者我们只想监听端口号为23的业务)。
我们可以自己定义一个监听规则的集合,“编译”它,然后在应用它。
上面三个步骤,连接的十分紧密,那一个步骤都不能丢掉。
规则其实就是定义好的字符串,我们需要将其转化为pcap可以是别的格式(所以我们需要编译)。
“编译器”仅仅通过内置的函数就可以实现上述的格式转换。
然后我们可以告诉pcap执行规则完成数据包的过滤。
4.之后,我们会告诉pcap进入主要的循环执行状态。
Libpcap详细教程

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。
libpcap

函数名称: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指针。
Libpcap库主要函数说明
函数名称:pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 函数功能:获得用于捕获网络数据包的数据包捕获描述字。 参数说明:device参数为指定打开的网络设备名。snaplen参 数定义捕获数据的最大字节数。promisc指定是否将网络接口 置于混杂模式。to_ms参数指*定超时时间(毫秒)。ebuf参数 则仅在pcap_open_live()函数出错返回NULL时用于传递错误消 息。 函数名称:char *pcap_lookupdev(char *errbuf) 函数功能:用于返回可被pcap_open_live()或pcap_lookupnet() 函数调用的网络设备名指针。参数说明:如果函数出错,则返 回NULL,同时errbuf中存放相关的错误消息。
过滤规则详细说明:
/link?url=OVjyr2tH30n0MnpYM44DlENU7Me2Q5uCwlmj7pkX10m5tFBOBf37y-DPnalckI1pXX9sNm4bvzGma84iSvgngcts3Yzv4_DxtzAFbc r7
开始:pcap应用程序的格式
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
struct pcap_pkthdr {struct timeval ts; /* time stamp */时间戳bpf_u_int32 caplen; /* length of portion present */在线抓到包的长度,无符号整形bpf_u_int32 len; /* length this packet (off wire) */离线包长度};pcap_pkthdr是.pcap文件中包的头部1.入门使用篇本篇讲述如何抓包最简单的libpcap抓包程序只要有以下几句就可以了char ebuf[PCAP_ERRBUF_SIZE];pcap_t *pd = pcap_open_live("eth0", 68, 0, 1000, ebuf);建立libpcap捕捉句柄,若出错,ebuf返回错误字串.ebuf可以为NULL(以后同)struct bpf_program fcode;pcap_compile(pd, &fcode, NULL, 1, 0);添写过滤规则串fcode,可以为空(即第三个参数,格式在后面讲到)pcap_setfilter(pd, &fcode);给 pd 设置上过滤规则pcap_loop(pd, 10, eth_printer, NULL);主循环,开始抓包,共抓10个(由第二个参数指定),抓到包后就进入函数 eth_printerpcap_close(pd);结束这个就是最简单的程序了,其中还有个不明,在pcap_loop参数 eth_printer的类型是pcap_handler,pcap_handler定义如下:typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,const u_char *);当然要包含#include "pcap.h"编译要加上 -lpcap至于怎么得到libpcap,还有安装,我就不费话了本文版权所有:doggy(chaujy@) 欢迎转载2.使用进阶篇刚才我们对程序的要求是能编译通过,能运行成功现在我们让这个程序实用点吧2.1 其它几个函数介绍这几个函数的特点是简单但无关紧要现在我们隆重退出char * pcap_lookupdev ( char * errbuf );这个函数就是查找本机上的网络接口设备,我机器上就返回"eth0",在pcap_open_live之前用,没什么意思吧,反正我是不爱用它int pcap_lookupnet(char *, bpf_u_int32 *, bpf_u_int32 *, char *);第一个参数就是pcap_lookupdev返回的接口名,二三参数都是32位无符号数, 分别是IP网段和掩码,最后那个参数还是ebufint pcap_datalink(pcap_t *);它返回你的网络类型,如 DLT_EN10MB 就是10M以太网让人ft氖钦庑┏A慷ㄒ宀辉趐cap.h中,在哪?自己找找吧;-)int pcap_snapshot(pcap_t *);返回最长抓多少字节,就是我们在pcap_open_live中第二个参数设置的int pcap_stats(pcap_t *, struct pcap_stat *);计数,共抓了多少过滤掉了多少,看看struct pcap_stat的定义就明白了struct pcap_stat {u_int ps_recv; /* number of packets received */u_int ps_drop; /* number of packets dropped */u_int ps_ifdrop; /* drops by interface XXX not yet supported */};int pcap_major_version(pcap_t *);int pcap_minor_version(pcap_t *);版本号,你有用么?我的eth_printer如下void eth_printer(u_char * user, const struct pcap_pkthdr * h, const u_char * p) {printf("I get one packet! ");}简单吧 :*)2.使用进阶篇刚才我们对程序的要求是能编译通过,能运行成功现在我们让这个程序实用点吧2.1 其它几个函数介绍这几个函数的特点是简单但无关紧要现在我们隆重退出char * pcap_lookupdev ( char * errbuf );这个函数就是查找本机上的网络接口设备,我机器上就返回"eth0",在pcap_open_live之前用,没什么意思吧,反正我是不爱用它int pcap_lookupnet(char *, bpf_u_int32 *, bpf_u_int32 *, char *);第一个参数就是pcap_lookupdev返回的接口名,二三参数都是32位无符号数,分别是IP网段和掩码,最后那个参数还是ebufint pcap_datalink(pcap_t *);它返回你的网络类型,如 DLT_EN10MB 就是10M以太网让人ft的是这些常量定义不在pcap.h中,在哪?自己找找吧;-)int pcap_snapshot(pcap_t *);返回最长抓多少字节,就是我们在pcap_open_live中第二个参数设置的int pcap_stats(pcap_t *, struct pcap_stat *);计数,共抓了多少过滤掉了多少,看看struct pcap_stat的定义就明白了struct pcap_stat {u_int ps_recv; /* number of packets received */u_int ps_drop; /* number of packets dropped */u_int ps_ifdrop; /* drops by interface XXX not yet supported */};int pcap_major_version(pcap_t *);int pcap_minor_version(pcap_t *);版本号2.2 现在的程序(C++)文件名p.cxx#ifdef __cplusplusextern "C" {#endif#include#ifdef __cplusplus}#endifvoid printer(u_char * user, const struct pcap_pkthdr * h, const u_char * p) {printf("I get one packet! ");/* 哈哈,我都想喝一杯庆祝一下了! */}#define DEFAULT_SNAPLEN 68/* 别问我为什么是68,我从tcpdump看来的 */int main(){char ebuf[PCAP_ERRBUF_SIZE];char *device = pcap_lookupdev(ebuf);bpf_u_int32 localnet, netmask;pcap_lookupnet(device, &localnet, &netmask, ebuf);printf("%u.%u.%u.%u", localnet&0xff, localnet>>8&0xff,localnet>>16&0xff, localnet>>24&0xff);printf(":%d.%d.%d.%d ", netmask&0xff, netmask>>8&0xff,netmask>>16&0xff, netmask>>24&0xff);struct pcap_t *pd = pcap_open_live(device, DEFAULT_SNAPLEN, 0, 1000, ebuf);if(pcap_datalink(pd) == DLT_EN10MB)printf("10Mb以太网 ");struct bpf_program fcode;pcap_compile(pd, &fcode, NULL, 1, 0);pcap_setfilter(pd, &fcode);pcap_loop(pd, 10, printer, NULL);struct pcap_stat stat;pcap_stats(pd, &stat);printf("recv %d, drop %d. ", stat.ps_recv, stat.ps_drop);pcap_close(pd);}#gcc p.cxx -lpcap#./a.out166.111.168.0:255.255.252.010Mb以太网I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!I get one packet!recv 10, drop 0.#重要提示: libpcap 程序需要root权限2.3 出错处理象其它库一样,libpcap 也有自己的错误处理机制基本上每个函数都有返回值,出错时返回值<0,另外有如下函数void pcap_perror(pcap_t *, char *);char *pcap_strerror(int);char *pcap_geterr(pcap_t *);前两个和 perror() strerror() 用法相同,最后一个也很简单在 pcap_t 中有一个成员存了错误字串struct pcap {...char errbuf[PCAP_ERRBUF_SIZE];};所以......于是我们在刚才的程序中加上错误处理先加一个函数#includeint err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);vfprintf(stderr, fmt, ap);va_end(ap);exit(-1);}之后处理每个函数的异常,在成功建立捕捉句柄pcap_t *pd前,使用ebuf参数char *device = pcap_lookupdev(ebuf);if(device == NULL)err_quit("%s", ebuf);有了句柄pd后if(pcap_compile(pd, &fcode, NULL, 1, 0) < 0)err_quit("%s", pcap_geterr(pd));注意不是每个函数都是出错返回<0pcap_datalink(pd)和pcap_snapshot(pd)等可不要这么处理2.4 参数初步研究前面使用各函数时,并没有具体说明每个函数的意义,现在来探讨一下pcap_t * pcap_open_live(char *device, int snaplen, int promisc,int to_ms, char *ebuf)device指定设备,snaplen指定最长抓多少字节,ebuf出错信息,前面都说过promisc指出是否设置为混杂模式(不懂?我也不懂,整个网都听还有什么安全性可言)to_ms设置超时时间,单位millisecondsint pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)cnt为要抓的包数,pcap_loop在正常时抓cnt个包后返回,异常时返回值<0 user是要传入callback()的数据,例如我们把上面的程序修改几行file://pcap_loop(pd, 10, printer, NULL);pcap_loop(pd, 10, printer, (u_char*)pd);再在printer()内加pcap_stat stat;pcap_stats((pcap_t*)user, &stat);printf("recv %d, drop %d. ", stat.ps_recv, stat.ps_drop);再编译运行后输出为166.111.168.0:255.255.252.010Mb以太网recv 1, drop 0.recv 2, drop 0.recv 3, drop 0.recv 4, drop 0.recv 5, drop 0.recv 6, drop 0.recv 7, drop 0.recv 8, drop 0.recv 9, drop 0.recv 10, drop 0.recv 10, drop 0.int pcap_compile(pcap_t *p, struct bpf_program *program,char *buf, int optimize, bpf_u_int32 mask)该函数用于解析过滤规则串buf,填写bpf_program结构. optimize为1表示对过滤规则进行优化处理netmask指定子网掩码buf的格式比较复杂int pcap_setfilter(pcap_t *handle, struct bpf_program *filter) 把pcap_compile()构造的filter设置到handle上。