当前位置:文档之家› 网络流量在线分析系统的设计与实现

网络流量在线分析系统的设计与实现

综合实训报告题目:网络流量在线分析系统的设计与实现华中农业大学正方教务系统王枫指导老师:***信息学院计算机科学系目录一、实训目的 (3)二、实训内容 (3)三、主要设备及环境 (4)四、设计与步骤 (5)五、整理与小结 (17)六、参考文献 (18)一、实训目的设计并实现一个网络流量的分析系统。

该系统具有以下功能:(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)编程环境为codeblocks四、设计与步骤(1)定义 mac,以太网帧,IPv4 首部,TCP 首部, UDP 首部与一些用于设置时间的结构体,回调函数原型包括哈希表的插入,搜索,初始化。

* 6字节的mac地址 */typedef struct mac_address{u_char byte1;u_char byte2;u_char byte3;u_char byte4;u_char byte5;u_char byte6;} mac_address;/* 以太网帧 */typedef struct ethernet_header{mac_address daddr; //目的MAC地址mac_address saddr; //源MAC地址u_short etherType //以太网帧类型} ethernet_header;/* IPv4 首部 */typedef struct ip_header{u_char ver:4,ihl:4; // 版本 (4 bits) + 首部长度 (4bits)u_char tos; // 服务类型(Type of service)u_short tlen; // 总长(Total length)u_short identification; // 标识(Identification)u_short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)u_char ttl; // 存活时间(Time to live)u_char proto; // 协议(Protocol)u_short crc; // 首部校验和(Header checksum)struct in_addr saddr; // 源地址(Source address)struct in_addr daddr; // 目的地址(Destinationaddress)u_int op_pad; // 选项与填充(Option + Padding)} ip_header;/* TCP 首部*/typedef struct tcp_header{u_short sport; // 源端口(Source port)u_short dport; // 目的端口(Destination port)u_int32_t snumber; //序列号u_int32_t cnumber; //确认号u_short reserve:6, //保留位tlen:4, //报头长度//后6位标志位fin : 1, //关闭连接标志syn : 1, //请求连接标志rst : 1, //重置连接标志psh : 1, //接收方尽快将数据放到应用层标志ack : 1, //确认序号标志urg : 1, //紧急指针标志ece : 1, //拥塞标志位cwr : 1; //拥塞标志位u_short window; //窗口u_short csum; //校验和u_short urgent; //紧急u_int op_pad; // 选项与填充(Option + Padding)} tcp_header;/* UDP 首部*/typedef struct udp_header{u_short sport; // 源端口(Source port)u_short dport; // 目的端口(Destination port)u_short len; // UDP数据包长度(Datagram length) u_short crc; // 校验和(Checksum)} udp_header;/*用于设置时间的结构体*/typedef struct argument{pcap_t *adhandle;int time;}argument;void crawl_time(void *time_c);/* 回调函数原型 */void packet_handler_mac(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);void packet_handler_ip(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);void packet_handler_tcp(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);void packet_handler_udp(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);void InitHashTable(HashTable* H)//初始化哈希表{int i;H -> count = MAXSIZE;H -> Table = ( HashNode* )malloc( ( H->count ) *sizeof( HashNode ) );for(i = 0;i < H->count; i++){H->Table[i].ip_source_address;H->Table[i].ip_dest_address;H->Table[i].source_port = 0;H->Table[i].dest_port = 0;H->Table[i].sum = NULLKEY;H->Table[i].next = NULL;}}int Hash(int key){return key % MAXSIZE;}int InsertHashTable(HashTable *H,struct in_addrsource_address,struct in_addr dest_address,u_int16_ts_port,u_int16_t d_port,int key)//插入哈希表{int addr;addr = Hash(key);if(H->Table[addr].sum != key && H ->Table[addr].sum != NULLKEY){HashNode *hashnode = (HashNode*)malloc(sizeof(HashNode));hashnode->next = H->Table[addr].next;hashnode->ip_source_address = source_address;hashnode->ip_dest_address = dest_address;hashnode->sum = key;hashnode->source_port = s_port;hashnode->dest_port = d_port;H->Table[addr].next = hashnode;addr++;return addr;}else if(H->Table[addr].sum == NULLKEY){H->Table[addr].sum = key;return addr;}}bool SerchHashTable(HashTable *H,struct in_addrsource_address,struct in_addr dest_address,u_int16_ts_port,u_int16_t d_port,int key)//搜索哈希表{int addr;addr = Hash(key);if(H->Table[addr].sum == key &&(inet_ntoa(H->Table[addr].ip_source_address) ==inet_ntoa(source_address)) &&(inet_ntoa(H->Table[addr].ip_dest_address) ==inet_ntoa(dest_address)) &&(H->Table[addr].source_port == s_port) &&(H->Table[addr].dest_port == d_port)){return true;}HashNode *p = H->Table[addr].next;while(p != NULL){if((p->sum == key) && (inet_ntoa(p->ip_source_address) == inet_ntoa(source_address)) &&(inet_ntoa(p->ip_dest_address) ==inet_ntoa(dest_address)) &&(p->source_port == s_port) &&(p->dest_port ==d_port)){return true;}elsep->next;}return false;}2./*获得设备名,检索机器所连接的所有网络适配器,并在屏幕中显示适配器的名称和详细信息,用户可以输入适配器编号选择指定的适配器用来捕获,代码与结果显示如下:*/if (pcap_createsrcstr(source, PCAP_SRC_IFLOCAL, NULL, NULL, NULL, errbuf) == -1) {printf("%s\n", errbuf);exit(-1);}/* 获得设备列表 */if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1){fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1);}/* 打印列表 */for(d=alldevs; d; d=d->next){printf("%d. %s", ++i, d->name);if (d->description)printf(" (%s)\n", d->description);elseprintf(" (No description available)\n");}if(i==0){printf("\nNo interfaces found! Make sure WinPcap is installed.\n");return -1;}while(inum < 1 || inum > i){printf("Enter the interface number (1-%d):",i); scanf("%d", &inum);if(inum < 1 || inum > i){printf("输入有误,请重新输入!!\n");}}截图如下:3. /*选择过滤协议*/int chang1 = 0;printf("\n过滤协议如下:");printf("\n\t1、MAC");printf("\n\t2、IP");printf("\n\t3、IP and TCP");printf("\n\t4、IP and UDP");printf("请选择:");scanf("%d",&chang1);while(chang1 < 0 || chang1 > 4){printf("输入有误,请重新输入:\n");scanf("%d",&chang1);}switch(chang1){case 1:strcpy(packet_filter,t0);break;case 2:strcpy(packet_filter,t1);break;case 3:strcpy(packet_filter,t2);break;case 4:strcpy(packet_filter,t3);break;}/*输入读取时间*/while(time <= 0){printf("\n读取时间(s):");scanf("%d",&time);if(time <= 0){printf("输入有误,请重新输入!!\n");}}4. /* 跳转到已选设备*/for(d=alldevs, i=0; i< inum-1 ; d=d->next, i++);5. /* 打开适配器*/if ((adhandle= pcap_open(d->name, // 设备名65536, // 要捕捉的数据包的部分// 65535保证能捕获到不同数据链路层上的每个数据包的全部内容PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式1000, // 读取超时时间NULL, // 远程机器验证errbuf // 错误缓冲池)) == NULL){fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n",d->name);/* 释放设备列表*/pcap_freealldevs(alldevs);return -1;}6./* 检查数据链路层,为了简单,我们只考虑以太网 */if(pcap_datalink(adhandle) != DLT_EN10MB){fprintf(stderr,"\nThis program works only on Ethernet networks.\n");/* 释放设备列表 */return -1;}7. /* 检查数据链路层,为了简单,我们只考虑以太网 */if(pcap_datalink(adhandle) != DLT_EN10MB){fprintf(stderr,"\nThis program works only on Ethernet networks.\n");/* 释放设备列表 */pcap_freealldevs(alldevs);return -1;}/*dump文件,打开指定文件存储捕获的数据包:*/dumpfp = pcap_dump_open(adhandle, "Output");if( dumpfp == NULL) {printf("Error on opening output file\n");exit(-1);}if(d->addresses != NULL)/* 获得接口第一个地址的掩码 */netmask=((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;else/* 如果接口没有地址,那么我们假设一个C类的掩码 */netmask=0xffffff;//编译过滤器if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask)<0 ){fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");/* 释放设备列表 */pcap_freealldevs(alldevs);return -1;}//设置过滤器if (pcap_setfilter(adhandle, &fcode)<0){fprintf(stderr,"\nError setting the filter.\n");/* 释放设备列表 */return -1;}printf("\nlistening on %s...\n", d->description);/* 释放设备列表 */pcap_freealldevs(alldevs);8. /*设置抓取时间*/pthread_t time_pt;argument time_c;time_c.adhandle = adhandle;time_c.time = time * 1000;if(pthread_create(&time_pt,NULL,crawl_time,&time_c) != 0){ fprintf(stderr,"\n pthread_create is error.\n");return -1;}printf("\n正在写入文件...\n");/* 开始捕捉并存储dump文件*/pcap_loop(adhandle, 0, packet_handler_mac,dumpfp);/*关闭设备*/pcap_close(adhandle);printf("文件已写入!\n");fclose(file_out);结果如下:9.pcap_t *fp;//文件指针int res;if ( pcap_createsrcstr(source, // 源字符串PCAP_SRC_FILE, // 我们要打开的文件NULL, // 远程主机NULL, // 远程主机端口"Output", // 我们要打开的文件名errbuf // 错误缓冲区) != 0){fprintf(stderr,"\nError creating a source string\n");return -1;}/* 打开捕获文件*/if ( (fp= pcap_open(source, // 设备名65536, // 要捕捉的数据包的部分// 65535保证能捕获到不同数据链路层上的每个数据包的全部内容PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式1000, // 读取超时时间NULL, // 远程机器验证errbuf // 错误缓冲池) ) == NULL){fprintf(stderr,"\nUnable to open the file %s.\n", source);return -1;}HashTable Htcp;//基于TCP协议的哈希链表InitHashTable(&Htcp);//进行初始化HashTable Hudp;//基于UDP协议的哈希链表InitHashTable(&Hudp);//进行初始化FILE *data_out = fopen("dataout.txt","w+");/* 从文件获取数据包*/while((res = pcap_next_ex(fp, &header, &pkt_data)) >= 0){packages_number++;int tcp_s = 0;int udp_s = 0;struct ip_header *ih0;ih0 = (struct ip_header *)(pkt_data + 14);int ip_len = ih0->ihl * 4;struct tcp_header *th0;th0 = (struct tcp_header *)(pkt_data + 14 + ip_len);struct udp_header *uh0;uh0 = (struct udp_header *)(pkt_data + 14 + ip_len);data_amount += ih0->tlen;if (ih0->proto == 17)/*UDP协议*/{udp_data_amount += ih0->tlen;udp_packages_number++;int sum = inet_addr(inet_ntoa(ih0->saddr));udp_s = InsertHashTable(&Hudp, ih0->saddr, ih0->daddr,uh0->sport,uh0->dport,sum);fprintf(data_out," 这是第%d个数据包",packages_number);fprintf(data_out," 该数据包为UDP协议:\n");fprintf(data_out," 源IP地址:%s\n", inet_ntoa(ih0->saddr));fprintf(data_out," 目的地址:%s\n", inet_ntoa(ih0->daddr));fprintf(data_out," 源端口:%d\n", uh0->sport);fprintf(data_out," 目的端口:%d\n", uh0->dport);if(strcmp(inet_ntoa(ih0->saddr),local_ip) == 0){fprintf(data_out," 目的地址与本地地址对比,判断为上传数据包\n");upload_udp_data_amount += ih0->tlen;upload_udp_packages_number++;}else{fprintf(data_out," 目的地址与本地地址对比,判断为下载数据包\n");download_udp_data_amount += ih0->tlen;download_udp_packages_number++;}fprintf(data_out,"+++++++++++++++++++++++++++++++++++++++++++++\n\n");}else{if (ih0->proto == 6)/*TCP协议*/{tcp_data_amount += ih0->tlen;tcp_packages_number++;int sum = inet_addr(inet_ntoa(ih0->saddr));tcp_s = InsertHashTable(&Htcp, ih0->saddr, ih0->daddr,th0->sport,th0->dport, sum);fprintf(data_out," 这是第%d个数据包",packages_number);fprintf(data_out," 该数据包为TCP协议:\n");fprintf(data_out," 源IP地址:%s\n", inet_ntoa(ih0->saddr));fprintf(data_out," 目的地址:%s\n", inet_ntoa(ih0->daddr));fprintf(data_out," 源端口:%d\n", th0->sport);fprintf(data_out," 目的端口:%d\n", th0->dport);if(strcmp(inet_ntoa(ih0->saddr),local_ip) == 0){fprintf(data_out," 目的地址与本地地址对比,判断为上传数据包\n\n");upload_tcp_data_amount += ih0->tlen;upload_tcp_packages_number++;}else{fprintf(data_out," 目的地址与本地地址对比,判断为下载数据包\n");download_tcp_data_amount += ih0->tlen;download_tcp_packages_number++;}fprintf(data_out,"++++++++++++++++++++++++++++++++++++++++++++\n");}}}if (res == -1){printf("Error reading the packets: %s\n", pcap_geterr(fp));}fclose(data_out);printf("\n-----------------统计量-----------------\n");printf(" 数据包总数量: %d\n",packages_number);printf(" tcp包数量: %d\n",tcp_packages_number);printf(" 上传tcp包数量: %d\n",upload_tcp_packages_number);printf(" 下载tcp包数量: %d\n",download_tcp_packages_number);printf(" udp包数量: %d\n",udp_packages_number);printf(" 上传udp包数量: %d\n",upload_udp_packages_number);printf(" 下载udp包数量: %d\n",download_udp_packages_number);printf(" 总数据量: %ld\n",data_amount);printf(" tcp数据量: %ld\n",tcp_data_amount);printf(" 上传tcp数据量: %ld\n",upload_tcp_data_amount);printf(" 下载tcp数据量: %ld\n",download_tcp_data_amount);printf(" udp数据量: %ld\n",udp_data_amount);printf(" 上传udp数据量: %ld\n",upload_udp_data_amount);printf(" 下载udp数据量: %ld\n",download_udp_data_amount);return 0; }截图:五、整理与小结本次实训的最终目标是将捕获的数据包保存到文件中,通过构造哈希表对文件中的数据包进行分流处理,实现数据流量的统计。

相关主题