Linux下Libpcap源码分析和包过滤机制

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

libpcap是unix/linux平台下的网络数据包捕获函数包,大多数网络监控软件都以它为基础。Libpcap可以在绝大多数类unix平台下工作,本文分析了libpcap在linux下的源代码实现,其中重点是linux的底层包捕获机制和过滤器设置方式,同时也简要的讨论了libpcap使用的包过滤机制BPF。网络监控绝大多数的现代操作系统都提供了对底层网络数据包捕获的机制,在捕获机制之上可以建立网络监控(NetworkMonitoring)应用软件。网络监控也常简称为sniffer,其最初的目的在于对网络通信情况进行监控,以对网络的一些异常情况进行调试处理。但随着互连网的快速普及和网络攻击行为的频繁出现,保护网络的运行安全也成为监控软件的另一个重要目的。例如,网络监控在路由器,防火墙、入侵检查等方面使用也很广泛。除此而外,它也是一种比较有效的黑客手段,例如,美国政府安全部门的肉食动物计划。包捕获机制从广义的角度上看,一个包捕获机制包含三个主要部分:最底层是针对特定操作系统的包捕获机制,最高层是针对用户程序的接口,第三部分是包过滤机制。不同的操作系统实现的底层包捕获机制可能是不一样的,但从形式上看大同小异。数据包常规的传输路径依次为网卡、设备驱动层、数据链路层、IP层、传输层、最后到达应用程序。而包捕获机制是在数据链路层增加一个旁路处理,对发送和接收到的数据包做过滤/缓冲等相关处理,最后直接传递到应用程序。值得注意的是,包捕获机制并不影响操作系统对数据包的网络栈处理。对用户程序而言,包捕获机制提供了一个统一的接口,使用户程序只需要简单的调用若干函数就能获得所期望的数据包。这样一来,针对特定操作系统的捕获机制对用户透明,使用户程序有比较好的可移植性。包过滤机制是对所捕获到的数据包根据用户的要求进行筛选,最终只把满足过滤条件的数据包传递给用户程序。Libpcap应用程序框架Libpcap提供了系统独立的用户级别网络数据包捕获接口,并充分考虑到应用程序的可移植性。Libpcap可以在绝大多数类unix平台下工作,参考资料A中是对基于libpcap的网络应用程序的一个详细列表。在windows平台下,一个与libpcap很类似的函数包winpcap提供捕获功能,其官方网站是。Libpcap软件包可从下载,然后依此执行下列三条命令即可安装,但如果希望libpcap能在linux上正常工作,则必须使内核支持packet协议,也即在编译内核时打开配置选项CONFIG_PACKET(选项缺省为打开)。./configure./make./makeinstalllibpcap源代码由20多个C文件构成,但在Linux系统下并不是所有文件都用到。可以通过查看命令make的输出了解实际所用的文件。本文所针对的libpcap版本号为0.8.3,网络类型为常规以太网。Libpcap应用程序从形式上看很简单,下面是一个简单的程序框架:char*device;/*用来捕获数据包的网络接口的名称*/pcap_t*p;/*捕获数据包句柄,最重要的数据结构*/structbpf_programfcode;/*BPF过滤代码结构*//*第一步:查找可以捕获数据包的设备*/device=pcap_lookupdev(errbuf);/*第二步:创建捕获句柄,准备进行捕获*/p=pcap_open_live(device,8000,1,500,errbuf);/*第三步:如果用户设置了过滤条件,则编译和安装过滤代码*/pcap_compile(p,&fcode,filter_string,0,netmask);pcap_setfilter(p,&fcode);/*第四步:进入(死)循环,反复捕获数据包*/for(;;){while((ptr=(char*)(pcap_next(p,&hdr)))==NULL);/*第五步:对捕获的数据进行类型转换,转化成以太数据包类型*/eth=(structlibnet_ethernet_hdr*)ptr;/*第六步:对以太头部进行分析,判断所包含的数据包类型,做进一步的处理*/if(eth-ether_type==ntohs(ETHERTYPE_IP))…………if(eth-ether_type==ntohs(ETHERTYPE_ARP))…………}/*最后一步:关闭捕获句柄,一个简单技巧是在程序初始化时增加信号处理函数,以便在程序退出前执行本条代码*/pcap_close(p);检查网络设备libpcap程序的第一步通常是在系统中找到合适的网络接口设备。网络接口在Linux网络体系中是一个很重要的概念,它是对具体网络硬件设备的一个抽象,在它的下面是具体的网卡驱动程序,而其上则是网络协议层。Linux中最常见的接口设备名eth0和lo。Lo称为回路设备,是一种逻辑意义上的设备,其主要目的是为了调试网络程序之间的通讯功能。eth0对应了实际的物理网卡,在真实网络环境下,数据包的发送和接收都要通过eht0。如果计算机有多个网卡,则还可以有更多的网络接口,如eth1,eth2等等。调用命令ifconfig可以列出当前所有活跃的接口及相关信息,注意对eth0的描述中既有物理网卡的MAC地址,也有网络协议的IP地址。查看文件/proc/net/dev也可获得接口信息。Libpcap中检查网络设备中主要使用到的函数关系如下图:libpcap调用pcap_lookupdev()函数获得可用网络接口的设备名。首先利用函数getifaddrs()获得所有网络接口的地址,以及对应的网络掩码、广播地址、目标地址等相关信息,再利用add_addr_to_iflist()、add_or_find_if()、get_instance()把网络接口的信息增加到结构链表pcap_if中,最后从链表中提取第一个接口作为捕获设备。其中get_instanced()的功能是从设备名开始,找第一个是数字的字符,做为接口的实例号。网络接口的设备号越小,则排在链表的越前面,因此,通常函数最后返回的设备名为eth0。虽然libpcap可以工作在回路接口上,但显然libpcap开发者认为捕获本机进程之间的数据包没有多大意义。在检查网络设备操作中,主要用到的数据结构和代码如下:/*libpcap自定义的接口信息链表[pcap.h]*/structpcap_if{structpcap_if*next;char*name;/*接口设备名*/char*description;/*接口描述*//*接口的IP地址,地址掩码,广播地址,目的地址*/structpcap_addraddresses;bpf_u_int32flags;/*接口的参数*/};char*pcap_lookupdev(registerchar*errbuf){pcap_if_t*alldevs;……pcap_findalldevs(&alldevs,errbuf);……strlcpy(device,alldevs-name,sizeof(device));}打开网络设备当设备找到后,下一步工作就是打开设备以准备捕获数据包。Libpcap的包捕获是建立在具体的操作系统所提供的捕获机制上,而Linux系统随着版本的不同,所支持的捕获机制也有所不同。2.0及以前的内核版本使用一个特殊的socket类型SOCK_PACKET,调用形式是socket(PF_INET,SOCK_PACKET,intprotocol),但Linux内核开发者明确指出这种方式已过时。Linux在2.2及以后的版本中提供了一种新的协议簇PF_PACKET来实现捕获机制。PF_PACKET的调用形式为socket(PF_PACKET,intsocket_type,intprotocol),其中socket类型可以是SOCK_RAW和SOCK_DGRAM。SOCK_RAW类型使得数据包从数据链路层取得后,不做任何修改直接传递给用户程序,而SOCK_DRRAM则要对数据包进行加工(cooked),把数据包的数据链路层头部去掉,而使用一个通用结构sockaddr_ll来保存链路信息。使用2.0版本内核捕获数据包存在多个问题:首先,SOCK_PACKET方式使用结构sockaddr_pkt来保存数据链路层信息,但该结构缺乏包类型信息;其次,如果参数MSG_TRUNC传递给读包函数recvmsg()、recv()、recvfrom()等,则函数返回的数据包长度是实际读到的包数据长度,而不是数据包真正的长度。Libpcap的开发者在源代码中明确建议不使用2.0版本进行捕获。相对2.0版本SOCK_PACKET方式,2.2版本的PF_PACKET方式则不存在上述两个问题。在实际应用中,用户程序显然希望直接得到原始的数据包,因此使用SOCK_RAW类型最好。但在下面两种情况下,libpcap不得不使用SOCK_DGRAM类型,从而也必须为数据包合成一个伪链路层头部(sockaddr_ll)。某些类型的设备数据链路层头部不可用:例如Linux内核的PPP协议实现代码对PPP数据包头部的支持不可靠。在捕获设备为any时:所有设备意味着libpcap对所有接口进行捕获,为了使包过滤机制能在所有类型的数据包上正常工作,要求所有的数据包有相同的数据链路头部。打开网络设备的主函数是pcap_open_live()[pcap-linux.c],其任务就是通过给定的接口设备名,获得一个捕获句柄:结构pcap_t。pcap_t是大多数libpcap函数都要用到的参数,其中最重要的属性则是上面讨论到的三种socket方式中的某一种。首先我们看看pcap_t的具体构成。structpcap[pcap-int.h]{intfd;/*文件描述字,实际就是socket*//*在socket上,可以使用select()和poll()等I/O复用类型函数*/intselectable_fd;intsnapshot;/*用户期望的捕获数据包最大长度*/intlinktype;/*设备类型*/inttzoff;/*时区位置,实际上没有被使用*/intoffset;/*边界对齐偏移量*/intbreak_loop;/*强制从读数据包循环中跳出的标志*/structpcap_sfsf;/*数据包保存到文件的相关配置数据结构*/structpcap_mdmd;/*具体描述如下*/intbufsize;/*读缓冲区的长度*/u_charbuffer;/*读缓冲区指针*/u_char*bp;intcc;u_char*pkt;/*相关抽象操作的函数指针,最终指向特定操作系统的处理函数*/int(*read_op)(pcap_t*,intcnt,pcap_handler,u_char*);int(*setfilter_op)(pcap_t*,structbpf_program*);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*,structpcap_stat*);void(*close_op)(pcap_t*);/*如果BPF过滤代码不能在内核中执行,则将其保存并在用户空间执行*/structbpf_programfcode;/*函数调用出错信息缓冲区*/charerrbuf[PCAP_ERRBUF_SIZE+1];/*当前设备支持的、可更改的数据链路类型的个数*/intdlt_count;/*可更改的数据链路类型号链表,在linux下没有使用*/int*dlt_list;/*数据包自定义头部,对数据包捕获时间、捕获长度、真实长度进行描述[pcap.h]*/structpcap_pkth

1 / 20
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功