实验报告实验名称:计算机网络课程设计学生姓名: 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、实验硬件设备:计算机型号:联想ThinkPad T430u处理器型号: Intel i5 主频: 1.8Hz网卡型号: (1)Realtek PCIe GBE (2)Broadcom 802.11n2、实验软件要求:操作系统: Windows10应用软件: Visual Studio 2015 Pro3、小组成员及分工:三、实验内容与步骤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)具体实现:#define HAVE_REMOTE#include "pcap.h"#include "remote-ext.h"#include "stdio.h"#include "stdlib.h"/*4 字节的 IP 地址 */typedef struct ip_address{u_char byte1;u_char byte2;u_char byte3;u_char byte4;}ip_address;/*IPv4 首部 */typedef struct ip_header{u_char ver_ihl;//版本(4bits) +首部长度(4bits)u_char tos;//服务类型u_short tlen;// 总长类型u_short identification;// 标识u_short flags_fo;//标志位+段偏移量u_char ttl;// 存活时间u_char proto;//协议u_short crc;//首部校验和ip_address daddr;//目的地址ip_address saddr;//源地址u_int op_pad;// 选项与填充}ip_header;void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);/* packet handler函数原型*/void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);int main(){pcap_if_t *alldevs;pcap_if_t *d;int inum;int i=0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];u_int netmask;char packet_filter[] = "ip";// 抓包类型pcap_dumper_t *dumpfile;/* 获取本机设备列表*/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;}printf("Enter the interface number (1-%d):",i);scanf("%d", &inum);if(inum < 1 || inum > i)printf("\nInterface number out of range.\n");/* 释放设备列表*/pcap_freealldevs(alldevs);return -1;}/* 跳转到选中的适配器*/for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);/* 打开设备*/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;}/* 打开堆文件 */dumpfile = pcap_dump_open(adhandle, "D:\\save.txt");if(dumpfile==NULL)fprintf(stderr,"\nError opening output file\n");return -1;}/* 检查数据链路层,只考虑以太网*/if(pcap_datalink(adhandle)!=DLT_EN10MB){fprintf(stderr, "nThis program works only on Ethernet networds.n");/* 释放设备列表*/pcap_freealldevs(alldevs);return -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){//释放设备列表pcap_freealldevs(alldevs);return -1;}printf("\nlistening on %s...\n", d->description);//释放设备列表pcap_freealldevs(alldevs);/* 手写数据包 */u_char packet[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[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;i<100;i++){packet[i]=i%256;}/* 发送数据包 */if (pcap_sendpacket(adhandle, packet, 100 /* size */) != 0)fprintf(stderr,"nError sending the packet: n", pcap_geterr(adhandle));return 0;}else{printf("Send successed");}/* 开始捕获*/pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);//回调方式捕获数据包pcap_close(adhandle);return 0;}/*每次捕获到数据包时,libpcap 都会自动调用这个回调函数*/void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {struct tm *ltime;char timestr[16];ip_header *ih;u_int ip_len;time_t local_tv_sec;//保存数据包到文件中pcap_dump((u_char*)param, header, pkt_data);/* 将时间戳转换成可识别的格式*/local_tv_sec = header->_sec;ltime=localtime(&local_tv_sec);strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);//打印数据包的时间戳和长度printf("%s,%.6d len:%d\n", timestr, header->_usec, header->len);//获得 IP 数据包头部的位置ih = (ip_header*)(pkt_data+14);// 以太网头部长度/* 打印IP 地址和UDP 端口*/printf(" 版本 +首部长度 :[%u]",ih->ver_ihl);printf(" 协议 :[%u]",ih->proto);printf("首部校验和:[%u]",ih->crc);printf("目的地址:[%u.%u.%u.%u]", ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4);:[%u.%u.%u.%u]\n", printf(" 源地址ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4);FILE *fp;fp=fopen("D:\\jiexi.txt", "a+");fprintf(fp," 解析结果: ");fprintf(fp," 版本 +首部长度 :[%u]",ih->ver_ihl);fprintf(fp," 协议 :[%u]",ih->proto);fprintf(fp," 首部校验和 :[%u]",ih->crc);fprintf(fp,"目的地址:[%u.%u.%u.%u]", ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4);fprintf(fp,"源地址:[%u.%u.%u.%u]\n", ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4);fclose(fp);}2、实验 2:子网内文件传送(1)实验内容(明确的实验内容)设计并实现一个局域网内部的文件传送工具,使用TCP协议进行可靠文件传输。