基于libpcap的网络编程技术_第1页
基于libpcap的网络编程技术_第2页
基于libpcap的网络编程技术_第3页
基于libpcap的网络编程技术_第4页
基于libpcap的网络编程技术_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第五章 基于libpcap的网络编程技术51 常见的包捕获机制简介包捕获就是利用以太网的介质共享的特性,通过将网络适配器设置为混杂模式的方法,接收到所有网络上的以太网帧。包捕获的机制大致可以分为两类:一类是由操作系统内核提供的捕获机制。另一类是由应用软件或系统开发包捕获驱动程序提供的捕获机制。常见的包捕获机制如表5-1所示。其中最主要的是下列4种: BPF(Berkeley Packet Filter) DLPI(Data Link Provider Interface) NIT(Network Interface Tap) SOCK-PACKET类型套接口。BPF由基于BSD的Unix系统内

2、核所实现。DLPI是Solaris(和其他System V UNIX)系统的内嵌子系统。NIT是SUN OS4系统的一部分,但在Solaris /SUN OS5中被DLPI所取代。Linux核心则实现了SOCK-PACKET的包捕获机制。从性能上看,BPF比DLPI和NIT 好得多,SOCK-PACKET最弱。表5-1 常用的包捕获机制包捕获机制系统平台备 注BPFBSD系列Berkeley Packet FilterDLPISolaris,HP-UX SCOData Link Provider InterfaceNITSunOS 3Network Interface TapSNOOPIRIX

3、SNITSunOS 4Streams NITSOCK_PACKETLinuxLSF=Linux 2.1.75Linux Socket FilterDrainIRIX用于窃听系统丢弃的包由于现在很多局域网为NT网,其网络传输方式大多采用以太网标准,所以涉及的编程也是在Windows环境下实现的。Windows操作系统没有提供包捕获机制,只提供了数量很少并且功能有限的API调用。在Windows环境下由于其自身的封装性,很难对其底层进行编程。本章将对BSD系列的libpcap进行深入地介绍。5.2 Libpcap与BPF(1)libpcap概述libpcap(Packet Capture libr

4、ary),即数据包捕获函数库。该库提供的C函数接口可用于捕获经过网络接口(只要经过该接口,目标地址不一定为本机)的数据包。它是由洛仑兹伯克利试验室的研究人员Steven McCanne和Van Jacobson于1993年在Usenix93会议上正式提出的一种用于Unix内核数据包过滤体制 。该函数库支持Linux、Solaris和BSD系统平台。采用libpcap可以捕获本地网络数据链路层上的数据。libpcap库是基于BPF(Berkeley Packet Filter:BSD包过滤器)系统的。BPF是BSD系统在的TCP/IP软件在实现的时候所提供的一个接口,通过这个接口,外部程序可以得

5、到到达本机的数据链路层网络数据,同时也可以设置过滤器,嵌入到网络软件中,获得过滤后的数据包。(2)BPF结构及工作原理BPF或者BSD Packet Filter是一种由steven McCanne和Van Jacobson提出的内核包捕获的体系结构,它使得UNIX下的应用程序通过一个高度优化的方法读取流经网图5-1 BPF工作原理络适配器的数据包。winpcap的核心网络驱动程序也是采用这种结构的。它主要由两部分组成:Network tap和Packet Filter。Network tap是一个回调函数(callback function), 并不是直接由BPF执行,当一个新的数据包到达时

6、,由网络适配器的设备驱动程序激活,它从网络拷贝每个数据包,并且将它们分发到对应的应用程序。Packet filter来决定一个数据包是否需要进行接收和拷贝到相应的应用程序,同时还提供一种很复杂的功能,可以确定需要进行拷贝的数据的长度。BPF的工作原理如图5-1所示。由Network tap不断地从网络适配器获得数据包,通过packet filter的判断后,拷贝数据到内核store buffer,当store buffer填满后,将和hold buffer进行数据交换,再由hold buffer将数据拷贝到处于用户层的user buffer中。由于采用这种内核过滤、数据包双缓冲、数据包批拷贝的

7、方式,减少了用户态进程调用内核的次数,极大地提高了数据包的处理能力。在系统实现的过程中可以充分利用BPF过滤模型的这种特性,通过根据不同的网络侦听的需求,如针对特定的协议、特定的机器等,设置内核过滤器,减少捕获的数据的大小,同时增加内核缓冲区的大小,使系统能够获得一个很好的性能。BPF的结构如图5-2所示。libpcap在BPF的基础上提供了实用的接口函数供其它程序调用,既可以捕获网络上的数据,也可以打开tcpdump和tcpslice格式的数据,进行分析。同时也可以根据需要,设置过滤器,获得感兴趣的数据包。可以编辑简单的BPF过滤器对数据进行过滤,获得指定的IP包、TCP包等。如下所示:可以

8、用tcpdump的过滤表达式进行过滤:tcpdump tcp 21表示获得FTP端口(21)的所有的TCP数据,即通过21端口进出的数据,其它的数据全部丢弃。应用程序1应用程序2应用程序N缓存过滤器缓存过滤器缓存过滤器TCP/IP等网络协议栈链路层驱动程序链路层驱动程序链路层驱动程序BPF内核内核网络网络监视器用户空间图5-2 BPF的结构Libpcap 软件包可从 / 下载,然后依此执行下列三条命令即可安装,但如果希望libpcap能在linux上正常工作,则必须使内核支持packet协议,也即在编译内核时打开配置选项 CONFIG_PACKET(选

9、项缺省为打开)。./configure./make./make install5.3 libpcap库函数与数据结构(1)libpcap库函数libpcap所提供的主要函数如下:1) pcap_t *pcap_open_live();用于获取一个包捕获描述符2) char *pcap_lookupdev();返回一个适于pcap_open_live()和pcap_lookupnet()函数使用的指向网络设备的指针3) int pcap_lookupnet();用于判断与网络设备相关的网络号和掩码4) int pcap_dispatch()或int pcap_loop();收集和处理数据包5)

10、void pcap_dump();将一个包输出到由pcap_dump_open()打开的保存文件中6) int pcap_compile();用于将过滤规则字符串编译成一个内核过滤程序7) int pcap_setfilter();设定一个过滤程序8) int pcap_datalink();返回数据链路层类型,如10M以太网,SLIP,PPP,FDDI,ATM,IEEE802.3等9) void pcap_close();关闭关联文件并回收资源 10) int pcap_stats(pcap_t *, struct pcap_stat *); 11) int pcap_read(pcap_t

11、 *, int cnt, pcap_handler, u_char *); 除了上面列出的主要函数外,libpcap还提供一些其他的函数,将在后面介绍。dump文件格式:文件头:struct pcap_file_header bpf_u_int32 magic;/ 0xa1b2c3d4u_short version_major;u_short version_minor;bpf_int32 thiszone;bpf_u_int32 sigfigs;bpf_u_int32 snaplen;bpf_u_int32 linktype;每一个包的包头和数据struct pcap_pkthdr stru

12、ct timeval ts; bpf_u_int32 caplen; bpf_u_int32 len;其中数据部分的长度为caplen(2)libpcap数据结构相关的数据结构:typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,const u_char *);typedef struct pcap pcap_t;struct bpf_program u_int bf_len;struct bpf_insn *bf_insns; (3)利用libpcap函数库开发应用程序的基本步骤图5-3说明了libpcap的应用

13、步骤。NY命令行中指定了要监视的网络设备查找可用的网络设备pcap_lookup_dev()打开网络设备或文件作为包捕获描述符pcap_open_live()/pcap_open_offline()判断与网络设备相关的网络号和掩码pcap_lookupnet()编译过滤规则为内核过滤程序pcap_compile()设置过滤程序 pcap_setfilter()捕获并处理 pcap_loop() 或pcap_dispatch()关闭并返回 pcap_close()图5-3 libpcap的调用流程 下面列出libpcap应用过程中的几个关键函数。获取设备名 char *pcap_lookupde

14、v(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中存放相关的错误消息。打开设备pcap_t * pcap_op

15、en_live ( char * device, int snaplen, int promisc, int to_ms, char * errbuf );获得用于捕获网络数据包的数据包捕获句柄,后续很多libpcap函数将使用该句柄,类似于文件操作函数频繁使用文件句柄。device参数为指定打开的网络设备名,比如eth0。snaplen参数定义捕获数据的最大字节数。promisc指定是否将网络接口置于混杂模式。to_ms参数指定超时时间(毫秒),测试下来的结论,0可能代表永不超时。errbuf参数则仅在pcap_open_live()函数出错返回NULL时用于传递错误消息。/usr/incl

16、ude/pcap.htypedef struct pcap pcap_t;pcap-int.h里定义了struct pcap struct pcap int fd; int snapshot; int linktype; int tzoff; /* timezone offset*/ int offset; /* offset for proper alignment*/ struct pcap_sf sf; struct pcap_md md; int bufsize; /* Read buffer*/ u_char *buffer; u_char *bp; int cc; u_char *

17、pkt; /* Place holder for pcap_next()*/ struct bpf_program fcode;/* Placeholder for filter code if bpf not in kernel. */ charerrbufPCAP_ERRBUF_SIZE;编译、优化、调试过滤规则int pcap_compile ( pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask ); 该函数用于解析过滤规则串,填写bpf_program结构。str指向过滤

18、规则串,格式参看tcpdump的man手册,比如: tcpdump -x -vv -n -t ip proto tcp and dst 0 and tcp13 & 2 = 2这条过滤规则将捕捉所有携带SYN标志的到0的TCP报文。过滤规则串可以是空串( ),表示抓取所有过路的报文。optimize为1表示对过滤规则进行优化处理。netmask指定子网掩码,一般从pcap_lookupnet()调用中获取。返回值小于零表示调用失败。这个函数可能比较难于理解,涉及的概念源自BPF,Linux系统没有这种概念,但是libpcap采用pcap_compile

19、()和pcap_setfilter()结合的办法屏蔽了各种链路层支持的不同,无论是SOCK_PACKET,还是DLPI。int pcap_setfilter ( pcap_t * p, struct bpf_program * fp );该函数用于设置pcap_compile()解析完毕的过滤规则。fp参数是bpf_program结构指针,通常取自pcap_compile()函数调用。出错时返回-1;成功时返回0。抓取下一个数据包抓取数据包int pcap_dispatch ( pcap_t * p, int cnt, pcap_handler callback, u_char * user

20、);捕获并处理数据包,即该函数用于捕捉报文、分发报文到预先指定好的处理函数(回调函数)。其中,cnt参数指定函数返回前所处理数据包的最大值,pcap_dispatch()接收够cnt个报文便返回。Cnt为-1表示在一个缓冲区中处理所有的数据包。如果cnt为0,仅当发生错误、读取到EOF或者读超时到了(pcap_open_live中指定)才停止捕捉报文并返回。callback参数指定一个带有三个参数的回调函数用于处理pcap_dispatch()所捕获的报文。回调函数的三个参数为: typedef void ( *pcap_handler ) ( u_char *, const struct p

21、cap_pkthdr *, const u_char * );一个从pcap_dispatch()函数传递过来的u_char指针,一个pcap_pkthdr结构的指针,和一个数据包大小的u_char指针。如果成功则pcap_dispatch()返回捕捉到的报文个数,如果在读取静态文件(以前包捕捉过程中存储下来的)时碰到EOF则返回0。返回-1表示发生错误,此时可以用pcap_perror()、pcap_geterr()显示错误信息。-/usr/include/pcap.h/* Each packet in the dump file is prepended with this generic

22、 header.* This gets around the problem of different headers for different* packet interfaces.*/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) */;/usr/include/net/bpf.h/* Structure prepended

23、to each packet.*/struct bpf_hdr struct timeval bh_tstamp; /* time stamp */ bpf_u_int32 bh_caplen; /* length of captured portion */ bpf_u_int32 bh_datalen; /* original length of packet */ u_short bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */;/* Because the structure above

24、 is not a multiple of 4 bytes, some compilers* will insist on inserting padding; hence, sizeof(struct bpf_hdr) wont work.* Only the kernel needs to know about it; applications use bh_hdrlen.*/#ifdef KERNEL#define SIZEOF_BPF_HDR 18#endif- int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_cha

25、r *user) 功能基本与pcap_dispatch()函数相同,只不过此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。而如果为pcap_open_live()函数指定了一个非零值的超时设置,然后调用pcap_dispatch()函数,则当超时发生时pcap_dispatch()函数会返回。cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误。例如:pcap_loop(pd, 10, eth_printer, NULL);主循环,开始抓包,共抓10个(由第二个参数指定),抓到包后就进入函数eth_printer u_char *pcap_next(pc

26、ap_t *p, structpcap_pkthdr *h) 返回指向下一个数据包的u_char指针。关闭void pcap_close(pcap_t *p)关闭p参数相应的文件,并释放资源。出错处理象其它库一样,libpcap 也有自己的错误处理机制。基本上每个函数都有返回值,出错时返回值小于零。void pcap_perror(pcap_t *, char *);char *pcap_strerror(int);char *pcap_geterr(pcap_t *);在pcap_t 中有一个成员存了错误字串struct pcap .char errbufPCAP_ERRBUF_SIZE;其

27、他的辅助函数 pcap_read() 打开设备 pcap_next() 循环包捕获脱机方式监听部分:Libpcap 支持脱机监听。即先将网络上的数据截获下来,存到磁盘上,再以后方便时从磁盘上获取数据来做分析。主要函数为pcap_open_offline()pcap_offline_read ()FILE *pcap_file(pcap_t *p)返回被打开文件的文件名。 int pcap_fileno(pcap_t *p)返回被打开文件的文件描述字号码。int pcap_snapshot(pcap_t *);返回最长抓多少字节,就是在pcap_open_live中第二个参数设置int pcap

28、_stats(pcap_t *, 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 notyet supported */;int pcap_datalink(pcap_t *);返回网络类型,如 DLT_EN10MB 就是10M以太网int pcap_major_versi

29、on(pcap_t *);返回libpcap主版本号int pcap_minor_version(pcap_t *);返回libpcap次版本号5.4 Libpcap的应用实例上面详细说明了libpcap的调用过程和步骤,下面通过两个具体的例子来说明libpcap库的应用。例5-1 一个简单的Libpcap测试程序(1) test.CXX#ifdef _cplusplusextern C #endif#include #ifdef _cplusplus#endifvoid printer(u_char * user, const struct pcap_pkthdr * h, const u_

30、char * p)printf(I get one packet! );#define DEFAULT_SNAPLEN 68int main()char ebufPCAP_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, localnet8&0xff,localnet16&0xff, localnet24&0xff);pr

31、intf(:%d.%d.%d.%d , netmask&0xff, netmask8&0xff,netmask16&0xff, netmask24&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_

32、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);2)直接g+ test.cxx -lpcap (编译lipcap需要加 -lpcap)“cant find pcap.h”,原来连libpcap都没有装3)去tcpdump下载最新版本libpcap,安装#configure“error: cant find both flex and bison”,ft,这么麻烦

33、4)去下载flex和bison,安装(注意,这里要先装bison,然后再装flex,否则在装flex到时候会提示没有yacc)#configure#make#make install5)再试装libpcap,ok终于成功6)编译,run: 10Mb 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 pack

34、et! I get one packet! I get one packet! recv 10, drop 0. 例5-2基于libpcap的Sniffer程序以Sniffer程序的源代码为例。所列代码节选自以开放源代码形式发行的IPGrab程序,由Mike Borella编写。本例作了一定的修改和简化处理,代码遵循GNU/GPL协议。这里假设是在以太网(Ethernet)环境中处理问题。 1 #include 2 #include 3 #include 4 #include 5 #include open_pcap.h 6 #include ethernet.h 7 #include err

35、or.h 8 #include 9 #define SNAPLEN 1514 10 #define PROMISC 1 11 #define READ_TIMEOUT 50012 pcap_t *pd; /* pcap device descriptor */13 pcap_handler dev_prcsr; /* ptr to func that processes packet for a device */ 14 int main()15 16 u_char *userdata;17 userdata = NULL;18 cnt = -1;19 /* Open the pcap dev

36、ice for sniffing*/20 open_pcap();21 dev_prcsr = (pcap_func_t) dump_ethernet;22 /* Read all packets on the device. Continue until cnt packets read */23 f (pcap_loop(pd, cnt, dev_prcsr, userdata) 0)GWF_error_fatal(pcap_loop: %s, pcap_geterr(pd);24 /*Close the pcap device */25 pcap_close(pd);26 exit(0)

37、;27 28 void open_pcap(void)29 30 extern struct bpf_program fcode;31 char errorbufPCAP_ERRBUF_SIZE;32 char *fd;33 /*Look up the device and get a handle to it*/34 fd = pcap_lookupdev(errorbuf);35 if (fd = NULL) GWF_error_fatal(open_pcap: pcap_lookupdev() failed for %s: %s, fd, errorbuf);36 /* Get a fi

38、le descriptor to the device*/37 pd = pcap_open_live(fd, SNAPLEN, PROMISC, READ_TIMEOUT, errorbuf);38 if (pd = NULL) GWF_error_fatal(open_pcap: pcap_open_live() failed for %s: %s, fd, errorbuf);39 /*Set the pcap filter with our fcode FSM. That should do it.*/40 if (pcap_setfilter(pd, &fcode) len;50 c

39、aplen = h-caplen;51 /*Dump header announcement*/52 printf(Ethernet Header(%u.%06u)n,(u_int32_t) h-ts.tv_sec, (u_int32_t) h-ts.tv_usec);53 /*Check for truncated header */54 if (caplen ether_type);58 printf(Hardware source: %sn, etheraddr_string(ep-ether_src);59 printf(Hardware destination: %sn, ether

40、addr_string(ep-ether_dst);60 printf(Protocol type: %xH (%s)n, ether_type, etherProto_string(ep-ether_type);61 printf(Length: %dn, length+4); /* add FCS */62 程序语句说明:12行定义了指向描述数据包截获设备描述符结构(pcap_t)即结构pcap,结构pcap或者(pcap_t)是实现数据包截获机制的一个关键数据结构,各个字段定义如下:lfd:文件描述符,这里指数据包截获描述符,即底层过滤器特殊文件的描述符Snapshot:快照,这里是所指

41、定查看数据包的长度。Linktype:底层数据链路层的结构类型。Tzoff:时区与格林威治时区的偏移量。Offset:对应于不同对齐方式的偏移量。sf:表示数据包转储文件的文件结构。md:表示数据包截获机制状态和相关设备状态的结构。bufsize:数据包缓冲区大小。buffer:数据包缓冲区的首地址。bp:缓冲区指针。cc:用于计数目的的整数。pkt:用于特定函数目的的地址指针。fcodebpf_program:数据结构类型的变量,为一指向过滤器程序代码的指针。errbuf:用于存放错误信息字符串的数组。 14:主函数main()该程序的主过程代码分析如下所示:20:调用open_pcap() (28行)来打开

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论