通信网络程序设计(王晓东西电版)第7章直接网络编程.ppt_第1页
通信网络程序设计(王晓东西电版)第7章直接网络编程.ppt_第2页
通信网络程序设计(王晓东西电版)第7章直接网络编程.ppt_第3页
通信网络程序设计(王晓东西电版)第7章直接网络编程.ppt_第4页
通信网络程序设计(王晓东西电版)第7章直接网络编程.ppt_第5页
已阅读5页,还剩250页未读 继续免费阅读

下载本文档

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

文档简介

,第7章 直接网络编程,7.1 以太网工作原理 7.2 基于Winpcap的网络编程 7.3 原始套接字编程 7.4 基于libnet的网络编程 7.5 基于NDIS的网络编程 小结,前面介绍的基于三大协议的网络编程能够满足常规网络编程的要求,可以实现普通网络通信应用的设计,但是却都无法直接访问网络层和数据链路层。随着计算机网络复杂性及规模的不断增长,迫切需要提供一些网络工具能够在网络层和数据链路层面上分析、诊断和测试网络,保证网络通信的正常运行和通信安全。由于这些网络诊断测试和安全工具工作在网络较低的层次(链路层或网络层),因而不能采用常规的网络编程方法。本章将介绍几种不同的直接网络编程方法来实现这种需求。通过对本章的学习,可以使读者进一步了解到网络低层协议的运行机理,从更深层次掌握网络编程方法。,本章在剖析以太网的工作原理的基础上,首先简要介绍基于Winpcap的网络数据包捕获编程,然后介绍基于原始套接字的网络编程,鉴于原始套接字编程数据包构造方面的局限,又介绍了基于libnet的数据包构造编程,最后介绍了基于NDIS的passtru数据包过滤编程方法。这些编程接口为用户开发网络嗅探、协议分析、网络攻击、入侵检测、防火墙等复杂网络应用提供了重要工具。,直接网络编程技术与网络链路层协议、网卡工作模式以及网卡驱动模型有密切关系,这三项技术解决了数据从网络到主机,再到应用的传递问题。在展开编程设计前,首先对这三方面的知识内容进行简要介绍。,7.1 以太网工作原理,7.1.1 CSMA/CD协议 OSI模型中,网络层的下面是链路层,这一层最重要的功能是确定由谁占有信道,以太网采用CSMA/CD协议实现该功能。在常见的网络总线型和环型拓扑中,网络上的设备必须共享传输线路(总线系统),为解决同一时间几个设备同时争用传输介质的难题,需要有某种访问控制方式,以便协调各设备访问介质的顺序,从而无障碍地在设备之间交换数据。,总线型结构中(如图7-1所示),每个站(网络节点)都能独立地决定帧的发送,若两个或多个站同时进行发送,就会产生冲突,而且同时发送的所有帧都会出错。因此,一个用户发送信息的成功与否在很大程度上取决于判断总线是否空闲的算法以及两个不同节点同时发送的分组发生冲突时所使用和中断传输的方法。在随机访问方式中,常用的争用总线技术为CSMA/CD(Carrier Sense Multiple Access/Collision Detect,遵循IEEE 802.3标准),它是载波监听多路访问(CSMA)和冲突检测(CD)两种技术的结合。,CSMA技术也叫做先听后说(Listen Before Talk,LBT)技术,这种技术总是希望传输的站首先对信道进行监听以确定是否有别的站在传输。如果信道空闲,该站可以传输;否则,该站先避让一段时间后再尝试。由此,LBT就需要有一种退避算法来决定退让时间,CSMA/CD常用的退避算法有非坚持、1-坚持、P-坚持三种。,图7-1 总线型结构,1非坚持算法 非坚持算法规则规定: 假如媒体是空闲的,则可以立即发送。 假如媒体是忙的,则等待一个由概率分布决定的随机重发延迟后,再重复前一步骤。 采用随机的重发延迟时间可以减少冲突发生的可能性。非坚持算法的缺点是:即使有几个节点都有数据要发送,但由于大家都在延迟等待过程中,致使媒体仍可能处于空闲状态,因此使用率降低。,21-坚持算法 1-坚持算法规则规定: 假如媒体空闲的,则可以立即发送。 假如媒体是忙的,则继续监听,直至检测到媒体是空闲,则立即发送。 假如有冲突(在一段时间内未收到肯定的回复),则等待一段随机量的时间后重复步骤。 这种算法的优点是:只要媒体空闲,站点就立即可发送,避免了媒体利用率的损失;其缺点是:假若有两个或两个以上的站点都有数据要发送,冲突就不可避免。,3P-坚持算法 P-坚持算法规则规定: 监听总线,假如媒体是空闲的,传输概率为P,以1-P的概率延迟一个时间单位。一个时间单位通常等于最大传播时延的2倍。 延迟一个时间单位后,再重复步骤。 假如媒体是忙的,继续监听直至媒体空闲并重复步骤。 P-坚持算法是一种既能像非坚持算法那样减少冲突,又能像1-坚持算法那样减少媒体空闲时间的折中方案。问题在于如何选择P的值,这要考虑到避免重负载下系统处理于不稳定状态。,在CSMA中,由于通道的传播延迟,当两个站点都监听到总线上没有存在信号而发送帧时,仍会发生冲突。由于CSMA算法没有冲突检测功能,即使冲突已发生,也仍然要将已破坏的帧发送完,使总线的利用率降低。一种CSMA的改进方案是使站点在传输时间继续监听媒体,一旦网络检测到冲突(Collision Detect),就立即停止发送,并向总线上发一串短的阻塞报文(Jam),通知总线上各站已发生冲突,这样通道容量不致因白白传送已受损的帧而浪费,可以提高总线的利用率,这就是CSMA/CD。CSMA/CD很好地解决了链路层信道竞争的问题,使得数据可以顺利地发送到网络上指定的站。,根据IEEE 802标准,数据链路层进一步又可划分为逻辑链路层LLC(Logical Link Control)子层和介质访问控制MAC子层。前者负责识别网络层协议并对它们进行封装;后者负责实现CSMA/CD或类似的访问控制(如Token令牌方式)。,7.1.2 NIC接收模式 虽然CSMA/CD协议解决了网络总线的信道资源利用的重要问题,但在站节点上,数据想要透过物理层和链路层到达主机的更上层直至应用,还离不开一个重要软硬件设备网卡。网卡即网络适配器(Network Interface Card,NIC),是局域网中最基本的部件之一,它是连接计算机与网络的关键设备,无论是双绞线连接、同轴电缆连接还是光纤连接,都必须借助于网卡才能实现主机与网络间的数据通信。,从网络通信模型角度来看,一块网卡包括OSI模型的两个层物理层和数据链路层。物理层定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口,我们编程时并不关心这些。数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能,这是我们进行直接网络编程所必须了解的。在这两个层面上,可以将网卡的功能总结为“来”和“去”两条:一是接收网络上其他设备传过来的帧,并将帧重新组合成数据,发送到所在的电脑的网络协议栈上层;二是将电脑的数据封装为帧,并通过网线(对无线网络来说就是电磁波)将数据发送到网络上去。,结合CSMA/CD的工作原理进行分析,要想实现信道的竞争占用,网卡必须能够监听到信道中所有的传输信号,这种接收模式称为混杂(Promiscuous)模式。正常情况下,网卡工作在非混杂模式下,接收传输来的数据的具体过程是:网卡检查数据帧目的MAC地址,根据计算机上的网卡驱动程序设置的接收模式判断接收与否。如接收,则产生中断信号通知CPU;如不接收,则将数据帧丢弃。CPU得到中断信号产生中断,操作系统接收数据。在混杂模式下,上述MAC地址检查的步骤会被跳过,因而所有的链路层帧都会被接收,若进一步对截获的帧进行解析,网络层、传输层的数据包也可以容易地获得。,总结起来,网卡共有如下四种接收模式: (1) 广播方式:能够接收网络中的广播信息。 (2) 组播方式:能够接收组播数据。 (3) 直接方式:只有目的网卡才能接收该数据。 (4) 混杂模式:能够接收通过它的一切数据,而不管该数据是否是传给它的。 本章重点讲述混杂模式,有很多方法可以将网卡设置成混杂模式,以下函数采用套接字I/O命令ioctlsocket(见5.2.3节)将套接字设置成混杂模式: ioctlsocket(sRaw,SIO_RCVALL,&dwValue) sRaw为原始套接字,见7.3节在后续的编程过程中,还会接触到其他设置方法。,7.1.3 NDIS驱动模型 进一步分析网卡的工作机制会发现,无论采用何种接收模式,网卡要实现网络数据与协议栈上层的数据交互必须具备两大技术,即网卡驱动程序和I/O技术。驱动程序使网卡和网络操作系统兼容,实现网卡与网络的通信;I/O技术可以通过数据总线实现计算机应用和网卡之间的通信,以太网的这两项技术遵循网络驱动程序接口规范(Network Driver Interface Specification,NDIS)。NDIS横跨传输层、数据链路层和网络层,它将这些层面无缝地衔接在一起,通过定义网卡或网卡驱动程序与上层协议驱动程序之间的通信接口规范,屏蔽了底层物理硬件的不同,使上层的协议驱动程序可以和底层任何型号的网卡通信。,NDIS同时也为网络驱动程序创建了一个完整的开发环境(参见7.5.2节),程序员只需调用NDIS函数来访问链路层,而不用考虑操作系统的内核(参见7.5.1节)以及与其他驱动程序的接口问题,从而使得网络驱动程序可以从与操作系统的复杂通信中分离,极大地方便了网络通信程序的编写。 NDIS支持的网络驱动程序类型有以下几类: (1) 网卡驱动程序。网卡驱动程序也称为微端口驱动,它负责管理网卡,是网卡与上层驱动程序通信的接口,它负责接收来自上层的数据包,或将数据包发送到上层相应的驱动程序,同时它还完成处理中断等工作。网卡驱动一般由网卡设备商提供。,(2) 中间驱动程序。中间驱动程序位于网卡驱动程序和协议驱动程序之间,它向上提供微端口(minport)函数集,向下提供协议(protocol)函数集,因此对于上层驱动程序而言,它是微端口驱动程序。对于底层的驱动程序,它是协议驱动程序,从而构建了网卡驱动与协议驱动之间的桥梁。中间层驱动工作在内核层(详见7.5节),有很高的执行权限。在这一层,通过有选择地拒绝转发一些数据包,可以实现包过滤的功能。 (3) 协议驱动程序。协议驱动程序处于NDIS的最高层,执行具体的网络协议,如IPX/SPX、TCP/IP等。协议驱动程序为应用层客户程序提供服务,接收来自网卡或中间驱动程序的信息。,由图7-2所示的Windows操作系统的网络接口拓扑结构图可以看出,NDIS处于微端口驱动程序的上面,微端口相当于IEEE 802标准的数据链路层的MAC子层,而NDIS则相当于LLC子层。当数据包到达网络适配器时,网卡驱动程序将数据通过NDIS发送给微端口驱动程序,然后微端口驱动程序通过NDIS发送给传输层驱动程序,最后到达上层应用程序。同样,当要发送数据时,应用程序将数据发送给传输层驱动程序,传输层驱动程序通过NDIS发送给微端口驱动程序,然后微端口驱动程序通过NDIS发送给网卡驱动程序,最终发送到物理链路上。,图7-2 Windows操作系统的网络接口拓扑结构,中间层驱动和协议驱动都可以由程序员按照自己的需求和专用开发工具自主开发。另外,三种驱动在网卡中并不一定是线性承接关系,协议驱动可以直接与网卡驱动通信,这一点需要注意。,由7.1.2节的内容可知,利用混杂模式可以捕获所有网络中传输的数据包。这种模式下,目前可以采用专用硬件和软件两种方法完成数据帧的捕获。虽然由软件来捕获的方法在性能上比不上专用硬件,但它更廉价,且易于修改和更新。基于以上原因,用软件的捕获方法得到了广泛的使用。下面介绍的基于Winpcap的网络编程就是目前主流的数据包捕获方法。,7.2 基于Winpcap的网络编程,7.2.1 Winpcap工作原理 1Winpcap的概念 Winpcap是Win32环境下的数据包捕获结构,它来源于California大学的Berkeley Packet Filter(BPF)。BPF是UNIX环境下的一个很有名的内核数据包捕获组件,它效率高,易于使用,有一个功能强大的用户层接口(libpcap函数库)。一个著名的使用这个函数库的网络工具是tcpdump,它在UNIX环境下得到了广泛使用,在Windows环境下的版本是Windump。,Winpcap提供捕获原语捕获网络中传输的各种数据包,并传输到调用它们的应用程序中。捕获原语的实现与操作系统紧密相关,不同平台的实现方法不同。为了能在高速且负荷较重的LAN中捕获到所有网络数据包,以及适应大量的网络协议、不断出现的新协议和不同网络应用的需求(如网络分析器、网络监视器、网络测试等),Winpcap提供了一个具有良好的易用性和可扩展性的高效、通用且富于弹性的内核。 Winpcap可以用于网络分析、网络故障诊断、网络安全和监视等网络工具中,提供的功能主要包括以下四个方面: (1) 捕获网络原始数据包; (2) 根据用户定义的规则过滤数据包;,(3) 发送用户构造的数据包到网络中; (4) 统计网络流量。 Winpcap是在Win32系统环境中通过计算机的网络接口来捕获网络数据的一种软件框架,它通过提供一些高层API函数来满足用户的需求。Winpcap由数据包捕获驱动器、底层动态链接库(Packet.dll)和高层静态连接库(Wpacp.lib)三部分组成。Winpcap可以用来制作新的Windows平台下的网络工具,,也可以通过它来移植UNIX/Linux系统环境中一些基于libpcap的网络应用程序,它与BPF-libpcap的捕获机制是兼容的。在Windows NT/2000环境中,Winpcap支持以太网、FDDI、ARCNET和ATM网络。 Winpcap的功能虽然强大,但也不是万能的。归纳起来,它可以完成的应用功能包括:网络协议分析器、网络监控器、网络流量记录器、流量发生器、用户层桥接/路由器、网络入侵检测系统(NIDS)、网络扫描器及安全工具。由于Winpcap不能拦截网络数据,因此不能完成的功能包括:流量控制、QOS调度、个人防火墙,希望读者在应用时加以区分。,2Winpcap的结构 下面从Winpcap的捕获栈结构和驱动器处理两方面进行介绍。 1) Winpcap的捕获栈结构 图7-3是Winpcap捕获栈的结构,图中的高层应用程序是Windump,最底层是网络接口,用来收发网络数据包。在捕获过程中,网络接口工作在混杂模式,接收网段中的所有数据包。数据包捕获驱动器是整个捕获栈中最底层的软件模块,它工作在系统内核层,与网络接口进行通信,取得网络数据包,并向高层应用程序提供读/写来自网络数据链路层数据的接口。,Packet.dll工作在用户层,与捕获应用程序分离,它屏蔽低层的实现细节,提供一个与系统无关的接口。Wpcap.lib是一个静态链接库,它利用Packet.dll提供的服务,为应用程序提供高层接口(API函数)。因为它是一个静态链接库,所以它是应用程序的一部分。最高层是用户的应用程序,用于显示捕获的数据包,或者对数据进行处理。,图7-3 Winpcap捕获栈的结构,捕获栈内核部分的基本任务是从网络中取得链路层数据包,并传送到应用程序中。应用程序通过读/写原语来访问捕获驱动器,把网络接口等同于一个普通文件来读/写来自网络中的数据。应用程序与内核捕获驱动器的通信是通过Packet.dll动态链接库来实现的。 捕获驱动器通过NDIS与网络接口的驱动程序进行通信。NDIS是Win32网络编码的一部分,它负责管理多种网络接口以及网络接口与网络协议软件之间的通信。一个基本的网络捕获驱动器可以非常简单,它只需要读取从网络接口传来的数据,并把数据拷贝到应用程序。但是,如果要得到较好的性能,这种基本的结构要做很大的修改,例如:, 为了减少丢包率,驱动器应当把捕获的数据包保存在缓存区中,等待用户程序读取。 为了尽量减少用户应用程序(在用户模式下)和驱动器(在内核模式下)之间的上下文切换,在一次读命令中应当可以传送多个数据包。 用户应用程序可以只接收它感兴趣的数据包。一个应用程序可以定义它所需要的数据包的种类(如来自某一个特定主机的数据包),驱动器只给它传送这些数据包。也就是说,应用程序可以设置一个过滤器(filter),只接收满足过滤条件的数据包,而忽略其他不感兴趣的数据包。,Winpcap支持的操作系统包括Windows 9x/NT/2000等。在Windows 9x系统中,Winpcap的核心是一个可以装载的虚拟设备驱动程序(.vxd);而在Windows NT4/2000系统中,则是一个驱动程序(.sys)。,图7-4 驱动程序的结构,2) Winpcap的驱动器处理 驱动程序的基本结构如图7-4所示。向上的箭头表示从网络到应用程序的数据流,在内核缓存区与应用程序之间的箭头表示一次读系统调用可以传送多个数据包;向下的箭头表示从应用程序到网络之间传送的数据包。图7-3只是简单的结构描述,实际的系统结构要复杂得多。 (1) 数据包过滤(filter)处理。Winpcap的基本过滤机制来源于UNIX环境中的BPF过滤器,需要过滤数据包的应用程序可以建立一个标准的BPF的过滤程序(调用函数pcap_compile),并把它传送到驱动程序,此后,过滤进程将在系统内核进行数据包过滤。,如果建立了过滤器,捕获驱动程序将会检查每个到达的数据包,不满足过滤条件的数据包将被丢弃;满足过滤条件的数据包则被复制到应用程序中。如果没有定义过滤器,捕获驱动程序则接收所有的数据包。对数据包的过滤处理是当数据包仍在网络接口驱动程序的存储空间中时进行的,不用把数据包复制到捕获驱动程序中。 (2) 读取缓存处理。当应用程序读取网络数据包时,它向NDIS数据包捕获驱动程序发出一个读(read)命令。NDIS数据包捕获驱动程序提供同步和异步两种调用方式。在同步方式中,读调用命令在有数据包到达本机网络接口之前被阻塞;在异步方式中,应用程序不会被阻塞,当有数据包到达时,需要进行检查。,(3) 写数据包处理。数据包捕获驱动程序可以让程序员自己构造数据包并发送到网络中去,这一功能对测试网络或协议非常有用。为了发送数据包,应用进程执行一条写(write)系统调用,把数据包发送到网络中。在发送之前,应用进程还要给数据加上各种网络协议的包头,数据链路层的FCS校验由网络接口硬件来计算并自动添加到数据帧中。因为每发送一个数据包都要进行一次系统调用,所以发送数据包的速度不是很高。在Windows NT/2000系统中,可以通过一条系统调用多次发送一个数据包。,(4) 统计处理。网络管理员通常并不是对所有的数据包都感兴趣,有时只是想了解网 络中传输数据包的统计数据,如用户可能需要了解网络的利用率、广播级别,或者网络中邮件数据包的数量、每秒钟web请求的数量等。统计模式(Statistics Mode,模式1)可以用来取得网络的各种统计数据。当驱动程序处于统计模式时,驱动程序不捕获任何数据包,而只是计算满足用户定义的BPF过滤器的数据包的数量,这些数据定期传送到应用进程。统计模式占用的系统资源很少,因为它只对每个数据包进行BPF过滤,而不拷贝。,由于数据包捕获驱动程序主要是基于以太网适配器而开发的,不支持令牌环网,因此不能捕获LCP和NCP数据包等。,7.2.2 Winpcap编程 1Winpcap函数 Winpcap提供了两组编程函数,即基于动态链接库Packet.dll和基于静态链接库Wpcap.lib的API函数集。Packet.dll中封装了许多函数,实现了用户进程与驱动器之间的通信,使用户程序避免使用系统调用或IOCTL命令。此外,它还提供一系列用来处理网络接口、从网络中读/写数据包、设置缓存区和过滤器等的函数。Wpcap.lib同样使用Packet.dll提供的函数,但是提供了一种更有效、更易于使用的编程环境。使用Wpcap.lib时,可以简便、安全地实现捕获数据包、创建捕获过滤器或保存数据包等任务。,此外,由于Wpcap.lib的Win32版本(Wpcap)和UNIX版本(Libpcap)是兼容的,所以可以很容易地把用Wpcap编写的应用程序移植到UNIX环境中。因此,如果要编写一个网络数据包捕获的应用程序,建议使用数据包捕获函数库(Wpcap.lib)。下面主要介绍Wpcap.lib所提供的API函数。 Win32环境中的Wpcap是UNIX版本的Libpcap的一个超集(superset),它在Win32环境中增加了统计模式和其他几个函数。下面介绍Win32环境中的Wpcap函数。 1) typedef void(*pcap_handler)(u_char *user,const struct pcap_pkthdr *pkt_header, const u_char *pkt_data),此函数是回调函数的原型。当用户调用函数pcap_dispatch()或者函数pcap_loop()时,数据包通过这个回调函数传递给应用进程。其中,参数user是用户定义的包含捕获会话状态的参数,它与函数pcap_dispatch()和pcap_loop()中的参数user一致;参数pkt_header包含了捕获数据包的包头,这个包头并不是网络数据包的协议头;参数pkt_data指向数据包中的数据,其中包含网络协议包头信息。,2) pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 此函数用来取得网络数据包捕获设备(网络接口)的描述符。其中,参数device表明要打开的网络设备的字符名;参数snaplen指明捕获数据包的最大值(bytes);参数promisc指明是否把网络接口设置成混合模式;参数to_ms定义捕获数据包的时间长度(单位是 毫秒);参数ebuf用来返回错误信息,只有在函数pcap_open_live()失败并返回NULL时才设置。,3) pcap_t * pcap_open_dead(int linktype, int snaplen) 此函数用来创建一个pcap_t结构,在调用libpcap的其他函数时要用到这个结构。一个典型的用途是在编译BPF过滤器编码时要用到。 4) pcap_t * pcap_open_offline(const char *fname, char *errbuf) 此函数用来打开一个保存数据的文件,读取文件中的信息。其中,参数fname定义了要打开的文件名,文件格式与tcpdump保存数据的文件格式相同;参数errbuf返回出错信息,只有在函数pcap_open_offline()失败并返回NULL时才被设置。,5) pcap_dumper_t *pcap_dump_open(pcap_t *p, const char *fname) 此函数用来打开一个保存数据的文件,往文件中写信息。如果函数出错,则返回NULL。其中,参数p是由函数pcap_open_offline()或者pcap_open_live()返回的一个pcap结构;参数fname定义打开的文件名,如果此函数返回NULL,则表明出错,通过调用函数pcap_geterr()可以得到出错信息。,6) int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) 此函数用来在阻塞(blocking mode)和非阻塞模式(nonblocking mode)之间进行转换。在非阻塞模式下,如果当前没有数据包可以读取,则捕获函数pcap_dispatch()立即返回0;而在阻塞模式下,捕获函数一直被阻塞,直到有数据包到来。 7) int pcap_getnonblock(pcap_t *p, char *errbuf) 此函数取得非阻塞模式下网络接口的状态。,8) int pcap_findalldevs(pcap_if_t *alldevsp, char *errbuf) 此函数返回系统中可用的网络接口列表。其中,参数alldevsp是指向列表第一个元素(网络接口)的指针。 9) void pcap_freealldevs(pcap_if_t *alldevsp) 此函数用来释放由函数pcap_findalldevs()分配的列表。 10) char *pcap_lookupdev(char *errbuf) 此函数返回一个适合于调用函数pcap_open_live()和pcap_lookupnet()的网络设备的指针。如果函数出错,则返回NULL,在errbuf中能找到错误信息。,11) int pcap_lookupnet(char*device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char*errbuf) 此函数用来确定网络设备device的网络号和子网掩码。两个参数netp 和maskp 都是指向结构bpf_u_int32的指针。函数的返回值如果为-1,表明出错,在数据结构errbuf中填充有错误信息。,12) int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 此函数用来收集和处理数据包。其中,参数cnt 定义在函数返回前进行处理的最大数据包数量,如果参数cnt为 -1,则在读驱动器中的数据时,处理接收在一个缓存区中的所有数据;参数callback定义了被调用的回调函数,此函数带有三个参数,即一个u_char指针由函数传递进来)、一个指向结构pcap_pkthdr的指针和一个指向数据包的u_char指针。,函数返回读取的数据包的数量。如果函数返回0,则表明没有数据包被读取,这可能是因为数据包不满足过滤条件而被丢弃,或者超时间隔内没有数据包到达网络接口等;如果函数返回 -1,表明函数出错,出错信息可以通过调用函数pcap_perror()或pcap_geterr()得到。,13) int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 此函数与函数pcap_dispatch()类似,不同之处在于,这个函数始终在读取数据包,直到处理数据包的数量超过参数cnt的值,或者函数发生错误为止。如果参数cnt为负数,函数将永远循环读取数据包而不退出,除非发生错误。 14) void pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) 此函数pcap_dump()把一个数据包输出到由函数pcap_dump_open()打开的文件中。,15) int pcap_compile(pcap_t *p,struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask) 此函数将参数str中包含的字符串(参照过滤规则)编译到过滤器程序中。其中,参数program是一个指向结构bpf_program的指针,此结构由函数pcap_compile()填写;参数optimize控制是否优化编译代码;参数netmask定义本地网络的子网掩码(netmask)。如果函数出错,则返回 -1。,16) int pcap_setfilter(pcap_t *p, struct bpf_program *fp) 此函数用来定义过滤器程序。参数fp是一个指向结构bpf_program的指针,此结构通常是调用函数pcap_compile()后的返回结果。函数返回 -1表明出错,返回0表明成功。 17) void pcap_freecode(struct bpf_program *fp) 当驱动器的BPF过滤程序没有用时,通过此函数释放分配给结构bpf_program的缓存区。 18) u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h) 此函数返回指向下一个数据包的指针。,19) int pcap_datalink(pcap_t *p) 此函数返回网络链路层的类型。链路层类型包括: DLT_EN10MB :以太网类型(10 Mb、100 Mb、1000 Mb或更高) DLT_IEEE802 :IEEE 802.5令牌环网 DLT_ARCNET :ARCNET SLIP DLT_PPP :PPP。如果前两个字节是0xff和0x03,则是采用类似HDLC装帧的 :PPP,带有一个PPP头和其他两个字节;否则是不装帧PPP, :数据包以PPP头开始 DLT_FDDI :FDDI,DLT_ATM_RFC1483 :RFC 1483 LLC/SNAP ATM;数据包以一个IEEE 802.2 LLC头开始 DLT_RAW :原始IP;数据包以一个IP头开始 DLT_PPP_SERIAL :串行PPP DLT_PPP_ETHER :PPPoE DLT_C_HDLC :Cisco PPP DLT_IEEE802_11 :IEEE 802.11 wireless LAN DLT_LOOP :OpenBSD网络回路 DLT_LTALK :Apple LocalTalk,20) int pcap_snapshot(pcap_t *p) 此函数返回调用函数pcap_open_live时定义的snapshot长度。 21) int pcap_is_swapped(pcap_t *p) 如果数据包保存文件时采用的字节顺序与目前系统不同,此函数返回true。 22) int pcap_major_version(pcap_t *p) 此函数返回pcap的主版本号。 23) int pcap_minor_version(pcap_t *p) 此函数返回pcap的次版本号。,24) int pcap_stats(pcap_t *p, struct pcap_stat *ps) 此函数填写一个pcap_stat结构,并返回0。结构中的值表示从驱动器开始运行到此函数调用时这一段时间内数据包的统计数据。如果函数出错或者驱动器不支持数据包统计功能,函数返回 -1。错误信息可以通过函数pcap_perror()或pcap_geterr()得到。 25) FILE * pcap_file(pcap_t *p) 此函数返回输出流(stdio stream)的文件名。 26) int pcap_fileno(pcap_t *p) 此函数返回保存数据文件的描述符。,27) void pcap_perror(pcap_t *p, char *prefix) 此函数输出最近一次的错误信息。 28) char *pcap_geterr(pcap_t *p) 此函数返回最近一次的错误信息。 29) char *pcap_strerror(int error) 如果系统中的函数strerror()不可用,则用函数pcap_strerror()来替代。 30) void pcap_close(pcap_t *p) 此函数关闭指针p指向的文件并释放资源。 31) void pcap_dump_close(pcap_dumper_t *p) 此函数关闭保存数据的文件。,32) int pcap_setbuff(pcap_t *p, int dim) 此函数把由参数p 指定的网络适配器的内核缓存区大小设置为dim bytes(参数二)。函数成功则返回0,否则返回 -1。pcap_open_live()缺省创建的缓存区大小为1 MB。 33) int pcap_setmode(pcap_t *p, int mode) 此函数设置网络接口的工作模式。有效的工作模式有两种:MODE_CAPT(缺省的捕获模式)和MODE_STAT(统计模式)。,34) int pcap_sendpacket(pcap_t *p, u_char *buf, int size) 此函数可以让应用程序发送原始数据包,而不用直接访问底层的API函数。其中,参数p是发送数据包的网络接口,参数buf包含了待发送数据包的数据(包括各层网络协议的包头),参数size是buf的大小。链路层MAC帧中的CRC校验字段不用添加到数据包中,它由网络接口自动计算添加。 35) int pcap_setmintocopy(pcap_t *p, int size) 此函数改变能引起读操作返回的最小内核缓存区中数据的数量。如果参数size设置太大,系统内核会强制等待接收到多个数据包后才把数据拷贝到用户进程。,这样做能减少系统调用的次数,提高系统的资源利用率,但是应用进程可能不会立即得到进入网络适配器的数据包;如果这个值设置的较小,系统内核会马上把数据包拷贝到应用进程,这对响应时间要求较高的实时应用程序有利。 36) HANDLE pcap_getevent(pcap_t *p) 此函数返回与网络接口p相关的事件的句柄。这一事件可以传递给诸如WaitForSingle- Object()或者WaitForMultipleObjects()函数。 37) pcap_send_queue *pcap_sendqueue_alloc(u_int memsize) (Win32特有函数),此函数分配一个发送队列缓存区,缓存区中保存将要通过函数pcap_sendqueue_ transmit()发送到网络中的一组原始数据包。参数memsize是队列的大小(bytes)。使用函数pcap_sendqueue_queue()可以把数据包插入到已经分配好的队列中。 38) void pcap_sendqueue_destroy(pcap_send_queue *queue) (Win32特有函数) 此函数删除一个发送队列并释放其存储空间。,39) int pcap_sendqueue_queue(pcap_send_queue*queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) (Win32特有函数) 此函数添加一个数据包到发送队列queue的末尾。参数pkt_header指向一个pcap_pkthdr结构,在这个结构中包含时戳和数据包的长度。结构pcap_pkthdr在WinPcap和libpcap中的用法相同,都是用来把数据包保存到文件中,因此,可以直接发送一个数据包捕获文件。如果要发送用户自己构造的原始数据包,则必须在数据包中包含各层网络协议包头。,40) u_int pcap_sendqueue_transmit( pcap_t *p,pcap_send_queue *queue,int sync) (Win32特有函数) 此函数把发送队列queue中的数据包发送到网络中。其中,参数p指明用来发送数据包的网络接口;参数queue指向结构pcap_send_queue,结构中是要发送的数据包;参数sync确定发送操作是否必须同步,如果它是一个非0值,则数据包根据时戳代表的时间来发送,否则尽可能快地把数据包发送出处。函数的返回值是实际已经发送的数据量(bytes)。如果这个值小于size参数,则表明在发送过程中有错误发生。,41) int pcap_read_ex(pcap_t *p,struct pcap_pkthdr *pkt_header, u_char *pkt_data) (Win32特有函数) 此函数用来取得可用的下一个数据包。函数填写参数pkt_header(数据包头)和pkt_data(数据包数据)。 函数的返回值为1表示数据包读取成功;为0表示函数pcap_open_live()设置的超时值超时(在这种情况下,指针pkt_header和pkt_data没有指向一个有效的数据包);为-1表示发生错误;-2表示在读取捕获文件时遇到EOF。,42) int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks) (Win32特有函数) 此函数把来自某个网络接口的数据保存到一个文件中,而且,数据包的保存完全在系统内核完成,因此,这个函数比pcap_dump()更有效。函数的参数包括一个网络接口描述符p(通过函数pcap_open_live()取得),一个表示保存数据包文件(dump file)名的字符串,一个表示文件最大容量(in bytes)的整数和一个表示文件能包含数据包的最大数目的整数。参数maxsize或者maxpacks如果设置成0,则表示文件容量没有限制。当文件大小达到参数maxsize或maxpacks的值时,函数操作结束。,43) int pcap_live_dump_ended(pcap_t *p, int sync) (Win32特有函数) 此函数返回系统内核dump进程的状态,查看是否达到了在函数pcap_live_dump()中定义的限制条件。 44) int pcap_stats_ex(pcap_t *p, struct pcap_stat *ps) (Win32特有函数) 此函数与pcap_stats()函数的目的和行为相同,但多返回一个计数器,记录实际捕获到的数据包数量。 上述只是部分wpcap.lib的API函数,对更多的API函数,读者可以自行查询http:/www. /docs/docs_412/html/group_wpcapfaunc/html或网站。,2Winpcap的过滤规则 Winpcap提供捕获数据包的过滤功能(注意,Winpcap只是过滤自己所捕获的数据包,而不是将该数据包从网络中屏蔽,详见7.2.1节的介绍),主要是向过滤器提供过滤规则实现的。过滤器接收一个包含过滤规则的ASCII字符串表达式(语法见表7-1),pcap_compile()得到这个表达式后,把它转换成内核过滤器使用的一个程序。过滤表达式用来选择处理哪些网络数据包。如果没有定义过滤表达式,系统内核将接收网络中所有数据包;否则只有满足过滤表达式的数据包被接收。,表达式包含一个或多个原语,原语通常由一个标识符id和它前面的一个或多个限定词组成,如host ,其中host是限定词,是标识符。以下是可以使用的常用原语列表,如果满足下面的原语,则为True。,表7-1 过滤规则常用原语,除了表中语句外,还允许用户使用下面语句: 1) relop 该语句创建复杂的过滤表示选择数据包中的字节或字节范围。其中,relop是、=、=、=、!= 之一;expr是一个数学表达式,包含整数常量、通常的二进制操作符(+、-、*、/、&、| ),长度操作符和特定的数据包数据访问标识。 2) proto expr : size 该语句用于访问数据包内部数据。proto是ether、fddi、tr、ip、arp、rarp、tcp、udp、icmp或者IPv6协议,表示操作的协议层。,其中,tcp、udp和其他高层协议类型只适用于IPv4,不适用于IPv6;expr表示协议层的偏移量(byte);size是一个可选项,表示查看的字节数,缺省值为1。 例如,ether0 & 1 != 0捕获所有多播的数据流。表达式ip0 & 0xf != 5捕获所有带有选项的IP数据包。表达式ip6:2 & 0x1fff = 0捕获没有分段的数据包。tcp0表示TCP包头的第一个字节。 原语的组合使用包括:否定操作符(! 或 not)、与操作符(& 或 and)、或操作符( |或 or)。,7.2.3 程序设计实现 在Microsoft Visual C+中使用Winpcap函数库Wpcap.lib要遵循以下步骤: (1) 首先安装Winpcap网络驱动程序。 (2) 在每个使用Winpcap函数的应用程序源文件的开始处包含文件pcap.h。 (3) 设置Visual C+编程环境链接器(linker)的选项(options),使其包含Wpcap.lib函数库文件。Wpcap.lib可以在Winpcap开发包(Winpcap Developers Pack)中找到。,(4) 设置Visual C+ 编程环境链接器(linker)的选项(options),使其包含WinSock函数库文件(例如Wsock32.lib),这是因为某些libpcap函数需要WinSock支持。,1捕获数据包 以下程序捕获网络数据包,并显示每个数据包的一些信息(运行该程序的计算机无需设定IP地址)。 用来打开捕获设备的函数是pcap_open_live()。在函数中,参数snaplen定义捕获数据包的部分内容。在Win32系统中,捕获驱动器可以只捕获一个数据包中的某一部分,这样减少了复制数据的数量,提高了系统的捕获效率。在本示例程序中,我们使用的值是65 536,这个值远大于通常的网络MTU(最大传送单位),因此可以保证程序能接收到完整的数据包。,参数promisc指明是否把网络接口设置成混杂模式。参数to_ms定义读操作的超时值,对网络接口的读操作(一般通过调用函数pcap_dispatch()或pcap_read_ex()通常在to_ms定义的时间后返回。如果to_ms设置为0,则函数直到有数据包到达后才返回;如果to_ms设置为 -1,则函数立即返回。 #include “pcap.h“ /处理数据包的回调函数原型 void packet_handler(u_char *param,const struct pcap_pkthdr *header,const u_char *pkt_data ); main() ,pcap_if_t *alldevs; pcap_if_t *d; int inum; int i = 0; pcap_t *adhandle; char errbufPCAP_ERRBUF_SIZE; /取得网络设备列表 if (pcap_findalldevs(&alldevs, errbuf) = -1) ,fprintf(stderr,“Error in pcap_findalldevs: %sn“, errbuf); exit(1); /显示网络设备列表 for

温馨提示

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

最新文档

评论

0/150

提交评论