网络流量在线分析系统的设计与实现.docx | 您所在的位置:网站首页 › pcap_createsrcstr › 网络流量在线分析系统的设计与实现.docx |
网络流量在线分析系统的设计与实现.docx 综合实训 报告 题目: 网络流量在线分析系统的设计与实现 22 信息学院计算机科学系目 录 一、 实训目的……………………………………………… 3 二、 实训内容……………………………………………… 3 三、 主要设备及环境……………………………………… 3 四、 设计与步骤…………………………………………… 4 五、 过程与调试…………………………………………… 22 六、 整理与小结…………………………………………… 23 七、 参考文献……………………………………………… 24 八、 附录…………………………………………………… 25 一、实训目的 设计并实现一个网络流量的分析系统。 该系统具有以下功能: (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 4、设计与步骤 (1)设计代码检索机器所连接的所有网络适配器,并在屏幕中显示适配器的名称和详细信息,用户可以输入适配器编号选择指定的适配器用来捕获包,如果没有找到适配器,提示用户检查WinPcap是否安装,代码与结果显示如下: /*setthesource*/ if(pcap_createsrcstr(source,PCAP_SRC_IFLOCAL,NULL,NULL,NULL,errbuf)==-1){ printf("%s\n",errbuf);exit(-1); } printf("source: %s",source); /*findalldevices*/ if(pcap_findalldevs_ex(source,NULL,&alldevs,errbuf)== -1){ printf("%s\n",errbuf);exit(-1); } /*chooseonedevices*/d=alldevs; while(d! =NULL){ printf("%s,%s\n",d->name,d->description);d=d->next; } printf("chooseadevice[numberbetween1to4]: ");scanf("%d",&i); d=alldevs;while(--i) d=d->next; printf("\n--------------------------------------------- -\n"); printf("selecteddevice: %s\n",d->name); 实验结果显示如下: (2)选择指定适配器后,调用ifprint();函数计算本机的IP地址、掩码、广播地址、目标地址等信息,并用声明staticcharb;用来记录本机IP地址,为接下来查找Hash表判断流量包的流向做准备: voidifprint(pcap_if_t*d) { pcap_addr_t*a; /*名称*/ //printf("%s\n",d->name); /*描述*/ if(d->description) printf("\tDescription: %s\n",d->description); /*回环地址*/ printf("\tLoopback: %s\n",(d->flags&PCAP_IF_LOOPBACK)? "yes": "no"); /*IP地址*/ for(a=d->addresses;a;a=a->next) { printf("\tAddressFamily: #%d\n",a->addr->sa_family); switch(a->addr->sa_family) { caseAF_INET: printf("\tAddressFamilyName: AF_INET\n"); if(a->addr) /*Y-IP地址*/ { printf("\tAddress: %s\n",iptos(((structsockaddr_in*)a- >addr)->sin_addr.s_addr)); b=iptos(((structsockaddr_in*)a->addr)- >sin_addr.s_addr); } if(a->netmask) /*Y-掩码*/ printf("\tNetmask: %s\n",iptos(((structsockaddr_in *)a->netmask)->sin_addr.s_addr)); if(a->broadaddr) /*Y-广播地址*/ printf("\tBroadcastAddress: %s\n",iptos(((structsockaddr_in*)a->broadaddr)->sin_addr.s_addr)); if(a->dstaddr) /*Y-目标地址*/ printf("\tDestinationAddress: %s\n",iptos(((structsockaddr_in*)a->dstaddr)->sin_addr.s_addr)); break; default: /*未知*/ printf("\tAddressFamilyName: Unknown\n"); break; } } printf("\n"); } /*来自tcptracert,把数字IP地址转换为点格式*/#defineIPTOSBUFFERS12 char*iptos(u_longin) { staticcharoutput[IPTOSBUFFERS][3*4+3+1]; staticshortwhich; u_char*p; p=(u_char*)∈ which=(which+1==IPTOSBUFFERS? 0: which+1); sprintf(output[which],"%d.%d.%d.%d",p[0],p[1],p[2],p[3]); returnoutput[which]; } 结果显示如下: (3)接收到用户输入的适配器编号,打开指定适配器: /*openonedevice*/ cap_ins_des=pcap_open(d->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,errbuf); if(cap_ins_des==NULL){printf("%s\n",errbuf);pcap_freealldevs(alldevs);exit(-1); } (4)打开指定文件存储捕获的数据包: /*openafiletodumpdata*/ dumpfp=pcap_dump_open(cap_ins_des,"traffic1");if(dumpfp==NULL){ printf("Erroronopeningoutputfile\n");exit(-1); } (5)在main()函数开始做一个声明,方便用户自由选择过滤规则,声明如下: intswitchnum; chart1[]="ip";//ip过滤规则 chart2[]="ipandtcp";//tcp过滤规则 chart3[]="ipandudp";//udp过滤规则 chart4[]="";//mac帧过滤 charpacket_filter[100];//thefilter 设置过滤规则时使用swich()语句判断用户输入的编号,是对应的编号与对应的过滤规则相一致: /*openafiletodumpdata*/ dumpfp=pcap_dump_open(cap_ins_des,"traffic1");if(dumpfp==NULL){ printf("Erroronopeningoutputfile\n");exit(-1); } /*getthenetmask,usedatcompilingthefilter*/if(d->addresses! =NULL) netmask=((structsockaddr_in*)(d->addresses- >netmask))->sin_addr.S_un.S_addr; /*@#$%^&*! */else netmask=0xffffff; /*255.25.255.0*/ //netmask=0; /*选择过滤规则*/ printf("\n \n"); printf("%d: %s\n",1,"IP协议"); printf("%d: %s\n",2,"IP和TCP协议"); printf("%d: %s\n",3,"IP和UDP协议"); printf("%d: %s\n",4,"MAC帧"); printf("请选择要获取的协议类型): "); scanf("%d",&switchnum); switch(switchnum){ case1: strcpy(packet_filter,t1); break; case2: strcpy(packet_filter,t2); break; case3: strcpy(packet_filter,t3); break; case4: strcpy(packet_filter,t4); break; default: printf("error\n"); } /*compilethefilter*/ if(pcap_compile(cap_ins_des,&fcode,packet_filter,1,netmask) printf("Error\n");pcap_freealldevs(alldevs);exit(-1); } 结果显示如下: (6)用户可以根据提示设置抓包的时间长短,该功能的实现依靠创建一个线程: pthread_tptClock; argumentargs; args.handle=cap_ins_des; intargv_time=atoi(argv[1]); inttimeLen; printf("\n设置抓包时长: "); scanf("%d",&timeLen); printf("设置抓包时长为%ds",timeLen); args.timeLen=(argv_time>0)? argv_time: timeLen; //intargv_time=2; //args.timeLen=argv_time; //printf("抓取时长: %ds\n",args.timeLen); if(pthread_create(&ptClock,NULL,thread_clock,&args)) { printf("pthread_create(): Error! \n"); return-1; } void*thread_clock(void*argv) { pcap_t*handle=((argument*)argv)->handle; inttimeLen=((argument*)argv)->timeLen;//settime //printf("%d",timeLen); Sleep(timeLen*1000); pcap_breakloop(handle); } 结果显示如下: (7)抓包时调用函数pcap_loop()函数调用cb_getPacket()函数,实现在线程内的抓包,Sleep函数一旦结束,通过pcap_breakloop()退出抓包: pcap_loop(cap_ins_des,-1,cb_getPacket,(u_char*)dumpfp); voidcb_getPacket(u_char*dumpfile,conststructpcap_pkthdr*pkthdr,constu_char*packet) { //ip_header*seg_ip=(ip_header*)(package+ETHER_LEN); pcap_dump(dumpfile,pkthdr,packet); ethernet_protocol_packet_callback(dumpfile,pkthdr,packet); } (8)设置完成抓包时长后,系统开始进行抓包,一旦抓包结束,调用 pcap_close()关闭会话并释放适配器列表: pcap_close(cap_ins_des); pcap_freealldevs(allAdapters);//释放适配器列表 (9)捕获结束后将捕获的数据包存入traffic1.data文件中,再将文件打开进行分析,打开文件之前使用pcap_createsrcstr函数指明文件位置为本机文件,文件名为“traffic1.data”,在调用pcap_open()打开捕 获文件: pcap_t*fp;//文件指针 //pcap_createsrcstr指明打开文件的地方: 本地文件 if(pcap_createsrcstr(source,/*源字符串*/ PCAP_SRC_FILE,/*本机文件*/ NULL,/*远程主机*/ NULL,/*远程主机端口*/ "traffic1",/*文件名*/ errbuf/*错误缓冲区*/)! =0) { fprintf(stderr,"\nErrorincreatesourcestring: %s\n",errbuf); return-1; } //打开捕获文件 if((fp=pcap_open(source,/*设备名*/65536,/*要捕捉的数据包的部分,65535保证能捕获到不同数据链路层上的每个数据包的全部内容*/ PCAP_OPENFLAG_PROMISCUOUS,//混杂模式1000,//读取超时时间 NULL,//远程机器验证errbuf//错误缓冲池 ))==NULL) { fprintf(stderr,"\nCannotopenthefile%s.\n", source); return-1; } (10)打开文件开始对数据包进行分析,通过timeval记录当前时间和上一次采样时间,通过计算可以求出延迟时间,根据数据包的大小,进行字节转换,求出采样时每秒的比特数以及每秒的数据包数量: structtimeval*old_ts=(structtimeval*)argument; u_intdelay; LARGE_INTEGERBps,Pps; structtm*ltime; chartimestr[16]; time_tlocal_tv_sec; //以毫秒计算上一次采样的延迟时间 //这个值通过采样到的时间戳获得 delay=(packet_header->ts.tv_sec-old_ts->tv_sec)*1000000-old_ts->tv_usec+packet_header->ts.tv_usec; //获取每秒的比特数b/s //Bps.QuadPart=(((*(LONGLONG*)(packet_content+8))*8 *1000000)/(delay)); /*^^ || || || 将字节转换成比特--|| 延时是以毫秒表示的--| */ u_intm=(*(LONGLONG*)(packet_content+8))*8*1000000; u_intn=((*(LONGLONG*)(packet_content))*1000000); Bps.QuadPart=m/delay; Pps.QuadPart=n/delay; //printf("%I64u\n",m); //printf("%I64u\n",delay); //得到每秒的数据包数量 //Pps.QuadPart=(((*(LONGLONG*)(packet_content))*1000000)/(delay)); //将时间戳转化为可识别的格式 /*local_tv_sec=packet_header->ts.tv_sec; ltime=localtime(&local_tv_sec); strftime(timestr,sizeoftimestr,"%H: %M: %S",ltime);*/ //打印时间戳 //printf("%s",timestr); //打印采样结果 //printf("%I64u\n",delay); printf("\n**************************************************\n每秒的比特数: "); printf("BPS=%I64u\n",Bps.QuadPart); printf("每秒的数据包数量: "); printf("PPS=%I64u\n",Pps.QuadPart); //存储当前的时间戳 old_ts->tv_sec=packet_header->ts.tv_sec; old_ts->tv_usec=packet_header->ts.tv_usec; 结果显示如下: (11)通过捕获的文件,对抓取的每个数据包的各层的首部进行解析,并将解析结果进行显示 ①首先对以太网协议进行解析: printf("捕获第%d个网络数据包\n",packet_number); printf("捕获时间: "); printf("%s",ctime((consttime_t*)&packet_header- >ts.tv_sec)); printf("数据包长度: "); printf("%d\n",packet_header->len); printf("\n--------------以太网协议 \n"); eth |
CopyRight 2018-2019 实验室设备网 版权所有 |