ARP 是日常频繁使用的网络协议之一, 如果你在局域网中打开 tcpdump, 通常可以看到有比较频繁的 ARP 请求包, ARP (Address Resolution Protocol) 协议于 1982 年被标准化, 其正式的协议文档是 RFC 826, ARP 协议产生的背景是 DEC/Intel/Xerox 10 Mbit 以太网逐渐开始流行, 以太网以 MAC 帧作为数据传输的基本单元, 在同一个以太网环境下, 主机之间通过 48 位的 MAC 地址来进行通信, 而上层, 如 IP 协议则通过 32 位的 IP 协议进行通信, 网络层协议与数据链路层协议之间使用的地址并没有特定的函数关系, 这造成当 IP 协议通过路由算法确定出下一跳的目标主机时, 数据包无法直接根据 IP 地址投递给目标主机, 在 ARP 协议之前, 由于缺乏一个统一的标准, 因此由具体的实现者 (implementor) 自行来做 IP 地址与 MAC 地址的转换, 而 RFC 826 便是要解决这个问题, ARP 协议并非特定应用于 MAC 协议与 IP 协议的地址映射, 而是支持多种数据链路层协议与网络层协议

16.1 数据包格式

ARP 协议的数据包 (Packet) 被封装在 MAC 帧中, 作为 MAC 帧的数据部分, MAC 帧由 Header, Data Payload 和尾部的 FCS (帧检测序列) 三部分构成, MAC 帧的 Header 部分有 3 个字段, 分别是源 MAC 地址(6 Byte)、目标 MAC 地址(6 Byte)以及上层协议的类型(2 Byte), 在 RFC 826 之前, 按照以太网标准, 类型字段共有 3 个取值, 分别是

  • ether_type$XEROX_PUP
  • ether_type$DOD_INTERNET
  • ether_type$CHAOS

而 ARP 协议引入后, RFC 826 增加了一种新的类型: ether_type$ADDRESS_RESOLUTION, 用于表示这个 MAC 帧包含的是 ARP 数据包, ARP 数据包的结构如下所示:

对于 ARP 数据, 其帧类型便为 ether_type$ADDRESS_RESOLUTION, 硬件类型指示数据链路层的网络类型, 如以太网 (Ethernet), 协议类型指示上层的网络协议类型, 如 IP 协议, 硬件地址长度以字节为单位表征硬件类型对应的主机地址标识符的长度, 对于以太网来说, 该值为 6, 同理, 协议地址长度以字节为单位标识上层协议的地址标识符的长度, 对于 IP 协议来说, 该值为 4, 操作类型有两个取值: REQUEST 和 REPLY, 用于表征当前数据包是 ARP 请求数据包还是 ARP 响应数据包, 而发送者的硬件地址对于以太网来说便是 MAC 地址, 发送者协议地址便是发送主机对应的源 IP 地址, 目标硬件地址和目标协议地址与之相同, 不再赘述

16.2 ARP 工作机制

从 ARP 协议的数据包结构来看, 它的硬件类型和协议类型是可配置的, 因此它可以支持多种上层网络协议与下层硬件协议的映射, 写成一般形式, ARP 协议便是要解决 < Protocol, Address > 到硬件地址地址的映射, 目前我们使用的绝大多数局域网都是通过 WIFI (IEEE 802.11, 使用 CSMA/CA 做介质访问控制) 或有线连接 (IEEE 802.3, 使用 CSMA/CD 做介质访问控制) 进行连接, 它们都使用 48 位的 MAC 地址来进行通信, 因此我们只讨论 IP 地址映射为 MAC 地址的情形

当局域网的一台主机需要和另一台主机进行通信时, 假定已知道对方的 IP 地址, 但它没有该 IP 地址对应的 MAC 地址, 此时它需要在该局域网内广播发送 ARP 请求包, ARP 请求包里携带发送者自身的 MAC 地址, 自身的 IP 地址, 希望请求的目标主机的 IP 地址, 目标主机的 MAC 地址字段置为 0, 当 ARP 请求包发出以后, 局域网内的所有主机都将收到这个 ARP 请求

收到 ARP 数据包的主机执行如下的步骤:

  1. 检查自己的硬件地址类型与 ARP 数据包的硬件地址类型相同, 由于我们讨论的都是在普通的使用 MAC 地址的局域网下, 因此这项检查都是通过的, 当然主机也应 (SHOULD) 在检查硬件地址类型相同之后, 进一步检查硬件地址的长度是否与 ARP 数据包的硬件地址长度是相等的

  2. 主机设置一个布尔型的标志位 Merge_Flag, 其初始值为 false, 如果 ARP 数据包中的发送者主机 IP 和发送者硬件地址在自己的 ARP 映射表中, 则主机应更新本机的 ARP 映射表, 并将 Merge_Flag 设置为 true

  3. 接下来, 主机检查 ARP 数据包中的目标主机 IP 是否其自身, 如果是的话, 则该主机就是 ARP 请求的目标主机, 如果 Merge_Flag 为 false, 则主机应将发送者主机 IP, 发送者 MAC 地址写到自己的 ARP 映射表中, 然后检查 ARP 数据包的操作类型字段, 如果此次的 ARP 数据包是 ARPREQUEST, 此时主机应将发送者的 IP 与发送者的 MAC 地址写到 ARP 数据包的目标主机的 IP 字段和目标主机的硬件地址字段上, 而将自身的 IP 地址与自身的 MAC 地址写到发送者的 IP 字段与发送者的 MAC 地址字段, 并将操作类型字段改为 ARPREPLY, 并以单播的方式发给目标主机

上面的 ARP 处理环节有几点需要注意:

  • ARP 请求是广播发送, 但 ARP 应答是单播发送

  • 主机首先检查 ARP 数据包的发送者 IP 与发送者 MAC 地址是否在自己的 ARP 映射表中, 注意此时并没有预先去检查操作码字段, 换句话说, 无论该 ARP 数据包是 ARP 请求包还是 ARP 应答包, 主机都应首先将发送者主机 IP 与发送者 MAC 地址写到自己本机的 ARP 映射表中

16.3 使用 tcpdump 观察 ARP 请求与应答

我们可以使用 tcpdump 来观察局域网内的 ARP 请求与响应数据包, 打开终端, 键入 sudo tcpdump 'arp' -vv, 便可以获取局域网的 ARP 请求与响应数据包, 如下图所示


16.4 Gratuitous ARP (免费 ARP)

注意 16.3 的 tcpdump 输出中, 除了常规的 ARP Request 和 ARP Reply 之外, 还有一类特殊的 ARP Announcement 数据包, 注意到 ARP Announcement 数据包请求的 IP 地址与其自身的 IP 地址是相同的, 此类请求也可以被称为免费 ARP (Gratuitous ARP), 普通 ARP 请求的目的是为了获得某个 IP 地址对应的 MAC 地址, 而免费 ARP 的作用一方面是向局域网主机宣告自己的 IP 地址与 MAC 地址的映射关系, 另一方面也可以用来探测 (probe) IP 地址是否冲突, 比如在 DHCP [RFC 2131] 协议中, 当主机收到 DHCP Server 发来的 DHCPACK 之后, 应向局域网广播发送免费 ARP 数据包, 若收到了某主机的响应, 说明该 IP 地址与局域网某主机的 IP 地址冲突, 此时主机应重新发起 DHCP 申请

16.5 ARP 的缺陷

ARP 协议本身缺乏验证机制, 所有的请求和响应都是通过明文发送, 它是建立在相互信任的机制之上运行的, 因此也缺乏安全性, 例如我们可以伪造 ARP 应答, 随意封装一个错误的 ARP 应答包, 以发起 ARP 攻击, 此类攻击的门槛很低, 任何了解 ARP 协议的攻击者都可以轻而易举地发送欺骗应答, 为了解决此类问题, 最直接的方法可以是静态绑定局域网主机 IP 地址与 MAC 地址的映射关系, 但这缺乏了灵活性, 还有的方法是当主机首次运行 DHCP 时, 可以由统一的交换机记录下主机 IP 与 MAC 地址的映射关系, 之后当需要请求获得映射关系时可以通过交换机的映射表来查询, 这些方法都需要采取额外的机制, 读者可自行查阅更多相关的实践