您好,欢迎访问三七文档
当前位置:首页 > 建筑/环境 > 工程监理 > libpcap编程-编写自己的网络嗅探程序
ProgrammingwithLibpcap--SniffingtheNetworkAuthor:LuisMartinGarcia=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-|**你将会学到什么?**||1.数据包捕获的原则;||2.如何利用libpcap捕获数据包;||3.关于我们何时需要编写数||据包捕获程序等方面.||||**你应该所掌握的...**||1.C语言程序设计;||2.网络的基本工作原理和OSI的标||准模型;||3.了解常见的协议,比如以太协仪,||TCP/IP协议,或者ARP协议。|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-******概要*********************************************************************自从1969年第一条电子信息带着研究人员的期望成功地通过阿葩网(ARPANET)进行了有史以来最便捷的信息传递方式,计算机网络已经发生了巨大的变化。以前网络(此处及以下均指计算机网络)规模小,结构简单,利用一些简单的诊断工具通常便可以解决网络问题。但随着网络的不断复杂化,对复杂网络的管理和检测的需求日益增加。现如今,计算机网络不仅规模大而且通常有着各种系统利用大量不同种类的协议所进行的通信。这种复杂的局面产生了更多的可以监视和检测网络通信的智能化工具。今天,在任何一个网络管理员的管理工具箱中都有着这样的一个工具,那就是嗅探器(sniffer)。嗅探器,也称做数据包分析器,是一些拥有拦截网络传输数据的能力的程序。这些程序在网络管理人员和黑帽社区之中相当流行,因为他们既可被环绕于正义的光环也可沦为邪恶的爪牙。在本文中,我们将阐述数据包捕获的主要原则和方法并且为大家介绍libpcap(一个开源并可移植的数据捕获库,著名的网络工具tcpdump,dsniff,kismet,snort和ettercap的核心便有libpcap库中的各种API)。******数据包捕获**************************************************************数据包捕获是在数据传输的网络上进行数据收集的一种行为。嗅探器是捕获数据包的最佳实现,但是许多其它种类的应用需要通过网卡才能完成数据包的捕获,它们包括网络数据统计工具,入侵检测系统,端口锁定守护进程,密码嗅探器,ARP注入攻击,路由检测器等等。首先让我们大致了解一下数据包捕获在以太网络中的工作原理。每当一个网卡收到一个以太帧,它就会检测该帧的目的网卡地址(MACaddress)是否与自己的网卡地址相符(相同)。如果相符,网卡便产生一个中断请求,该中断请求将由负责处理此类中断的系统网卡驱动程序处理。该驱动给接收到的数据打上时间戳,然后将数据从网卡缓冲区复制到系统内核空间的一块内存上。接着系统通过查看以太数据帧头的以太类型区域判断接收到的数据包是属于哪一种类型继而将该包中的数据传递给协议堆栈由相应的协议处理机制处理。大多数情况下数据包包含一个IPv4数据报,如此,IPv4协议处理机制将被激活。这种处理机制将进行一系列验证行为来确保比如数据包没有遭到损坏,本机的确是该包的目的地等等。当所有验证均通过后,IP头被移除,剩下的部分再被传递到下一层协议处理机制(可能是TCP或者UDP)。这种处理过程不断重复直到数据到达由用户空间的应用程序来处理的应用层。当我们使用嗅探器时,数据包将完成上述的相同过程,但除了一个地方:网络驱动程序也将拷贝接收到的或是发出的任何数据到内核中名叫数据包过滤器的部分。而正是数据包过滤器使数据包的捕获成为可能。默认的情况下,数据包过滤器允许任意包通过,但是,我们稍候将会看到它们通常提供了高级的过滤能力。由于数据包捕获可能涉及到网络安全,因此多数操作系统要求必须要有管理员的权限才能使用数据过滤的这一项功能。图1阐释了捕获数据包的过程。******Libpcap*****************************************************************Libpcap是一个提供了针对网络数据包捕获系统的高层接口的开源函数库。它是在1994年由麦克坎尼(McCanne),莱乐士(Leres)和杰科宾森(Jacobson)创建的。当时他们是美国加洲柏克利大学劳恩斯国家实验室的研究生,而Libpcap正是他们研究和改善TCP和英特网网关功能的一部分成果。Libpcap作者的主要愿望是开创一个独立平台的应用程序接口(API)以此消除程序中针对不同操作系统所包含的数据包捕获代码模块,因为通常每一个操作系统商都会实现他们自己的捕获机制。(也就是解决了移植性的问题,这有利于提高程序员开发的效率--译者注)Libpcap应用程序接口(API)被设计用于C或者C++语言。然而后来出现很多封装包使它也可用于其它语言,比如:perl语言,python语言,Java语言,C#或者Ruby语言。Libpcap运行于大多数类UNIX操作系统上(Linux,Solaris,BSD,HP-UX...)。当然,也有Windows版本,曰Winpcap。现在libpcap由Tcpdump团队维护。完整的文档和源代码可以从tcpdump的官方网站上获得:()******我们之于libpcap的第一步**********************************************现在我们已经知道数据包捕获的原理,让我们编写自己的嗅探程序吧!我们需要的第一件事情是一个用于监听的网络接口。我们可以自己明确的详细说明一个接口,或者让libpcap为我们获取一个。函数char*pcap_lookupdev(char*errbuf)返回一个指向包含第一个适合于数据包捕获的网络设备名称的字符串的指针。通常当用户自己没有说明任何一个网络接口时,这个函数应该被调用。使用硬编码的接口名称是一个很差的主意,因为他们几乎没有移植性。函数pcap_lookupdev()中的参数errbuf是应由用户提供的一段缓冲区,如果有不正常的地方libpcap库将用这个缓冲区存储出错信息。许多由libpcap实现的函数所带有这个参数。当我们请求分配这个缓冲区时我们一定要谨慎,因为该缓冲区必须要至少可以容纳下PCAP_ERRBUF_SIZE个字节(目前它被定义为256个字节)。当函数出错时返回NULL.一旦我们获取了网络设备的名称,我们还需要打开它。函数pcap_t*pcap_open_live(constchar*device,intsnaplen,intpromisc,intto_ms,char*errbuf)便可以做到。该函数返回一个pcap_t类型的接口描述符,此描述符稍候将会被libpcap的其他函数用到。(与此类似的比如文件描述符--译者注)如果函数调用失败,就返回NULL.函数pcap_open_live()的第一个参数是一个指向包含我们想要打开的网络设备名称的字符串指针,显然该参数可由pcap_lookupdev()获得。第二个参数是我们要捕获的数据包的最大字节数。给这个参数设定一个较小的值在某些情况下也会起到一定作用,比如:我们只想抓获包头或者是在内存资源紧张的嵌入式系统中的程序编写。通常最大的以太帧大小是1518字节。但是其它的链接类型,比如FDDI或者是802.11有跟大的上限值。65535这个数值对于容纳任何网络的任何数据包应该是足够的。参数to_ms定义了在把捕获的数据从内核空间复制到用户空间之前内核应该等待多少个毫秒。反复地改变缓冲区的内容将严重地消耗昂贵的计算时间。如果我们是在一个繁忙的网络传输环境中捕获数据包,那么最好是让内核在内核空间和用户空间之间拷贝数据之前先将数据包聚集,然后一起拷贝。当我们把to_ms的值是赋为零时,这将导致读操作将永远进行下去直到足够的数据包到达网络接口(在拷贝数据之前驱动程序要从网络接口读入数据)。Libpcap文档对该参数没有提供任何建议值,不过我们可以通过参考其他的嗅探器程序来获取一些灵感。Tcpdump用的是数值1000,dsniff用的是数值512,此外ettercap在linux或OpenBSD操作系统下用数值0,其他操作系统下用数值10。参数promisc决定是否将网卡置于混杂模式。也就是说网卡是否可以接收目的地不是自己的数据包。将其置零我们会获取非混杂模式,其他任何值都将置网卡于混杂模式。请注意即使是我们让libpcap将网卡置于非混杂模式,但如果网络接口在此之前已经处于混杂模式,那么他将继续保持在混杂模式的状态下。我们不能保证我们不会收到传输给其它主机的数据包,相反,我们最好像后面做的那样利用libpcap提供的过滤能力。一旦我们打开了一个可以捕获数据包的网络接口,我们必须告诉libpcap我们想要开始捕获数据包了。对此,我们有以下选择:*函数constu_char*pcap_next(pcap_t*p,structpcap_pkthdr*h)将利用由pcap_open_live返回的接口描述符pcap_t,一个指向pcap_pkthdr类型的结构体进行处理后返回第一个到达网络接口的数据包。*函数intpcap_loop(pcap_t*p,intcnt,pcap_handlercallback,u_char*user)被用于收集数据包并且处理它们。该函数直到cnt个数据包被捕获后才会返回。如果cnt是负值,那么pcap_loop()只有在出现错误时才会返回。你可能正在疑惑:如果这些函数只是返回一些整数,那么那些被捕获的数据包在哪儿呢?答案听起来有些复杂。pcap_loop()并没有返回那些捕获的数据包,相反,每当一个数据包被读取时它调用一个由用户定义的函数。这样我们就可以在一个分开的函数中实现我们自己的数据处理方式而不是循环调用pcap_next()并在循环内部处理这些数据。然而,这里面有一个问题,如果pcap_loop()调用我们的函数,我们如何向它传递参数呢?我们需要应用丑陋的全局规则吗?答案是否定的。libpcap的开发团队早已考虑过这些问题并找到一种可以向回调函数(callbackfunction)传递参数的方法,那就是参数user。这个指针在函数的每次调用中均被传递,该指针是指向u_char类型的,因此当调用pcap_loop()和当在回调函数内部使用该参数时我们必须按照程序的需求对它进行强制类型转换。我们的数据包处理函数一定要有具体的原型,否则pcap_loop()将不会知道如何去使用它。它应该按如下方式被声明:voidfunction_name(u_char*userarg,conststructpcap_ptkhdr,constu_char*packet);第一个参数是用于传递给pcap_loop()的用户指针,第二个指针是指向一个包含与被捕获数据包相关的信息的结构体。列表1给出了这种结构体的定义。列表1.Structurepcap_pkthdrstructpcap_pkthdr{structtimevalts;//timestampofcapturebpf_u_int32caplen;//numberofbytesthatwerestoredbpf_u_int32len;//totallengthofthepacket};该结构体中的成员caplen通常和成员len的值一样,但除了以下情况:捕获到的数据包大小超过了我们在函数pcap_open_live()中给snaplen赋的值。*函数intpcap_dispatch(pcap_t*p,intcnt,pcap_handlercallback,u_char*user)是我们的第三个选择。它与pcap_loop()类似,但当函数pcap_open_live()
本文标题:libpcap编程-编写自己的网络嗅探程序
链接地址:https://www.777doc.com/doc-4598613 .html