DHCP这个协议,几乎所有网络入门教材都会讲,四步交互画得明明白白,考试也爱考"DISCOVER、OFFER、REQUEST、ACK"这几个名字。但我在带新人的时候发现一个挺普遍的现象:能把四个报文名字背下来的人很多,真让他打开抓包软件,从一堆广播帧里把完整的地址分配过程捞出来、逐个字段对上号的人,少得可怜。更麻烦的是,实验环境里DHCP几乎不会出错,一旦上了真实网络,地址池重叠、中继配置漏了、租期设得太短、客户端拿到169.254开头的地址,这些问题的排查全都要回到报文层面去看。
这篇东西就是围绕这个落差写的。前半部分把DHCP的报文结构、字段含义、租期计时机制拆开讲清楚,重点放在教材往往一笔带过的地方,比如REQUEST为什么要广播、T1和T2到底怎么算、giaddr字段在跨网段时起了什么作用;后半部分是完整的抓包实操,从抓包位置怎么选、过滤器怎么写、字段怎么逐条核对,到抓不到包的几种典型原因,都给出来。适合正在备考网络初级认证的朋友,也适合已经上手干活但每次遇到地址分配问题只能靠重启设备碰运气的同行。文中配置以通用思路呈现,关键字按你手头的设备做调整,逻辑是通的。
1. DHCP真正的价值不在"自动配地址",而在把变更成本压下去
1.1 手配IP在小规模下确实没什么毛病
先把话说透:如果一张网里只有五台设备、拓扑三年不动、也没有笔记本进进出出,那手工配静态地址反而是最稳的做法,不用管服务器在不在、不用管租期到期、出了问题一目了然。很多老机房到现在还是这么干的,我不觉得这有什么问题。
DHCP真正开始体现价值,是在"变化"出现之后。设备数量从十台变成两百台,笔记本、手机、打印机、监控摄像头全都要接入,人员流动导致工位和设备对不上号,业务上线要求新网段明天就能用。这时候手工维护一张Excel地址表,出错的概率跟设备数量基本是成正比往上走的。我在一个项目里见过地址表最后三个版本同时在用,谁也说不清哪个是准的,最后是靠全网扫一遍ARP才把冲突理清楚。
所以理解DHCP,第一个要建立的认知是:它是一套集中式的地址租借管理机制,不是简单的"自动填IP"。中心化的地址池意味着地址的分配权收归一处,谁在用、用了多久、什么时候该回收,都有据可查。这才是它在大网络里不可替代的原因。
顺带说一句,DHCP管的不只是IP。网关、DNS服务器、域名后缀、NTP服务器地址、WINS(现在基本没用了),这些参数都可以通过选项字段一起下发。设备多了以后,"改一次DNS要挨个机器点一遍"这种活,靠DHCP一个选项就能全网生效。
1.2 备考阶段为什么要抠到报文级
考试题里DHCP的考法通常比较规矩,问报文顺序、问端口号、问租期百分比。但我觉得如果只按考点来学,会留下一个很大的空洞:你知道有这四个报文,但不知道每个报文里装了什么、为什么这么装。
举个很具体的例子。很多人第一次抓包会疑惑:为什么客户端发出的DISCOVER,源IP是0.0.0.0?这个地址看起来像个错误值,其实是刻意为之——客户端此刻还没有地址,只能用全零作为源地址占位,目的地址用255.255.255.255做本地广播。同理,为什么OFFER有时候是广播、有时候是单播?这就牵扯到Flags字段里的广播标志位,以及客户端实现上的差异。这些细节不看报文是理解不了的。
再比如REQUEST报文,教材上写"客户端广播REQUEST确认",但实际抓包你会发现,续租阶段的REQUEST是单播直接发给原服务器的,源地址就是自己正在用的那个IP。同一类报文,在不同阶段的行为完全不同,这个差别在排查"为什么续租失败"的时候就是关键线索。
我的建议是:备考阶段至少完整抓一次包,把四个报文的每个字段对一遍,做完这一次,后面看任何DHCP相关的文档都不会再有陌生感。
1.3 这个协议的设计里藏着哪些"妥协"
DHCP脱胎于BOOTP,保留了BOOTP的报文格式和67/68端口,这解释了为什么抓包时用bootp过滤器依然能过滤出DHCP报文——本质上是同一套帧格式,DHCP只是把选项字段用起来了。
它的设计里有几处明显的妥协,理解了这些妥协,很多"看起来很奇怪"的行为就说得通了:
| 设计取舍 | 具体表现 | 带来的后果 |
|---|---|---|
| 基于广播起步 | 客户端无地址,只能广播找服务器 | 广播域边界就是DHCP的天然边界,跨网段必须靠中继 |
| 无认证机制 | 任何设备都能应答DHCP请求 | 存在私设服务器的风险,需要额外的防护手段 |
| 靠租期自愈 | 地址不是永久绑定,到期回收 | 租期设置不当会导致频繁续租或地址长期被占 |
| 依赖客户端自觉 | 客户端发现冲突后要主动发DECLINE | 客户端实现不规范时,冲突地址会被反复下发 |
最后一条尤其值得注意。DHCP服务器本身并不做冲突检测(部分实现可以配ping探测,但有延迟和漏判),它默认地址池里是干净的。真正发现冲突的是客户端——拿到地址后做一次ARP探测,发现有别人应答,就发DECLINE告诉服务器这个地址别用了。这套机制能不能生效,完全取决于客户端实现。
2. 四个报文只是骨架,字段和选项才是血肉
2.1 DISCOVER:一个"我什么都不知道"的广播
抓到的第一个包通常是这样的:源0.0.0.0,目的255.255.255.255,UDP,源端口68,目的端口67。帧层面目的MAC是全F广播。这就是DISCOVER。
这个报文里的信息量其实很少,但有几个字段值得看:
- Transaction ID(xid):一个随机数,后续三个报文都会带着同一个值。这是把一次交互的四个包串起来的唯一线索,抓包时用它做过滤非常有效,
bootp.id == 0x开头的那串就能锁定一次完整会话。 - Flags:16位,最高位是广播标志位。置1表示"我还没配好IP栈,请用广播回我"。有些客户端(尤其是早期的嵌入式设备、部分PXE引导场景)必须靠广播才能收到回应。
- chaddr:客户端MAC地址,六字节。服务器分配地址、做静态绑定,靠的就是这个字段。
- Option 53:消息类型,DISCOVER对应值1。这是区分四个报文最直接的方式。
- Option 55(Parameter Request List):客户端在这里列出"我想要哪些参数",比如子网掩码(1)、路由器(3)、DNS(6)、域名(15)、NTP(42)。服务器会尽量按这个清单来组织OFFER的内容。这个字段挺有意思,不同操作系统的请求列表差别很大,抓包时靠它猜客户端是什么系统,准确率不低。
- Option 61(Client Identifier):有些客户端会带,通常是类型+MAC,作用是让服务器在MAC变化(比如虚拟机迁移)时仍能识别同一台客户端。
- Option 12(Hostname):客户端主机名,配了的话服务器日志里能看到是谁来的。
2.2 OFFER:地址池往外掏东西的那一刻
服务器收到DISCOVER后,从地址池里挑一个可用地址,回OFFER。源地址是服务器自己的IP,源端口67,目的端口68。目的地址是广播还是单播,取决于DISCOVER里的Flags位和服务器实现。
OFFER里最关键的是yiaddr字段——"your IP address",也就是服务器打算给你的地址。另外几个字段也值得看:
- siaddr:下一个服务器地址,主要在PXE网络引导场景里用,普通地址分配时一般是0。
- Option 54(Server Identifier):服务器自己的IP。这个字段非常重要,因为一个网段里可能有多台DHCP服务器,客户端要靠它区分是谁给的OFFER。
- Option 51(IP Address Lease Time):租期,单位秒。比如86400就是一天。
- Option 58(Renewal Time Value,T1)和Option 59(Rebinding Time Value,T2):这两个是可选的,服务器不给的话客户端按租期的50%和87.5%自己算。
- Option 3(Router):网关地址,可以有多个。
- Option 6(DNS):DNS服务器列表。
这里有个实操经验:如果你在抓包时发现OFFER给了地址,但客户端拿到后上不了网,先看OFFER里有没有Option 3和Option 6。有些服务器配置只写了地址池范围,忘了配网关和DNS,客户端确实能拿到IP,但路由和解析全是空的,表现为"能ping通网关但打不开网页"或者干脆什么都通不了。
2.3 REQUEST:为什么它要"喊"给所有人听
这是四个报文里最容易让人困惑的一个。客户端已经收到了OFFER,明明可以直接单播回复那台服务器,为什么还要广播?
原因是:客户端可能收到了多个OFFER。一个网段里如果存在两台DHCP服务器(不管是刻意做的冗余还是有人私接),客户端会收到两份OFFER。它只能选一个,但其他服务器并不知道自己落选了,还占着一个地址等着。所以客户端用广播的方式发REQUEST,并在里面带两个关键字段:
- Option 50(Requested IP Address):我想要的是这个地址。
- Option 54(Server Identifier):我是向这台服务器要的。
广播出去之后,被选中的服务器回ACK,没被选中的服务器看到Option 54不是自己,就把刚才预留的地址收回池子。这个设计用一次广播解决了"多方竞争下的资源释放"问题,挺巧妙的。
续租阶段的REQUEST就完全不同了:此时客户端已经有地址,直接用单播发给原来的服务器,源地址是自己的IP,目的地址是服务器IP,报文里通常不带Option 54(因为它就是发给原来那台的)。这个差别在抓包里一眼就能看出来,也是判断"这台机器是在初次获取还是在续租"的依据。
2.4 ACK之后,计时器才开始真正运转
ACK是服务器对REQUEST的确认,里面包含最终的地址、租期和各项参数。客户端收到ACK后,做几件事:把地址配到网卡上、按Option 3配默认路由、按Option 6配DNS、启动三个计时器。
这三个计时器是很多人记不住的地方,其实逻辑很直白:
| 计时器 | 触发时间 | 客户端动作 | 报文形式 |
|---|---|---|---|
| T1 续租计时器 | 租期的50% | 向原服务器单播REQUEST请求续租 | 单播 |
| T2 重绑定计时器 | 租期的87.5% | 广播REQUEST,向任意服务器请求 | 广播 |
| 租期到期 | 100% | 放弃地址,重新走DISCOVER流程 | 广播 |
假设租期是86400秒(一天),那么T1在43200秒(12小时)触发,T2在75600秒(21小时)触发。如果T1时刻服务器没回应(比如服务器宕机或者网络不通),客户端会一直重试到T2,然后转为广播找其他服务器。T2之后还是没回应,到租期结束就只能放弃地址,此时网卡上的地址会被清掉,业务中断。
这里有个经常被忽略的点:租期设得太短,续租流量会明显增加。假设你有500台设备,租期设成2小时,那平均每分钟就有4台多在发续租请求,虽然流量不大,但DHCP服务器的日志会被刷得很满,排查问题的时候很难找。反过来租期设得太长(比如30天),地址回收不及时,临时设备走了地址还占着,池子容易被耗尽。办公网一般设1到8天比较合适,访客网络可以设几小时。
3. 地址池怎么划:几个必须想清楚的问题
3.1 地址池的边界要和网关、网段对齐
配地址池第一件事是想清楚这段地址属于哪个网段、网关是谁。地址池的network必须和网关所在网段一致,否则服务器分配出去的地址客户端根本用不了。
假设网段是192.168.10.0/24,网关是192.168.10.1,那么地址池大概长这样:
# 通用配置思路,关键字按设备厂商做调整 ip pool office-pool network 192.168.10.0 mask 255.255.255.0 gateway-list 192.168.10.1 dns-list 223.5.5.5 119.29.29.29 excluded-ip-address 192.168.10.1 192.168.10.2 excluded-ip-address 192.168.10.100 192.168.10.120 lease day 3 hour 0然后在网关接口上启用全局地址池模式:
interface Vlanif10 ip address 192.168.10.1 255.255.255.0 dhcp select global注意最后一行,很多初学者配完地址池忘了在接口上启用,结果客户端一直拿不到地址,抓包只能看到DISCOVER反复发,一个OFFER都没有。这个坑我见过太多次,排查的时候第一件事就是看接口上有没有启用DHCP。
3.2 排除地址留多少,怎么留
地址池里必须排除掉几类地址:
- 网关地址本身:
192.168.10.1,不能分给客户端,否则网关和客户端抢地址。 - 服务器、打印机、监控NVR这类固定设备:它们用静态地址,必须排除,否则DHCP可能把同一个地址分给别的设备造成冲突。
- 网络地址和广播地址:
.0和.255,正常配置下服务器不会分配,但排除掉更保险。 - 预留区:给未来扩容或者临时设备留一段。
留多少?我的经验是按网段规模的10%到20%来留。24位掩码的网段有254个可用地址,排除20个左右比较合理。如果这个网段里固定设备特别多(比如机房、监控专网),排除比例要更高,有时候能到40%。
还有个细节:如果做了多台DHCP服务器做冗余,两台服务器的地址池要错开,不能重叠。比如A服务器管100-150,B服务器管151-200,公共部分用排除地址处理。重叠的地址池会导致同一地址被两台服务器同时认为可用,冲突概率极高。
3.3 租期长短背后的计算
租期这个参数,很多人是随手填的。其实可以简单算一下。
假设某办公网有300台设备,租期设为8小时。按最坏情况估算,每台设备每天至少续租一次(实际上设备开关机会重新走流程,续租次数会更多),那么DHCP服务器每天要处理的交互大概在600次以上,平均每分钟不到一次,压力可以忽略。
如果租期设为30分钟,300台设备每15分钟续租一次,每天就是28800次交互,平均每分钟20次,虽然服务器扛得住,但日志量会暴涨,而且一旦服务器有一分钟不可用,就会有大批设备进入重绑定状态。
我的取值习惯是:
- 固定办公终端:3到7天
- 笔记本、移动设备用的无线网络:8到24小时(人员流动大,地址要及时回收)
- 访客网络:2到4小时(用短租期控制池子占用)
- 会议室、培训室这类集中接入区域:1到2小时
3.4 静态绑定怎么做,什么场景用
有些设备确实需要固定地址,但又不想在设备上手工配(比如网络打印机、摄像头,配置界面难用)。这时候用DHCP静态绑定,把MAC和IP对应起来,走DHCP流程但每次拿到的都是同一个地址。
ip pool office-pool static-bind ip-address 192.168.10.50 mac-address 00e0-fc12-3456静态绑定的地址会自动从动态池里排除,不用重复配置excluded。
什么场景用静态绑定?我的判断标准是:设备本身没有配置界面,或者配置界面极其难用,但地址又必须固定。如果设备能方便地配静态地址,我倾向于直接在设备上配,少一层依赖——DHCP服务器挂了,静态配的设备照样能用。
4. 抓包这件事,位置选错后面全白搭
4.1 抓包点怎么选
DHCP是广播起家的协议,这意味着抓包位置非常关键。可选的位置有几个:
- 客户端本机抓:最直接,能拿到客户端视角的完整交互,但要注意抓包软件本身要占用网卡,而且如果客户端是嵌入式设备就没法抓。
- 接入交换机上做端口镜像:把客户端所在端口镜像到抓包口,适合客户端不方便装软件的场合。注意镜像要配双向,只镜像入方向会漏掉服务器的回应。
- 网关接口上抓:如果是跨网段场景,DHCP报文会经过网关,在这里抓能看到中继处理后的报文,能看到giaddr字段被填充的过程。
- 服务器本机抓:能看到服务器视角的所有请求,但过滤起来比较麻烦,因为一个服务器可能服务多个网段。
我一般优先选客户端本机或者接入交换机镜像。原因很实在:DHCP问题十有八九出在客户端到服务器这段路径上,服务器本身反而是最稳的一环。
4.2 过滤器怎么写才不漏
Wireshark里过滤DHCP有几种写法,各有适用场景:
# 最宽松,老版本Wireshark用这个能抓到DHCP bootp # 新版本支持直接写dhcp dhcp # 按端口过滤,能同时抓到客户端和服务端视角 udp.port == 67 || udp.port == 68 # 只看某个客户端 bootp.hw.mac_addr == 00:e0:fc:12:34:56 # 按事务ID锁定一次完整交互 bootp.id == 0x3d1e0a2b # 只看某个类型的报文,53号选项值为1是DISCOVER bootp.option.dhcp == 1几个经验点:
不要上来就写很复杂的过滤器。先开bootp看全貌,确认报文确实存在,再逐步收窄。我见过有人一开始就写了个超长的过滤表达式,结果什么都没抓到,折腾半天发现是表达式把报文过滤掉了。
如果一张网里活跃客户端很多,广播帧会刷屏。这时候用bootp.option.dhcp按消息类型过滤,或者干脆先用bootp.hw.mac_addr锁定你要查的那台设备的MAC。设备的MAC地址从哪来?让用户报一下,或者从交换机MAC地址表里查。
还有一个隐蔽的坑:某些版本的Wireshark对DHCPv6和DHCPv4的过滤器是分开的,写dhcp可能只匹配v4。如果抓不到包,试着换成bootp,因为是同一个底层协议。
4.3 四个报文逐个字段核对清单
抓到包之后,我习惯按下面这个清单走一遍,基本能覆盖90%的问题:
| 报文 | 要核对的字段 | 异常表现说明什么 |
|---|---|---|
| DISCOVER | 源IP、目的IP、xid、Option 55 | 源IP不是0.0.0.0说明客户端已有地址,可能在续租 |
| OFFER | yiaddr、Option 51、Option 54、Option 3、Option 6 | yiaddr为0说明池子耗尽;缺Option 3/6说明配置漏了 |
| REQUEST | Option 50、Option 54、目的地址 | 没有Option 54通常是续租;有则是初次获取 |
| ACK | yiaddr、Option 51、Option 58、Option 59 | 与OFFER不一致说明服务器配置有变或存在多台服务器 |
再补一条:看时间戳。正常情况下四个报文之间的间隔在毫秒级,如果看到DISCOVER和OFFER之间隔了好几秒,说明网络有延迟或者服务器负载高。如果看到DISCOVER重复发了好几次才有OFFER,说明中间有丢包或者服务器响应不过来。这个时间维度是很多人抓包时忽略的。
4.4 抓不到包的五种典型原因
排查"抓不到包"比分析报文更考验经验,我按遇到频率排个序:
第一种,抓包位置不对。在错误的接口上抓,或者镜像口只配了单向。这个最常见,解决办法是先在网关接口上抓一次,确认报文确实存在,再往客户端方向找。
第二种,过滤表达式写错。比如把bootp写成bootps,或者用了新版本才支持的语法在老版本上跑。把过滤器清空再看一遍,是最快的验证方法。
第三种,客户端压根没发DHCP请求。有些设备配置了静态地址,或者网卡被禁用,或者DHCP客户端服务没启动。这时候抓包一片安静,看起来像"网络问题",实际上是设备行为问题。让用户确认一下网卡状态。
第四种,报文被中间设备拦了。接入交换机上如果启用了DHCP Snooping但没配信任端口,来自服务器的OFFER会被丢弃。这个现象很典型:客户端一直发DISCOVER,服务器日志显示正常回应了,但客户端收不到。抓包位置如果在客户端侧,就只能看到DISCOVER,看不到OFFER。
第五种,虚拟化环境的特殊性。虚拟机里的抓包有时受虚拟交换机影响,抓不到广播帧。这种情况下要么在宿主机上抓,要么在物理交换机上做镜像。
4.5 一个完整案例的排查链路
说个我印象很深的场景。某办公区反馈"部分电脑开机后半小时上不了网,重启就好"。听起来像随机故障,实际上有规律。
第一步,在出问题的电脑上抓包。发现完整走完了DISCOVER、OFFER、REQUEST、ACK,地址也拿到了。看起来正常。
第二步,看ACK里的租期。租期只有1800秒,也就是半小时。这就跟"半小时上不了网"对上了。
第三步,看续租过程。发现T1时刻(15分钟)的续租REQUEST发出去了,但没有ACK回应。客户端一直重试到T2,改成广播,还是没有回应。
第四步,去服务器侧抓包。发现服务器压根没收到续租请求。问题定位到路径上。
第五步,查中间设备。发现客户端和服务器之间跨了一个网段,中间有台设备做了地址转换,续租的单播报文目的地址是服务器IP,但转换表里没有对应条目,包被丢了。
结论是:初次获取时用的是广播,能穿过;续租用单播,被转换设备挡了。解决方案是调整转换策略,或者把DHCP服务器挪到本地网段。
这个案例说明一件事:初次获取正常不代表DHCP没问题,续租路径是独立的,必须单独验证。
5. 跨网段场景下,中继到底做了什么
5.1 广播过不了路由器,这是硬限制
DHCP的起点是广播,而路由器默认不转发广播。这就意味着如果一个网段里没有DHCP服务器,客户端喊破嗓子也没人应。
解决办法是DHCP中继。中继设备部署在客户端所在网段的网关上,它监听67端口,收到客户端的广播后,把报文重新封装成单播,发给远端配置好的DHCP服务器。服务器回应的报文再经由中继转回给客户端。
整个过程中,客户端完全感知不到中继的存在——它仍然以为自己是在跟本地服务器对话。这种透明性靠的就是giaddr字段。
5.2 giaddr字段:服务器判断"该给哪个池"的依据
中继转发请求时,会把收到请求的那个接口的IP填到giaddr(Gateway IP Address)字段里。服务器收到后,看giaddr的值,判断这个请求来自哪个网段,然后从对应的地址池里分配地址。
这个机制非常关键。如果giaddr填错了(比如中继配置了错误的接口或者地址),服务器就会从错误的池里分配地址,客户端拿到的地址根本不在自己网段,自然用不了。
配置大概是这个思路:
# 在客户端侧网关接口上启用中继,指向DHCP服务器地址 interface Vlanif20 ip address 192.168.20.1 255.255.255.0 dhcp select relay dhcp relay server-ip 10.1.1.100服务器侧则要配置对应192.168.20.0/24的地址池,并且保证到中继地址有路由可达。
一个容易忽略的点:服务器回包的目的地址是giaddr,不是客户端的MAC。这意味着服务器到中继之间的路由必须通。如果服务器配置了到客户端网段的路由但漏了到中继接口地址的路由,回包发不出去,客户端就永远收不到OFFER。
5.3 中继环境下的抓包差异
跨网段场景下抓包,看到的东西跟同网段不一样:
- 客户端侧抓到的DISCOVER还是
0.0.0.0到255.255.255.255。 - 中继侧转发的报文,源地址变成中继接口IP,目的地址是服务器IP,giaddr字段被填充。
- 服务器回应的OFFER,目的地址是giaddr,也就是中继的地址。
- 中继再把OFFER转给客户端,此时的报文形式取决于Flags位。
如果你在中继设备上抓包,会看到两套报文:一套是广播进来的,一套是单播转出去的。这两套的xid是相同的,靠这个能对应起来。
5.4 几个容易翻车的地方
中继地址和地址池对不上。这是最常见的配置错误。客户端在192.168.20.0/24,中继接口配了192.168.20.1,但服务器上没有对应这个网段的地址池,或者池子写成了192.168.2.0。表现是客户端一直发DISCOVER,服务器日志里有请求但拒绝分配,或者根本不回应。
多台中继指向同一台服务器,地址池没区分。服务器靠giaddr区分网段,如果两台中继的giaddr恰好落在同一个池的范围里,就会从同一个池分配地址,客户端拿到跨网段地址,用不了。
中继服务器组配置了多个地址,主用挂了没切过去。冗余配置要验证,不能只配不测。测试方法很简单,把主服务器接口关掉,看客户端能不能从备用服务器拿到地址。
Option 82的处理。部分中继会在报文里插入Option 82(Relay Agent Information),携带接入端口信息。有些服务器不认识这个选项会直接丢弃报文,表现为"中继配了但就是不生效"。这时候要么在服务器上开启对Option 82的支持,要么在中继上关掉这个功能。
6. 那些文档里不会写的坑
6.1 地址冲突为什么会出现,DECLINE起了什么作用
DHCP服务器分配地址时是不做冲突检测的(可以配ping探测,但会增加延迟,而且很多场景下不启用)。它只保证"这个地址当前没有被自己分配出去",但如果有设备手工配了一个池子里的地址,服务器是不知道的。
这时候客户端的作用就体现出来了。规范要求客户端在收到ACK后做一次ARP探测,如果发现这个地址已经有人应答,就发DECLINE报文告诉服务器"这个地址有问题"。服务器收到DECLINE后会把地址标记为不可用,通常隔离一段时间不再分配。
但这里有个现实问题:不是所有客户端都规范实现了DECLINE。有些嵌入式设备、部分老系统压根不做ARP探测,拿到冲突地址就直接用,结果就是间歇性的网络异常——有时候通有时候不通,排查起来极其难受。
我的做法是:如果发现某个网段频繁出现冲突,先查是不是有人手工配了池子里的地址。方法很简单,在网关上抓ARP,把应答的IP和MAC列出来,跟DHCP服务器的分配记录对一遍,对不上的就是手工配的。
6.2 NAK什么时候出现,出现了说明什么
NAK是服务器对REQUEST的拒绝。出现NAK通常有三种情况:
第一种,客户端请求的地址已经不在服务器的池子里了(比如池子被改小了,或者地址被排除掉了)。客户端重启后还记着上次的地址,发REQUEST想续用,服务器一看这个地址不归我管了,回NAK。
第二种,客户端换网段了。笔记本从办公室拿到192.168.10.x的地址,合上盖子到会议室(192.168.20.0/24),醒来后还在续租原来的地址。中继把这个请求转给服务器,服务器发现giaddr是20网段但请求的是10网段的地址,回NAK。客户端收到NAK后立刻放弃地址重新走DISCOVER。
第三种,地址已经被分配给别的设备了。这种情况一般发生在服务器重启后状态丢失,或者多台服务器之间没有同步。
看到NAK不用慌,它本身是个正常机制,客户端收到后重新获取就行。但如果NAK出现得很频繁,说明租期设置或者网络切换策略有问题,值得优化。
6.3 私设DHCP服务器怎么发现
这是运维里比较头疼的问题。有人在办公网里插了个家用路由器,LAN口接上网线,路由器的DHCP功能没关,开始给周围设备发地址。表现是部分设备突然拿到192.168.1.x或者192.168.x.x的地址,网关指向一个陌生的IP,上不了网。
发现方法有几个:
最直接的是抓包看OFFER的源地址。如果你的网络里只有一台合法服务器是10.1.1.100,抓包看到OFFER来自192.168.1.1,那就锁定问题了。这时候看这个OFFER是从哪个交换机端口进来的,通过MAC地址表就能定位到物理端口。
预防手段是在接入交换机上启用DHCP Snooping,把连接合法服务器的端口设为信任端口,其他端口收到的OFFER直接丢弃。这个功能配置起来不复杂,但要注意两点:信任端口一定要配对,否则合法的OFFER也会被丢;另外如果网络里有中继,中继的上行端口也要设为信任。
6.4 无线环境下的特殊表现
无线网络里DHCP的表现和有线不太一样,值得单独说。
终端在AP之间漫游时,如果跨了三层网段,会重新走一遍DHCP流程。这个过程通常在几百毫秒内完成,用户感知不到。但如果DHCP服务器响应慢,或者中继配置有问题,漫游时就会出现明显的断网,表现为"走着走着网断了,等一会儿又好了"。
另一个常见问题是地址池耗尽。无线网络的地址池消耗速度比有线快得多,因为手机、平板、笔记本加起来人均两三台设备很常见。一个能坐50人的会议室,如果按50个地址配池子,肯定不够用。我一般按人数的2到3倍来配,租期设短一点(2到4小时),保证离场后地址能快速回收。
还有一种情况是终端休眠后唤醒,续租失败。移动设备为了省电,休眠时会断开无线,唤醒后网卡可能还在用旧的地址信息发续租请求,而此时AP已经把它踢下线了。这种问题的表现是"手机锁屏一会儿再打开,要等十几秒才能上网",抓包能看到续租请求发出去没回应,然后重新走DISCOVER。解决办法一般是缩短租期配合终端的快速重连机制,或者干脆接受这个延迟——它其实是终端省电策略的一部分。
6.5 抓包文件怎么保存和复盘
最后说个实操细节。抓包的时候建议直接保存成pcap文件,不要只看着实时界面。原因是DHCP的问题往往要跨时间对比,比如"昨天好的今天不行",有历史抓包文件才能对比出租期、地址池、服务器地址有没有变。
Wireshark保存的时候注意几个设置:抓包缓冲区设大一点,防止高速流量下丢包;抓包文件按大小或者时间自动切分,避免单文件过大打不开;文件名带上时间戳和位置标识,方便后面找。
复盘的时候,用Statistics > Flow Graph能看到交互的时序图,比逐个点报文直观得多。不过要注意这个功能对UDP广播的展示可能不够准确,我一般还是看报文列表配合时间列。
一个我常用的技巧:把bootp.time或者帧编号加到列里,按时间排序,然后对照客户端的开机时间,就能算出从发第一个DISCOVER到拿到地址用了多久。正常情况下这个值应该在100毫秒以内,如果超过1秒,说明中间有重传或者服务器响应慢,值得深挖。