1. 从一个"设备拿不到地址"的现场说起
上周帮朋友处理了一个办公网的问题:三层核心交换机下挂了三个VLAN,其中两个VLAN的终端能正常获取IP,唯独访客VLAN的笔记本一直卡在"正在获取网络地址",手动配静态IP就能通。这种"部分网段正常、部分网段异常"的现象,十有八九是DHCP中继没配对或者配漏了。很多人对DHCP的理解停留在"路由器自动发IP"这个层面,一旦网络做了VLAN划分、跨了三层设备,就开始抓瞎。这篇内容就把DHCP和DHCP中继这两件事从头到尾讲透,包括协议交互的底层逻辑、中继的报文改写机制、以及可以直接抄作业的配置方案。不管你是刚入行的网络运维,还是考完认证但没怎么碰过真机的朋友,看完都能自己动手把一套跨网段的DHCP环境搭起来。
DHCP这个协议本身不复杂,难的是它在真实网络里的部署形态。小型网络里,一台路由器开个DHCP池就完事了;但到了有多个网段的环境,你不可能每个网段都放一台DHCP服务器,这时候就需要DHCP中继来"代收代发"。理解中继的关键,是搞清楚DHCP Discover报文里的那个giaddr字段到底怎么被改写、服务器又是怎么根据它来决定从哪个地址池分配IP的。这些细节,才是排障时真正用得上的东西。
2. DHCP协议核心机制拆解
2.1 DHCP到底解决了什么问题
在没有DHCP的年代,每台机器上线都要手动配IP、掩码、网关、DNS,机器一多就是灾难。DHCP的核心价值就两个词:自动化和集中管理。它基于UDP工作,服务器用67端口,客户端用68端口。整个交互过程被设计成四步,业内叫DORA:
- Discover:客户端不知道服务器在哪,就用广播喊一嗓子"谁是DHCP服务器"。源地址0.0.0.0,目的地址255.255.255.255。
- Offer:服务器收到后,从地址池挑一个可用的IP,通过Offer报文回给客户端。注意,这一步很多情况下也是广播,因为客户端此时还没有IP。
- Request:客户端可能收到多个Offer,它选一个,然后广播Request正式请求这个地址。广播的目的是让其他也发了Offer的服务器知道"我被拒绝了",好回收地址。
- Ack:被选中的服务器回Ack确认,客户端拿到IP后还会做一次ARP探测(免费ARP),确认这个地址在网段内没冲突才正式启用。
这四步里,Discover和Request是广播,Offer和Ack的发送方式取决于客户端有没有IP以及是否设置了广播标志位。理解这一点,对后面理解中继的行为至关重要。
2.2 租约、续租与地址回收
DHCP分配的地址不是永久的,而是有**租约(Lease)**的。默认租约常见是24小时到8天不等,具体看设备厂商。租约机制解决的是地址回收问题——设备下线后地址能自动回到池子里给别人用。
租约过半(T1,默认50%)时,客户端会尝试单播续租,直接找原来那台服务器。如果续租失败,到租约的87.5%(T2)时,客户端会广播找任意一台服务器续租。如果到租约到期还没续上,客户端就得放弃这个地址,重新走DORA流程。
这里有个实操中经常踩的坑:如果DHCP服务器换了,但客户端还拿着旧租约,续租会失败。因为续租是单播到原服务器地址的,服务器没了自然没人应答。这时候要么等租约过期,要么在客户端手动释放(Windows下ipconfig /release再/renew)。
2.3 地址池的几种分配策略
配置DHCP池的时候,分配方式不是只有一种:
| 分配方式 | 特点 | 适用场景 |
|---|---|---|
| 动态分配 | 从池中随机/顺序取,有租约 | 普通办公终端、访客 |
| 自动分配 | 首次分配后永久绑定 | 需要固定但不想手配的设备 |
| 静态绑定 | MAC与IP一一对应 | 打印机、服务器、AP |
| 排除地址 | 从池中挖掉一段 | 网关、保留给静态设备的地址 |
实际部署里,最常见的组合是"动态池 + 静态绑定 + 排除段"。比如网关地址、几台网络设备的地址,都要从动态池里排除掉,否则可能被分给终端造成冲突。这个排除操作在配置时千万别忘,我见过不止一次因为网关地址没排除,结果被某台终端抢走导致整个网段瘫痪的案例。
3. 为什么需要DHCP中继:广播域的天然限制
3.1 广播不能跨三层,这是问题的根源
DHCP的Discover是广播报文,而路由器(三层设备)默认不转发广播。这就意味着,如果DHCP服务器在A网段,客户端在B网段,客户端的广播喊话根本传不到服务器那里。这是IP协议的基本设计——广播域就是二层网络边界,跨了三层就断了。
那怎么办?有两个思路:一是在每个网段都部署一台DHCP服务器,二是让三层设备帮忙"转发"这些DHCP报文。第一种方案成本高、管理分散,网段一多根本管不过来。第二种方案就是DHCP中继(DHCP Relay),也叫DHCP代理。
3.2 中继的本质:把广播变单播
DHCP中继做的事情,说白了就是代收代发。它部署在网关设备(通常是三层交换机或路由器)上,监听客户端所在网段的68端口。当收到客户端的DHCP广播时,中继把它从广播转成单播,直接发给配置好的DHCP服务器。服务器回包后,中继再把它转回给客户端。
这个"广播转单播"的过程,关键在于中继会往报文里塞一个**giaddr(Gateway IP Address)**字段,填的是收到该报文的接口IP,也就是客户端的网关地址。服务器看到giaddr,就知道"这个请求来自哪个网段",然后从对应的地址池里分配IP。这就是为什么一台DHCP服务器能同时服务多个网段——全靠giaddr来区分。
3.3 giaddr字段:中继的灵魂
giaddr这个字段值得单独拎出来说,因为它是排障时最常出问题的地方。
当客户端直接和服务器在同一网段时,giaddr是0.0.0.0。当经过中继时,中继会把giaddr改成自己接收报文的接口IP。服务器收到后,逻辑是这样的:
- 看giaddr是不是0。如果是0,说明客户端和自己在同一网段,用接收接口所在网段的池子。
- 如果giaddr非0,说明经过了中继,服务器会去找和giaddr在同一网段的地址池来分配。
所以配置中继时,服务器上必须有一个网段和giaddr匹配的地址池,否则服务器不知道给什么地址,直接丢弃报文。这就是为什么"中继配了但拿不到地址"最常见的原因——服务器上没有对应网段的池子,或者池子的网段和giaddr对不上。
提示:giaddr填的是中继接口的IP,不是服务器的IP,也不是客户端的IP。排障时抓包看这个字段,能快速定位是哪个环节出了问题。
4. 中继报文交互全过程实录
4.1 一次完整的跨网段DORA
假设客户端在192.168.20.0/24网段,网关是192.168.20.1(中继接口),DHCP服务器在192.168.10.100。整个流程是这样的:
- 客户端广播Discover,源0.0.0.0,目的255.255.255.255,giaddr为0。
- 中继接口192.168.20.1收到,把giaddr改成192.168.20.1,然后单播发给192.168.10.100。
- 服务器收到,看到giaddr是192.168.20.1,找到192.168.20.0/24的地址池,挑一个IP,回Offer。Offer的目的地址是giaddr,也就是发给中继。
- 中继收到Offer,把它转回给客户端。此时客户端还没IP,所以中继通常广播或按客户端MAC单播。
- 客户端广播Request,中继同样改写giaddr后转发给服务器。
- 服务器回Ack,中继转回客户端,客户端正式启用IP。
整个过程里,中继做了两次改写(Discover和Request),两次转发(Offer和Ack)。抓包的时候,在服务器侧看到的报文giaddr都是中继接口IP,源地址是中继接口IP,这就是判断中继是否正常工作的依据。
4.2 中继的Option 82:位置信息的传递
除了giaddr,中继还可以插入Option 82(Relay Agent Information),用来传递客户端接入的物理端口、VLAN等信息。这个选项在需要精细化管理的场景很有用,比如:
- 根据接入端口分配不同网段的地址
- 防止DHCP欺骗(服务器校验Option 82)
- 审计终端接入位置
不过Option 82不是必须的,很多简单环境不开也能正常工作。开了之后要注意,某些老旧的DHCP服务器不认这个选项,可能会丢弃报文。我遇到过一台服务器因为收到带Option 82的报文直接不回,排查了半天才发现是服务器不支持,关掉中继上的Option 82就正常了。
4.3 中继与DHCP Snooping的配合
在接入层,通常会开DHCP Snooping来防止私接DHCP服务器。Snooping会把连接合法DHCP服务器的端口设为信任端口,其他端口收到的DHCP Offer/Ack直接丢弃。这个机制和中继是配合使用的:
- 接入交换机开Snooping,信任端口指向上行(通往中继/服务器的方向)。
- 中继设备正常转发DHCP报文。
- 如果有人在接入层私接路由器开DHCP,Snooping会把它发的Offer丢掉,防止终端拿到错误地址。
这个组合在企业网里几乎是标配,尤其是访客网络,不开Snooping很容易被私接设备搞乱。
5. 配置方案:从零搭一套跨网段DHCP
5.1 拓扑规划与地址分配
先明确一套可复现的拓扑。假设有一台三层交换机作为核心,下挂两个业务VLAN,一台独立的DHCP服务器接在核心的一个接口上:
| 设备/接口 | 地址 | 说明 |
|---|---|---|
| 核心VLAN10接口 | 192.168.10.1/24 | 服务器所在网段网关 |
| 核心VLAN20接口 | 192.168.20.1/24 | 业务网段A网关(中继接口) |
| 核心VLAN30接口 | 192.168.30.1/24 | 业务网段B网关(中继接口) |
| DHCP服务器 | 192.168.10.100/24 | 网关指向192.168.10.1 |
| 地址池VLAN20 | 192.168.20.100-200 | 排除.1到.99 |
| 地址池VLAN30 | 192.168.30.100-200 | 排除.1到.99 |
服务器上要建两个池子,分别对应20和30网段。核心交换机上,VLAN20和VLAN30的接口要配中继指向192.168.10.100。VLAN10不需要中继,因为服务器就在这个网段。
5.2 服务器侧地址池配置
以常见的Linux DHCP服务为例,配置文件里两个池子大概长这样:
subnet 192.168.20.0 netmask 255.255.255.0 { range 192.168.20.100 192.168.20.200; option routers 192.168.20.1; option domain-name-servers 192.168.10.100, 114.114.114.114; default-lease-time 86400; max-lease-time 172800; } subnet 192.168.30.0 netmask 255.255.255.0 { range 192.168.30.100 192.168.30.200; option routers 192.168.30.1; option domain-name-servers 192.168.10.100, 114.114.114.114; default-lease-time 86400; max-lease-time 172800; }几个关键点:option routers填的是各网段的网关,也就是中继接口地址,不是服务器地址。default-lease-time是默认租约,86400秒即24小时。DNS可以填服务器自己,也可以填公共DNS。
如果要做静态绑定,加一段host声明:
host printer-01 { hardware ethernet 00:11:22:33:44:55; fixed-address 192.168.20.50; }注意静态绑定的地址要在动态池范围之外,否则可能冲突。
5.3 中继设备配置(以三层交换机为例)
核心交换机上,VLAN20和VLAN30的接口要开中继。不同厂商命令略有差异,但逻辑一致。以通用风格示意:
interface Vlanif20 ip address 192.168.20.1 255.255.255.0 dhcp select relay dhcp relay server-ip 192.168.10.100 interface Vlanif30 ip address 192.168.30.1 255.255.255.0 dhcp select relay dhcp relay server-ip 192.168.10.100关键就是两步:把接口的DHCP模式设为relay,然后指定服务器IP。VLAN10接口不用配中继,如果它也要发地址,直接配dhcp select global用本地池即可。
配完之后,用display dhcp relay之类的命令查看中继状态,确认服务器IP配置正确、接口状态up。
5.4 验证与抓包确认
配完别急着说搞定,一定要验证。最直接的办法是在客户端ipconfig /renew(Windows)或dhclient -r && dhclient(Linux),看能不能拿到正确网段的地址。
更靠谱的是抓包。在服务器侧抓,看收到的Discover报文里giaddr是不是对应网段的中继接口IP。如果giaddr是0,说明中继没生效,报文是直接广播过来的(或者根本没经过中继)。如果giaddr对但服务器不回,检查服务器上有没有对应网段的池子。
在客户端侧抓,看有没有收到Offer。如果客户端一直发Discover收不到Offer,问题多半在服务器或中继到服务器的链路上。
6. 常见故障与排查速查
6.1 中继配了但客户端拿不到地址
这是最高频的问题,按下面顺序排查:
| 排查点 | 检查方法 | 常见原因 |
|---|---|---|
| 中继是否生效 | 服务器侧抓包看giaddr | 接口没开relay,或服务器IP配错 |
| 服务器是否有对应池 | 检查配置文件subnet段 | 池子网段和giaddr不匹配 |
| 中继到服务器是否通 | ping测试 | 路由不可达、ACL拦截 |
| 服务器服务是否运行 | 查进程/端口 | 服务没启动、67端口被占 |
| 地址池是否耗尽 | 查租约文件 | 池子太小、租约太长 |
我遇到最多的是第二项——服务器上池子的网段写错了,或者压根没建。因为giaddr是192.168.20.1,服务器就找192.168.20.0/24的池子,你建了个192.168.2.0/24的池子,那肯定对不上。
6.2 部分终端能拿地址,部分不能
这种"部分正常"的情况,通常指向几个方向:
- VLAN配置不一致:某个接入口没划到正确的VLAN,导致报文到了错误的网段。
- 中继接口漏配:多个网段里只配了部分接口的中继。
- Snooping信任端口没设对:某些接入交换机的上行口没设为信任,Offer被丢了。
- 地址池耗尽:某个网段的池子被占满,新终端拿不到。
排查时先确认故障终端在哪个VLAN、对应哪个中继接口,然后针对性检查。
6.3 拿到地址但上不了网
拿到IP不等于网络通。如果客户端拿到了正确网段的地址,但ping不通网关,检查:
- 网关地址是否和客户端同网段
- 中继接口是否up
- 是否有ACL或防火墙拦截
如果网关能通但上不了外网,那是路由或NAT的问题,和DHCP无关了。这时候别在DHCP上浪费时间,直接查路由表。
6.4 地址冲突频发
地址冲突一般是这几种原因:
- 静态配置的设备和动态池范围重叠
- 排除地址没配全,网关被分出去了
- 多台DHCP服务器同时工作,池子重叠
解决办法:把静态设备地址从动态池排除,或者用静态绑定;确保一个网段只有一套DHCP在发地址(或者做HA时池子不重叠)。
提示:Windows下可以用
arp -a看冲突地址的MAC,Linux下用arping探测,快速定位是哪台设备占了地址。
7. 进阶话题与实操心得
7.1 DHCP中继的高可用考虑
单台DHCP服务器挂了,整个网络的新终端都拿不到地址。生产环境要考虑冗余,常见做法有两种:
一是双服务器热备,两台服务器配相同的池子但地址范围错开,比如A服务器发100-150,B服务器发151-200。客户端广播时两台都收到,谁先回用谁的。这种方案简单,但要注意池子不能重叠。
二是服务器集群/故障转移,一些DHCP服务支持主备模式,租约同步,一台挂了另一台接管。配置复杂些,但地址利用率高。
中继侧也可以配多个服务器IP,一个不通自动切另一个。这个在关键网络里很有用。
7.2 租约时间的取舍
租约设多长,是个需要权衡的事:
- 租约太长:地址回收慢,池子容易耗尽,尤其是流动性大的网络(如访客WiFi)。
- 租约太短:续租频繁,增加服务器和网络负担,客户端也可能因为续租失败频繁掉线。
经验值:办公网24小时到3天,访客网2到8小时,服务器/固定设备用静态绑定不走租约。流动性越大的网络,租约越短。
7.3 抓包排障的几个实用技巧
抓DHCP包的时候,过滤条件用port 67 or port 68最直接。看报文时重点关注:
- giaddr:判断是否经过中继、中继接口是哪个
- yiaddr:服务器分配的地址
- Option 53:报文类型(1 Discover、2 Offer、3 Request、5 Ack)
- Option 54:服务器标识
- Option 82:中继插入的信息
如果看到客户端反复发Discover没有Offer,问题在服务器侧或链路上。如果看到Offer但客户端不发Request,可能是客户端问题或收到了多个Offer在纠结。
7.4 我踩过的几个坑
第一个坑是网关地址没排除。有次配池子忘了排除网关,结果网关地址被分给了一台终端,整个网段瞬间瘫痪。后来养成习惯,配池子第一件事就是排除前100个地址。
第二个坑是中继服务器IP配成了服务器所在网段的网关。当时想当然填了192.168.10.1,结果报文发到网关上,网关又不是DHCP服务器,自然没响应。中继要填的是DHCP服务器本身的IP,不是它的网关。
第三个坑是Option 82导致服务器不回包。一台老服务器不支持这个选项,中继默认开了,报文全被丢弃。关掉中继上的Option 82功能后恢复正常。所以遇到"中继配置全对但就是不通",不妨查查Option 82。
第四个坑是Snooping信任端口漏配。接入交换机换了台新的,忘了配信任端口,结果下面所有终端都拿不到地址。这种问题排查起来最费劲,因为中继和服务器都正常,问题出在接入层。
7.5 关于IPv6下的DHCPv6中继
现在不少环境开始上IPv6,DHCPv6的中继逻辑和IPv4类似,但细节有差异。DHCPv6用UDP 546(客户端)和547(服务器/中继),中继通过Relay-Forward和Relay-Reply报文转发。IPv6里没有广播,客户端用组播地址FF02::1:2找服务器,中继同样负责跨网段转发。如果以后要迁移到IPv6,这套中继的思路是通用的,只是报文格式和地址变了。
配置上,DHCPv6中继要指定服务器地址,接口上开relay模式,逻辑和IPv4一致。需要注意的是IPv6的地址池配置更复杂,涉及前缀委派(PD)等概念,那是另一个话题了。
最后分享一个实用习惯:每次配完DHCP和中继,我都会在服务器上开个实时日志,然后让一台测试终端反复renew几次,看日志里有没有对应的请求记录、giaddr对不对、分配是否成功。这个动作花不了两分钟,但能提前发现大部分配置问题,比等用户报障再排查高效得多。网络这东西,配置是一回事,验证是另一回事,两者都做到位,才算真正交付。