模块三 · 网络层:数据平面
IPv6
IPv4 地址不够用这件事,最终的解决方案是 IPv6。但 IPv6 不只是"地址变长了"—— 它顺手改掉了一批延续几十年的设计(广播被取消、ARP 被替换、路由器不再分片)。本章会实测本机的 IPv6 现状。
本章要解决的问题:IPv4 地址不够用这件事,最终的解决方案是 IPv6。但 IPv6 不只是"地址变长了"—— 它顺手改掉了一批延续几十年的设计(广播被取消、ARP 被替换、路由器不再分片)。本章会实测本机的 IPv6 现状。
本章的证据来源:历史实测记录(IPv6 地址列表、IPv6 连通性测试、链路本地地址的生成方式验证)。地址格式与规则出自 RFC 4291、RFC 8200、RFC 4861、RFC 7217。
先从一个例子理解概念
IPv4常见地址形式只有有限数量,IPv6换用了更大的地址空间。但先别背长数字,先认识哪些地址能在哪儿使用。
另一种IP格式:IPv6
IPv6是IP的另一版本,地址128位,常以冒号分隔的十六进制组书写。它与IPv4的包格式不同,不能只给IPv4多添几个数字就兼容。
只在这一段用:链路本地地址
链路本地地址只服务同一链路通信,IPv6常见以fe80开头。用于更大范围通信的全局单播地址是另一类;有前者不代表公网IPv6已可用。
查邻居和找路由器:NDP
NDP(邻居发现)使用ICMPv6消息完成邻居地址解析、路由器发现等工作。ICMPv6是IPv6对应的控制协议,不能直接套IPv4消息类型表。
设备怎样得到地址:SLAAC与接口标识
SLAAC(无状态地址自动配置)可根据路由器提供的前缀形成地址。接口标识是地址的一部分,可采用不同生成策略,不必直接来自MAC。
下面再用这些概念看原理、命令和结果。规范与官方资料列在本章末尾,类比只帮助理解,不代替协议规则。
先看 IPv4 为什么不够用
IPv4 地址是 32 位,总共能表示:
2³² = 4,294,967,296 个地址大约 43 亿个。听起来不少,但:
- 1990 年代互联网爆发时,全球人口已经超过 60 亿
- 一个人往往不止一台设备(手机、电脑、平板、手表、电视……)
- 还有大量地址被保留或浪费:分类编址时代的低效分配、私有地址段、多播段、实验用段
结果是:2011 年 2 月,IANA 把最后一批 IPv4 地址分配完了。2011-02-03的公告指IANA未分配IPv4地址池耗尽,不等于所有区域注册机构同时无地址,也不等于现存IPv4无法使用。ICANN 官方公告
为应对地址压力,人们陆续采用了以下方案;NAT和IPv6都早于2011年出现:
| 办法 | 效果 |
|---|---|
| NAT(下一章) | 让许多设备共用一个公网 IP,救急,但破坏了端到端通信 |
| IPv6 | 从根上解决地址数量问题,但推广很慢 |
为什么 IPv6 推广慢? 因为它和 IPv4 不兼容 —— 不是改几个字段的事,而是整个地址体系都换了。全世界的设备、软件、配置都要改。这就是为什么到了今天,很多网络仍然是 IPv4 为主。
位是什么概念
IPv6 地址是 128 位:
2¹²⁸ ≈ 340,282,366,920,938,463,463,374,607,431,768,211,456约 3.4 × 10³⁸ 个地址。
换个说法体会一下:地球表面积约 5.1 × 10¹⁴ 平方米。如果把这些地址平均分到地球表面,每平方米能分到大约 6.6 × 10²³ 个 IPv6 地址(这里只作数量级比喻)。
这就是为什么 IPv6 的设计者不再考虑"节省地址" —— 他们可以给每台设备、每个虚拟机、每个容器都分一个全球唯一的地址,不需要 NAT。
地址怎么写
128 位写起来太长,所以用十六进制分组表示,共 8 组、每组 4 位十六进制数字:
2001:0db8:0000:0000:0000:ff00:0042:8329缩写规则(两条,都很实用)
规则一:每组里的前导零可以省略。
2001:0db8:0000:... → 2001:db8:0:...规则二:连续的全零组可以用 :: 代替,但整个地址里只能用一次。
2001:0db8:0000:0000:0000:ff00:0042:8329
↓ 中间三组全零,压缩成 ::
2001:db8::ff00:42:8329实测:本机的 IPv6 地址
InterfaceAlias IPAddress PrefixLength PrefixOrigin SuffixOrigin
WLAN fe80::fd00:98a4:4701:5b30%17 64 WellKnown Link
FlClash fe80::139c:e04d:5cd:696a%16 64 WellKnown Link
vEthernet (WSL...) fe80::9680:7eb5:5f54:447b%34 64 WellKnown Link两个值得解释的部分:
① fe80:: 是"链路本地"前缀。
fe80::/10 这一段的地址只能在同一个网段内使用,路由器不会把它转发出去。它的作用和 IPv4 的 169.254.x.x(《网络层》模块讲过的 APIPA)类似 —— 都是"没有配置时自己先有一个可用地址"。
② %17 是"区域索引"(zone index)。
链路本地地址的同一个地址值可能出现在多块网卡上(因为前缀都一样)。所以通信时必须指明"从哪块网卡出去",%17 就是接口编号。
历史实测记录确认了这一点 —— 同一个地址出现在多块网卡上:
InterfaceAlias IPAddress
vEthernet (WSL (Hyper-V firewall)) fe80::139c:e04d:5cd:696a%16 ← 注意这里
以太网 3 fe80::139c:e04d:5cd:696a ← 同一个地址
本地连接* 10 fe80::139c:e04d:5cd:696a但这里其实有个反常之处:fe80::139c:e04d:5cd:696a 明明是 FlClash 网卡的地址(上表第一行),却在别的网卡的邻居表里以 Unreachable 状态出现。
说明:系统曾经尝试从别的网卡去访问这个地址,失败了(因为链路本地地址不跨网段),留下了 Unreachable 记录。这类"看着奇怪但无害"的缓存残留,是真实系统里很常见的现象。
实测:本机 IPv6 不可用
地址列表里全是 fe80:: —— 没有任何全局 IPv6 地址。直接验证一下:
ping -6 2001:4860:4860::8888实测结果:
Pinging 2001:4860:4860::8888 with 32 bytes of data:
PING: transmit failed. General failure.transmit failed(发送失败)是关键 —— 不是"超时"(超时说明包发出去了但没回应),而是根本发不出去。历史地址清单没有全局IPv6地址;该次发送失败与缺少可用源地址/路由等原因相容,仍须查路由与错误码,不能只用这行输出确定根因。
与 IPv4 的关键差异
IPv6 不只是把地址加长,它顺手改掉了一批老设计:
| 方面 | IPv4 | IPv6 | 为什么改 |
|---|---|---|---|
| 地址长度 | 32 位 | 128 位 | 解决地址枯竭 |
| 广播 | 有(255.255.255.255) | 取消,用多播代替 | 广播会打扰全网;多播只发给订阅者 |
| 地址解析 | ARP | NDP(用 ICMPv6 承载) | 可以做得更安全、更规范 |
| 头部校验和 | 有 | 去掉 | 二层和四层都有校验,三层重复校验是浪费 |
| 分片 | 路由器可以分片 | 只有发送方能分片 | 路由器分片开销大,而且被攻击者利用过 |
| 头部长度 | 20~60 字节(可变) | 固定 40 字节 + 扩展头 | 固定长度让路由器处理更快 |
| NAT | 广泛使用 | 设计上不需要 | 地址够多,可以恢复端到端通信 |
几处值得单独说的:
① 取消广播是个不小的改动。 IPv4 里到处都在用广播(ARP 请求、DHCP 发现)。IPv6 换成了多播:只有真正订阅了某个多播组的设备才会收到。这减少了无谓的打扰。
② 路由器不再分片。 这是吸取教训的结果 —— IPv4 允许中间路由器分片,被攻击者利用来消耗资源。IPv6 规定只有发送方可以分片,路径中间的设备如果发现包太大,就丢弃并回一个 ICMPv6 通知,让发送方自己改小(这就是《全景与基础》模块讲的 PMTUD 机制,在 IPv6 里变成了强制要求)。
③ 去掉头部校验和是个"减法"。 二层有 FCS,四层(TCP/UDP)有各自的校验和,三层的校验和属于重复劳动,而且每经过一跳都要重算(因为 TTL 变了),拖慢路由器。去掉之后,路由器转发更快。
NDP:用 ICMPv6 代替 ARP
IPv6 没有 ARP,取而代之的是 NDP(Neighbor Discovery Protocol,邻居发现协议)。它用 ICMPv6 承载,做的是同一件事:
| 功能 | IPv4 的做法 | IPv6 的做法 |
|---|---|---|
| 解析地址 | ARP 请求(广播) | 邻居请求(多播到特定组) |
| 应答 | ARP 应答(单播) | 邻居通告 |
| 缓存状态 | Reachable / Stale / … | 完全相同的一套状态 |
Get-NetNeighbor -AddressFamily IPv6IPAddress LinkLayerAddress State
fe80::139c:e04d:5cd:696a 00-00-00-00-00-00 UnreachableUnreachable + 全零 MAC —— 和《ARP》那一章看到的一模一样。这说明"维护一个带状态的邻居缓存"这件事,是两种协议共同的需求,只是实现手段换了。
NDP 比 ARP 多出来的能力:
- 路由器发现(自动找到网关,不需要手工配置)
- 地址自动配置(SLAAC —— 设备自己根据网络前缀生成地址)
- 重复地址检测(开机时先确认这个地址没被别人占用)
实测:链路本地地址不是从 MAC 推导的
这是一个关于隐私设计的有趣细节。
IPv6 早期标准(RFC 2464)规定:链路本地地址的后 64 位由网卡的 MAC 地址推导,这叫 EUI-64。规则是:
- 把 MAC(48 位)从中间劈开
- 在中间插入
FF:FE - 把第一个字节的第 1 位取反
本机 WLAN 的 MAC 是 44:38:E8:0A:55:23,按这个规则算:
MAC: 44:38:E8:0A:55:23
插入 FF:FE: 44:38:E8 : FF:FE : 0A:55:23
第一位取反: 46:38:E8 : FF:FE : 0A:55:23
→ 应该得到: fe80::4638:e8ff:fe0a:5523但本机实际观测到的地址是:
fe80::fd00:98a4:4701:5b30两者不同。 这与使用不透明接口标识相容,但未核对永久MAC和地址生成策略,不能由此证明采用RFC 7217。
为什么这很重要
如果按 EUI-64 生成地址,那么任何人看到你的 IPv6 地址,就能反推出你的 MAC 地址,进而查出你的设备厂商和型号。而且因为地址里带着 MAC,无论你走到哪个网络,地址的后半段都一样 —— 这等于给了追踪者一个永久标识。
对隐私来说这是灾难。所以后来的标准(RFC 7217)改用基于秘密值和网络等输入生成的不透明稳定接口标识:后缀按规定的输入和函数生成,不直接暴露MAC(但对同一台设备、同一个网络保持稳定,便于管理)。
双栈:现在怎么和 IPv4 共存
现实中 IPv6 不可能一夜替换 IPv4,所以有几种共存方式:
| 方式 | 原理 | 现状 |
|---|---|---|
| 双栈 | 设备同时有 IPv4 和 IPv6 地址,按目标选 | 最主流,本机就是(有 IPv4,也有链路本地 IPv6) |
| 隧道 | 把 IPv6 包封装在 IPv4 包里传(6to4、Teredo) | 过渡方案,用得越来越少 |
| NAT64 / DNS64 | 让只有 IPv6 的设备能访问 IPv4 资源 | 运营商侧主要方案 |
本机的情况:IPv4 完整可用,IPv6 只有链路本地 —— 属于"装了 IPv6 协议栈,但网络没有提供 IPv6 服务"这种最常见的中间状态。
常见误解
误解一:"IPv6 就是地址变长了一点"
改的远不止地址长度:广播被取消、ARP 被 NDP 替换、路由器不再分片、头部校验和被去掉、头部变成固定长度。这些改动的影响加起来,比"地址变长"大得多。
误解二:"IPv6 没有 NAT,所以不安全"
NAT 本来就不是安全机制。 它带来的"外网连不进来"只是副作用,不是保护。真正的安全来自防火墙规则和认证加密。IPv6 环境下仍然可以用防火墙做同样的事 —— 而且因为没有 NAT,端到端通信恢复了,反而更简单。
误解三:"到 IPv6 就没有 ARP 了,所以没有地址解析了"
有,只是换了名字和协议:NDP 做的正是 ARP 的事。而且它用的是多播(只打扰相关设备)而不是广播,还能顺便做路由器发现和地址自动配置。
误解四:"有 fe80:: 地址就说明 IPv6 能用"
不能。 fe80:: 是链路本地地址,只在本网段内有效。历史实测记录就是反例:有 fe80:: 地址,但 ping -6 到公网直接 transmit failed。"有 IPv6 地址"和"有 IPv6 互联网接入"是两回事。
本章小结
| 结论 | 类型 |
|---|---|
| IPv4 共约 43 亿个地址,2011年IANA未分配池耗尽,不等于所有IPv4地址都不能再分配或使用 | 标准/公开记录 |
| IPv6 地址 128 位,约 3.4 × 10³⁸ 个 | 标准 |
地址写法 8 组十六进制,可省略前导零,:: 只能用一次 | 标准 |
fe80::/10 是链路本地地址,只在同网段有效 | 标准 |
%17 是区域索引,指明从哪块网卡出去 | 标准 |
实测:本机所有接口只有 fe80:: 地址,无全局 IPv6 | 实测 |
实测:ping -6 公网返回 transmit failed,证明无 IPv6 接入 | 实测 |
| IPv6 取消广播、用 NDP 代替 ARP、路由器不再分片、去掉头部校验和 | 标准 |
| 实测:IPv6 邻居表沿用与 ARP 相同的状态机(含 Unreachable) | 实测 |
| 历史地址与当前MAC的EUI-64推导值不同,具体生成策略未核实 | 观察与限制 |
| RFC 7217定义不透明稳定接口标识;地址生成策略不能仅由单个地址确定 | 标准与限制 |
自测题
7 题 · 先自己答,再展开对照
2001:0db8:0000:0000:0000:0000:0000:0001的最简写法是什么?2001:db8::1。 步骤:省略各组的前导零(0db8→db8),然后把连续的全零组用::压缩(中间 5 组全零压缩成::)。注意::在整个地址里只能用一次。fe80::开头的地址能用来访问互联网吗?为什么?不能。fe80::/10是链路本地地址,路由器不会把它转发出去,它的作用范围仅限同一个网段。要访问互联网必须有全局单播地址(通常是2000::/3段)。历史实测记录就是反例:有fe80::地址但ping -6到公网返回transmit failed。IPv6 里那个
%17是干什么的?区域索引(zone index),用来指明从哪块网卡发出。 因为链路本地地址的前缀都一样,同一个地址值可能出现在多块网卡上,所以通信时必须指明出口接口。%17就是那个接口的编号。IPv6 取消了广播,那原来用广播做的事情(比如地址解析)怎么办?
用多播代替。 原来 ARP 用广播问"谁是 X",现在 NDP 用多播发邻居请求 —— 只有加入了对应多播组的设备(也就是相关的那几台)才会收到并处理,其他设备不受打扰。这是"广播 → 多播"这个改动的一个典型收益:减少无谓的打扰。为什么 IPv6 规定"只有发送方可以分片",而不像 IPv4 那样允许路由器分片?
IPv6路由器不分片,过大报文以ICMPv6 Packet Too Big通知发送端;分片仅由源节点执行,重组在目的端。不能把路由器分片和终端重组资源混在一起。IPv6 早期标准用 EUI-64 生成地址,后来为什么改了?这解决什么问题?
基于MAC的Modified EUI-64可能暴露接口标识;RFC7217给出按网络等输入生成的不透明稳定标识方案。它不是所有系统都必须采用的唯一算法,也不同于临时地址机制。一台机器有
fe80::地址,能不能说明它可以用 IPv6 上网?不能。fe80::只是链路本地地址,说明 IPv6 协议栈是启用的、能进行同网段通信,但不代表有 IPv6 互联网接入。要访问互联网,还需要全局单播地址和 IPv6 默认网关 —— 历史实测记录就是只有前者没有后者(ping -6直接transmit failed)。
参考资料与适用范围
修订核对日期:2026-10-13。规则按所列协议与实现范围理解;文中的原始命令输出是历史观察,不表示本次重新实测。跨版本、代理/隧道及不同捕获位置需要另行核对。