Linux 平台 DHCP 运作原理与握手过程详解
概述
- DHCP(Dynamic Host Configuration Protocol)在以太网广播域内为主机自动分配 IPv4 地址及网络参数(子网掩码、默认网关、DNS 等)。
- 客户端使用 UDP
68端口,服务器使用 UDP67端口;初次阶段客户端常以源地址0.0.0.0向广播地址255.255.255.255发送报文。 - Linux 上的 DHCP 客户端为用户态进程(如
dhclient,udhcpc,dhcpcd,systemd-networkd),通过套接字与内核网络栈交互,并最终使用netlink/ioctl配置 IP 地址和路由。
基础概念
- 广播域:DHCP 依赖二层广播,跨网段时需要中继(Relay Agent)。
- 关键字段:
chaddr(客户端 MAC)、ciaddr(客户端当前 IP)、yiaddr(服务器分配的 IP)、giaddr(中继地址)、xid(事务 ID)。 - 重要选项:
- 53(消息类型)
- 50(请求的 IP 地址)
- 54(服务器标识)
- 51(租约时长)
- 1/3/6(子网掩码/默认网关/DNS)
- 15(域名)
- 121(无类静态路由)
- 82(中继代理信息,交换机/中继用于安全审计与策略)
报文与端口
- 客户端端口:
UDP/68;服务器端口:UDP/67。 - 初次阶段无 IP 时:客户端以
0.0.0.0:68→255.255.255.255:67广播发送;服务器响应通常广播回客户端,或在具备条件时单播。 - 续租阶段客户端已有地址:可能单播
REQUEST到服务器的UDP/67(更高效且更少广播)。
标准四步握手(DORA)
- Discover:客户端广播
DHCPDISCOVER,表明需要地址与参数。 - Offer:一个或多个服务器广播/单播
DHCPOFFER,给出候选yiaddr与参数集合;包含Server Identifier(54)。 - Request:客户端选择其一后广播
DHCPREQUEST,指明目标服务器(选项 54)与请求 IP(选项 50);同时向其他服务器隐式拒绝。 - Ack:目标服务器返回
DHCPACK,确认分配并给出完整参数与租约时间(选项 51);若拒绝则返回DHCPNAK。
续租与重绑定(T1/T2)
- 租约时间由服务器设定(选项 51)。客户端维护两个阈值:
- T1:通常为租约的 50%。到达后客户端单播
REQUEST给原服务器续租。 - T2:通常为租约的 87.5%。若 T1 阶段失败,T2 阶段客户端广播
REQUEST,尝试与任意可用服务器重绑定。
- T1:通常为租约的 50%。到达后客户端单播
- 若直到租约到期仍续租失败,客户端应释放地址并回到 Discover 阶段。
地址冲突检测与 ARP 行为
- 一些客户端在获取
DHCPACK后会进行 ARP Probe(如arping -D)以检测地址是否被占用;若冲突,发送DHCPDECLINE给服务器并重新 Discover。 - 成功配置后可能发送 Gratuitous ARP 通告自身地址,便于邻居缓存更新与冲突快速暴露。
Linux 平台常见实现
- dhclient(ISC):传统、功能全面,广泛用于发行版;可通过钩子脚本执行路由/DNS 更新。
- udhcpc(BusyBox):面向嵌入式(如 Ingenic 平台),体积小、启动快;通过
/usr/share/udhcpc/default.script等脚本配置网络。 - dhcpcd:集成度高,支持多特性与自动化配置。
- systemd-networkd:在
*.network中设置DHCP=yes即可自动完成握手与应用网络参数。 - NetworkManager:桌面/服务器常用,统一管理 Wi‑Fi/以太网并调用后端 DHCP 客户端。
握手时序细节(初次获取)
- 客户端创建 UDP 套接字并设置
SO_BROADCAST,绑定0.0.0.0:68。 - 发送
DHCPDISCOVER(L2 广播 MAC ff:ff:ff:ff:ff:ff;L3 广播 255.255.255.255)。 - 服务器接收后选择可用地址,检查租约池/冲突/策略(VLAN、snooping、ACL),生成
DHCPOFFER。 - 客户端可能收到多个 Offer,依据策略(服务器延迟、参数完整性、策略权重)选择一个,随后广播
DHCPREQUEST指定服务器(选项 54)。 - 服务器确认并返回
DHCPACK,含租约时间与参数。若发现冲突/策略不符则DHCPNAK。 - 客户端应用配置(通过
netlink设置ip addr add,ip route add等),更新 DNS(/etc/resolv.conf 或 resolvconf/systemd‑resolved),触发 ARP 通告。
续租与重绑定细节
- T1 阶段:单播
REQUEST给原服务器(ciaddr为当前地址,Server Identifier指向原服务器);成功则延长租约。 - T2 阶段:若原服务器不可达,广播
REQUEST,任何服务器都可ACK续租或重新分配。 - 失败与回退:若
NAK或超时,客户端释放地址并回到 Discover;某些实现会暂时保留旧配置以避免瞬断。
中继与跨网段(Relay Agent)
- 二层广播无法跨三层边界,需 DHCP 中继(例如
dhcrelay)。 - 中继在接收客户端广播后将报文封装并转发到服务器,同时填充
giaddr与可选的Option 82。服务器据此返回响应给中继,再由中继转发回客户端。
多场景行为
- 多网卡:每个接口独立握手与租约;避免同一 MAC 在不同 VLAN 产生冲突。
- VLAN/Bridge:在桥接或 VLAN 接口上进行 DHCP;确保过滤策略(
ebtables/交换机 ACL)允许 67/68 端口流量。 - 虚拟化/容器:容器通常由宿主网络栈分配地址(如 Docker 使用桥接+NAT),容器内部一般不直接运行 DHCP 客户端;但在特定 CNI 或裸容器场景可启用。
安全与网络设备特性
- DHCP Snooping:交换机记录可信端口与租约绑定,防止伪造服务器与地址欺骗。
- Option 82:中继/交换机插入接入信息(端口/VLAN),服务器依据此进行精细策略。
- 过滤与隔离:
iptables/nftables/ebtables需允许UDP/67与UDP/68;不当过滤会导致"无法获取地址"。
调试与排错
- 抓包:
tcpdump -i eth0 -vvv -n port 67 or port 68 - 交互日志:
dhclient -v eth0查看详细过程journalctl -u systemd-networkd或nmcli device show观察状态
- 常见问题:
- 交换机未放通广播或 DHCP Snooping 策略错误→检查接入策略与可信端口。
- 防火墙阻断 67/68→调整
iptables/nftables规则。 - 中继配置错误(
giaddr/Option82)→检查中继路由与服务器策略。 - 多服务器竞争→客户端应选择一个并在 Request 中明确 Server Identifier。
常见 DHCP 消息类型
DHCPDISCOVER:发现DHCPOFFER:提供DHCPREQUEST:请求/续租/重绑定DHCPACK:确认DHCPNAK:否认DHCPDECLINE:地址冲突声明DHCPRELEASE:主动释放DHCPINFORM:客户端已有地址,需要仅获取参数(无分配)
实践建议(Linux)
- 嵌入式/精简系统:优先使用
udhcpc并定制脚本以最小化启动时延与依赖。 - 服务器/桌面:使用
systemd-networkd或 NetworkManager,统一管理并与策略/防火墙集成。 - 配置文件示例(systemd-networkd):
/etc/systemd/network/10-eth0.network中设置:DHCP=yes,可选UseDomains=true,RouteMetric=控制路由优先级。
快速命令参考
- 启动客户端:
sudo dhclient -v eth0 - BusyBox 客户端:
sudo udhcpc -i eth0 -f -v - 抓包:
sudo tcpdump -i eth0 -vvv -n port 67 or port 68 - 冲突检测:
sudo arping -D -I eth0 <ip>
总结
- DHCP 在 Linux 上通过用户态客户端配合内核网络栈,基于 UDP 广播完成 DORA 四步握手,并在租约周期内进行 T1/T2 续租与重绑定。
- 正确的交换机/中继配置、主机防火墙策略与客户端实现选择,是确保可靠地址分配与网络可用性的关键。