这两个月梳理IPv6项目资料时,发现一个很普遍的现象:一提IPv6地址自动配置,大家第一反应都是SLAAC(无状态地址自动配置),对DHCPv6却总有种"好像知道、细问就懵"的状态,甚至有朋友直接抛出一句"IPv6不是有SLAAC了吗,还要DHCP干嘛?"——这句话我听过太多次了,但等你真正要在一个管理要求不低的园区网或家庭网络里落地IPv6,要下发DNS、要记录租约、要给下级设备委派前缀时,DHCPv6就是绕不开的核心协议。这篇博客我想把自己在IPv6过渡和双栈改造项目中对DHCPv6的理解完整写出来,从协议原理到报文交互再到部署排错,尽量说人话,让新人和有一定基础的朋友都能直接拿去做参考。
1. 为什么IPv6时代还需要DHCPv6
总有朋友觉得,IPv6的地址空间大到可以给每个设备发一辈子地址,似乎就不需要"动态分配"这套东西了。这个直觉有一半是对的,但另一半恰恰是DHCPv6的价值所在。
1.1 IPv6地址到底怎么来的
在IPv6网络里,一台主机想要上网,先得解决三个最基本的问题:有没有地址、网关在哪、DNS是谁。其中地址的获取方式,大致分三类:
- 手动静态配置:网管手工敲地址、前缀、网关,适合服务器、网络设备这类数量少且地址需要固定的场景。
- SLAAC(无状态地址自动配置):主机收到路由器的RA(Route Advertisement,路由通告)报文后,自己拿前缀加接口标识生成地址。
- DHCPv6(有状态或混合配置):客户端和DHCPv6服务器交互,由服务器分配地址和下发配置参数。
SLAAC的好处是即插即用、不需要额外部署服务器,但它的核心逻辑是"让每个主机自己算地址",而DHCPv6的核心逻辑是"由服务器统一管理地址"。这两种思路从设计哲学上就不一样,所以不能说SLAAC能替代DHCPv6。
1.2 SLAAC的短板就是DHCPv6的主场
SLAAC有一个非常尴尬的短板:它最初只告诉主机怎么生成地址,却不管DNS、域名、NTP这些参数怎么下发。虽然后来出现了RFC 8106,允许路由器把DNS选项塞进RA的RDNSS字段里,但实际终端对不同厂商实现的响应并不统一,很多老旧系统根本不理会RDNSS。结果就是,只靠SLAAC,很多设备虽然拿到了地址,DNS却是空白的,访问域名根本解析不了。
另一个短板是没有租约概念。SLAAC地址的生命周期由RA报文里的前缀有效期决定,但主机是否还活着、该IP能不能回收复用,路由器基本不掌握,这让网络管理和审计无从下手。而DHCPv6天然带租约管理,谁在什么时间从哪个池子里拿走了哪个地址、何时续租、何时释放,全部有账可查。
1.3 不同场景对DHCPv6的刚需
稍微梳理一下就能发现,DHCPv6在下面这些场景里几乎是刚需:
- 企业/园区网络:终端数量多、人员流动大,需要DHCPv6有状态分配地址,并统一下发DNS、搜索域。配合准入系统记录终端IP和MAC的映射关系,出了问题可以追溯。
- 运营商家庭网络:CPE设备需要从局端获取IPv6前缀,再在自己的LAN侧做路由下发。这时候用的不是普通地址分配,而是DHCPv6-PD(前缀委派),这个SLAAC完全做不到。
- 数据中心双栈环境:服务器要稳定、可区分的IPv6地址,而且业务变更时希望做到自动化,DHCPv6可以按MAC或DUID保留固定地址。
- 纯IPv6改造项目:当你把DNS、日志、网关等全部搬到IPv6时,没有DHCPv6这一层,几百上千台终端的网络配置就得全靠人工,谁受得了。
这些场景落地多了,你就会认可一句话:SLAAC解决的是"能通"的问题,DHCPv6解决的是"能管"的问题。
2. DHCPv6的核心机制:报文、端口与完整通信流程
要理解DHCPv6,不能只看它能干什么,还得知道它底层是怎么运作的。这部分如果只记几个报文名字,到了排错现场很容易发懵,所以我把端口、报文和流程放在一起讲。
2.1 端口和多播地址
DHCPv6的传输层完全基于UDP,这一点和DHCPv4类似,但端口号不一样。DHCPv6客户端使用UDP 546,服务器使用UDP 547。
还有一个重要的区别是通信方式。IPv6下很少用广播,DHCPv6里客户端往特定的多播地址发报文:
- FF02::1:2:本地链路范围内所有DHCPv6中继和服务器地址,客户端在本地链路发现服务器时用它。
- FF05::1:3:站点本地范围内所有DHCPv6服务器地址,主要用于中继向服务器转发报文时使用的目的地址。
我刚开始抓包时老盯着源端口546、目的端口547看,其实只要看到FF02::1:2或者FF05::1:3就大致能猜到这是DHCPv6流量了。这些多播地址在抓包过滤里可以直接写ip6.dst == ff05::1:3来定位。
2.2 两种分配模式:有状态与无状态
DHCPv6其实是一套"两栖"协议,既可以管地址,也可以只管参数:
- 有状态模式(Stateful DHCPv6):服务器给客户端分配IPv6地址,同时下发DNS等参数。客户端通过SOLICIT/REQUEST等报文完成地址获取。
- 无状态模式(Stateless DHCPv6):客户端地址靠SLAAC自己生成,DHCPv6只负责下发DNS、域名、NTP等参数。客户端发送的是INFORMATION-REQUEST报文,服务器回REPLY。
这两种模式的切换不是客户端随心所欲,而是由路由通告RA中的M位和O位决定:
- M位(Managed address configuration flag)= 1,表示地址也由DHCPv6管理。
- O位(Other configuration flag)= 1,表示其他配置参数由DHCPv6获取。
如果M位和O位都是0,主机就只用SLAAC,完全不需要理会DHCPv6。如果M=1、O=1,则是有状态模式;M=0、O=1则是无状态模式。这个细节排错时非常关键,因为很多人明明部署了DHCPv6服务器,结果Router那边RA没开O位,终端压根不会来找DHCPv6,还查半天服务器配置。
2.3 从SOLICIT到REPLY的四步流程
有状态模式下,一个客户端第一次获取地址的标准流程可以理解为"四步握手",和DHCPv4的DORA(Discover/Offer/Request/Ack)类似,但报文名字不同:
- 客户端发送SOLICIT报文,目的地址是链路本地多播FF02::1:2,里面带上客户端的DUID和请求参数列表,意思是"这条链路上有DHCPv6服务器吗?我需要地址和配置。"
- 服务器收到后回应ADVERTISE报文,告诉客户端"我在,我可以给你地址",并携带候选地址、租期和服务器DUID。
- 客户端选择一个服务器,发送REQUEST报文确认要地址。
- 服务器收到REQUEST后回复REPLY报文,把正式分配的地址、租期和配置参数给到客户端。
如果链路中还有其他服务器,所有能提供服务器的都会回ADVERTISE,客户端通过选项里的服务器优先级(Preference Option)和服务端DUID来决定选谁。这里和DHCPv4不太一样的地方是,DHCPv4用广播和广播回复,DHCPv6全程要么多播要么单播,没有广播。
我用Wireshark抓过很多次这个交互过程,最直观的观察方式是抓取dhcpv6过滤器,你会看到一个很清晰的四报文序列。以前排查问题时,我打开抓包文件第一步就是数这四个报文有没有齐,缺哪个基本就能锁定问题出在哪一端。
2.4 续租重绑:T1/T2的完整状态机
拿到地址之后并不是一劳永逸,DHCPv6里地址有首选生命期(Preferred Lifetime)和有效生命期(Valid Lifetime),服务器通过报文中的IAADDR选项告诉客户端。真正决定续租节奏的是IA_NA里的T1和T2两个定时器:
- T1:进入RENEW状态的时间,通常是有效生命期的一半。T1到期,客户端直接向当初分配地址的服务器单播发送RENEW报文,请求续租。
- T2:进入REBIND状态的时间,通常会大于T1而小于有效生命期,默认是有效生命期的80%。T2到期而RENEW还没成功,客户端转为多播发送REBIND报文,目的是让链路上任意一台服务器响应,应对原服务器挂了的情况。
如果到了有效生命期结束还都没续上,客户端必须停止使用这个地址,重新走一遍SOLICIT流程。这一段状态机理解了,后面看日志就不会一头雾水。比如客户端日志里出现REBIND,我第一反应就是T1阶段没有续租成功,原服务器可能不可达,而不是直接去看DNS配置。
3. DHCPv6的选项系统是灵魂
DHCPv6的报文体里塞满了各种选项,协议的全部扩展能力几乎都体现在选项上。很多朋友学了一半说"祥林嫂"的,基本就是栽在这个选项上。其实核心选项没几个,掌握了它们,整个协议的血肉就都有了。
3.1 DUID和IA:身份证和户口本
先聊两个字符串概念,DUID和IA。
DUID就是DHCP唯一标识符(DHCP Unique Identifier),可以类比成客户端或服务器在DHCP体系里的身份证。客户端和服务器的DUID各自唯一。客户端把DUID放在选项里发出去,服务器就能识别"这是同一个客户端在续租"。类似地,服务器DUID让客户端确认自己收到的REPLY来自当初应答的那个服务器。
IA(Identity Association)则可以理解成"户口本":把一组地址和一个客户端关联起来。DHCPv6里主要有两类:
- IA_NA(Non-temporary Address):非临时地址关联,用于常规网络接口的稳定地址,会携带IAID、T1、T2和IAADDR子选项。
- IA_TA(Temporary Address):临时地址关联,不携带T1/T2,生命周期短,更适合隐私保护场景。
IAID是接口自定义的标识,客户端用它区分自己不同接口上的不同IA。比如笔记本电脑有线和无线两个网卡,各维护一个IA,DHCPv6服务器靠IAID和DUID的组合来分别记录租约。
3.2 高频选项清单速查
实际抓包和配置里,你大概率会遇到下表这些选项:
| 选项编号 | 选项名称 | 中文可读理解 | 典型用途 |
|---|---|---|---|
| 1 | Client Identifier | 客户端DUID | 标识客户端身份 |
| 2 | Server Identifier | 服务器DUID | 标识服务器身份 |
| 3 | IA_NA | 非临时地址关联 | 请求/分配稳定地址 |
| 4 | IA_TA | 临时地址关联 | 请求/分配临时地址 |
| 5 | IAADDR | 具体IPv6地址+生命周期 | 携带分配到的地址 |
| 6 | ORO | 选项请求列表 | 客户端声明想要哪些选项 |
| 23 | DNS Servers | IPv6 DNS服务器列表 | 下发DNS |
| 24 | Domain List | DNS搜索域名列表 | 下发搜索域 |
| 32 | Information Refresh Time | 无状态参数刷新时间 | 无状态模式刷新周期 |
| 39 | FQDN | 客户端主机名 | 动态DNS联动 |
| 59 | OPTION_NTP_SERVER | NTP服务器信息 | 下发时间服务器 |
配置DHCPv6时,除了地址池,记得把Option 23(DNS)和Option 24(Domain List)一并下发,否则终端即使拿到地址也经常会遇到域名解析失败的问题。这个坑我在第6节会详细讲。
3.3 选项协商:客户端也会提要求
DHCPv6不像DHCPv4那样只靠服务器单方面给参数,客户端在SOLICIT或INFORMATION-REQUEST中会带一个ORO(Option Request Option),实际上是"我想要哪些选项"的愿望清单。服务器看到ORO之后,会尽可能响应客户端请求的选项。
这个设计在无状态模式下特别讨喜:我只需要DNS,那我就只请求Option 23;我需要NTP,就再加上Option 59。服务器不用给所有客户端下发全部配置,节省报文空间,客户端端到端的体验也更干净。实际部署中,我们经常在路由器上写"DNS服务器地址"和"域名"两个全局配置,但客户端请求里若没在ORO里提,部分实现也可能不会主动下发,所以务必检查RA的O位和服务器端的相关选项下发生效情况。
3.4 前缀委派(PD)的原理与价值
如果说前面这些选项是针对主机终端的,那IA_PD(Prefix Delegation,前缀委派)就是面向路由器这类设备的一等公民。
简单场景是:上层网络(比如运营商局端)通过DHCPv6给下级CPE设备(比如家里的光猫、路由器)委派一个前缀,比如分配一个2001:db8:2000::/56,CPE再把这个前缀进一步划分成多个/64发到下面的LAN口,让家里每个子网都能获得全局可达的IPv6地址段。这里面用的是Option 25(IA_PD)和Option 26(IAPREFIX)。
PD机制的价值在于把前缀的管理权集中到上一级,下级设备不用自己瞎编地址段,全网路由聚合也干净。在园区网里,总部给各个楼层/科室委派不同前缀,实现地址段的逻辑隔离;在运营商网络里,终端用户获得的全局地址由局端统一规划。可以说没有DHCPv6-PD,IPv6在接入网和家庭网络里很难实现灵活规划。
4. 三种地址获取方式怎么选
在实际网络设计评审里,我最常被问的不是协议本身,而是"我这场景到底用哪种方式"。这个选择严重影响后续配置和维护成本,所以我把对比和选择逻辑单独放一节来写。
4.1 静态配置 vs SLAAC vs DHCPv6 大对比
| 对比项 | 手动静态配置 | SLAAC | DHCPv6有状态 | DHCPv6无状态 |
|---|---|---|---|---|
| 地址分配 | 管理员手工维护 | 主机自己生成 | 服务器统一分配 | SLAAC生成 |
| 默认网关 | 手写或RA下发 | 来自RA | RA下发 | RA下发 |
| DNS获取 | 手写 | RA RDNSS(支持有限) | 服务器下发 | 服务器下发 |
| 集中管理 | 差 | 几乎没有 | 强,有租约日志 | 中,只有参数管理 |
| 地址回收 | 靠手工 | 靠生命周期过期 | 租约机制主动回收 | 不适用 |
| 前缀委派能力 | 不支持 | 不支持 | 支持PD | 不支持 |
| 典型场景 | 服务器、网络设备 | 物联网/极简接入 | 企业办公、运营商局端 | 仅需要DNS等参数 |
这张表基本是我给项目出方案时的评审底稿,核心话术就一条:要管理、要审计、要委派选DHCPv6有状态;只要能通、不追求管控选SLAAC;设备少且要稳定地址选静态。
4.2 RA的M/O位:指挥客户端该听谁的
前面提过M/O位,这里把它们的组合逻辑列清楚,因为这是设计中最容易搞错的地方:
- M=0、O=0:主机只用SLAAC,不碰DHCPv6。适合极简网络或物联网场景。
- M=1、O=1:主机通过DHCPv6获取地址和参数。完整的有状态模式,适合企业接入。
- M=0、O=1:主机地址走SLAAC,参数走DHCPv6。无状态模式,适合终端数量大但不需要管地址的场合。
设计双栈园区时,我建议对办公终端打开M位和O位,同时给打印机、摄像头这类设备走SLAAC只开O位甚至全关。因为很多摄像头和打印机的IPv6协议栈比较"潜水艇",遇到DHCPv6有状态分配反而兼容性差。这就是现实网络运维的修行——不是所有设备都吃得起相同的配置策略。
4.3 混合部署的一个日常例子
拿一个几百人的企业园区举例:客户端Wi-Fi接入的网段,RA里开M=1、O=1,DHCPv6服务器统一分配地址并下发DNS和搜索域;服务器区则用静态地址,因为数据库、核心业务需要稳定的IP配合访问控制策略;物联网摄像头单独划分一个VLAN,RA里设M=0、O=0,靠SLAAC获取地址。
这套混合策略的好处是,核心管控区牢牢握在手里,终端密集区享受DHCP的自动化,低管理要求的设备省去协议复杂度。实践证明,方案越细分,后期排障半径越小。
5. 动手做一套DHCPv6环境的完整流程
说一千道一万,不做一次实验很难真正搞懂DHCPv6。这一节我按最小可验证的思路,讲一下怎么快速搭一个DHCPv6环境并观察协议行为。全程用开源软件,你在一台Linux机器上就能做。
5.1 用开源软件快速搭一个验证环境
我的常用选择是ISC/Kea DHCPv6服务器和radvd。Kea是面向现代网络设计的DHCPv6/DHCPv4服务器,配置文件是JSON格式,比老ISC dhcpd清晰不少。下面给一个精简的kea-dhcp6.conf思路,重点看结构而不是逐字抄:
{ "Dhcp6": { "interfaces-config": { "interfaces": [ "eth0" ] }, "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::100 - 2001:db8:1::1ff" } ], "option-data": [ { "name": "dns-servers", "data": "2001:db8:1::53" }, { "name": "domain-search", "data": "example.com" } ] } ] } }注意几点:
- Kea会绑定UDP 547端口,最好在Linux上用root用户跑,或者用systemd配置capabilities。
subnet定义的是链路前缀,pools才是真正可以分配的地址范围。option-data是全局或子网级下发参数,我一般会把DNS和Domain Search放在子网级,因为不同VLAN的DNS规划也许不一样。
启动后可以用kea-dhcp6 -d -c /etc/kea/kea-dhcp6.conf看调试日志。真正调通之后,再用journalctl -u kea-dhcp6看运行期日志。
如果你的环境里已有radvd负责RA,那还要确认RA的M/O位设置。比如radvd配置文件里可以这样:
interface eth0 { AdvManagedFlag on; AdvOtherConfigFlag on; prefix 2001:db8:1::/64 { AdvOnLink on; AdvAutonomous on; }; };关闭radvd、单独手工敲RA或直接改M/O位也是排查手段之一,下文会展开。
5.2 客户端侧的观察手段
客户端只要接到这个网段,并且RA携带合适的M/O位,就会自动发起DHCPv6。Linux上建议安装radvdump来查看RA的M/O位,用ip -6 addr show查IPv6地址是否带scope global dynamic字样。Windows上可以看ipconfig /all里IPv6地址是否有"首选"生命周期。
还要学会抓包验证:在客户端上执行tcpdump -i eth0 ip6 proto udp and port 546 or port 547,观察SOLICIT/ADVERTISE/REQUEST/REPLY四条报文。如果只看到本机发了SOLICIT,一直没人回ADVERTISE,大概率是服务器或链路问题;如果收到ADVERTISE但没继续REQUEST,可能是客户端对选项不满意或服务器鉴权策略拒绝。
有个很实用的细节:用dhcpcd这类客户端工具时,加-6参数可以强制走IPv6模式,而且它打印的日志带详细状态信息,非常适合排错。我在实验环境里经常同时开着tcpdump和dhcpcd的控制窗口,两边对照着看,一个问题往往几分钟就能定位。
5.3 跨网段的中继配置思路
DHCPv6服务器通常放在核心机房,终端在接入交换机下面,跨网段时就需要中继(Relay Agent)。中继在收到客户端的多播SOLICIT后,把它封装成RELAY-FORW报文发给服务器;服务器回REPLY时,中继再解封装并转发给客户端。
中继配置在主流网络设备上的逻辑基本一致:需要指定中继代理的客户侧接口,以及IPv6 DHCP服务器地址。我在现网中的经验是,中继一定不要指向链路本地地址或不可达地址,否则RELAY-FORW发不出去。还要注意中继接口上需要开启IPv6多播侦听,如果接入交换机把FF02::1:2多播段给过滤了,客户端和中继之间也会静默失联。
6. 实战排错:我踩过的坑和速查手册
DHCPv6常见故障其实很集中,我把这几类问题的排查路径整理成下面的清单,能省掉你大量的抓包时间。
6.1 最常翻车的三个环节
一个是RA没有正确设置M/O位。客户端完全靠RA决定要不要理睬DHCPv6,如果路由器的RA还是老配置,M=0、O=0,终端就静悄悄地只用SLAAC,DHCPv6服务器那边自然全是"查无此人"的冷清。排查时第一件事就是到客户端上radvdump或抓RA报文,确认M/O位。
第二个是防火墙放行漏掉546/547端口。我见过不少人,DHCPv6服务器和客户端都配置正确,但服务器防火墙没有放行UDP 547,客户端SOLICIT根本进不来。IPv6防火墙的ACL有时比IPv4严格得多,大家一定要在服务器端和终端侧都检查UDP 546、547是否放行。
第三个是DUID变化导致租约错乱。很多终端在网卡重置、系统重装后会生成新DUID,服务器还按旧DUID续租,结果新会话一直收到REJECT。另外,配置固定地址时如果以客户端DUID绑定,实际中继场景还要注意看到的DUID是客户端还是中继的,这个坑在接入层下挂多个终端时特别容易翻车。我已习惯做绑定前先在日志里确认客户端DUID转发路径不变。
6.2 疑难问题排查思路
除了上面三个高发问题,还有几个相对隐蔽的场景值得单独说。比如DNS下发失败,终端拿到了地址但解析不了域名,很多是因为服务器只配了地址池没配Option 23,或者RA处于无状态模式但Info Refresh Time(Option 32)设得太长,导致参数更新滞后。再比如IPv6地址有但网关不通,大概率是RA没有下发路由(有些设备通过RDNSS或DHCPv6下发网关,这在设计上就比SLAAC的RA传网关要多绕不少弯路)。
还有一个小众但现实的问题:启用隐私扩展后,终端会生成临时地址,DHCPv6续租日志里的IAID可能频繁变化,导致固定地址绑定失效。如果业务需要固定地址,要么关闭隐私扩展,要么按DUID而不是IAID做绑定的流水线设计。
6.3 安全要点与防护
DHCPv6本身没有像样的认证机制,协议信任链很大程度上依赖网络接入安全。接入层交换机上开启DHCPv6 Guard和RA Guard,能有效拦截伪造服务器和伪造RA的报文,是保护IPv6接入网络的基本功。另外,地址扫描和邻居欺骗攻击在IPv6里依然存在,有条件建议配合NDP监控和MAC/IP绑定策略。
我经手的一个跨平台系统改造项目里,就是因为接入层没有过滤DHCPv6报文,测试同事在验证环境里随手搭的DHCPv6服务器把整个网段的终端都带偏了,DNS全被导向一个不存在的地址,排查了半天。从那以后,我把"接入交换机三层首跳必须开DHCPv6 Guard"写进了项目基线。
6.4 DHCPv6常见问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 终端拿不到IPv6地址 | RA M/O位没设置,终端不知道要用DHCPv6 | radvdump看RA;抓包看是否发SOLICIT |
| SOLICIT发出但无ADVERTISE | 服务器不可达/防火墙封端口/中继没指对 | 检查UDP 547放行、服务器日志、中继配置 |
| 拿到地址但DNS解析不生效 | Option 23没下发,或ORO没请求DNS | 查看REPLY报文的option-data;补DNS选项 |
| 续租失败频繁REBIND | 原服务器不可达;T1/T2设置不合理 | 看客户端日志;调整T1/T2并抓包确认单播可达 |
| 固定地址老是变 | DUID变化或绑定发错了对象 | 核对客户端DUID和绑定策略;注意中继路径 |
| 前缀委派不生效 | 上级DHCPv6未支持PD;IAPREFIX下发不完整 | 检查RELAY报文中的IA_PD选项;确认Request内容 |
最后说点实在的
我自己从第一次配DHCPv6到现在,最大的体会是:它其实不复杂,容易搞混的是位和选项太多,而且排错时总得和RA联动看。真正想熟练,建议在实验环境里把radvd、Kea、tcpdump搭配起来,把有状态、无状态、PD这三种模式各跑一遍,再用故障注入去模拟"RA不到位""防火墙挡端口""DUID变化"这几个场景。走完这一轮,你再到现网里看DHCPv6日志,基本就是一马平川了。后续我还想写一篇专门讲IPv6动态DNS联动和DHCPv6-PD在运营商接入里的实战案例,如果你也踩过类似坑,欢迎一起交流。