基于Winpcap的网络数据包嗅探抓包和发包工具的设计与实现

Tattoo

发布日期: 2018-11-25 09:14:47 浏览量: 1375
评分:
star star star star star star star star star star
*转载请注明来自write-bug.com

摘 要

本文课题设计为基于WinPcap的开源网络数据处理工具程序包的设计与实现,使用MFC库和C++来实现。

本文首先说明了课题研究的目的、意义和网络监听的背景,讨论了在网络数据处理领域领先的工具以及当前网络学习的困难,以此引出了本课题研究的需求和可行性分析。然后分析了网络结构,重要网络协议和网络数据传输的基本原理,介绍基于WinPcap、MFC实现网络监听。接着罗列了本程序设计思路和架构,功能流程及其实现逻辑,自顶向下,结合源码逐一展开描述。最后将程序的功能测试及其结果进行展示。

关键词:网络协议,数据包,TCP/UDP,socket,ARP,WinPcap

ABSTRACT

This article is designed to subject the design and realization of WinPcap open source tool for network data processing package based on the use of MFC and C++ libraries to achieve.

This paper describes the purpose, significance and network monitoring research background ,discusses network data processing field-leading tools and the difficulty of the current network learning , this leads to the need for and feasibility of this research . Then it analyzes the basic principles of network architecture,network protocols, and important network data transmission introduced on WinPcap, MFC for network monitoring. Then a list of design ideas and architecture, functional flow of the program and its implementation logic ,top-down , one by one to start binding source description . Finally, the functions of the program and the test results show.

KEYWORDS:network protocol, datagram, TCP/UDP, socket, ARP, WinPcap

1 绪论

1.1 网络与监听

互联网时代与大数据时代的到来,愈发体现出了信息的快速增长与知识膨胀的力量。信息的不平等造就了当前这个时代的不平等,只有掌握了最新、最全的数据,才能在这个时代立足脚跟,快速前进。而网络,则是承载信息的天桥,伸手在信息的洪流中抓一把,逝去的会多于获得的,因此我们更加需要了解网络的结构和数据传输的协议、方式,以提供更高效的信息获取手段。

然而,随着计算机的普及,网络已成为人们生活中不可或缺的工具,随之而来的非法入侵也不断加剧着计算机网络系统的安全问题。正是由于以太网中采用广播方式,因此,在某个广播域中可以监听到该域所有的信息包,利用一定是技术手段,还能向外拓展,侵入其他网络。

网络监听是一种监视当前网络状态以及网络上数据传输的管理工具,它可以将计算机网卡设定成监听模式,从而获取该域网络上所传输的信息。对于网络管理员来说,网络监听技术可以用来查看、分析该域网络的性能和实时状态;对于入侵者来说,网络监听技术可以用来获得网络中传输的各种数据。为了保护网络信息的安全,必须采用网络监听技术进行反跟踪,时刻探明网络的安全现状,掌握先机,才能保证网络的信息安全。

目前,市场上针对不同版本的操作系统,有不同版本的网络数据监听软件,如 Window9x 平台的NetXray、Win2000/xp平台下的Sniffer Pro以及UNIX 平台Netman和SunSniff 等等。

其中要数翘楚的,有NAI公司推出的一款一流的网络管理和应用故障诊断分析软件Sniffer。不论是在有线网络还是在无线网络中,它都能够帮助网络管理人员进行实时的网络监视、数据包捕获以及故障诊断分析。对于在实时快速的网络问题故障诊断中,基于该便携式软件的解决方案具备很高的性价比,它能够让用户获得强大的网络管理和应用故障诊断能力。

说到Sniffer就不得不提Wireshark了,我校网络工程专业在本科三年级的网络协议学习中,就使用WireShark来帮助获取本机网络中的实时数据,以此学习分析TCP/IP等协议。WireShark(前称Ethereal)是一个免费开源的网络数据包分析软件。网络数据包分析软件的功能是截取网络数据包,并尽可能显示出最为详细的网络数据包数据。

以上介绍的均是由单纯软件实现的网络嗅探器,其功能相对硬件嗅探器来说还是较为简单。下面将罗列几款由硬件实现的网络嗅探器。硬件的网络嗅探器又称为网络分析仪(协议分析仪)。目前,网络分析仪的技术已经非常的成熟,产品种类繁多。但各种产品的功能略有差异,有的专精于某种协议,有的“包罗万象”。一般的情况下,大型的企业网络都会使用软硬件想结合的网络分析仪。如:1)安捷伦网络分析仪系统,2)Fluke Optiview 综合网络协议分析仪等。

1.2 研究意义

网络数据的传输、网络协议和网络结构对于计算机的使用者来说是透明的,它们非常重要但又十分复杂,需要初学者去好好了解和学习。然而,由于无法直观地获取到网络实时传输的数据,在课堂上学习到的都是相关的理论知识,对于学习者来说是无法具象化的,难以理解的。使用网络数据处理工具能解决这一问题,但是目前该领域的优秀工具使用起来步骤繁琐,在学习协议之前需要学习如何使用该工具,有着“先有鸡还是先有蛋”的矛盾,不适合网络协议的初学者使用。

因此,本着开源的精神来做一款工具,帮助了解、学习网络数据的传输、网络协议和网络结构。本毕业设计软件是基于OSI(Open System Interconnection)参考模型以及一些常用的网络协议,采用C++语言,使用MFC库、WinPcap库和Visualstudio 2012作为开发工具编写本软件。本系统操作界面简单大方,功能较为齐备。是一个简单实用的网络数据处理软件,本系统具有以下基本功能:

本机网卡扫描/选择,混杂模式抓包,协议过滤,数据包分析,数据包导入导出,自制ARP包。

本软件的目的重在抓取经过本机网卡的数据包,对其进行加工处理、分析展示,供初学者学习、参考。

2 网络数据处理工具需求分析

2.1 网络数据处理工具的需求分析

对于网络数据的处理,大部分软件或系统是不会直接读写该数据包的每一位的,因为有了各大协议的存在,它们只需要建立在OSI七层模型中的应用层就足够了。通过协议的转换,软件或系统可以从整个数据包中只读取需要的相应字段,之后再进行相应的数据处理。因此,在这里要说的是很重要的一部分功能,即捕获数据包。

业务需求:

  • 满足网络管理员对网络内流量的实时观察。
  • 满足学生对网络协议的学习和练习使用。
  • 扫描本机网卡和本网段内活跃主机信息。
  • 满足对网卡内流过的数据读写操作 。

性能需求:

  • 网卡混杂式捕获不造成2G内存计算机宕机。
  • 文件磁盘IO操作不造成软件奔溃。
  • 任何操作不造成GUI交互无响应。
  • 并发不造成内存泄露等问题。
  • 程序流程合理,不会造成逻辑上的死循环。

可靠、可用性需求:

  • 在规定的条件下,在规定的时间内,软件不引起系统失效的概率。
  • 在规定的时间周期内,在所述条件下程序执行所要求的功能的能力。

2.2 网络数据处理工具的可行性分析

在大部分传输介质上,网络信息的传输是有被截获、监听的可能性的。在网络上,实施监听最好的地方是在网关、路由器和防火墙一类的位置,因为这些位置是网络数据的汇聚节点,经常有大量的数据经过它们,但它们的防御措施也相应得做地更好。大多数黑客用来监听网络传输的地方是以太网中任何一台连网的主机上,因为这是监听最方便的地方,数量多、防御能力低。因此,本工具也打算从个人计算机入手,进行网络数据处理的第一步:网络监听。下面,将主要从经济可行性、技术可行性、运行可行性和操作可行性等方面进行分析本毕业设计。

2.2.1 经济可行性

开发该软件所需的相关资料可以通过文献资料和网络进行调查采集,所需的软件系统、硬件平台等都易于获得,无需特殊工具,开发成本低,简单易实现,从经济角度来看,开发该软件经济可行。

2.2.2 技术可行性

因为以太网是一种广播型的网络,且目前人们使用的因特网多是使用以太网技术来实现的,所以大多数网络数据的截获是可以在以太网上实现的,其中可以分为共享式以太网监听和交换式以太网监听。因此,从技术角度来说,以某一网络域中的计算机为节点,监听该域网络,这种方式是可行的。

2.2.3 运行可行性

运行性是对组织结构的影响。该软件界面简洁,操作十分简单,只需要相应的windows系统和动态库(都是可以下载获得的)就可以运行起来,所以从运行角度上看,该软件是可行的。

综上所述,该系统的开发从经济、技术、运行等方面完全可行。

2.2.4 操作可行性分析

开发所采用的工具是VisualStudio 2012,开发出的应用程序在windows系统的计算机上,以窗口的方式展现,接收鼠标和键盘的输入,以显示器为输出,符合当代计算机使用者的使用习惯,方便人们对网络数据的监视和处理,简单易上手。所以此软件在操作上是可行的。

3 网络数据处理工具开发相关知识

3.1 MFC框架的介绍

MFC(Microsoft Foundation Classes)是微软基础类库的简称,MFC提供了面向对象的框架,采用面向对象技术,将大部分的WindowsAPI 封装到C++类中,以类成员函数的形式提供给程序开发人员调用。

参见微软定义:https://msdn.microsoft.com/en-us/library/d06h2x6e.aspx

3.2 OSI模型简介

OSI(Open System Interconnection,开放系统互连)七层网络模型被称为开放式系统互联参考模型 ,是一个人为抽象的定义,它把网络概念从逻辑上分为了七层。 OSI 七层模型是一种框架性的设计,建立七层模型的主要目的,是为解决异种网络互连时所遇到的兼容性问题,分层的左右就是起到了“低耦合,高聚合”的效果。其最主要的功能就是帮助数据在不同类型的主机间实现传输。它的最大优点是将服务、接口和协议这三个抽象概念清晰地区分开来,通过七个层次化的结构模型使不同的系统不同的网络之间进行可靠的设备通讯。

  • 物理层:提供为建立、维护和拆除物理链路所需要的机械的、电气的、功能的和规程的特性 。
  • 数据链路层:负责网络寻址、错误侦测和修正等;提供数据链路的流控。
  • 网络层:决定数据的传输目的和寄转,添加网络表头(NH),如IP协议首部。
  • 传输层:添加传输表头(TH)形成数据包,如TCP协议首部。
  • 会话层:提供两进程之间建立、维护和结束会话连接的功能。
  • 表示层:转换数据格式使其与接收者系统兼容;完成数据转换、格式化和文本压缩。
  • 应用层:为应用软件而设定的层,不同软件有不同的通讯方式,如HTTP,FTP等。

3.3 网络协议简介

网络协议是为在计算机网络中进行数据交换而建立的规则、标准或约定的集合,由三个要素组成:

  • 语义:说明控制信息每个部分的意义。它规定了计算机需要发出何种控制信息,实现的的过程,以及做出何种响应。
  • 语法:用户数据与控制信息的相关结构、格式,以及各种意义数据出现的顺序。
  • 时序:对事件、协议发生顺序的详细说明。

人们形象地把这三个要素描述为:语义表示要做什么,语法表示要怎么做,时序表示什么时候做。

结合OSI模型,可以更好地理解抽象的“网络协议”这个概念,在硬件和软件的双重人为规定下,形成了各大网络协议。

3.3.1 数据包嵌套形式

数据通过OSI模型,被分片、包装、嵌套处理之后,最后形成了一个完整、符合以太网协议的数据包。

3.3.2 以太网协议首部说明

对应程序中的数据结构

  1. struct eth_hdr{
  2. u_char eth_tar[6];
  3. u_char eth_src[6];
  4. u_short eth_op;
  5. };

3.3.3 IP协议首部说明

字节和数字的存储顺序是从右到左,依次是从低位到高位(Big Endian),而 网络存储顺序是从左到右,依次从低位到高位(Little Endian)。

  • 版本:占第一个字节的高四位。头长度:占第一个字节的低四位。

  • 服务类型:前三位为优先字段权,现已忽略。接下来四位用来表示最小延迟、 最大吞吐量、最高可靠性和最小费用。

  • 封包总长度:整个 IP 报长度,单位为字节。

  • 存活时间:就是封包的生存时间。

  • 协议:定义了数据的协议,分别为:TCP、UDP、ICMP 和 IGMP。定义为:

    1. define PROTOCOL_TCP 0x06
    2. define PROTOCOL_UDP 0x11
    3. define PROTOCOL_ICMP 0x06
    4. define PROTOCOL_IGMP 0x06
  • 检验和:首先将该字段设置为0,然后将IP头的每16位进行二进制取反求和,将结果保存在校验和字段。

  • 来源IP地址:将来源IP地址看作是32位数值则需要将网络字节顺序转化位主机字节顺序。

  • 目的IP地址:将目的IP地址看作是32位数值则需要将网络字节顺序转化位主机字节顺序。

在网络协议中,IP协议是面向非连接的,所谓的面向非连接就是传递数据时,不检测网络是否连通,所以IP协议是不可靠的数据报协议。它主要负责在主机之间寻址和选择数据包路由。

对应程序中的数据结构

  1. typedef struct ip_header{
  2. u_char ver_ihl; // 版本 (4 bits) + 首部长度 (4 bits)
  3. u_char tos; // 服务类型(Type of service)
  4. u_short tlen; // 总长(Total length)
  5. u_short identification; // 标识(Identification)
  6. u_short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)
  7. u_char ttl; // 存活时间(Time to live)
  8. u_char proto; // 协议(Protocol)
  9. u_short crc; // 首部校验和(Header checksum)
  10. ip_address saddr; // 源地址(Source address)
  11. ip_address daddr; // 目的地址(Destination address)
  12. u_int op_pad; // 选项与填充(Option + Padding)
  13. }ip_header;

3.3.4 ICMP协议首部说明

  • 类型:一个8位类型字段,表示ICMP数据包类型(类型繁多,不一一列举)。
  • 代码:一个8位代码域,与类型组合,表示指定类型中的一个功能。如果一个类型中只有一种功能,代码域置为0。
  • 检验和:数据包中ICMP部分上的一个16位检验和。

对应程序中的数据结构

  1. typedef struct _ICMPHeader
  2. {
  3. UCHAR icmp_type; //消息类型
  4. UCHAR icmp_code; //代码
  5. USHORT icmp_checksum; //校验和
  6. //下面是回显头
  7. USHORT icmp_id; //用来惟一标识此请求的ID号,通常设置为进程ID
  8. USHORT icmp_sequence; //序列号
  9. ULONG icmp_timestamp; //时间戳
  10. }ICMPHeader,*PICMPHeader;

3.3.5 TCP协议首部说明

  • TCP源端口(Source Port):源端口和IP地址的是用来标识报文的发送地址。
  • TCP目的端口(Destination Port):16位的目的端口域指明报文接收计算机上的应用程序端口地址。
  • 序列号(Sequence Number):TCP连接发送方向接收方发送的封包顺序号,用于重组分片。
  • 确认序号(Acknowledge Number):接收方应答顺序号。
  • 头长度(HeaderLength):表示TCP头的双四字节数,转化为字节个数需乘以四。
  • URG:紧急指针标志位,0为不使用,1为使用。
  • ACK:请求/应答状态标志位。0为请求,1为应答。
  • PSH:以最快的速度传输数据标志位。
  • RST:连线复位标志位,先断开,再重建。
  • SYN:同步连线序号标志位,用来建立连线。
  • FIN:结束连线标志位。0是结束连线请求,1表示结束连线。
  • 窗口大小(Window):目的机使用十六位的域告诉源主机,它想收到的每个TCP数据段大小。
  • 校验和(CheckSum):这个校验和和IP的校验和不同,对首部数据和封包内容都进行校验。
  • 紧急指针(Urgent Pointer):当URG为1时才有效。

对应程序中的数据结构

  1. typedef struct _tcp_hdr
  2. {
  3. unsigned short src_port; //源端口号
  4. unsigned short dst_port; //目的端口号
  5. unsigned int seq_no; //序列号
  6. unsigned int ack_no; //确认号
  7. #if LITTLE_ENDIAN
  8. unsigned char reserved_1:4; //保留6位中的4位首部长度
  9. unsigned char thl:4; //tcp头部长度
  10. unsigned char flag:6; //6位标志
  11. unsigned char reseverd_2:2; //保留6位中的2位
  12. #else
  13. unsigned char thl:4; //tcp头部长度
  14. unsigned char reserved_1:4; //保留6位中的4位首部长度
  15. unsigned char reseverd_2:2; //保留6位中的2位
  16. unsigned char flag:6; //6位标志
  17. #endif
  18. unsigned short wnd_size; //16位窗口大小
  19. unsigned short chk_sum; //16位TCP检验和
  20. unsigned short urgt_p; //16为紧急指针
  21. }tcp_hdr;

3.3.6 UDP协议首部说明

  • 源端口(SourcePort):十六位的源端口域包含初发送方端口号。源端口和IP地址表示了报文的返回地址。
  • 目的端口(DestinationPort):六位的目的端口域定义传输的目的地。这个端口指明报文接收计算机上的应用程序端口地址。
  • 封包长度(Length):UDP首部和封包数据的总长度。
  • 校验和(CheckSum):和TCP校验和一样,不仅对首部数据进行校验,还对封包的内容进行校验。

对应程序中的数据结构

  1. typedef struct udp_header{
  2. u_short sport; // 源端口(Source port)
  3. u_short dport; // 目的端口(Destination port)
  4. u_short len; // UDP数据包长度(Datagram length)
  5. u_short crc; // 校验和(Checksum)
  6. }udp_header;

3.3.7 ARP协议首部说明

  • 硬件类型:指明了硬件接口类型,以太网的值为1;
  • 协议类型:指明了高层协议类型,IP为0x0800;
  • 硬件地址长度,协议长度:硬件地址和高层协议地址的长度,这样ARP报文就可以在任意硬件和任意协议的网络中使用;
  • 操作字段:报文的类型,ARP请求为1,ARP响应为2,RARP请求为3,RARP响应为4……;
  • 发送方硬件地址(0-3字节):源主机硬件地址的前3个字节;
  • 发送方硬件地址(4-5字节):源主机硬件地址的后3个字节;
  • 发送方IP地址(0-1字节):源主机硬件地址的前2个字节;
  • 发送方IP地址(2-3字节):源主机硬件地址的后2个字节;
  • 目的硬件地址(0-1字节):目的主机硬件地址的前2个字节;
  • 目的硬件地址(2-5字节):目的主机硬件地址的后4个字节;
  • 目的IP地址(0-3字节):目的主机的IP地址。

对应程序中的数据结构

  1. //28字节的ARP头
  2. typedef struct _ARPHeader
  3. {
  4. USHORT hrd; //硬件地址空间,以太网中为ARPHRD_EHER
  5. USHORT eth_type; //以太网类型,ETHERTYPE_IP
  6. UCHAR maclen; //MAC地址的长度,为6
  7. UCHAR iplen; //IP地址的长度,为4
  8. USHORT opcode; //操作代码,ARPOP_REWUEST为请求,ARPOP_REPLY为响应
  9. UCHAR smac[6]; //源MAC地址
  10. UCHAR saddr[4]; //源IP地址
  11. UCHAR dmac[6]; //目的MAC地址
  12. UCHAR daddr[4]; //目的IP地址
  13. }ARPHeader,*PARPHeader;

3.4 WinPcap简介

本工具所使用的WinPcap大大降低了本软件的开发难度。由于Window操作系统没有提供可以直接捕获网络传输数据包的API,尽管提供了一些内核模块接口,但存在着严重的局限性。例如:IP Filter Driver只运行在 Windows 2000 下,且仅支持IP协议;对内核的操作和对文件I/O的操作都带来了设计上和使用上的复杂度飙升;Windows内核的不透明等。由于这些局限,使得Windows平台下的网络安全管理和分析工具无论在数量上,还是质量上都与Unix下有很大的差距。为此,微软研究院赞助了意大利一家开发机构,为Win32平台底层网络分析开发了一套有力且易扩展的体系结构——WinPcap,它将Unix支持的数据包捕获功能移植到Win32系统中,从而弥补了Windows操作系统在网络分析方面的欠缺。而且WinPcap完全开放,提供源代码,同时它提供了与Libpcap相兼容的函数接口,是的程序代码在不同操作系统平台间的可读性大大提升。

WinPcap是一个基于Win32平台的,用于捕获数据包并进行网络分析的体系结构。它包括了一个内核级的数据包过滤器,一个低层的动态链接库(packet.dll),一个高层的,依赖于系统的动态链接库(wpcap.dll)。其结构图如下所示:

4 网络数据处理工具的设计

4.1 模块结构

本网络数据处理工具是一般的PC桌面软件,由于都是二进制的数据分包,不适合使用数据库来存储数据,因此没有使用数据库,而是直接转储为.CAP后缀文件。开发之初,在构思软件时设计了一套软件架构,从底层网卡获取数据开始,由WinPcap混杂式获取数据包,交由Filter层过滤数据,经过过滤层之后的数据由提供给用户界面的各个功能模块进行相应的数据处理:导出、展示、包装等。抛开该网络数据监听功能,还提供一个手动创建数据包并发送的功能接口,并将这些功能都统一交付给捕获器处理。

4.2 流程关系

本程序流程其实不复杂,只是有一些流程需要有上下级关系,有一些流程需要并行,有一些流程需要串行互斥。正如下图所示,和捕获网络数据包有关的流程都必须先设置需要捕获的本机网卡,因为,就算一台PC,也可能会有多张网卡的情况(目前而言,这种情况是多数)。接着,开始捕获的数据包会经过过滤层,也就是自定义的过滤条件。然后被程序中的分派器分配到不同的协议分析模型下,不同的协议分析模型会对相应的协议进行相同格式地解析,并将解析后的数据交由下一级处理:展示和转储。

上述所涉及到的流程是数据包捕获的主流程,下面说下其他功能流程:

  • 发包流程:在发包时,也必须选择用来发包的本机网卡(基本上都是以太网卡),然后手动填写相应协议的数据包格式,点击发包即可。这里需要对该协议每一个字段有一定的了解;
  • 导入导出流程:在导入导出流程中,不需要选择网卡(当然选择也是可以的),之后就是对文件的I/O操作和MFC的展示了,就不再多说;
  • 扫描本网段主机流程:同样需要选择网卡,然后在菜单中选择“scanhost”功能。由于本功能需要花费一定时间,同时不能与本工具的任意一个功能同步进行,所以需要等扫描结束,或者退出本次扫描,才能进行其他操作。

4.3 功能设计及分析

4.3.1 网卡扫描/选择

在软件打开的界面,选择WinPcap扫描出来的本机网卡。只有在选择了网卡之后,才能进行相应的数据操作。下拉条中列出了本机的所有网卡,选中一块网卡,下方的静态文本框会显示相应的描述信息。关键代码如下所示:

  1. /***********************adapterDlg.cpp***********************/
  2. /**
  3. * 单击combo box中条目时的回调函数
  4. */
  5. void CAdapterDlg::OnCbnSelchangeAdapterCombo()
  6. {
  7. //一些变量的声明和条件判断
  8. // 利用WinPcap遍历本机所有网卡,将用户选择的网卡存入adp_info对象中
  9. for (adp_info.usedDevs = adp_info.allDevs; adp_info.usedDevs; adp_info.usedDevs = adp_info.usedDevs->next){
  10. if (name == adp_info.usedDevs->name)
  11. {
  12. CString content = "Name: " + name + "\r\nDescription: " + adp_info.usedDevs->description;
  13. GetDlgItem(IDC_ADAPTER_EDIT)->SetWindowText(content);
  14. /**
  15. * 将具体信息存入适配器对象中
  16. */
  17. if ((adp_info.ahandler = pcap_open(adp_info.usedDevs->name, 65535,
  18. PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL,
  19. adp_info.errBuf)) == NULL)
  20. {
  21. MessageBox("Open the adapter failed.");
  22. }
  23. break;
  24. }
  25. }
  26. }

4.3.2 抓包

在选中网卡后,即可开始抓包。每捕捉到一条不满足过滤条件(不会被过滤)的数据包,就会在List Ctronller中显示,并根据实际封包数据,显示相应信息。如果单机选中某一条目,还会在下方的两个静态文本框内显示更详细的十六进制内容。如果双击条目,还能弹出详细信息框。

本功能在实现的时候,在多个层有不同功能代码。关键代码如下所示:

  1. /***********************captureDlg.cpp***********************/
  2. /**
  3. * 开始、停止抓包
  4. */
  5. void CcaptureDlg::OnBnClickedBegStp()
  6. {
  7. //一些变量的声明和条件判断
  8. //清空列表
  9. m_listctl.DeleteAllItems();
  10. //锁定“扫描主机”菜单
  11. GetMenu()->GetSubMenu(2)->EnableMenuItem(0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  12. //dump出去一个缓存包,这样内存就不用一直添加数据包内容了
  13. hThreadCapture = (HANDLE)_beginthreadex(NULL, 0, (THREAD_PROC)captureDataInfo, (LPVOID)this, 0, NULL);
  14. // 设置界面、功能锁定
  15. }

正如代码中判断的一样,根据adp_info对象中的isCapturing标志来表示是否进行多线程数据包捕获工作和转储、展示数据包工作。在开始捕获时,利用新的工作线程进行数据捕获处理,GUI线程依旧对用户提供快速响应。

  1. /***********************captureServiceImpl.cpp***********************/
  2. /**
  3. * 显示捕获的数据包内容
  4. *
  5. * @param lParam
  6. * @return
  7. */
  8. unsigned WINAPI captureDataInfo(LPVOID lParam)
  9. {
  10. //打开导出文件
  11. dumpfile = pcap_dump_open(adp_info.ahandler, lp->CapFilePath);
  12. while ((res = pcap_next_ex(adp_info.ahandler, &(adp_info.header), &(adp_info.pkt_data))) >= 0 && adp_info.isCapturing){
  13. // 读取并展示
  14. readAndDisplay(res, lp, dumpfile, nIndex);
  15. }
  16. pcap_dump_close(dumpfile);
  17. return 1;
  18. }
  1. /**
  2. * 展示数据
  3. *
  4. * @param res
  5. * @param lp
  6. * @param dumpFile
  7. * @param nIndex
  8. */
  9. void readAndDisplay(int res, CcaptureDlg *lp, pcap_dumper_t *dumpfile, long &nIndex)
  10. {
  11. // 一些变量声明和条件判断
  12. switch (ntohs(eth->ehr_ftp))
  13. {
  14. case ETHERTYPE_ARP:
  15. // ARP协议处理
  16. break;
  17. case ETHERTYPE_REVARP:
  18. //RARP协议处理
  19. break;
  20. case ETHERTYPE_IP:
  21. //IP协议簇处理
  22. switch (ip_hdr->proto)
  23. {
  24. case IPTYPE_ICMP:
  25. // ICMP协议处理
  26. break;
  27. case IPTYPE_TCP:
  28. // TCP协议处理
  29. break;
  30. case IPTYPE_UPD:
  31. // UDP协议处理
  32. break;
  33. default:
  34. // 未知协议处理(未添加的协议)
  35. break;
  36. }
  37. break;
  38. default:
  39. // 未知协议处理(未添加的协议)
  40. break;
  41. }
  42. //记录在缓存文件中
  43. if(dumpfile != NULL){
  44. pcap_dump((u_char *)dumpfile, adp_info.header, adp_info.pkt_data);
  45. }
  46. // 发送自定义消息WM_UPDATE_LIST给captureDlg
  47. SendMessageTimeout(lp->m_hWnd, WM_UPDATE_LIST, (WPARAM)&Data, 0, SMTO_BLOCK, 1000, NULL);
  48. }

4.3.3 过滤

过滤格式目前只支持当前这几种协议(分析功能也是如此)。可以多选需要查看的协议和根据接收包的IP地址来进行过滤。

协议的过滤采用标志位设定的方式,相应的单选框对应相应的协议类型。

4.3.4 分析

双击软件主界面的任意一条捕捉的信息条目,将会弹出此“细节分析”对话框。正如其命名,其中包含了许多细节信息,例如:被捕捉的时间、数据包长度、源MAC地址、目标MAC地址、具体协议类型、协议数据内容(十六进制形式显示)等,帮助了解各种协议的数据格式和当前记录的详细数据内容。

协议的分析其实是对主界面的List组件的单击和双击消息进行了重写,并分派给对应的协议分析器来分析对应的协议为相同的格式,不同的协议展示方式继承自同一个“分析父类”,以便程序扩展:

  1. /***********************AnalyseDispatcher.cpp***********************/
  2. /**
  3. * 分析数据入口,分发数据处理器
  4. *
  5. * @param res
  6. * @param data
  7. * @param header
  8. * @return
  9. */
  10. bool AnalyseDsipatcher::analyseData(CString &res, const u_char* data, pcap_pkthdr *header = NULL)
  11. {
  12. // 一些变量的声明
  13. // 协议头格式化,增加可读性
  14. if (header != NULL)
  15. {
  16. }
  17. // 以太网头首部数据获取
  18. // 协议分派,使用组合的设计模式
  19. switch (ptype)
  20. {
  21. case ETHERTYPE_ARP:
  22. analyseService = new AnalyseARPService();
  23. break;
  24. case ETHERTYPE_REVARP:
  25. res += "RARP datagram\r\n";
  26. break;
  27. case ETHERTYPE_IP:
  28. analyseService = new AnalyseIPService();
  29. break;
  30. default:
  31. res += "unknow\r\n";
  32. break;
  33. }
  34. // 具体分析交由相应协议的分析派生类完成
  35. analyseService->analyse(res, data);
  36. delete analyseService;
  37. analyseService = NULL;
  38. return true;
  39. }

4.3.5 导入导出

导入导出功能是对此次捕捉的数据转存。其实在本次捕捉时,已经实时dump为一个默认的,名为:capture_data.cap的,WinPcap格式数据包。

导入导出数据包只是对系统文件的I/O操作,源码如下所示:

  1. /***********************captureDlg.cpp***********************/
  2. /**
  3. * 导入抓取的数据包文件
  4. */
  5. void CcaptureDlg::importData(){
  6. // 一些变量的声明和条件条件判断
  7. CString extFileCategory = CString("capture data file|*") + dumpFileSuffix + CString("||");
  8. CFileDialog fileDlg(TRUE/*打开文件*/, extFileCategory, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, extFileCategory);
  9. fileDlg.m_ofn.lpstrInitialDir = currentDir;
  10. if(fileDlg.DoModal()==IDOK){
  11. CString openFilePath = fileDlg.GetPathName();
  12. CapFilePath = openFilePath;
  13. DataIOService dataIOServiceInstance(openFilePath.GetBuffer(openFilePath.GetLength()), this);
  14. //清空列表
  15. m_listctl.DeleteAllItems();
  16. dataIOServiceInstance.display();
  17. }
  18. }
  1. void CcaptureDlg::exportData(){
  2. //一些变量的声明和条件判断
  3. CString extFileCategory = CString("capture data file|*") + dumpFileSuffix + CString("||");
  4. CFileDialog fileDlg(FALSE/*写入文件*/, extFileCategory, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, extFileCategory);
  5. fileDlg.m_ofn.lpstrInitialDir = currentDir;
  6. if(fileDlg.DoModal()==IDOK){
  7. CString outputFile = fileDlg.GetPathName();
  8. DataIOService dataIOServiceInstance;
  9. if(false == dataIOServiceInstance.exportData(CapFilePath, outputFile, false)){
  10. MessageBox("Cannot export file!");
  11. }
  12. }
  13. }

4.3.6 扫描本网段主机

如图所示,本软件利用ARP协议,自动遍历本网段内的所有活跃主机,并把它们的MAC值和IP地址列出来。

对于本网段内主机的扫描,采用了发送UDP报文给本网段内所有主机,在规定时间内查看是否有响应的方式来判断,源码如下所示:

  1. /***********************scanHostDlg.cpp***********************/
  2. /**
  3. * 将CScanHostService类的构造放在另一个线程中,主线程用来绘窗口,提高用户体验
  4. *
  5. * @Param lParam
  6. */
  7. unsigned int WINAPI scanThread(LPVOID *lParam)
  8. {
  9. CScanHostDlg *pScanHostDlgPtr = (CScanHostDlg *)lParam;
  10. CScanHostService *hostScan = new CScanHostService(pScanHostDlgPtr);
  11. pScanHostDlgPtr->setHostScan(hostScan);
  12. return 0;
  13. }
  1. /***********************scanHostServiceImpl.cpp***********************/
  2. /**
  3. * 利用winsock取得本机MAC和网关MAC,也为后来取得网关IP打下坚实的基础!
  4. */
  5. void CScanHostService::getMAC(){
  6. //一些变量的声明和条件判断
  7. //接收线程开始
  8. _beginthread(recvThread, 0, (void*)this);
  9. WSAStartup(MAKEWORD(2, 2, ), &wsadata);
  10. SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
  11. int err = GetLastError();
  12. SOCKADDR_IN addr;
  13. addr.sin_family = AF_INET;
  14. addr.sin_port = htons(8888);
  15. addr.sin_addr.S_un.S_addr = destIP;
  16. sendto(sock, buff, strlen(buff), 0, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
  17. // 等待两秒
  18. Sleep(2000);
  19. terminate = true;
  20. Sleep(1000);
  21. WSACleanup();
  22. }
  23. /**
  24. * 念念不忘,必有回响
  25. * 接收发送出去的UDP报文,该报文有MAC地址
  26. */
  27. void recvThread(void *lp){
  28. //一些变量的声明和条件判断
  29. while (!np->getTerminate()){
  30. //分析接收到的ARP回应
  31. res = pcap_next_ex(adp_info.ahandler, &header, &pkt_data);
  32. if (res == 0) //超时时间到
  33. continue;
  34. if (res >0){
  35. mhdr = (EHR*)pkt_data;
  36. if (mhdr->ehr_ftp != 0x0008)
  37. continue;
  38. iphdr = (IP_HDR*)(pkt_data + 14);
  39. // 分析本机MAC地址
  40. if (iphdr->daddr[0] == 9 && iphdr->daddr[1] == 2 && iphdr->daddr[2] == 0 && iphdr->daddr[3] == 5){
  41. np->setMac(mhdr->ehr_sha);
  42. np->setGatewayMac(mhdr->ehr_tha);
  43. np->setGwayFlag(true);
  44. break;
  45. }
  46. }
  47. }
  48. _endthreadex(0);
  49. }
  1. /***********************scanHostServiceImpl.cpp***********************/
  2. /**
  3. * 扫描主机
  4. */
  5. bool CScanHostService::scanHost()
  6. {
  7. // 一些变量声明和条件判断
  8. //打开接收线程
  9. this->scanRevThreadHandle = (HANDLE)_beginthreadex(NULL, 0, (THREAD_PROC)scanRev, (LPVOID *)this, NULL, 0);
  10. Sleep(500);
  11. //扫描本网段活动主机,逐一遍历
  12. u_int ip = (g_netmask & g_localip) + 1, tmp;
  13. u_char tp[4];
  14. do{
  15. tmp = ntohl(ip);
  16. memcpy(tp, &tmp, 4);
  17. fillARP(tp);
  18. pcap_sendpacket(adp_info.ahandler, (const u_char*)&arp, 42);
  19. ++ip;
  20. Sleep(50);
  21. } while ((ip&g_netmask) == (g_netmask&g_localip) && !terminate);
  22. }
  23. /**
  24. * 主机扫描接收ARP包线程
  25. *
  26. * @param lParam
  27. */
  28. unsigned int scanRev(LPVOID *lParam)
  29. {
  30. // 一些变量声明和条件判断
  31. if (pcap_next_ex(adp_info.ahandler, &header, &data) <= 0)
  32. continue;
  33. if (htons(eth_hdr->ehr_ftp) == 0x0806) //只接收ARP包
  34. {
  35. arp = (ARP*)data;
  36. if (ntohs(arp->arp_hdr.arp_op) == 0x0001) //只接收reply ARP包
  37. continue;
  38. // 将接收到的特定回响存入“存活主机”队列
  39. CListCtrl *m_list = np->getList();
  40. int nCount = m_list->GetItemCount();
  41. m_list->InsertItem(nCount, "");
  42. m_list->SetItemText(nCount, 0, hostMac);
  43. m_list->SetItemText(nCount, 1, hostIp);
  44. }
  45. }

4.3.7 自制ARP包

根据ARP的格式,填写正确的ARP信息,点击start发送。

  1. /***********************manualDlg.cpp***********************/
  2. /**
  3. * 发送数据包线程
  4. * @param lParam
  5. */
  6. unsigned int WINAPI sendPackThread(LPVOID lParam)
  7. {
  8. CManualDlg *lp = (CManualDlg*)lParam;
  9. switch (lp->choice)
  10. {
  11. case ARP_TYPE:
  12. if (lp->fillARP() == false)
  13. break;
  14. lp->sendPacket();
  15. break;
  16. // 其他协议
  17. }
  18. lp->isSending = false;
  19. lp->m_bn_beg_stp.SetWindowText("Start");
  20. return 1;
  21. }
  22. /**
  23. * 启动按钮
  24. */
  25. void CManualDlg::OnBnClickedStart()
  26. {
  27. //锁定“扫描主机”菜单
  28. lp_Main->GetMenu()->GetSubMenu(2)->EnableMenuItem(0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  29. m_bn_beg_stp.SetWindowText("Stop");
  30. //打开发送packet线程
  31. _beginthreadex(NULL, 0, (THREAD_PROC)sendPackThread, (LPVOID)this, NULL, 0);
  32. }

4.4 网络数据处理工具开发方法

软件工程中经常可以遇见的系统开发方法有:结构化开发方法、面向对象的开发方法、可视化开发技术。

结构化开发方法依照功能分解的原则,自顶向下、逐步求精,最终实现软件功能。它以功能划分为基础,简单、实用。结构化开发方法将系统开发总共分为五个阶段:划定系统开发范围、系统分析、系统设计、系统实现和系统支持。

面向对象的方法是将现实世界问题向抽象对象空间直接映射,以此实现对现实世界的直接模拟,它以数据为中心,而不是基于对功能的分解,所以软件结构相对来说稳定,软件的重用性、可靠性、可维护等特性都不错。

可视化开发技术是由图形用户界面的兴起而发展起来的,是通过事件驱动实现应用软件的。良好的图形库简化了图形用户界面的设计和编码工作,将开发人员的注意力主要集中在程序的执行逻辑和工作流程上。

对于本软件的可扩展性而言,继承和组合在各个协议的数据处理上有了单独的派生类,便于新增和减少对其他协议的支持。

4.5 定义规范

虽然这是单独完成的一个项目,但是作为一名程序员,是需要有行业规范来约束自己,帮助自己融入团队的。代码规范就是很重要的一点。

4.5.1 代码注释规范

1.头文件注释

所有头文件开头都要加注释,写明文件创建时间、作者、用途、概述等。格式如下所示:

  1. /*
  2. * 属于:个人
  3. * 创建日期:2016.5.12
  4. * 作者:XXX
  5. * 功能说明:XXXXXXXXXXXXXXXXX
  6. */

2.函数注释

所有函数一定要注明函数的作用、参数的作用、返回值的作用等。格式如下所示:

  1. /**<summary>
  2. * </summary>
  3. * @param
  4. * @param
  5. * @return
  6. */

3.常量变量注释

所有的常量和变量,无论全局或者局部只要在代码中起关键作用的必须都加上注释。格式如下所示:

  1. // 变量或常量作用

4.测试用例文件存放位置

在项目的test目录下,新建与功能逻辑相同的目录结构树,在对应的目录下存放对应的测试用例;

5.测试用例命名

文件名:[被测试类名]Test.cpp格式,对应的类名为[被测试类名]Test,具体实现按照CppUnitTestFramework框架规定。

4.5.2 代码命名规范

采用驼峰命名法。

  • 类命名:英文,单词首字母大写,剩余字母小写。在意义上表达该类的作用,如:CaptureDlg,是捕获对话框类。
  • 函数命名:英文,首字母小写,剩余单词首字母大写,剩余字母小写。在意义上表达该函数的作用,如:analyseData,是分析数据的函数。

5 网络数据处理工具测试与调试

5.1 程序调试

在开发软件的过程中无法避免会产生一些问题,除开最常见的环境错误,语法错误之外,还在实际的开发过程中遇到了许多其它的问题。首先,在构建整个软件主体的过程中,主要采用模块化的构建方式。从磁盘文件组织上来看,每一个独立的功能都是一个独立的文件,单独编写,单独测试,从物理上就已经把每一个单独的功能分开,减少因文件互相耦合度过高而出错的概率。

在测试与调试过程中主要的调试工具是Visual Studio的错误语法提示和Debug断点单步调试,用来快速定位错误代码,和显示错误内存信息。

5.2 工具的测试

5.2.1 测试的意义及目的

软件测试的目的,是在真实的软件运行环境下通过与软件起初的需求定义作比较,发现软件与软件/子软件设计文档和软件开发合同约定不符或与之矛盾的地方。

5.2.2 测试框架

由于开发集成工具是VisualStudio 2012,并采用MFC框架,所以打算使用Microsoft的原生测试框架:Microsoft::VisualStudio::CppUnitTestFramework。

5.2.3 测试步骤

测试是一门学问,有多重分类方式和多重测试技巧。由于本软件目前的功能几乎不涉及与其他主机的交互,同时也不需要对其他用户开放,只是对个人电脑的网卡数据包抓取和处理,因此,本工程只打算通过手工测试、单元测试、集成测试和系统测试来对系统的功能和稳定来做保证。

开始是单元测试,集中对用源代码实现的每一个功能单元进行测试,尽量争取覆盖每一个函数,最终组合,检查各个程序模块是否正确地实现了所描述的功能。

集成测试是把已测试过的模块拼凑、组装起来,主要是针对软件体系结构的构造进行测试。

系统测试把已经经过确认的软件纳入实际运行环境中(分别在Windows XP、Windows 7、Windows 8中运行),与其它系统成份组合在一起进行环境相关的测试。

5.3 测试用例设计

本项目的测试用例根据功能模块进行划分,在业务逻辑代码同等级的目录结构下新建对应[ClassName]Test.cpp用例文件。

这里列举两个例子:

5.3.1 适配器选择测试用例

  1. #ifdef _TEST
  2. TEST_CLASS(AdpInfoImplTest){
  3. // 预备和清理工作,宏定义
  4. TEST_CLASS_INITIALIZE(AdpInfoImplTestInit){
  5. }
  6. TEST_CLASS_CLEANUP(AdpInfoImplTestEnd){
  7. }
  8. TEST_METHOD(showAllDevs){
  9. // 断言
  10. Assert::IsNotNull(dlg);
  11. }
  12. #endif

该测试用例对应于sourcecode->biz->analyse->AdpInfoImpl.cpp,被存放于test->biz->analyse->AdpInfoImplTest.cpp。需要注意TEST_CLASS_INITIALIZE、TEST_CLASS_CLEANUP、TEST_CLASS等宏的使用,具体参阅MSDN文档,此处统一使用了预编译字段_TEST,用来区分Debug模式、Release模式和自定义的unit test编译模式。

5.3.2 分析功能测试用例

  1. TEST_CLASS(AnalyseDsipatcherTest){
  2. /**
  3. * header数据生成器
  4. */
  5. struct pcap_pkthdr *ARPHeaderGenerator(){
  6. }
  7. /**
  8. * 期望结果
  9. */
  10. CString ARPResGenerator(){
  11. }
  12. /**
  13. * 数据分派测试,ARP协议测试具体期望结果
  14. */
  15. TEST_METHOD(analyseARPDataTest){
  16. // 数据准备
  17. analyser.analyseData(res, data, headerPtr);
  18. CString expectRes(this->ARPResGenerator());
  19. // 结果断言
  20. Assert::AreEqual(expectRes, res);
  21. }
  22. #endif

该测试用例对应于source code->biz->analyse-> AnalyseDsipatcher.cpp,被存放于test->biz->analyse-> AnalyseDsipatcherTest.cpp。这里展示了测试过程中的几个阶段:数据准备阶段,功能执行阶段和结果验证阶段,是比较典型、常规的测试步骤。

由于目前代码中较为繁重的是图形处理过程,所以单纯的业务逻辑代码被覆盖后,显示的测试用例覆盖率不高,目前为34%,还有待提升。

5.4 测试数据

在每一个功能完成之后都会进行分模块的功能测试,以确保这个功能模块的正常运行,同时也是为了方便之后功能的整合。通过选择某些具有代表性的数据和某些边界数据来测试可以很好的测试程序的健壮性,以保证程序的良好运行。下表是本软件中选择某些主要功能所做的测试以及出现的问题和解决方案,以及应用此解决方案后产生的效果。

功能模块 测试方法 测试数据 测试出现过的问题 解决方法 结果
网卡扫描 在不同网卡数量机器上运行本软件 各种网卡 正常
扫描本网段主机 压力测试 并发执行时,会出现重复机器条目或者程序崩溃 设置本功能和其他功能以及自身为串行 正常
自制ARP包 填写ARP欺骗包内容并发送 ARP欺骗包 正常
导入导出 手动测试 随机几次实时抓包结果 正常
过滤 设置过滤条件 随机几次实时抓包 正常
抓包 正常上网抓包 随机几次上网过程 正常

结 论

开源网络数据处理工具程序包采用了C++技术开发,利用MFC库、WinPcap库使程序界面和Windows系统接口对接,加入多线程并发技术以及多种设计模式,并以企业级规范开发。本程序代码已推送到github、gitlab以及coding.net上开源,并在CSDN上写明详细开发过程和程序代码介绍。如有意向者,可以阅读后提交请求共同开发。

对于网络协议以及计算机对网络数据的处理,我一直以来都抱有强烈的好奇和热烈的兴趣,很想对计算机网络和操作系统一探究竟。于是,我就动手收集相关资料,从最基础的概念看起。在不断地积累中,我对计算机的认识和网络的认识越来越清晰,就好像自身如同一串二进制比特流,经过物理层,被网卡读取,被上层系统一层层剥去外壳,展示出自己的数据。我将本程序中的资料罗列在了纸上,大概都有10多张A2的白纸那么多,沉甸甸的,特别有成就感。“纸上得来终觉浅”,在明白了这些协议的关系和一些网络的概念后,我动手写了这个程序,来帮我更加直观和清晰地认识我从书上的知识。一边写,一边温习和学习新知识的过程是非常愉悦的,在完成这个工程后,趁着知识记忆深刻和项目脉络清晰,又高高兴兴地在网络上描述了自己的代码,将这些天来的成果展示给大家。

参考文献

[1] Stanley B. Lippman , Josée Lajoie , Barbara E. Moo. C++ Primer 第5版[M].

北京:电子工业出版社, 2013.9

[2] [美]ames F.Kurose / [美] Keith W. Ross.计算机网络(第4版):自顶向下方法. 机械工业出版社. 2009.11

[3] Programming Applications for Microsoft Windows [M], Microsoft Press (October23, 1999)

[4] msdn.microsoft.com .Microsoft API and reference catalog [OL]. 微软开发手册

[5] www.winpcap.org/docs/docs_412/html/main.html. WinPcapDocumentation [OL]

[6] https://www.wireshark.org [OL].WireShark官网

[7] http://www.http-sniffer.com [OL].Sniffer官网

[8] Beard, Jonathan C., Peng Li, and Roger D. Chamberlain. “RaftLib: a C++template library for high performance stream parallel processing.”InProceedings of the Sixth International Workshop on Programming Models andApplications for Multicores and Manycores, pp. 96-105. ACM, 2015.

[9] 龙昱程. “基于 TCP 协议 的应用层协议设计” [M]. 信息通信 5 (2015): 69-70.

[10] 李玉石. “基于 C++ Builder 的网络调试助手设计与实现” [M]. 品牌与标准化 5 (2015): 85-87.

[11] 刘志蕾, 陈艳花, 冯志亮, 乔森, 张芳.”基于 TCP/IP 协议的测控系统的开发” [M]. 计算机测量与控制 23, no. 10 (2015): 3418-3420.

[12] https://git-scm.com/documentation [OL].Github官方手册

[13] 侯俊杰 . 深入浅出MFC[M] . 华中科技大学出版社 .2001.1

[14] Kevin R. Fall. TCP/IP Illustrated, Vol. 1: The Protocols[M] 2nd Edition. Addison-WesleyProfessional. November 25, 2011

[15] W. Richard Stevens. TCP/IP Illustrated, Vol. 2: The Implementation[M] 1stEdition. Addison-Wesley Professional. February 10, 1995

[16] W. Richard Stevens. TCP/IP Illustrated, Vol. 3: TCP for Transactions, HTTP,NNTP, and the UNIX Domain Protocols[M] 1st Edition. Addison-Wesley Professional.Addison-Wesley Professional. January 29, 1996

[17] 董越. 未雨绸缪:理解软件配置管理[M].电子工业出版社.2008-5

[18] Ron Patton. 软件测试(第二版)[M].机械工业出版社.2006-4

上传的附件 cloud_download 毕业设计-源码和文档.7z ( 3.61mb, 23次下载 )
error_outline 下载需要20点积分

发送私信

人生最好的三个词:久别重逢,失而复得,虚惊一场

14
文章数
32
评论数
最近文章
eject