昨天在定位一个 IP 分片丢包问题过程中,通过 Wireshark 抓包时发现两个设备之间在不时地互发单播类型的 ARP 请求报文,且相对应地有 ARP 响应报文(当然也是单播)。
在我的理解中,ARP 请求报文就是已知对方的 IP 地址,想要请求其 MAC 地址用于封装成以太网报文。在对方 MAC 地址未知的前提下,需要发送广播报文使整个子网内的设备都能收到此请求。当特定 IP 地址的设备收到此请求后,发送一个 ARP 响应报文给请求方。也就是说,ARP 请求报文应该是广播报文。
而单播 ARP 请求报文是什么概念呢?就是已知对方的 MAC 地址了,还向对方询问其 MAC 地址,这种做法类似于问对方:「张士超,你叫什么名字?」为什么会有这种「明知故问」的报文存在呢?
回来后 Google 了一下「unicast arp request」,在 ServerFault.com 的一个问答《Why ARP request is unicast?》中找到了答案。
原来,在 RFC 1122 中定义了四种用于刷新 ARP 缓存条目的机制,其中的第二种 Unicast Poll 就是定时向 ARP 缓存条目中的主机发送点到点(单播)的 ARP 请求报文,假如在 N 次连续超时时间过后,都没有收到对应主机的 ARP 响应报文,则将此条目从 ARP 缓存中删除(第一种是常见的老化机制,需要注意的是网络中的 ARP 广播报文中的源 MAC 地址会刷新缓存条目而重置老化定时器)。
IMPLEMENTATION: Four mechanisms have been used, sometimes in combination, to flush out-of-date cache entries.
(1) Timeout – Periodically time out cache entries, even if they are in use. Note that this timeout should be restarted when the cache entry is “refreshed” (by observing the source fields, regardless of target address, of an ARP broadcast from the system in question). For proxy ARP situations, the timeout needs to be on the order of a minute.
(2) Unicast Poll – Actively poll the remote host by periodically sending a point-to-point ARP Request to it, and delete the entry if no ARP Reply is received from N successive polls. Again, the timeout should be on the order of a minute, and typically N is 2.
[…]
这就是「明知故问」的单播 ARP 请求报文的真相。
值得一提的是,在 RFC 1122 文档中紧接四种 ARP 缓存刷新机制的后面,有这样一段说明:
Approaches (1) and (2) involve ARP cache timeouts on the order of a minute or less. In the absence of proxy ARP, a timeout this short could create noticeable overhead traffic on a very large Ethernet. Therefore, it may be necessary to configure a host to lengthen the ARP cache timeout.
也就是说,在有代理 ARP 存在的大型以太网环境中,前两种机制将显著增加网络开销,因此需要延长主机上 ARP 缓存的超时时间。
另外,Linux 下有个 arping 命令,可用于发送单播类型的 ARP 请求报文。本文开头的截图就是使用 arping 命令从本机的无线网卡 wlan0 向无线路由器(192.168.1.1)发送单播 ARP 请求报文,再使用 Wireshark 抓包实现的。
arping -I wlan0 192.168.1.1
arping 命令在发送单播 ARP 请求报文之前,总是会先发送一个常见的广播 ARP 请求报文,不管当前 ARP 缓存中是否有对应主机的 MAC 地址。详细选项及说明请参考 arping(8)。
实际上,在 Linux 下使用 arp(8) 命令查询主机上的 ARP 缓存时,也会先向缓存中的每个主机发送一个单播 ARP 请求报文,以确认对应主机是否在线并更新对应的缓存条目。
以上。