99网
您的当前位置:首页网络协议分析(论文)

网络协议分析(论文)

来源:99网
湖南城市学院毕业论文

※※※※※※※※※ ※2008届学生 ※

毕业设计(论文)材料 ※ ※※※※※(二)※

※※ ※※※

业 设

计(论

文)

课题名称

网络协议分析

姓 名 学 号 04001*20 院、系、部 计算机科学与技术系

专 业 网络工程

指导教师

2008年 5月 25 日

1

湖南城市学院毕业论文

材料清单

1、毕业设计(论文)课题任务书 2、毕业设计(论文)开题报告 3、指导教师评阅表 4、评阅教师评阅表 5、答辩及最终成绩评定表 6、毕业设计说明书 7、附录材料

2

湖南城市学院毕业论文

湖南城市学院

2008届毕业设计说明书

网络协议分析

院(系)、部: 计算机科学系 学生姓名: 指导教师: 职称 讲师 专 业: 计算机科学与技术 班 级: 04001班 完成时间: 2008年5月20日

3

湖南城市学院毕业论文

摘 要

嗅探器就是能够捕获网络报文的设备。嗅探器的正当用处在于分析网络的流量,以便找出所关心的网络中潜在的问题。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器来作出精确的问题判断。

嗅探器在功能和设计方面有很多不同。有些只能分析一种协议,而另一些可能能够分析几百种协议。

Socket是Windows下网络编程的标准接口,它允许两个或多个应用程序在相同机器上,或者是通过网络互相交流。

关键词 嗅探器;多线程;Socket;Visual C++ 6.0;MFC

ABSTRACT

Sniffer network is able to capture the text on the equipment. Sniffer is the legitimate use of network traffic, in order to identify the concerns of potential problems in the network. For example, if a certain period of operation of the network is not a very good, to send the text more slowly, but we do not know that the problem in any place at this time can be used sniffer to make accurate judgement of the issue.

Sniffer in function and design of a lot of different. Some can only be of an agreement, while others may be able to analysis of hundreds of agreement. Socket network programming under Windows is the standard interface, which allows two or more applications in the same machine, or through the Internet exchange.

Key words snifffer;multithreading;Socket;Visual C++ 6.0;MFC

4

湖南城市学院毕业论文

目 录

摘 要 ································ 4 1 前言 ······························· 7

1.1 项目开发背景 ························ 7 1.2 项目开发目标 ························ 7 1.3 几个关键技术 ························ 7

1.3.1 多线程编程 ······················ 7 1.3.2 Socket编程 ······················ 8 1.3.3 MFC编程 ······················· 12

2 开发工具Visual C++简介 ····················· 13 3 需求分析 ···························· 14

3.1 整体需求分析 ······················· 14 3.2 具体应用分析 ······················· 14

3.2.1 网络抓包及协议分析需求分析 ············· 14 3.2.2 本地网络信息获取需求分析 ·············· 15 3.2.3 端口扫描需求分析 ·················· 15 3.2.4 域名查询需求分析 ·················· 15 3.3 可行性研究 ························ 15

3.3.1 技术方面 ······················ 15 3.3.2 经济方面 ······················ 15 3.3.3 工作难点 ······················ 15

4.系统总体结构设计 ························· 16

4.1 软件模块结构设计 ····················· 16

4.1.1 软件工作模式图 ··················· 16 4.1.2 软件模块结构图 ··················· 16

5.系统详细设计 ··················· 错误!未定义书签。

5.1 嗅探器 ·························· 18

5

湖南城市学院毕业论文

5.1.1 嗅探器简介 ·············· 错误!未定义书签。 5.1.2 界面设计 ······················· 18 5.1.3 程序流程图 ·············· 错误!未定义书签。 5.1.4 主要代码分析 ············· 错误!未定义书签。 5.2 本地网络信息浏览 ·············· 错误!未定义书签。

5.2.1 界面设计 ······················ 19 5.2.2 程序流程图 ············· 错误!未定义书签。 5.2.3 主要代码分析 ···················· 19 5.3 端口扫描 ························· 24

5.3.1 界面设计 ······················ 24 5.3.2 程序流程图 ····················· 24 5.3.3 主要代码分析 ···················· 24 5.4 域名分析 ························· 25

5.4.1 主要代码分析 ···················· 25

6 系统的安装与调试 ························ 26

6.1 系统的安装 ························ 26 6.2 系统的调试 ························ 26 7 结束语 ····························· 27 参考文献 ······························ 28 致 谢 ······························· 28 附 录 ······························· 29

6

湖南城市学院毕业论文

1 前言

1.1 项目开发背景

随着计算机网络的不断普及,网络管理的应用需求越来越大,而嗅探器很早就在此领域发挥着重要的作用。嗅探器的种类繁多,有的是专门的某一个协议的分析器,有的则具有强大的功能,如非常著名的Ethereal,NetXRay和 Sniffer等。而这些大型的嗅探器需要昂贵的价格购买,对于小型网络则有“大材小用”之弊。所以,针对小型网络的简易实用的嗅探器应运而生。这里,我们的网络协议分析工具就是应用于小型局域网的管理,对其进行基于数据抓包的监控,包括本地局域网行为的实时查看,从而满足小型局域网如学校机房,公司部门,单位等这样规模的网络的监管及网络信息获取。

1.2 项目开发目标

本项目开发的目标是开发出实用于规模不大的局域网的监控于管理。监控就是实时对网络的行为进行监视从而获取采取控制行为所需的信息。管理是基于网络信息的掌握而产生的,我们提供了本地网络信息快速获取的工具,域名查询的实用工具,以观察本地主机的行为,另外我们还提供了端口扫描的功能,使监视能力更加强大。总之,我们的开发目标是满足小型网络的信息获取和行为监管。

1.3 几个关键技术

1.3.1 多线程编程

(1) 多线程处理的优点

同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成的任务,因此可以在以下方面显著提高性能:

· 多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的

同时一直处于活动状态。

· 当前没有进行处理的任务可以将处理器时间让给其他任务。

7

湖南城市学院毕业论文

· 占用大量处理时间的任务可以定期将处理器时间让给其他任务。 · 可以随时停止任务。

· 可以分别设置各个任务的优先级以优化性能。

是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:

· 耗时或大量占用处理器的任务阻塞用户界面操作。

· 各个任务必须等待外部资源(如远程文件或 Internet 连接)。 例如,用于跟踪 Web 页上的链接并下载满足特定条件的文件的 Internet 应用程序“robot”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程 Web 服务器的响应非常慢,也可以下载文件。

(2) 多线程编程的难点

当多个线程之间有联系的时候,线程之间的同步控制就会成为一个难点,因为没有人能预期线程的被执行。在一个合作型多任务系统中,操作系统必须得到程序的允许才能够改变线程。但是在强制性多任务系统中,控制权被调度程序强制转移,也因此两个线程之间的执行次序变得不可预期。这不可预期性造成了所谓的race condition。由于资源是共享的,有时还会出现死锁。

1.3.2 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)为了更好地说明套接字编程原理,下面给出几个基本套接字系统调用说明。

8

湖南城市学院毕业论文

①创建套接字──socket()

应用程序在使用套接字前,首先必须拥有一个套接字,系统调用socket()向应用程序提供创建套接字的手段,其调用格式如下:

SOCKET PASCAL FAR socket(int af, int type, int protocol);

该调用要接收三个参数:af、type、protocol。参数af指定通信发生的区域,UNIX系统支持的地址族有:AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中仅支持AF_INET,它是网际网区域。因此,地址族与协议族相同。参数type 描述要建立的套接字的类型。参数protocol说明该套接字使用的特定协议,如果调用者不希望特别指定使用的协议,则置为0,使用默认的连接模式。根据这三个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。

②指定本地地址──bind()

当一个套接字用socket()创建后,存在一个名字空间(地址族),但它没有被命名。bind()将套接字地址(包括本地主机地址和本地端口地址)与所创建的套接字号联系起来,即将名字赋予套接字,以指定本地半相关。其调用格式如下: int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen); 参数s是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。参数name 是赋给套接字s的本地地址(名字),其长度可变,结构随通信域的不同而不同。namelen表明了name的长度。

如果没有错误发生,bind()返回0。否则返回值SOCKET_ERROR。

地址在建立套接字通信过程中起着重要作用,作为一个网络应用程序设计者对套接字地址结构必须有明确认识。例如,UNIX BSD有一组描述套接字地址的数据结构,其中使用TCP/IP协议的地址结构为: struct sockaddr_in{

short sin_family; /*AF_INET*/

u_short sin_port; /*16位端口号,网络字节顺序*/ struct in_addr sin_addr; /*32位IP地址,网络字节顺序*/ char sin_zero[8]; /*保留*/ }

③建立套接字连接──connect()与accept()

这两个系统调用用于完成一个完整相关的建立,其中connect()用于建立连接。无连接的套接字进程也可以调用connect(),但这时在进程之间没有实际的报文交

9

湖南城市学院毕业论文

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

connect()的调用格式如下:

int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR * name, int namelen);

参数s是欲建立连接的本地套接字描述符。参数name指出说明对方套接字地址结构的指针。对方套接字地址长度由namelen说明。

如果没有错误发生,connect()返回0。否则返回值SOCKET_ERROR。在面向连接的协议中,该调用导致本地系统和外部系统之间连接实际建立。

由于地址族总被包含在套接字地址结构的前两个字节中,并通过socket()调用与某个协议族相关。因此bind()和connect()无须协议作为参数。

accept()的调用格式如下:

SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);

参数s为本地套接字描述符,在用做accept()调用的参数前应该先调用过listen()。addr 指向客户方套接字地址结构的指针,用来接收连接实体的地址。addr的确切格式由套接字创建时建立的地址族决定。addrlen 为客户方套接字地址的长度(字节数)。如果没有错误发生,accept()返回一个SOCKET类型的值,表示接收到的套接字的描述符。否则返回值INVALID_SOCKET。

accept()用于面向连接服务器。参数addr和addrlen存放客户方的地址信息。调用前,参数addr 指向一个初始值为空的地址结构,而addrlen 的初始值为0;调用accept()后,服务器等待从编号为s的套接字上接受客户连接请求,而连接请求是由客户方的connect()调用发出的。当有连接请求到达时,accept()调用将请求连接队列上的第一个客户方套接字地址及长度放入addr 和addrlen,并创建一个与s有相同特性的新套接字号。新的套接字可用于处理服务器并发请求。

④四个套接字系统调用,socket()、bind()、connect()、accept(),可以完成一个完全五元相关的建立。socket()指定五元组中的协议元,它的用法与是否为客户或服务器、是否面向连接无关。bind()指定五元组中的本地二元,即本地主机地址和端口号,其用法与是否面向连接有关:在服务器方,无论是否面向连接,均要调用bind();在客户方,若采用面向连接,则可以不调用bind(),而通过connect()自动完成。若采用无连接,客户方必须使用bind()以获得一个唯一的地址。

10

湖南城市学院毕业论文

以上讨论仅对客户/服务器模式而言,实际上套接字的使用是非常灵活的,唯一需遵循的原则是进程通信之前,必须建立完整的相关。

监听连接──listen()

此调用用于面向连接服务器,表明它愿意接收连接。listen()需在accept()之前调用,其调用格式如下:

int PASCAL FAR listen(SOCKET s, int backlog);

参数s标识一个本地已建立、尚未连接的套接字号,服务器愿意从它上面接收请求。backlog表示请求连接队列的最大长度,用于排队请求的个数,目前允许的最大值为5。如果没有错误发生,listen()返回0。否则它返回SOCKET_ERROR。 listen()在执行调用过程中可为没有调用过bind()的套接字s完成所必须的连接,并建立长度为backlog的请求连接队列。

调用listen()是服务器接收一个连接请求的四个步骤中的第三步。它在调用socket()分配一个流套接字,且调用bind()给s赋于一个名字之后调用,而且一定要在accept()之前调用。

accept()调用为实现并发服务提供了极大方便,因为它要返回一个新的套接字号

⑤数据传输──send()与recv() 当一个连接建立以后,就可以传输数据了。常用的系统调用有send()和recv()。 send()调用用于在参数s指定的已连接的数据报或流套接字上发送输出数据,格式如下:

int PASCAL FAR send(SOCKET s, const char FAR *buf, int len, int flags); 参数s为已连接的本地套接字描述符。buf 指向存有发送数据的缓冲区的指针,其长度由len 指定。flags 指定传输控制方式,如是否发送带外数据等。如果没有错误发生,send()返回总共发送的字节数。否则它返回SOCKET_ERROR。

recv()调用用于在参数s指定的已连接的数据报或流套接字上接收输入数据,格式如下:

int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int flags); 参数s 为已连接的套接字描述符。buf指向接收输入数据缓冲区的指针,其长度由len 指定。flags 指定传输控制方式,如是否接收带外数据等。如果没有错误发生,recv()返回总共接收的字节数。如果连接被关闭,返回0。否则它返回SOCKET_ERROR。

11

湖南城市学院毕业论文

⑥输入/输出多路复用──select()

select()调用用来检测一个或多个套接字的状态。对每一个套接字来说,这个调用可以请求读、写或错误状态方面的信息。请求给定状态的套接字集合由一个fd_set结构指示。在返回时,此结构被更新,以反映那些满足特定条件的套接字的子集,同时, select()调用返回满足条件的套接字的数目,其调用格式如下: int PASCAL FAR select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout); 参数nfds指明被检查的套接字描述符的值域,此变量一般被忽略。

参数readfds指向要做读检测的套接字描述符集合的指针,调用者希望从中读取数据。参数writefds 指向要做写检测的套接字描述符集合的指针。exceptfds指向要检测是否出错的套接字描述符集合的指针。timeout指向select()函数等待的最大时间,如果设为NULL则为阻塞操作。select()返回包含在fd_set结构中已准备好的套接字描述符的总数目,或者是发生错误则返回SOCKET_ERROR。

使用TCP创建网络应用程序稍微复杂一些,因为TCP是面向连接的协议,需要通信双方首先建立一个连接,而UDP编程则相对简单些。

Winsock的编程步骤是比较固定的,一般分以下几个步骤:套接字的创建和关闭;绑定套接字到指定的IP地址和端口号;设置套接字进入监听状态;接受连接请求;收发数据。

1.3.3 MFC编程

如果你曾经使用过传统的windows编程方法开发应用程序,你会深刻地体会到,即使是开发一个简单的windows应用程序也需要对windows的编程原理有很深刻的认识,同时也要手工编写很多的代码。因为程序的出错率几乎是随着代码长度的增加呈几何级数增长的,这就使得调试程序变得非常困难。所以传统的windows编程是需要极大的耐心和丰富的编程经验的。

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

MFC的英文全称是Microsoft Fundation Classes,即微软的基本类库,MFC的

12

湖南城市学院毕业论文

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

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

最后要指出的是MFC类库在提供的对象的各种属性和方法都是经过谨慎的编写和严格的测试,可靠性很高,这就保证了使用MFC类库不会影响程序的可靠性和正确性。

2 开发工具Visual C++简介

Visual C++是一个功能强大的可视化软件开发工具。自1993年Microsoft公司推出Visual C++1.0后,随着其新版本的不断问世,Visual C++已成为专业程序员进行软件开发的首选工具。

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

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

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

13

湖南城市学院毕业论文

(1) Developer Studio,这是一个集成开发环境,我们日常工作的99%都是在它上面完成的,再加上它的标题赫然写着“Microsoft Visual C++”,所以很多人理所当然的认为,那就是Visual C++了。其实不然,虽然Developer Studio提供了一个很好的编辑器和很多Wizard,但实际上它没有任何编译和链接程序的功能,真正完成这些工作的幕后英雄后面会介绍。我们也知道,Developer Studio并不是专门用于VC的,它也同样用于VB,VJ,VID等Visual Studio家族的其他同胞兄弟。所以不要把Developer Studio当成Visual C++, 它充其量只是Visual C++的一个壳子而已。这一点请切记! (2) MFC。从理论上来讲,MFC也不是专用于Visual C++,Borland C++,C++Builder和Symantec C++同样可以处理MFC。同时,用Visual C++编写代码也并不意味着一定要用MFC,只要愿意,用Visual C++来编写SDK程序,或者使用STL,ATL,一样没有。不过,Visual C++本来就是为MFC打造的,Visual C++中的许多特征和语言扩展也是为MFC而设计的,所以用Visual C++而不用MFC就等于抛弃了Visual C++中很大的一部分功能。但是,Visual C++也不等于MFC。

(3) Platform SDK。这才是Visual C++和整个Visual Studio的精华和灵魂,虽然我们很少能直接接触到它。大致说来,Platform SDK是以Microsoft C/C++编译器为核心(不是Visual C++,看清楚了),配合MASM,辅以其他一些工具和文档资料。上面说到Developer Studio没有编译程序的功能,那么这项工作是由谁来完成的呢?是CL,是NMAKE,和其他许许多多命令行程序,这些我们看不到的程序才是构成Visual Studio的基石。

3 需求分析

3.1 整体需求分析

小型局域网的管理不可能使用Ethereal,NetXRay和 Sniffer等大型嗅探器,但又需要有经济实用的网络数据抓包及协议分析工具,这里,不仅要求此工具具有一般协议分析器的通用功能,即对网络中的所有主机的嗅探和行为分析,而且要配备一些实用的网络信息查询辅助工具,包括内网和的一些信息,使之有所联系。

3.2 具体应用分析

3.2.1 网络抓包及协议分析需求分析

如何对网络中的所有行为做到实时监控?这就需要对网络中的所有数据包都能获取继而进行协议分析,这样才能获取有用的信息。所以在本软件中此模块为主题功能,即主要模块,担任对总体把握和实时监控的功能。

14

湖南城市学院毕业论文

3.2.2 本地网络信息获取需求分析

对于一个网管,获取本地网络的全部或一个地址段的一组包括IP地址,主机名,物理地址,用户信息及其所在工作组的信息是非常有用的,甚至是必须的。基于这种需求,我们提供了这样的工具,即本模块所实现的具有获取本地网络信息功能的工具。

3.2.3 端口扫描需求分析

网络通信的最终地址就不仅仅是主机地址了,还包括可以描述进程的某种标识符。为此,TCP/IP协议提出了协议端口(protocol port,简称端口)的概念,用于标识通信的进程。网络通信的最终地址就不仅仅是主机地址了,还包括可以描述进程的某种标识符。为此,TCP/IP协议提出了协议端口的概念,用于标识通信的进程。 所以,扫描端口的信息对网络行为的分析有着至关重要的作用。这里我们在主模块的基础上提供了功能更强大的端口扫描工具,具有主机选择和端口号指定扫描功能。为网管提供更有针对性的扫描工具。

3.2.4 域名查询需求分析

DNS是网络信息更直观,这里也是出于这种考虑,提供给使用者一个辅助查询工具,相信它将对使用者有所助益。主要是考虑到软件完善性而加入的小模块。

3.3 可行性研究

3.3.1 技术方面

Visual C++ 6.0提供了功能强大的开发平台,使得程序界面的实现简单、快速、标准。Winsock为Windows网络编程提供了丰富的接口技术,结合多线程技术,使得此处的基于TCP/IP网络编程具有良好的健壮性和强大的可扩展性。本软件最后所生成的.EXE可执行文件具有很好的可移植性。

3.3.2 经济方面

开发本软件我们只需要至少两台可以互相通信(在一个网络中)的计算机,而这样的开发条件是很容易满足的,所以本软件的开发成本是非常低的。具有良好的经济性。

3.3.3 工作难点

开发本软件主要要研究和解决的问题有: (1) 多线程编程

使用多线程编程是为了使程序的响应速度更快,在使用时应注意避免出现资源竞争和死锁的出现。

(2) Socket编程

Socket编程主要提供标准的网络编程接口,使得两个或多个应用程序在同一台

15

湖南城市学院毕业论文

电脑上,或者是通过网络相互交流。使得本软件中基于IP协议的TCP、 UTP、ICMP和ARP等协议的编程得以实现。

⑶ 界面设计

界面中各个控件的布局以及消息响应函数的编写是贯穿整个工程的一项重要的工作。它也在整个工程设计的过程中耗费了我们很多经历。

4.系统总体结构设计

4.1 软件模块结构设计

4.1.1 软件工作模式图

安装本软件的主机(服务器)

(客户机)

图4.1 工作模式图

4.1.2 软件模块结构图

数据抓包及协议分析(主程序域名查询 本地计算机信息浏端口扫图4.2 软件结构图

16

湖南城市学院毕业论文

4.1.3 软件设计结构图

服务器方 客户方 Socket(),建立流式套接字,返回套接字句柄Bind(),关联一个本地地址到套接字sListen。 Listen(),设置backlog值,进入监听状态。 Socket(),建立流式套接字s。 Accept(),等待接受客户连接请求。 Connect(),将套接字s与服务器连接。 建立连接,accept函数返回,得到新的套接字,Recv()/send(),在套接Recv()/send(),在套接字上收发数据,直到完成字sClient上收发数据,直到完成交换。 Closesocket(),关闭套接字s,结束TCP对话。 Closesocket(),关闭套接字sClient。 Closesocket(),关闭监听套接字sListen,服务

17

湖南城市学院毕业论文

5.系统详细设计

5.1 嗅探器

5.1.1 嗅探器简介

嗅探器(snifffer)就是能够捕获网络报文的设备。嗅探器的正当用处在于分析网络的流量,以便找出所关心的网络中潜在的问题。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器来作出精确的问题判断。

嗅探器在功能和设计方面有很多不同。有些只能分析一种协议,而另一些可能能够分析几百种协议。一般情况下,大多数的嗅探器至少能够分析下面的协议: ■标准以太网 ■TCP/IP ■IPX ■DECNet

嗅探器通常是软硬件的结合。专用的嗅探器价格非常昂贵。另一方面,免费的嗅探器虽然不需要花什么钱,但得不到什么支持。

嗅探器与一般的键盘捕获程序不同。键盘捕获程序捕获在终端上输入的键值,而嗅探器则捕获真实的网络报文。嗅探器通过将其置身于网络接口来达到这个目的——例如将以太网卡设置成杂收模式。(为了理解杂收模式是怎么回事,先解释局域网是怎么工作的)。

数据在网络上是以很小的称为帧(Ftame)的单位传输的帧由好几部分组成,不同的部分执行不同的功能。(例如,以太网的前12个字节存放的是源和目的的地址,这些位告诉网络:数据的来源和去处。以太网帧的其他部分存放实际的用户数据、TCP/IP的报文头或IPX报文头等等)。

帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上。通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧的到达,然后对其进行存储。就是在这个传输和接收的过程中,嗅探器会造成安全方面的问题。

每一个在LAN上的工作站都有其硬件地址。这些地址唯一地表示着网络上的机器(这一点于Internet地址系统比较相似)。当用户发送一个报文时,这些报文就会发送到LAN上所有可用的机器。

在一般情况下,网络上所有的机器都可以“听”到通过的流量,但对不属于自己的报文则不予响应(换句话说,工作站A不会捕获属于工作站B的数据,而是简单的忽略这些数据)。

如果某在工作站的网络接口处于杂收模式,那么它就可以捕获网络上所有的报文和帧,如果一个工作站被配置成这样的方式,它(包括其软件)就是一个嗅探器。

嗅探器可能造成的危害:

■嗅探器能够捕获口令

■能够捕获专用的或者机密的信息

18

湖南城市学院毕业论文

■可以用来危害网络邻居的安全,或者用来获取更高级别的访问权限

事实上,如果你在网络上存在非授权的嗅探器就以为着你的系统已经暴露在别人面前了。 一般我们只嗅探每个报文的前200到300个字节。用户名和口令都包含在这一部分中,这是我们关心的真正部分。工人,也可以嗅探给定接口上的所有报文,如果有足够的空间进行存储,有足够的那里进行处理的话,将会发现另一些非常有趣的东西。

简单的放置一个嗅探器宾将其放到随便什么地方将不会起到什么作用。将嗅探器放置于被攻击机器或网络附近,这样将捕获到很多口令,还有一个比较好的方法就是放在网关上。如果这样的话就能捕获网络和其他网络进行身份鉴别的过程。这样的方式将成倍地增加我们能够攻击的范围。

关于怎么抵御嗅探器的攻击,有三种方法可能会有所作用: ■检测和消灭嗅探器

■将数据隐藏,使嗅探器无法发现。 ■会话加密

5.1.2 界面设计

5.1.3 程序流程图 5.1.4 主要代码分析

在IpMonDlg.h中,首先定义一些协议相关的结构和宏。另外还会申明一个线程函数为友员函数,它负责监听网络数据报。代码及相关注释如下:

19

湖南城市学院毕业论文

//定义协议的名称结构 typedef struct _PROTN2T {

int proto ;

char *pprototext ; }PROTN2T ;

// 协议数 #define PROTO_NUM 11

//IP头结构

typedef struct _IPHEADER {

unsigned char header_len:4; unsigned char version:4;

unsigned char tos; //服务类型 unsigned short total_len; // 数据报大小 unsigned short ident; // 数据报标识 unsigned short flags; unsigned char ttl;

unsigned char proto; // 协议( IP , TCP, UDP 等) unsigned short checksum; unsigned int sourceIP; unsigned int destIP;

}IPHEADER;

这里附加IP包头部结构图: 16位 16位 版本 IHL 服务类型 总长 标识 标志 分段偏移 生命期 协议 头校验和 源地址 目的地址 选项(0或更多)

#define UDP_HEAD_LEN 8 /* UDP 头度 */

#define PSEUDO_HEAD_LEN 12

#define ICMP_HEAD_LEN 4 /* ICMP头度 */ //TCP包头部结构

struct TCPPacketHead { WORD SourPort; WORD DestPort;

20

湖南城市学院毕业论文

DWORD SeqNo; DWORD AckNo; BYTE HLen; BYTE Flag; WORD WndSize; WORD ChkSum; WORD UrgPtr; };

这里附加TCP包头部结构图: 16位 16位 源端口 目的端口 顺序号 确认号 TCP头(保留)7URG ACK PSH RST SYN FIN 窗口大小 长 位 校验和 紧急指针 可选项(0或更多的32位字) 数据(可选项)

//ICMP包头部结构

struct ICMPPacketHead { BYTE Type; BYTE Code; WORD ChkSum; };

//UDP包头部结构

struct UDPPacketHead { WORD SourPort; WORD DestPort; WORD Len; WORD ChkSum; };

这里附加UDP包头部结构图: 16位 16位 源端口 目的端口 UDP长度 UDP校验和 //监听线程函数

friend UINT threadFunc ( LPVOID p ) ;

21

湖南城市学院毕业论文

为程序流程的清晰起见,去掉了错误检查等保护性代码。主要代码实现清单为: // 检查 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时取消 DWORD dwValue = 1;

// 设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL // 的定义为: #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1) ioctlsocket(sock, SIO_RCVALL, &dwValue);

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

// 接收原始数据包信息

int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0); if (ret > 0) {

// 对数据包进行分析,并输出分析结果 ip = *(IP*)RecvBuf;

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

TRACE(\"协议: %s\\r\\n\

TRACE(\"IP源地址: %s\\r\\n\TRACE(\"IP目标地址: %s\\r\\n\TRACE(\"TCP源端口号: %d\\r\\n\TRACE(\"TCP目标端口号:%d\\r\\n\

22

湖南城市学院毕业论文

TRACE(\"数据包长度: %d\\r\\n\\r\\n\\r\\n\} }

其中,在进行协议分析时,使用了GetProtocolTxt()函数,该函数负责将IP包中的协议(数字标识的)转化为文字输出,该函数实现如下: #define PROTOCOL_STRING_ICMP_TXT \"ICMP\" #define PROTOCOL_STRING_TCP_TXT \"TCP\" #define PROTOCOL_STRING_UDP_TXT \"UDP\" #define PROTOCOL_STRING_SPX_TXT \"SPX\" #define PROTOCOL_STRING_NCP_TXT \"NCP\" #define PROTOCOL_STRING_UNKNOW_TXT \"UNKNOW\" „„

CString CSnifferDlg::GetProtocolTxt(int Protocol) {

switch (Protocol){ case IPPROTO_ICMP : //1

return PROTOCOL_STRING_ICMP_TXT; case IPPROTO_TCP : //6

return PROTOCOL_STRING_TCP_TXT; case IPPROTO_UDP : //17 return PROTOCOL_STRING_UDP_TXT; default:

return PROTOCOL_STRING_UNKNOW_TXT; }

最后,为了使程序能成功编译,需要包含头文件winsock2.h和ws2tcpip.h。另外,由于捕获到的数据包头不包含有帧信息,因此不能接收到与 IP 同属网络层的其它数据包, 如 ARP数据包、RARP数据包等。

23

湖南城市学院毕业论文

5.2 本地网络信息浏览

5.2.1 界面设计

5.3.2 程序流程图 5.3.3 主要代码分析

24

湖南城市学院毕业论文

5.3 端口扫描

5.3.1 界面设计

5.3.2 程序流程图 5.3.3 主要代码分析

5.4 域名分析

5.4.1 界面设计

25

湖南城市学院毕业论文

5.4.2 程序流程图 5.4.3 主要代码分析

6 系统的安装与调试

6.1 系统的安装

本系统是基于Visual C++ 6.0开发出来的,生成的是.EXE格式的可以在Windows

环境下直接运行的可执行文件。所以我们避免了麻烦的安装向导,将文件用WinRAR压缩。安装时用户直接解压到硬盘上即可使用。

6.2 系统的调试

调试环境:安装在Windows XP下的Visual C++ 6.0的Debug工具。

26

湖南城市学院毕业论文

调试结果:在调试过程中有两个问题,一个是网络协议分析器主界面的ListBox控件中数据列不支持中文,一个是在端口扫描模块中,树形表中无法在扫描的端口后输出对应的中文服务信息,以更直观的信息反馈给使用者。除了这两个问题还有待完善外,程序基本上没有问题。并在多个网络中运行成功。

7 结束语

这次毕业设计一开始,在吴湘华老师的指导下,通过对设计任务的分析和查找相关的技术资料,我们很快就确定了一个初步的设计方案。在接下来的设计日程中,在老师的耐心指导下,我们按照设计任务书中的进度有条不紊的完成了任务。通过这次毕业设计,让我学到了很多东西,了解了多线程编和socket编程,熟悉了使用VC++ 6.0开发平台。同时我也充分认识到,不管做什事,都要有科学严谨的态度,勤奋务实的作风,埋头苦干的精神。最重要的是要有一种坚定的信念,不轻易说放弃。相信自己,要做就做得最好。

这个网络协议分析系统的开发基本上达到了预期的目标,功能基本上都已经实现,但是还存在很多不足的地方:

第一:只做了系统的内核,对于系统的界面没有美化。

第二:系统功能还不完善,主要是中文信息输出不充分,使得用户得到的反馈信息不直观,这是我最感到遗憾的地方。而且没有链接数据库使得本系统的价值大打折扣,因为时间和能力的关系,没能实现查询功能,这也足以让人感到缺憾。 另外,我还要感谢我的同学在这次毕业设计中给我的帮助。

最后,我要再次感谢吴老师这几年对我的教育和关怀,无论是专业知识还是做人做事,我都从您身上学到了很多东西。我将终身不忘老师对我的培养。

27

湖南城市学院毕业论文

参考文献

[1] (美)Roger S.Pressman.软件工程实践者的研究方法[M].(第5版).北京:

机械工业出版社,2002年

[2] (美)Microsoft Corporation. SQL Server 2000管理员指南[M].北京:科

学出版社,2001年

[3] 李存斌等.数据库应用技术——SQL Server 2000 简明教程[M].北京:中国

水利水电出版社,2004年

[4] 李代平等.SQL Server 2000数据库应用基础教程[M].北京:冶金工业出版社,

2001年

[5] 张志学..NET框架开发人员参考手册(数据库分册)[M].北京:清华大学出

版社,2001年

[6]Visual C++.NET开发指南与实例详析/王华 朱时银.北京:机械工业出版社,2003年

[7] http://blog.csdn.net/axes/archive/2005/03/11/316887.aspx 学用VC++ 进行Winsock编程

[8] http://www.vczx.com/tutorial/mfc/mfc12.php MFC教程 [9] http://www.cnblogs.com用Socket实现断点续传

致 谢

感谢吴湘华老师,他严谨细致、一丝不苟的作风一直是我工作、学习中的榜样;他循循善诱的教导和不拘一格的思路给予我无尽的启迪。

还要感谢何建新老师对我毕业设计中遇到的一些问题的指导,从而使我遇到的困难迎刃而解。谢谢何老师!

另外,我要感谢谢三德、胡科顺等同学对我的帮助和指点。没有他们的帮助和提供资料,对于我来说,要想在短短的三个月的时间里熟练掌握VC++ 6.0编程并完成毕业设计几乎是不可能的事情。

28

湖南城市学院毕业论文

附 录

1. 计算机源程序或资料

------------------------------------网络协议分析源码------------------------------------ 核心部分——监听线程函数 UINT threadFunc ( LPVOID p )

CIpmonDlg *pDlg = static_cast(p) ; char buf [1000] , *bufwork ; MSG msg ; int iRet ; DWORD dwErr ;

char *pSource , *pDest ; IPHEADER *pIpHeader ; in_addr ina ;

char szSource [16] , szDest[16] , szErr [ 50 ]; char *pLastBuf = NULL ;

int HdrLen, totallen; WORD sourport, destport;

struct TCPPacketHead *pTCPHead; struct ICMPPacketHead *pICMPHead; struct UDPPacketHead *pUDPHead; BYTE *pdata = NULL;

29

湖南城市学院毕业论文

PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE) ; pDlg->m_threadID = GetCurrentThreadId() ;

while( TRUE ) {

if( PeekMessage( &msg , 0 , WM_CLOSE,WM_CLOSE,PM_NOREMOVE ) ) {

closesocket( pDlg->m_s ) ; pDlg->m_threadID = 0 ; pDlg->m_start.EnableWindow(TRUE) ; break ; }

memset( buf , 0 , sizeof(buf) ) ;

iRet = recv( pDlg->m_s , buf , sizeof( buf ) , 0 ) ; if( iRet == SOCKET_ERROR ) {

dwErr = WSAGetLastError() ;

sprintf( szErr , \"Error recv() = %ld \" , dwErr ) ; continue ; } else

if( *buf ) {

30

湖南城市学院毕业论文

bufwork = buf ;

pIpHeader = (IPHEADER *)bufwork ; WORD iLen = ntohs(pIpHeader->total_len) ; while( TRUE ) {

if( iLen <= iRet ) {

ina.S_un.S_addr = pIpHeader->sourceIP ; pSource = inet_ntoa( ina ) ; strcpy( szSource , pSource ) ; ina.S_un.S_addr = pIpHeader->destIP ; pDest = inet_ntoa( ina ) ; strcpy( szDest , pDest ) ;

CString str, strProto, strSourPort, strDestPort, strData, strSize;

strProto = get_proto_name( pIpHeader->proto );

HdrLen = pIpHeader->header_len&0xf; HdrLen *= 4;

totallen = ntohs(pIpHeader->total_len); totallen-=HdrLen; switch(pIpHeader->proto) {

31

湖南城市学院毕业论文

case IPPROTO_ICMP: {

pICMPHead=(struct ICMPPacketHead *)(buf+HdrLen);

//strL4.Format(\" type:%d code:%d\\n\ strSourPort = \"-\"; strDestPort = \"-\"; pdata=((BYTE *)pICMPHead)+ICMP_HEAD_LEN;

totallen -= ICMP_HEAD_LEN; break; }

case IPPROTO_TCP: {

pTCPHead=(struct TCPPacketHead *)(buf+HdrLen);

sourport = ntohs(pTCPHead->SourPort); destport = ntohs(pTCPHead->DestPort); //strL4.Format(\" sour port:%d,dest port:%d\

strSourPort.Format(\"%d\ strDestPort.Format(\"%d\ HdrLen = (pTCPHead->HLen)>>4; //in fact only 4 bits

HdrLen *= 4;

32

湖南城市学院毕业论文

pdata=((BYTE *)pTCPHead)+HdrLen; totallen -= HdrLen; break; }

case IPPROTO_UDP: {

pUDPHead=(struct UDPPacketHead *)(buf+HdrLen);

sourport = ntohs(pUDPHead->SourPort); destport = ntohs(pUDPHead->DestPort); //strL4.Format(\" sour port:%d,dest port:%d\

strSourPort.Format(\"%d\ strDestPort.Format(\"%d\ pdata=((BYTE *)pUDPHead)+UDP_HEAD_LEN; totallen -= UDP_HEAD_LEN; break; } }

if(pIpHeader->proto == IPPROTO_ICMP) strData.Format(\"type:%d code:%d data:%s\ else strData.Format(\" %s\

strSize.Format(\"%d\

33

湖南城市学院毕业论文

pDlg->AddData(strProto,szSource,strSourPort,szDest,strDestPort,strSize,strData);

if( iLen < iRet ) {

iRet -= iLen ; bufwork += iLen ;

pIpHeader = (IPHEADER *)bufwork ; } else

break ; // pIpHeader->total_len == iRet and go out

} else

{ // read last part of buf. I wrote it , but always recv() read exactly

// the lenght of the packet int iLast = iLen - iRet ; pLastBuf = new char [ iLen ] ; int iReaden = iRet ;

memcpy( pLastBuf , bufwork , iReaden ) ; iRet = recv( pDlg->m_s , pLastBuf + iReaden , iLast , 0 ) ;

if( iRet == SOCKET_ERROR ) {

34

湖南城市学院毕业论文

dwErr = WSAGetLastError() ;

sprintf( szErr , \"Error recv() = %ld \" , dwErr ) ;

break ; } else {

bufwork = pLastBuf ;

pIpHeader = (IPHEADER *)bufwork ; if( iRet == iLast ) iRet = iLen ; else

{ // read all last data iReaden += iRet ; iLast -= iRet ; while( TRUE ) {

iRet = recv( pDlg->m_s , pLastBuf +iReaden , iLast , 0 ) ;

if( iRet == SOCKET_ERROR ) {

dwErr = WSAGetLastError() ;

sprintf( szErr , \"Error recv() = %ld \" , dwErr ) ;

break ; }

35

湖南城市学院毕业论文

else {

iReaden += iRet ; iLast -= iRet ; if( iLast <= 0 ) break ; } } // while } } } } // while if( pLastBuf )

delete [ ] pLastBuf ; } else {

AfxMessageBox( \"No data on network\" ) ; continue ; } }

return TRUE ; }

其余代码见光盘源程序

36

湖南城市学院毕业论文

37

因篇幅问题不能全部显示,请点此查看更多更全内容