使用ARP协议获取局域网内部活动主机物理地址的程序实现C++广工计算机网络课程设计.docx
- 文档编号:15713989
- 上传时间:2023-07-07
- 格式:DOCX
- 页数:21
- 大小:171.53KB
使用ARP协议获取局域网内部活动主机物理地址的程序实现C++广工计算机网络课程设计.docx
《使用ARP协议获取局域网内部活动主机物理地址的程序实现C++广工计算机网络课程设计.docx》由会员分享,可在线阅读,更多相关《使用ARP协议获取局域网内部活动主机物理地址的程序实现C++广工计算机网络课程设计.docx(21页珍藏版)》请在冰点文库上搜索。
使用ARP协议获取局域网内部活动主机物理地址的程序实现C++广工计算机网络课程设计
课程设计
课程名称计算机网络_
题目名称______________________
学生学院_____计算机学院_______
专业班级____
学号
学生姓名
指导教师_______
2013年1月11日
计算机网络课程设计
一、设计题目
使用ARP协议获取局域网内部活动主机物理地址的程序实现(C++)
二、已知技术参数和设计要求
1.已知参数:
选择适当的网络适配器,以绑定Winpcap。
2.设计要求:
2.1协议实现需要哪些数据帧?
注意要数据帧的定义要符合公共标准。
2.2如何实现实现数据帧的发送?
2.3如何接收及解析目的主机的响应数据帧?
2.4如何显示ARP协议的执行结果?
3.C++环境为VisualC++
三、设计内容与步骤
1.熟悉ARP协议的工作原理;
2.熟悉ARP协议相关数据帧结构;
3.构造ARP请求数据帧;
4.使用Winpcap相关函数实现数据帧的发送;
5.接收及解析目的主机的响应数据帧;
6.获得IP地址与MAC地址的对应关系并显示;
7.课程设计任务说明书。
四、课程设计中涉及的网络基本理论简介:
(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协议工作的过程如下:
A广播一个ARP请求报文,请求IP地址为IPD的主机回答其物理地址。
网上所有主机都能收到该ARP请求,并将本机IP地址与请求的IP地址比较,D主机识别出自己的地址IPD,并作出回应,通报自己的物理地址。
A收到这个ARP回应包后,就可以与D进行通信。
为了提高效率,ARP协议使用了高速缓存技术。
在每台使用ARP的主机中,都保留了一个专用的内存区,一收到ARP应答,主机就将获得的IP地址和物理地址存入缓存。
以后每次要发送报文时,首先到缓存中查找有无相应的项,若找不到,再利用ARP进行地址解析。
由于多数网络通信都要连续发送多个报文,所以高速缓存大大提高ARP的效率。
在ARP请求报文中还放入源主机的“IP地址——物理地址”的地址对,源主机在广播ARP请求时,网络上所有主机都可以知道该源主机的“IP地址——物理地址”的地址对并将其存入自己的缓存。
在新主机入网时,令其主动广播其地址映射,以减少其他主机进行ARP请求。
(5)网卡具有如下的几种工作模式:
广播模式(BroadCastModel):
它的物理地址(目的地址)地址是0Xffffff的帧为广播帧,工作在广播模式的网卡接收广播帧。
多播传送(MultiCastModel):
多播传送地址作为目的物理地址的帧可以被组内的其它主机同时接收,而组外主机却接收不到。
但是,如果将网卡设置为多播传送模式,它可以接收所有的多播传送帧,而不论它是不是组内成员。
直接模式(DirectModel):
工作在直接模式下的网卡只接收目地址是自己Mac地址的帧。
混杂模式(PromiscuousModel):
工作在混杂模式下的网卡接收所有的流过网卡的帧,信包捕获程序就是在这种模式下运行的。
(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个字节
六、运行结果:
打开页面:
选择网卡1:
获取到的结果:
七、代码分析:
#include
#include
#include"pcap.h"
#include"Packet32.h"
#pragmapack
(1)//按一个字节内存对齐
#defineIPTOSBUFFERS12
#defineETH_ARP0x0806//以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为x0806
#defineARP_HARDWARE1//硬件类型字段值为表示以太网地址
#defineETH_IP0x0800//协议类型字段表示要映射的协议地址类型值为x0800表示IP地址
#defineARP_REQUEST1
#defineARP_REPLY2
#defineHOSTNUM255
/*packethandler函数原型*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);
//函数原型
voidifget(pcap_if_t*d,char*ip_addr,char*ip_netmask);
char*iptos(u_longin);
char*ip6tos(structsockaddr*sockaddr,char*address,intaddrlen);
intSendArp(pcap_t*adhandle,char*ip,unsignedchar*mac);
intGetSelfMac(pcap_t*adhandle,constchar*ip_addr,unsignedchar*ip_mac);
DWORDWINAPISendArpPacket(LPVOIDlpParameter);
DWORDWINAPIGetLivePC(LPVOIDlpParameter);
//28字节ARP帧结构
structarp_head
{
unsignedshorthardware_type;//硬件类型
unsignedshortprotocol_type;//协议类型
unsignedcharhardware_add_len;//硬件地址长度
unsignedcharprotocol_add_len;//协议地址长度
unsignedshortoperation_field;//操作字段
unsignedcharsource_mac_add[6];//源mac地址
unsignedlongsource_ip_add;//源ip地址
unsignedchardest_mac_add[6];//目的mac地址
unsignedlongdest_ip_add;//目的ip地址
};
//14字节以太网帧结构
structethernet_head
{
unsignedchardest_mac_add[6];//目的mac地址
unsignedcharsource_mac_add[6];//源mac地址
unsignedshorttype;//帧类型
};
//arp最终包结构
structarp_packet
{
structethernet_headed;
structarp_headah;
};
structsparam
{
pcap_t*adhandle;
char*ip;
unsignedchar*mac;
char*netmask;
};
structgparam
{
pcap_t*adhandle;
};
boolflag;
structsparamsp;
structgparamgp;
intmain()
{
pcap_if_t*alldevs;
pcap_if_t*d;
intinum;
inti=0;
pcap_t*adhandle;
charerrbuf[PCAP_ERRBUF_SIZE];
char*ip_addr;
char*ip_netmask;
unsignedchar*ip_mac;
HANDLEsendthread;
HANDLErecvthread;
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=(unsignedchar*)malloc(sizeof(unsignedchar)*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,"Errorinpcap_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);
else
printf("(Nodescriptionavailable)\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
/*打开设备*/
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("\nlisteningon网卡%d...\n",inum);
/*释放设备列表*/
pcap_freealldevs(alldevs);
getchar();
getchar();
return0;
}
/*获取可用信息*/
voidifget(pcap_if_t*d,char*ip_addr,char*ip_netmask)
{
pcap_addr_t*a;
charip6str[128];
/*IPaddresses*/
for(a=d->addresses;a;a=a->next)
{
switch(a->addr->sa_family)
{
caseAF_INET:
if(a->addr)
{
char*ipstr;
ipstr=iptos(((structsockaddr_in*)a->addr)->sin_addr.s_addr);//*ip_addr
memcpy(ip_addr,ipstr,16);
}
if(a->netmask)
{
char*netmaskstr;
netmaskstr=iptos(((structsockaddr_in*)a->netmask)->sin_addr.s_addr);
memcpy(ip_netmask,netmaskstr,16);
}
caseAF_INET6:
break;
}
}
}
/*将数字类型的IP地址转换成字符串类型的*/
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];
}
char*ip6tos(structsockaddr*sockaddr,char*address,intaddrlen)
{
socklen_tsockaddrlen;
#ifdefWIN32
sockaddrlen=sizeof(structsockaddr_in6);
#else
sockaddrlen=sizeof(structsockaddr_storage);
#endif
if(getnameinfo(sockaddr,
sockaddrlen,
address,
addrlen,
NULL,
0,
NI_NUMERICHOST)!
=0)address=NULL;
returnaddress;
}
/*获取自己主机的MAC地址*/
intGetSelfMac(pcap_t*adhandle,constchar*ip_addr,unsignedchar*ip_mac)
{
unsignedcharsendbuf[42];//arp包结构大小
inti=-1;
intres;
structethernet_headeh;
structarp_headah;
structpcap_pkthdr*pkt_header;
constu_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("\nPacketSendsucceed\n");
}
else
{
printf("PacketSendPacketingetmineError:
%d\n",GetLastError());
return0;
}
while((res=pcap_next_ex(adhandle,&pkt_header,&pkt_data))>=0)
{
if(*(unsignedshort*)(pkt_data+12)==htons(ETH_ARP)&&
*(unsignedshort*)(pkt_data+20)==htons(ARP_REPLY)&&
*(unsignedlong*)(pkt_data+38)==inet_addr("100.100.100.100"))
{
for(i=0;i<6;i++)
{
ip_mac[i]=*(unsignedchar*)(pkt_data+22+i);
}
printf("获取自己主机的MAC地址成功!
\n");
break;
}
}
if(i==6)
{
return1;
}
else
{
return0;
}
}
/*向局域网内所有可能的IP地址发送ARP请求包线程*/
DWORDWINAPISendArpPacket(LPVOIDlpParameter)//(pcap_t*adhandle,char*ip,unsignedchar*mac,char*netmask)
{
sparam*spara=(sparam*)lpParameter;
pcap_t*adhandle=spara->adhandle;
char*ip=spara->ip;
unsignedchar*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");
unsignedcharsendbuf[42];//arp包结构大小
structethernet_headeh;
structarp_headah;
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包
unsignedlongmyip=inet_addr(ip);
unsignedlongmynetmask=inet_addr(netmask);
unsignedlonghisip=htonl((
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 ARP 协议 获取 局域网 内部 活动 主机 物理地址 程序 实现 C+ 计算机网络 课程设计