bigywater.tech
网络协议 · 26

SLAAC 与隐私地址:IPv6 地址怎么自己生成

IPv6 主机怎么不靠 DHCP 就给自己配好地址?为什么 EUI-64 会暴露设备身份,临时地址又是什么?这篇先看本机的 SLAAC 参数和各接口地址的生成方式,再用计算演示三种接口标识符,最后看这个没有 IPv6 路由器的网络里应用看到的现象。

24 小时 / 7 天
本机临时地址的首选寿命与有效寿命(temppltime / tempvltime)
0 个 RA
在 en0 上听 120 秒收到的路由器通告个数:这条链路上没有 IPv6 路由器,所以没有 SLAAC
0.1 ms
连接 example.com 的 IPv6 地址时内核报 No route to host 所用的时间

SLAAC 的前提

实测 · 本机执行输出
  net.inet6.ip6.accept_rtadv = 1
  net.inet6.ip6.auto_linklocal = 1
  net.inet6.ip6.use_tempaddr = 1
  net.inet6.ip6.temppltime = 86400
  net.inet6.ip6.tempvltime = 604800
  net.inet6.ip6.dad_count = 1
  net.inet6.icmp6.nd6_optimistic_dad = 63
  net.inet6.ip6.auto_flowlabel = 1
  net.inet6.icmp6.nd6_delay = 5
  net.inet6.icmp6.nd6_mmaxtries = 3
  net.inet6.icmp6.nd6_umaxtries = 3
  临时地址:首选寿命 24 小时、有效寿命 7 天(use_tempaddr = 1,1 表示启用隐私扩展);nd6_delay = 5 秒,就是上一篇看到的 DELAY 阶段长度;auto_flowlabel = 1,就是第 23 篇里内核自动填流标签的开关
    lo0    无 MAC(隧道)     接口标识符无法与 MAC 比较
    en0    有 MAC         接口标识符不是 EUI-64(地址标志 secured)
    awdl0  有 MAC         接口标识符= MAC 推出的 EUI-64
    llw0   有 MAC         接口标识符= MAC 推出的 EUI-64
    utun0  无 MAC(隧道)     接口标识符无法与 MAC 比较
    utun1  无 MAC(隧道)     接口标识符无法与 MAC 比较
    utun2  无 MAC(隧道)     接口标识符无法与 MAC 比较
    utun3  无 MAC(隧道)     接口标识符无法与 MAC 比较
  有 MAC 的接口 3 个,其中链路本地地址是 EUI-64 的 2 个

路由器通告前缀(RA),主机用前缀加自己生成的 64 位接口标识符拼出地址,再做重复地址检测(DAD)。本机参数已打开 accept_rtadv,但这条链路上听不到 RA,所以只有链路本地地址。

接口标识符

实测 · 本机执行输出
  (示例 MAC 用 00:11:22:33:44:55,不是本机的 MAC)
  1. EUI-64:接口标识符 = MAC 中间插 ff:fe 并翻转第 7 位 → 0211:22ff:fe33:4455(由 MAC 决定,在任何网络里都一样)
  2. 稳定不透明:接口标识符 = 哈希(前缀, 接口名, 本机秘密值, DAD 计数)的前 64 位 → 1c7b:e47c:206a:da37;同一前缀每次算出相同:True;换一个前缀(2001:db8:9:9::/64)得到 bf28:db64:a331:f008,不同:True
  3. 临时地址:每个首选寿命周期重新随机生成:2291:d8cd:c310:411e;7ec2:7378:a661:c935;187c:07e4:d563:6e9b
  拼出来的地址:EUI-64 2001:db8:1:2:211:22ff:fe33:4455、稳定 2001:db8:1:2:1c7b:e47c:206a:da37、临时 2001:db8:1:2:2291:d8cd:c310:411e
  EUI-64 的缺点:同一个设备走到任何网络,后 64 位都不变,可以被跟踪;稳定不透明地址在一个网络内不变、换网络就变;临时地址对外连接用,定期更换
  同一台机器在两个网络(前缀 2001:db8:1:2::/64 与 2001:db8:9:9::/64)里:EUI-64 地址后 64 位相同,稳定地址后 64 位不同

EUI-64 由 MAC 决定,换网络不变,可被跟踪;稳定不透明在同一前缀内不变,换前缀就变;临时地址随机并定期更换。本机 en0 的链路本地地址就是稳定不透明的(secured),而 awdl0 和 llw0 仍是 EUI-64。

临时地址

实测 · 本机执行输出
  120 秒共抓到 24 个 ICMPv6 报文:NS 邻居请求 12;NA 邻居通告 12
  其中 NS 里:源地址是 ::(DAD 探测,有设备在检查自己要用的地址有没有人占用)0 个;目的是被请求节点组播的 0 个;单播的(NUD 探测)12 个
  RA 路由器通告 0 个——120 秒内没有任何路由器通告(RA 的发送间隔通常是几分钟,但本机的 ndp -rn 也显示 en0 上没有路由器,见上一篇)

本机 use_tempaddr = 1,临时地址首选 24 小时,到期换新的;有效 7 天后才彻底作废。

没有 IPv6 路由时

实测 · 本机执行输出
  经 DNS 查 example.com:A 记录 2 个、AAAA 记录 2 个(DNS 里有 IPv6 地址)
  getaddrinfo(example.com, 80) 使用 默认:返回 2 项:{'IPv4': 2};第一项是 IPv4
  getaddrinfo(example.com, 80) 使用 AI_ADDRCONFIG:返回 2 项:{'IPv4': 2};第一项是 IPv4
  route get -inet6 到 example.com 的一个 IPv6 地址:route: writing to routing socket: not in table;接口 ?,标志 ?
  connect 到该 IPv6 地址:OSError: No route to host,用时 0.1 ms——没有 IPv6 路由,内核立刻失败,不用等超时

getaddrinfo 在这台机器上只返回 IPv4;若硬连 IPv6 地址,内核立刻报 No route to host。是否自动回退由应用决定。

分步演示

SLAAC 与隐私地址
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64(Apple 芯片)/ Python 3.14.8 / tcpdump(libpcap)/ scapy 2.8 / dpkt / dnspython / h2 / aioquic / OpenSSL / curl 8.7.1;抓包在 lo0(环回)上做,少数实验用真实网卡 en0(这台机器上 en0 是 Wi-Fi,tcpdump 看到的是系统转成以太网格式的帧,所以文中的“以太网头”都指这个 14 字节的头)或访问公网(会在文章里注明);需要丢包 / 延迟 / 限速时,用一个只作用于 lo0 端口 9400-9499 的 dummynet 辅助脚本(netlab);所有服务端都是本机自己起的进程;时间戳取自 tcpdump 的 -tt,数字每次运行会有小幅抖动。本机网络没有 IPv6 路由器,所以没有观察到 RA / SLAAC 的实际过程;第二节是计算(稳定不透明地址的哈希是简化方案,不是 RFC 7217 的精确算法),示例 MAC 是虚构的;第三节只抓 120 秒,别的设备的流量只统计个数
    • 没有验证:真实的 RA 内容(前缀选项、M / O 标志、RDNSS 选项);DAD 的实际过程与 optimistic DAD;临时地址的实际生成和轮换(本机没有全球前缀);DHCPv6 和 SLAAC 的配合;getaddrinfo 为什么在没有 IPv6 地址时不返回 AAAA(系统解析器行为)
    京ICP备2026067502号-1京公网安备11010502063487号