前言

ARP,全称Address Resolution Protocol,译作地址解析协议,是位于 TCP/IP 协议栈底层的协议。
任何网络的通信都是基于底层硬件链路的,底层的数据链路有着自己的一套寻址机制,在以太网中,往往是通过一个48位的MAC地址来标示不同的网络通信设备的。
TCP/IP协议的上层是使用IP地址作为各个主机间通信寻址机制的。

ARP作用:当源主机上层要向目标主机发送数据时,它只知道目标主机的IP地址,此时源主机需要将该IP地址转换为目的主机对应的MAC地址,这样才能在数据链路上选择正确的通道将数据传送出去。

ARP协议简介

在ARP背后有一个基本概念,就是每个网络接口有一个硬件地址(一个48位的值,标识不同的以太网或令牌环网络接口),在硬件层次上进行的数据帧交换必须有正确的硬件接口地址。
知道主机的 I P 地址并不能让内核发送一帧数据给主机。内核(如以太网驱动程序)必
须知道目的端的硬件地址才能发送数据。

  • ARP的功能:在32位的IP地址和采用不同网络技术的硬件地址之间提供动态映射。ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的进行。
  • ARP协议实现的核心是ARP缓存表,ARP的实质就是对对缓存表的建立、更新、查询等操作。
  • ARP缓存表是由一个个的缓存表项(entry)组成的,LWIP中描述缓存表项的数据结构叫etharp_entry,源代码如下:
struct etharp_entry {#if ARP_QUEUEINGstruct etharp_q_entry *q; // 数据包缓冲队列指针
#endifstruct ip_addr ipaddr; // 目标 IP 地址struct eth_addr ethaddr; // MAC 地址enum etharp_state state; // 描述该 entry 的状态u8_t ctime; // 描述该 entry 的时间信息struct netif *netif; // 相应网络接口信息
};

ARP_QUEUEING是编译选项,表示是否允许缓存表项有数据包缓冲队列,在opt.h里面设置。
其中state是个美剧类型,表示该缓存表项的状态,如下所示:

 enum etharp_state {ETHARP_STATE_EMPTY = 0,ETHARP_STATE_PENDING,ETHARP_STATE_STABLE
};

LWIP内核通过数组的方式来创建ARP缓存表,如下

static struct etharp_entry arp_table[ARP_TABLE_SIZE];

工作流程

  • 在初始状态下,每个表项都处于ETHARP_STATE_EMPTY 状态;
  • 当表项记录到了IP地址,还未记录到对应该IP地址的MAC地址,此时就处于ETHARP_STATE_PENDING 状态,发往该表项中IP地址处的数据包会被连接在表项对应的数据包缓冲队列上,此时LWIP 内核会发出一个广播 ARP 请求到数据链路上,以让对应 IP 地址的主机回应其 MAC 地址,当源主机接收到 MAC 地址时,它就更新对应的 ARP 表项。
  • 当 ARP 表项得到更新后,它就完全记录了一对 IP 地址和 MAC 地址,此时该表项就处于 ETHARP_STATE_STABLE 状态。
  • ctime字段记录表项处于某个状态的时间,当某表项的ctime值大于规定的表项最大生存值时,该表项会被内核删除。

ARP数据包

ARP数据包是正确建立ARP缓存的基础,ARP数据包可以分为ARP请求数据包ARP应答数据包,ARP数据包到达底层链路时会被加上以太网数据包头发送出去,最终呈现在链路上的数据报头格式如下图。

以太网数据报头

  • 以太网包头中的前两个字段是以太网的目的MAC地址和源MAC地址。目的地址为全1的特殊地址是广播地址。

    1. 在ARP表项建立前,源主机只知道目的主机的IP地址,并不知道其MAC地址,所以在数据链路上,源主机只有通过广播的方式将ARP请求数据包发送出去。
    2. 电缆上的所有以太网接口都要接收广播的数据包,并检测数据包是否是发给自己的,通过对照目的IP地址来实现
    3. 如果是发给自己的,目的主机需要回复一个ARP应答数据包给源主机,以告诉源主机自己的MAC地址。
  • 以太网帧类型表示后面数据的类型,对于ARP请求或应答数据包来说,该字段的值为0x0806,对于IP数据包来说,该字段的值为0x0800。

ARP数据报头

  • 硬件类型字段表示硬件地址的类型,它的值为1即表示以太网MAC地址,长度为6个字节。协议类型字段表示要映射的协议地址类型。它的值与包含IP数据报的以太网数据帧头中的类型字段的值相同。
  • 两个1字节的字段,意见地址长度和协议地址长度分别指出硬件地址和协议地址的长度,以字节为单位。对于以太网上 ARP 请求或应答来说,它们的值分别为 6 和 4。
  • 操作字段op指出四种操作类型,它们是ARP请求(值为1)、ARP应答(值为2)、RARP请求(值为3)和RARP应答(值为4)。
  • 接下来的四个字段是发送端的以太网 MAC 地址、发送端的 I P 地址、目的端的以太网MAC 地址和目的端的IP地址。

请求和应答过程描述

  • 在以太网的数据帧报头中和 A R P 请求数据帧中都有发送端的以太网 MAC 地址
  • 对于一个 ARP 请求来说,除目的端 MAC 地址外的所有其他的字段都有填充值。
  • 当目的主机收到一份给自己的 ARP 请求报文后,它就把自己的硬件地址填进去
  • 将该请求数据包的源主机信息和目的主机信息交换位置,并把操作字段 op 置为 2,最后把该新构建的数据包发送回去,这就是** ARP 响应**。

源代码如下:

struct etharp_hdr {PACK_STRUCT_FIELD(struct eth_hdr ethhdr); // 14 字节的以太网数据报头PACK_STRUCT_FIELD(u16_t hwtype); // 2 字节的硬件类型PACK_STRUCT_FIELD(u16_t proto); // 2 字节的协议类型PACK_STRUCT_FIELD(u16_t _hwlen_protolen); // 两个 1 字节的长度字段PACK_STRUCT_FIELD(u16_t opcode); // 2 字节的操作字段 opPACK_STRUCT_FIELD(struct eth_addr shwaddr); // 6 字节源 MAC 地址PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); // 4 字节源 IP 地址PACK_STRUCT_FIELD(struct eth_addr dhwaddr); // 6 字节目的 MAC 地址PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); // 4 字节目的 IP 地址
} PACK_STRUCT_STRUCT;

ARP表查询

下面主要介绍ARP表的创建,更新和查询等操作。

重要函数介绍

第一个函数是find_entry,该函数最重要的输入是一个IP地址,返回值是该IP地址对应的ARP缓存表项索引。函数声明原型如下,

static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
  • 主要功能:寻找一个匹配的ARP表项或者创建一个新的ARP表项,并返回该表项的索引号,若参数ipaddr为给定的非空的的内容,则函数需要返回一个处于pending或stable的索引表项;若没有匹配的表项,则该函数需要返回一个empty表项。
  • 工作流程:
    1. 首先找到上次的表项索引是否为要找的内容,如果是则直接返回该索引号
    2. 如果不是,则必须检索整个ARP表。对于每个表项首先判断它是否为empty状态,find_entry只关心第一个状态为empty的表项索引值。如果一个表项不是empty状态,则判断它是不是pending状态。
    3. 如果匹配,则返回该索引值,更新etharp_cached_entry 为该索引值,若不匹配,则判断该索引的数据包指针是否为空
    4. 如果一个表项也不是pending状态,则判断是不是stable状态
    5. 如果最终还是没有找到匹配的表项,就需要为find_entry调用者返回一个empty的表项索引。

另一个重要的函数是 etharp_query,该函数的功能是向给定的 IP 地址发送一个数据包或者发送一个 ARP 请求。

etharp_query 函数原型如下所示

err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
  • 工作流程:

    1. 首先判断给定的ipaddr是否合法,对于空IP地址、广播IP地址、多播IP地址不予处理
    2. 将ipaddr作为参数调用函数find_entry,函数返回一个ARP表项索引,该表项可能是原来已经有的,此时该表项应该是pending或stable状态;该表项也可能是新申请得到的,此时该表项应该是 empty 状态。
    3. 根据返回的表项索引找到该ARP表项,判断该表项是否为 empty 状态,如果是,说明该表项是新申请的,则将该表项状态设置为 pending 状态。
    4. 判断要发送的数据包是否为空,或者判断ARP表项是否为pending状态,这两个条件只要有一个成立,就发送一个ARP请求出去,发送ARP请求的函数是etharp_request。
    5. 如果待发送的数据包不为空,就根据 ARP 表项的状态作不同的处理:若 ARP 表项处于 stable 状态,则直接调用函数 etharp_send_ip 发送数据包;若 ARP 表项处于 pending状态,则需要将该数据包挂接到表项的待发送数据链表上,由于 pending 状态的表项必然在第(4)步中发出了一个 ARP 请求,当内核接收到 ARP 回应时,会将表项设置为 stable状态,并将其链表上的数据全部发送出去。

ARP传输流程

关于ARP的传输过程,就需要介绍一个函数update_arp_entry,该函数用于更新ARP缓存表中的表项或者在缓存表中插入一个新的表项。该函数会在收到一个IP数据包或ARP数据包后被调用。
源代码如下所示:

static err_t
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{s8_t i; // 两个变量,不解释u8_t k;i = find_entry(ipaddr, flags); // 查找或新建一个 ARP 表项,返回其索引值if (i < 0) return (err_t)i; // 如果为不合法的索引值,则更新缓存表失败else{arp_table[i].state = ETHARP_STATE_STABLE; // 否则将对应表项状态改为 stablearp_table[i].netif = netif; // 记录下网络接口}k = ETHARP_HWADDR_LEN; // 这一段是更新缓存表项中的 MAC 地址while (k > 0) {k--;arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];}arp_table[i].ctime = 0; // 生存时间值置 0#if ARP_QUEUEING //该 ARP 表项上有未发送的队列,则把这些队列发送出去while (arp_table[i].q != NULL) { // 只要缓冲链表中海有数据则循环struct pbuf *p;struct etharp_q_entry *q = arp_table[i].q; // 记录下缓冲链表表头arp_table[i].q = q->next; // 缓冲链表表头指向下一个节点p = q->p; // 取得记录下的缓冲链表表头指向的数据包memp_free(MEMP_ARP_QUEUE, q); // 释放记录下的缓冲链表表头etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); // 发送数据包pbuf_free(p); // 释放数据包缓存空间}
#endifreturn ERR_OK;
}

LWIP的数据包接收与发送的全过程入下所示:

  • ARP的功能:

    1. 当有数据包输入时,更新arp表,如果是ip包则递交给ip层,如果是arp包,则针对不同的arp包类型做相应的响应;
    2. 当向目的ip发送一个数据包的时候,需要通过arp实现ip到MAC地址的映射,必要时需要发送广播数据包获得目标机器的MAC地址。
  • LWIP利用netif.input指向的函数接收以太网数据包,通常这个函数为ethernet_input,更底层的函数接收到数据包后将数据包递交给ethernet_input,ethernet_input再对其进行处理。

  • 以太网的帧类型可以是:IP, ARP,甚至是pppoe,wlan等。ethernet_input 根据以太网首部的类型字段判断收到的数据包的类型,分别递交给图中两个函数。

  • 对于ip类型的数据包,etharp_ip_input首先检查是否开启了ETHARP_TRUST_IP_MAC,若开启了就要用这个帧中的信息和update_arp_entry函数来更新arp表,然后丢弃以太网帧首部,将IP报文通过ip_input函数递交给ip层。

  • 对于ARP类型的数据包,etharp_arp_input函数首先利用数据包头信息更新arp表的内容,然后再判断该ARP数据包的类型,如果是 ARP 请求包,则首先判断这个包是不是给自己的,如果是给自己的,则在原有包的基础上重组一个 ARP 应答包发送出去,否则直接忽略。如果是ARP应答包,主要工作就是更新arp表,但这一步已经在arp包刚进来的时候处理完了,故不需要重复做。

  • LWIP利用netif.output指向的函数发送ip数据包,函数为etharp_output。主要是将IP数据包打包成以太网帧数据,递交给netif.linkoutput 函数来发送;

  • etharp_output函数接收IP层要发送的数据包,并将数据包发送出去由于是发送 ip 数据包,所以函数一开始需要增加缓冲区大小,大小为以太网的数据首部的大小。然后检查 ip地址,可以分为广播包,多播包,单播包(单播包又分为是局域网内部还是局域网外面)。

参考资料

老衲五木:TCP/IP协议栈LwIP的设计与实现

LwIP协议栈之ARP(Address Resolution Protocal)协议详解相关推荐

  1. LwIP协议栈之ICMP(Internet Message Protocal)协议

    在之前主要讲到LWIP了IP层的相关概念(详见本人另外一篇文章:LwIP协议栈之IP协议),其中主要讲解了网络接口(链路层)与IP层(网络层)的数据交互,而数据包是如何从IP层向上级(传输层)传输的并 ...

  2. TCP/IP网络协议栈:ARP协议详解

    <TCP/IP网络协议栈:以太网数据包结构.802.3> <TCP/IP网络协议栈:ARP协议详解> <TCP / IP攻击:ARP缓存中毒的基本原理.TCP序列号预测和 ...

  3. ARP地址解析协议详解

    ARP地址解析协议详解 网络层的ARP协议完成IP地址与物理地址的映射.首先,每台主机都会在自己的ARP缓冲区中建立一个ARP缓存表,以表示IP地址和MAC地址的对应关系.当源主机需要将一个数据包发送 ...

  4. 网络层协议详解(主要是IP协议、ICMP协议和ARP协议)

    网络层协议详解(主要是IP协议.ICMP协议和ARP协议) 一.网络层的功能 定义了基于IP协议的逻辑地址: 连接不同的媒介类型: 选择数据通过网络的最佳路径. 二.IP数据包格式 第一层 版本:该字 ...

  5. 网络层协议详解(IP协议、ICMP协议和ARP协议)

    这里写目录标题 一.网络层的功能 二.IP数据包格式 三.ICMP协议 四.ARP协议 一.网络层的功能 定义了基于IP协议的逻辑地址: 连接不同的媒介类型: 选择数据通过网络的最佳路径. 二.IP数 ...

  6. ARP协议详解之ARP动态与静态条目的生命周期

    ARP协议详解之ARP动态与静态条目的生命周期 ARP动态条目的生命周期 动态条目随时间推移自动添加和删除. q  每个动态ARP缓存条目默认的生命周期是两分钟.当超过两分钟,该条目会被删掉.所以,生 ...

  7. ARP协议详解之Gratuitous ARP(免费ARP)

    ARP协议详解之Gratuitous ARP(免费ARP) Gratuitous ARP(免费ARP) Gratuitous ARP也称为免费ARP,无故ARP.Gratuitous ARP不同于一般 ...

  8. ARP缓存表的构成ARP协议全面实战协议详解、攻击与防御

    ARP缓存表的构成ARP协议全面实战协议详解.攻击与防御 1.4.3  ARP缓存表的构成 在局域网的任何一台主机中,都有一个ARP缓存表.该缓存表中保存中多个ARP条目.每个ARP条目都是由一个IP ...

  9. 04 TCP/IP协议详解

    目录 章节目标 4.1 概述 1.为什么会有TCP/IP协议 2.介绍 4.2 TCP/IP协议族 4.2.1 TCP/IP协议栈 1.协议的分层 2. 主机与主机之间通信的三要素 3.应用层 4.传 ...

  10. IP,ARP,以太网--网络层与数据链路层详解

    目录 网络层 IP协议--网络层 基本概念 IP协议格式 IP地址 子网 网段划分 特殊的IP地址 IP地址的数量限制 私有IP地址和公网IP地址 路由 ICMP协议--网络层 ping命令 面试常问 ...

最新文章

  1. 锐捷EG易网关远程命令执行漏洞-1
  2. Tomcat基础教程(一)
  3. quartz java spring_从零开始学 Java - Spring 使用 Quartz 任务调度定时器
  4. Linux中配置文件复制粘贴格式错乱
  5. 串口传输(51单片机版)
  6. java 图片线条_JAVA 关于JFrame的问题,我的图片会被线条给覆盖住,怎样让图片在上面呢...
  7. ionic cordova 热更新
  8. 图解 Excel 添加数据透视表
  9. 爬虫小白第一篇 西刺代理
  10. 计算机键盘上删除,电脑键盘删除键是哪一个
  11. 基于springboot的美食点评APP设计与实现
  12. 微信会员卡-创建会员卡接口post参数字段说明
  13. 订单用户表2(用户名查询、手机号查询、选择城市、选择状态、选择月份、ID排序、添加数据、批量发货、批量删除、敏感字、修改数据)
  14. 在内存只有10M的空间中申请一块5M的数组空间,会导致OOM吗?
  15. mysql 复制frm_通过拷贝frm myd myi opt文件来实现mysql的备份和还原
  16. 零基础是学习Java还是大数据?
  17. c语言文件打开方式字符串,C语言打开文件-C语言打开文件的方式-C语言以只读方式打开文件-C语言以读写方式打开文件-嗨客网...
  18. 3分钟通过一个App的演示深入理解区块链运行原理
  19. 【学习贴】Ps终极动画练习
  20. 学Linux到底学什么?老司机来告诉你!

热门文章

  1. 中兴服务器管理口配置,中兴交换机简明配置教程
  2. 计算机留言板毕业论文摘要,留言板系统设计(毕业论文)
  3. vc2008编译libjpeg
  4. visio阵列_什么软件可以画这种图,Visio怎么画?
  5. 在国内 PMP 有多少含金量?分析+资料分享
  6. YUV444,YUV420P,YUV420SP,YUV422P,YUV422SP,NV12,NV21,NV16,NV61等格式区分与存储简介
  7. Unity最新官方下载地址 - Unity Download
  8. python切割音频文件_python3使用pydub切分音频文件
  9. iOS视频直播初窥:高仿喵播APP
  10. 图解Java设计模式