摘要

  • 1982 年的 RFC 826 解决了一个很窄却无法省略的问题:路由选定下一跳协议地址后,以太网仍需一个 48 位硬件地址。主机只在本地表中没有答案时,才向所在链路广播询问。
  • ARP 请求不仅提问,也暴露发送者自己的映射。目标在回答前就能学会如何回去,而缓存把这次观察变成后续帧的执行依据。
  • Proxy ARP、DHCP 最终检查和 IPv4 地址冲突检测揭示了权限边界:应答可能只是网关的转发承诺;配置记录有效,也仍可能被链路现场否决。

路由完成后还缺一个目的地

主机准备发送 IP 包时,路由表可以告诉它:目标在本地,或者应先交给某个网关,并指定出接口。但以太网控制器不能把“下一跳 IP 地址”直接写进目的字段。它需要另一种名字——当时是 48 位以太网地址。

David C. Plummer 在 1982 年 11 月发布的 RFC 826,正是从这道接缝开始。地址解析模块接收协议类型与目标协议地址,在自己的转换表里找对应硬件地址。命中就立即返回;未命中才在路由已经选定的那段本地网络上发问。

报文同时带硬件类型、协议类型、两种地址的长度、操作码,以及发送方和目标方在两个地址空间里的值。这种格式没有假定协议地址一定是 IPv4,也没有把以太网写成唯一介质。它承认两个命名体系彼此独立,必须通过一次可观察的交换建立关系。

因此,ARP 不是路由。路由先决定“眼前应交给哪个协议地址”。如果最终目的地在远端,IP 头仍写远端服务器,帧的目的地址却属于本地网关。两层指向不同设备并非冲突,而是一次跨网传输的两个阶段。

把问题说给附近所有人听

本地缓存没有映射时,请求者填写自己的硬件与协议地址,写明要找的目标协议地址,再把帧广播给整个局部链路。每台站点都能听见,但只有理解相应地址类型、并确认目标是自己的设备需要回答。

回答通常直接单播回请求者。发现阶段必须公开,是因为请求者尚不知道目标硬件地址;答案已有去处,就没有必要再次惊动所有邻居。RFC 826 还明确反对周期性播报整张表。若百台机器不停宣布大量彼此从不使用的关系,广播与缓存都会为“完整”付出无意义成本。

最初算法可能丢掉触发解析的 IP 包,等待高层重传。1989 年的 RFC 1122 后来建议链路层至少保留未解析目的地的最新一个包,避免每次会话的第一个包都必然牺牲。这个队列只优化执行,不增加应答者的可信度。

询问也必须限速。RFC 1122 要求防止对同一 IP 高频重复发送 ARP 请求,并建议每个目的地每秒不超过一次。没有回应可能是地址无人使用,也可能是丢包、休眠、分段或攻击;把问题喊得更响,并不会把不确定性变成所有权证明。

在读取操作码之前先学习

RFC 826 接收算法的顺序很有意味。设备先检查硬件和协议类型。如果缓存已经存在发送者协议地址,它就用报文里的新硬件地址更新旧值;如果自己正是目标且此前没有条目,就加入发送者映射。完成这些动作后,它才判断这是请求还是应答。

所以一份请求同时包含问题与陈述:“谁能接收目标地址的流量?”以及“若要回我,请用这个硬件地址。”目标还没回答,就已经学到了返回路径。链路上的监视器即使不运行上层协议,也能从 ARP 发送者字段观察本地活动。

新观察可以覆盖旧映射,这使迁移或重配置更容易恢复,也直接暴露其信任模型:ARP 包没有密码学身份凭据。最近听到的声明可能有用,也可能错误或恶意。缓存是行动假设,不是产权账簿。

RFC 826 讨论了老化与超时,却没有规定统一实现。RFC 1122 随后要求每个实现都必须能清掉过时条目;如果采用超时,时间还应可配置。它列举定时淘汰、向旧硬件地址单播确认、接受链路层提示、根据高层失败判断等方式。方法不同,共识只有一个:一次本地观察不能永久支配以后所有帧。

网关替别人回答时

1987 年 10 月的 RFC 1027 记录了 Proxy ARP。当时得州大学需要把大型以太网划为子网,许多厂商主机却尚不理解子网,而且同时修改多个操作系统并不现实。

若 A 广播询问 B,而 B 位于另一段物理网络,网关可依据路由知识用自己的硬件地址回答。A 把这个映射放进缓存,随后仍在 IP 包里写 B,却把承载它的本地帧交给网关。B 一侧也可发生对称代理,于是两端都不必看见子网边界。

兼容价值很清楚:网络能演进,而不必等待所有端系统同时升级。代价也清楚:应答不等于“我就是 B”,而是“把去 B 的帧交给我,我负责继续转发”。这是操作承诺,不是终端身份。

承诺是否兑现取决于 ARP 之外的路由与管理配置。多台代理网关都回答时,先到的应答可能占据缓存;错误代理会制造一个表面完整、后续却断裂的路径。ARP 报文本身不能证明 B 与回答者同处一机,也不能证明它有资格长期代表 B。

租约仍可能被网线拒绝

集中分配地址并未取消链路检查。1997 年的 DHCP 规范 RFC 2131 建议服务器重用地址前先探测,也要求客户端收到 DHCPACK 后做最后确认。

客户端可以发送 ARP 请求:硬件地址写自己,目标 IP 写待用地址,发送者 IP 写全零。全零意味着它还没有宣布“这个地址属于我”,从而避免邻居把一份尚可能撤销的映射写进缓存。

若发现地址已有人使用,客户端必须发送 DHCPDECLINE 并重新开始。确认可用后,再广播公告帮助邻居清理上一个使用者留下的旧缓存。DHCP 租约可以在服务器记录中完全正确,链路上仍可能存在旧设备、重复静态配置或伪造者。

这不是两个协议争权。DHCP 管理地址池与租期;ARP 检查这项决定即将落地的局部现场。记录层提出可用候选,观察层可以对安全执行提出反证。

从一次查找到持续冲突检测

2005 年的 RFC 3927 为 IPv4 链路本地地址规定了带时间约束的流程。主机随机等待,发送若干零源 IP 的 ARP Probe;若没有冲突,再发公告,发送者与目标 IP 都写已选地址。随机间隔避免一批同时启动的设备齐声竞争,冲突计数和限速则防止异常设备把网络拖入无限探测。

检查不能只做一次。两段各自正常的网络可能都有同一链路本地地址,后来它们被桥接到一起。开机时没有冲突,并不能保证未来拓扑变化后仍然没有。主机必须在使用期间继续观察。

2008 年的 RFC 5227 把 IPv4 地址冲突检测推广到更一般场景。它把 Probe 解释为一个问题和一份较弱声明:“有人用吗?”以及“我希望用。”Announcement 则更强:“我现在正在用。”

发生冲突后,普通主机可以立即退出,也可用一次公告进行防卫。如果在 DEFEND_INTERVAL 内再次看到冲突,就必须停止使用并通知配置方,避免两台机器互相广播、永不退让。默认路由器或 DNS 服务器等关键设备可被特别配置为不放弃,但仍应控制公告频率并留下证据;角色例外并不会自动变成身份认证。

冲突检测能减少事故,却也可被攻击者用来制造拒绝服务。无人回答一次 Probe,不代表地址永远空闲;回应一次,也不能证明合法所有权。它是一项足以改变当前行为的局部测试,而非裁决世界的法院。

ARP 数字注册表没有管什么

ARP 报文自身也使用协调过的编号。2009 年的 RFC 5494 规定 IANA 如何分配硬件类型与操作码,并预留实验值。没有这些共同编号,不同实现就无法一致解释同一串比特。

但管理协议词汇,不等于管理每个用该词汇表达的地址声明。IANA 可以协调某个硬件类型的编号,却不会因此决定某个 VLAN 上哪台机器可以使用某个 IPv4 地址。把互操作注册表解释成终端身份权力,会把语法层的协调扩大为它从未获得的授权。

一份必须懂得遗忘的本地账

ARP 的历史力量来自克制。它没有要求所有主机先向全球服务登记,也没有要求每个节点保存一份完整地图。需要通信时才在附近发问,得到候选后本地记住,足以支撑下一帧。

这种轻量设计也要求运营者保持边界意识。最新声明可能是假;代理可能遮蔽关键依赖;静态表可能活得比设备更久。安全不是来自把缓存叫作真相,而是让它受链路范围、时间、反证与恢复路径约束。

ARP 没有让网线成为权威,只让网线成为证人。最终仍由主机决定是否缓存、发送、重试、防卫或退出;若它把局部证词误当成永久身份,后果也由执行者承担。

来源与证据边界

RFC 826 提供原始格式、按需广播、先学习后读操作码和新值覆盖旧值的算法。RFC 1027 记录代理应答,RFC 1122 强制缓存淘汰与请求限速。RFC 2131 区分 DHCP 租约和本地最终检查;RFC 3927 规定链路本地探测;RFC 5227 推广冲突与有限防卫;RFC 5494 管理 ARP 编号。

这些文档证明设计与规范要求,不证明全网部署时间或今天的普及率。一份 ARP 抓包只能证明某个局部链路在某时观察到某个声明,不能单独证明身份、所有权、意图或代理之后的实际交付。