网络知识大全
RFC 精读 · Link · STD 37

RFC 826

An Ethernet Address Resolution Protocol —— 在 IPv4 局域网里,把“下一跳协议地址”动态翻译成 48-bit 以太网地址。

编号 / 标题
RFC 826 · An Ethernet Address Resolution Protocol
发布
November 1982 · David C. Plummer
状态
Internet Standard · STD 37
关系
Updated by RFC 5227RFC 5494
原文
rfc-editor HTML · 纯文本 · datatracker
实验室样本
ARP Request / Reply(EtherType 0x0806)
The Problem

为什么需要一张翻译表

The 10Mbit Ethernet allows all of these protocols
(and more) to coexist on a single cable by means of a type field
in the Ethernet packet header.  However, the 10Mbit Ethernet
requires 48.bit addresses on the physical cable, yet most
protocol addresses are not 48.bits long, nor do they necessarily
have any relationship to the 48.bit Ethernet address of the
hardware.  For example, CHAOS addresses are 16.bits, DOD Internet
addresses are 32.bits, and Xerox PUP addresses are 8.bits.  A
protocol is needed to dynamically distribute the correspondences
between a <protocol, address> pair and a 48.bit Ethernet address.

注解

以太网帧的目的地址是 48-bit MAC,IPv4 地址是 32-bit,两者没有换算公式。ARP 解决的是同一条链路上的下一跳:把 <协议类型, 协议地址> 动态映射成硬件地址。

注意原文写的是通用翻译,不是“只为 IP 发明的协议”。今天我们几乎只在 IPv4/以太网里见到它:ar$hrd=1ar$pro=0x0800ar$hln=6ar$pln=4

易误解:访问远方服务器时 ARP 解析的是服务器 MAC。错。主机只解析默认网关(或直连下一跳)的 MAC;路由器每跳都会换一帧。

Packet format

以太网封装 + ARP 载荷

    Ethernet transmission layer (not necessarily accessible to
	 the user):
	48.bit: Ethernet address of destination
	48.bit: Ethernet address of sender
	16.bit: Protocol type = ether_type$ADDRESS_RESOLUTION
    Ethernet packet data:
	16.bit: (ar$hrd) Hardware address space (e.g., Ethernet,
			 Packet Radio Net.)
	16.bit: (ar$pro) Protocol address space.  For Ethernet
			 hardware, this is from the set of type
			 fields ether_typ$<protocol>.
	 8.bit: (ar$hln) byte length of each hardware address
	 8.bit: (ar$pln) byte length of each protocol address
	16.bit: (ar$op)  opcode (ares_op$REQUEST | ares_op$REPLY)
	nbytes: (ar$sha) Hardware address of sender of this
			 packet, n from the ar$hln field.
	mbytes: (ar$spa) Protocol address of sender of this
			 packet, m from the ar$pln field.
	nbytes: (ar$tha) Hardware address of target of this
			 packet (if known).
	mbytes: (ar$tpa) Protocol address of target.

注解

外层 EtherType 是地址解析本身(今天写 0x0806),不是 0x0800。里面的 ar$pro 才声明“我要解析的是哪种协议地址”,以太网 IPv4 时填 0x0800

操作码:REQUEST = 1REPLY = 2(高字节先传)。后面四段地址长度由 hln/pln 决定,所以 ARP 不是定长 28 字节的抽象协议——只是以太网+IPv4 时恰好 28 字节。

请求里 ar$tha 未知,常填全 0;有的实现图省事填广播 MAC。规范允许“不设成任何特别值”。

Packet Generation

先查表,没有再广播

Packet Generation:
------------------

As a packet is sent down through the network layers, routing
determines the protocol address of the next hop for the packet
and on which piece of hardware it expects to find the station
with the immediate target protocol address.  In the case of the
10Mbit Ethernet, address resolution is needed and some lower
layer (probably the hardware driver) must consult the Address
Resolution module (perhaps implemented in the Ethernet support
module) to convert the <protocol type, target protocol address>
pair to a 48.bit Ethernet address.  The Address Resolution module
tries to find this pair in a table.  If it finds the pair, it
gives the corresponding 48.bit Ethernet address back to the
caller (hardware driver) which then transmits the packet.  If it
does not, it probably informs the caller that it is throwing the
packet away (on the assumption the packet will be retransmitted
by a higher network layer), and generates an Ethernet packet with
a type field of ether_type$ADDRESS_RESOLUTION.  The Address
Resolution module then sets the ar$hrd field to
ares_hrd$Ethernet, ar$pro to the protocol type that is being
resolved, ar$hln to 6 (the number of bytes in a 48.bit Ethernet
address), ar$pln to the length of an address in that protocol,
ar$op to ares_op$REQUEST, ar$sha with the 48.bit ethernet address
of itself, ar$spa with the protocol address of itself, and ar$tpa
with the protocol address of the machine that is trying to be
accessed.  It does not set ar$tha to anything in particular,
because it is this value that it is trying to determine.  It
could set ar$tha to the broadcast address for the hardware (all
ones in the case of the 10Mbit Ethernet) if that makes it
convenient for some aspect of the implementation.  It then causes
this packet to be broadcast to all stations on the Ethernet cable
originally determined by the routing mechanism.

注解

缓存命中:直接交出 MAC,上层那一帧可以发出去。未命中:原文的典型实现是丢掉当前数据包并广播请求,指望上层(TCP 等)重传。现代内核多半会把首包排队等 ARP 完成,但“先解析再发”这条逻辑没变。

请求发到路由选中的那根电缆上的广播——ARP 广播不过路由器。这也是“跨网段不要 ARP 对端主机”的物理原因。

Packet Reception

先合并发送方,再看操作码

?Do I have the hardware type in ar$hrd?
Yes: (almost definitely)
  [optionally check the hardware length ar$hln]
  ?Do I speak the protocol in ar$pro?
  Yes:
    [optionally check the protocol length ar$pln]
    Merge_flag := false
    If the pair <protocol type, sender protocol address> is
        already in my translation table, update the sender
	hardware address field of the entry with the new
	information in the packet and set Merge_flag to true. 
    ?Am I the target protocol address?
    Yes:
      If Merge_flag is false, add the triplet <protocol type,
          sender protocol address, sender hardware address> to
	  the translation table.
      ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
      Yes:
	Swap hardware and protocol fields, putting the local
	    hardware and protocol addresses in the sender fields.
	Set the ar$op field to ares_op$REPLY
	Send the packet to the (new) target hardware address on
	    the same hardware on which the request was received.

Notice that the <protocol type, sender protocol address, sender
hardware address> triplet is merged into the table before the
opcode is looked at.  This is on the assumption that communcation
is bidirectional; if A has some reason to talk to B, then B will
probably have some reason to talk to A.  Notice also that if an
entry already exists for the <protocol type, sender protocol
address> pair, then the new hardware address supersedes the old
one.  Related Issues gives some motivation for this.

注解

算法顺序是考点:先处理发送方映射,最后才看 opcode。原文假设通信是双向的——A 找 B,B 大概也要回 A。已有表项会被新的硬件地址直接覆盖。

只有“我是 TPA”时才会新建表项。别人的 ARP 对话,你若本来没有发送方的条目,不会因此塞满 ARP 表(这是对广播风暴的一点收敛)。但若你已有该 IP 的条目,任何人宣称“我是这个 IP”都能刷新 MAC——这就是 ARP 欺骗的规范缝。

应答是单播回请求方 MAC,不是再广播一次。请求才是广播。

易误解:IPv6 也用 ARP。错。IPv6 用 ICMPv6 Neighbor Discovery(NS/NA),没有 ARP。

抓包对照

Wireshark 显示 Ethernet II / ARP,没有 IP 层。过滤器 arpeth.type == 0x0806

Ethernet dst = ff:ff:ff:ff:ff:ff (请求)或 单播 MAC(应答) src = 发送方 MAC type = 0x0806 ARP 28 字节(以太网 + IPv4) 00 01 hrd = Ethernet 08 00 pro = IPv4 06 04 hln=6, pln=4 00 01 / 00 02 op = request / reply SHA (6) SPA (4) THA (6) TPA (4) tcpdump: arp arp[6:2] == 1 只看请求 arp[6:2] == 2 只看应答

考点与易错点

  1. ARP 解析的是下一跳,不是远端服务器。出网段时下一跳是默认网关。
  2. 请求广播、应答单播。广播不过普通路由器。
  3. 以太网 IPv4:EtherType 0x0806,hrd=1,pro=0x0800,op 1/2,载荷 28 字节。
  4. 接收算法先合并发送方、后看 opcode;已有表项会被新 MAC 覆盖,且无认证。
  5. RFC 5227 把“免费 ARP”拆开:Probe 的 SPA=0,用来做地址探测;Announcement / 传统 gratuitous ARP 的 SPA=TPA。单次传统 gratuitous(SPA=TPA)不提供可靠的重复地址检测
  6. IPv6 没有 ARP,改走 NDP。