ARP——地址解析协议

来源:互联网 发布:淘宝ecco鞋真假 编辑:程序博客网 时间:2024/06/05 04:07

目录:

1:概述

2:ARP报文格式

3:ARP解析缓存

4:ARP实现例程

5:总结


1、概述

1.1:当数据需要在不同的局域网中进行传输时,由于不同的局域网可能其物理地址(MAC地址)格式不同,所以制定IP地址,来统一标识网络中的设备;

1.2:ARP协议是通过给定的IP地址,找到所对应设备的物理地址:,通过以太网协议进行传输;

1.3:当上层协议通过IP协议发送数据报时,已经有目的设备的IP地址,但此时需要知道物理地址通过以太网协议把数据发送至目标设备,这时,原设备会发送一个包含ARP报文的广播帧,ARP报文包含目的设备的IP地址。ARP帧被所有设备接收,在对ARP帧进行分析后,具有该IP地址的设备应答报文的发送者,在应答报文中就有其物理地址(MAC地址),通过这样的ARP请求和响应,目的设备和源设备都会知道双方的IP地址和物理地址,并各自将这些IP地址和对应的物理地址记录下来,形成ARP条目表;


2、ARP报文格式

2.1:ARP协议共28字节(IPv4协议);

2.2:报文中主要提供:数据链路层的硬件类型(以太网)+协议类型(IPv4)+硬件地址和协议地址长度+操作码(请求或者应答)+目标设备和源设备的物理地址(MAC地址)和协议地址(IPv4);


3、ARP解析缓存

3.1:运行在设备中的程序会维护一个IP地址和MAC地址的对应关系表(ARP条目表),当发送设备需要解析IP地址时,去条目表中字节查找,c语言中,我们用结构体数组来实现ARP条目标;

3.2:ARP条目中的表项必须在一定的时间内更新,重新建立对应关系,比如主机更换IP地址、设备跟换网卡、主机关机、设备移除网络等,这些情况下,条目中将不再继续维护对应关系;


4、ARP实现例程

4.1:初始化ARP表

定义ARP条目表结构体

/*ARP条目结构体定义*/struct arp_entry{char proaddr[4];        //协议地址,我们使用IPV4地址 char mac_address[6];    //以太网的mac地址,即物理地址 char state;             //arp条目状态 unsigned int time_out;  //arp条目超时时间,指示条目何时更新char retry_cnts;        //发送ARP请求,得不到回应时,重新发送ARP请求的次数 char usage_cnts;        //条目被请求的次数};
初始化ARP条目表,启动定时器

void arp_init(void)

{char i = 0;for(i=0;i<ARP_ENTRY_SIZE;i++){arp_cache[i].state = ARP_ENTRY_FREE;}/*开启定时器*/timer_start(&timer_arp,10);}

4.2:定义ARP报文结构体

/*arp报文结构体定义*/#pragma pack(1)struct arp_message{  unsigned short hwtype;           //硬件类型 1:10Mbps以太网  unsigned short protype;          //协议类型,第三层的协议类型,IPv4:0x0800  char           hwaddrlen;        //硬件地址长度,以太网:mac地址为6字节  char           proaddrlen;       //协议地址长度 IPv4:4字节  unsigned short opcode;           //操作码 1:ARP请求 2:ARP应答  char          sendhwaddr[6];    //发送者硬件地址 mac地址  char           sendproaddr[4];   //发送者IP地址  char           deshwaddr[6];     //目标硬件地址 mac地址  char           desproaddr[4];    //目标协议地址 IP地址};#pragma pack()

4.2:处理ARP报文

(1)当数据链路层收到一个含有ARP模块的数据帧时,arp_process()函数被调用;

(2)在串口控制台上将受到的ARP报文进行打印;

(3)更新ARP条目表,受到的ARP数据包是ARP请求或者ARP响应报文,ARP请求数据包是局域网中的其他设备发送的以太网广播帧,不判断此数据包是不是给自己的,一并接受更新ARP条目;ARP响应数据包,肯定是本机设备发送的ARP请求,然后目标设备收到请求后做出的回应,也进行接受更新;

(4)判断接受到的数据是不是ARP请求并且判断ARP数据包是不是给自己的,如果是,发送ARP响应,告诉请求设备自己的MAC地址,请求设备会受到数据包问,并且更新ARP条目表;

void arp_process(void){//char i = 0;#ifdef debug_arparp_printf();   //在控制台上打印arp报文#endifarp_update();     //更新ARP条目 arp_entry_ptintf();/*判断是都是给自己的包*/if(memcmp(RX_ARP->desproaddr,IP,4) == 0){if(RX_ARP->opcode == HTONS(1))   /*判断是不是ARP请求*/{arp_respond();          /*发送arp响应*/ }}}
APR更新函数,arp_process(),代码如下:

/*arp条目表更新*/void arp_update(void){char i = 0,j=0,cnt = 0;struct arp_entry *entry;for(i=0;i<ARP_ENTRY_SIZE;i++){entry = &arp_cache[i];if(entry->state == ARP_ENTRY_FREE)continue;if(memcmp(entry->proaddr,RX_ARP->sendproaddr,4) == 0)  /*如果发现ARP条目中有接受到的IP地址,更新这个条目*/{memcpy(entry->mac_address,RX_ARP->sendhwaddr,6);entry->state = ARP_ENTRY_OK;entry->retry_cnts = ARP_RETRY_CNTS;entry->time_out = ARP_TIME_OUT;entry->usage_cnts = 0;return ;}}/*ARP条目中没有找到接受到的IP地址对应的条目*/for(i=0;i<ARP_ENTRY_SIZE;i++){entry = &arp_cache[i];if(entry->state == ARP_ENTRY_FREE){memcpy(entry->mac_address,RX_ARP->sendhwaddr,6);memcpy(entry->proaddr,RX_ARP->sendproaddr,4);entry->state = ARP_ENTRY_OK;entry->retry_cnts = ARP_RETRY_CNTS;entry->time_out = ARP_TIME_OUT;entry->usage_cnts = 0;return ;}}/*条目全满,依据条目被使用的次数来决定是否删除此条目*/  cnt = arp_cache[0].usage_cnts;for(i=1;i<ARP_ENTRY_SIZE;i++) /*找到使用次数最少的条目,然后更新值*/{entry = &arp_cache[i];if(entry->usage_cnts < cnt){cnt = entry->usage_cnts;j = i;}}entry = &arp_cache[j];memcpy(entry->mac_address,RX_ARP->sendhwaddr,6);memcpy(entry->proaddr,RX_ARP->sendproaddr,4);entry->state = ARP_ENTRY_OK;entry->retry_cnts = ARP_RETRY_CNTS;entry->time_out = ARP_TIME_OUT;entry->usage_cnts = 0;return ;}
ARP响应函数,arp_respond(),代码如下:

/*发送arp响应*/void arp_respond(void){/*构建ARP响应报文*/generate_arp_messsage(0x0002,RX_ARP->sendproaddr,RX_ARP->sendhwaddr);/*构建以太网首部*/ generate_eth_head(RX_ARP->sendhwaddr,ARP_PROTOCOL);/*发送数据包*/ethernet_send(42); }

4.3:IP地址解析

(1)在串口控制台中输入IP地址,模拟IP地址解析,调用arp_ip_analyze()函数;

(2)判断ARP条目表中对否有IP对应的物理地址,如果有,将其打印至串口控制台;

(3)如果找不到,发送ARP请求,后会受到此条请求的响应ARP报文,然后更新ARP条目;

/*IP解析*/void arp_ip_analyze(char *ip_address){char i = 0;struct arp_entry *entry; for(i=0;i<ARP_ENTRY_SIZE;i++)   /*检查entry条目中是否有IP对应的硬件地址*/{entry = &arp_cache[i];if(entry->state == ARP_ENTRY_FREE)continue;if(memcmp(entry->proaddr,ip_address,6) == 0){printf("IP %d.%d.%d.%d is found\r\n",ip_address[0],ip_address[1],ip_address[2],ip_address[3]);return;}}printf("IP %d.%d.%d.%d is not found\r\n",ip_address[0],ip_address[1],ip_address[2],ip_address[3]);/*entry条目中未找到对应的IP地址,发送ARP请求*/arp_request(ip_address);}

arp_request()函数,发送一个包含有本设备IP地址和mac地址的以太网广播帧,代码如下:

/*发送arp请求*/void arp_request(char *ip_address){char board_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};char mac[6] = {0,0,0,0,0,0};   /*arp请求中目的mac地址为0*/ /*构建ARP响应报文*/generate_arp_messsage(0x0001,ip_address,mac);/*构建以太网首部*/ generate_eth_head(board_addr,ARP_PROTOCOL);/*发送数据包*/ethernet_send(42); }

5:总结

使用PING指令,PING本机的ip地址,本机会收到ARP请求包,更新ARP条目表,然后发送ARP响应,然后查看电脑的ARP条目表,其中有记录设备的IP地址和MAC地址,设备的条目表中也出现电脑端的IP和MAC地址;



本例程使用内核时钟定时器进行arp条目的更新,由于时间关系,没有实现维护ARP表的函数,大概的思路是:

(1)sysclk是100ms中断一次,我们设定定时器的初始值为10,然后1s后定时器溢出,溢出后重新启动定时器,然后去arp条目里面找非空闲条目,对time_out减1,初始值为100,当time_out至0时,发送ARP请求,将此条目的state设置为ARP_ENTRY_RESOLVIN,表示此条目在等待回应;

(2)如果有回应,条目被更新,如果一直没有回应,维护表函数中将对retry_cnts定时减去1,retry_cnts至0后,还是没有回应,删除条目;



1 0