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

下载本文档

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

文档简介

小型网络嗅探器的设计与实现摘要:随着网络技术的发展和网络应用的普及,越来越多的信息资源放在了互联网上,网络的安全性和可靠性显得越发重要。因此对于能够分析诊断网络,测试网络性能与安全性的工具软件的需求也越来越迫切。嗅探器就是能够捕获网络报文的设备,嗅探器的正当用处在于分析网络的流量,以便找出所关心的网络中潜在的问题。网络管理者可以通过使用嗅探器捕获网络中传输的数据包并对其进行分析,分析结果可供网络安全分析之用。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器来作出精确的问题判断。嗅探器在功能和设计方面有很多不同。本文对嗅探器技术进行了简要分析,研究了网络数据包的捕获机制。分析了嗅探的原理,利用原始套接字在windows平台下实现了一个网络嗅探器程序,完成了对数据包进行解包、分析数据包的功能。Socket是Windows下网络编程的标准接口,它允许两个或多个应用程序在相同机器上,或者是通过网络互相交流。分析了网络化嗅探器在实用中的若干问题及对策.初步进展和实验表明了这一技术路线的可行性。关键词:嗅探器;多线程;Socket;VisualC++6.0;MFC一、绪论(一)项目开发背景随着计算机网络的不断普及,网络管理的应用需求越来越大,而嗅探器很早就在此领域发挥着重要的作用。嗅探器的种类繁多,有的是专门的某一个协议的分析器,有的则具有强大的功能,如非常著名的Ethereal,NetXRay和Sniffer等。而这些大型的嗅探器需要昂贵的价格购买,对于小型网络则有“大材小用”之弊。所以,针对小型网络的简易实用的嗅探器应运而生。这里,我们的网络协议分析工具就是应用于小型局域网的管理,对其进行基于数据抓包的监控,包括本地局域网行为的实时查看,从而满足小型局域网如学校机房,公司部门,政府单位等这样规模的网络的监管及网络信息获取。(二)项目开发目标本项目开发的目标是开发出实用于规模不大的局域网的监控于管理。监控就是实时对网络的行为进行监视从而获取采取控制行为所需的信息。管理是基于网络信息的掌握而产生的,我们提供了本地网络信息快速获取的工具,域名查询的实用工具,以观察本地主机的行为,另外我们还提供了端口扫描的功能,使监视能力更加强大。总之,我们的开发目标是满足小型网络的信息获取和行为监管。二、相关技术(一)多线程编程多线程处理的优点同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成独立的任务,因此可以在以下方面显著提高性能:· 多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的同时一直处于活动状态。· 当前没有进行处理的任务可以将处理器时间让给其他任务。· 占用大量处理时间的任务可以定期将处理器时间让给其他任务。· 可以随时停止任务。· 可以分别设置各个任务的优先级以优化性能。是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:· 耗时或大量占用处理器的任务阻塞用户界面操作。· 各个任务必须等待外部资源(如远程文件或Internet连接)。例如,用于跟踪Web页上的链接并下载满足特定条件的文件的Internet应用程序“robot”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程Web服务器的响应非常慢,也可以下载文件。多线程编程的难点当多个线程之间有联系的时候,线程之间的同步控制就会成为一个难点,因为没有人能预期线程的被执行。在一个合作型多任务系统中,操作系统必须得到程序的允许才能够改变线程。但是在强制性多任务系统中,控制权被调度程序强制转移,也因此两个线程之间的执行次序变得不可预期。这不可预期性造成了所谓的racecondition。由于资源是共享的,有时还会出现死锁。(二)Socket编程Socket是Windows下网络编程的标准接口,它允许两个或多个应用程序在相同机器上,或者是通过网络互相交流。这种Windows下的Socket简称Winsock,Winsock库有两个版本,Winsock1和Winsock2。现在开发网络应用程序都使用Winsock2,需要在程序中包含头文件Winsock2.h,它包含了绝大部分socket函数和相关结构类型的声明和定义。同时要添加的还有到WS2_32.lib库的链接。包含必要的头文件,设置好链接环境之后,便可进行编码工作了。(1)TCP/IP的socket提供下列三种类型套接字。流式套接字(SOCK_STREAM):提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传送协议(FTP)即使用流式套接字。数据报式套接字(SOCK_DGRAM):提供了一个无连接服务。数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。网络文件系统(NFS)使用数据报式套接字。原始式套接字(SOCK_RAW):该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。(2)为了更好地说明套接字编程原理,下面给出几个基本套接字系统调用说明。=1\*GB3①创建套接字──socket()

应用程序在使用套接字前,首先必须拥有一个套接字,系统调用socket()向应用程序提供创建套接字的手段,其调用格式如下:SOCKETPASCALFARsocket(intaf,inttype,intprotocol);该调用要接收三个参数:af、type、protocol。参数af指定通信发生的区域,UNIX系统支持的地址族有:AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中仅支持AF_INET,它是网际网区域。因此,地址族与协议族相同。参数type描述要建立的套接字的类型。参数protocol说明该套接字使用的特定协议,如果调用者不希望特别指定使用的协议,则置为0,使用默认的连接模式。根据这三个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。=2\*GB3②指定本地地址──bind()

当一个套接字用socket()创建后,存在一个名字空间(地址族),但它没有被命名。bind()将套接字地址(包括本地主机地址和本地端口地址)与所创建的套接字号联系起来,即将名字赋予套接字,以指定本地半相关。其调用格式如下:intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);参数s是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。参数name是赋给套接字s的本地地址(名字),其长度可变,结构随通信域的不同而不同。namelen表明了name的长度。如果没有错误发生,bind()返回0。否则返回值SOCKET_ERROR。地址在建立套接字通信过程中起着重要作用,作为一个网络应用程序设计者对套接字地址结构必须有明确认识。例如,UNIXBSD有一组描述套接字地址的数据结构,其中使用TCP/IP协议的地址结构为:structsockaddr_in{

shortsin_family;

/*AF_INET*/

u_shortsin_port;

/*16位端口号,网络字节顺序*/

structin_addrsin_addr;

/*32位IP地址,网络字节顺序*/

charsin_zero[8];

/*保留*/}=3\*GB3③建立套接字连接──connect()与accept()

这两个系统调用用于完成一个完整相关的建立,其中connect()用于建立连接。无连接的套接字进程也可以调用connect(),但这时在进程之间没有实际的报文交换,调用将从本地操作系统直接返回。这样做的优点是程序员不必为每一数据指定目的地址,而且如果收到的一个数据报,其目的端口未与任何套接字建立“连接”,便能判断该端口不可操作。而accept()用于使服务器等待来自某客户进程的实际连接。

connect()的调用格式如下:intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);参数s是欲建立连接的本地套接字描述符。参数name指出说明对方套接字地址结构的指针。对方套接字地址长度由namelen说明。

如果没有错误发生,connect()返回0。否则返回值SOCKET_ERROR。在面向连接的协议中,该调用导致本地系统和外部系统之间连接实际建立。由于地址族总被包含在套接字地址结构的前两个字节中,并通过socket()调用与某个协议族相关。因此bind()和connect()无须协议作为参数。accept()的调用格式如下:SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);

参数s为本地套接字描述符,在用做accept()调用的参数前应该先调用过listen()。addr指向客户方套接字地址结构的指针,用来接收连接实体的地址。addr的确切格式由套接字创建时建立的地址族决定。addrlen为客户方套接字地址的长度(字节数)。如果没有错误发生,accept()返回一个SOCKET类型的值,表示接收到的套接字的描述符。否则返回值INVALID_SOCKET。accept()用于面向连接服务器。参数addr和addrlen存放客户方的地址信息。调用前,参数addr指向一个初始值为空的地址结构,而addrlen的初始值为0;调用accept()后,服务器等待从编号为s的套接字上接受客户连接请求,而连接请求是由客户方的connect()调用发出的。当有连接请求到达时,accept()调用将请求连接队列上的第一个客户方套接字地址及长度放入addr和addrlen,并创建一个与s有相同特性的新套接字号。新的套接字可用于处理服务器并发请求。=4\*GB3④四个套接字系统调用,socket()、bind()、connect()、accept(),可以完成一个完全五元相关的建立。socket()指定五元组中的协议元,它的用法与是否为客户或服务器、是否面向连接无关。bind()指定五元组中的本地二元,即本地主机地址和端口号,其用法与是否面向连接有关:在服务器方,无论是否面向连接,均要调用bind();在客户方,若采用面向连接,则可以不调用bind(),而通过connect()自动完成。若采用无连接,客户方必须使用bind()以获得一个唯一的地址。以上讨论仅对客户/服务器模式而言,实际上套接字的使用是非常灵活的,唯一需遵循的原则是进程通信之前,必须建立完整的相关。监听连接──listen()

此调用用于面向连接服务器,表明它愿意接收连接。listen()需在accept()之前调用,其调用格式如下:intPASCALFARlisten(SOCKETs,intbacklog);参数s标识一个本地已建立、尚未连接的套接字号,服务器愿意从它上面接收请求。backlog表示请求连接队列的最大长度,用于限制排队请求的个数,目前允许的最大值为5。如果没有错误发生,listen()返回0。否则它返回SOCKET_ERROR。listen()在执行调用过程中可为没有调用过bind()的套接字s完成所必须的连接,并建立长度为backlog的请求连接队列。调用listen()是服务器接收一个连接请求的四个步骤中的第三步。它在调用socket()分配一个流套接字,且调用bind()给s赋于一个名字之后调用,而且一定要在accept()之前调用。accept()调用为实现并发服务提供了极大方便,因为它要返回一个新的套接字号=5\*GB3⑤数据传输──send()与recv()

当一个连接建立以后,就可以传输数据了。常用的系统调用有send()和recv()。send()调用用于在参数s指定的已连接的数据报或流套接字上发送输出数据,格式如下:intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags);参数s为已连接的本地套接字描述符。buf指向存有发送数据的缓冲区的指针,其长度由len指定。flags指定传输控制方式,如是否发送带外数据等。如果没有错误发生,send()返回总共发送的字节数。否则它返回SOCKET_ERROR。recv()调用用于在参数s指定的已连接的数据报或流套接字上接收输入数据,格式如下:intPASCALFARrecv(SOCKETs,charFAR*buf,intlen,intflags);参数s为已连接的套接字描述符。buf指向接收输入数据缓冲区的指针,其长度由len指定。flags指定传输控制方式,如是否接收带外数据等。如果没有错误发生,recv()返回总共接收的字节数。如果连接被关闭,返回0。否则它返回SOCKET_ERROR。=6\*GB3⑥输入/输出多路复用──select()

select()调用用来检测一个或多个套接字的状态。对每一个套接字来说,这个调用可以请求读、写或错误状态方面的信息。请求给定状态的套接字集合由一个fd_set结构指示。在返回时,此结构被更新,以反映那些满足特定条件的套接字的子集,同时,select()调用返回满足条件的套接字的数目,其调用格式如下:intPASCALFARselect(intnfds,fd_setFAR*readfds,fd_setFAR*writefds,fd_setFAR*exceptfds,conststructtimevalFAR*timeout);参数nfds指明被检查的套接字描述符的值域,此变量一般被忽略。参数readfds指向要做读检测的套接字描述符集合的指针,调用者希望从中读取数据。参数writefds指向要做写检测的套接字描述符集合的指针。exceptfds指向要检测是否出错的套接字描述符集合的指针。timeout指向select()函数等待的最大时间,如果设为NULL则为阻塞操作。select()返回包含在fd_set结构中已准备好的套接字描述符的总数目,或者是发生错误则返回SOCKET_ERROR。使用TCP创建网络应用程序稍微复杂一些,因为TCP是面向连接的协议,需要通信双方首先建立一个连接,而UDP编程则相对简单些。Winsock的编程步骤是比较固定的,一般分以下几个步骤:套接字的创建和关闭;绑定套接字到指定的IP地址和端口号;设置套接字进入监听状态;接受连接请求;收发数据。(三)MFC编程如果你曾经使用过传统的windows编程方法开发应用程序,你会深刻地体会到,即使是开发一个简单的windows应用程序也需要对windows的编程原理有很深刻的认识,同时也要手工编写很多的代码。因为程序的出错率几乎是随着代码长度的增加呈几何级数增长的,这就使得调试程序变得非常困难。所以传统的windows编程是需要极大的耐心和丰富的编程经验的。

近几年来,面向对象技术无论是在理论还是实践上都在飞速地发展。面向对象技术中最重要的就是“对象”的概念,它把现实世界中的气球、自行车等客观实体抽象成程序中的“对象”。这种“对象”具有一定的属性和方法,这里的属性指对象本身的各种特性参数。如气球的体积,自行车的长度等,而方法是指对象本身所能执行的功能,如气球能飞,自行车能滚动等。一个具体的对象可以有许多的属性和方法,面向对象技术的重要特点就是对象的封装性,对于外界而言,并不需要知道对象有哪些属性,也不需要知道对象本身的方法是如何实现的,而只需要调用对象所提供的方法来完成特定的功能。从这里我们可以看出,当把面向对象技术应用到程序设计中时,程序员只是在编写对象方法时才需要关心对象本身的细节问题,大部分的时间是放在对对象的方法的调用上,组织这些对象进行协同工作。

MFC的英文全称是MicrosoftFundationClasses,即微软的基本类库,MFC的本质就是一个包含了许多微软公司已经定义好的对象的类库,我们知道,虽然我们要编写的程序在功能上是千差万别的,但从本质上来讲,都可以化归为用户界面的设计,对文件的操作,多媒体的使用,数据库的访问等等一些最主要的方面。这一点正是微软提供MFC类库最重要的原因,在这个类库中包含了一百多个程序开发过程中最常用到的对象。在进行程序设计的时候,如果类库中的某个对象能完成所需要的功能,这时我们只要简单地调用已有对象的方法就可以了。我们还可以利用面向对象技术中很重要的“继承”方法从类库中的已有对象派生出我们自己的对象,这时派生出来的对象除了具有类库中的对象的特性和功能之外,还可以由我们自己根据需要加上所需的特性和方法,产生一个更专门的,功能更为强大的对象。当然,你也可以在程序中创建全新的对象,并根据需要不断完善对象的功能。

正是由于MFC编程方法充分利用了面向对象技术的优点,它使得我们编程时极少需要关心对象方法的实现细节,同时类库中的各种对象的强大功能足以完成我们程序中的绝大部分所需功能,这使得应用程序中程序员所需要编写的代码大为减少,有力地保证了程序的良好的可调试性。

最后要指出的是MFC类库在提供的对象的各种属性和方法都是经过谨慎的编写和严格的测试,可靠性很高,这就保证了使用MFC类库不会影响程序的可靠性和正确性。(四)开发工具VisualC++简介VisualC++是一个功能强大的可视化软件开发工具。自1993年Microsoft公司推出VisualC++1.0后,随着其新版本的不断问世,VisualC++已成为专业程序员进行软件开发的首选工具。

虽然微软公司推出了VisualC++.NET(VisualC++7.0),但它的应用的很大的局限性,只适用于Windows2000,WindowsXP和WindowsNT4.0。所以实际中,更多的是以VisualC++6.0为平台。

VisualC++6.0不仅是一个C++编译器,而且是一个基于Windows操作系统的可视化集成开发环境(integrateddevelopmentenvironment,IDE)。VisualC++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard、类向导ClassWizard等开发工具。这些组件通过一个名为DeveloperStudio的组件集成为和谐的开发环境。

VisualC++它大概可以分成三个主要的部分:

(1)DeveloperStudio,这是一个集成开发环境,我们日常工作的99%都是在它上面完成的,再加上它的标题赫然写着“MicrosoftVisualC++”,所以很多人理所当然的认为,那就是VisualC++了。其实不然,虽然DeveloperStudio提供了一个很好的编辑器和很多Wizard,但实际上它没有任何编译和链接程序的功能,真正完成这些工作的幕后英雄后面会介绍。我们也知道,DeveloperStudio并不是专门用于VC的,它也同样用于VB,VJ,VID等VisualStudio家族的其他同胞兄弟。所以不要把DeveloperStudio当成VisualC++,它充其量只是VisualC++的一个壳子而已。这一点请切记!

(2)MFC。从理论上来讲,MFC也不是专用于VisualC++,BorlandC++,C++Builder和SymantecC++同样可以处理MFC。同时,用VisualC++编写代码也并不意味着一定要用MFC,只要愿意,用VisualC++来编写SDK程序,或者使用STL,ATL,一样没有限制。不过,VisualC++本来就是为MFC打造的,VisualC++中的许多特征和语言扩展也是为MFC而设计的,所以用VisualC++而不用MFC就等于抛弃了VisualC++中很大的一部分功能。但是,VisualC++也不等于MFC。

(3)PlatformSDK。这才是VisualC++和整个VisualStudio的精华和灵魂,虽然我们很少能直接接触到它。大致说来,PlatformSDK是以MicrosoftC/C++编译器为核心(不是VisualC++,看清楚了),配合MASM,辅以其他一些工具和文档资料。上面说到DeveloperStudio没有编译程序的功能,那么这项工作是由谁来完成的呢?是CL,是NMAKE,和其他许许多多命令行程序,这些我们看不到的程序才是构成VisualStudio的基石。三、需求分析(一)整体需求分析小型局域网的管理不可能使用Ethereal,NetXRay和Sniffer等大型嗅探器,但又需要有经济实用的网络数据抓包及协议分析工具,这里,不仅要求此工具具有一般协议分析器的通用功能,即对网络中的所有主机的嗅探和行为分析,而且要配备一些实用的网络信息查询辅助工具,包括内网和外网的一些信息,使之有所联系。具体应用分析1.网络抓包及协议分析需求分析如何对网络中的所有行为做到实时监控?这就需要对网络中的所有数据包都能获取继而进行协议分析,这样才能获取有用的信息。所以在本软件中此模块为主题功能,即主要模块,担任对总体把握和实时监控的功能。2.本地网络信息获取需求分析对于一个网管,获取本地网络的全部或一个地址段的一组包括IP地址,主机名,物理地址,用户信息及其所在工作组的信息是非常有用的,甚至是必须的。基于这种需求,我们提供了这样的工具,即本模块所实现的具有获取本地网络信息功能的工具。 3.端口扫描需求分析网络通信的最终地址就不仅仅是主机地址了,还包括可以描述进程的某种标识符。为此,TCP/IP协议提出了协议端口(protocolport,简称端口)的概念,用于标识通信的进程。网络通信的最终地址就不仅仅是主机地址了,还包括可以描述进程的某种标识符。为此,TCP/IP协议提出了协议端口的概念,用于标识通信的进程。所以,扫描端口的信息对网络行为的分析有着至关重要的作用。这里我们在主模块的基础上提供了功能更强大的端口扫描工具,具有主机选择和端口号指定扫描功能。为网管提供更有针对性的扫描工具。4.域名查询需求分析DNS是网络信息更直观,这里也是出于这种考虑,提供给使用者一个辅助查询工具,相信它将对使用者有所助益。主要是考虑到软件完善性而加入的小模块。开发本软件我们只需要至少两台可以互相通信(在一个网络中)的计算机,而这样的开发条件是很容易满足的,所以本软件的开发成本是非常低的。具有良好的经济性。(三)可行性研究1.技术方面VisualC++6.0提供了功能强大的开发平台,使得程序界面的实现简单、快速、标准。Winsock为Windows网络编程提供了丰富的接口技术,结合多线程技术,使得此处的基于TCP/IP网络编程具有良好的健壮性和强大的可扩展性。本软件最后所生成的.EXE可执行文件具有很好的可移植性。2.经济方面3.工作难点开发本软件主要要研究和解决的问题有:1)、多线程编程使用多线程编程是为了使程序的响应速度更快,在使用时应注意避免出现资源竞争和死锁的出现。2)Socket编程Socket编程主要提供标准的网络编程接口,使得两个或多个应用程序在同一台电脑上,或者是通过网络相互交流。使得本软件中基于IP协议的TCP、UTP、ICMP和ARP等协议的编程得以实现。3)界面设计界面中各个控件的布局以及消息响应函数的编写是贯穿整个工程的一项重要的工作。它也在整个工程设计的过程中耗费了我们很多经历。四、系统总体结构设计(一)软件模块结构设计1.软件工作模式图(客户机)图4.1工作模式图2.软件模块结构图数据抓包及协议分析(主程序sniffer)数据抓包及协议分析(主程序sniffer)域名查询端口扫描本地计算机信息浏览域名查询端口扫描本地计算机信息浏览 图4.2软件结构图3.软件设计结构图SSocket(),建立流式套接字,返回套接字句柄sListen。Bind(),关联一个本地地址到套接字sListen。Listen(),设置backlog值,进入监听状态。Socket(),建立流式套接字s。建立连接,accept函数返回,得到新的套接字,如sClient。Recv()/send(),在套接字sClient上收发数据,直到完成交换。Closesocket(),关闭监听套接字sListen,服务结束。Closesocket(),关闭套接字s,结束TCP对话。Accept(),等待接受客户连接请求。Closesocket(),关闭套接字sClient。Connect(),将套接字s与服务器连接。Recv()/send(),在套接字上收发数据,直到完成交换。服务器方客户方五、系统详细设计(一)嗅探器1.嗅探器简介嗅探器(snifffer)就是能够捕获网络报文的设备。嗅探器的正当用处在于分析网络的流量,以便找出所关心的网络中潜在的问题。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器来作出精确的问题判断。嗅探器在功能和设计方面有很多不同。有些只能分析一种协议,而另一些可能能够分析几百种协议。一般情况下,大多数的嗅探器至少能够分析下面的协议:■标准以太网■TCP/IP■IPX■DECNet嗅探器通常是软硬件的结合。专用的嗅探器价格非常昂贵。另一方面,免费的嗅探器虽然不需要花什么钱,但得不到什么支持。嗅探器与一般的键盘捕获程序不同。键盘捕获程序捕获在终端上输入的键值,而嗅探器则捕获真实的网络报文。嗅探器通过将其置身于网络接口来达到这个目的——例如将以太网卡设置成杂收模式。(为了理解杂收模式是怎么回事,先解释局域网是怎么工作的)。数据在网络上是以很小的称为帧(Ftame)的单位传输的帧由好几部分组成,不同的部分执行不同的功能。(例如,以太网的前12个字节存放的是源和目的的地址,这些位告诉网络:数据的来源和去处。以太网帧的其他部分存放实际的用户数据、TCP/IP的报文头或IPX报文头等等)。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上。通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧的到达,然后对其进行存储。就是在这个传输和接收的过程中,嗅探器会造成安全方面的问题。每一个在LAN上的工作站都有其硬件地址。这些地址唯一地表示着网络上的机器(这一点于Internet地址系统比较相似)。当用户发送一个报文时,这些报文就会发送到LAN上所有可用的机器。在一般情况下,网络上所有的机器都可以“听”到通过的流量,但对不属于自己的报文则不予响应(换句话说,工作站A不会捕获属于工作站B的数据,而是简单的忽略这些数据)。如果某在工作站的网络接口处于杂收模式,那么它就可以捕获网络上所有的报文和帧,如果一个工作站被配置成这样的方式,它(包括其软件)就是一个嗅探器。嗅探器可能造成的危害:■嗅探器能够捕获口令■能够捕获专用的或者机密的信息■可以用来危害网络邻居的安全,或者用来获取更高级别的访问权限事实上,如果你在网络上存在非授权的嗅探器就以为着你的系统已经暴露在别人面前了。一般我们只嗅探每个报文的前200到300个字节。用户名和口令都包含在这一部分中,这是我们关心的真正部分。工人,也可以嗅探给定接口上的所有报文,如果有足够的空间进行存储,有足够的那里进行处理的话,将会发现另一些非常有趣的东西。简单的放置一个嗅探器宾将其放到随便什么地方将不会起到什么作用。将嗅探器放置于被攻击机器或网络附近,这样将捕获到很多口令,还有一个比较好的方法就是放在网关上。如果这样的话就能捕获网络和其他网络进行身份鉴别的过程。这样的方式将成倍地增加我们能够攻击的范围。关于怎么抵御嗅探器的攻击,有三种方法可能会有所作用:■检测和消灭嗅探器■将数据隐藏,使嗅探器无法发现。■会话加密2.界面设计3.程序流程图4.主要代码分析在IpMonDlg.h中,首先定义一些协议相关的结构和宏。另外还会申明一个线程函数为友员函数,它负责监听网络数据报。代码及相关注释如下://定义协议的名称结构typedefstruct_PROTN2T{ intproto; char*pprototext;}PROTN2T;//协议数 #definePROTO_NUM11//IP头结构typedefstruct_IPHEADER{unsignedcharheader_len:4;unsignedcharversion:4;unsignedchartos;//服务类型unsignedshorttotal_len;//数据报大小unsignedshortident;//数据报标识unsignedshortflags;unsignedcharttl;unsignedcharproto;//协议(IP,TCP,UDP等)unsignedshortchecksum;unsignedintsourceIP;unsignedintdestIP;}IPHEADER;这里附加IP包头部结构图:16位16位版本IHL服务类型总长标识标志分段偏移生命期协议头校验和源地址目的地址选项(0或更多)#defineUDP_HEAD_LEN8 /*UDP头部长度*/#definePSEUDO_HEAD_LEN12 #defineICMP_HEAD_LEN4 /*ICMP头部长度*///TCP包头部结构structTCPPacketHead{ WORDSourPort; WORDDestPort; DWORDSeqNo; DWORDAckNo; BYTEHLen; BYTEFlag; WORDWndSize; WORDChkSum; WORDUrgPtr;};这里附加TCP包头部结构图:16位16位源端口目的端口顺序号确认号TCP头长(保留)7位URGACKPSHRSTSYNFIN窗口大小校验和紧急指针可选项(0或更多的32位字)数据(可选项)//ICMP包头部结构structICMPPacketHead{ BYTEType; BYTECode; WORDChkSum;};//UDP包头部结构structUDPPacketHead{ WORDSourPort; WORDDestPort; WORDLen; WORDChkSum;};这里附加UDP包头部结构图:16位16位源端口目的端口UDP长度UDP校验和//监听线程函数friendUINTthreadFunc(LPVOIDp);为程序流程的清晰起见,去掉了错误检查等保护性代码。主要代码实现清单为://检查Winsock版本号,WSAData为WSADATA结构对象

WSAStartup(MAKEWORD(2,2),&WSAData);

//创建原始套接字

sock=socket(AF_INET,SOCK_RAW,IPPROTO_RAW));

//设置IP头操作选项,其中flag设置为ture,亲自对IP头进行处理

setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag));

//获取本机名

gethostname((char*)LocalName,sizeof(LocalName)-1);

//获取本地IP地址

pHost=gethostbyname((char*)LocalName));

//填充SOCKADDR_IN结构

addr_in.sin_addr=*(in_addr*)pHost->h_addr_list[0];//IP

addr_in.sin_family=AF_INET;

addr_in.sin_port=htons(57274);

//把原始套接字sock绑定到本地网卡地址上

bind(sock,(PSOCKADDR)&addr_in,sizeof(addr_in));

//dwValue为输入输出参数,为1时执行,0时取消

DWORDdwValue=1;

//设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL

//的定义为:#defineSIO_RCVALL_WSAIOW(IOC_VENDOR,1)

ioctlsocket(sock,SIO_RCVALL,&dwValue);前面的工作基本上都是对原始套接字进行设置,在将原始套接字设置完毕,使其能按预期目的工作时,就可以通过recv()函数从网卡接收数据了,接收到的原始数据包存放在缓存RecvBuf[]中,缓冲区长度BUFFER_SIZE定义为65535。然后就可以根据前面对IP数据段头、TCP数据段头的结构描述而对捕获的数据包进行分析:while(true)

{

//接收原始数据包信息

intret=recv(sock,RecvBuf,BUFFER_SIZE,0);

if(ret>0)

{

//对数据包进行分析,并输出分析结果

ip=*(IP*)RecvBuf;

tcp=*(TCP*)(RecvBuf+ip.HdrLen);

TRACE("协议:%s\r\n",GetProtocolTxt(ip.Protocol));

TRACE("IP源地址:%s\r\n",inet_ntoa(*(in_addr*)&ip.SrcAddr));

TRACE("IP目标地址:%s\r\n",inet_ntoa(*(in_addr*)&ip.DstAddr));

TRACE("TCP源端口号:%d\r\n",tcp.SrcPort);

TRACE("TCP目标端口号:%d\r\n",tcp.DstPort);

TRACE("数据包长度:%d\r\n\r\n\r\n",ntohs(ip.TotalLen));

}

}其中,在进行协议分析时,使用了GetProtocolTxt()函数,该函数负责将IP包中的协议(数字标识的)转化为文字输出,该函数实现如下:#definePROTOCOL_STRING_ICMP_TXT"ICMP"

#definePROTOCOL_STRING_TCP_TXT"TCP"

#definePROTOCOL_STRING_UDP_TXT"UDP"

#definePROTOCOL_STRING_SPX_TXT"SPX"

#definePROTOCOL_STRING_NCP_TXT"NCP"

#definePROTOCOL_STRING_UNKNOW_TXT"UNKNOW"

……

CStringCSnifferDlg::GetProtocolTxt(intProtocol)

{

switch(Protocol){

caseIPPROTO_ICMP://1

returnPROTOCOL_STRING_ICMP_TXT;

caseIPPROTO_TCP://6

returnPROTOCOL_STRING_TCP_TXT;

caseIPPROTO_UDP://17

returnPROTOCOL_STRING_UDP_TXT;

default:

returnPROTOCOL_STRING_UNKNOW_TXT

温馨提示

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

最新文档

评论

0/150

提交评论