一、  pcap简介

封装了OS提供的底层抓包技术,对外提供一些统一的抓包(及发送)接口。实现这些功能的其他技术包括:BPF(Berkeley Packet Filter),DLPI(Data Link Provider Interface),NIT ,Linux专用的SOCKET_PACKET或PF_PACKET等。

二、  pcap Linux安装

参考《INSTALL.txt》。

进入pcap源码目录,执行./configure,这将检测系统环境,并生成Makefile文件;执行make;执行make install,这将安装开发头文件、库、手册等;注意这不会安装动态库。

三、  pcap 开发介绍

2.1 API介绍

本部分介绍API,并对主要的API进行详细的说明。

pcap_open_live打开由dev指定的设备,

pcap_open_dead,只是建立一个pcap_t结构体,用处不大;

pcap_open_offline,打开一个tcpdump/libpcap 格式的文件,从中读取数据;

pcap_dump_open

pcap_setnonblock

pcap_getnonblock

pcap_findalldevs,获取设备列表

pcap_freealldevs,关闭查询的设备

pcap_lookupdev,获得设备信息,如eth0,只是获得找到的第一个设备

pcap_lookupnet,获得IP/Mask信息

pcap_dispatch,抓包引擎,需循环调用

pcap_loop抓包引擎,与pcap_dispatch的不同处在于它少一个超时返回参数;

pcap_dump

pcap_compile,编译过滤语法

pcap_setfilter,绑定过滤器

pcap_freecode

pcap_next,轮询方式抓包

pcap_datalink

pcap_snapshot

pcap_is_swapped

pcap_major_version

pcap_minor_version

pcap_stats,获取当前捕获的统计信息

pcap_file

pcap_fileno

pcap_perror

pcap_geterr

pcap_strerror

pcap_close,关闭设备

pcap_dump_close

pcap_sendpacket,发送一个原始数据包

说明:

1,  函数的返回值,0表示成功,-1表示错误;

2,  参数errbuf用于接收错误信息,不小于PCAP_ERRBUF_SIZE;

2.2使用pcap的一般步骤

Ø         pcap_lookupdev等获得设备信息,网卡设备名、设备所在网络地址;

Ø         pcap_open_live打开设备,设置网卡成混杂模式;

Ø         循环调用pcap_loop中实现包捕获引擎,编写包分析程序;

2.3回调函数定义

typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);

2.4设置过滤条件

首先使用pcap_compile编译一个filter字符串,然后使用pcap_setfilter将编译结果绑定到一个设备;

char* filter = "udp port 5060";

bpf_program fp;

if(-1 == pcap_compile(cap_des, &fp, filter, 0, netp))

{

cout<<"compile err: "<<pcap_geterr(cap_des)<<endl;

return 6;

}

if(-1 == pcap_setfilter(cap_des, &fp))

{

cout<<"set filter err: "<<pcap_geterr(cap_des)<<endl;

return 7;

}


2.5 错误返回

存在两种获取错误原因的方式,一是通过函数参数的errbuf;如果函数没有该参数,则使用pcap_geterr获得,函数执行错误时会将错误信息写入结构体中的预分配的errbuf(其中一些是基于errno),该函数返回该errbuf的地址;

四、  pcap Linux实现

4.1函数

本部分介绍某些关键函数的实现:

1,  pcap_findalldevs,首先使用socket()获得一个socket的句柄,然后使用ioctl获得所有网卡信息;该函数会尝试打开找到的设备(add_or_find_if),它只返回能够用于live capture的设备;

2,  pcap_lookupdev,调用pcap_findalldevs,将找到的第一个device返回。

3,  pcap_open_live

a)         参数device赋空(NULL)或“any”时将抓取所有网卡的数据包(这种情况下将不支持混杂模式?);

b)        尝试使用live_open_new打开设备(PF_PACKET),失败将使用live_open_old(SOCK_PACKET);

c)        live_open_new,对捕获单块网卡,调用socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))(数据带链路层头),如果需捕获所有网卡,调用socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL))(不带链路层头);调用setsockopt设置混杂模式;

d)        设置pcap_t对象,设置操作系统相关的处理函数的指针,及初始化buffer(大小由参数snaplen确定),

4,  pcap_close,调用pcap_close_linux,

5,  pcap_lookupnet,先使用socket()获得一个socket句柄,然后调用ioctl获得设备相关的参数;

6,  pcap_loop,判断open方式,循环调用pcap_offline_read读取文件或read_op(pcap_read_linux)读取socket,读取cnt个packet,并对每个packet调用callback函数;将参数user传给callbask函数;函数返回已处理的packet数;

a)         pcap_read_linux调用pcap_read_packet,后者调用recvfrom将数据接收到bufsize;如果kernel filter没有起作用,调用bpf_filter进行处理;最后调用callback函数;

7,  pcap_dispatch仅调用一次read_op,相对pcap_loop,不能用于读取文件,及不循环;这样它的处理少一些;在Linux下,每次调用只抓一个packet;

8,  pcap_next,调用pcap_dispatch实现,每次只抓一个packet,将packet作为函数返回值;

9,  pcap_next_ex,提供了读取文件的能力,其他处理与pcap_next相仿;

10,              pcap_compile,调用了lex_init等函数——没看到这些函数的实现;

11,              pcap_setfilter,调用了pcap_setfilter_linux(#ifdef SO_ATTACH_FILTER);filter分内核filter及pcap自己实现的filter两种,pcap会优先使用内核filter;如果filter语法过于复杂(#ifdef USHRT_MAX),会使用或经检查filter不能在内核执行时,

a)         调用fix_program,

b)        调用set_kernel_filter设置内核filter,使用setsockopt(SO_ATTACH_FILTER);

12,              pcap_inject,调用p->inject_op,pcap_inject_linux,send发送数据;

13,              pcap_sendpacket,与pcap_inject实现一样,只是更改了接口;

14,              pcap_stats,调用stats_op(pcap_stats_linux)函数,内核版本需2.4 以上,调用getsockopt获得数据;可统计数据包括:经过filter到达pcap的packet数量、通过了filter但是因为buffer不足等原因而没有到达pcap的packet数量;

15,              pcap_setnonblock,将socket设置成阻塞或非阻塞模式;

16,              pcap_setdirection,设置要抓取的packet的方向,发出还是收到?

4.1数据结构

本部分为pcap的关键数据结构:

struct pcap_if {

struct pcap_if *next;

char *name;

char *description;

struct pcap_addr *addresses;

bpf_u_int32 flags;       PCAP_IF_LOOPBACK

};

struct pcap_pkthdr {

struct timeval ts;         //获得packet的时间

bpf_u_int32 caplen;              //抓取到的packet长度

bpf_u_int32 len;       //packet的真实长度

};

len可能大于caplen

pcap_t,摘出了Linux相关部分:

struct pcap {

int fd;

int selectable_fd;

int send_fd;

int snapshot;

int linktype;

int tzoff;

int offset;

int break_loop;

#ifdef PCAP_FDDIPAD

int fddipad;

#endif

struct pcap_sf sf;

struct pcap_md md;

int bufsize;

u_char *buffer;

u_char *bp;

int cc;

u_char *pkt;

pcap_direction_t direction;

int     (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);

int     (*inject_op)(pcap_t *, const void *, size_t);

int     (*setfilter_op)(pcap_t *, struct bpf_program *);

int     (*setdirection_op)(pcap_t *, pcap_direction_t);

int     (*set_datalink_op)(pcap_t *, int);

int     (*getnonblock_op)(pcap_t *, char *);

int     (*setnonblock_op)(pcap_t *, int, char *);

int     (*stats_op)(pcap_t *, struct pcap_stat *);

void  (*close_op)(pcap_t *);

struct bpf_program fcode;

char errbuf[PCAP_ERRBUF_SIZE + 1];

int dlt_count;

u_int *dlt_list;

struct pcap_pkthdr pcap_header;

};

五、  一些问题

1,c代码与c++代码风格比较

1,  C++使用继承结构区分共性与个性,将代表个性的数据结构放到子类中,这样区别能集中到子类中;C中使用大量的条件编译,如#ifdef HAVE_PF_PACKET_SOCKETS,代码混杂;

2,  C中实现多态的方式,结构体中定义函数指针,不同的实现赋不同的值;

六、  一些测试数据

1,基于Winpcap,使用filter;

程序执行环境:Windows XP sp2,无线网卡;

测试方式:向10.130.24.158拷贝一个超过1G的文件,检查程序的性能情况;

测试数据:

描述

CPU(%)

程序消耗(%)

其他

1

不设置filter,抓取所有数据

65~85

20

2

设置filter(udp)使得不抓取数据

15~25

0

3

设置filter(tcp)抓取所有数据

65~80

20

2,Winpcap的发送速度

说明:本次测试只测试了发送函数的执行耗时,未检查接受端的情况,即不能保证数据真的通过网卡发出。

测试方式:每次发送300B大小的数据包,每循环执行100000或500000次发送,记录每循环的耗时,取多次循环的折中值;另外24.158机器上安装有两块千兆网卡,一块接在千兆交换机上,另一块接在百兆交换机上。

1,  pcap_sendpacket与pcap_sendqueue_transmit的发送速度比较:

每循环执行100000次pcap_sendpacket发送,耗时约6秒,流量约40Mb/s,且100Mb网络稍快于1000Mb网络;

使用pcap_sendqueue_transmit,积累到100个数据包时发送一次;千兆网络每循环耗时0.7秒,流量342Mb/s,百兆网络每循环耗时2.6秒,流量92Mb/s。

结论:pcap_sendqueue_transmit比pcap_sendpacket发送速度快得多。

2,  用户buffer、系统buffer、每次发送数量对发送速度的影响

本部分测试用户buffer、系统buffer、每次发送数量对pcap_sendqueue_transmit的发送速度的影响;本测试每循环发送500000个包,每个包300B;

关于pcap_sendqueue_alloc的说明:该函数用于分配一块用户空间存储,应设置得足够大以容纳数据;测试发现它会影响到程序占用的内存,但对发送速度没有影响。

用户buffer 1M,系统buffer1M

每次发包数

50

100

1200

1

1000Mb网络(秒)

3

4

3

32

100Mb网络(秒)

13

13

13

30

设置用户buffer为8M,系统buffer 1M;

每次发包数

100

1200

1000Mb网络(秒)

2.7

3

100Mb网络(秒)

13

13.3

设置用户buffer为64M,系统buffer 1M;

每次发包数

100

1200

1000Mb网络(秒)

2.7

3

100Mb网络(秒)

13

13.4

设置用户buffer为1M,系统buffer 1M;

每次发包数

100

1200

1000Mb网络(秒)

2.7

3

100Mb网络(秒)

13

13.4

设置用户buffer为1M,系统buffer 64M;

每次发包数

100

1200

1000Mb网络(秒)

3.7

3.1

100Mb网络(秒)

13

13.3

设置用户buffer为8M,系统buffer 8M;

每次发包数

100

1200

12000

1000Mb网络(秒)

3.7

3

2.9

100Mb网络(秒)

13

13.4

13.6

设置用户buffer为8M,系统buffer 64M;

每次发包数

100

1200

1000Mb网络(秒)

2.7

3

100Mb网络(秒)

13

13.4

PCAP研究的更多相关文章

  1. 基于802.11Fuzz技术的研究

    转自安全客 关于无线的Fuzz最开始接触了解时,国内基本毛线都搜不到.经过几个月的资料搜集和学习,将大约全网的fuzz资料整理翻译分析并读懂写下,就为填补国内空白,也希望无线爱好者能多多交流. 在各个 ...

  2. 针对于网络安全领域中基于PCAP流量的数据集

    网络安全领域中基于PCAP流量的数据集 MAWI Working Group Traffic Archive URL:http://mawi.wide.ad.jp/mawi/ CIC dataset ...

  3. tcpreplay 发包速率控制算法研究

    一.  序 1.1  tcpreplay历史 Tcpreplay 的作者是Aaron Turner,该项目开始于2000年,早期的功能是对tcpdump等抓包工具生成的网络包(即pcap文件)的回放, ...

  4. EKFiddle:基于Fiddler研究恶意流量的框架

    转载自FreeBuf.COM EKFiddle是一个基于Fiddler web debugger的,用于研究漏洞利用套件.恶意软件和恶意流量的框架. 安装 下载并安装最新版本的Fiddler http ...

  5. 将ERF格式转换成PCAP格式

    在研究网络流量分析的时候,wireshark默认采用pcap格式.对于用Endace DAG捕捉卡捕获的数据包,一般来说,都是erf格式的.一般来说,此种格式包含了更多了链路层信息.而我们采用wire ...

  6. 闲来无聊,研究一下Web服务器 的源程序

    web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...

  7. SQLSERVER聚集索引与非聚集索引的再次研究(上)

    SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻 ...

  8. 深入研究Visual studio 2017 RC新特性

    在[Xamarin+Prism开发详解三:Visual studio 2017 RC初体验]中分享了Visual studio 2017RC的大致情况,同时也发现大家对新的Visual Studio很 ...

  9. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

随机推荐

  1. vs2015安装没有wim32

    刚开始在官网上下载VS2015没在意太多,选择了默认安装,结果是没有win64的,所以就不能写c代码.默认安装很多库都没有,所以要什么都得下载.转载一篇文章

  2. BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap

    3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec  Memory Limit: 256 MBSubmit: 102  Solved: 54[Submit][Status ...

  3. [BZOJ 3942] [Usaco2015 Feb] Censoring 【KMP】

    题目链接:BZOJ - 3942 题目分析 我们发现,删掉一段 T 之后,被删除的部分前面的一段可能和后面的一段连接起来出现新的 T . 所以我们删掉一段 T 之后应该接着被删除的位置之前的继续向后匹 ...

  4. [BZOJ 3620] 似乎在梦中见过的样子 【KMP】

    题目链接:BZOJ - 3620 题目分析 这道题使用 KMP 做 O(n^2) 的暴力就能过. 首先,我们依次枚举字串左端点 l ,然后从这个左端点开始向后做一次 KMP. 然后我们枚举右端点 r  ...

  5. websocket nodejs实例

    http://blog.sina.com.cn/s/blog_49cc837a0101aljs.html http://blog.sina.com.cn/s/blog_49cc837a0101a2q3 ...

  6. codeforces C. No to Palindromes!

    http://codeforces.com/contest/465/problem/C 题意:给你一个字符串,然后按照字典序找出下一个字符串,这个字符串中不能含有长度大于等于2的子串为回文串,如果含有 ...

  7. 【uva10917】Walk Through the Forest (最短路)

    题目: gbn最近打算穿过一个森林,但是他比较傲娇,于是他决定只走一些特殊的道路,他打算只沿着满足如下条件的(A,B)道路走:存在一条从B出发回家的路,比所有从A出发回家的路径都短.你的任务是计算一共 ...

  8. SQLite 中的各种限制

    英文原文:Limits In SQLite       本文定义了 SQLite 的限制,如何针对这些限制定制特定的应用程序.默认的限制设置通常是适当的,几乎适合于每一个应用.有一些应用程序可能需要在 ...

  9. mysql优化21条经验(转)

    今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序 员需要去关注的事情.当我们去设计数据库表结构,对操作数 ...

  10. This configuration file was broken by system-config-keyboard

    posts • Page of problem with startx Postby evarie » // :: Normally i can get started with the x wind ...