IPv6 地址长什么样、怎么缩写、有哪些类型?为什么链路本地地址后面总要加“%en0”?邻居的地址是怎么生成的?这篇在本机上列出所有 IPv6 地址,枚举一个地址的所有写法,验证作用域规则,并向整条链路问一声“谁在”。
有 IPv6 地址的接口 8 个,共 9 个地址
lo0 回环 ::1 /128;链路本地 fe80::/10 /64 带作用域编号
en0 链路本地 fe80::/10 /64 [secured] 带作用域编号
awdl0 链路本地 fe80::/10 /64 带作用域编号
llw0 链路本地 fe80::/10 /64 带作用域编号
utun0 链路本地 fe80::/10 /64 带作用域编号
utun1 链路本地 fe80::/10 /64 带作用域编号
utun2 链路本地 fe80::/10 /64 带作用域编号
utun3 链路本地 fe80::/10 /64 带作用域编号
按类型统计:回环 ::1 1;链路本地 fe80::/10 8;全球单播 / 唯一本地地址 0 个——这台机器所在的网络没有给它分配可路由的 IPv6 地址,所以它没有公网 IPv6 连通性每个接口至少有一个 fe80::/10 链路本地地址,lo0 另有 ::1。本机网络没有分配全球单播地址,所以后面的 IPv6 实验都在本地链路上做。
输入 → 压缩(RFC 5952) 完整展开
2001:0db8:0000:0000:0000:ff00:0042:8329 → 2001:db8::ff00:42:8329 2001:0db8:0000:0000:0000:ff00:0042:8329
2001:db8:0:0:1:0:0:1 → 2001:db8::1:0:0:1 2001:0db8:0000:0000:0001:0000:0000:0001
2001:db8:0:1:1:1:1:1 → 2001:db8:0:1:1:1:1:1 2001:0db8:0000:0001:0001:0001:0001:0001
0:0:0:0:0:0:0:1 → ::1 0000:0000:0000:0000:0000:0000:0000:0001
0:0:0:0:0:0:0:0 → :: 0000:0000:0000:0000:0000:0000:0000:0000
2001:db8:: → 2001:db8:: 2001:0db8:0000:0000:0000:0000:0000:0000
FE80::0202:B3FF:FE1E:8329 → fe80::202:b3ff:fe1e:8329fe80:0000:0000:0000:0202:b3ff:fe1e:8329
::ffff:192.0.2.128 → ::ffff:192.0.2.128 0000:0000:0000:0000:0000:ffff:192.0.2.128
64:ff9b::192.0.2.33 → 64:ff9b::c000:221 0064:ff9b:0000:0000:0000:0000:c000:0221
2001:db8::1 这一个地址,只算小写字母,按“每组可补前导 0 + 压缩任意一段连续的 0 组(或不压缩)”枚举出 20936 种写法,其中经 ipaddress 解析都等于 2001:db8::1 的有 20936 种;RFC 5952 规定输出时:去掉前导 0、小写、压缩最长的连续 0 组(等长取最左)、单个 0 组不压缩
::ffff:192.0.2.128 是 IPv4 映射地址,Python 里 .ipv4_mapped = 192.0.2.128;64:ff9b::/96 是 NAT64 的转换前缀一个地址可以补前导 0 也可以压缩连续的 0 组,有两万多种写法;RFC 5952 规定输出时去前导 0、小写、压缩最长的 0 段(等长取最左)。
前缀 地址个数(2 的几次方) 占整个空间 用途
::/128 2^0 2.939e-39 未指定地址
::1/128 2^0 2.939e-39 回环
::ffff:0:0/96 2^32 1.262e-29 IPv4 映射地址
64:ff9b::/96 2^32 1.262e-29 NAT64 转换前缀
2000::/3 2^125 1.250e-01 全球单播(目前分配的都在这里)
2001:db8::/32 2^96 2.328e-10 文档用
fc00::/7 2^121 7.812e-03 唯一本地(类似 IPv4 私有地址)
fe80::/10 2^118 9.766e-04 链路本地
ff00::/8 2^120 3.906e-03 组播
全球单播 2000::/3 占整个 128 位空间的 1/8;IPv4 整个空间是 2^32,一个 /64 子网(2^64 个地址)就是整个 IPv4 空间的 4,294,967,296 倍
样本地址 global private linklocal multicast loopback unspecified
:: - 是 - - - 是
::1 - 是 - - 是 -
fe80::1 - 是 是 - - -
fd12:3456::1 - 是 - - - -
2001:db8::1 - 是 - - - -
2606:4700:4700::1111 是 - - - - -
ff02::1 是 - - 是 - -
::ffff:192.0.2.1 - 是 - - - -
64:ff9b::192.0.2.1 是 - - - - -2000::/3 是全球单播(占 1/8),fc00::/7 唯一本地,fe80::/10 链路本地,ff00::/8 组播。一个 /64 子网的地址数是整个 IPv4 空间的 43 亿倍。
fe80::1%lo0 上收发:成功,收到 b'link-local-lo0';套接字地址是四元组 (地址, 端口, flowinfo, scope_id=1),scope_id 就是接口编号(lo0 的编号 1)
往本机自己的链路本地地址(scope_id = 0(不带接口))发 UDP:OSError: No route to host
往本机自己的链路本地地址(scope_id = en0 的编号)发 UDP:发送成功
往邻居表里的一个邻居(链路本地地址,scope_id = 0)发 UDP:OSError: No route to host
往邻居表里的一个邻居(链路本地地址,scope_id = en0 的编号)发 UDP:发送成功
ping6 -c 3 -I en0 ff02::1:共收到 284 个应答,来自 146 个不同的链路本地地址;应答里的跳数限制取值 {64: 264, 255: 17, 63: 2, 254: 1};其中本机自己的地址也应答了
ping6 -c 3 -I en0 ff02::2:共收到 51 个应答,来自 25 个不同的链路本地地址;应答里的跳数限制取值 {64: 49, 255: 2}
en0 上加入的 IPv6 组播组 5 个,按作用域(ff0X 的 X):ff01:1;ff02:4(1 = 接口本地,2 = 链路本地)链路本地地址在不同接口上可以重复,所以发送时必须带接口(scope_id);不带就是 No route to host。ff02::1 能一次问出整条链路上的几百个应答。
本机:MAC 推出的 EUI-64 接口标识符与链路本地地址的后 64 位不同;地址标志里有 secured(= 稳定的不透明标识符,不是由 MAC 推出的) 邻居表(ndp -an)里 en0 上有 MAC 的 172 个邻居:链路本地地址是 EUI-64(由 MAC 推出)的 80 个,不是的 92 个——地址只统计个数 被请求节点组播地址 = ff02::1:ff + 地址的后 24 位 → 形如 ff02::1:ff__:____(本机一个);en0 上有没有加入:有 en0 上加入的组播组里,被请求节点组(ff02::1:ffXX:XXXX 形式)有 1 个——每个地址对应一个,邻居发现用它代替广播
EUI-64 由 MAC 推出,已知邻居里约一半是这样,本机的 en0 是稳定的不透明标识符;被请求节点组播地址由地址的后 24 位决定。