ARP 与 NDP

本页目录

能 ping 通同网段,却访问不了远端,先看路由选出的下一跳,再看该下一跳的邻居解析。ARP/NDP 解决的是当前链路上的邻接问题,不负责寻找互联网中的目标位置。缓存已有有效映射、点到点链路或其他邻接机制也可能不需要逐次发送解析请求。

问题本篇入口不要混淆
ARP 应该问网关还是服务器路由与解析顺序最终 IP 与下一跳 IP
28 B ARP 为什么抓到 42/60 B报文字节账协议、以太网头、填充和 FCS
STALE 是否必须清空邻居状态可用映射与近期可达证明
IPv6 如何定向发现邻居NS/NA 与组播地址解析、可达性探测与 DAD
RA 怎样影响地址和默认路由自动配置前缀 L/A 标志、地址生命周期、路由器生命周期
加密隧道是否解决欺骗安全边界身份认证、转发与可用性

从一次跨网段发送讲起

假设 A 为 192.0.2.10/24,默认网关为 192.0.2.1,要访问 198.51.100.20。路由查询选择网关为下一跳,A 查询所在接口的邻居表;没有映射时,才解析 192.0.2.1 的 MAC,而不是对远端 198.51.100.20 广播。

先选下一跳,再解析它的 MAC:跨网段不会直接 ARP 远端 主机 A 192.0.2.10/24 本链路网关 192.0.2.1 ARP 广播:谁有 192.0.2.1? ARP 应答:网关 IP 对应网关 MAC IP 目的仍为 198.51.100.20,二层目的为网关 MAC 第一条请求在所在广播域传播,图中只画相关网关;邻居缓存命中时可跳过解析交互。

接口也是邻居上下文的一部分:相同 IPv4 地址可能出现在不同 VLAN 或网络命名空间中,不能用一个全局“IP→MAC 字典”描述所有系统状态。路由错误、VLAN 不通或接口选择错误,都可能表现为邻居解析失败。

ARP 报文与最小帧长度

Ethernet 上的 IPv4 ARP 使用 EtherType 0x0806,直接承载在以太网中,不经过 IPv4 头。它的通用字段允许不同地址长度,常见 Ethernet/IPv4 组合如下。RFC 826

字段字节数本例值
Hardware Type / Protocol Type2 + 21 / 0x0800
Hardware Length / Protocol Length1 + 16 / 4
Operation21 请求,2 应答
Sender Hardware / Protocol Address6 + 4发送者 MAC / IPv4
Target Hardware / Protocol Address6 + 4目标 MAC / IPv4

合计 28 B。加未标记以太网头 14 B 后只有 42 B,还需 18 B 填充才到不含 FCS 的 60 B,最后加 4 B FCS 为 64 B。这里的 46 B 最小以太网负载由 28 B ARP 和 18 B 填充组成,不包含以太网头与 FCS。抓包时填充和 FCS 是否可见又取决于位置与驱动。

初次解析请求通常以广播 MAC 发送,目标硬件地址尚未知;常见实现填零,但它不是用来决定广播范围的以太网目的地址。普通回复通常单播,也存在公告等不同使用形式,不能把所有 ARP 请求/应答方向固定化。

邻居表:有 MAC 与已确认可达是两件事

Linux 将 IPv4 ARP 与 IPv6 邻居行为纳入通用邻居框架。INCOMPLETE 表示正在解析,待发分组可在有限队列中等待;REACHABLE 表示近期得到相应可达确认;STALE 保留映射但确认已旧,不是条目“坏了”。

邻居状态描述映射与可达性:STALE 仍可先发送数据 INCOMPLETE 正在解析,可能排队 REACHABLE 近期有可达性确认 STALE 映射存在,确认已旧 DELAY 先发数据,等待确认 PROBE / FAILED 主动探测 / 解析失败 有效确认 确认变旧 再次使用 等待期无确认 获得确认可恢复 REACHABLE 常见路径示意,非完整状态图;重试/老化可配置,FAILED 不等于对象当场从邻居表删除。

使用 STALE 条目时,通常可以先用已有 MAC 发出分组,再进入 DELAY 等待来自上层等途径的确认;必要时转 PROBE 主动探测。若所有探测耗尽则可进入 FAILED,但表项回收由后续生命周期/垃圾回收处理,不保证立即从 ip neigh 消失。收到的报文是否构成可达证明也取决于类型与状态,并非任何 ARP/NA 都直接置 REACHABLE。

本篇按Linux 7.2 的 net/core/neighbour.c 核对了 STALE→DELAY、等待确认和探测失败路径。实际还有永久、外部管理条目等特殊状态,图只展示常见路径;REACHABLE 到期也会结合近期使用直接进入 DELAY 等状态,不能把图当作逐行实现。

base_reachable_time_ms 是可达时间基准,实际可达时间有随机化等处理;delay_first_probe_time、retrans_time_ms、ucast_solicit、mcast_solicit 分别影响等待和探测。gc_stale_time 与未使用条目的回收资格相关,不是每条 STALE 的固定存活倒计时。配置还要区分默认模板与具体接口,不宜未看实际状态就按固定 30/60 秒“调优”。

有 MAC,为什么还要确认可达?

把映射是否存在、数据是否已发出和可达证明是否新鲜分成三项。试试直接从 STALE 发送,再选择确认;也可让等待耗尽,观察失败并不凭空把已经发出的数据撤回。清除映射后再发送,会走另一条需要排队的路径。

正在呈现知识画面
有 MAC,为什么还要确认可达?

STALE 仍保留可用映射,首次使用可先发再等待确认。解析未知地址才需要暂存分组;探测失败与立即删除整项不是同一个事件。

IPv4 冲突探测与地址公告不同

RFC 5227 的 ARP Probe 在尚未使用候选地址时探测冲突,发送者 IPv4 为 0.0.0.0,目标 IPv4 为候选地址;这样避免先把尚未确认的映射写进其他主机缓存。ARP Announcement 则声明正在使用的地址,发送者与目标 IPv4 相同。把两者都写成“发一个 gratuitous ARP,等回复”会漏掉同时探测与冲突判断。RFC 5227:IPv4 地址冲突检测

故障切换时公告有助于更新邻居映射,交换设备又可从源 MAC 学习入口;这些是不同表。策略过滤、静态表项、MAC 不变或转发表尚未收敛,都可能影响切换结果,不能承诺发出公告后立即零丢包。

Proxy ARP 是某设备代目标应答并提供自己的 MAC,随后代为转发。前提是发送主机按路由/链路判断确实会解析该目标;若它已经判定目标经默认网关,就通常问网关。代理可用于明确设计的接入场景,也可能掩盖错误的 on-link 判断,应结合路由与策略解释其作用。

NDP 消息:正确编号与校验规则

NDP 由 ICMPv6 承载,基本消息包括 RS 133、RA 134、NS 135、NA 136、Redirect 137,这些消息的 Code 都为 0。共同头只有 Type、Code、Checksum 等通用部分,后续固定字段随消息类型变化,不能统一画成四字节 Reserved。校验和包含 IPv6 伪首部;接收验证还检查 Hop Limit=255 等条件,以限制被跨路由转发的伪造报文,但不认证本地发送者。RFC 4861:消息格式与验证

常见 ND Option 类型含义
1Source Link-Layer Address
2Target Link-Layer Address
3Prefix Information
4Redirected Header
5MTU

这些选项的 Length 以 8 B 为单位且包含类型和长度字段;零长度无效。以太网链路地址选项常为 8 B,不能把 Type 1 同时称为源/目标地址,再把后续编号整体错移。

NS/NA:组播缩小范围,但一个组可对应多个地址

初始解析通常向目标的 solicited-node 组播地址发 NS。该地址为 ff02::1:ff00:0/104 加目标 IPv6 最低 24 bit;以太网 IPv6 组播 MAC 使用 33:33 加 IPv6 组播地址最低 32 bit。因此目标 2001:db8::1234:5678 对应 ff02::1:ff34:5678 和 33:33:ff:34:56:78。RFC 2464:IPv6 组播到以太网映射

多个 IPv6 地址可能共享低 24 bit,也就共享该组;接收者仍需核对 NS 的完整 Target Address,不能仅凭以太网目的 MAC 判断“就是找我”。已知邻居的可达性探测又可能使用单播 NS,NS 不只是一种组播问询。

普通被请求的 NA 可单播返回,携带目标链路地址及 R/S/O 标志。R 指示路由器角色,S 表示对应的被请求可达确认语义,O 影响已有映射更新;组播 NA 的 Solicited 标志不能按“它也是回应”一概置 1。缓存更新要结合原状态和标志执行。RFC 4861:地址解析与 NA 处理

DAD:还没有地址时怎样问有没有冲突

普通 DAD 中,候选地址处于 tentative,发出的 NS 源为 ::,Target 为候选地址,不带 Source Link-Layer Address 选项。已有地址所有者可以回复相应 NA;两个同时探测相同地址的节点也可能通过收到对方的 NS 发现冲突,因此不能只统计 NA,或认为一定只有“第二台”失败。

没有观察到冲突才按协议流程启用地址,但丢包、过滤和链路分隔意味着 DAD 不是唯一性的绝对证明。启用次数、适用例外、优化 DAD 与操作系统策略都要区分,不能对任何类型地址一概规定相同流程。RFC 4862:DAD

主机可通过 RS 请求路由器信息,路由器也可周期发送 RA;RA 来源通常为路由器链路本地地址。响应目的需要按 RS 来源等条件选择,源为 :: 的 RS 不能要求 RA 单播回一个未指定地址。

Prefix Information 的 L 表示前缀的 on-link 信息,A 表示能否用于自主地址配置,两者独立。拥有一个地址/前缀长度不应被无条件解释成所有匹配地址均直接可达;主机需遵循 on-link 信息与路由选择。RFC 5942:IPv6 子网模型

地址的 Preferred Lifetime 到期会进入 deprecated,通常避免为新通信选择它,但既有通信在仍有效时可继续;Valid Lifetime 到期后地址不再有效。RA Router Lifetime 则控制该路由器作为默认路由候选的期限,设为 0 不等于同时撤销所有前缀与地址。具体生命周期更新还有协议规则,不能给它们统一设为固定天数。

SLAAC 的 IID 可以使用适当的稳定不透明机制或临时地址策略,不应默认从 MAC 生成。RFC 8981 的临时地址周期性变化,降低特定地址关联风险,但它不隐藏全部网络标识,也不是所有 Linux 安装默认启用;系统配置与地址选择策略需要实际核对。RFC 8981:临时地址扩展

地址与默认路由,会一起过期吗?

公式里的不同寿命属于不同对象。选择 t=70 时,地址可以仍有效但已不再首选,而这份 RA 提供的默认路由已经过期;关掉 L 也不会自动关掉 A。时间滑杆只观察一次初始通告的后续结果,修改标志则重新构造这份通告。

正在呈现知识画面
地址与默认路由,会一起过期吗?

A 与 L 独立;preferred 到期只使地址弃用,valid 到期才使其无效。Router Lifetime 另管默认路由候选。

安全:加密保护内容,不修复邻居可用性

ARP/NDP 的基本地址声明缺少普遍的源认证,本链路伪造可影响映射、路由或地址配置。接入控制、适当的 ARP 检查/绑定与 RA 防护要结合可信入口和地址来源设计;静态邻居条目可以固定部分映射,但带来维护负担,也不能保护全部链路行为。

经过正确认证的 TLS 或加密隧道可保护所覆盖会话的内容与完整性,但攻击者仍可能丢包、阻断握手或制造链路不可达。因此“用了 WireGuard,ARP 欺骗就无效”不成立;保密性、身份与可用性应分别判断。

本地报文与组播映射复算

import struct
from ipaddress import IPv4Address, IPv6Address

sha = bytes.fromhex('020000000001')
arp = struct.pack('!HHBBH', 1, 0x0800, 6, 4, 1)
arp += sha + IPv4Address('192.0.2.10').packed
arp += bytes(6) + IPv4Address('192.0.2.1').packed
assert len(arp) == 28
padding = max(0, 46-len(arp))
assert padding == 18 and 14+len(arp)+padding+4 == 64
assert struct.unpack('!H', arp[6:8])[0] == 1

target = IPv6Address('2001:db8::1234:5678')
solicited = IPv6Address(int(IPv6Address('ff02::1:ff00:0')) | (int(target)&0xffffff))
assert str(solicited) == 'ff02::1:ff34:5678'
mac = bytes.fromhex('3333') + solicited.packed[-4:]
assert mac.hex(':') == '33:33:ff:34:56:78'
assert bytes([1, 1]) + sha == bytes.fromhex('0101020000000001')
print('ARP 字段/填充、请求操作码和 IPv6 组播映射通过')

仅在本地构造字节并复算,没有向网络发送 ARP/NS、清理邻居缓存或修改 sysctl。

继续查阅