实验报告实验名称:计算机网络课程设计学生姓名:xxxxxxxxxxxxxxx专业:xxxxxxxxxxxxxxx班级:xxxxxxxxxxxxxxx学号:xxxxxxxxxxxxxxx指导教师:xxxxxxxxxxxxxxx实验成绩:实验地点:实验时间:2016年5月6日一、实验目的与实验要求1、实验目的将书本上抽象的概念与具体实现技术结合,通过网络软件编程的实践,深入理解理论课上学习到的ARP、IP、TCP等重要网络协议的原理,通过自己动手编程封装与发送这些数据包,加深对网络协议的理解,掌握协议帧的结构和工作原理及其对协议栈的贡献。2、实验要求网络课程设计包含两个部分的内容:题目一是数据包的封装发送和解析(ARP/IP/TCP),要求使用Winpcap技术和Socket技术,根据ARP/IP/TCP帧的结构,封装数据包发送到局域网中。另外要捕获网络中的TCP/IP/ARP数据包,解析数据包的内容,并将结果显示,并同时写入日志文件。题目二是从可选题目中选择一个,可选题目均是网络应用小程序,要求小组使用网络编程技术设计并实现一个网络应用程序,加深对网络协议协的理解,并锻炼网络编程能力。二、实验设备(环境)及要求1、实验硬件设备:计算机型号:联想ThinkPadT430u处理器型号:Inteli5主频:1.8Hz网卡型号:(1)RealtekPCIeGBE(2)Broadcom802.11n2、实验软件要求:操作系统:Windows10应用软件:VisualStudio2015Pro3、小组成员及分工:三、实验内容与步骤1、实验1:数据包的封装发送和解析(ARP/IP/TCP)(1)实验内容1)程序目标:根据IP帧的结构,封装IP数据包发送到局域网中。并捕获网络中的IP数据包,解析数据包的内容,并将结果显示,并同时写入日志文件。2)程序功能:以命令行形式运行在标准输出中显示捕获的IP报文的首部字段的内容。使用winpcap访问网卡,手动封装定义IP首部的数据结构填充数据包,发送数据包,捕获数据包使用winpcap,捕获IP数据包(2)主要步骤1)总体设计:a.获取设备列表并打印,打开所选择的适配器;b.准备工作:定义ip相关的结构体、打开要存放结果的文件,设置过滤器,手写ip数据报(内容有无效的MAC源和目的地址,和均为本机地址的ip源地址和目的地址,即发给自己一个ip报文),设置抓到数据报的解析和输出到文件的操作函数(解析ip报,打印并写入文件:报文的版本、协议、源和目的地址等)。c.发包、抓包。d.分析获取的数据。2)具体实现:#defineHAVE_REMOTE#includepcap.h#includeremote-ext.h#includestdio.h#includestdlib.h/*4字节的IP地址*/typedefstructip_address{u_charbyte1;u_charbyte2;u_charbyte3;u_charbyte4;}ip_address;/*IPv4首部*/typedefstructip_header{解析数据包过滤数据包打开选择适配器获取设备列表u_charver_ihl;//版本(4bits)+首部长度(4bits)u_chartos;//服务类型u_shorttlen;//总长类型u_shortidentification;//标识u_shortflags_fo;//标志位+段偏移量u_charttl;//存活时间u_charproto;//协议u_shortcrc;//首部校验和ip_addressdaddr;//目的地址ip_addresssaddr;//源地址u_intop_pad;//选项与填充}ip_header;voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);/*packethandler函数原型*/voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);intmain(){pcap_if_t*alldevs;pcap_if_t*d;intinum;inti=0;pcap_t*adhandle;charerrbuf[PCAP_ERRBUF_SIZE];u_intnetmask;charpacket_filter[]=ip;//抓包类型structbpf_programfcode;pcap_dumper_t*dumpfile;/*获取本机设备列表*/if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf)==-1){fprintf(stderr,Errorinpcap_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((Nodescriptionavailable)\n);}if(i==0){printf(\nNointerfacesfound!MakesureWinPcapisinstalled.\n);return-1;}printf(Entertheinterfacenumber(1-%d):,i);scanf(%d,&inum);if(inum1||inumi){printf(\nInterfacenumberoutofrange.\n);/*释放设备列表*/pcap_freealldevs(alldevs);return-1;}/*跳转到选中的适配器*/for(d=alldevs,i=0;iinum-1;d=d-next,i++);/*打开设备*/if((adhandle=pcap_open(d-name,//设备名65536,//65535保证能捕获到不同数据链路层上每个数据包的全部内容PCAP_OPENFLAG_PROMISCUOUS,//混杂模式1000,//读取超时时间NULL,//远程机器验证errbuf//错误缓冲池))==NULL){fprintf(stderr,\nUnabletoopentheadapter.%sisnotsupportedbyWinPcap\n,d-name);/*释放设备列表*/pcap_freealldevs(alldevs);return-1;}/*打开堆文件*/dumpfile=pcap_dump_open(adhandle,D:\\save.txt);if(dumpfile==NULL){fprintf(stderr,\nErroropeningoutputfile\n);return-1;}/*检查数据链路层,只考虑以太网*/if(pcap_datalink(adhandle)!=DLT_EN10MB){fprintf(stderr,nThisprogramworksonlyonEthernetnetwords.n);/*释放设备列表*/pcap_freealldevs(alldevs);return-1;}if(d-addresses!=NULL)//获得接口第一个地址的掩码netmask=((structsockaddr_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,nUnabletocompilethepacketfilter.Checkthesyntax.n);//释放设备列表pcap_freealldevs(alldevs);return-1;}//设置过滤器if(pcap_setfilter(adhandle,&fcode)0){fprintf(stderr,nErrorsettingthefilter.n);//释放设备列表pcap_freealldevs(alldevs);return-1;}printf(\nlisteningon%s...\n,d-description);//释放设备列表pcap_freealldevs(alldevs);/*手写数据包*/u_charpacket[100];/*假设在以太网上,设置MAC的目的地址为1:1:1:1:1:1*/packet[0]=1;packet[1]=1;packet[2]=1;packet[3]=1;packet[4]=1;packet[5]=1;/*设置MAC的源地址为2:2:2:2:2:2*/packet[6]=2;packet[7]=2;packet[8]=2;packet[9]=2;packet[10]=2;packet[11]=2;/*设置ip类型*/packet[12]=0x08;packet[13]=0x00;packet[14]=0x45;packet[15]=0x20;packet[16]=0x00;packet[17]=0x28;packet[18]=0xcb;packet[19]=0x16;packet[20]=0x00;packet[21]=0x00;packet[22]=0x2e;packet[23]=0x06;packet[24]=0x3e;packet[25]=0xe6;packet[26]=0xc0;//192packet[27]=0xa8;//168packet[28]=0x01;//1packet[29]=0x64;//100packet[30]=0xc0;packet[31]=0xa8;packet[32]=0x01;packet[33]=0x64;packet[34]=0x8f;packet[35]=0x50;/*填充剩下的内容*/for(i=36;i100;i++){packet[i]=i%256;}/*发送数据包*/if(pcap_sendpacket(adhandle,packet,100/*size*/)!=0){fprintf(stderr,nErrorsendingthepacket:n,pcap_geterr(adhandle));return0;}else{printf(Sendsuccessed);}/*开始捕获*/pcap_loop(adhandle,0,packet_handler,(unsignedchar*)dumpfile);//回调方式捕获数据包pcap_close(adhandle);return0;}/*每次捕获到数据包时,libpcap都会自动调用这个回调函数*/voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data){structtm*ltime;chartimestr[16];ip_header*ih;u_intip_len;time_tlocal_tv_sec;//保存数据包到文件中pcap_dump((u_char*)param,header,pkt_data);/*将时间戳转换成可识别的格式*/local_tv_sec=header-ts.tv_sec;ltime=localtime(&local_tv_sec);strftime(timestr,sizeoftimestr,%H:%M:%S,ltime);//打印数据包的时间戳和长度printf(%