<ARP 协议获得局域网内活动主机物理地址程序>
项目设计报告
1. 需求分析
实验目的:使用 ARP 发现局域网内活动主机,自行构造、发送 ARP 请求
数据帧,加深对 ARP 协议的了解。
实验任务:(1)掌握 ARP 协议分组结构与协议运作过程;
(2) 了解 ARP 协议获取活动主机 MAC 地址的方法与软件实现;
(3)在 windows/linux 平台上构造自定义数据帧,并通过指定网络适配
器(网卡)发送的基本方法。
实验环境:1~2 台 PC 机
操作系统:Windows XP
开发环境:Microsoft Visual C++ 6.0 ,winpcap;可以使用 MFC 类库
1.1 问题重述
(1)梳洗 arp 数据帧格式和字段含义以及 arp 协议运作过程
(2)了解 Winpcap 开发包的使用方法,
(3) 掌握 windows 平台构造自定义数据帧,并通过指定的网络适配器发送的
基本过程。
应用现状综述:
Ethernet 是目前使用最为广泛的局域网,它基于 802.3 协议,主机间通过网
卡的 MAC(Media Access Control)地址(即物理地址)进行通信。
Arp 协议工作在 TCP/IP 协议的第二层(数据链路层)。用于将 IP 地址转换为
网卡物理地址(NIC 的 MAC 地址,媒体访问控制地址)。无论是任何高层协议的
通信,最终都将转换为数据链路层的 MAC 地址来通信。所以说,ARP 协议是保证
网络通信的基础协议。
ARP 攻击就是通过伪造 IP 地址和 MAC 地址实现 ARP 欺骗,能够在网络中产生大
量的 ARP 通信量使网络阻塞,攻击者只要持续不断的发出伪造的 ARP 响应包就能
更改目标主机 ARP 缓存中的 IP-MAC 条目,造成网络中断或中间人攻击。
2 概要设计
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
协议工作的过程如下:
A 广播一个 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 个字节。
2. 2 主要问题
1.ARP 相关数据帧结构
2.ARP 协议工作原理
3.程序的流程
4. Winpcap 开发包的使用方法
5.Windows 平台构造自定义数据帧,并通过指定网络适配器发送的方法。
解决思路:
(1).先查找资料,深入掌握 ARP 的相关数据帧结构,工作原理。并且对要编
程的 ARP 程序的流程进行熟悉。
(2).查阅资料,掌握 Winpcap 开发包的使用方法。
(3).查阅资料,掌握通过指定网络适配器发送数据帧的方法。
实现预期目标的可行性分析:
ARP 协议工作在 TCP/IP 的第二层,用于将 IP 地址转换为网卡的物理地址。
通过一定时间的学习,熟悉 ARP 协议和 Winpcap 开发包使用方法,并且在老师的
细心指导下,本课题中遇见的问题可以迎刃而解。顺利完成程序的开发。
本论文主要通过对 ARP 协议的帧结构,ARP 原理,工作流程等的分析来完成
获取局域网内活动主机的物理地址的程序的开发。第一章主要介绍当前计算机网
络,协议的发展。第二章主要描述网络基础知识和 ARP 协议的原理,帧结构等相
关知识。第三章主要介绍 ARP 软件开发时使用的工具,包括 Visual C++和 Winpcap
开发包。第四章为 ARP 软件的详细设计,主要包括 ARP 软件的工作程序的编写,
和 ARP 软件界面的设计。第五章为总结,对本文进行最终的归纳。
2.3 数据结构
struct ethernet_head
{
unsigned char dest_mac[6];
unsigned char source_mac[6];
unsigned short eh_type;
//目标主机 MAC 地址
/源端 MAC 地址
//以太网类型
};
struct arp_head
{
unsigned short hardware_type;
unsigned short protocol_type;
unsigned char add_len;
unsigned char pro_len;
unsigned short option;
unsigned char sour_addr[6];
unsigned long sour_ip;
unsigned char dest_addr[6];
//硬件类型:以太网接口类型为 1
//协议类型:IP 协议类型为 0X0800
//硬件地址长度:MAC 地址长度为 6B
//协议地址长度:IP 地址长度为 4B
//操作:ARP 请求为 1,ARP 应答为 2
/源 MAC 地址:发送方的 MAC 地址
//源 IP 地址:发送方的 IP 地址
//目的 MAC 地址:ARP 请求中该字段
没有意义;ARP 响应中为接收方的 MAC 地址
unsigned long dest_ip;
//目的 IP 地址:ARP 请求中为请求解析
的 IP 地址;ARP 响应中为接收方的 IP 地址
unsigned char padding[18];
};
//最终 arp 包结构
//以太网头部
//arp 数据包头部
struct arp_packet
{
ethernet_head eth;
arp_head arp;
};
3 详细设计
3.1 主要函数说明
/****************
*物理帧头部结构
*****************/
typedef struct
{
ethernet_head
unsigned char
unsigned char
unsigned short
eh_dest_mac[6];
eh_source_mac[6];
eh_type;
}ethernet_head, *pEthernetHead;
//目标主机 mac
//本地主机 mac
//类型
/************
*ARP 帧结构
*************/
typedef struct
{
arpHead
unsigned short
unsigned short
unsigned char
unsigned char
unsigned short
unsigned char
unsigned long
unsigned char
unsigned long
unsigned char
arp_hardwaretype;
arp_protocoltype;
arp_har_len;
arp_pro_len;
arp_option;
arp_sour_addr[6];
arp_sour_ip;
arp_dest_addr[6];
arp_dest_ip;
padding[18];
//硬件类型(2 bit)
//协议类型(2 bit)
//硬件地址长度(1 bit)
//协议地址长度(1 bit)
//操作号(2 bit)
//源硬件地址(6 bit)
//源协议地址(4 bit)
//目的硬件地址(6 bit)
//目的协议地址(4 bit)
//填充数据(18 bit)
}arpHead, *pArpHead;
/****************
*IP 数据报头结构
*****************/
typedef struct
ipHead
{
unsigned char
unsigned char
unsigned short
unsigned short
unsigned short
h_lenver;
tos;
total_len;
ident;
frag_and_flags;
// 版本 (4 bits) + 首部长度 (4 bits)
// 服务类型(Type of service)
// 总长(Total length)
// 标识(Identification)
// 标志位(Flags) (3 bits) + 段偏移量(Fragment
offset) (13 bits)
unsigned char
unsigned char
unsigned short
unsigned int
unsigned int
ttl;
proto;
checksum;
sourceip;
destip;
}ipHead, *PipHead;
// 存活时间(Time to live)
// 协议(Protocol)
// 首部校验和(Header checksum)
// 源地址(Source address)
// 目的地址(Destination address)
#pragma pack(push)
LPADAPTER
ADAPTER structure 设备指针
LPPACKET
PACKET structure 包指针
unsigned long
unsigned char
char
int
增
lpadapter = 0;
lppacketr, lppackets;
myip;
mymac[6] = {0};
adapterlist[MAX_NUM_ADAPTER][1024];
num = 0;
//define a pointer to an
//define a pointer to a
//本地主机 IP
//本地主机 mac 初始化
//本地主机网卡列表
//用于发送 ARP 包时候递
void start()
{
局域网内活动主机检测
printf("************************************\n");
printf("*
*\n");
*\n");
printf("*
*\n");
printf("*
printf("*
*\n");
printf("************************************\n");
return;
07 微电子 董巍 2120070223
}
/**********************
*获得本地主机的 mac 地址
***********************/
int getmine()
{
char
int
ethernet_head
arpHead
sendbuf[1024];
k;
eth;
arp;
for(k=0;k<6;k++)
{
eth.eh_dest_mac[k] =0xff;
eth.eh_source_mac[k]=0x82;
arp.arp_sour_addr[k]=0x82;
arp.arp_dest_addr[k]=0x00;
}
eth.eh_type=htons(ETH_ARP);
arp.arp_hardwaretype=htons(ARP_HARDWARE);
arp.arp_protocoltype=htons(ETH_IP);
arp.arp_har_len=6;
arp.arp_pro_len=4;
arp.arp_option=htons(ARP_REQUEST);
arp.arp_dest_ip=htonl(myip);
arp.arp_sour_ip=inet_addr("112.112.112.112");
memset(sendbuf,0,sizeof(sendbuf));
memcpy(sendbuf,e,sizeof(eth));
memcpy(sendbuf+sizeof(eth),&arp,sizeof(arp));
PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp));
if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE)
{
printf("PacketSendPacket in getmine Error: %d\n",GetLastError());
return -1;
}
return 0;
}
/****************
*解析数据报
*****************/
void receivedata(LPPACKET lppktr)
{
unsigned long
unsigned long
char
PipHead
struct bpf_hdr
struct sockaddr_in
ethernet_head
arpHead
ulbytesreceived, off;
j;
*buf, *pChar, *base;
ip;
*hdr;
sin;
*eth;
*arp;
ulbytesreceived = lppktr->ulBytesReceived;
buf = (char *)lppktr->Buffer;
off = 0;
//解析数据报
while (off < ulbytesreceived)
{
//数据报头部
if(kbhit())
{
return;
}
hdr = (struct bpf_hdr *)(buf+off);
off += hdr->bh_hdrlen;
//数据报头部长度
pChar = (char *)(buf+off);
base = pChar;
off = Packet_WORDALIGN(off + hdr->bh_caplen);
eth = (pEthernetHead)pChar;
arp = (pArpHead)(pChar + sizeof(ethernet_head));
if (eth->eh_type == htons(ETH_IP))
{
ip = (PipHead)(pChar+sizeof(ethernet_head));
}
else
if((eth->eh_type==htons(ETH_ARP))
&&
(arp->arp_option==htons(ARP_REPLY)))
{
sin.sin_addr.s_addr = arp->arp_sour_ip;
if (sin.sin_addr.s_addr == htonl(myip))
{
memcpy(mymac, eth->eh_source_mac, 6);
}
//输出 ip 地址
printf("\n[IP:] %.16s [MAC:] ", inet_ntoa(sin.sin_addr));
//输出 mac 地址
for(j=0;j<5;j++)
{
printf("%.2x-",eth->eh_source_mac[j]);
}
printf("%.2x\n",eth->eh_source_mac[5]);
}
}
return ;
}