《TCP/IP 详解 卷一:协议》第四章:地址解析协议

4.1 引言

IP 协议的设计目标是为跨越不同类型物理网络的分组交换提供互操作。这需要网络层软件使用的地址和底层网络硬件使用的地址之间进行转换。网络接口硬件通常有一个主要的硬件地址(例如以太网或 802.11 无线接口的 48 位地址)。由硬件交换的帧需要使用正确的硬件地址定位到正确的接口;否则,无法传输数据。但是,一个传统 IPv4 网络需要使用自己的地址:32 位的 IPv4 地址。如果一台主机要将一个帧发送到另一台主机,仅知道这台主机的 IP 地址是不够的,还需要知道主机在网络中的有效硬件地址。操作系统软件(即以太网驱动程序)必须知道目的主机的硬件地址,以便直接向它发送数据。对于 TCP/IP 网络,地址解析协议(ARP) [RFC0826] 提供了一种在 IPv4 地址和各种网络技术使用的硬件地址之间的映射。 ARP 仅用于 IPv4, IPv6 使用邻居发现协议,它被合并入 ICMPv6 (见第 8 章)。

这里需要注意的是,网络层地址和链路层地址是由不同部门分配的。对于网络硬件,主地址是由设备制造商定义的,并存储在设备的永久性内存中,所以它不会改变。因此,工作在特定硬件技术上的任意协议族,必须利用特定类型的地址。这允许不同协议族中的网络层协议同时运行。另一方面,网络接口的 IP 地址是由用户或网络管理员分配的,并且可以接需选择。为便携设备分配的 IP 地址可能改变,例如设备移动时。 IP 地址通常从维护附近网络连接点的地址池中获得,它在系统启用或配置时分配(见第 6 章)。当两个局域网的主机之间传输的以太网帧包含 IP 数据报时,由 48 位以太网地址确定该帧的目的接口。

地址解析是发现两个地址之间的映射关系的过程。对于使用 IPv4 的 TCP/IP 协议族,这是由运行的 ARP 来实现的。 ARP 是一个通用的协议,从这个意义上来看,它被设计为支持多种地址之间的映射。实际上, ARP 几乎总是用于 32 位 IPv4 地址和以太网的 48 位 MAC 地址之间的映射。这种情况在 [RFC0826] 中进行描述,它也是我们感兴趣的。在本章中,我们将互换使用以太网地址和 MAC 地址。

ARP 提供从网络层地址到相关硬件地址的动态映射。我们使用动态这个术语是因为它会自动执行和随时间变化,而不需要系统管理员重新配置。也就是说,如果一台主机改变它的网络接口卡,从而改变了它的硬件地址(但保留其分配的 IP 地址), ARP 可以在一定延时后继续正常运作。 ARP 操作通常与用户或系统管理员无关。

注意 提供 ARP 反向映射的协议称为 RARP,它用于缺少磁盘驱动器(通常是无盘工作站或 X 终端)的系统。它在当前已很少使用,而且需要系统管理员手功配置。详情见 [RFC0903] 。


4.2 一个例子

当我们使用 Internet 服务时,例如在浏览器中打开一个网页,本地计算机必须确定如何与相关的服务器联系。它首先是判断该服务位于本地(同一 IP 子网的一部分)还是远程。如果是远程的,需要一台可到达目的地的路由器。仅在到达位于同一 IP 子网的系统时,ARP 才能工作。那么对于这个例子,我们假设使用 Web 浏览器打开以下网址:

http://10.0.0.1

注意,这个 URL 包含一个 IPv4 地址,而不是更常见的域名或主机名。这里使用地址的原因是要强调一个事实,例子中是共享相同 IPv4 前缀的相关系统(见第 2 章)。这里,我们使用包含地址的 URL,以确定一个本地的 Web 服务器,并探索 直接交付 的运行原理。随着嵌入式设备(例如打印机和 VoIP 适配器)使用内置 Web 服务器进行配置,这种本地服务器越来越常见。

4.2.1 直接交付和 ARP

在本节中,我们列出了直接交付的步骤,重点集中在 ARP 的运行上。直接交付发生在一个 IP 数据报被发送到一个 IP 地址,而该地址与发送方具有相同 IP 前缀的情况下。在 IP 数据报转发(见第 5 章)的常见方式中,它扮演着一个重要角色。下面用前面的例子列出 IPv4 直接交付的基本操作:

  1. 在这种情况下,应用程序是一个 Web 浏览器,调用一个特殊函数来解析 URL,看它是否包含主机名。这里不是,应用程序使用 32 位 IPv4 地址 10.0.0.1
  2. 应用程序要求 TCP 协议建立一条到 10.0.0.1 的连接。
  3. 通过向 10.0.0.1 发送一个 IPv4 数据报,TCP 尝试向远程主机发送一个连接请求(第 15 章将介绍细节)。
  4. 我们假设地址 10.0.0.1 使用与发送主机相同的网络前缀,数据报可被直接发送到这个地址而不经过任何路由器。
  5. 假设以太网兼容地址被用于 IPv4 子网,发送主机必须将 32 位的 IPv4 目的地址转换为 48 位的以太网地址。使用 [RFC0826] 的术语,就是需要从 逻辑 Internet 地址向对应 物理 硬件地址进行转换。这是 ARP 功能。ARP 工作在正常模式下,仅适用于 广播网络,链路层能将一个消息交付到它连接的所有网络设备。这是 ARP 运行的一个重要要求。在非广播网络(有时被称为 非广播多路访问(NBMA))中,可能需要更复杂的映射协议 [RFC2332] 。
  6. 在一个共享的链路层网段上,ARP 向所有主机发送一个称为 ARP 请求 的以太网帧。这被称为 链路层广播。图 4-1 的斜线阴影中显示了一个广播域。ARP 请求包含目的主机的 IPv4 地址(10.0.0.1),并寻找以下问题的答案:“如果你将 IPv4 地址 10.0.0.1 配置为自己的地址,请向我回应你的 MAC 地址。”
  7. 通过 ARP,同一广播域中的所有系统可接收 ARP 请求。这包括可能根本不允许 IPv4 或 IPv6 协议的系统,但不包括位于不同 VLAN 中的系统,即使支持它们(VLAN 详细信息见第 3 章)。如果某个系统使用请求中指出的 IPv4 地址,它仅需要响应一个 ARP 应答。这个应答包含 IPv4 地址(与请求相匹配)和对应的 MAC 地址。这个应答通常不是广播,而是仅直接发送给请求的发送方。同时,接收 ARP 请求的主机学习 IPv4 到 MAC 地址的映射,并记录在内存中供以后使用(见 4.3 节)。
  8. ARP 应答被原始请求的发送方接收,现在可发送引起这次 ARP 请求/应答交换过程的数据报。
  9. 发送方可将数据报封装在以太网帧中直接发送到目的主机,并使用由 ARP 交换学到的以太网地址作为目的地址。由于这个以太网地址仅指向正确的目的主机,所有其他主机或路由器不会接收到这个数据报。因此,当仅使用直接交付时,并不需要经过路由器。
图 4-1

图 4-1 以太网主机在同一广播域中。ARP 查询使用链路层广播帧发送,并被所有主机接收。 IP 地址匹配的主机直接向请求主机返回响应。 IP 地址不匹配的主机主动丢弃 ARP 查询

ARP 用于运行 IPv4 的多接入链路层网络,每个主机都有自己首选的硬件地址。点到点链路(例如 PPP)不使用 ARP (见第 3 章)。当这些链路被建立后(通常是由用户或系统来发起创建),在链路两端通知正在使用的地址。由于不涉及硬件地址,因此不需要地址解析或 ARP。


4.3 ARP 缓存

ARP 高效运行的关键是维护每个主机和路由器上的 ARP 缓存(或表)。该缓存使用地址解析为每个接口维护从网络层地址到硬件地址的最新映射。当 IPv4 地址映射到硬件地址时,它对应于高速缓存中的一个条目,其正常到期时间是条目创建开始后的20分钟,这在 [RFC1122] 中描述。

我们可在 Linux 或 Windows 中使用 arp 命令查看 ARP 缓存。选项 -a 用于显示这两个系统的缓存中的所有条目。在 Linux 中,运行 arp 会产生以下输出:

Linux% arp
Address                  HWtype  HWaddress           Flags Mask            Iface
gw.home            ether   00:0D:66:4F:60:00   C                     eth0
printer.home              ether   00:0A:95:87:38:6A   C                     eth0
Linux% arp -a
printer.home (10.0.0.4) at 00:0A:95:87:38:6A [ether] on eth1
gw.home (10.0.0.1) at 00:0D:66:4F:60:00 [ether] on eth1

在 Windows 中,运行 arp 会产生以下类似的输出:

c:\> arp -a
Interface: 10.0.0.56 --- 0x2
  Internet Address         Physical Address              Type
  10.0.0.1            00-0d-66-4f-60-00     dynamic
  10.0.0.4            00-0a-95-87-38-6a     dynamic

这里,我们看到的是 IPv4 到硬件地址的缓存。在第一个(Linux)例子中,每个映射是一个包含 5 个元素的条目:主机名(对应一个 IP 地址)、硬件地址类型、硬件地址、标志和本地网络接口(它对于这个映射是活跃的)。标志列包含一个符号:C、 M 或 P。 C 类条目由 ARP 协议动态学习, M 类条目通过手工输入(arp -s ;见 4.9 节),而 P 类条目的含义是“发布”。也就是说,对于任何 P 类条目,主机对输入的 ARP 请求返回一个 ARP 应答。这个选项用于配置代理 ARP(见 4.7 节)。第二个 Linux 的例子显示了使用“BSD 风格”的类似信息。这里,给出了主机名和地址,对应的地址类型([ether] 表示一个以太网类型的地址),以及映射活跃在哪个接口上。

Windows 的 arp 程序显示了接口的 IPv4 地址,它的接口号是十六进制数(这里的 0x2)。Windows 版本还指出地址是手动输入还是 ARP 学习。在这个例子中,两个条目都是动态的,这意味着它们来自 ARP 学习(如果通过手工输入,它们是静态的)。注意, 48 位 MAC 地址被显示为 6 个十六进制数,在 Linux 中使用冒号分隔,在 Windows 中使用短杠(dash)分隔。在传统上, UNIX 系统一直使用冒号,而 IEEE 标准和其他操作系统倾向于使用短杠。我们在 4.9 节中讨论 arp 命令的附加功能和其他选项。


4.4 ARP 帧格式

图 4-2 显示了在以太网中转换一个 IPv4 地址时常用的 ARP 请求和应答分组的格式(正如前面所说, ARP 通常也能用于 IPv4 以外的地址,虽然这是非常少见的)。前 14 字节构成标准的以太网头部,假设没有 802.1p/q 或其他标记,其余部分由 ARP 协议来定义。 ARP 帧的前 8 个字节是通用的,这个例子中的剩余部分专门用于将 IPv4 地址映射到 48 位的以太网地址。

图 4-2

图 4-2 IPv4 地址映射到 48 位的 MAC(以太网)地址时使用的 ARP 帧格式

在图 4-2 所示的 ARP 帧的以太网头部中,前两个字段包含目的和源以太网地址。对于 ARP 请求,目的以太网地址 ff:ff:ff:ff:ff:ff (全部为 1)是广播地址,在同一广播域中的所有以太网接口可接收这些帧。在以太网帧中,对于 ARP (请求或应答), 2 字节的长度类型字段必须为 0x0806

长度/类型字段之后的前 4 个字段指定了最后 4 个字段的类型和大小。这些值由 IANA [RFC5494] 来指定。 术语硬件协议用于描述 ARP 分组中的字段。例如,一个 ARP 请求询问协议地址(在这种情况下是 IPv4 地址)对应的硬件地址(在这种情况下是以太网地址)。这些术讳很少被用于 ARP 之外。相对来说,硬件地址的常见术语有 MAC、物理链路层地址(或以太网地址,当网络基于 IEEE 802.3/以太网的一系列规范时)。 硬件类型字段指出硬件地址类型。 对于以太网,该值为 1。 协议类型字段指出映射的协议地此类型。 对于 IPv4 地址,该值为 0x0800。 当以太网帧包含 IPv4 数据报时,这可能与以太网帧的类型字段值一致。对于下面两个 1 字节的字段,硬件大小协议大小分别指出硬件地址和协议地址的字节数。对于以太网中使用 IPv4 地此的 ARP 请求或应答,它们的值分别为 6 和 4。 Op 字段指出该操作是 ARP 请求(值为 1)、 ARP 应答(2)、 RARP 请求(3)或 RARP应答(4)。由于 ARP 请求和 ARP 应答的长度/类型字段相同,因此这个字段是必需的。

紧跟在后面的 4 个字段是发送方硬件地址(在这个例子中是以太网 MAC 地址)、发送方协议地址(lPv4 地址)、目的硬件地址(MAC/以太网地址)和目的协议地址(IPv4 地址)。注意,这里存在一些重复的信息:以太网头部和 ARP 消息都包含发送方硬件地址。对于一个 ARP 请求,除了目的硬件地址(设为 0)之外,其他字段都需要填充。当一个系统接收到一个 ARP 请求,它填充自己的硬件地址,将两个发送方地址和两个接收方地址互换,将 Op 字段设置为 2,然后发送生成的应答。


4.5 ARP 例子

在本节中,我们将使用 tcpdump 命令查看在执行一个正常 TCP/IP 应用(例如 Telnet)时运行 ARP 所实际发生的过程。Telnet 是一个简单的应用程序,可用于在两个系统之间建立一条 TCP/IP 连接。

4.5.1 正常的例子

为了查看 ARP 运行,我们将执行 telnet 命令,使用 TCP 端口 80 (称为 www)连接到主机 10.0.0.3 上的 Web 服务器。

C:\> arp -a                    // 验证 arp 缓存为空
No ARP Entries Found
C:\> telnet 10.0.0.3 www                    // 连接到 Web 服务器 [端口80]
Connecting to 10.0.0.3...
Escape character is '^]'.

按下 CTRL + 右括号键获得 Telnet 客户机的提示。

Welcome to Microsoft Telnet Client
Escape Character is 'CTRL+]'
Microsoft Telnet> quit

指令 quit 用于退出程序。

在这些命令执行的同时,我们在另一个系统上预习呢 tcpdump 命令,并观察交换的流量信息。使用 -e 选项可以显示 MAC 地址(这个例子中是 48 位以太网地址)。

下面列出的内容包含来自 tcpdump 的输出。我们删除了输出的最后 4 行,它们用于终止连接(我们将在第 13 章中详细讨论),但与这里的讨论无关。注意,不同系统中的 tcpdump 版本提供的输出细节可能稍有不同。

Linux# tcpdump -e
1       0.0    0:0:c0:6f:2d:40    ff:ff:ff:ff:ff:ff    arp   60:
        arp    who-has    10.0.0.3    tell   10.0.0.56
2        0.002174    (0.0022)0:0:c0:c2:9b:26    0:0:c0:6f:2d:40    arp    60:
        arp    reply    10.0.0.3    is-at    0:0:c0:c2:9b:26

3       0.002831    (0.0007)0:0:c0:6f:2d:40    0:0:c0:c2:9b:26    ip    60:
        10.0.0.56.1030    >    10.0.0.3.www:    S    596459521:596459521(0)
        win    4096    <ms    1024>    [tos    0x10]
4       0.007834    (0.0050)0:0:c0:c2:9b:26    0:0:c0:6f:2d:40    ip    60:
        10.0.0.3.www    >    10.0.0.56.1030:    S    3562228225:3562228225(0)
        ack    596459522    win    4096    <mss    1024>
5       0.009615    (0.0018)0:0:c0:6f:2d:40    0:0:c0:c2:9b:26    ip    60:
        10.0.0.56.1030    >    10.0.0.3.discard:    .    ack    1    win    [tos    0x10]

在分组 1 中,源硬件地址为 0:0:c0:6f:2d:40。 目的硬件地址为ff:ff:ff:ff:ff:ff。 它是一个以太网广播地址。同一广播域(在同一局域网或 VLAN 中的所有主机,无论它们是否运行 TCP/IP)中的所有以太网接口接收并处理该帧,如图 4-1 所示。分组 1 的下一个输出字段为 arp,意味着帧类型字段为 0x0806。表明它是 ARP 请求或 ARP 应答。在前 5 个分组中, arp 和 ip 后面打印的值 60 是以太网帧的长度。 ARP 请求或 ARP 应答的大小是 42 字节(ARP 消息为 28 字节,以太网头部为 14 字节)。每个帧均填充为最小以太网帧:60 字节数据和 4 字节 CRC (见第 3 章)。

分组 1 的下一部分(即 arp who-has)用于标识该帧是 ARP 请求,目的地址是 IPv4 地址 10.0.0.3,源地址是 IPv4 地址 10.0.0.56。tcpdump 显示默认 IP 地址对应的主机名,但在这里没有显示(由于没有为它们建立反向 DNS 映射;第 11 章介绍 DNS 的细节)。接下来,我们使用 -n 选项查看 ARP 请求中的 IP 地址,无论它们是否进行 DNS 映射。

我们从分组 2 中看到,虽然 ARP 请求是广播的,但 ARP 应答的目的地址是(单播)MAC 地址 0:0:c0:6f:2d:40。因此,ARP 应答是直接发送到请求主机,它并不是通常的广播(在 4.8 节的一些情况下,这个规则可能会改变)。tcpdump 显示出该帧的 ARP 应答,以及响应者的 IPv4 地址和硬件地址。第 3 行是请求建立的第一个 TCP 段。其目的硬件地址属于目的主机(10.0.0.3)。我们将在第 13 章涉及这部分的细节。

对于每个分组,分组号后面的数字是 tcpdump 接收分组的相对时间(秒)。除第一个之外的每个分组都包含从前一段时间到现在的时间差(秒),该值放在括号中。我们可以看到发送 ARP 请求和接受 ARP 应答之间的时间约为 2.2ms。第一个 TCP 段在此后 0.7ms 发送。在这个例子中,ARP 动态地址解析的开销少于 3ms。注意,如果主机 10.0.0.3 的 ARP 表项在 10.0.0.56 的 ARP 缓存中是有效的,最初的 ARP 交换并不会发生,最初的 TCP 段可能已使用目的以太网地址立即发送。

有关 tcpdump 输出的一个微妙问题是,在向 10.0.0.56 (第 4 行)发送自己的第一个 TCP 段之前,我们没看到来自 10.0.0.3 的 ARP 请求。10.0.0.3 在自己的 ARP 缓存中可能已有一个 10.0.0.56 的条目,通常当系统接收到发送给它的 ARP 请求时,除了发送 ARP 应答外,它还会在 ARP 缓存中保存请求者的硬件地址和 IP 地址。这是一个基于逻辑假设的优化,如果请求者发送一个数据报,该数据报的接收者可能发送一个应答。

4.5.2 对一个不存在的主机的 ARP 请求

如果 ARP 请求中指定的主机关闭或不存在,将会发生什么?为了查看这种情况,我们尝试访问一个不存在的本地 IPv4 地址,其前缀对应本地子网,但没有主机使用该地址。在这个例子中,我们使用 IPv4 地址 10.0.0.99

Linux% date ; telnet 10.0.0.99 ; date
Fri Jan 29 14:46:33 PST 2010
Trying 10.0.0.99...
telnet: connect to address 10.0.0.99: No route to host
Fri Jan 29 14:46:36 PST 2010               // 3s after previous date

Linux% arp -a
? (10.0.0.99) at <incomplete> on eth0

这是 tcpdump 的输出:

1    21:12:07.440845 arp who-has 10.0.0.99 tell 10.0.0.56
2    21:12:08.436842 arp who-has 10.0.0.99 tell 10.0.0.56
3    21:12:09.436836 arp who-has 10.0.0.99 tell 10.0.0.56

由于我们已知使用广播地址发送 ARP 请求,因此本次并没有指定 -e 选项。 ARP 请求的频率接近每秒一次,这是 [RFC1122] 建议的最大值。 Windows 系统中(没有给出图示)的测试显示出不同的行为。不是 3 个请求之间各间隔 1 秒,而是根据使用的应用程序或其他协议改变间隔。对于 ICMP 和 UDP (分别见第 8 章和第 10 章),使用的间隔约为 5 秒,而 TCP 使用的间隔为 10 秒。对于 TCP,在 TCP 放弃尝试建立一条连接之前, 10 秒间隔足以发送 2 个无须应答的 ARP 请求。


4.6 ARP 缓存超时

超时通常与 ARP 缓存中的每个条目相关(我们在后面将会看到, arp 命令允许管理员设置缓存条目永远不超时)。在大多数实现中,完整条目的超时为 20 分钟,而不完整条目的超时为 3 分钟(我们在前面的例子中看到一个不完整条目,它强迫执行一次到不存在主机的 ARP 请求)。这些实现通常在每次使用一个条目后为它重新启动 20 分钟的超时。 [RFC1122] 是描述主机需求的 RFC,它规定每个条目即使在使用也应启动超时,但很多实现并不这样做,它们在每次使用条目后重新启动超时。

注意,这是关于软状态的一个重要例子。软状态是指在超时到达前没有更新而被丢弃的信息。如果网络条件发生玫变,软状态有助于启动自动重新配置,因此很多 Internet 协议使用软状态。软状态的成本是协议必须刷新状态以避免过期。在一些协议设计中,经常包括“软状态刷新”,以保持软状态的活跃。


4.7 代理 ARP

代理 ARP [RFC1027] 使一个系统(通常是一台专门配置的路由器)可回答不同主机的 ARP 请求。它使 ARP 请求的发送者认为做出响应的系统就是目的主机,但实际上目的主机可能在其他地方(或不存在)。ARP 代理并不场景,通常应尽量避免使用它。

代理 ARP 也被成为 混杂 ARPARP 黑客。这些名称来自 ARP 代理的历史用途:两个物理网络相互隐蔽自己。在这种情况下,两个物理网络可使用相同的 IP 前缀,只要将中间的路由器配置为一个代理 ARP,在一个网络中由代理响应对其他网络中主机的 ARP 请求。这种技术可用于向一组主机隐藏另一组主机。从前,这样做有两个常见原因:有些系统无法进行子网划分,有些系统使用比较旧的广播地址(全 0 的主机 ID,而不是当前全 1 的主机 ID)。

Linux 支持一种称为自动代理 ARP 的功能。它可通过在文件 /proc/sys/net/ipv4/confys/proxy_aap 中写入字符 1,或使用 sysctl 命令来启用。它支持使用代理 ARP 功能,而不必为被代理的每个可能的 IPv4 地址手工输入 ARP 条目。这样做允许自动代理一个地址范围,而不是单个地址。


4.8 免费 ARP 和地址冲突检测

ARP 的另一个功能被称为免费 ARP。它发生在一台主机发送 ARP 请求以寻找自己的地址时。它通常出现在启动时,当接口被配置为“上行”时常这样做。下面是一个例子,在一台 Linux 机器上跟踪显示 Windows 主机的启动:

Linux# tcpdump -e -n arp
1        0.0    0:0:c0:6f:2d:40    ff:ff:ff:ff:ff:ff    arp    60:
        arp who-has 10.0.0.56    tell    10.0.0.56

(我们为 tcpdump 增加 -n 标志,以打印数字化的点分十进制地址而不是主机名。)就 ARP 请求字段而言,发送方协议地址和目的协议地址相同:10.0.0.56。另外,以太网头部中的源地址字段被 tcpdump 显示为 0:0:c0:6f:2d:40,它等于发送方硬件地址。免费 ARP 需要达到两个目标:

  1. 允许一台主机确定另一台主机是否配置相同的 IPv4 地址。发送免费 ARP 的主机并不期望它的请求获得应答。但是,如果它接收到一个应答,通常显示的是错误消息“从以太网地址......发送的重复 IP 地址”。这是对系统管理员和用户的警告,在同一广播域(例如局域网或 VLAN)中有一个系统配置出错。
  2. 如果发送免费 ARP 的主机已改变硬件地址(关闭主机或替换接口卡,然后重新启动主机),该帧导致任何接收广播并且其缓存中有该条目的其他主机,将该条目中的旧硬件地址更新为与该帧一致。如前面所述,如果一台主机接收到一个 ARP 请求,该请求来自一个已存在接收方缓存中的 IPv4 地址,则缓存条目更新为 ARP 请求中发送方的硬件地址。这由接收到 ARP 请求的主机完成,免费 ARP 正好利用这个特性。

虽然免费 ARP 提供的一些迹象显示,多个站可尝试使用相同 IPv4 地址,但它实际上没有对这种情况提供解决机制(除了显示一个消息,实际由系统管理员完成)。为了解决这个问题, [RFC5227] 描述了 IPv4 地址冲突检测(ACD)。 ACD 定义了 ARP 探测分组和 ARP 通告分组。ARP 探测分组是一个 ARP 请求分组,其中发送方协议(IPv4)地址字段被设置为 0。探测分组用于查看一个候选 IPv4 地址是否被广播域中的任何其他系统所使用。通过将发送方协议地址字段设置为 0,避免候选 IPv4 地址被另一台主机使用时的缓存污染,这是它与免费 ARP 工作方式的一个差别。ARP 通告与 ARP 探测相同,除了其发送方协议地址目的协议地址字段被填充为候选 IPv4 地址外。它用于通告发送方使用侯选 IPv4 地址的意图。

为了执行 ACD,当一个接口被启用或从睡眠中唤醒,或一个新链路建立(例如,当一个新的无线网络关联建立)时,这台主机发送一个 ARP 探测分组。在发送 3 个探测分组之前,首先需要等待一个随机时间(范围为 0 ~ 1 秒,均匀分布)。当多个系统同时启用时,通过延迟来避免启用带来的拥塞,否则都立即执行 ACD,这将导致网络流量激增。探测分组之间存在一个随机的时间间距,大约 1 ~ 2 秒的延迟(均匀分布)。

当请求站发送探测的探测时,它可能接收到 ARP 请求或应答。对其探测的应答表明其他站已使用候选 IP 地址。从不同系统发送的请求,其目的协议地址字段中包含相同的候选 IPv4 地址,表明其他系统也在同时尝试获得候选 IPv4 地址。在这两种情况下,该系统将会显示一个地址冲突消息,并采用其他可选地址。例如,当使用 DHCP (见第 6 章)分配地址时,这是推荐的行为。 [RFC5227] 对尝试获得地址设置了 10 次的冲突限制,在请求的主机进入限速阶段之前,它被允许每 60 秒执行一次 ACD,直至成功。

根据前面所描述的过程,如果发送请求的主机没有发现冲突,它会间隔 2 秒向广播域中发送 2 个 ARP 通告,以表明它现在使用这个 IPv4 地址。在这个通告中,发送方协议地址目的协议地址字段被设置为其声称的地址。发送这些通告的目的是确保更新缓存地址映射,以正确反映发送方当前使用的地址。

ACD 被认为是一个持续的过程,这是它与免费 ARP 的区别。当一台主机通告它正使用的地址后,它会继续检查输入的 ARP 流量(请求和应答),查看自己的地址是否出现在发送方协议地址字段中。如果是的话,说明其他系统与自己在使用相同的地址。在这种情况下,[RFC5227] 提供了 3 种可能的解决方案:停止使用这个地址;保留这个地址,但发送一个“防御性” ARP 通告,如果冲突继续,则停止使用它;不理会冲突,仍继续使用。对于最后一个选择,仅建议那些真正需要一个固定、稳定地址的系统(例如打印机或路由器等嵌入式设备)使用。

[RFC5227] 还说明了使用链路层广播发送 ARP 应答的潜在好处。虽然这不是传统的 ARP 工作方式,但同一网段中所有站需处理 ARP 流量时,这样做可带来一些好处。广播应答可以更快地执行 ACD,这是由于所有站都会注意到这个应答,并在发现冲突时使自己的缓存无效。


4.9 arp 命令

在 Windows 和 Linux 中,我们使用带有 -a 标志的 arp 命令显示 ARP 缓存中的所有条目(在 Linux 上,我们可不使用 -a 而获得类似信息)。超级用户或管理员可指定 -d 选项来删除 ARP 缓存中的条目(这在运行一些例子前用于强制执行一次 ARP 交换。)

我们也可以使用 -s 选项增加条目。它需要一个 IPv4 地址(或使用 DNS 从 IPv4 地址转换的主机名)和一个以太网地址。这个 IPv4 地址和以太网地址作为一个条目被添加在缓存中。这个条目是半永久性的(即它在缓存中不会超时,但在系统重启时消失)。

Linux 版本的 arp 比 Windows 版本提供更多功能。当在命令行结尾使用关键字 temp,并使用 -s 增加一个条目时,这个条目被认为是临时的,并与其他 ARP 条目一样会超时。当在命令行结尾使用关键字 pub 并使用 -s 时,系统对该条目做出 ARP 应答。系统对 ARP 请求的 IPv4 地址以相应的以太网地址来应答。如果通告地址是系统自己的地址之一,该系统可作为一个指定 IPv4 地址的代理 ARP (见 4.7 节)。如果 arp -s 用于启用代理 ARP, Linux 对指定地址做出应答,在 /proc/sys/net/ipv4/conf/*/proxy_arp 文件中写人 0。


4.10 使用 ARP 设置一台嵌入式设备的 IPv4 地址

随着越来越多的嵌入式设备与以太网、 TCP/IP 协议兼容,那些无法直接输入网络配置信息的联网设备越来越普遍(例如,它们没有键盘,难以输入自已使用的 IP 地址)。这些设备通常采用以下两种方式之一配置:一种是使用 DHCP 自动分配地址和其他信息(见第 6 章);另一种是使用 ARP 设置 IPv4 地址,虽然这种方法并不常见。

通过 ARP 为嵌入式设备配置 IPv4 地址不是协议的初衷,这是由于它不是完全自动的。它的基本思路是为设备手动建立一个 ARP 映射(使用 arp -s 命令),然后向这个地址发送一个 IP 分组。由于相应 ARP 条目已存在,因此不会产生 ARP 请求/应答。相反,硬件地址可以立即使用。当然,设备的以太网(MAC)地址必须已知。它通常印在设备上,有时兼作制造商的设备序列号。当设备接收到一个目标为自身硬件地址的分组时,这个数据报包含的目的地址用于指定其初始 IPv4 地址。此后,这台设备可用其他方式(例如通过一个嵌入式 Web 服务器)完成配置。


4.11 与 ARP 相关的攻击

目前已有一系列涉及 ARP 的攻击。最直接的是使用代理 ARP 功能假扮主机,对 ARP 请求做出应答。如果受害主机不存在,这很直观,而且可能难以发现。如果该主机仍在运行,这被认为更困难,因为每个 ARP 请求可能有多个应答,这样比较容易发现。

一种更巧妙的攻击可被 ARP 触发,它涉及一台主机被连接到多个网络,并且一个接口的 ARP 条目被其他 ARP 表“遗漏”的情况,这是由 ARP 软件的一个错误造成的。利用这种漏洞可将流量引导到错误网段上。 Linux 提供了一个直接影响该行为的方式,可通过修改文件 /proc/sys/net/ipv4/conf/*/arp_filter 实现。如果将数值 1 写入这个文件,当输入的 ARP 请求到达一个接口时,就进行一次 IP 转发检查。这时需要查找请求者的 IP 地址,以确定哪个接口将用于发送返回的 IP 数据报。如果到达的 ARP 请求与返回发送方的 IP 数据报使用不同的接口,这个 ARP 应答被抑制(触发它的 ARP 请求被丢弃)。

更具破坏性的 ARP 攻击涉及静态条目处理。如前所述,当查找对应一个特定 IP 地址的以太网(MAC)地址时,静态条目可用于避免 ARP 请求/应答。这种条目已被用于尝试增强安全性。它的思路是在 ARP 缓存中对重要主机使用静态条目,以快速检测任何针对该 IP 地址的主机欺骗。不幸的是,大多数 ARP 实现通常用 ARP 应答提供的条目代替静态缓存条目。这样的后果是,接收到 ARP 应答(即使它没发送 ARP 请求)的主机被欺骗,并使用攻击者提供的条目代替自己的静态条目。


4.12 总结

ARP 是 TCP/IP 实现中的一个基本协议,但它通常在应用程序或用户没有察觉的情况下运行。 ARP 用于确定本地可达的 IPv4 子网使用的 IPv4 地址对应的硬件地址。它在数据报的目的地与发送方处于同一子网时使用,还用于数据报的目的地不在当前子网(在第 5 章详细说明)时将其转发到一台路由器。 ARP 缓存是其运行的基础,我们可使用 arp 命令查看和处理缓存。缓存中每个条目都有一个计时器,用于清除不完整的条目和完整的条目。 arp 命令可显示和修改 ARP 缓存中的条目。

我们深入了解特殊 ARP 的正常运行:代理 ARP (一台路由器回答主机通过另一台路由器接口访问的 ARP 请求)和免费 ARP (发送自己拥有的 IP 地址的 ARP 请求,通常用于引导)。我们还讨论了 IPv4 地址冲突检测,采用一种持续运行的类似免费 ARP 的交换,来避免在同一广播域中地址重复。最后,我们讨论了一系列涉及 ARP 的攻击。如果高层协议没有强大的安全措施,这可能会导致高层协议出现问题(见第 18 章)。


4.13 参考文献

[RFCO826] D. Plummer, "Ethernet Address Resolution Protocol: Or Converting Network Protocol Addresses to 48.bit Ethernet Address for Transmission on Ethernet Hardware," Internet RFC 0826/STD 0037, Nov.1982.

[RFCO903]R. Finlayson, T. Mann,J. C. Mogul, and M. Theimer, "A Reverse Address Resolution Protocol," Internet RFC 0903/STD 0038,June 1984.

[RFC1027] S. Carl-Mitchell and J. S. Quarterman, "Using ARP to Implement Transparent Subnet Gateways," Internet RFC 1027,Oct. 1987.

[RFC1122]R. Braden, ed., "Requirements for Internet Hosts," Internet RFC 1122/STD 0003,Oct. 1989.

[RFC2332] J. Luciani, D. Katz, D. Piscitello, B. Cole, and N. Doraswamy, "NBMA Next Hop Resolution Protocol (NHRP)," Internet RFC 2332,Apr. 1998.

[RFC5227] S. Cheshire, "IPv4 Address Conflict Detection," Internet RFC 5227, July. 1998.

[RFC5494] J.Arkko and C. Pignataro, "IANA Allocation Guidelines for the Address Resolution Protocol(ARP)" Internet RFC 5494,Apr. 2009.