收藏 分销(赏)

第5章直接网络编程.ppt

上传人:xrp****65 文档编号:13186213 上传时间:2026-01-31 格式:PPT 页数:54 大小:300KB 下载积分:10 金币
下载 相关 举报
第5章直接网络编程.ppt_第1页
第1页 / 共54页
第5章直接网络编程.ppt_第2页
第2页 / 共54页


点击查看更多>>
资源描述
*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,Windows,网络程序设计,第,5,章 直接网络编程,第,4,章 网络基本应用,5.1,原始套接字编程,5.2,基于,Winpcap,的网络数据包捕获技术,5.3,基于,Libnet,的网络数据包构造技术,习题与思考题,5.1,原始套接字编程,5.1.1,概念,利用原始套接字可直接访问网络协议数据,可以对底层的传输协议加以控制。,原始套接字,(raw socket),是使用,SOCK_RAW,这个套接字类型来创建的。,WinSock 2.2,提供了对它的支持。,创建原始套接字可用,Socket,或,WSASocket,函数。在套接字的创建过程中,必须自行设定,SOCK_RAW,标志。,例:原始套接字的创建:,SOCKET s;,s=,socket(AF_INET,SOCK_RAW,IPPROTO_ICMP,);,if(s,=INVALID_SOCKET),/,创建套接字失败,IGMP,,设置,IPPROTO_IGMP,UDP,,设置,IPPROTO_UDP,IP,,设置,IPPROTO_IP,原始,IP,,设置,IPPROTO_RAW,ICMP,,设置,IPPROTO_ICMP,Windows 98/NT,Windows 2000/XP,原始套接字的使用:,在,WindowsNT/2000/XP,上,只有“管理员”组的成员,才有权创建原始套接字。,5.1.2 ICMP,实现,Ping,程序的实现方法是主机向远程计算机发出,ICMP,回应请求以后,远程计算机会处理这个请求,然后生成一条回应应答消息,再通过网络传回给发送主机;假如由于某些原因,不能抵达目标主机,就会生成对应的,ICMP,错误消息,(,比如“目标主机不可到达”,),,由那个路径上某处的一个路由器返回。,Ping,示例在程序中采取如下步骤:,(1),创建类型为,SOCK_RAW,的一个套接字,同时设定协议,IPPROTO_ICMP,。,(2),创建并初始化,ICMP,头。,(3),调用,sendto,或,WSASendto,,将,ICMP,请求发给远程主机。,(4),调用,recvfrom,或,WSARecvfrom,,以接收任何,ICMP,响应。,ICMP,协议首部信息见教材,17,页,/,ping.cpp,文件,#include,#include,#include,#include Ws2tcpip.h,#,pragma,comment(lib,WS2_32)/,链接到,WS2_32.lib,typedef,struct,icmp_hdr,unsigned char,icmp_type,;/,消息类型,unsigned char,icmp_code,;/,代码,unsigned short,icmp_checksum,;/,校验和,/,下面是回显头,unsigned short,icmp_id,;/,用来惟一标识此请求的,ID,号,通常设置为进程,ID,unsigned short,icmp_sequence,;/,序列号,unsigned long,icmp_timestamp,;/,时间戳,ICMP_HDR,*PICMP_HDR;,USHORT,checksum(USHORT,*buff,int,size),unsigned long,cksum,=0;,while(size,1),cksum,+=*buff+;,size-=,sizeof(USHORT,);,/,是奇数,if(size,),cksum,+=*(UCHAR*)buff;,/,将,32,位的,chsum,高,16,位和低,16,位相加,然后取反,cksum,=(,cksum,16)+(,cksum,cksum,+=(,cksum,16);,return(,USHORT)(cksum,);,BOOL,SetTimeout(SOCKET,s,int,nTime,BOOL,bRecv,),int,ret=,setsockopt(s,SOL_SOCKET,bRecv,?SO_RCVTIMEO:SO_SNDTIMEO,(char*)&,nTime,sizeof(nTime,);,return ret!=SOCKET_ERROR;,int,main(),/,目的,IP,地址,即要,Ping,的,IP,地址,char,szDestIp,=127.0.0.1;/127.0.0.1,/,初始化,WS2_32.dll,WSADATA,wsaData,;,WORD,sockVersion,=MAKEWORD(2,2);,if(WSAStartup(sockVersion,&,wsaData,)!=0),exit(0);,/,创建原始套节字,SOCKET,sRaw,=,socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);,/,设置接收超时,SetTimeout(sRaw,1000,TRUE);,/,设置目的地址,sockaddr_in,dest,;,dest.sin_family,=AF_INET;,dest.sin_port,=htons(0);,dest.sin_addr.S_un.S_addr,=,inet_addr(szDestIp,);,/,创建,ICMP,封包,char,buffsizeof(ICMP_HDR,)+32;,ICMP_HDR*,pIcmp,=(ICMP_HDR*)buff;,/,填写,ICMP,封包数据,pIcmp,-,icmp_type,=8;/,请求一个,ICMP,回显,pIcmp,-,icmp_code,=0;,pIcmp,-,icmp_id,=(,USHORT)GetCurrentProcessId,();,pIcmp,-,icmp_checksum,=0;,pIcmp,-,icmp_sequence,=0;,/,填充数据部分,可以为任意,memset(&buffsizeof(ICMP_HDR,),E,32);,/,开始发送和接收,ICMP,封包,USHORT,nSeq,=0;,char recvBuf1024;,SOCKADDR_IN from;,int,nLen,=,sizeof(from,);,while(TRUE,),static,int,nCount,=0;,int,nRet,;,if(nCount,+=4),break;,pIcmp,-,icmp_checksum,=0;,pIcmp,-,icmp_timestamp,=,GetTickCount,();,pIcmp,-,icmp_sequence,=,nSeq,+;,pIcmp,-,icmp_checksum,=,checksum(USHORT,*)buff,sizeof(ICMP_HDR,)+32);,nRet,=,sendto(sRaw,buff,sizeof(ICMP_HDR,)+32,0,(SOCKADDR*)&,dest,sizeof(dest,);,if(nRet,=SOCKET_ERROR),printf,(,sendto,()failed:%d n,WSAGetLastError,();,return-1;,nRet,=,recvfrom(sRaw,recvBuf,1024,0,(,sockaddr,*)&from,&,nLen,);,if(nRet,=SOCKET_ERROR),if(WSAGetLastError,()=WSAETIMEDOUT),printf,(timed outn);,continue;,printf,(,recvfrom,()failed:%,dn,WSAGetLastError,();,return-1;,/,下面开始解析接收到的,ICMP,封包,int,nTick,=,GetTickCount,();,/,if(nRet,sizeof(IPHeader,)+,sizeof(ICMP_HDR,),if(nRet,icmp_type,!=0)/,回显,printf,(,nonecho,type%d,recvd,n,pRecvIcmp,-,icmp_type,);,return-1;,if(pRecvIcmp,-,icmp_id,!=,GetCurrentProcessId,(),printf,(someone elses packet!n);,return-1;,printf,(%d bytes from%s:,nRet,inet_ntoa(from.sin_addr,);,printf,(,icmp_seq,=%d.,pRecvIcmp,-,icmp_sequence,);,printf,(time:%d ms,nTick,-,pRecvIcmp,-,icmp_timestamp,);,printf,(n);,Sleep(1000);,WSACleanup,();,return 0;,5.1.3,Tracert,(,路由追踪,),使用目的:侦测出为抵达网络内任何一个指定的主机,中途需经过哪些路由器,以及它们的,IP,地址是什么。,设计原理是:向目的地发送一个数据包,并重复递增,IP,的“存活时间”,(TTL),值。只需将返回的每一条,ICMP,消息都收集下来,便能为中途经过的路由器,IP,地址勾勒出一个清晰的轮廓,直到最终的目标主机。,5.1.4 IP_HDRINCL,的使用,原始套接字存在的一项限制是只能对已经定义好的协议,(,如,IGMP,和,ICMP,等,),进行操作,而不能用,IPPROTO_UDP,、,IPPROTO_TCP,来创建一个新的原始套接字,也不能对,UDP,头、,TCP,头进行操作。,要想对,IP,头、,TCP,头、,UDP,头或封装在,IP,内的其他任何协议进行操作,必须在使用原始套接字的同时使用,IP_HDRINCL,选项。利用该套接字选项,用户可以自行构建,IP,等任何协议头。,5.2,基于,Winpcap,的网络数据包捕获技术,捕获数据包的需求:分析网络中的数据流,查找网络故障或安全问题。,包捕获方法:,使用专用硬件,利用普通,NIC,(混杂模式),网卡的接收模式:,广播方式:能够接收网络中的广播信息,组播方式:能够接收组播数据,直接方式:只有目的网卡才能接收该数据,混杂模式:能够接收通过它的一切数据,而不管该数据是否是传给它的。,5.2.1,Winpcap,简介,Winpcap,是一个基于,Win32,平台的,用于捕获网络数据包并进行分析的开源库,,它来源于,California,大学的,Berkeley Packet,Filter(BPF,),。,Winpcap,提供捕获原语捕获网络中传输的各种数据包,并传输到调用它们的应用程序中。,Winpcap,可以用于网络分析、网络故障诊断、网络安全和监视等网络工具中,所提供的功能主要包括以下四个方面:,捕获网络原始数据包;,根据用户定义的规则过滤数据包;,发送用户构造的数据包到网络中;,统计网络流量。,什么程序在使用,WinPcap,一些基于,WinPcap,的典型应用有:,网络与协议分析器,(network and protocol analyzers),网络监视器,(network monitors),网络流量记录器,(traffic loggers),网络流量发生器,(traffic generators),用户级网桥及路由,(user-level bridges and routers),网络入侵检测系统,(network intrusion detection systems(NIDS),网络扫描器,(network scanners),安全工具,(security tools),什么是,WinPcap,做不到的,WinPcap,能独立地通过主机协议发送和接受数据,如同,TCP-IP,。这就意味着,WinPcap,不能阻止、过滤或操纵同一机器上的其他应用程序的通讯:它仅仅能简单地,监视,在网络上传输的数据包。所以,它不能提供类似网络流量控制、服务质量调度和个人防火墙之类的支持。,Winpcap,是在,Win 32,系统环境中通过计算机的网络接口来捕获网络数据的一种软件框架,它通过提供一些高层,API,函数来满足用户的需求。,Winpcap,由数据包捕获驱动器、底层动态链接库,(,Packet.dll,),和高层静态连接库,(,wpcap.lib,),三部分组成。,5.2.2,数据包捕获驱动器结构,Windows,下的数据包捕获驱动程序提供了一个高性能、灵活且与,UNIX,系统环境中的,BPF,兼容的网络工具。它的主要功能如下:,捕获网络中原始的网络流量,并交由高层应用程序进行处理。,过滤收到的数据包。,在应用进程忙碌时,把数据包保存在缓存区中。,给收到的数据包打包,并加上时戳、包长和偏移量。,构造数据包,并注入到网络中。,统计网络流量。,1,、驱动器结构,图中,向上的箭头表示从网络到应用程序的数据流,在内核缓存区与应用程序之间的箭头表示一次读系统调用可以传送多个数据包。向下的箭头表示从应用程序到网络之间传送的数据包。,2.,数据包过滤,(filter),处理,需要过滤数据包的应用程序可以建立一个标准的,BPF,的过滤程序,(,调用函数,pcap_compile,),,并把它传送到驱动程序,此后,过滤进程将在系统内核中进行数据包过滤。,3.,读和缓存处理,当应用程序读取网络数据包时,它向,NDIS,数据包捕获驱动程序发出一个读,(read),命令。,4.,写数据包处理,数据包捕获驱动程序可以让程序员自己构造数据包并发送到网络中去。为了发送数据包,应用进程执行一条写,(write),系统调用,把数据包发送到网络中。,5.,统计模式,(Statistics mode),统计模式,(Statistics mode,,模式,1),可以用来取得网络的各种统计数据。如网络的利用率、广播级别,或者网络中邮件,(mail),数据包的数量、每秒,web,请求的数量等。,5.2.3,数据包捕获驱动程序,API,的使用,Winpcap,提供了一个动态链接库,Packet.dll,,它为用户应用程序提供了与数据包捕获驱动器之间的接口。,如果要编写一个网络数据包捕获的应用程序,建议使用数据包捕获函数库,(,wpcap.lib,),,而不采用本节描述的,API,函数。,编写使用,Packet.dll,的应用程序,安装,Winpcap,网络驱动程序,,在每个使用,dll,导出函数的程序源文件中包含头文件,packet32.h,。,将,packet.lib,包含到工程中。,示例程序:包捕获,testapp,;,网络流量产生程序,tg,5.2.4,数据包捕获函数库的使用,1.,Wpcap,函数介绍,Win 32,环境中的,Wpcap,是,UNIX,版本的,Libpcap,的一个超集,(superset),,它在,Win 32,环境中增加了统计模式和其他几个函数。,统计模式,(statistics mode),的使用方法,(1),使用函数,pcap_open_live,打开网络接口。,(2),使用函数,pcap_setmode,把网络接口设置成统计模式。,(3),使用函数,pcap_setfilter,和,pcap_loop,初始化网络接口。此时,每当函数,pcap_open_live,中定义超时值到达后,捕获过程的回调函数就会被调用,这个函数通过它的第三个参数接收一个缓存区指针,这个缓存区包含两个,64 bit,的计数器,第一个计数器保存满足过滤条件的数据包的数量,第二个计数器保存数据包的大小,(,单位是,Byte),。,过滤器的语法规则,过滤器是一个包含过滤规则的,ASCII,字符串表达式,,pcap_compile,(),得到这个表达式后,将把它转换成内核过滤器使用的一个程序。,过滤表达式用来选择处理哪些网络数据包。表达式包含一个或多个原语,原语通常由一个标识符,id,和它前面的一个或多个限定词组成,如,host 192.168.0.1,,其中,host,是限定词,,192.168.0.1,是标识符。,2.,使用,Winpcap,函数库,wpcap.lib,的步骤及实例,(1),下载并安装,Winpcap,网络驱动程序。,www.winpcap.org/install/bin/WinPcap_4_0.exe,(2),下载,WinPcap,的开发包并解压。,www.winpcap.org/install/bin/WpdPack_4_0.zip,(3),在,VC 6.0,中,Tool-Options-Directory,分别把解压包里的,inlude,和,library,加进去。,(4),设置,Visual C+,编程环境链接器,(linker),的选项,(options),,使其包含,wpcap.lib,、,Packet.lib,(、,wsock32.lib,)函数库文件。,(5),在每个使用,Winpcap,函数的应用程序源文件的开始处包含文件,pcap.h,。,Winpcap,编程举例:,1),取得网络设备列表,基于,Winpcap,应用程序要做的第一件事就是要取得网络设备列表。,Libpcap,提供函数,pcap_findalldevs,(),来取得网络设备列表,此函数返回一个,pcap_if,结构的链表,链表中每个节点包含一个网络设备的信息。字段,name,和,description,是网络设备的名称和描述。,2),取得网络设备信息,函数,pcap_findalldevs,(),返回的每一个,pcap_if,结构中,都包含有一列,pcap_addr,结构。在结构,pcap_addr,中有以下信息:,*网络接口的地址列表。,*网络掩码列表,(,每一个网络掩码与一个地址相对应,),。,*广播地址列表,(,每一个广播地址与一个地址相对应,),。,*目的地址列表。,3),打开网络适配器和捕获数据包,用来打开捕获设备的函数是,pcap_open_live,(),。使用回调函数和函数,pcap_loop(adhandle,0,packet_handler,NULL),实现捕获数据包。,4),不用回调函数来捕获数据包,这个示例程序捕获数据包采用函数,pcap_read_ex,(),,而不是函数,pcap_loop,(),。,5),过滤网络数据包,用于过滤数据包的函数是,pcap_compile,(),和,pcap_setfilter,(),。函数,pcap_compile,(),编译过滤器,它把一个高层的布尔表达式编译生成一个底层过滤器二进制代码。函数,pcap_setfilter,(),用来为捕获应用程序设置过滤器。,6),解释网络数据包,上面,捕获到的数据包是原始的链路层数据帧,,数据包解释部分的主要工作是对捕获的原始数据包进行处理,把原始的链路层数据帧中包含的信息提取出来。然后对数据包进行分解,进一步提取高层协议信息,(,如,TCP,、,UDP,、,ARP,、,RARP,、,ICMP,等,),。,7),处理捕获文件,(dump files),Winpcap,提供了许多函数用来把网络数据包保存在文件中并进行读取。文件的格式很简单,包含捕获数据包的二进制形式。,把数据包写到文件中:打开网络接口后,调用了函数,pcap_dump_open,(),打开一个文件,并使文件与打开的网络接口相关连。在回调函数,packet_handler,(),中,使用函数,pcap_dump,(),把数据包写到文件中。,从文件中读取数据包:用函数,pcap_open_offline,(),打开文件,然后用,pcap_loop,(),来处理数据包。,解释网络数据包,8),发送数据包,用函数,pcap_sendpacket,发送单个数据包,发送队列,(send queue),是一个大的容器,其中包含许多将要发送的数据包。调用函数,pcap_sendqueue_alloc,(),可以创建一个发送队列,定义其大小。此后,调用函数,pcap_sendqueue_queue,(),来把数据包存储在队列中。如果要发送数据包,则通过,pcap_sendqueue_transmit,(),函数来发送。发送结束后,可以通过函数,pcap_sendqueue_destroy,(),来释放队列占用的缓存区。,9),取得网络流量的统计信息,取得网络流量的统计信息,应打开网络接口,并用函数,pcap_setmode,(),设置成统计模式。,5.3,基于,Libnet,的网络数据包构造技术,5.3.1,Libnet,简介,Libnet,是一个,C,函数库,它提供跨平台的网络数据包构造和发送接口。,Libnet,的主要目的是用来构造和注入网络数据包,而不是捕获网络数据包。,Libnet,的出现主要是基于以下两个原因:,(1),为网络程序员提供一个简单的编程接口,使程序员能把主要精力集中起来解决问题,而不用考虑底层网络细节。,(2),Libnet,是一个与,Libpcap,类似的数据包注入器,可以用来编写有关网络测试、网络故障诊断和网络安全等方面的应用程序和工具。,Libnet,的工作过程,Libnet,与,Libpcap,的关系,程序中使用,LibnetNT,的方法:,第一种是在程序编译时直接进行链接,这种方法需要把,LibnetNT.lib,文件添加到程序中,还必须把,Libnet.h,文件包含在程序中。,第二种方法是直接使用,LibnetNT.dll,,通过,LoadLibrary,(),和,GetProcAddress,(),函数来动态加载和调用,DLL,中封装的函数,这样不用在程序编译时链接,LibnetNT.lib,库文件。,5.3.2,Libnet,的使用方法,1.,操作顺序,Libnet,提供两种接口,一种是在,IP,层构造数据包,一种是在链路层构造数据包。链路层接口在数据链路层构造数据包,(,链路层帧,),,而,IP,层接口在网络层构造数据包,(IP,包,),。链路层接口功能更为强大,但程序比较复杂,编码更多,如果要构造,ARP/RARP/,以太网帧,则只能采用链路层接口。,IP,层接口相对要简单一些。,图,5.7 IP,层接口与链路层接口比较,要构造数据包并发送到网络中,一个标准的处理过程通常包括以下五个步骤:,(1),初始化存储空间;,(2),初始化网络;,(3),构造数据包;,(4),计算数据包校验和;,(5),把数据包发送到网络中。,IP,层接口与链路层接口函数集,原始,IP,层接口,链路层接口,libnet_init_packet,libnet_open_raw_sock,libnet_build_ip,libnet_build_icmp,libnet_do_checksum,libnet_write_ip,libnet_init_packet,libnet_open_link_interface,libnet_build_ethernet,libnet_build_ip,libnet_build_icmp,libnet_do_checksum(IP,头校验和,),libnet_do_checksum,(,传输层校验和,),libnet_write_link_layer,2.,存储空间分配和初始化,通过调用函数,libnet_init_packet,(),来完成。,程序员事先必须知道将要构造数据包的大小。,程序结束前,调用函数,libnet_destroy_packet,(),释放存储空间。,分配存储空间的另一种方法是通过,arena,接口,arena,是一个可以一次分配多块存储空间的缓存池。,Libnet,的,arena,接口在需要为不同大小数据包分配存储空间时非常有用。,通过函数,libnet_init_packet_arena,(),初始化存储空间,通过函数,libnet_next_packet_from,_arena(),来取得每个数据包的存储区域。,存储空间使用结束后,调用函数,libnet_destroy,_,packet_arena,(),释放存储空间。,3.,网络初始化,在,IP,层接口中,可以通过调用函数,libnet_open_raw_sock,(),来打开接口,函数返回一个原始套接字,(raw socket),,套接字设置成,IP_HDRINCL,。,在链路层接口中,通过调用函数,libnet_open_link_interface,(),打开网络接口。,4.,构造数据包,在构造数据包时,对每一个协议层都要调用相应的构造函数。在,IP,层接口中,需要调用函数,libnet_build_ip,(),和,libnet_build_tcp,(),。在链路层接口中,还需要调用函数,libnet,_,build_ethernet,(),。,这些数据包构造函数的调用顺序并不重要,重要的是给这些函数分配正确的存储区域。,图,5.8 TCP,数据包的构造过程,5.,数据包校验和,(Checksum),对原始,IP,层接口而言,只需要计算传输层校验和,系统内核会自动处理,IP,层的校验和。如果采用链路层接口,,IP,层的校验和必须由用户来计算。,计算校验和可以调用函数,libnet_do_checksum,(),。,6.,发送数据包,如果程序中使用的是,IP,层接口,应使用函数,libnet_write_ip,(),来发送数据包;,如果采用链路层接口,则使用函数,libnet_write_link_layer,(),来发送数据包。,5.3.3,Libnet,函数,1.,操作存储空间的函数,2.,地址解析函数,3.,数据包发送支持函数,4.,数据包构造函数,5.,支持函数,6,符号常量,5.3.4,应用程序示例,1.,示例程序一,此程序使用原始套接字,API,函数构造一个不带负载的,TCP,数据包,并把构造好的数据包发送到网络中。,2.,示例程序二,此示例程序显示如何使用,Libnet,的链路层接口,通过链路层接口,发送一个,ICMP_MASK,数据包。,3.,示例程序三,此示例程序显示如何使用原始套接字接口发送多个,ICMP_ECHO,数据包,并采用,arena,接口分配数据包存储空间。,4.,示例程序四,此示例程序显示如何使用端口列表链构造,UDP,数据包。,
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服