历史
从上个世纪90年代开始,IPv6的规范就已经开始制定。到2012年全球的IPv6网络正式启用。由于IPv4只有32位长度,可以分配的地址是有限的,ARIN在2019年11月宣布,他们已经分配完最后一块/22的IPv4公网地址。因此,各个国家的IPv6推进进程也大大加快。
我们国家一开始只有部分科研网和教育网上了IPv6,从17年开始,整体的v6部署也开始加速,到了今年2月份,我国的移动网络中,已经有超过50%的流量是IPv6。
地址表示和类型
地址表示方式
IPv6地址的长度是128比特,一般采用x:x:x:x:x:x:x:x这种格式来展现,也就是使用“冒号分隔十六进制”格式,每个IPv6地址包含8组数,每组16bit。每个x是一个16比特的16进制字符串,也就是0000到ffff。用这种方式表示,IPv6 地址范围是从 0000:0000:0000:0000:0000:0000:0000:0000 到 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff。
IPv6地址还有如下两种缩写方式:
- 前导的0可以省略,比如:2000:1050:0000:0000:0000:0005:0600:200c:3311可以写成 2000:0:0:0:5:0600:200c:3311
- 通过使用双冒号(::)替换一系列零来表示IPv6 地址。例如,IPv6 地址 fe80:0:0:0:0:0:0:a2 可写作 fe80::a2。一个 IP 地址中只可使用一次双冒号。
IPv6地址还有一种混合方式,可以同时使用冒号和点分表示,也就是左边的96位用十六进制冒号方式表示,最右边的32位用ipv4的十进制方式表示,这种方式可以将ipv4地址用IPv6方式展现,样例:0:0:0:0:0:ffff:192.168.1.1 或者::ffff:192.168.1.1/96。基于IPv6的应用可以用这种地址直接和基于IPv4的应用通信。这种地址只存在于主机内部。
IPv6的前缀是以”地址/前缀长度”的格式表示,IPv4中的网络掩码表示方式已经不再适用。前缀格式如下:
2000:0:0:0::/64
2001:11:22::/48
地址类型
IPv6有三种类型的地址:
- 单播地址(Unicast Address):指向单个网络接口的地址。单播地址是IPv6地址的最常见类型。
- 组播地址(Multicast Address):指向多个接口的地址。组播地址用于将数据传输到一个组中的所有接口。组播地址的范围包括节点本地范围、站点范围、组织范围和全球范围。
- 任播地址(Anycast Address):用于标识一组接口,数据包将被传递到其中的任何一个接口。任播地址通常用于提高网络服务的可靠性和性能。
注意IPv6没有广播,它已经完全通过组播来实现广播功能。
单播地址
单播地址指向单个网络接口的地址。在IPv6中,单播地址可以被用于在单个主机之间传输数据,或在不同网络之间传输数据。
IPv6单播地址有多种类型,包括全球单播地址、唯一本地单播地址、链路本地单播地址等。其中,全球单播地址可以在全球范围内路由,唯一本地单播地址只能在特定的本地网络中路由,链路本地单播地址则只能在特定的链路上路由。
全球单播地址
全球单播地址(Global Unicast Address,GUA)是唯一的、全球可路由的IPv6地址。全球单播地址的前缀通常由Internet号码分配局(IANA)和互联网注册机构(IR)分配,可以在全球范围内路由。全球单播地址的范围为2000::/3。
注:部分ip地址已被预留,比如2002::/16 是6to4隧道中继的6to4地址。
开始地址:2000:0000:0000:0000:0000:0000:0000:0000
结束地址:3FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF。
前缀计算
全球单播地址由两部分组成:网络前缀和接口标识。网络前缀指定了主机所在的网络,而接口标识则指定了主机上的特定接口。全球单播地址的格式如下:
prefix:interface_id
其中,prefix是网络前缀,interface_id是接口标识。
这是一个比较粗的格式,prefix可以看成网络提供商分配给用户或者机构的前缀,这个前缀一般是/48,当然对于个人用户,有时运营商会只给/56或者/60,甚至直接只给/64. 以典型的/48 为例,假如我们有这么一个地址:2000:0abc:1def:0011:0000:0000:1111:2222,其中2000:0abc:1def这48位就是prefix,用于标志公共拓扑,这个prefix是分配给用户自行使用的。0011作为子网id,用于表示站点拓扑,由于我们分到的是/48的prefix,这里的可用子网id范围就是0000到ffff,假如我们分到的是/56的prefix,那么可用的子网范围就是xx00到xxff,这里的xx是prefix的一部分,分给我们是什么值就是什么值,不是我们能自己定义的。0000:0000:1111:2222才可以当成是真正的接口id。
标准的ipv6用/64作为一个子网,对于上面的例子,2000:0abc:1def:0011是一个子网。

上图所示是一个 分配到/48前缀的ipv6地址,我们通常将绿色部分称为前缀,黄色部分称为子网id,蓝色部分称为接口id。
如果是/56的前缀,地址表示如下(总共128位,后64位是interfaceId,前56位是前缀, 子网id就是128-64-56=8,也就是两个十六进制字符):

如果是/60的前缀,地址表示如下:

链路本地单播地址
链路本地单播地址(Link-Local Unicast Address)只能在特定的链路上路由,不能跨越路由器转发。链路本地单播地址的前缀为FE80::/10。链路本地单播地址通常用于网络设备之间的通信,如路由器和交换机之间的通信。
在所有启用IPv6的接口都需要有link-local地址,即使是没有IPv6相关的路由,应用可能会仍然依赖这个link-local地址。这个地址对应于IPv4中用于地址自动配置的169.254.0.0/16。 169.254.0.0/16这个地址在网络接口获取到正式的ip之后会自动消失,IPv6的link-local在接口获取到GUA或者下文所说的ULA之后,仍然会保持在接口上,IPv6的邻居发现协议(Neighbor Discovery)需要通过这种地址来实现。
开始地址:FE80::
结束地址:FEBF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
独立本地单播地址
独立本地单播地址(Site-Local Unicast Address)用于在特定的站点或组织内部进行通信。独立本地单播地址的前缀为FEC0::/10。独立本地单播地址已被弃用,建议使用全球单播地址代替。
唯一本地单播地址
唯一本地单播地址(Unique Local Unicast Address,ULA)也用于在特定的站点或组织内部进行通信,但是它的前缀不像独立本地单播地址那样被预留。唯一本地单播地址的前缀为FC00::/7。唯一本地单播地址与全球单播地址相似,但它们是本地分配的,不会路由到互联网上。
开始地址:FC00::
结束地址:FDFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
本地回环地址
本地回环地址(Loopback Address)是一个特殊的单播地址,它指向主机本身。在IPv6中,本地回环地址为::1。本地回环地址通常用于主机和应用程序之间的通信。
除了上述各种类型单播地址之外,还有一个特殊的未指定地址(Unspecified address)也就是0:0:0:0:0:0:0:0。 也可以使用两个冒号(::)来表示。未指定地址表示一个不存在的地址,这个地址不会被任何机器占用。它可以在主机未被分配地址时使用。比如主机如果需要检测一个地址是否被其它主机占用,它可以用(::)作为它的源地址。
组播(多播)地址
组播地址是IPv6协议中用于一对多通信的地址。与单播地址和任播地址不同,组播地址用于将数据包从一个源发送到多个目的地。IPv6中的组播地址是由128位的地址空间中的前8位组播地址标识符(FF开头);紧接的9到12位如果是0,表示这个组播地址是预定义的(well-known);13到16位是ScopeID,如果是2,则表示link-local地址;剩余的是GroupID,1表示所有节点,比如FF02::1,表示ScopeID是2,GroupID是1,也就是本地链路中所有的节点,类似于IPv4的广播地址。
组播的组成员是动态的,主机可以随时加入或退出某个组。组播监听发现(Multicast Listener Discovery MLD)消息用于确定用户和组的成员关系。
即使主机不归属于某个组,它依然可以给这个组发消息。
IPv6中定义了多个不同的组播地址范围,每个范围用于不同的目的。下面是IPv6中的一些重要的组播地址范围:
- ff00::/8:全球范围的组播地址范围,其中ff01::/16是接口本地范围的组播地址,ff02::/16是链接本地范围的组播地址,ff05::/16是站点本地范围的组播地址,ff0e::/16是全球范围的定时器组播地址,ff02::1是所有节点组播地址。
- ff02::/16:链接本地范围的组播地址范围,用于在同一个物理网络上进行多播通信,例如路由器发送路由更新信息、节点发现邻居节点等。
- ff05::/16:站点本地范围的组播地址范围,用于在同一个站点或网络内进行多播通信,例如网络管理员发布站点内的通告等。
- ff0e::/16:全球范围的定时器组播地址范围,用于全球范围内的时间同步协议和其他类似的应用。
组播地址在IPv6协议中有着重要的应用,它可以有效地降低网络通信的负载和带宽消耗,减少网络拥塞,提高网络性能和可靠性。同时,使用组播地址还可以实现一些重要的网络功能,例如组播文件传输、组播视频流媒体、网络会议等。
常见的一些组播地址:
| 地址 | 描述 |
|---|---|
| FF02::1 | 本地链路所有节点 |
| FF02::2 | 本地链路所有路由器 |
| FF02::5 | 本地链路所有OSPF路由器地址 |
| FF02::6 | 本地链路所有OSPF指定路由器地址(all-OSPF-designated routers) |
| FF02::1:FFXX:XXXX | 被请求节点组播地址(Solicited-node Address),主要用于重复地址检测和获取邻居节点的链路层地址时,代替IPv4中使用的广播地址 |
Tips:
Linux下我们可以通过如下指令查询链路上所有节点和所有路由器:
[root@Test ~]# ping6 ff02::1%enp0s8
[root@Test ~]# ping6 ff02::2%enp0s8
任播地址
任播地址是一种IPv6地址类型,它用于标识一组接口中的任意一个接口。任播地址可以用于提高网络服务的可靠性和性能,尤其是在具有多个副本的分布式系统中,可以将请求路由到距离最近的副本。
在任播地址中,同一地址被分配给多个接口,但是当数据包发送到该地址时,只有距离最近的一个接口会处理该数据包。因此,任播地址提供了一种分布式系统中简单而有效的负载均衡方法,同时也提高了系统的可靠性和可用性。
任播地址的分配是由路由协议自动完成的。当路由器接收到任播地址的数据包时,它将选择最近的接口并将数据包转发到该接口。因此,任播地址不需要特定的配置,而是由路由器和网络拓扑结构自动决定。
任播地址和全球单播地址共用地址空间,接口在配置任播地址时,需要显式指定该地址类型为任播。
比较常见的任播场景是DNS解析服务器和CDN。
特殊用途地址
下表是一些特殊用途的地址,有些地址在上文中已经提过。
| 地址 | 描述 |
|---|---|
| 2001:0000::/32 | Teredo |
| 2001:0002::/48 | 用于性能测试,不能作为源或目标地址出现 |
| 2001:0010::/28 | 用于Orchid的固定的长期实验,不能作为源或目标地址出现 |
| 2001:db8::/32 | 为文档预留的地址,不能作为源或目标地址出现 |
| 2002::/16 | 用于6to4的地址,IPv4中的地址段为192.88.99.0/24 |
| loopback address (::1/128) | 本地环回地址 |
| Unspecified address (::/128) | 未指定地址,类似IPv4的0.0.0.0 |
IP包头
IPv6同IPv4相比,具有以下变革:
- 寻址能力的扩展:从地址空间从32位扩展到128位,支持简单的自动地址配置;通过在多播地址上增加scope字段增强了多播路由的可扩展性;增加了任播地址类型
- 简化了数据包的头部,去除了IPv4中的部分头部字段,减少了数据包在处理过程中的开销
- 提升了扩展和选项能力,通过改变IP报头选项的编码方式,实现更高效的转发、放宽对选项长度的限制,并为未来引入新选项提供更大的灵活性。这些变化有助于提升网络性能、减少开销,并促进协议的演进和功能的增加
- 引入流的打标能力
- 增加了认证和隐私能力
基本头部
IPv6包的基本头部信息如下:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Traffic Class | Flow Label |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload Length | Next Header | Hop Limit |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
这个头部信息相比较IPv4取消了三层IP的校验,由二层和四层来实现;取消了中间节点的分片功能,收发端通过PMTU来发现路径MTU。这个基本头部信息是定长了,有利于硬件设备快速处理数据包。
Next Header字段定义了IPv6Heaer之后跟的是什么头部,一般是各种Option头信息。
Hop Limit是一个8比特的TTL值,经过一个路由节点就减1。在转发节点中,如果发现数据包的Hop Limit为0,这个数据包会被丢弃;对于目标节点,如果Hop Limit为0,需要能正常处理。
扩展头部
IPv6的可以带0到多个扩展头部信息。每个扩展头部信息都以一个Next Header信息开头,这个信息指示下一个header是什么扩展头,或者是TCP/UDP头。
IPv6头部信息的展现顺序如下:
IPv6基本头部
逐跳选项头部
目的选项头部
路由头部
分片头部
认证头部
封装安全载荷头部
目的选项头部
上层协议头部
比较常见的头部是逐跳(Hop-By-Hop)选项头部。这个头部比较特殊,其它头部信息在数据包转发的中间节点都不需要被处理(检查,删除或修改),而逐跳选项头部需要被中间转发节点检查或修改。
地址配置
IPv6支持手工配置地址,也支持自动配置地址。手工配置地址,和ipv4没有太大区别,主要是根据实际需要,配置独立本地单播地址(ULA),或者全球单播地址(GUA)。我们这里重点关注下自动配置地址。
自动配置IPv6的方法有无状态地址自动配置(StateLess Address AutoConfiguration,SLAAC)和DHCPv6.
无状态地址自动配置
SLAAC的方式简洁高效,无状态指的是不需要在服务端上维护复杂的DHCP配置信息,客户端自动就能获取到IPv6地址和网关等信息。这种方式也有利于客户端在不同的网络环境下移动。不需要通过有状态的协议(比如DHCP)就可以实现自动配置地址是IPv6的一大特性。
在具体讨论SLAAC之前,我们先简单了解下ND和地址状态。
ND
无状态地址自动配置的实现是基于邻居发现协议(Neighbor Discovery Protocol,简称ND或者NDP)。ND其实是一组功能的合称,它并不是一个协议实体,ND协议是通过ICMPv6实现的,它主要包含如下功能:
- 路由发现
- 前缀发现
- 参数发现
- 地址自动配置
- 地址解析
- 下一条决策
- 邻居不可达检测
- 重复地址检测
- 重定向
ND的数据包头部如下图所示:
![[Pasted image 20240821105148.png]]
总共有5种协议消息:
- 路由器请求(Router Solicitication),也就是ICMPv6类型为133的消息。
- 路由器通告(Router Advertisement),也就是ICMPv6类型为134的消息。
- 邻居请求(Neighbor Solicitication),也就是ICMPv6类型为135的消息。
- 邻居通告(Neighbor Advertisement),也就是ICMPv6类型为136的消息。
- 重定向(Redirect),也就是ICMPv6类型为137的消息。
在SLAAC过程种,我们会用到前4种消息。
地址的状态
自动配置的IPv6地址生命周期如下图所示:

Tentative: 暂态,IP地址在经过重复地址检测(DAD)通过之前所处的状态,节点不能通过这个地址收到单播消息,但是可以正常接收和处理邻居通告消息,这种通告消息是响应给重复地址检测期间发送的邻居发现消息。
Valid:有效状态,包含首选(Preferred)和弃用(Deprecated)状态,处于这种有效状态的地址可以用来接收和发送单播消息。Tentative+Preferred+Deprecated这三种状态时间之和是有效的生存时间,这个值取决于SLAAC前缀信息中有效生存时间字段或者DHCPv6 IA 地址选择中的有效生存时间字段。
Preferred: 首选状态,这种状态的地址既可以作为源地址也可以作为目标地址来收发单播消息。
Deprecated:弃用状态,处于这种状态的地址是有效的,它还可以作为目标地址继续进行原有连接上的通讯,但是不建议用这种地址新发起的连接。
Invalid:无效状态,不能用这种地址来进行单播消息的接收和发送。
无状态自动配置流程
RFC4862 定义了SLAAC的交互流程。首先接口需要自动生成一个链路本地(link-local)地址。
- 节点根据接口id和链路本地前缀FE80::/64生成一个链路本地地址,这个地址处于暂态。
- 通过重复地址检测(DAD)确认这个链路本地地址的唯一性,节点的接口发送邻居请求消息,消息中的目标地址(Target Address)字段是步骤1生成的暂态链路本地地址,消息的源地址被设置为未指定地址(::),目标地址则是被请求节点多播地址(FF02::1:FFXX:XXXX)。这里面还涉及其它一些细节信息,比如客户端的接口需要加入到所有节点多播地址(FF02::1)和暂态地址的被请求节点多播地址(FF02::1:FFXX:XXXX); 需要有一定的重发机制等。
- 如果收到一条针对此邻居请求的邻居通告消息,我们可以认为DAD失败,地址已经被占用,因此需要终止自动配置,节点需要手工配置ip。
- 如果没有收到对应的邻居通告消息,这个暂态的链路本地地址可以认为是唯一并有效的,ip被初始化到对应的网络接口上。
生成链路本地地址之后,接口就可以继续进行网络的自动配置:
- 节点发出一条路由器请求消息。SLAAC过程中,节点依赖路由器发送的路由器通告消息进行地址配置,路由器可以周期性发布这个路由器通告,节点也可以通过发送路由器请求消息来获取即时的通告响应消息。
- 如果没有收到路由器通告消息,节点可以选择其它地址配置协议(DHCPv6)来获取地址和其它信息(MTU,DNS服务器,NTP服务器等)
- 如果收到一条路由器通告消息,对应的hop limit,重传计时器,MTU就可以通过这个消息来确认。
- 如果通告中有前缀信息选项,则会走如下流程 4.1 如果On-link标志位设置了,前缀会加入到前缀列表 4.2 如果Autonomous字段设置了,会根据这个前缀生成一个合适的暂态地址(这是一个GUA或者ULA地址)。 4.3 同样走一个DAD流程,发送邻居请求消息。 4.4 DAD流程如果收到对应的邻居通告消息,表示地址已经被占用,不能被初始化到节点的网络接口上 4.5 如果没有收到对应的邻居通告消息,则可以将该地址配置到网络接口,同时根据路由器通告消息的对应字段设置该ip的有效生存时间和首选生存时间
- 如果路由器通告消息中包含了Managed Address Configuration标志(简称M标志),则需要通过地址配置协议(通常是DHCPv6)去获取附加的IPv6地址。
- 如果路由器通告消息中包含了Other Stateful Configuration标志(简称O标志),则需要通过地址配置协议(通常是DHCPv6)去获取附加的其它参数信息。
在处理路由器通告消息时,通常还会有些校验,比如:
- 如果Autonomous字段没有设置,忽略这个前缀信息。
- 如果前缀是link-local类型,忽略这个前缀信息。
- 如果preferred lifetime 大于valid lifetime,忽略这个前缀信息。
- 如果前缀和之前通过SLAAC获取的地址的前缀不一样,并且Valid lifetime不为0,则配合接口id生成ipv6地址,并分配给对应的接口,设置好valid和preferred生存时间。 前缀的长度加上接口id的长度应该等于128,以太网的接口id是64,所以,路由通告的前缀长度应该是128-64=64。从系统设计上来说,这个不能作为常量,因为根据规范,这个接口id长度可以是不固定的。
- 如果收到的路由通告的前缀和当前已经获取的ip前缀一致 ,valid生存时间大于2小时,并且这个时间大于现有ip的valid生存时间,则用通告里的时间更新现有ip的对应字段。 如果通告中的valid生存时间小于2小时,但是通告是经过认证的,也应该用通告里的时间更新现有ip的valid生存时间; 否则现有ip的valid生存时间统一更新成2小时。 主要是防止攻击,如果有人在网络中恶意构造valid生存时间很小的通告,会导致所有网络接口失效。Preferred生存时间没有这个逻辑,直接根据收到通告的值进行更新即可。
DHCPv6
DHCPv6类型
DHCPv6有两种:
- 有状态DHCPv6,DHCPv6 Stateful
- 无状态DHCPv6,DHCPv6 Stateless
我们在SLACC中提到,路由器通告中有两个标志位,一个是M标志,一个是O标志。如果M标志和O标志都设置为1,这种情况下进行的DHCPv6就是有状态的,也就是IPv6地址和其它配置信息都由DHCP服务器管理。如果M标志是0,O标志是1,这就是无状态的DHCPv6,地址通过路由器通告中的前缀自动配置,而其它信息由DHCPv6管理。这里的其它信息,一般是指DNS服务器,NTP服务器这些地址信息。
消息格式
DHCPv6和DHCPv4类似,都是UDP消息,对于DHCPv6客户端监听在UDP546端口上,而服务端监听在UDP547端口。
消息的格式如下所示:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| msg-type | transaction-id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
. options .
. (variable number and length) .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
其中:
Transaction-id: 3个字节的事务id,用于标记同一个组DHCP请求和响应。DHCPv6服务端从请求消息中拷贝这个字段,带入响应消息发回客户端。
Options: 可变长度的选项字段,用于携带服务端和客户端的id(DUID),有状态的IPv6地址和其它配置设置。
Msg-type: 消息类型,参见下表:
| 消息类型 | 消息 | 描述 |
|---|---|---|
| 1 | SOLICIT | 由客户端发出,用于定位服务端地址。 |
| 2 | ADVERTISE | 服务端发送通告消息表明自己具备提供DHCP服务能力,此消息用于响应SOLICIT消息。 |
| 3 | REQUEST | 客户端向指定服务端发送Request消息用于获取地址或前缀以及其它信息。 |
| 4 | CONFIRM | 由客户端发往任何可用的服务端,用于确认客户端被分配的地址在链路上依然是有效的。 |
| 5 | RENEW | 客户端向原先提供租约和其它信息的DHCP服务端发送更新消息,用于延长租约的生存时间或更新其它配置信息。 |
| 6 | REBIND | 客户端向任何可用服务端发送重新绑定信息,用于更新租约时间和其它信息。当客户端发送Renew消息得不到响应时,会触发此消息。 |
| 7 | REPLY | 服务端针对特定客户端SOLICIT,REQUEST,RENEW,REBIND,INFORMATION-REQUEST,CONFIRM,RELEASE或者DECLINE消息的响应。 |
| 8 | RELEASE | 客户端给服务端发送RELEASE消息释放对某个地址的占用。 |
| 9 | DECLINE | 客户端给服务端发送DECLINE消息,反馈服务端分配的地址已经在链路上被占用。 |
| 10 | RECONFIGURE | 服务端发送RECONFIGURE给客户端,通知它服务端上有配置信息更新,客户端需要发起RENEW或REBIND或者INFORMATION-REQUEST来获取更新后的信息。 |
| 11 | INFORMATION-REQUEST | 客户端通过INFORMATION-REQUEST消息在没有被分配地址租约的情况下获取其它信息。 |
| 12 | RELAY-FORW | 中继代理通过RELAY-FORW消息将请求转发给服务端 |
| 13 | RELAY-REPL | 服务端通过RELAY-REPL消息让中继代理转发REPLY消息给客户端。 |
DUID
DHCP唯一标识符(DUID)是用于DHCP客户端和服务器的标识符,用于在DHCP网络中识别和关联彼此。服务端和客户端都有DUID。服务端通过客户端的DUID来识别客户端,以区分不同客户端分配对应的配置。客户端通过服务端的DUID识别DHCP服务器,确保是同正确的服务端通信并收到正确配置。DHCP中的DUID实现是一个黑盒,客户端和服务端都应该只把它当成一个唯一标志符做比较,不要试图通过解析它的格式获取某种客户端信息。DUID还需要是稳定的,也就是说DHCP的参与者应该确保DUID不会随时间或硬件变更而发生变化,需要能持久化。
身份关联
身份关联(Identity Association,简称IA) 是DHCPv6中用于关联客户端设备(也就是网络接口)和与其对应的网络配置,这里的配置主要是指IPv6地址、前缀、DNS服务器、NTP服务器等信息。
IA可以用于地址关联和前缀委派关联(IA_PD)。地址关联又分为非临时地址关联(IA_NA)和临时地址关联(IA_TA)。前缀委派(prefix delegation ,PD)是客户端向服务端申请一到多个前缀,然后自行管理这个(些)前缀,下级网络可以从用这种前缀来配置自己的网络接口。
每个IA都有一个唯一的标识符,称为IAID(Identity Association Identifier),这个值是一个4字节的整型。IAID用于在DHCPv6消息中标识和区分不同的IA。客户端设备通过IAID将其所需的网络配置与相应的IA关联起来。IAID由客户端设定,对于某种IA(IA_NA/IA_TA/IA_PD)这个IAID应该是唯一的,但是不同IA可以重复。比如我们可以定义IA_NA和IA_PD的IAID都是0。
IA是作为选项携带在DHCPv6消息中,客户端可以在DHCPv6的SOLICIT消息发送1到多个IA,服务端需要在Advertise或Reply消息中为客户端提供相应IA选项,每个IA对应一个网络配置信息。
IA的消息格式样例如下:

消息交互流程
四个消息交互流程
四个消息交互流程是常规的DHCPv6用于分配地址的模式,适用于较复杂的网络,主要流程如下:
- 客户端发送一个Solicit消息到All_DHCP_Relay_Agents_and_Servers(ff02::1:2)这个多播地址,用于发现可用的DHCP服务器。
- 任何符合客户端要求的DHCP服务端可以响应Advertise消息。
- 客户端选择一个DHCP服务端发送Request请求以申请确认分配的地址或前缀和其它信息。
- 服务端通过Reply消息返回所需的地址或其它信息。
两个消息交互流程
两个消息的交互有两个场景。
无状态DHCP
在无状态DHCP模式下,客户端不需要从服务端获取地址,只需要获取DNS等其它信息。这种情况下,客户端可以给All_DHCP_Relay_Agents_and_Servers(ff02::1:2)这个多播地址发送Information-request消息。服务端通过Reply消息返回对应的其它信息。
有状态DHCP
正常的有状态DHCP流程是上一小节提到的四个消息交互,如果环境中只有一个DHCP服务器,客户端想要走加急模式实现地址分配,也是可以通过两个消息实现。这种情况下,客户端在发送Solicit消息的时候,会带上Rapid Commit选项,表示客户端希望从服务端立即获取到携带被分配的地址等信息的Reply消息。服务端可以选择接受这种加急请求,并返回Reply消息,这种情况两个消息的交互就完成了,客户端可以直接使用Reply中的地址或前缀信息。当然服务端也可以选择不接受这种加急请求。
更新流程
客户端地址到期的更新流程也是两个消息的交互流程,这种流程比较好理解,就是客户端发送Renew消息,而服务端响应Reply消息。
附录
EUI-64d地址转换
在SLAAC或者DHCP流程中,都可能涉及到EUI-64地址的生成。

EUI64地址的转换逻辑,原始的MAC地址是48位,分成前24位和后24位,中间插入0xFF和0xFE。左数第七个比特为U/L位,需要做一次翻转,原来是0,就变成1,原来是1就变成0。
单播MAC地址中,第1个Byte的第7bit是U/L(Universal/Local,也称为G/L,其中G表示Global)位,用于表示MAC地址的唯一性。 如果U/L=0,则该MAC地址是全局管理地址,是由拥有OUI的厂商所分配的MAC地址; 如果U/L=1,则是本地管理地址,是网络管理员基于业务目的自定义的MAC地址。 而在在EUI-64接口ID中,第7bit的含义与MAC地址正好相反,0表示本地管理,1表示全球管理,所以使用EUI-64格式的接口ID,U/L位为1,则地址是全球唯一的,如果为0,则为本地唯一。这就是为什么要反转该位。
U/L位翻转也方便了IPv6地址的压缩,比如我们可以手工将一个point-to-point 链路的两端mac地址配置为02-00-00-00-00-00-00-01 和 02-00-00-00-00-00-00-02,在引入翻转之前,两边的IPv6地址是FE80::200:0:0:1和FE80::200:0:0:2,翻转后是FE80::1和FE80::2。
IPv6隐私扩展
IPv6的隐私扩展(Privacy Extensions for IPv6)是一种用于保护网络设备用户隐私的机制。在IPv6中,每个设备通常会根据其MAC地址生成一个全球唯一的IPv6地址,这可能导致用户的在线活动被追踪和监视。隐私扩展旨在解决这个问题,通过生成临时的、随机化的IPv6地址来保护用户的隐私。
隐私扩展通过使用临时地址(Temporary Address)来替代固定的全球唯一地址(Stable Address)。临时地址是在设备的网络接口上动态生成的,并且通常有一个较短的生存期。这样,设备的IPv6地址会定期更换,使其更难被追踪。
隐私扩展通常采用以下两种生成临时地址的方法之一:
- 随机生成 :设备使用随机数生成器生成一个新的临时地址。这个地址通常只在设备的当前会话期间有效,关闭会话后将被丢弃。
- 使用加密算法 :设备使用某种加密算法,如Cryptographically Generated Address (CGA),根据一些密钥和标识信息生成临时地址。这种方法可以提供更长期的地址稳定性,同时仍保持一定的隐私性。
Windows系统一般默认开启了隐私扩展,linux下需要针对网卡设置对应选项开启这个功能。一般情况下,我们会同时获取一个管理地址和一个临时隐私地址。管理地址可能是一个根据EUI64地址生成的IPv6地址,它的生命周期可以长达几天,也会定期触发renew,我们可以用这个地址来访问主机的相关服务(HTTPS/SSH等)。临时隐私地址的生存时间一般只有几个小时,主要是用于主机访问外部资源。
引用
RFC 8200 - Internet Protocol, Version 6 (IPv6) Specification (ietf.org)
RFC 4291 - IP Version 6 Addressing Architecture (ietf.org)
RFC 4861 - Neighbor Discovery for IP version 6 (IPv6) (ietf.org)
RFC 4862 - IPv6 Stateless Address Autoconfiguration (ietf.org)
RFC 6724 - Default Address Selection for Internet Protocol Version 6 (IPv6) (ietf.org)
RFC 6275 - Mobility Support in IPv6 (ietf.org)
RFC 8415 - Dynamic Host Configuration Protocol for IPv6 (DHCPv6) (ietf.org)
RFC 4941 - Privacy Extensions for Stateless Address Autoconfiguration in IPv6 (ietf.org)
RFC 3810 - Multicast Listener Discovery Version 2 (MLDv2) for IPv6 (ietf.org)
QingYo