IPv6 没有 ARP,邻居的链路层地址怎么解析?“邻居不可达检测”到底是怎样的状态机?为什么 ND 报文的跳数限制必须是 255?这篇在本机的 en0 上抓真实的 NS/NA,让一个邻居从 STALE 走到 REACHABLE,再去解析一个不存在的地址。
en0 上的邻居缓存 172 项(另有 5 项 incomplete):状态 S=169;R=3(R = REACHABLE,S = STALE,D = DELAY,P = PROBE;incomplete = 还在解析) 过期时间(剩余):最长 24.0 小时、最短 3 秒;STALE 项最长可以放 24 小时,但下一次发数据时会先重新确认 en0 的参数:基础可达时间 30s0ms,当前随机化后的可达时间 15s,NS 重传间隔 1s0ms;标志:0x201 PERFORMNUD DAD 默认路由器列表里有 4 项,其中接口是 en0 的 0 项(其余是 utun 隧道接口)——en0 这条链路上没有收到过路由器通告(RA),所以没有 IPv6 默认路由器,也没有学到全球前缀 前缀列表里 en0 的条目:有,且“No advertising router”(只有自己的链路本地前缀),没有任何路由器通告过的前缀
邻居缓存里绝大多数是 STALE(没用过、需要时再确认),REACHABLE 很少。en0 上没有收到过路由器通告,所以既没有默认路由器,也没有学到全球前缀。
选了缓存里一个状态为 STALE 的邻居(地址不写出)发一个 UDP 包。状态变化(相对发包时刻):D @ 0.0s → P @ 5.3s → R @ 5.6s
+ 5150.9 ms 本机 发 邻居请求 NS,以太网目的 单播给邻居,跳数限制 255,选项 [1],校验和正确
+ 5379.1 ms 邻居 发 邻居通告 NA,以太网目的 单播给本机,跳数限制 255 标志 R=0 S=1 O=1,选项 [2],校验和正确
线上共 2 个相关的 ND 报文;发 UDP 数据的那一下并不等 NUD:数据包立刻就发出去了(数据先发,NUD 在后台确认)往 STALE 邻居发数据后:先 DELAY 约 5 秒,若上层没有确认可达就进入 PROBE,单播 NS,收到 NA 后回到 REACHABLE。数据包本身不等这个过程。
目标地址是随机的链路本地地址(后 24 位决定被请求节点组播地址,形如 ff02::1:ff__:____);抓到发给它的 NS 4 个
+ 0.0 ms NS #1:IPv6 目的是被请求节点组播地址(与目标地址的后 24 位对应),以太网目的 MAC = 33:33 + 组播地址的后 4 字节,跳数限制 255,选项 [1](1 = 源链路层地址,内容是本机 MAC)
+ 1571.2 ms NS #2:IPv6 目的是被请求节点组播地址(与目标地址的后 24 位对应),以太网目的 MAC = 33:33 + 组播地址的后 4 字节,跳数限制 255,选项 [1](1 = 源链路层地址,内容是本机 MAC)
+ 2581.7 ms NS #3:IPv6 目的是被请求节点组播地址(与目标地址的后 24 位对应),以太网目的 MAC = 33:33 + 组播地址的后 4 字节,跳数限制 255,选项 [1](1 = 源链路层地址,内容是本机 MAC)
+ 4504.9 ms NS #4:IPv6 目的是被请求节点组播地址(与目标地址的后 24 位对应),以太网目的 MAC = 33:33 + 组播地址的后 4 字节,跳数限制 255,选项 [1](1 = 源链路层地址,内容是本机 MAC)
NS 之间的间隔(毫秒):[1571, 1010, 1923];ndp -i 给出的重传间隔是 1s0ms,实测间隔在 1.0 到 1.9 秒之间不等,为什么比 1 秒长没有深究
之后 ndp -an 里这个地址的状态:(incomplete);第二次 sendto:成功解析新邻居时 NS 发往目标地址对应的被请求节点组播地址,以太网目的 MAC 是 33:33 加后 4 字节;解析一个不存在的邻居时,4.5 秒内发了 4 个 NS(1 个首发加 3 次重传)。
一个 NS 的 ICMPv6 部分(十六进制,目标地址与链路层地址已遮盖):87 00 f7 9b 00 00 00 00 <目标地址 16 字节> 01 01 <MAC 6 字节> = 类型 135(135 = 邻居请求)、代码 0、校验和 0xf79b、4 字节保留 + 16 字节目标地址 + 选项(类型 1、长度 1×8 = 8 字节,即 2 + 6 字节 MAC) 全部 6 个 ND 报文的跳数限制取值:[255];校验和全部正确:True 类型号:133 路由器请求 RS、134 路由器通告 RA、135 邻居请求 NS、136 邻居通告 NA、137 重定向。NA 的标志位 R = 发送者是路由器、S = 这是对 NS 的回应、O = 覆盖旧的缓存记录 组播 MAC 映射:IPv6 组播地址的后 4 字节接在 33:33 后面:例如被请求节点组播地址 → 33:33:ff:xx:xx:xx(上面抓到的 NS 的目的 MAC 就是这样) 用普通 ICMPv6 套接字发路由器请求(类型 133):失败,Operation not permitted——ND 报文只能由内核发,应用不能伪造(也就不能伪造跳数限制 255)
NS 是类型 135 + 4 字节保留 + 16 字节目标地址 + 选项(类型 1 = 源链路层地址);NA 多了 R / S / O 三个标志。跳数限制必须是 255,表明没有经过路由器,应用不能伪造 ND 报文。
ARP 缓存(arp -an)en0 上 274 项,其中 incomplete 2 项;NDP 缓存 172 项(+5 项 incomplete) IPv4:net.link.ether.inet.max_age: 1200 秒;IPv6 的 STALE 项可以保留的最长剩余时间约 24.0 小时 ARP 缓存里是 IPv4 地址 ↔ MAC;NDP 缓存里是 IPv6 地址 ↔ MAC,还多了状态机(REACHABLE / STALE / DELAY / PROBE)——ARP 靠定时器过期后重新广播,NDP 在使用时才用单播 NS 探测邻居
ARP 靠广播和定时器;NDP 用多播的被请求节点组减少打扰,并用单播探测验证邻居的可达性。