版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第5章 直接网络编程 第5章 直接网络编程 随着计算机网络复杂性和规模的不断增长,迫切需要一些网络工具来分析、诊断和测试网络,保证网络的正常运行和安全性。这些网络诊断测试和安全工具工作在网络较低的层次(链路层或网络层),不能采用常规的网络编程方法。 本章介绍几种不同的直接网络编程方法。第5章 直接网络编程 第5章 直接网络编程 5.1 原始套接字编程原始套接字编程 5.2 基于基于Winpcap的网络数据包捕获技术的网络数据包捕获技术 5.3 基于基于Libnet的网络数据包构造技术的网络数据包构造技术 习题与思考题习题与思考题 第5章 直接网络编程 5.1 原始套接字编程原始套接字编程 5.
2、1.1 5.1.1 概念概念原始套接字可以对底层的传输协议加以控制,对IP头信息进行实际的操作,通过它可以模拟一些IP的实用工具,如Tracert和Ping等。原始套接字(raw socket)是使用SOCK_RAW这个套接字类型来创建的。目前WinSock 2.2提供了对它的支持。利用原始套接字可直接访问网络协议数据。 第5章 直接网络编程 本节重点讨论利用IP层协议Internet控制消息协议(ICMP)进行原始套接字编程。为了说明问题,运用这种原始套接字来模拟IP的一些实用工具,如Ping和Tracert程序等。Ping这个实用程序探测到某个主机的路由是否有效和畅通,看看对方的机器是否会
3、作出响应。对程序开发者来说,经常都要用到一种程序化的方法,以便判断一台机器是否“活动”,网络数据能否抵达它。IP多播通信利用IGMP将多播组成员信息通知路由器。大多数Win32平台目前都增加了对IGMP第2版的支持。但在某些情况下,我们也需要送出自己的IGMP数据包,以便脱离组成员关系。 第5章 直接网络编程 创建原始套接字可用Socket或WSASocket函数。在套接字的创建过程中,必须自行设定SOCK_RAW标志。下述代码片断解释了如何将ICMP作为一种基层IP协议来完成一个原始套接字的创建:SOCKET s;s=socket(AF_INET, SOCK_RAW, IPPROTO_ICM
4、P);if(s=INVALID_SOCKET)/创建套接字失败 第5章 直接网络编程 在完成了原始套接字的创建之后,就可以在发送及接收调用中使用对应的套接字句柄。创建原始套接字时,无论是否设定了IP_HDRINCL选项,IP头都会包含在接收到的任何返回数据中。上述代码中采用的是ICMP。当使用IGMP、UDP、IP或者原始IP时,只需分别设置IPPROTO_IGMP、IPPROTO_ UDP、IPPR -OTO_IP或IPPROTO_RAW即可。但值得注意的是,Windows 95无法使用原始套接字;在Windows 98/NT的操作系统中,创建原始套接字时,只能使用IGMP(IPPROTO
5、_IGMP)和ICMP(IPPROTO_ICMP)两种协议;而Windows 2000/XP在前者基础上还能够处理IP(IPPROTO_RAW)、TCP (IPPROTO_TCP)及UDP (IPPROTO_UDP)。 第5章 直接网络编程 由于使用原始套接字可以控制基层传输机制,存在潜在的安全隐患,因此,在Windows NT/2000/XP上,只有属于“管理员”(administrator)组的成员,才有权创建类型为SOCK_RAW的套接字。要绕过这一限制,可禁止对原始套接字的安全检查。方法是在注册表中创建变量HKEY_LOCAL_MACHINESystemCur rentControlS
6、etServicesAfdParametersDisableRawSecuri-ty,并将它的值设为1(DWORD类型),然后重新启动计算机。在Windows 9x中,系统未对SOCK_RAW的使用加以限制。 第5章 直接网络编程 5.1.2 ICMP5.1.2 ICMP实现实现Ping程序的实现方法是,主机向远程计算机发出ICMP回应请求以后,远程计算机会处理这个请求,然后生成一条回应应答消息,再通过网络传回给发送主机;假如由于某些原因,不能抵达目标主机,就会生成对应的ICMP错误消息(比如“目标主机不可到达”),由那个路径上某处的一个路由器返回。假定与远程主机的物理性连接并不存在问题,但远
7、程主机已经关机或没有设置对网络事件作出响应,便需由自己的程序来执行超时检查,来检测这样的情况。 第5章 直接网络编程 Ping示例在程序中采取如下步骤:(1) 创建类型为SOCK_RAW的一个套接字,同时设定协议IPPRO TO_ICMP。(2) 创建并初始化ICMP头。(3) 调用sendto或WSASendto,将ICMP请求发给远程主机。(4) 调用recvfrom或WSARecvfrom,以接收任何ICMP响应。接下来的代码示范了如何初始化并发送一个ICMP echo请求: 第5章 直接网络编程 /定义ICMP头typedef struct icmp_hdrunsigned chari
8、cmp_type;unsigned charicmp_code;unsigned shorticmp_checksum;unsigned shorticmp_id;unsigned shorticmp_sequence;unsigned longicmp_timestamp; ICMP_HDR, *PICMP_HDR, FAR *LPICMP_HDR; 第5章 直接网络编程 ICMP_HDR*icmp = NULL;SOCKETs;SOCKADDR_STORAGEdest;charbufsizeof(ICMP_HDR) + 32;icmp = (ICMP_HDR *)buf;icmp-icmp
9、_type=8;/定义echo请求类型icmp-icmp_code=0;icmp-icmp_id=GetCurrentProcessId();icmp-icmp_checksum=0;/将校验和域清零 第5章 直接网络编程 icmp-icmp_sequence=0;icmp-icmp_timestamp=GetTickCount();memset(&bufsizeof(ICMP_HDR), , 32);/随机填充负载端/计算ICMP头和负载的校验和,checksum()函数的实现参见下文Ping程序icmp-icmp_checksum = checksum(buf, sizeof(IC
10、MP_HDR)+32);s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 第5章 直接网络编程 /初始化目标SOCKADDR_STORAGE(SOCKADDR_IN *)&dest)-sin_family=AF_INET;(SOCKADDR_IN *)&dest)-sin_port=htons(0);(SOCKADDR_IN *)&dest)-sin_addr.s_addr=inet_addr(1.2.3.4);sendto(s, buf, sizeof(ICMP_HDR)+32, 0, (SOCKADDR *)&dest
11、, sizeof(dest); 第5章 直接网络编程 ICMP和ICMPv6(基于IPv6的ICMP)的echo请求的唯一差别是计算ICMP头中的校验和。在IPv4中,校验和仅简单地针对ICMP头和负载,但在IPv6中,因校验和应包括IPv6伪头、ICMPv6头和负载进行处理而较为复杂。这就意味着Ping程序必须知道发送IPv6数据包的源和目标地址,以获得IPv6头计算ICMPv6请求。第5章 直接网络编程 5.1.3 Tracert5.1.3 Tracert对IP网络来说,另一个非常有用的工具是Tracert(路由追踪)。在Windows操作系统中,一般可以直接运行tracert.exe来调
12、用这个工具。利用它可侦测出为抵达网络内任何一个指定的主机,中途需经过哪些路由器,以及它们的IP地址是什么。Tracert的设计原理是令其向目的地发送一个数据包,并重复递增IP的“存活时间”(TTL)值。刚开始的时候,TTL等于1;也就是说,一旦它抵达路途中的第一个路由器,TTL首先会超时(变成0),这样便会造成路由器生成一个ICMP“超时”数据包。随后,最初的TTL值递增1,以便UDP包能继续传到下一个路由器,而生成的ICMP超时包会自第一个路由器返回。只需将返回的每一条ICMP消息都收集下来,便能为中途经过的路由器IP地址勾勒出一个清晰的轮廓,直到最终的目标主机。 第5章 直接网络编程 之所
13、以认为Tracert是一个有用的工具,是由于它为我们提供了与途中经历的路由器有关的大量信息。对具体的应用程序来说,尽管需要执行Tracert的机会比Ping少得多,但对某些特定的任务而言,只有Tracert才能胜任。实现Tracert程序,只需将ICMP数据包简单地发给目的地,同时连续递增更改TTL的值。在TTL“超时”的时候,这样做也会造成一条ICMP错误消息的返回。注意这种方法和Ping有着某些共通之处,它也只要求使用一个套接字(安装ICMP协议)。 本书附录6列举了Tracert的完整源代码,有兴趣的读者可以参考。第5章 直接网络编程 5.1.4 IP_HDRINCL5.1.4 IP_H
14、DRINCL的使用的使用 对原始套接字来说,它存在的一项限制是只能对已经定义好的协议(如IGMP和ICMP等)进行操作,而不能用IPPROTO_UDP来创建一个新的原始套接字,也不能对UDP头进行操作;TCP也是一样的。要想对IP头、TCP头、UDP头或封装在IP内的其他任何协议进行操作,必须在使用原始套接字的同时使用IP_HDRINCL选项。利用该套接字选项,用户可以自行构建IP等任何协议头。 第5章 直接网络编程 此外,要在应用程序中实现自定义的协议方案,并将其封装到IP内,必须首先创建一个原始套接字,然后将协议类型设为IPPROTO_RAW。这样,用户就可在IP头内自定义协议字段,同时构
15、建自己的定制协议头。本小节将讲述如何自定义一个UDP数据包,使用户对其中牵涉到的步骤有一个比较全面的了解。一旦理解了如何操作UDP头,就可以很方便地实现自定义的协议头,或对IP内封装的其他协议进行处理。 第5章 直接网络编程 使用IP_HDRINCL选项时,必须针对每一次发送和调用,向IP头内自行填充内容。同时,还要填写封装在其中的其他任何协议头。如下文所示,可以创建一个原始套接字,然后设置IP_HDRINCL标志。SOCKETs;BOOLbOpt;第5章 直接网络编程 s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, 0, WSA_FLA
16、G_OVERLAPPED);ret= setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt);注意,我们现已创建了一个协议为IPPROT_UDP的原始套接字。这种做法只适用于Windows 2000,因为它同时也要求设置IP_HDRINCL选项。 第5章 直接网络编程 5.2 基于基于Winpcap的网络数据包捕获技术的网络数据包捕获技术 许多网络应用通常需要分析网络中的数据流,查找网络故障或安全问题。要分析网络数据流,首先要能从网络中得到数据包。 在一个实际的系统中,数据的收/发是由网卡来完成的,网卡接收到传
17、输来的数据,然后检查数据帧的目的MAC地址,根据计算机上的网卡驱动程序设置的接收模式判断接收与否。如接收,则产生中断信号通知CPU;如不接收,则将数据帧丢弃。CPU得到中断信号产生中断,操作系统接收数据。通常网卡有如下接收模式:(1)广播模式:能够接收网络中的广播信息。第5章 直接网络编程 5.2 基于基于Winpcap的网络数据包捕获技术的网络数据包捕获技术 (2)组播模式:能够接收组播数据。(3)直接模式:只有目的网卡才能接收该数据。(4)混杂模式:能够接收通过它的一切数据,而不管该数据是否时传给它的。 目前有两种方法可以从网络中获得数据包,一种是采用专用硬件,另一种是利用计算机的网络接口
18、(网络适配器),由软件来完成数据帧的获得,这种方法的前提是将本地NIC工作状态设成混杂模式,扑捉与其连接的物理媒体上传输的所有数据。第5章 直接网络编程 5.2 基于基于Winpcap的网络数据包捕获技术的网络数据包捕获技术 虽然由软件来扑获的方法在性能上比不上专用硬件,但它更廉价,且易于修改和更新。基于以上原因,用软件扑获的方法得到了广泛的使用和认同。5.2.1 Winpcap5.2.1 Winpcap简介简介Winpcap是Win 32环境下的数据包捕获结构,它来源于California大学的Berkeley Packet Filter(BPF)。BPF是UNIX环境下的一个很有名的内核数
19、据包捕获组件,它效率高,易于使用,有一个功能强大的用户层接口(Libpcap函数库)。使用这个函数库的一个著名的网络工具是Tcpdump,它在UNIX环境下得到广泛使用,它在Windows环境下的版本是Windump。 第5章 直接网络编程 Winpcap提供捕获原语捕获网络中传输的各种数据包,并传输到调用它们的应用程序中。捕获原语的实现与操作系统紧密相关,不同平台的实现方法不同。为了能在高速且负荷较重的LAN中捕获到所有的网络数据包,并适应大量的网络协议、不断出现的新协议和不同网络应用的需求(如网络分析器、网络监视器、网络测试等),Winpcap提供了一个具有良好的易用性和可扩展性的高效、通
20、用且富于弹性的内核。第5章 直接网络编程 * 捕获网络原始数据包; * 根据用户定义的规则过滤数据包;* 发送用户构造的数据包到网络中;* 统计网络流量。 Winpcap可以用于网络分析、网络故障诊断、网络安全和监视等网络工具中,所提供的功能主要包括以下四个方面:第5章 直接网络编程 Winpcap是在Win 32系统环境中通过计算机的网络接口来捕获网络数据的一种软件框架,它通过提供一些高层API函数来满足用户的需求。Winpcap由数据包捕获驱动器、底层动态链接库(Packet.dll)和高层静态连接库(wpcap.lib)三部分组成。Winpcap可以用来制作新的Windows平台下的网络
21、工具,也可以通过它来移植UNIX/Linux系统环境中一些基于Libpcap的网络应用程序,它与BPF-libpcap的捕获机制是兼容的。图5.1是Winpcap捕获栈的结构,图中的高层应用程序是Windump。 第5章 直接网络编程 图5.1 捕获栈结构 Windump.exe网络数据包应用程序用户层wpcap.libPacket.dll数据包捕获驱动器其他协议栈动态链接库内核层网络接口第5章 直接网络编程 图中最底层是网络接口,用来收/发网络数据包。在捕获过程中,网络接口工作在混杂模式,接收网段中的所有数据包。数据包捕获驱动器是整个捕获栈中最低层的软件模块,它工作在系统内核层,与网络接口进
22、行通信,取得网络数据包,并向高层应用程序提供读/写来自网络数据链路层数据的接口。Packet.dll工作在用户层,与捕获应用程序分离,它屏蔽低层的实现细节,提供一个与系统无关的接口。wpcap.lib是一个静态连接库,它利用Packet.dll提供的服务,为应用程序提供高层接口(API函数)。因为它是一个静态连接库,所以它是应用程序的一部分。最高层是用户的应用程序,显示捕获的数据包,或者对数据进行处理。 第5章 直接网络编程 捕获栈内核部分的基本任务是从网络中取得链路层数据包,并传送到应用程序中。在Windows NT/2000系统中,它的实现为一个内核驱动程序(packet.sys),在Wi
23、ndows 95/98系统中是一个虚拟设备驱动程序(packet.vxd)。应用程序通过读/写原语来访问捕获驱动器,把网络接口等同于一个普通文件来读/写来自网络中的数据。应用程序与内核捕获驱动器的通信是通过Packet.dll动态链接库来实现的。第5章 直接网络编程 捕获驱动器通过NDIS与网络接口的驱动程序进行通信。NDIS是Win 32网络编码的一部分,它负责管理多种网络接口以及网络接口与网络协议软件之间的通信。一个基本的网络捕获驱动器可以非常简单,它只需要读取从网络接口来的数据,并把数据拷贝到应用程序。但是,如果要得到较好的性能,这种基本结构要做很大的修改,例如:* 为了减少丢包率,驱动
24、器应当把捕获的数据包保存在缓存区中,等待用户程序读取。* 为了尽量减少用户应用程序(在用户模式下)和驱动器(在内核模式下)之间的上下文切换,在一次读命令中应当可以传送多个数据包。 第5章 直接网络编程 * 用户应用程序可以只接收它感兴趣的数据包。一个应用程序可以定义它所需要的数据包的种类(如来自某一个特定主机的数据包),驱动器只给它传送这些数据包。也就是说,应用程序可以设置一个过滤器(filter),只接收满足过滤条件的数据包,而忽略其他不感兴趣的数据包。Winpcap支持的操作系统包括Windows 9x/NT/2000等。在Windows 9x系统中,Winpcap的核心是一个可以装载的虚
25、拟设备驱动程序(.vxd);在Windows NT4/2000系统中,则是一个驱动程序(.sys)。 第5章 直接网络编程 数据包捕获驱动程序主要是基于以太网适配器而开发的,目前还不能支持令牌环网。在Windows 9x环境中,它除了适用于以太网以外,还可以用于PPP WAN链路。但是却存在一些局限性。 第5章 直接网络编程 5.2.2 5.2.2 数据包捕获驱动器结构数据包捕获驱动器结构Windows下的数据包捕获驱动程序提供了一个高性能、灵活且与UNIX系统环境中的BPF兼容的网络工具。它的主要功能如下:* 捕获网络中原始的网络流量,并交由高层应用程序进行处理。* 过滤收到的数据包。* 在
26、应用进程忙碌时,把数据包保存在缓存区中。* 给收到的数据包打包,并加上时戳、包长和偏移量。* 构造数据包,并注入到网络中。* 统计网络流量。 第5章 直接网络编程 1.1. 驱动器结构驱动器结构驱动程序的基本结构如图5.2所示。 图中,向上的箭头表示从网络到应用程序的数据流,在内核缓存区与应用程序之间的箭头表示一次读系统调用可以传送多个数据包。向下的箭头表示从应用程序到网络之间传送的数据包。图5.2只是简单的结构描述,实际的系统结构要复杂得多。 第5章 直接网络编程 图5.2 驱动程序结构 用户层内核层网络接口网络数据包内核缓存区网络tap数据包捕获驱动器应用程序User BufferPack
27、et.dllFilterNIC驱动程序第5章 直接网络编程 2. 2. 数据包过滤数据包过滤(filter)(filter)处理处理Winpcap的基本过滤机制来源于UNIX环境中的BPF过滤器,需要过滤数据包的应用程序可以建立一个标准的BPF的过滤程序(调用函数pcap_compile),并把它传送到驱动程序,此后,过滤进程将在系统内核中进行数据包过滤。如果建立了过滤器,捕获驱动程序将会检查每个到达的数据包,不满足过滤条件的数据包将被丢弃。满足过滤条件的包则被复制到应用程序。如果没有定义过滤器,捕获驱动程序则接收所有的数据包。对数据包的过滤处理是当数据包仍在网络接口驱动程序的存储空间中时进行
28、的,不用把数据包复制到捕获驱动程序中。 第5章 直接网络编程 3. 3. 读和缓存处理读和缓存处理当应用程序读取网络数据包时,它向NDIS数据包捕获驱动程序发出一个读(read)命令(在Windows 9x系统中是通过IOCTL调用来取得数据的)。NDIS数据包捕获驱动程序提供同步和异步两种调用方式。在同步方式中,读调用命令在有数据包到达本机网络接口之前被阻塞;在异步方式中,应用程序不会被阻塞,当有数据包到达时,需要进行检查。在一个数据包通过过滤器后,捕获驱动可能处于以下两种状态: 第5章 直接网络编程 * 应用进程已经准备好接收数据包,它执行了一条读调用命令,且正在等待返回结果。在这种情况下
29、,收到的数据包立即被拷贝到应用进程的存储空间中,读调用命令结束,应用进程被唤醒。* 应用进程没有准备好接收数据包,而是在做其他工作。为了防止丢失数据包,数据包应被缓存在驱动程序的缓存区中。当应用进程发出读调用命令时,被缓存的数据则传送到应用进程。驱动器采用循环缓存区来存取数据包,存储在缓存区中的数据带有一个数据头,保存诸如数据包的时戳和大第5章 直接网络编程 小等信息。此外,在数据包之间插入有填充(padding)比特,以使每个数据包的字边界对齐,减少拷贝数据包的时间。当缓存区被填满后,新到达的数据包则被丢弃。当应用进程发出读调用命令且缓存区中有数据时,缓存区中的数据被拷贝到应用进程,读调用命
30、令立即返回。在一次系统调用中可以拷贝多个数据包,这样便提高了系统的性能,减少了系统调用的次数。因为每一次调用都包含一次从用户模式到内核模式的上下文切换,而这些上下文切换比较慢,减少切换的次数可以显著地提高捕获的速度。 第5章 直接网络编程 4. 4. 写数据包处理写数据包处理数据包捕获驱动程序可以让程序员自己构造数据包并发送到网络中去,这一功能对测试网络或协议非常有用。为了发送数据包,应用进程执行一条写(write)系统调用(在Windows 9x系统中是IOCTL系统调用),把数据包发送到网络中。在发送之前,应用进程还要给数据加上各种网络协议的包头,数据链路层的FCS校验由网络接口硬件来计算
31、并自动添加到数据帧中。因为每发送一个数据包都要进行一次系统调用,所以发送数据包的速度不是很高。在Windows NT/2000系统中,可以通过一条系统调用多次发送一个数据包。 第5章 直接网络编程 5. 5. 统计模式统计模式(Statistics mode)(Statistics mode)网络管理员通常不是对所有的数据包都感兴趣,有时只是想了解网络中传输数据包的统计数据。如用户可能需要了解网络的利用率、广播级别,或者网络中邮件(mail)数据包的数量、每秒web请求的数量等。统计模式(Statistics mode,模式1)可以用来取得网络的各种统计数据。当驱动程序处于统计模式时,驱动程序
32、不捕获任何数据包,而只是计算满足用户定义的BPF过滤器的数据包的数量,这些数据定期传送到应用进程。统计模式占用的系统资源很少,因为对每个数据包只进行BPF过滤,而不拷贝。 第5章 直接网络编程 5.2.3 5.2.3 数据包捕获驱动程序数据包捕获驱动程序APIAPI的使用的使用Winpcap提供了一个动态链接库Packet.dll,它为用户应用程序提供了与数据包捕获驱动器之间的接口。 在DLL中封装了许多函数,简化了用户进程与驱动器之间的通信,可使用户程序避免使用系统调用或IOCTL(ioctl( )是设备驱动程序中对设备的I/O通道进行管理的函数)命令。 它还提供一系列用来处理网络接口、从网
33、络中读/写数据包、设置缓存区和过滤器等的函数。 第5章 直接网络编程 如果要编写一个网络数据包捕获的应用程序,建议使用数据包捕获函数库(wpcap.lib),而不采用本节描述的API函数。因为使用Wpcap时,可以简便、安全地实现捕获数据包、创建捕获过滤器或保存数据包等任务。 由于Wpcap.lib的Win 32版本(Wpcap)和UNIX版本(Libpcap)是兼容的,所以用Wpcap编写的应用程序可以很容易地移植到UNIX环境中。 Packet.dll有两种版本,分别工作在Windows 9x环境和Windows NT/2000环境下。这两个版本的DLL导出的是相同的编程接口,使程序员可以
34、编写与系统无关的数据包扑获应用程序。 下面我们将给出如何在应用程序中使用Packet.dll和数据包捕获驱动器,并详细介绍DLL中导出的API函数。第5章 直接网络编程 1. 1. 数据结构数据结构Packet.dll用到的数据结构定义在packet32.h中,主要包括:PACKET、ADAPTER、PACKET_OID_DATA、bpf_insn、bpf_program、bpf_hdr、bpf_stat和NetType八个数据结构,其中PACKET和ADAPTER是Windows环境下捕获驱动器特有的,其他的数据结构与Libpcap中用到的数据结构相同。第5章 直接网络编程 PACKET结构
35、 PACKET结构包含以下字段:struct PACKETOVERLAPPEDOverLapped;PVOIDBuffer;UINTLength;PVOIDNext;UINTulBytesReceived;BOOLEANbIoComplete; 第5章 直接网络编程 l OverLapped用来处理对驱动器的异步调用。它包含一个hEvent字段,在使用异步方式接收数据包时,通过函数ResetEvent( )进行复位(清0)。当操作结束后,驱动器对这个event进行置位(置1),通知应用程序操作已经结束。lBuffer是一个指向包含数据包数据的缓存区的指针。lLength表示缓存区的大小。lul
36、BytesReceived表示缓存区中包含有效数据部分的长度。lbIoComplete字段指示异步调用后数据包中是否包含有效数据。 第5章 直接网络编程 ADAPTER结构这个结构中包含的数据是对网络接口的描述。Struct ADAPTERHANDLEhFile;TCHARSymbolicLink;lhFile是指向驱动器句柄(handle)的指针。为了直接与驱动器进行通信,应用进程必须得到这个句柄。lSymbolicLink包含当前操作的网络接口名的字符串。 第5章 直接网络编程 PACKET_OID_DATA结构这个结构通过OID查询和设置操作来与网络接口进行通信。Struct PACKE
37、T_OID_DATAULONGOid;ULONGLength;UCHARData; 第5章 直接网络编程 l Oid是一个数字标识符,指明对网络接口进行设置/查询的PacketRequest函数的类型,可以用来取得网络接口错误计数器的状态、网络接口的MAC地址、接口上定义的多播组(multicast groups)等。它的可能的值定义在ntddndis.h文件中。l Length字段表明Data字段的长度。l Data字段包含发往网络接口或者从接口来的数据。 第5章 直接网络编程 bpf_insn结构这个结构体包含了一个BPF注册机的单指令。它传递过滤器程序给适配器。 Struct bpf_i
38、nsnUSHORTcode;UCHARjt;UCHARjf;intk;code字段表明命令类型和地址模式。条件转移指令使用jt和jf字段,而k字段是一个可以用于多种目的的通用字段。 第5章 直接网络编程 bpf_program结构这个结构指向一个BPF过滤器程序,由PacketSetBPF函数来设置驱动器的过滤器。Struct bpf_programUINTbf_len;struct bpf_insn*bf_insns;l bf_len字段表明程序的长度;l bf_insns字段是指向程序中第一条指令的指针;第5章 直接网络编程 bpf_hdr结构这个结构定义了由驱动器使用的包头格式。它与UN
39、IX环境中的BPF相同。Struct bpf_hdrstruct timevalbh_tstamp;UINTbh_caplen;UINTbh_datalen;USHORTbh_hdrlen; 第5章 直接网络编程 l bh_tstamp字段保存捕获数据包的时戳。时戳采用TimeVal结构存储,TimeVal结构有两个字段:tv_sec:标准UNIX时间格式的捕获日期(从1970年1月1日至今的秒数);tv_usec:捕获时间的毫秒数。l bh_caplen字段表明已捕获部分的长度。l bh_datalen字段是数据包的原始长度。l bh_hdrlen字段是包裹数据包的包头的长度,这个字段只是用
40、在UNIX环境的BPF中,在Windows环境中,这个字段是一个固定值,也就是bpf_hdr结构的长度。 第5章 直接网络编程 bpf_stat结构这个结构由驱动器来返回捕获的统计值。Struct bpf_statUINTbs_recv;UINTbs_drop;l bs_recv字段表明已经从网络接口收到的数据包的数量。l bs_drop字段表明丢弃数据包的数量。一般来说,当驱动器的缓存区装满后,新来的数据包就会被丢弃,上面的变量并没有把由网络接口直接丢弃的数据包计算在内。 第5章 直接网络编程 NetType结构 这个结构由PacketGetNetType函数来取得网络接口的信息。 Stru
41、ct NetType UINTLinkType; UINTLinkSpeed; lLinktype字段指明当前网络接口的类型;lLinkspeed字段指明网络的速率(bps或b/s)。 第5章 直接网络编程 2. 2. 函数函数Packet.dll提供了一个函数集,可以用来发送和接收数据包、查询和设置网络适配器参数、打开和关闭网络适配器、动态分配PACKET结构、设置BPF过滤器、改变驱动器缓存区的大小和返回捕获统计数据等。包含的函数如下: ULONG PacketGetAdapterNames(PTSTR pStr, PULONG BufferSize)通常这是与驱动器通信的第一个函数,它用
42、来返回系统中安装的网络接口名,并保存在用户分配的缓存区pStr中。BufferSize是缓存区的长度。 注意:函数的返回值是通过查询操作系统的注册表且执行OID(客体标识符)系统调用而得到的,因此,结果的格式在Windows NT/2000和Windows 9x中是不同的。 Windows 9x使用ASCII码存储字符串,而 Windows NT使用UNICODE字符集。第5章 直接网络编程 LPADAPTER PacketOpenAdapter(LPTSTR AdapterName)这个函数用来接收要打开的网络接口的名称,并返回已正确初始化的网络接口对象。网络接口的名称可以通过调用函数Pac
43、ketGetAdapterNames得到。 VOID PacketCloseAdapter(LPADAPTER lpAdapter)这个函数用来释放网络接口结构lpAdapter,且关闭它指向的网络接口。 LPPACKET PacketAllocatePacket(void)此函数用来分配一个PACKET结构,并返回一个指向它的指针。 第5章 直接网络编程 VOID PacketInitPacket(LPPACKET lpPacket, PVOID Buffer, UINT Length)此函数用来初始化一个PACKET结构。函数中包含三个输入参数:指向被初始化的结构的指针、指向用户分配的缓存
44、区的指针(该缓存区将包含packet数据)和缓存区的长度。注意:与PACKET 结构相关的缓存区的长度直接影响着程序的捕获性能。缓存区存储来自捕获驱动器的数据包,驱动器可以在一次系统调用中(使用函数PacketReceivePacket)返回多个数据包,返回数据包的数量直接与PACKET结构中缓存区的大小相关,因此,设置较大的缓存区能够减少系统调用的次数,提高系统的捕获速度。 第5章 直接网络编程 VOID PacketFreePacket(LPPACKET lpPacket)此函数用来释放由指针lpPacket指向的PACKET结构。注意:PACKET结构中的Buffer缓存区不能由此函数释
45、放,必须由程序员自己来释放。 BOOLEANPacketReceivePacket(LPADAPTER AdapterObject, LPPACKETlpPacket, BOOLEANSync ) 第5章 直接网络编程 此函数用来进行网络数据包捕获。它包含以下输入参数:l AdapterObject:指向网络接口的指针,指明用来捕获数据包的网络接口;l lpPacket:指向PACKET结构的指针,此结构用来保存数据包;l Sync:标志位,指明采取同步或异步操作方式。注意:建议采用同步方式,异步方式可能会存在某些问题。通过此函数获得的数据包的数量一般来说是未知的,它与实际存储在驱动器缓存区中
46、的数据包的数量、数据包的大小和缓存区的大小有关。图5.3显示了驱动器交给应用程序的数据包的格式。 第5章 直接网络编程 图5.3 数据包的编码格式 bpf_hdrdatapaddingbpf_hdrdatapadding第5章 直接网络编程 数据包存储在结构lpPacket PACKET中,每个数据包包含一个头。头是bpf_hdr结构,包含数据包的长度和时戳。在数据之后是填充(padding)字段,用来与字边界对齐。 BOOLEAN PacketWaitPacket(LPADAPTER AdapterObject, LPPACKET lpPacket )此函数用来验证驱动器的I/O操作是否完成
47、。如果操作没有结束,此函数将被阻塞。返回值为TRUE表明操作已成功完成,返回值为FALSE说明操作没有完成,通过SDK的GetLast- Error 函数可以得到出错码(error code)。 第5章 直接网络编程 BOOLEAN PacketSendPacket(LPADAPTER AdapterObject, LPPACKET pPacket, BOOLEAN Sync ) 此函数用来发送一个原始数据包到网络中。因为原始数据包是被直接发送到网络中的,所以程序员必须自己构造数据包的各种包头,如TCP头和IP头等。用户不用构造bpf_hdr头,数据包的CRC校验由网络接口自动计算并添加到数据
48、帧中。 第5章 直接网络编程 此函数的语法规则与PacketReceivePacket函数类似,它的行为与函数PacketSetNumWrites有关,可以多次发送同一个数据包。如果数值是1,则每次发送一个数据包到网络中,如果大于1,例如1000,构造的原始数据包则被发送到网络中1000次。这一特性可以用来产生大量的网络流量,测试网络、路由器、服务器的性能。不过,这个功能目前只适用于Windows NT/2000系统,在Windows 9x系统中则是在用户模式下的Packet.dll中进行模拟,其发送速度比在Windows NT/2000中要慢得多。 第5章 直接网络编程 BOOLEAN Pa
49、cketResetAdapter(LPADAPTER AdapterObject) 此函数用来复位网络接口。如果函数调用成功,则返回TRUE。 BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject, ULONG Filter)此函数用来设置数据包的硬件过滤器(hardware filter)。过滤器的一些常数定义在文件ntddndis.h中。函数的输入参数包含设置过滤器的网络接口和过滤器的标识符。操作成功则返回TRUE。 第5章 直接网络编程 下面是一些最常用的过滤器:lNDIS_PACKET_TYPE_PROMISCUOUS:设置混合模式,网络接
50、口接收网络中所有的数据包。lNDIS_PACKET_TYPE_DIRECTED:只接收发往本网络接口的数据包。lNDIS_PACKET_TYPE_BROADCAST:只接收网络中的广播数据包。lNDIS_PACKET_TYPE_MULTICAST:只接收本网络接口所属的多播(multicast)组的数据包。lNDIS_PACKET_TYPE_ALL_MULTICAST:接收所有的多播(multicast)数据包。第5章 直接网络编程 BOOLEAN PacketRequest( LPADAPTER AdapterObject, BOOLEAN Set, PPACKET_OID_DATA Oid
51、Data ) 此函数用来对网络接口进行查询/设置(query/set)操作。第一个参数指明进行操作的网络接口;第二个参数定义是否进行设置(set1)或者查询(set0);第三个参数是一个指向PACKET_OID_DATA结构的指针。如果函数正确完成,则返回TRUE。第5章 直接网络编程 注意:不是所有的网络接口都支持这些查询/设置操作。对于有一些强制OID函数,所有网络接口都支持,还有一些功能函数不是所有网络接口都支持(在DDK(Device Development Kit ,设备驱动程序开发包)中可以看到哪些是强制性的函数)。 第5章 直接网络编程 BOOLEAN PacketSetBuff
52、(LPADAPTER AdapterObject, int dim )此函数用来重新设置驱动器的缓存区大小。函数的第一个参数AdapterObject指明驱动器操作的网络接口;第二个参数dim是缓存区的大小(bytes)。如果函数设置成功,则返回TRUE,如果没有足够的存储空间来分配,则返回FALSE。当缓存区大小重新设置后,保存在旧缓存区中的数据将被丢弃,其中存储的数据包会丢失。 第5章 直接网络编程 BOOLEAN PacketSetBpf( LPADAPTER AdapterObject, struct bpf_program *fp )此函数用来给参数AdapterObject指定的网
53、络接口设置一个BPF过滤器。过滤器是驱动器用来检查每个数据包的指令集,它由fp指针指出。如果设置成功,函数返回TRUE,否则返回FALSE。驱动器在接受每一个新的过滤器之前,都要进行检查,防止错误的过滤程序使系统崩溃。过滤器可以用libpcap中的pcap_compile函数自动创建。 第5章 直接网络编程 BOOLEAN PacketGetStats( LPADAPTER AdapterObject, struct bpf_stat *s )通过调用这个函数,程序员可以知道驱动器中两个内部变量的值:参数AdapterObject所指向的网络接口已经收到的数据包的数量和网络接口已经收到但被内核
54、丢弃的数据包的数量。数据包被丢弃可能是因为用户进程没有做好接收的准备,或者是驱动器的内核缓存区已经装满。驱动器把这两个值拷贝到用户进程提供的结构bpf_stat中。这两个值对了解网络的状况和用户捕获程序的行为很有帮助,它们还有助于调整捕获栈的性能和选择合适的缓存区大小。 第5章 直接网络编程 如果bs_recv变量的值很大,则表明网络中的数据流量很大。如果应用程序并不需要所有网络中的数据包,在这种情况下,最好设置一个带选择性的过滤器,尽量减少应用程序要处理的数据包的数量。过滤器工作在内核模式下,一个良好的过滤器可以提高应用程序的性能并减轻系统的负荷。 第5章 直接网络编程 如果变量bs_dro
55、p的值大于零,则表明应用进程的速度太慢 , 它 正 在 丢 失 数 据 包 。 程 序 员 可 以 试 着 通 过 函 数PacketSetBuff来设置一个更大一些的内核缓存区。一个大小合适的内核缓存区通常可以显著地减少数据包的丢失率。另一个解决方法是通过增加PACKET结构中用户缓存区的大小来提 高 捕 获 进 程 的 速 度 , 这 可 以 通 过 调 用 函 数PacketReceivePacket来做到。采用这种方法可以减少系统调用的次数,从而提高捕获速度。如果应用进程仍然在丢失数据包,则应用程序可能需要重写或者进行优化。 第5章 直接网络编程 BOOLEAN PacketGetNe
56、tType(LPADAPTER AdapterObject, NetType *type)此函数用来返回参数AdapterObject 所指的网络接口的类型,返回结果存储在一个NetType结构中。链路类型字段(Link Type)包括以下值:l NdisMedium802_3:以太网 (802.3);l NdisMedium802_5:令牌环网(802.5);l NdisMediumFddi:光纤分布数据接口,媒介是光纤的令牌环网网;l NdisMediumWan:广域网;l NdisMediumLocalTalk: APPLE公司开发的局域网;l NdisMediumDix:Digital
57、、Inter、Xerox合作;l NdisMediumAtm:基于异步传输模式的宽带骨干网; 第5章 直接网络编程 lNdisMediumArcnetRaw: Datapoint公司的局域网 (raw);lNdisMediumArcnet878_2:Datapoint公司的局域网 (878.2);lNdisMediumWirelessWan:各种类型媒介的无线广域网。LinkSpeed字段表明网络的速率(bps)。如果操作成功,则函数返回TRUE。 第5章 直接网络编程 BOOLEAN PacketSetReadTimeout( LPADAPTER AdapterObject , int ti
58、meout )此函数用来设置网络接口的读超时值。参数timeout是新的超时值,单位是毫秒(ms),为0则表明没有超时值,如果没有数据包到达,则读操作不返回。 第5章 直接网络编程 BOOLEAN PacketSetMode( LPADAPTER AdapterObject, int mode )此函数设置参数AdapterObject指定的网络接口的工作模式。工作模式有以下两种选择:l 模式0:标准捕获模式,这种模式在调用函数PacketOpen Adapter后被缺省地设置。第5章 直接网络编程 l 模式1:统计模式,用来实时统计网络流量。在这种模式下,驱动器并不捕获数据包,而只是计算满足
59、用户定义的BPF过滤器的数据包的数量和大小,应用程序可以在一定的时间间隔内通过调用函数PacketReceivePacket来取得这些数值。缺省的时间间隔是1秒,但用户可以通过函数PacketSetReadTimeout来进行设置。这个时间值保存在结构bpf_hdr中,它可以精确到毫秒级。 第5章 直接网络编程 应用程序如果采用模式1,它要进行如下操作:(1) 打开网络接口;(2) 用函数PacketSetMode把网络接口设置成模式1;(3) 用函数PacketSetBpf 设置用于计数的过滤器;(4) 用函数PacketSetReadTimeout设置正确的时间间隔;(5) 用函数Pack
60、etReceivePacket接收统计结果。此函数返回在上一个时间间隔内满足过滤条件的数据包的数量和大小(Byte)。第5章 直接网络编程 注意:如果网络接口工作在模式1下,则不需要内核缓存区。因为计算数据包的统计值不需要存储数据包的数据,所以可以用函数PacketSetBuff 把内核缓存区的大小设置成0。BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject, int nwrites )此函数用来设置对网络接口(AdapterObject)的一次写操作由网络接口重复的次数(nwrites)。 第5章 直接网络编程 3. 3. 编写使用编写使用Packet.dllPacket.dll的应用
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 福建公务员面试模拟58
- 河北行政职业能力模拟28
- 初中学生心理健康教育讲座讲
- 苏教一年级《心理健康》教案(完整版)
- 地方公务员广东申论201
- 河南申论模拟101
- 云南行政职业能力模拟41
- 2024届中考数学一次方程(组)天天练(8)及答案
- 北师大版数学七年级上册 第4章 第41课时 《基本平面图形》回顾与思考习题课件
- 二手货车买卖合同2024年
- 中耳胆脂瘤的护理查房
- 高空作业安全防护措施与操作规程
- 财务科廉洁风险点及防控措施【15篇】
- 公路防汛安全培训
- 全国七岁以下儿童生长标准
- 物联网的数据传输技术
- 劳动与社会保障专业大学生职业生涯规划书
- 目的论的角度下浅析中国传统动画电影汉译英字幕翻译-以《白蛇缘起》为例
- 2023-2024学年广西南宁十四中八年级(上)期中数学试卷
- 2022年内蒙古事业单位联考C类试题及答案解析
- 【月考】数学六年级(上)全优好卷第二次月考卷b-北师大版(含答案)
评论
0/150
提交评论