网络嗅探器设计与实现_第1页
网络嗅探器设计与实现_第2页
网络嗅探器设计与实现_第3页
网络嗅探器设计与实现_第4页
网络嗅探器设计与实现_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

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

文档简介

计算机科学与技术网络工程06-1班网络嗅探器的设计与实现计算机科学与技术网络工程06-1班学院班级姓名学号指导老师网络嗅探器的设计与实现Designandimplementationofnetworksniffer摘要随着网络技术的发展和网络应用的普及,越来越多的信息资源放在了互联网上,网络的安全性和可靠性显得越发重要。因此,对于能够分析、诊断网络,测试网络性能与安全性的工具软件的需求也越来越迫切。网络嗅探器具有两面性,攻击者可以用它来监听网络中数据,达到非法获得信息的目的,网络管理者可以通过使用嗅探器捕获网络中传输的数据包并对其进行分析,分析结果可供网络安全分析之用。本文对网络嗅探技术进行了简要分析,研究了网络数据包的捕获机制,如winpcap、原始套接字。文中首先分析了嗅探的原理和危害,并介绍了几种常见的嗅探器,然后研究了入侵检测系统中使用的包捕获技术。本文利用原始套接字在windows平台下实现了一个网络嗅探器程序,完成了对数据包进行解包、分析数据包的功能。关键词:网络嗅探器数据包捕获数据包分析原始套接字目录TOC\o"1-5"\h\z\o"CurrentDocument"摘要 2关键词 2\o"CurrentDocument"1网络嗅探概述 4\o"CurrentDocument"1.1网络嗅探的简介 4\o"CurrentDocument"1.2相关的网络知识 4\o"CurrentDocument"1.3基于网卡混杂模式的嗅探原理 7\o"CurrentDocument"1.4基于arp欺骗的嗅探原理 7\o"CurrentDocument"1.5网络嗅探的安全威胁 7\o"CurrentDocument"1.6网络嗅探的防范 8\o"CurrentDocument"2基于原始套接字的嗅探程序 9\o"CurrentDocument"2.1嗅探实现 9\o"CurrentDocument"嗅探运行结果 25\o"CurrentDocument"3网络嗅探工具应用----WinSniffer使用方法 27WinSniffer简介 27WinSniffer嗅探功能使用方法 27\o"CurrentDocument"小结 29\o"CurrentDocument"参考资料 291网络嗅探概述1.1网络嗅探的简介网络嗅探器又称为网络监听器,简称为Sniffer子系统,放置于网络节点处,对网络中的数据帧进行捕获的一种被动监听手段,是一种常用的收集有用数据的方法,这些数据可以是用户的账号和密码,可以是一些商用机密数据等等。Sniffer是利用计算机的网络接口截获目的地为其他计算机的数据报文的一种工具。Sniffer的正当用处主要是分析网络的流量,以便找出所关心的网络中潜在的问题。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器截获网络中的数据包,分析问题的所在。而嗅探器也可作为攻击工具被黑客所利用为其发动进一步的攻击提供有价值的信息。1.2相关的网络知识1.2.1交换基础交换发生网络的第二层,即数据链路层。谈到交换的问题,从广义上讲,任何数据的转发都可以称作交换。当然,现在我们指的是狭义上的交换,仅包括数据链路层的转发。交换原理所谓交换,就是将分组(或帧)从一个端口移到另一个端口的简单动作。交换机在操作过程当中会不断的收集资料去建立它本身的一个地址表,MAC地址表显示了主机的MAC地址与以太网交换机端口映射关系,指出数据帧去往目的主机的方向。当以太网交换机收到一个数据帧时,将收到数据帧的目的MAC地址与MAC地址表进行查找匹配。如果在MAC地址表中没有相应的匹配项,则向除接收端口外的所有端口广播该数据帧,有人将这种操作翻译为泛洪。在我们测试过的交换机中,有的除了能够对广播帧的转发进行限制之外,也能对泛洪这种操作进行限制。而当MAC地址表中有匹配项时,该匹配项指定的交换机端口与接收端口相同则表明该数据帧的目的主机和源主机在同一广播域中,不通过交换机可以完成通信,交换机将丢弃该数据帧。否则,交换机将把该数据帧转发到相应的端口。交换技术局域网交换技术是作为对共享式局域网提供有效的网段划分的解决方案而出现的,它可以使每个用户尽可能地分享到最大带宽。交换技术是在OSI七层网络模型中的第二层,即数据链路层进行操作的,因此交换机对数据包的转发是建立在MAC地址基础上的,对于IP网络协议来说,它是透明的,即交换机在转发数据包时,不知道也无须知道信源机和目标机的IP地址,只需知其物理地址。从网络交换产品的形态来看,交换产品大致有三种:端口交换、帧交换和信元交换。路由基础所谓路由就是指通过相互连接的网络把信息从源地点移动到目标地点的过程。路由原理当IP子网中的一台主机发送IP分组给同一IP子网的另一台主机时,它将直接把IP分组送到网络上,对方就能收到。而要送给不同IP子网上的主机时,它要选择一个能到达目的子网上的路由器,把IP分组送给该路由器,由路由器负责把IP分组送到目的地。如果没有找到这样的路由器,主机就把IP分组送给一个称为“缺省网关”的路由器上。“缺省网关”是每台主机上的一个配置参数,它是接在同一个网络上的某个路由器端口的IP地址。路由器转发IP分组时,只根据IP分组目的IP地址的网络号部分,选择合适的端口,把IP分组送出去。同主机一样,路由器也要判定端口所接的是否是目的子网,如果是,就直接把分组通过端口送到网络上,否则,也要选择下一个路由器来传送分组。路由器也有它的缺省网关,用来传送不知道往哪儿送的IP分组。这样,通过路由器把知道如何传送的IP分组正确转发出去,不知道的IP分组送给“缺省网关”路由器,这样一级一级的传送,IP分组最终将送到目的地,送不到目的地的IP分组则被网络丢弃了。路由技术路由器不仅负责对IP分组的转发,还要负责与别的路由器进行联络,共同确定“网间网”的路由选择和维护路由表。路由包含两个基本的动作:选择最佳路径和通过网络传输信息。在路由的过程中,后者也称为(数据)交换。交换相对来说比较简单,而选择路径很复杂。路径选择路径选择是判定到达目的地的最佳路径,由路由选择算法来实现。由于涉及到不同的路由选择协议和路由选择算法,要相对复杂一些。为了判定最佳路径,路由选择算法必须启动并维护包含路由信息的路由表,其中路由信息依赖于所用的路由选择算法而不尽相同。metric是路由算法用以确定到达目的地的最佳路径的计量标准,如路径长度。为了帮助选路,路由算法初始化并维护包含路径信息的路由表,路径信息根据使用的路由算法不同而不同。1.2.3网卡的工作原理发送数据时,网卡首先侦听介质上是否有载波,如果有,则认为其他站点正在传送信息,继续侦听介质。一旦通信介质在一定时间段内是安静的,即没有被其他站点占用,则开始进行帧数据发送,同时继续侦听通信介质,以检测冲突。在发送数据期间。如果检测到冲突,则立即停止该次发送,并向介质发送一个“阻塞”信号,告知其他站点已经发生冲突,从而丢弃那些可能一直在接收的受到损坏的帧数据,并等待一段随机时间。在等待一段随机时间后,再进行新的发送。如果重传多次后(大于16次)仍发生冲突,就放弃发送。接收时,网卡浏览介质上传输的每个帧,如果其长度小于64字节,则认为是冲突碎片。如果接收到的帧不是冲突碎片且目的地址是本地地址,则对帧进行完整性校验,如果帧长度大于1518字节或未能通过CRC校验,则认为该帧发生了畸变。通过校验的帧被认为是有效的,网卡将它接收下来进行本地处理。接受到报文的计算机的网卡处理报文的过程如下图所示:报文处理过程1.3基于网卡混杂模式的嗅探原理在网络中,嗅探器接收所有的分组,而不发送任何非法分组。它不会妨碍网络数据的流动,因此很难对其进行检测。不过,处于混杂模式网卡的状态很显然和处于普通模式下不同。在混杂模式下,应该被硬件过滤掉的分组文会进入到系统的内核。是否回应这种分组完全依赖与内核。下面我举一个现实世界中的例子,说明我们检测处于混杂模式网络节点的方法。设想一下,在一个会议室中正在举行一个会议。某个人把耳朵放在会议室就可以进行窃听。当她进行窃听时,会屏住呼吸,安静地聆听会议室内所有的发言。然而,如果此时会议室内有人忽然叫窃听者的名字:“太太”,她就可能答应“唉”。这听起来有点好笑,但是完全可以用于网络嗅探行为的检测。网络进行网络嗅探的节点会接收网络的所有报文,因此其内核可能对某些本该被硬件过滤的分组作出错误回应。根据这个原理,我们可以通过检查节点对ARP报文的响应来检测网络的嗅探行为。1.4基于arp欺骗的嗅探原理所谓ARP欺骗,就是利用广播地址上主机保持周边计算机信息方式的固有安全弱点,使用伪造的MAC地址和IP地址伪装成ARP高速缓存中的另一台主机的技术。根据交换机的工作原理,有以下两种基于ARP欺骗的网络嗅探方法。基于交换机的MAC-端口映射表修改的嗅探。基于中间人攻击的嗅探。1.5网络嗅探的安全威胁实际应用中的嗅探器分软、硬两种。软件嗅探器便宜易于使用,缺点是往往无法抓取网络上所有的传输数据,也就可能无法全面了解网络的故障和运行情况;硬件嗅探器的通常称为协议分析仪,它的优点恰恰是软件嗅探器所欠缺的,但是价格昂贵。目前主要使用的嗅探器是软件的。嗅探器捕获真实的网络报文。嗅探器通过将其置身于网络接口来达到这个目的--例如将以太网卡设置成杂收模式。数据在网络上是以帧的单位传输的。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上。通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧的到达,然后对其进行存储。就是在这个传输和接收的过程中,每一个在LAN上的工作站都有其硬件地址。这些地址唯一地表示着网络上的机器。当用户发送一个报文时,这些报文就会发送到LAN上所有可用的机器。在一般情况下,网络上所有的机器都可以"听"到通过的流量,但对不属于自己的报文则不予响应。如果某在工作站的网络接口处于杂收模式,那么它就可以捕获网络上所有的报文和帧,如果一个工作站被配置成这样的方式,它就是一个嗅探器。这也是嗅探器会造成安全方面的问题的原因。通常使用嗅探器的入侵者,都必须拥有基点用来放置嗅探器。对于外部入侵者来说,能通过入侵外网服务器、往内部工作站发送木马等获得需要,然后放置其嗅探器,而内部破坏者就能够直接获得嗅探器的放置点,比如使用附加的物理设备作为嗅探器(例如,他们可以将嗅探器接在网络的某个点上,而这个点通常用肉眼不容易发现。除非人为地对网络中的每一段网线进行检测,没有其他容易方法能够识别出这种连接。嗅探器可能造成的危害:嗅探器能够捕获口令.能够捕获专用的或者机密的信息.可以用来危害网络邻居的安全,或者用来获取更高级别的访问权限.分析网络结构,进行网络渗透。1.6网络嗅探的防范1.6.1检测嗅探器检测嗅探器可以采用检测混杂模式网卡的工具。由于嗅探器需要将网络中入侵的网卡设置为混杂模式才能工作,能够检测混杂模式网卡的AntiSniff是一个工具。证明你的网络有嗅探器有两条经验:网络通讯丢包率非常高:通过一些网管软件,可以看到信息包传送情况,最简单是ping命令。它会告诉你掉了百分之多少的包。如果你的网络结构正常,而又有20%—30%数据包丢失以致数据包无法顺畅的流到目的地。就有可能有人在监听,这是由于嗅探器拦截数据包导致的。网络带宽出现反常:通过某些带宽控制器,可以实时看到目前网络带宽的分布情况,如果某台机器长时间的占用了较大的带宽,这台机器就有可能在监听。应该也可以察觉出网络通讯速度的变化。1.6.2将数据隐藏,使嗅探器无法发现嗅探器非常难以被发现,因为它们是被动的程序一个老练的攻击者可以轻易通过破坏日志文件来掩盖信息。它们并不会给别人留下进行核查的尾巴.。完全主动的解决方案很难找到,我们可以采用一些被动的防御措施:安全的拓扑结构。会话加密。用静态的ARP或者IP-MAC对应表代替动态的。除了以上三点另外还要重视重点区域的安全防范。这里说的重点区域,主要是针对嗅探器的放置位置而言。入侵者要让嗅探器发挥较大功效,通常会把嗅探器放置在数据交汇集中区域,比如网关、交换机、路由器等附近,以便能够捕获更多的数据。因此,对于这些区域就应该加强防范,防止在这些区域存在嗅探器。2基于原始套接字的嗅探程序2.1嗅探实现下面通过c语言实现基于原始套接字的嗅探程序,代码以及代码分析如下:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<winsock2.h>#include<ws2tcpip.h>#pragmacomment(lib,"ws2_32.lib")#defineSIO_RCVALL_WSAIOW(IOC_VENDOR,1)#defineMAX_PACK_LEN65535//最大包长度#defineMAX_ADDR_LEN16//最大地址长度#defineMAX_PROTO_TEXT_LEN16//子协议名称最大长度#defineMAX_PROTO_NUM12//子协议数量#defineMAX_HOSTNAME_LEN255//最大主机名长度上面程序主要包含了工程所需的头文件和进行了相关的宏定义。其中,SIO_RCVALL表示套接字接收所有的数据包。//定义IP首部格式typedefstruct_IPHeader{unsignedcharh_verlen;//版本和首部长度unsignedchartos; //服务类型unsignedshorttotal_len;//总长度unsignedshortident; //标识号unsignedshortfrag_and_flags;//段偏移量unsignedcharttl; //生存时间unsignedcharproto; //协议unsignedshortchecksum; //首部校验和unsignedintsourceIP;//源IP地址unsignedintdestIP;//目的地址}IPHEADER;//定义TCP首部格式typedefstruct_TCPHeader{unsignedshortth_sport;//源端口号unsignedshortth_dport;//目的端口号unsignedintth_seq;//SEQ序号unsignedintth_ack;//ACK序号unsignedcharth_lenres;//首部长度unsignedcharth_flag;//控制位unsignedshortth_win;//窗口大小unsignedshortth_sum;//校验和unsignedshortth_urp;//紧急指针}TCPHEADER;上面程序定义了IP数据包和TCP数据包的首部格式,以便进行数据包的解析。//定义UDP首部格式typedefstruct_UDPHeader{unsignedshortuh_sport;//16位源端口unsignedshortuh_dport;//16位目的端口unsignedshortuh_len;//16位长度unsignedshortuh_sum;//16位校验和}UDPHEADER;//定义ICMP首部格式typedefstruct_ICMPHeader{BYTEi_type;//8位类型BYTEi_code;//8位代码unsignedshorti_cksum;//16位校验和unsignedshorti_id;//识别号unsignedshorti_seq;//报文序列号unsignedlongtimestamp;//时间戳}ICMPHEADER;上面程序定义了UDP数据包和ICMP数据包的首部格式,以便进行数据包的解析。//定义子协议映射表typedefstruct_protomap{intProtoNum;charProtoText[MAX_PROTO_TEXT_LEN];}PROTOMAP;//为子协议映射表赋值PROTOMAPProtoMap[MAX_PROTO_NUM]={{IPPROTO_IP,"IP"},{IPPROTO_ICMP,"ICMP"},{IPPROTO_IGMP,"IGMP"},{IPPROTO_GGP,"GGP"},{IPPROTO_TCP,"TCP"},{IPPROTO_PUP,"PUP"},{IPPROTO_UDP,"UDP"},{IPPROTO_IDP,"IDP"},{IPPROTO_ND,"ND"},{IPPROTO_RAW,"RAW"},{IPPROTO_MAX,"MAX"},{NULL,""}};上面程序定义了子协议映射表并对映射表进行了赋值。SOCKETSockRaw;//全局套接字charTcpFlag[6]={'F','S','R','P','A','U'};//TCP标志位boolparamAll=false;//嗅探所有的数据包boolparamTcp=false;//嗅探TCP数据包boolparamUdp=false;//嗅探UDP数据包boolparamIcmp=false;//嗅探ICMP数据包intparamkeyword=0;//是否进行关键字查询intpacket_totallen=0;//数据包总长度charparamHostAddr_A[20];//嗅探的主机AcharparamHostAddr_B[20];//嗅探的主机Bcharkeyword[100];//嗅探的关键信息//IP数据包解析函数intDecodeIpPack(char*);//TCP数据包解析函数intDecodeTcpPack(char*);//UDP数据包解析函数intDecodeUdpPack(char*);//ICMP数据包解析函数intDecodeIcmpPack(char*);//显示数据包信息voidShowPackInfo(char*buf,intiProtocol,char*szSoueceIP,char*szDestIP,char*szProtocol);//显示子协议数据包函数voidShowSubPackInfo(char*,int);〃错误检测函数voidCheckSockError(int,char*);//协议检测函数char*CheckProtocol(int);//设置嗅探器参数函数boolSetSnifferParam();上面程序主要定义了相关的全部变量和声明了相关函数。变量SockRaw是负责接收数据包的原始套接字。变量TcpFlag定义了TCP的标识位,以便进行TCP的数据包解析。变量paramAll表示是否对所有类型数据包进行嗅探。变量paramTcp表示是否对TCP数据包进行嗅探。变量paramUdp表示是否对UDP数据包进行嗅探。变量paramIcmp表示是否对ICMP数据包进行嗅探。变量paramKeyword表示是否进行关键字搜索。变量Keyword表示关键字。变量packet_totallen表示嗅探到的每个数据包的总长度,变量aramHostAddr_A和aramHostAddr_B表示通信双方的IP地址。//SOCK错误处理函数voidCheckSockError(intiErrorCode,char*pErrorMsg){if(iErrorCode==SOCKET_ERROR){printf("%sError:%d",pErrorMsg,GetLastError());closesocket(SockRaw);exit(0);}}上面程序是实现SOCK错误的功能函数。参数iErrorCode是输入的校验码;参数pErrorMsg是输入的错误信息。程序流程是:如果校验码表示的是错误码SOCKET_ERROR,则调用GetLastError函数将具体的错误信息输出。//协议识别函数char*CheckProtocol(intiProtocol){for(inti=0;i<MAX_PROTO_NUM;i++){//如果找到对应的子协议,则返回名称if(ProtoMap[i].ProtoNum==iProtocol){returnProtoMap[i].ProtoText;}}return"";}上面程序是实现根据输入的协议编号到协议映射表中查找对应的功能函数。参数iProtocol是输入的协议编号。程序流程是:对映射表进行循环查找,找到对应的协议编号后,输出协议名称。//TCP解包函数intDecodeTcpPack(char*TcpBuf){TCPHEADER*pTcpHeader;chardata[MAX_PACK_LEN];inti;//转换成TCP首部格式pTcpHeader=(TCPHEADER*)TcpBuf;//输出源端口和目的端口printf("Port:%d-->%d",ntohs(pTcpHeader->th_sport),ntohs(pTcpHeader->th_dport));unsignedcharFlagMask=1;//输出标志位for(i=0;i<6;i++){if((pTcpHeader->th_flag)&FlagMask){printf("%c",TcpFlag[i]);}else{printf("-");}FlagMask=FlagMask<<1;}printf("\n");上面程序是实现解析TCP数据包函数的部分代码。参数TcpBuf是输入的TCP首部和数据段的头指针。程序流程是:首先将TcpBuf转换成TCP首部格式。然后输出TCP首部中的源端口号th_sport和目的端口号th_dport。最后采用循环与位的方法输出TCP首部中的标志位。//求数据段长度inttotalheadlen=sizeof(IPHEADER)+sizeof(TCPHEADER);inttcpheadlen=sizeof(TCPHEADER);memcpy(data,TcpBuf+tcpheadlen,packet_totallen-totalheadlen);//进行关键字寻求和输出if(paramkeyword==1){//如果找到关键字,则输出数据段if(strstr(data,keyword)){““““““““““““““““““““““““.、・、printf(\n************************DATA******************************\n);for(i=0;i<packet_totallen-totalheadlen;i++)printf("%c”,data[i]);}““““““““““““““““““““““““.、・、pnntf(\n************************DATA******************************\n);returntrue;}上面程序是实现解析TCP数据包函数的部分代码。程序流程是:首先将数据包中的数据段部分复制到数组中。然后判断用户是否选择了关键字搜索,如果是,则调用strtstr函第15页/共29页数比对数据和关键字,如果找到关键字,则对数据段进行输出,以便用户查看。//UDP解包函数intDecodeUdpPack(char*UdpBuf){UDPHEADER*pUdpHeader;chardata[MAX_PACK_LEN];pUdpHeader=(UDPHEADER*)UdpBuf;//输出端口和数据长度printf("Port:%d-->%d”,ntohs(pUdpHeader->uh_sport),ntohs(pUdpHeader->uh_dport));printf("Len=%d\n”,ntohs(pUdpHeader->uh_len));inttotalheadlen=sizeof(IPHEADER)+sizeof(UDPHEADER);intudpheadlen=sizeof(UDPHEADER);memcpy(data,UdpBuf+udpheadlen,packet_totallen-totalheadlen);//进行关键字寻求和输出if(paramkeyword==1){//如果找到关键字,则输出数据段if(strstr(data,keyword)){““““““““““““““““““““““““.、・、Dnntf(\n************************DATA******************************\n);for(inti=0;i<packet_totallen-totalheadlen;i++){printf("%c”,data[i]);}““““““““““““““““““““““““.、・、print^'n^^^^^^^^^^^^^^^^^^^^^^^^DATA^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'n):returntrue;}上面程序是实现了解析UDP数据包的功能函数。参数UdpBuf表示输入的UDP数据首部和数据段。程序流程是:首先将输入参数UdpBuf 转换成UDP首部格式,然后输出第16页/共29页UDP首部格式中的源端口号uh_sport,目的端口号uh_dport和数据长度uh_len。最后和TCP解析函数一样对关键字进行查找和输出。//ICMP解包函数intDecodeIcmpPack(char*IcmpBuf){ICMPHEADER*pIcmpHeader;pIcmpHeader=(ICMPHEADER*)IcmpBuf;//输出ICMP数据包类型、ID和SEQprintf("Type:%d,%d",pIcmpHeader->i_type,pIcmpHeader->i_code);printf("ID=%dSEQ=%d\n”,pIcmpHeader->i_id,pIcmpHeader->i_seq);returntrue;}上面程序是实现了解析ICMP数据包的功能函数。参数IcmpBuf表示输入的ICMP首部和数据段。程序流程是:首先将输入参数IcmpBuf转换成ICMP首部格式。然后输出ICMP首部中的类型码Type。最后输出首部格式中的识别号ID和报文序列号SEQ。//显示子协议数据包信息voidShowSubPackInfo(char*buf,intiProtocol){switch(iProtocol){caseIPPROTO_TCP://TCP数据包DecodeTcpPack(buf);break;caseIPPROTO_UDP://UDP数据包DecodeUdpPack(buf);break;caseIPPROTO_ICMP://ICMP数据包DecodeIcmpPack(buf);break;default:break;}}上面程序是实现了显示子协议数据包内容的功能函数。参数buf表示除去IP首部的子协议首部和数据段;参数iProtocol是输入的协议编号。程序流程是:判断输入的协议编号,如果是TCP数据包编号IPPROTO-TCP则调用DecodeTcpPack函数进行解析。如果是UDP数据包编号IPPROTO-UDP,则调用DecodeUdpPack函数进行解析。如果是ICMP数据包编号IPPROTO-ICMP则调用DecodeIcmpPack函数进行解析。//根据过滤条件显示数据包信息voidShowPackInfo(char*buf,intiProtocol,char*szSoueceIP,char*szDestIP,char*szProtocol){//如果设置了主机B的IP,没有设置主机A的IPif((!strcmp(paramHostAddr_A,"all"))&&(strcmp(paramHostAddr_B,"all"))){if((!strcmp(paramHostAddr_B,szSoueceIP))||(!strcmp(paramHostAddr_B,szDestIP))){printf("\n%s”,szProtocol);printf("%s-->%s”,szSoueceIP,szDestIP);//显示子协议数据包相关信息ShowSubPackInfo(buf,iProtocol);}}//如果设置主机A的IP,没有设置主机B的IPelseif((strcmp(paramHostAddr_A,"all"))&&(!strcmp(paramHostAddr_B,"all"))){if((!strcmp(paramHostAddr_A,szSoueceIP))||(!strcmp(paramHostAddr_A,szDestIP))){printf("\n%s”,szProtocol);printf("%s-->%s”,szSoueceIP,szDestIP);ShowSubPackInfo(buf,iProtocol);}}上面程序是实现了显示数据包信息功能函数的部分代码。参数buf表示除去IP首部的子协议首部和数据段;参数iProtocol是输入的协议编号。参数szSouecelP表示数据包源地址IP;参数szDestIP表示目的地址IP参数szProtocol表示协议名称。程序流程是:判断如果设置了通信主机B的IP地址,而没有设置通信主机A的IP地址,这说明程序嗅探所有流经主机B的数据包。在这种条件下,只要符合源地址IP或目的地址IP和主机B的IP相同,就调用ShowSubPackInfo显示子协议数据包内容。同理,如果设置了通信主机A的IP地址,而没有设置通信主机B的IP地址,操作流程是相同的。//如果主机A和B的IP都进行了设置elseif((strcmp(paramHostAddr_A,"all"))&&(strcmp(paramHostAddr_B,"all"))){if((!strcmp(paramHostAddr_A,szSoueceIP)&&!strcmp(paramHostAddr_B,szDestIP))||(!strcmp(paramHostAddr_B,szSoueceIP)&&!strcmp(paramHostAddr_A,szDestIP))){printf("\n%s”,szProtocol);printf("%s-->%s”,szSoueceIP,szDestIP);ShowSubPackInfo(buf,iProtocol);}}//如果主机A和B的IP都没有进行设置else{printf("\n%s",szProtocol);printf("%s-->%s”,szSoueceIP,szDestIP);ShowSubPackInfo(buf,iProtocol);}上面程序是实现了显示数据包信息功能函数的部分代码。程序流程是:首先判断如果同时设置了通信主机B和通信主机A的IP地址,则说明程序嗅探所有的主机A和主机B之间的通信数据并调用ShowSubPackInfo函数显示子协议数据内容。如果主机A和主机B的IP地址都没有设置,则说明程序嗅探所有Hub上的数据包并调用ShowSubPackInfo函数显示子协议数据包内容。//IP解包函数intDecodeIpPack(char*buf){IPHEADER*pIpHeader;intiProtocol;//定义协议charszProtocol[MAX_PROTO_TEXT_LEN];charszSourceIP[MAX_ADDR_LEN];charszDestIP[MAX_ADDR_LEN];SOCKADDR_INsaSource,saDest;pIpHeader=(IPHEADER*)buf;//检测协议是哪种类型iProtocol=pIpHeader->proto;strncpy(szProtocol,CheckProtocol(iProtocol),MAX_PROTO_TEXT_LEN);//检测源地址saSource.sin_addr.s_addr=pIpHeader->sourceIP;strncpy(szSourceIP,inet_ntoa(saSource.sin_addr),MAX_ADDR_LEN);//检测目的地址saDest.sin_addr.s_addr=pIpHeader->destIP;strncpy(szDestIP,inet_ntoa(saDest.sin_addr),MAX_ADDR_LEN);intiIpLen=sizeof(unsignedlong)*(pIpHeader->h_verlen&0xf);packet_totallen=ntohs(pIpHeader->total_len);上面程序是实现解析IP数据包的功能函数部分代码。参数buf是输入的嗅探到的数据包。程序流程是:首先将输入的buf转换成IP首部格式。然后从IP首部提取出协议类型编号并调用inet_nto函数提取源地址IP,目的地址IP。最后提取IP首部长度iIpLen和整个第20页/共29页数据包长度packet_totallen。//下面显示过滤信息if(paramAll)//显示所有协议类型数据包{ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);}//显示TCP类型数据包elseif(paramTcp&&(iProtocol==IPPROTO_TCP)){ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);}//显示UDP类型数据包elseif(paramUdp&&(iProtocol==IPPROTO_UDP)){ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);}//显示ICMP类型数据包elseif(paramIcmp&&(iProtocol==IPPROTO_ICMP)){ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);}returntrue;}上面程序是实现解析IP数据包的功能函数部分代码。程序判断嗅探协议类型的变量,如果paramAll为True,则表明显示所有协议类型的数据包。如果paramTcp为True并且iProtocol协议编号为TCP,则表明显示TCP的数据包。如果paramUdp为True并且iProtocol协议编号为UDP,则表明显示UDP的数据包。如果paramIcmp为True并且iProtocol协议编号为ICMP,则表明显示ICMP的数据包。//设置嗅探器参数boolSetSnifferParam()intret;boolcheck_input=false;while(!check_input){printf("请选择要嗅探的数据包类型0->全部1->TCP2->UDP3->ICMP:");scanf("%d”,&ret);switch(ret){case0:paramAll=true;check_input=true;break;case1:paramTcp=true;check_input=true;break;case2:paramUdp=true;check_input=true;break;case3:paramIcmp=true;check_input=true;break;default:printf("输入错误\n");check_input=false;break;}}上面程序是实现设置嗅探器参数的功能函数部分代码。程序使用控制台交互的方式由用户输入要嗅探的数据包协议类型,0代表所有协议类型,1代表TCP类型,2代表UDP类型,3代表ICMP类型。如果用户输入错误,则重新进行输入。printf("\n请输入嗅探的主机A的IP地址(输入all即为全部主机):");scanf("%s”,paramHostAddr_A);printf("\n请输入嗅探的主机B的IP地址(输入all即为全部主机):");scanf("%s”,paramHostAddr_B);printf("\n是否进行关键字搜索?0->否1->是:”);scanf("%d”,¶mkeyword);if(paramkeyword==1){printf("\n请输入关键字:”);scanf("%s”,keyword);}returntrue;}上面程序是实现设置嗅探器参数的功能函数部分代码。程序首先由用户输入嗅探的主机A的IP地址,如果输入“al表示全部主机。最后用户选择是否进行关键字查询,如果是,则再次输入关键字。voidmain(intargc,char**argv){intiErrorCode;charRecvBuf[MAX_PACK_LEN]={0};SetSnifferParam();WSADATAwsaData;//初始化Winsock库iErrorCode=WSAStartup(MAKEWORD(2,1),&wsaData);CheckSockError(iErrorCode,"WSAStartup");SockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_IP);CheckSockError(SockRaw,"socket");//获取本机IP地址,并且判断Socket版本,建立原始套接字charFARname[MAX_HOSTNAME_LEN];iErrorCode=gethostname(name,MAX_HOSTNAME_LEN);CheckSockError(iErrorCode,"gethostname");structhostentFAR*pHostent;pHostent=(structhostent*)malloc(sizeof(structhostent));pHostent=gethostname(name);//设置地址结构,端口为本地的6000SOCKADDR_INsa;sa.sin_family=AF_INET;sa.sin_port=htons(6000);memcpy(&sa.sin_addr.S_un.S_addr,pHostent->h_addr_list[O],pHostent->h_length);//绑定地址结构iErrorCode=bind(SockRaw,(PSOCKADDR)&sa,sizeof(sa));CheckSockError(iErrorCode,"bind");上面程序是实现嗅探功能的主函数部分代码。程序流程是:首先调用SetSnifferParam函数设置嗅探器相关参数,调用WSAStartup函数初始化Winsock库。然后调用socket函数创建原始套接字,并且调用gethostname函数和gethostname函数获得本机上IP地址,同时设置本地监听端口号为6000.最后调用bind函数将本地地址结构绑定在套接字上。//设置套接字为SIO_RCVALL,以便接收所有的IP包DWORDdwBufferLen[10];DWORDdwBufferInLen=1;DWORDdwBytesReturned=0;iErrorCode=WSAIoctl(SockRaw,SIO_RCVALL,&dwBufferInLen,sizeof(dwBufferInLen),&dwBufferLen,sizeof(dwBufferLen),&dwBytesReturned,NULL,NULL);CheckSockError(iErrorCode,"Ioctl");//监听IP报文while(1){//每次将接收缓冲区清零memset(RecvBuf,0,sizeof(RecvBuf));//开始接收缓冲区的数据iErrorCode=recv(SockRaw,RecvBuf,sizeof(RecvBuf),0);CheckSockError(iErrorCode,"recv");//对接收到的数据包进行解析iErrorCode=DecodelpPack(RecvBuf);CheckSockError(iErrorCode,"Decode");Sleep(10);}}上面程序是实现嗅探功能的主函数部分代码。程序流程是:首先调用WSAIoctl函数设置原始套接字接受所有的数据包,主要是将函数的第二个参数设置为SIO_RCVALL。然后开始无限循环调用recv函数接收Hub上所有的数据包。最后对接收到的数据包调用DecodeIpPack函数进行解析。2.2嗅探运行结果2.2.1嗅探普通数据包执行RawSocketSniffer.exe,程序提示选择嗅探的数据包协议类型,输入“0”,表示嗅探所有的协议类型。然后程序提示输入嗅探的主机A的ip地址,输入“88”程序提示输入嗅探的主机B的ip地址,输入“all”,表明程序嗅探

温馨提示

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

评论

0/150

提交评论