当前位置:文档之家› 广工计算机网络课程设计

广工计算机网络课程设计

课程设计课程名称计算机网络题目名称使用ARP获取局域网内部活动主机的物理地址学生学院计算机学院专业班级学号学生姓名指导教师2013年1月 6 日计算机网络课程设计任务书使用ARP协议获取局域网内部活动主机的物理地址一.实验需求分析1.1实验要求定义和封装ARP数据包,将主机对应的网卡设置成混杂模式,截取局域网的数据包,并设置过滤后获取ARP包,分析ARP包,获得活动主机的物理地址。

1.2实验内容与步骤(1).熟悉ARP协议的工作原理;(2).熟悉ARP协议相关数据帧结构;(3).构造ARP请求数据帧;(4).使用Winpcap相关函数(ARP包的发送函数)实现数据帧的发送;(5).接收及解析目的主机的响应数据帧;(6.)获得IP地址与MAC地址的对应关系并显示;1.3编程环境Win7,visual studio 2010,wincap二.项目设计2.1概要设计1.课程设计中基本理论简介(1)在网际协议中定义的是因特网的IP地址,但在实际进行通信时,物理层不能识别IP地址只能识别物理地址。

因此,需在IP地址与物理地址之间建立映射关系,地址之间的这种映射称为地址解析。

(2)以太网网络中的物理地址即网卡的序列号。

IEEE规定网卡序列号为6个字节(48位),前三个字节为厂商代号,由于厂商向IEEE注册登记申请,后3个字节为网卡的流水号。

(3)地址解析包括从IP地址到物理地址的映射和从物理地址到IP地址的映射。

TCP/IP协议组提供了两个映射协议:地址解析协议ARP和逆向地址解析协议RARP。

ARP用于从IP地址到物理地址的映射,RARP用于从物理地址到IP地址的映射。

(4)地址解析协议的ARP的工作原理:假定在一个物理网络上,A(源主机)要与D(目的主机)进行通信,但是不知道D的物理地址。

A利用ARP协议工作的过程如下:广播一个ARP请求报文,请求IP地址为IPD的主机回答其物理地址。

网上所有主机都能收到该ARP请求,并将本机IP地址与请求的IP地址比较,D主机识别出自己的地址IPD,并作出回应,通报自己的物理地址。

A收到这个ARP回应包后,就可以与D进行通信。

为了提高效率,ARP协议使用了高速缓存技术。

在每台使用ARP的主机中,都保留了一个专用的内存区,一收到ARP应答,主机就将获得的IP地址和物理地址存入缓存。

以后每次要发送报文时,首先到缓存中查找有无相应的项,若找不到,再利用ARP进行地址解析。

由于多数网络通信都要连续发送多个报文,所以高速缓存大大提高ARP的效率。

在ARP请求报文中还放入源主机的“IP地址——物理地址”的地址对,源主机在广播ARP请求时,网络上所有主机都可以知道该源主机的“IP地址——物理地址”的地址对并将其存入自己的缓存。

在新主机入网时,令其主动广播其地址映射,以减少其他主机进行ARP请求。

(5)网卡具有如下的几种工作模式:广播模式(Broad Cast Model):它的物理地址(MAC)地址是0Xffffff 的帧为广播帧,工作在广播模式的网卡接收广播帧。

多播传送(MultiCast Model):多播传送地址作为目的物理地址的帧可以被组内的其它主机同时接收,而组外主机却接收不到。

但是,如果将网卡设置为多播传送模式,它可以接收所有的多播传送帧,而不论它是不是组内成员。

直接模式(Direct Model):工作在直接模式下的网卡只接收目地址是自己Mac 地址的帧。

混杂模式(Promiscuous Model):工作在混杂模式下的网卡接收所有的流过网卡的帧,信包捕获程序就是在这种模式下运行的。

(6)ARP帧的数据结构表达方式:以太网帧头中的前两个字段是以太网的目的地址和源地址。

目的地址为全1时为广播地址。

两个字节长的以太网帧类型表示后面数据的类型。

对于ARP请求或应答来说,该字段的值为0X0806.硬件类型字段:指明了发送方想知道的硬件地址的类型,以太网的值为1;协议类型字段:表示要映射的协议地址类型,IP为0X0800;硬件地址长度和协议地址长度:指明了硬件地址和高层协议地址的长度,这样ARP帧就可以在任意硬件和任意协议的网络中使用。

对于以太网上IP地址的ARP 请求或应答来说,它们的值分别为6和4;操作字段:用来表示这个报文的类型,ARP请求为1,ARP响应为2,RARP 请求为3,RARP响应为4;发送端的以太网地址:源主机硬件地址,6个字节;发送端IP地址:发送端的协议地址(IP地址),4个字节;目的以太网地址:目的端硬件地址,6个字节;目的IP地址:目的端的协议地址(IP地址),4个字节。

(7)WinPcap是用于网络封包抓取的一套工具,可适用于32位的操作平台上解析网络封包,包含了核心的封包过滤,一个底层动态链接库,和一个高层系统函数库,及可用来直接存取封包的应用程序界面。

Winpcap是一个免费公开的软件系统。

它用于windows系统下的直接的网络编程。

三.数据结构3.1 //28字节ARP帧结构struct arp_head{unsigned short hardware_type; //硬件类型unsigned short protocol_type; //协议类型unsigned char hardware_add_len; //硬件地址长度unsigned char protocol_add_len; //协议地址长度unsigned short operation_field; //操作字段unsigned char source_mac_add[6]; //源mac地址unsigned long source_ip_add; //源ip地址unsigned char dest_mac_add[6]; //目的mac地址unsigned long dest_ip_add; //目的ip地址};//14字节以太网帧结构struct ethernet_head{unsigned char dest_mac_add[6]; //目的mac地址unsigned char source_mac_add[6]; //源mac地址unsigned short type; //帧类型};//arp最终包结构struct arp_packetstruct ethernet_head ed; struct arp_head ah;};3.2实现程序的基本结构流程四.详细设计4.1主要函数说明主函数int main(){pcap_if_t *alldevs;pcap_if_t *d;int inum;int i=0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];char *ip_addr;char *ip_netmask;unsigned char *ip_mac;HANDLE sendthread;HANDLE recvthread;ip_addr=(char *)malloc(sizeof(char)*16);//申请内存存放IP地址if(ip_addr==NULL){printf("申请内存存放IP地址失败!\n");return -1;}ip_netmask=(char *)malloc(sizeof(char)*16);//申请内存存放NETMASK地址if(ip_netmask==NULL){printf("申请内存存放NETMASK地址失败!\n");return -1;}ip_mac=(unsigned char *)malloc(sizeof(unsigned char)*6);//申请内存存放MAC地址if(ip_mac==NULL){printf("申请内存存放MAC地址失败!\n");return -1;}/* 获取本机设备列表*/if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1){fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);exit(1);}/* 打印列表*/printf("[本机网卡列表:]\n");for(d=alldevs; d; d=d->next){printf("%d) %s\n", ++i, d->name);if (d->description)printf(" (%s)\n", d->description);elseprintf(" (No description available)\n");}if(i==0){printf("\n找不到网卡!请确认是否已安装WinPcap.\n");return -1;}printf("\n");printf("请选择要打开的网卡号(1-%d):",i);scanf("%d", &inum);if(inum < 1 || inum > i){printf("\n该网卡号超过现有网卡数!请按任意键退出…\n");getchar();getchar();/* 释放设备列表*/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,"\n无法读取该适配器. 适配器%s 不被WinPcap支持\n", d->name);/* 释放设备列表*/pcap_freealldevs(alldevs);return -1;}ifget(d,ip_addr,ip_netmask);//获取所选网卡的基本信息--掩码--IP地址GetSelfMac(adhandle,ip_addr,ip_mac);//输入网卡设备句柄网卡设备ip地址获取该设备的MAC地址sp.adhandle=adhandle;sp.ip=ip_addr;sp.mac=ip_mac;mask=ip_netmask;gp.adhandle=adhandle;sendthread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SendArpPacket,&sp,0,NULL );recvthread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)GetLivePC,&gp,0,NULL); printf("\nlistening on 网卡%d ...\n",inum);/* 释放设备列表*/pcap_freealldevs(alldevs);getchar();getchar();return 0;}/* 获取可用信息*/void ifget(pcap_if_t *d,char *ip_addr,char *ip_netmask){pcap_addr_t *a;char ip6str[128];/* IP addresses */for(a=d->addresses;a;a=a->next){switch(a->addr->sa_family){case AF_INET:if (a->addr){char *ipstr;ipstr=iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr);//*ip_addr memcpy(ip_addr,ipstr,16);}if (a->netmask){char *netmaskstr;netmaskstr=iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr);memcpy(ip_netmask,netmaskstr,16);}case AF_INET6:break;}}}/* 将数字类型的IP地址转换成字符串类型的*/char *iptos(u_long in){static char output[IPTOSBUFFERS][3*4+3+1];static short which;u_char *p;p = (u_char *)&in;which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);return output[which];}char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen){socklen_t sockaddrlen;#ifdef WIN32sockaddrlen = sizeof(struct sockaddr_in6);#elsesockaddrlen = sizeof(struct sockaddr_storage);#endifif(getnameinfo(sockaddr,sockaddrlen,address,addrlen,NULL,0,NI_NUMERICHOST) != 0) address = NULL;return address;}/* 获取自己主机的MAC地址*/int GetSelfMac(pcap_t *adhandle,const char *ip_addr,unsigned char *ip_mac) {unsigned char sendbuf[42];//arp包结构大小int i = -1;int res;struct ethernet_head eh;struct arp_head ah;struct pcap_pkthdr * pkt_header;const u_char * pkt_data;memset(eh.dest_mac_add,0xff,6);//目的地址为全为广播地址memset(eh.source_mac_add,0x0f,6);memset(ah.source_mac_add,0x0f,6);memset(ah.dest_mac_add,0x00,6);eh.type = htons(ETH_ARP);ah.hardware_type = htons(ARP_HARDWARE);ah.protocol_type = htons(ETH_IP);ah.hardware_add_len = 6;ah.protocol_add_len = 4;ah.source_ip_add = inet_addr("100.100.100.100"); //随便设的请求方ip ah.operation_field = htons(ARP_REQUEST);ah.dest_ip_add=inet_addr(ip_addr);memset(sendbuf,0,sizeof(sendbuf));memcpy(sendbuf,&eh,sizeof(eh));memcpy(sendbuf+sizeof(eh),&ah,sizeof(ah));if(pcap_sendpacket(adhandle,sendbuf,42)==0){printf("\nPacketSend succeed\n");}else{printf("PacketSendPacket in getmine Error: %d\n",GetLastError());return 0;}while((res = pcap_next_ex(adhandle,&pkt_header,&pkt_data)) >= 0){if(*(unsigned short *)(pkt_data+12) == htons(ETH_ARP)&&*(unsigned short*)(pkt_data+20) == htons(ARP_REPLY)&&*(unsigned long*)(pkt_data+38) == inet_addr("100.100.100.100")){for(i=0; i<6; i++){ip_mac[i]=*(unsigned char *)(pkt_data+22+i);}printf("获取自己主机的MAC地址成功!\n");break;}}if(i==6){return 1;}else{return 0;}}/* 向局域网内所有可能的IP地址发送ARP请求包线程*/DWORD WINAPI SendArpPacket(LPVOID lpParameter)//(pcap_t *adhandle,char *ip,unsigned char *mac,char *netmask){sparam *spara=(sparam *)lpParameter;pcap_t *adhandle=spara->adhandle;char *ip=spara->ip;unsigned char *mac=spara->mac;char *netmask=spara->netmask;printf("ip_mac:%02x-%02x-%02x-%02x-%02x-%02x\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);printf("自身的IP地址为:%s\n",ip);printf("地址掩码NETMASK为:%s\n",netmask);printf("\n");unsigned char sendbuf[42];//arp包结构大小struct ethernet_head eh;struct arp_head ah;memset(eh.dest_mac_add,0xff,6);//目的地址为全为广播地址memcpy(eh.source_mac_add,mac,6);memcpy(ah.source_mac_add,mac,6);memset(ah.dest_mac_add,0x00,6);eh.type = htons(ETH_ARP);ah.hardware_type = htons(ARP_HARDWARE);ah.protocol_type = htons(ETH_IP);ah.hardware_add_len = 6;ah.protocol_add_len = 4;ah.source_ip_add = inet_addr(ip); //请求方的IP地址为自身的IP地址ah.operation_field = htons(ARP_REQUEST);//向局域网内广播发送arp包unsigned long myip=inet_addr(ip);unsigned long mynetmask=inet_addr(netmask);unsigned long hisip=htonl((myip&mynetmask));for(int i=0;i<HOSTNUM;i++){ah.dest_ip_add=htonl(hisip+i);memset(sendbuf,0,sizeof(sendbuf));memcpy(sendbuf,&eh,sizeof(eh));memcpy(sendbuf+sizeof(eh),&ah,sizeof(ah));if(pcap_sendpacket(adhandle,sendbuf,42)==0){//printf("\nPacketSend succeed\n");}else{printf("PacketSendPacket in getmine Error: %d\n",GetLastError()); }Sleep(50);}Sleep(1000);flag=TRUE;return 0;}/* 分析截留的数据包获取活动的主机IP地址*/DWORD WINAPI GetLivePC(LPVOID lpParameter)//(pcap_t *adhandle){gparam *gpara=(gparam *)lpParameter;pcap_t *adhandle=gpara->adhandle;int res;unsigned char Mac[6];struct pcap_pkthdr * pkt_header;const u_char * pkt_data;while(true){if(flag){printf("扫描完毕,按任意键退出!\n");break;}if((res=pcap_next_ex(adhandle,&pkt_header,&pkt_data))>=0){if(*(unsigned short *)(pkt_data+12)==htons(ETH_ARP)){struct arp_packet *recv=(arp_packet *)pkt_data;if(*(unsigned short *)(pkt_data+20)==htons(ARP_REPLY)){printf("-------------------------------------------\n");printf("IP地址:%d.%d.%d.%d MAC地址:",recv->ah.source_ip_add&255,recv->ah.source_ip_add>>8&255,recv->ah.source_ip_ad d>>16&255,recv->ah.source_ip_add>>24&255);for(int i=0;i<6;i++){Mac[i]=*(unsigned char *)(pkt_data+22+i);printf("%02x",Mac[i]);}printf("\n");}}}Sleep(10);}return 0;}五.实验结果六.实验总结实验中最难做的是vs2010的环境变量的设置,找了很多的网站才找到此环境变量的图解。

相关主题