- 实训目的
 
设计并实现一个网络流量的分析系统。该系统具有以下功能:(1)实时抓取网络数据。(2)网络协议分析与显示。(3)将网络数据包聚合成数据流,以源IP、目的IP、源端口、目的端口及协议等五元组的形式存储。(4)计算并显示固定时间间隔内网络连接(双向流)的统计量(如上行与下行的数据包数目,上行与下行的数据量大小等)。在这些统计数据的基础上分析不同网络应用的流量特征。
- 实训内容
 
(1)能够实时抓取网络中的数据包。并实时显示在程序界面上。用户可自定义过滤条件以抓取所需要的数据包。
(2)分析各个网络协议格式,能够显示各协议字段的实际意义。例如,能够通过该程序反映TCP三次握手的实现过程。
(3)采用Hash链表的形式将网络数据以连接(双向流)的形式存储。
(4)计算并显示固定时间间隔内网络连接(双向流)的统计量(如上行与下行的数据包数目,上行与下行的数据量大小等)。例如,抓取一段时间(如30分钟)的网络流量,将该段时间以固定时长(如1分钟)为单位分成若干个时间片,计算网络连接在每一个时间片内的相关统计量。并在上述统计数据的基础上分析不同应用如WEB、DNS、在线视频等服务的流量特征。注意,可根据实际的流量分析需要自己定义相关的统计量。
- 主要设备和环境
 
硬件设备:
(1)台式计算机或笔记本计算机(含网络适配器)
软件设备:
(2)Windows操作系统
(3)网络数据包捕获函数包,Windows平台为WinPcap
(4)编程语言选用C/C++。
(5)编程环境为Code::Blocks
- 配置环境
 
(1)编译环境为Code::Blocks,由于Code::Blocks在大一就经常使用,具体安装步骤可以省去。
(2)因为开发的程序需要网络编程,所以需要获取实时网络数据流,需要抓包,因此Windows平台上需要安装WinPcap环境,并在Code::Blocks中配置WinPcap的库函数。配置WinPcap步骤如下:
A.需下载WinPcap的运行库和WinPcap的开发包
WinPcap运行库下载网址:
https://www.winpcap.org/install/default.htm
下载后按默认选项直接安装
WinPcap开发包下载网址:
https://www.winpcap.org/devel.htm
下载在一个英文路径下,并解压。
至此的结果截图如下:
   
B.打开Code::Blocks通过Settings->Compiler 在其中文本框输入WPCAP 和HAVE_REMOTE

C.打开WinPcap开发包的解压文件将其中的名为“Packet”和“wpcap”的文件

复制粘贴到CodeBlocks文件的 ..CodeBlocks\MinGW\lib\ 目录下如图:

在网上搜索WS2_32.lib文件,下载到本地,同样复制粘贴到和上述一样目录下如图:

接下来点击Code::blocks Settings->Compiler页面的Linker Setting,点击左下角的Add完成下面情形如图:

(libws2_32.a是原本就存在..\lib\ 目录下的文件)
D.仍在Settings->Compiler页面中找到Search directories并点击,然后点击左下角的Add完成下面的情形(也就是将Code::blocks目录下的include文件和WinPcap开发包解压文件目录下的Include文件Add)

E.最后点击OK完成在Code::Blocks中配置WinPcap的过程。
2.显示主机所有网络适配器
设计代码检索机器所连接的所有网络适配器,并在在屏幕上显示本机连接的所有网络适配器的名称和详细信息,用户输入适配器的编号来选择适配器捕获包。首先利用pcap_createsrctr()函数初始化一个source,指明我们在哪里查找设备;然后使用函数pcap_findalldevs_ex()函数来获取网络设备信息,利用alldevs存储返回的接口信息,列出所有网络适配器的信息,最后输入你要选择的网络适配器的编号。初始化一个source,指明我们在哪里查找设备、使用函数pcap_findalldevs_ex()这个函数来获取网络设备、显示所有网络适配器信息、选择要使用的网络适配器的编号。
结果如下所示:

3.显示选择的适配器的信息
显示上一步输入编号的网络适配器的信息,通过定义一个ifprint()函数来输出选中的适配器的信息,同时在ifprint()函数中调用*iptos函数,将把数字IP地址转换为点格式
结果如下:
    
4.打开指定的适配器
5.指定文件存储捕获的数据包
6.选择要获取的协议类型,首先要在main函数的开始做出如下声明,方便用户自由选择过滤规则,然后利用switch语句判断用户输入的编号,对应的编号和对应的过滤规则一致
结果如下:

7.设置抓包时间的长短
首先在main函数中设置抓包的时间长短,main函数中调用了*thread_clock()函数创建一个线程。其中需要调用thread_clock()函数。
结果如下:
![]()
8.开始抓包
调用pcap_loop()函数,捕获数据包。
9.计算采样时每秒的比特数和每秒的数据包数量
首先打开文件对数据包进行分析,利用timeval记录当前时间和上一次采样时间,通过计算可以求出延迟时间,根据数据包大小,进行字节转换,求出采样时每秒的比特数以及每秒的数据包数量
结果如下:
![]()
10.分析各个网络协议格式,能够显示各协议字段的实际意义
(1)显示以太网协议各字段实际意义
以太网协议格式如下:
|   Destination Address 目的MAC地址 [ 6 bytes ]  |   Source Address 源MAC地址 [ 6 bytes ]  |   Ethertype 以太网帧类型 [ 2 bytes ]  |   Data 数据部分  | 
首先显示这是分析的第几个网络数据包、捕获的时间是多久以及数据包的长度;然后分析以太网各个协议字段的实际意义,显示以太网的类型、以太网的上层协议、MAC帧源地址以及MAC帧的目的地址;同时要求如果上层协议为IP协议则要继续解析IP协议。
以太网协议结果显示如下:

(2)显示IP协议各字段实际意义
IP报文格式如下:
|   IP报文格式  |   
  | ||||||
|   版本号 [4 bits ]  |   首部长度[ 4 bits ]  |   服务类型 [ 8 bits ]  |   报文总长度 [ 16 bits ]  | ||||
|   标识 [ 16 bits ]  |   标志 [ 3 bits ]  |   片偏移 [ 13 bits ]  |   
  | ||||
|   生存时间TTL [ 8 bits ]  |   协议类型 [ 8 bits ]  |   首部校验和 [ 16 bits ]  |   
  | ||||
|   源地址 [ 32 bits ]  |   
  | ||||||
|   目的地址 [ 32 bits ]  |   
  | ||||||
|   选项(如果有)  |   
  | ||||||
|   报文数据  |   
  | ||||||
首先根据IP报文格式,显示出IP版本号、首部长度、服务质量、总长度、标识、标志、偏移、生存时间、协议类型、校验和、源IP地址、目的地址各个字段的实际意义;然后根据IP协议的上层协议的类型,利用switch语句进行判断如果是TCP协议则继续解析TCP协议,如果是UDP协议则继续解析UDP协议。
主要代码如下:
IP协议结果如下:

(3)显示TCP协议各字段实际意义
TCP协议格式如下:
|   源端口[16 bits]  |   目的端口[16 bits]  | ||
|   序列号[32 bits]  | |||
|   确认号[32 bits]  | |||
|   报头长度 [4 bits]  |   保留 [6 bits]  |   标志 [6 bits]  |   窗口[16 bits]  | 
|   校验和[16 bits]  |   紧急[16 bits]  | ||
|   选项[可选]  | |||
|   数据  | |||
解析TCP协议各个字段的含义,包括源端口、目的端口、SEQ、ACK_SEQ、fin标志位、syn标志位、rst标志位、psh标志位、ack标志位、urg标志位、ece标志位、cwr标志位、check、滑动窗口、紧急字段。最后根据目的端口判断如果目的端口是53,则继续向上解析DNS协议。
TCP协议结果如下:

(4)显示UDP协议各字段实际意义
UDP协议格式如下:
|   源端口[ 16bits ]  |   目的端口[ 16bits ]  | 
|   用户数据包的长度[ 16bits ]  |   校验和[ 16bits ]  | 
|   数据  | |
输出源端口、目的端口、用户数据包长度和校验和。最后根据目的端口判断如果目的端口是53,则继续向上解析DNS协议。
UDP协议结果如下:

(5)显示DNS协议各字段实际意义
DNS协议格式如下:
|   会话标识[ 16bits ]  |   标志[ 16bits ]  | 
|   问题数[ 16bits ]  |   回答资源记录数[ 16bits ]  | 
|   授权资源记录数[ 16bits ]  |   附加资源记录数[ 16bits ]  | 
|   查询问题区域  | |
|   回答区域  | |
|   授权区域  | |
|   附加区域  | |
在终端输出标识、标志、问题数、资源记录数、授权资源记录数、额外资源记录数、解析出来的域名和查询类型,结果如下:

11.抓包结束后输出文件已保存信息给用户提示
结果如下:

12.设置抓包的时长后系统开始抓包,抓包结束后调用pcap_close()关闭会话并释放适配器列表。
13.构建Hash表的过程
(1)首先以二进制形式读打开文件traffic1.data,用fp存储打开的文件
(2)定义一些以太网协议、IP协议、TCP协议、UDP协议格式的结构体和构建插入Hash表中需要的节点等,并初始化。主要代码如下:
(3)定义一些变量方便后续操作,其中利用ftell()函数用于确定文件当前指针相对于文件首部的偏移量,返回给定流 stream 的当前文件位置、feek()函数移动文件位置指针int fseek(fp,-packet_header_len,seek_cur) 设置流 fp的文件位置为给定的偏移 -pcket_header_len,参数 -packet_header_len 意味着从给定的 seek_cur 位置查找的字节数、fread(pkthdr,packet_header_len,1,fp) 从给定流 fp读取数据到 pkthdr 所指向的数组中,packet_header_len是读取的每个数据的长度,1是读取的数据的个数,同时初始化第一个包的开始时间。
(4)用户在终端输入分析的周期,并将分析周期写入result.data文件
在终端结果显示如下:
![]()
在result.data文件中显示如下:

(5)当文件的指针在文件长度偏移范围内进行如下操作
在result.data包中写入每一个周期内包的开始时间到结束时间,并在result.data文件中分别写入TCP和UDP的结果,如果是TCP还要再在文件中输出Hash表的结构。
在result.data文件中显示如下:

判断当前以太网协议的类型是否为IP协议,若不是移动文件指针的偏移量再进行判断,若为IP协议则要进一步判断上层协议是否为TCP和UDP协议,若不是则继续读下一个包,若为TCP和UDP协议则进行下一步处理。
A.为TCP和UDP协议,下面要将ip的源地址和目的地址赋值给五元组中记录源地址和目的地址的元素,并记录其上层协议类型。
B.如果上层协议为TCP类型,则要在终端实现输出。输出是第几个数据包中的协议、以太网上层协议类型、IP上层协议类型(这里为TCP报文)、源IP地址、源端口号、目的IP地址、目的端口,输出的过程中调用了upper_protool()函数,upper_protool()函数的作用是为了判断TCP上
层协议为何种类型
在终端输出的结果如下:

C.如果上层协议为UDP类型,则要在终端实现输出,输出是第几个数据包中的协议、以太网上层协议类型、IP上层协议类型(这里为UDP报文)、源IP地址、源端口号、目的IP地址、目的端口,输出的过程中调用了upper_protool()函数,upper_protool()函数的作用是为了判断UDP上层协议为何种类型,在之前输出的结尾加上上层协议类型,若不是常用协议类型则不输出。在终端输出结果为:

D.在Hash表、UDP链表中插入节点,并在文件在显示Hash表和UDP链表的情况。
E.输出抓包过程中统计的所有TCP和UDP上层协议类型的个数,调用print_upper_protool()函数,输出所有协议总数。结果如下:

F.Hash表构建完成之后,对traffic1文件分析结束后释放节点和链表。
基于WinPcap的网络流量在线分析系统源代码网址:https://download.csdn.net/download/weixin_43545546/11338561


















