pcap编程深入解析

       首先,该文章不限定OS不单针对Winpcap或者libpcap,对于Winpcap的特殊扩展使用了PS标示。

       我以前使用过Winpcap,但并没有对pcap开发进行过深入解析。希望这篇文章可以深入浅出的讲清楚这个问题。Pcap是什么?它是个监视器,或者发生器,它可以监视,也可以发生,但它不能拦截。它可以在网络上增加一些消息,但不能阻止已经存在的消息。

      

获取设备列表:

int pcap_findalldevs (pcap_if_t **alldevsp, char *errbuf)

构造一个可打开的网络设备的列表

-1表示错误,buf中会有错误消息;0表示成功。能被查找到的设备是能被打开的设备。

PS:下面这个函数是Windows平台下的扩展,不是非常建议使用这个函数。

int pcap_findalldevs_ex (char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)

创建一个网络设备列表,它们可以由 pcap_open()打开。

对比上面的函数,这个扩展表现在参数上,从上面可以看出来,前面两个参数是增加的,那么这个增加的参数就使打开查找远端网卡成为可能。这两个参数的规则,请查看Winpcap相关文档。

 

打开设备

pcap_t *pcap_open_live (const char *device, int snaplen, int promisc, int to_ms, char *ebuf)

在网络中打开一个活动的捕获

第一个参数是从查找查到的设备名,snaplen为最大抓包长度,65535可以满足大多数的应用,promisc代表打开设备的模式,当选择混杂模式的情况下,可以抓下所有的包。To_ms,抓包的超时时间。

PSWinpcap扩展接口

pcap_t * pcap_open (const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)

打开一个用来捕获或发送流量(WinPcap)的通用源。

 

打开一个文件

pcap_t * pcap_open_offline (const char *fname, char *errbuf)

打开一个 tcpdump/libpcap 格式的存储文件,来读取数据包。

 

过滤器的使用

int  pcap_compile (pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask)

编译数据包过滤器,将程序中高级的过滤表达式,转换成能被内核级的过滤引擎所处理的东西。 (参见 过滤表达式语法)第一个参数代表设备句柄,第二个参数为输出参数,为编译完成的过滤条件,第三个参数代表过滤条件的表达式,第四个参数表示是否优化,1是个不错的选择,第五个参数为网卡的掩码。

int pcap_setfilter (pcap_t *p, struct bpf_program *fp)

在捕获过程中绑定一个过滤器

 

回调抓包

int pcap_dispatch (pcap_t *p, int cnt, pcap_handler callback, u_char *user)

收集一组数据包

int pcap_loop (pcap_t *p, int cnt, pcap_handler callback, u_char *user)

收集一组数据包

typedef void(*)  pcap_handler (u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)

接受数据包的回调函数的原型

当适配器被打开,捕获工作就可以用 pcap_dispatch() pcap_loop()进行。 这两个函数非常的相似,区别就是 pcap_ dispatch() 当超时时间到了(timeout expires)就返回 (尽管不能保证) ,而 pcap_loop() 不会因此而返回,只有当 cnt 数据包被捕获,所以,pcap_loop()会在一小段时间内,阻塞网络的利用。pcap_loop()对于我们这个简单的范例来说,可以满足需求,不过, pcap_dispatch() 函数一般用于比较复杂的程序中。

这两个函数都有一个 回调 参数, packet_handler指向一个可以接收数据包的函数。 这个函数会在收到每个新的数据包并收到一个通用状态时被libpcap所调用 ( 与函数 pcap_loop() pcap_dispatch() 中的 user 参数相似),数据包的首部一般有一些诸如时间戳,数据包长度的信息,还有包含了协议首部的实际数据。 注意:冗余校验码CRC不再支持,因为帧到达适配器,并经过校验确认以后,适配器就会将CRC删除,与此同时,大部分适配器会直接丢弃CRC错误的数据包,所以,Pcap没法捕获到它们。

 

非回调抓包

u_char * pcap_next (pcap_t *p, struct pcap_pkthdr *h)

返回下一个可用的数据包

int pcap_next_ex (pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data)

从一个设备接口,或从一个脱机文件中,读取一个数据包

第一个参数代表设备句柄,第二个参数代表包头,第三个参数代表数据。从我对参数的理解来看,无论是回调或者非回调,内存都是pcap管理的,且这些内存是复用的,没有任何证据表明pcap_next_ex这类的接口是线程安全的,至少参数不满足线程安全的要求。所以我理解的抓包都需要在单线程下进行。如果需要延迟分析的话,需要把所有的数据另行缓存,pcap是不会做这些工作的。

对比之下,为什么我们要用 pcap_next_ex() 代替以前的 pcap_next() 因为 pcap_next() 有一些不好的地方。首先,它效率低下,尽管它隐藏了回调的方式,但它依然依赖于函数 pcap_dispatch()。第二,它不能检测到文件末尾这个状态(EOF),因此,如果数据包是从文件读取来的,那么它就不那么有用了。

 

发送数据包

发送单个数据包

int pcap_sendpacket (pcap_t *p, u_char *buf, int size)

发送一个原始数据包

第一个参数为设备句柄,第二个数据为缓存,第三个数据为buffer的大小。

 

统计

int pcap_stats (pcap_t *p, struct pcap_stat *ps)

返回当前捕获的统计信息

PS:对Winpcap,对于统计来说,pcap使用pcap_setmode直接将模式设置到驱动层,通过驱动层实现对统计的优化。

 

 

关闭设备

pcap_close

 

关闭查询的设备

pcap_freealldevs

 

pcap的底层实现

pcap在我们看来非常底层,其实并不是这样。Pcap对网卡的调用,以来Cace technologiespacket.dll。而packet.dll的实现使用的是windows底层API——DeviceIOControl

相关资源:

http://www.winpcap.org/

http://www.coffeecat.net.cn/winpcap/html/index.html

http://www.cacetech.com/

http://msdn.microsoft.com/

http://blog.csdn.net/bhw98/archive/2003/05/27/19660.aspx DeviceIOControl使用详解

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值