DHCP 服务

本文合并自:09-DHCP服务.md、1-9-DHCP服务部署.md、01-NFS与DHCP服务器.md(仅 DHCP 部分)

适用环境:RHEL 5 / RHEL 6 / CentOS 6 / CentOS 7 及其衍生版本。凡涉及 CentOS 6 与 CentOS 7 命令差异之处(service 与 systemctl、iptables 与 firewalld),均并列给出并标注适用版本。

本文的 NFS / autofs 相关内容已归入 09-02-NFS与autofs.md,此处不再重复。

本章要点

  • 理解 OSI 七层模型与 TCP/IP 四层模型,明确 DHCP 在应用层的位置。
  • 理解静态地址分配与动态地址分配的取舍,掌握 DHCP 动态分配 IP、提高地址利用率的原理。
  • 掌握 DHCP 全部报文类型与首次租约获取的四步交互过程,理解租约续订(T1/T2)机制。
  • 掌握 dhcpd 的安装、主配置文件 /etc/dhcp/dhcpd.conf 的结构与全部常用参数。
  • 能够为单个局域网分配 IP 地址,也能在一台服务器上配置多个子网为多个局域网分配 IP 地址。
  • 能够为指定 MAC 地址绑定固定 IP,能够部署 DHCP 中继,能够与 PXE 网络装机配合。
  • 掌握租约文件、日志、抓包等验证与排错手段。

一、DHCP 概述与原理

1.1 DHCP 在网络分层模型中的位置

TCP/IP 是互联网(Internet)的基础协议栈。DHCP 属于应用层协议,承载在传输层的 UDP 之上。

完整的 OSI 七层模型:

层次 名称 主要作用 数据单位 典型设备/协议
7 应用层(Application) 为终端应用程序提供服务,直接面向用户 数据/报文 DHCP、HTTP、FTP、DNS、NFS
6 表示层(Presentation) 对数据进行解释、加密与解密、压缩与解压缩 数据 SSL/TLS、JPEG、ASCII
5 会话层(Session) 通过传输层建立数据传输通路,发起或接收会话请求,建立、管理、终止会话 数据 RPC、NetBIOS
4 传输层(Transport) 定义数据传输协议和端口号,对数据分段并在到达后重组 段(Segment) TCP、UDP
3 网络层(Network) 对数据进行 IP 地址的封装与解封装,路由选择 数据包(Packet) 路由器、IP、ICMP
2 数据链路层(Data Link) 对数据进行 MAC 地址(网卡地址)的封装与解封装 帧(Frame) 交换机、以太网、PPP
1 物理层(Physical) 定义物理设备标准,将数据编码为 0、1 比特流通过物理介质传输 比特(Bit) 网线、光纤、集线器、Wi-Fi

实际工作中常用的 TCP/IP 四层模型:

层次 名称 典型协议/技术
4 应用层(Application) DHCP、HTTP、FTP、DNS、NFS
3 传输层(Transport) TCP、UDP
2 互联网层(Internet) IP
1 物理层(Physical) Wi-Fi、802.11g/b/n

1.2 静态地址分配与动态地址分配的取舍

两台连接到互联网的电脑要相互通信,必须各自拥有 IP 地址。地址的下发方式有两种:

方式 做法 优点 缺点 适用场景
静态分配(手工配置) 管理员逐台在网卡配置文件中写死 IP、掩码、网关、DNS 地址固定、便于访问控制与审计、不依赖额外服务 工作量大、易配错、易冲突;即使主机不上网地址也被独占,浪费地址 服务器、网关、打印机、监控设备等需要固定地址的设备
动态分配(DHCP) 由 DHCP 服务器集中管理地址池,客户端上线时自动获取 集中管理、零配置接入、地址回收复用、参数(网关/DNS)可统一变更 依赖 DHCP 服务,服务故障则新客户端无法上网;地址可能变化,不利于按 IP 做访问控制 办公终端、笔记本、手机、教室与会议室、无线网络、大规模装机

由于 IPv4 地址资源有限,宽带接入运营商或企业网络无法为每个终端都分配一个长期独占的固定 IP(固定 IP 即使用户不上网别人也不能使用,该资源一直被独占),因此普遍采用 DHCP 方式对上网用户进行临时地址分配:

  • 电脑连上网时,DHCP 服务器从地址池中临时分配一个 IP 地址;
  • 每次上网分配到的 IP 地址可能不同,取决于当时的 IP 地址资源情况;
  • 用户下线、租约到期后,DHCP 服务器可将该地址分配给之后上线的其他电脑。

这样可以有效节约 IP 地址,既保证网络通信,又提高 IP 地址使用率。

1.3 DHCP 的作用与适用场景

DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)由服务器控制一段 IP 地址范围,客户机登录服务器时可自动获得服务器分配的网络参数。DHCP 可下发的内容包括:

  • IP 地址与子网掩码;
  • 默认网关(路由器);
  • DNS 服务器与搜索域(domain-name);
  • 广播地址;
  • 租约时间;
  • NTP 服务器、WINS 服务器等其他可选项;
  • PXE 网络引导所需的 next-server(TFTP 服务器)与 filename(引导文件名);
  • 在 DNS 支持(DDNS)的情况下,还可以分配主机名。

提示:主机名分配只能做简单分配,不能做严格绑定。实际生产环境中不建议依赖 DHCP 分配主机名,可考虑 puppet、ansible 等配置管理工具统一管理主机名。

典型适用场景:

  • 办公局域网、校园网、教室机房的终端自动接入;
  • 无线网络(Wi-Fi)客户端接入;
  • 虚拟化平台中大量临时虚拟机的地址下发;
  • PXE 无人值守批量装机(与 TFTP、kickstart/Cobbler 配合);
  • 需要统一变更网关或 DNS 的网络(只改服务端,客户端续约后自动生效)。

不适用/需谨慎的场景:

  • DHCP 服务器自身、网关、DNS 服务器等基础设施必须使用静态 IP,不能依赖自己给自己分配地址;
  • 需要按 IP 做严格访问控制或端口映射的服务器,应使用静态地址或 DHCP 固定地址保留(MAC 绑定)。

1.4 DHCP 使用的端口与广播机制

端口 协议 使用方 说明
67 UDP 服务器(dhcpd)监听 客户端把请求发往服务器的 67 端口
68 UDP 客户端(dhclient)监听 服务器把应答发往客户端的 68 端口

工作机制要点:

  • 客户端初始状态下没有 IP 地址,也不知道服务器在哪里,因此只能以广播方式通信:源地址 0.0.0.0、目的地址 255.255.255.255。
  • 由于依赖广播,DHCP 的作用范围默认被限制在同一个广播域(同一个二层网络/VLAN)之内;跨网段必须借助 DHCP 中继。
  • 客户端在报文中携带自己的 MAC 地址作为身份标识(chaddr 字段),服务器据此识别客户端并记录租约。
  • 广播特性也带来风险:同一广播域内若存在多台 DHCP 服务器(例如私接的家用路由器),客户端会接受最先收到的 Offer,从而可能拿到错误网段的地址。

1.5 DHCP 报文类型

报文 方向 作用
DHCP DISCOVER 客户端 → 广播 客户端上线,广播寻找网络中可用的 DHCP 服务器
DHCP OFFER 服务器 → 客户端 服务器响应 DISCOVER,从地址池中挑选一个可用 IP 及相关参数提供给客户端
DHCP REQUEST 客户端 → 广播 客户端从(可能多个)Offer 中选定一个,广播声明正式请求使用该 IP;续约时也使用该报文(单播给原服务器)
DHCP ACK 服务器 → 客户端 服务器确认分配,客户端正式获得地址,租约生效
DHCP NAK 服务器 → 客户端 服务器拒绝客户端的请求(例如客户端请求的地址已不可用、已不属于本网段、租约已失效),客户端收到后必须重新从 DISCOVER 开始
DHCP DECLINE 客户端 → 服务器 客户端通过 ARP 探测发现分配到的地址已被他人占用(地址冲突),通知服务器该地址不可用,随后重新申请
DHCP RELEASE 客户端 → 服务器 客户端主动释放地址(如关机、执行 dhclient -r、ipconfig /release),服务器收回该地址
DHCP INFORM 客户端 → 服务器 客户端已有静态 IP,只想向服务器索取其他配置参数(网关、DNS 等)

1.6 首次租约获取的四步交互过程

首次获取地址是经典的"四次交互"(也常被称为四次握手):

  1. DHCP DISCOVER:客户端在局域网中广播 Discover 包(源 0.0.0.0:68 → 目的 255.255.255.255:67),寻找 DHCP 服务器。
  2. DHCP OFFER:DHCP 服务器收到广播后,从地址池中选出一个可用 IP,回应 Offer 包,提供 IP 与网关、掩码、DNS、租期等参数。
  3. DHCP REQUEST:客户端可能收到多个服务器的 Offer,通常接受最先到达的一个,然后广播 Request 包,正式声明请求使用该 IP(广播的目的是同时告知其他服务器"我不用你们提供的地址了")。
  4. DHCP ACK:被选中的服务器回应 Ack 包,确认分配并写入租约文件;客户端进行 ARP 冲突检测,无冲突则正式启用该地址与全部参数。
Client                         DHCP Server
  |------ DHCP DISCOVER ----->|   广播:我需要一个 IP
  |<----- DHCP OFFER ---------|   我可以给你 x.x.x.x
  |------ DHCP REQUEST ------>|   广播:我确认要用 x.x.x.x
  |<----- DHCP ACK -----------|   确认,租期 N 秒,参数如下

若客户端在 ARP 检测中发现地址冲突,则发送 DECLINE 并重新开始;若服务器认为请求不合法,则回应 NAK,客户端也重新开始。

1.7 租约续订与重绑定(T1 / T2)

DHCP 分配的地址是有租期(lease time)的。客户端不会等到租约到期才行动,而是在租期内的两个时间点尝试续约:

时间点 名称 占租期比例 客户端行为
T1 续订(Renewing)计时器 租期的 50% 以单播方式向原 DHCP 服务器发送 REQUEST 请求续租。收到 ACK 则租期重新计时(回到 0);收不到则继续使用地址,等待 T2
T2 重绑定(Rebinding)计时器 租期的 87.5%(7/8) 原服务器仍无响应,客户端改为广播 REQUEST,向网络中任意 DHCP 服务器请求续租
100% 租约到期(Expire) 租期的 100% 仍无任何服务器响应,客户端放弃该地址,停用网络配置,回到 DISCOVER 阶段重新申请(Windows 会退化为 169.254.x.x 的 APIPA 地址)

举例:default-lease-time 600;(600 秒 = 10 分钟)时,T1 ≈ 第 300 秒发起单播续租,T2 ≈ 第 525 秒发起广播续租,第 600 秒租约失效。

生产环境中租期设置的取舍:租期过短会增加服务器负载与广播流量;租期过长则地址回收慢,客户端流动性大的场景(如会议室、无线网络)容易出现地址池耗尽。办公网络常用 8 小时至 1 天,公共无线常用 1~2 小时。

1.8 DHCP 中继(DHCP Relay)的作用

DHCP 依赖广播,而广播不能跨越路由器。当客户端与 DHCP 服务器不在同一个网段(广播域)时,客户端的 DISCOVER 报文无法到达服务器。

DHCP 中继代理(dhcrelay) 用于解决这一问题:

  • 中继代理部署在客户端所在网段(通常是三层交换机、路由器,或一台多网卡的 Linux 主机);
  • 它侦听本网段的 DHCP 广播请求,将其转换为单播转发给指定的 DHCP 服务器,并在报文的 giaddr 字段中填入自己接收该请求的接口地址;
  • DHCP 服务器根据 giaddr 判断请求来自哪个网段,从对应的 subnet 声明中挑选地址;
  • 服务器的应答先发回中继代理,再由中继代理转发(广播)给客户端。

这样,一台 DHCP 服务器即可为整个企业网中多个网段集中提供地址服务,无需在每个网段各放一台 DHCP 服务器。具体部署方法见第四章。


二、安装与配置

2.1 安装 dhcp 软件包

RHEL / CentOS 系列:

# CentOS 6 / CentOS 7:软件包名为 dhcp
yum install dhcp -y

# 也可用通配符一次装齐相关包(含 dhclient、dhcp-common 等)
yum install dhcp* -y

# CentOS 8 / RHEL 8 及以上:服务端包名改为 dhcp-server
yum install -y dhcp-server

Debian / Ubuntu 系列:

apt-get update
apt-get install -y isc-dhcp-server

查询是否已安装:

rpm -qa | grep dhcp
rpm -qi dhcp

实验环境提示:教学实验中虚拟机常被断开外网,此时需使用本地 yum 源安装。

  1. 在虚拟化管理界面为虚拟机添加一个存储设备,设备类型选择 CDROM 设备,点击"管理"把系统 ISO 镜像加进去;
  2. 挂载 ISO 并配置本地仓库:
mount -ro loop /dev/cdrom /mnt

2.2 相关文件一览

文件路径 说明
/etc/dhcp/dhcpd.conf DHCP 主配置文件(RHEL 6 及以上)。RHEL 5 中位于 /etc/dhcpd.conf
/usr/share/doc/dhcp*/dhcpd.conf.example 官方配置模板。安装后默认的 dhcpd.conf 几乎只有注释,习惯做法是从该模板复制后修改。较新版本中模板名为 dhcpd.conf.example,旧版本可能为 dhcpd.conf.sample
/var/lib/dhcpd/dhcpd.leases 服务端租约数据库,记录已分配的地址、MAC、起止时间
/var/lib/dhclient/dhclient-<接口>.leases 客户端租约记录
/etc/sysconfig/dhcpd 服务启动参数(CentOS 6 用于指定监听网卡)。Debian/Ubuntu 为 /etc/default/isc-dhcp-server
/usr/lib/systemd/system/dhcpd.service CentOS 7 的 systemd 服务单元文件
/var/log/messages 默认日志位置(log-facility local7 时可自定义到独立文件)
/etc/dhcp/dhclient.conf 客户端配置文件

从模板复制作为配置起点:

# 先备份自带的空配置
cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.bak

# 用官方模板覆盖
cp /usr/share/doc/dhcp*/dhcpd.conf.example /etc/dhcp/dhcpd.conf

# 查看模板路径(版本号不同,路径会变)
ls /usr/share/doc/dhcp*/

也可以直接删除默认文件从零编写(教学实验常用做法):

rm -f /etc/dhcp/dhcpd.conf
vim /etc/dhcp/dhcpd.conf

完整参数手册:man 5 dhcpd.conf、man dhcpd、man dhcp-options。

2.3 配置文件的结构

dhcpd.conf 由参数(parameter)、选项(option)和声明块(declaration)组成,每条指令必须以分号 ; 结尾,声明块用大括号 {} 包裹。层级由外到内为:

全局参数 / 全局 option        ← 对所有子网生效
│
├── shared-network 名称 { }   ← 共享网络:同一物理网络上的多个逻辑子网
│     ├── subnet ... { }
│     └── subnet ... { }
│
├── subnet 网段 netmask 掩码 { }   ← 子网声明:一个网段的作用域
│     ├── range ...                 ← 地址池
│     ├── option ...                ← 该子网专属选项(覆盖全局)
│     └── pool { }                  ← 地址池细分(可配 allow/deny)
│
├── group { }                 ← 组声明:把一组主机的公共参数集中书写
│     ├── host ... { }
│     └── host ... { }
│
└── host 名称 { }             ← 主机声明:按 MAC 绑定固定地址
      ├── hardware ethernet MAC;
      └── fixed-address IP;

作用域覆盖规则:内层覆盖外层。写在 subnet 内的 option routers 会覆盖全局的同名选项;写在 host 内的参数优先级最高。

声明块 作用
subnet NET netmask MASK { } 声明一个子网的作用域及其地址池、下发参数。必须与 DHCP 服务器某块网卡所在网段匹配,否则 dhcpd 无法启动
host NAME { } 为特定客户端(按 MAC 识别)保留固定地址或指定专属参数
group { } 把若干 host(或 subnet)的公共参数提取出来集中书写,避免重复
shared-network NAME { } 声明多个 subnet 处于同一物理网络/同一广播域,服务器可从其中任一子网的地址池取址
pool { } 在 subnet 内部细分地址池,可对不同池设置不同的 allow/deny 与租期

2.4 常用参数逐项详解

2.4.1 网段与地址池

指令 说明
subnet 192.168.0.0 netmask 255.255.255.0 声明该配置块作用的网段与掩码。服务器自身网卡 IP 必须落在此网段内
range 192.168.0.100 192.168.0.200; 可动态分配的地址池起止范围,必须落在所属 subnet 网段之内。一个 subnet 中可写多条 range
range dynamic-bootp 3.3.3.101 3.3.3.254; 带 dynamic-bootp 关键字,表示该地址池同时允许 BOOTP 客户端动态获取地址
allow bootp; / deny bootp; 是否允许 BOOTP 客户端获取地址(PXE 网络引导依赖 BOOTP,需要 allow)
allow booting; / deny booting; 是否响应该客户端的引导请求,常用于 PXE 场景

2.4.2 下发给客户端的网络选项(option)

指令 说明
option subnet-mask 255.255.255.0; 下发给客户端的子网掩码。若省略,则使用 subnet 声明中的 netmask
option routers 192.168.0.1; 下发给客户端的默认网关地址。可写多个,用逗号分隔
option domain-name "abc.com"; 下发给客户端的搜索域(写入客户端 /etc/resolv.conf 的 search 行),注意值要加双引号
option domain-name-servers 223.5.5.5, 114.114.114.114; 下发给客户端的 DNS 服务器地址,多个用逗号分隔
option broadcast-address 192.168.0.255; 下发给客户端的广播地址
option ntp-servers 192.168.0.1; 下发 NTP 时间服务器
option netbios-name-servers 192.168.0.5; 下发 WINS 服务器(Windows 客户端)
option host-name "client01"; 下发主机名(一般写在 host 块中,只做简单分配)
option interface-mtu 1500; 下发 MTU

2.4.3 租约时间

指令 说明
default-lease-time 600; 默认租约时长(秒)。客户端未主动申请租期时使用,此处为 600 秒(10 分钟)
max-lease-time 7200; 最大租约时长(秒)。客户端申请的租期上限,超过则按此值下发,此处为 7200 秒(2 小时)
min-lease-time 300; 最小租约时长(秒),可选

2.4.4 服务行为与全局参数

指令 说明
ddns-update-style none; 动态 DNS 更新方式。none 表示不做 DDNS 更新(最常用);interim 为过渡型 DDNS 更新;ad-hoc 为临时方式(已废弃)。该指令必须写在全局区域,且新版 dhcpd 中不写会告警
authoritative; 声明本服务器为该网络的权威 DHCP 服务器。开启后,当客户端请求一个本服务器认为非法的地址时,会主动回复 DHCP NAK 让客户端立即重新申请,而不是沉默不响应。生产环境中在唯一的、正式的 DHCP 服务器上应开启
not authoritative; 显式声明非权威,测试或存在其他 DHCP 服务器时使用
log-facility local7; 指定日志设施,对应 syslog 的 local0 ~ local7。配合 rsyslog 可把 dhcpd 日志单独输出到一个文件
one-lease-per-client true; 一个客户端只保留一条租约,客户端换网卡/重启时回收旧租约
ping-check true; 分配前先 ping 目标地址,避免与手工静态配置的主机冲突(会略微增加分配延迟)
deny unknown-clients; 拒绝未在配置文件中通过 host 声明登记过的客户端(即只服务已知 MAC,实现 MAC 白名单)
allow unknown-clients; 允许未登记的客户端获取地址(默认行为)
deny known-clients; 拒绝已登记客户端(少用,通常配合多个 pool 做分池)
ignore-client-uids true; 忽略客户端 UID,仅以 MAC 作为唯一标识

2.4.5 MAC 绑定与 PXE 网络引导

指令 说明
host NAME { } 保留项名称,一般写客户端主机名,仅作标识用
hardware ethernet 00:0c:29:df:da:d4; 客户端网卡 MAC 地址
fixed-address 2.2.2.188; 固定分配给该客户端的 IP。该地址不必、也建议不要包含在 range 地址池范围内,以免与动态分配冲突
next-server 192.168.0.10; 指定 TFTP 服务器的 IP 地址,客户端从该服务器下载网络引导文件。PXE 装机必需
filename "pxelinux.0"; 指定客户端从 TFTP 服务器下载的引导文件名。BIOS 引导常用 pxelinux.0,UEFI 引导常用 grubx64.efi 或 shim.efi

2.5 完整可用的配置示例

示例一:单网段基本配置(最常用模板)

# ===== 全局参数 =====
ddns-update-style none;            # 不做动态 DNS 更新
authoritative;                     # 本机为权威 DHCP 服务器
log-facility local7;               # 日志设施
allow bootp;                       # 允许 BOOTP 客户端
default-lease-time 600;            # 默认租约 600 秒
max-lease-time 7200;               # 最大租约 7200 秒

# ===== 子网声明 =====
subnet 192.168.0.0 netmask 255.255.255.0 {
    range                      192.168.0.100 192.168.0.200;   # 可分配的 IP 范围
    option routers             192.168.0.1;                   # 默认网关
    option subnet-mask         255.255.255.0;                 # 子网掩码
    option broadcast-address   192.168.0.255;                 # 广播地址
    option domain-name         "abc.com";                     # 搜索域
    option domain-name-servers 223.5.5.5, 114.114.114.114;    # DNS 服务器
    default-lease-time         600;
    max-lease-time             7200;
}

示例二:实验环境配置(3.3.3.0/24 网段)

服务器网卡 IP 为 3.3.3.1/24,向客户端分配 3.3.3.101 - 3.3.3.254:

allow bootp;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;
subnet 3.3.3.0 netmask 255.255.255.0 {
        option routers                  3.3.3.1;        # 默认网关
        option subnet-mask              255.255.255.0;  # 子网掩码
        option domain-name              "abc.com";      # 搜索域
        option domain-name-servers      223.5.5.5;      # 域名服务器
        range dynamic-bootp 3.3.3.101 3.3.3.254;        # 可供分配的 IP 范围
}

示例三:多子网 + 广播地址 + 固定地址保留(综合示例)

ddns-update-style none;
authoritative;
log-facility local7;

subnet 1.1.1.0 netmask 255.255.255.0 {
    range 1.1.1.10 1.1.1.20;
    option domain-name-servers 8.8.8.8;
    option routers 1.1.1.1;
    option broadcast-address 1.1.1.255;
    default-lease-time 600;
    max-lease-time 7200;
}

subnet 2.2.2.0 netmask 255.255.255.0 {
    range 2.2.2.100 2.2.2.200;
    option domain-name-servers 114.114.114.114;
    option routers 2.2.2.1;
    option broadcast-address 2.2.2.255;
    default-lease-time 600;
    max-lease-time 7200;
}

# 按 MAC 固定分配地址
host vmware {
    hardware ethernet 00:0c:29:df:da:d4;
    fixed-address 2.2.2.188;
}

2.6 配置注意事项

  1. 每条指令必须以分号 ; 结尾,声明块的大括号不需要分号,漏写分号是 dhcpd 启动失败最常见的原因。
  2. 服务器网卡 IP 必须包含在某个 subnet 声明的网段之内,否则 dhcpd 启动时报 "no subnet declaration for ..." 并拒绝启动。
  3. range 设置的地址范围必须落在所属 subnet 的网段之内。
  4. 地址池不要与静态分配的 IP 重叠(服务器自身、网关、打印机、fixed-address 保留地址等),否则会造成 IP 冲突。
  5. DHCP 服务器自身必须使用静态 IP,不能依赖自己分配地址。
  6. option domain-name 的值需要用双引号包裹。
  7. 新版 dhcpd 中 ddns-update-style 未声明会产生告警,建议显式写 ddns-update-style none;。
  8. ip 和 brctl 命令配置的地址、路由、网桥均为临时配置,重启后失效。如需持久化,应写入网卡配置文件或通过 NetworkManager / systemd-networkd / /etc/network/interfaces 管理。

三、启动与验证

3.1 配置语法检查(启动前必做)

修改完 dhcpd.conf 后,先做语法检查再启动,可以快速定位漏分号、括号不匹配、网段不存在等问题:

# 方式一:以测试模式前台运行,只检查配置不真正提供服务(推荐)
dhcpd -t

# 指定配置文件检查
dhcpd -t -cf /etc/dhcp/dhcpd.conf

# 方式二:前台运行并打印详细过程(Ctrl+C 退出),可看到监听了哪些网卡
dhcpd -d -f

# 方式三:同时检查租约文件语法
dhcpd -T

检查通过时输出中会包含类似信息:

Internet Systems Consortium DHCP Server 4.2.5
Copyright 2004-2013 Internet Systems Consortium.
...
Wrote 0 leases to leases file.

若出现下面这类提示,说明服务器没有任何网卡属于配置文件中声明的网段,需要先给网卡配好静态 IP:

No subnet declaration for eth0 (192.168.1.5).
** Ignoring requests on eth0.  If this is not what
   you want, please write a subnet declaration ...

3.2 启动服务与开机自启

CentOS 6 / RHEL 6(SysV init,service + chkconfig)

# 启动 / 停止 / 重启 / 查看状态
service dhcpd start
service dhcpd stop
service dhcpd restart
service dhcpd status

# 等价的脚本调用方式
/etc/init.d/dhcpd start
/etc/init.d/dhcpd restart
/etc/rc.d/init.d/dhcpd restart

# 设置开机自启 / 关闭自启 / 查看自启状态
chkconfig dhcpd on
chkconfig dhcpd off
chkconfig --list dhcpd

RHEL 5 中主配置文件为 /etc/dhcpd.conf,服务脚本同样是 /etc/init.d/dhcpd。

CentOS 7 / RHEL 7 及以上(systemd,systemctl)

# 启动 / 停止 / 重启 / 重载 / 查看状态
systemctl start dhcpd
systemctl stop dhcpd
systemctl restart dhcpd
systemctl status dhcpd

# 设置开机自启 / 关闭自启 / 查看自启状态
systemctl enable dhcpd
systemctl disable dhcpd
systemctl is-enabled dhcpd

# 启动并同时设置开机自启(CentOS 7.3+)
systemctl enable --now dhcpd

CentOS 6 与 CentOS 7 服务管理命令对照表:

操作 CentOS 6 CentOS 7 及以上
启动服务 service dhcpd start systemctl start dhcpd
停止服务 service dhcpd stop systemctl stop dhcpd
重启服务 service dhcpd restart systemctl restart dhcpd
查看状态 service dhcpd status systemctl status dhcpd
开机自启 chkconfig dhcpd on systemctl enable dhcpd
取消自启 chkconfig dhcpd off systemctl disable dhcpd
服务定义文件 /etc/init.d/dhcpd /usr/lib/systemd/system/dhcpd.service

Debian / Ubuntu:

systemctl restart isc-dhcp-server
systemctl enable isc-dhcp-server

3.3 指定 dhcpd 监听的网卡

当服务器有多块网卡时,默认 dhcpd 会在所有能匹配到 subnet 声明的网卡上提供服务。为安全起见(例如避免向公网侧网卡提供 DHCP),应显式限定监听网卡。

CentOS 6:修改 /etc/sysconfig/dhcpd

# /etc/sysconfig/dhcpd
# Command line options here
DHCPDARGS=eth1

多块网卡用空格分隔并加引号:

DHCPDARGS="eth1 eth2"

修改后重启服务:

service dhcpd restart

CentOS 7:修改 systemd 单元或使用 drop-in

CentOS 7 的 dhcpd.service 默认不再读取 /etc/sysconfig/dhcpd,需要修改单元文件。推荐用 drop-in 方式,避免升级时被覆盖:

systemctl edit dhcpd

在打开的编辑器中写入(ExecStart 需先清空再重设):

[Service]
EnvironmentFile=-/etc/sysconfig/dhcpd
ExecStart=
ExecStart=/usr/sbin/dhcpd -f -cf /etc/dhcp/dhcpd.conf -user dhcpd -group dhcpd --no-pid $DHCPDARGS

然后在 /etc/sysconfig/dhcpd 中写入网卡名:

DHCPDARGS=ens33

重新加载并重启:

systemctl daemon-reload
systemctl restart dhcpd

也可以直接编辑 /usr/lib/systemd/system/dhcpd.service(不推荐,升级会被覆盖),或复制到 /etc/systemd/system/ 后修改:

cp /usr/lib/systemd/system/dhcpd.service /etc/systemd/system/dhcpd.service
vim /etc/systemd/system/dhcpd.service
systemctl daemon-reload
systemctl restart dhcpd

Debian / Ubuntu 在 /etc/default/isc-dhcp-server 中指定:

INTERFACESv4="eth1"

3.4 防火墙与 SELinux 放行

DHCP 使用 UDP 67(服务端) 和 UDP 68(客户端),必须放行。

CentOS 6:iptables

# 放行 DHCP 端口(推荐做法)
iptables -I INPUT -p udp --dport 67 -j ACCEPT
iptables -I INPUT -p udp --dport 68 -j ACCEPT
service iptables save

# 教学实验中可临时清空规则并把 INPUT 默认策略设为 ACCEPT
iptables -F
iptables -P INPUT ACCEPT

# 查看规则
iptables -L -n

# 彻底关闭防火墙(仅实验环境)
service iptables stop
chkconfig iptables off

也可使用 setup 图形工具,进入 Firewall configuration,把 firewall 前的 * 去掉后保存。

CentOS 7:firewalld

# 放行 dhcp 服务(等价于放行 udp/67)
firewall-cmd --permanent --add-service=dhcp
firewall-cmd --reload

# 按端口放行
firewall-cmd --permanent --add-port=67/udp
firewall-cmd --permanent --add-port=68/udp
firewall-cmd --reload

# 查看当前放行内容
firewall-cmd --list-all

# 教学实验中可直接停用(仅实验环境)
systemctl stop firewalld
systemctl disable firewalld

CentOS 6 与 CentOS 7 防火墙对照表:

操作 CentOS 6(iptables) CentOS 7(firewalld)
放行 DHCP iptables -I INPUT -p udp --dport 67 -j ACCEPT firewall-cmd --permanent --add-service=dhcp
保存/生效 service iptables save firewall-cmd --reload
查看规则 iptables -L -n firewall-cmd --list-all
停止服务 service iptables stop systemctl stop firewalld
取消自启 chkconfig iptables off systemctl disable firewalld

CentOS 7 中若想继续使用 iptables 语法,可安装 iptables-services 并停用 firewalld。

SELinux

# 查询当前状态
getenforce

# 临时设为 Permissive(宽容模式,只告警不拦截)
setenforce 0

# 恢复 Enforcing
setenforce 1

# 查看详细状态
sestatus

永久关闭需修改 /etc/selinux/config,将:

SELINUX=enforcing

改为:

SELINUX=disabled

修改后需重启系统生效。生产环境更推荐保留 SELinux 并放行相应布尔值/端口,而非直接关闭:

# 查看 dhcpd 相关布尔值
getsebool -a | grep dhcp

# 查看被 SELinux 拦截的记录
grep dhcpd /var/log/audit/audit.log
ausearch -m avc -c dhcpd

3.5 查看服务运行状态与监听端口

# 查看进程
ps -ef | grep dhcpd

# 查看 UDP 67 端口是否被监听
netstat -anup | grep 67
ss -anup | grep 67

# CentOS 7 查看服务详细状态与最近日志
systemctl status dhcpd -l

3.6 租约文件 /var/lib/dhcpd/dhcpd.leases 的读法

服务端把每一条已分配的租约写入 /var/lib/dhcpd/dhcpd.leases,这是核对"谁拿到了哪个地址"的权威依据:

cat /var/lib/dhcpd/dhcpd.leases

# 只看当前分配出去的地址与 MAC 对应关系
grep -E "lease|hardware ethernet|client-hostname" /var/lib/dhcpd/dhcpd.leases

典型内容:

# The format of this file is documented in the dhcpd.leases(5) manual page.
# This lease file was written by isc-dhcp-4.2.5

lease 192.168.0.100 {
  starts 4 2026/08/20 09:15:32;
  ends 4 2026/08/20 11:15:32;
  cltt 4 2026/08/20 09:15:32;
  binding state active;
  next binding state free;
  rewind binding state free;
  hardware ethernet 00:0c:29:df:da:d4;
  uid "\001\000\014)\337\332\324";
  client-hostname "client01";
}

字段含义:

字段 含义
lease IP { } 该条租约对应的 IP 地址
starts 租约开始时间(UTC 时间,格式为 星期 年/月/日 时:分:秒,星期 0 表示周日)
ends 租约结束时间(UTC)。值为 never 表示永久
cltt client last transaction time,客户端最后一次交互的时间
binding state active 当前绑定状态:active 使用中、free 空闲可再分配、expired 已过期、released 已被客户端释放、abandoned 已放弃(通常因地址冲突)
next binding state 当前租约结束后将进入的状态
hardware ethernet 客户端 MAC 地址
uid 客户端标识符
client-hostname 客户端上报的主机名

维护要点:

  • 该文件由 dhcpd 自动维护,不要手工编辑;文件损坏会导致 dhcpd 无法启动。
  • 若必须重置租约数据库(例如文件损坏),做法是备份后清空并重建:
service dhcpd stop            # CentOS 6
# systemctl stop dhcpd        # CentOS 7

mv /var/lib/dhcpd/dhcpd.leases /var/lib/dhcpd/dhcpd.leases.bak
touch /var/lib/dhcpd/dhcpd.leases
chown dhcpd:dhcpd /var/lib/dhcpd/dhcpd.leases

service dhcpd start           # CentOS 6
# systemctl start dhcpd       # CentOS 7
  • dhcpd 会自动生成 dhcpd.leases~ 备份文件,属正常现象。

3.7 日志查看

默认日志位置:/var/log/messages

# 实时跟踪 DHCP 交互过程
tail -f /var/log/messages | grep dhcpd

# 过滤历史记录
grep dhcpd /var/log/messages
cat /var/log/messages | grep dhcp

# CentOS 7 还可用 journalctl
journalctl -u dhcpd
journalctl -u dhcpd -f          # 实时跟踪
journalctl -u dhcpd --since today

典型的一次成功分配在日志中表现为四行:

dhcpd: DHCPDISCOVER from 00:0c:29:df:da:d4 via ens33
dhcpd: DHCPOFFER on 192.168.0.100 to 00:0c:29:df:da:d4 via ens33
dhcpd: DHCPREQUEST for 192.168.0.100 (192.168.0.1) from 00:0c:29:df:da:d4 via ens33
dhcpd: DHCPACK on 192.168.0.100 to 00:0c:29:df:da:d4 via ens33

把 dhcpd 日志单独输出到一个文件:配置文件中已写 log-facility local7;,在 /etc/rsyslog.conf 中追加一行:

local7.*                                                /var/log/dhcpd.log

重启 rsyslog 使其生效:

# CentOS 6
service rsyslog restart

# CentOS 7
systemctl restart rsyslog

之后即可通过 tail -f /var/log/dhcpd.log 单独观察 DHCP 日志。


四、进阶与实战

4.1 为指定 MAC 绑定固定 IP(固定地址保留)

某些主机(打印机、监控设备、需要做端口映射的服务器)既希望享受集中管理,又需要地址固定。做法是在 /etc/dhcp/dhcpd.conf 中添加 host 声明,按客户端 MAC 地址固定分配指定 IP。

最小示例:

host vmware {
    hardware ethernet 00:0c:29:df:da:d4;
    fixed-address 2.2.2.188;
}
字段 含义
host NAME 保留项名称,一般写客户端主机名,仅作标识,不影响功能
hardware ethernet MAC 客户端网卡 MAC 地址
fixed-address IP 固定分配给该客户端的 IP

完整示例(含专属参数与主机名):

ddns-update-style none;
authoritative;
log-facility local7;
default-lease-time 600;
max-lease-time 7200;

subnet 192.168.0.0 netmask 255.255.255.0 {
    range                      192.168.0.100 192.168.0.200;
    option routers             192.168.0.1;
    option subnet-mask         255.255.255.0;
    option broadcast-address   192.168.0.255;
    option domain-name         "abc.com";
    option domain-name-servers 223.5.5.5;
}

# 打印机:固定地址 + 无限租期
host printer01 {
    hardware ethernet 00:1b:11:aa:bb:cc;
    fixed-address 192.168.0.240;
    option host-name "printer01";
    default-lease-time -1;                 # -1 表示永久租约
    max-lease-time -1;
}

# 服务器:固定地址 + 专属网关与 DNS(覆盖 subnet 中的同名选项)
host web01 {
    hardware ethernet 00:0c:29:df:da:d4;
    fixed-address 192.168.0.241;
    option routers 192.168.0.254;
    option domain-name-servers 192.168.0.2;
}

用 group 集中书写多台主机的公共参数:

group {
    option routers             192.168.0.254;
    option domain-name-servers 192.168.0.2;
    default-lease-time         86400;

    host srv01 {
        hardware ethernet 00:0c:29:11:11:11;
        fixed-address 192.168.0.211;
    }
    host srv02 {
        hardware ethernet 00:0c:29:22:22:22;
        fixed-address 192.168.0.212;
    }
    host srv03 {
        hardware ethernet 00:0c:29:33:33:33;
        fixed-address 192.168.0.213;
    }
}

只服务已登记 MAC(MAC 白名单):

subnet 192.168.0.0 netmask 255.255.255.0 {
    option routers 192.168.0.1;
    deny unknown-clients;              # 拒绝未登记的客户端
    range 192.168.0.100 192.168.0.200;
}

若希望已知客户端与未知客户端使用不同地址池,可用 pool 细分:

subnet 192.168.0.0 netmask 255.255.255.0 {
    option routers 192.168.0.1;

    pool {
        deny unknown-clients;          # 已登记设备使用的池
        range 192.168.0.10 192.168.0.99;
        default-lease-time 86400;
    }
    pool {
        allow unknown-clients;         # 访客设备使用的池,租期短
        range 192.168.0.200 192.168.0.250;
        default-lease-time 1800;
        max-lease-time 3600;
    }
}

注意事项:

  • MAC 地址书写用冒号分隔的十六进制,大小写不敏感。
  • fixed-address 的地址建议不要落在 range 地址池范围内,避免该地址先被动态分配给别人造成冲突。
  • 配置完成后重启服务并在客户端重新获取 IP 验证:
# CentOS 6
/etc/init.d/dhcpd restart
service dhcpd restart

# CentOS 7
systemctl restart dhcpd

获取客户端 MAC 的方法:

# Linux 客户端
ip l                             # 或 ip a s
ifconfig eth0 | grep -i hwaddr   # CentOS 6

# Windows 客户端
ipconfig /all                    # 查看"物理地址"

# 从服务端日志或 ARP 表反查
grep DHCPDISCOVER /var/log/messages
arp -n
ip neigh

4.2 多网段配置与 shared-network

4.2.1 一台服务器多块网卡,服务多个物理网段

最常见的多网段场景:服务器有多块网卡,每块网卡接入一个独立的物理网络,分别为各自网段提供地址。此时只需在 dhcpd.conf 中并列写多个 subnet 声明:

allow bootp;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;

subnet 10.1.1.0 netmask 255.255.255.0 {
        option routers                  10.1.1.1;       # 默认网关
        option subnet-mask              255.255.255.0;  # 子网掩码
        option domain-name              "abc.com";      # 搜索域
        option domain-name-servers      10.1.1.1;       # 域名服务器
        range dynamic-bootp 10.1.1.101 10.1.1.254;      # 可供分配的 IP 范围
}
subnet 10.1.2.0 netmask 255.255.255.0 {
        option routers                  10.1.2.1;       # 默认网关
        option subnet-mask              255.255.255.0;  # 子网掩码
        option domain-name              "abc.com";      # 搜索域
        option domain-name-servers      10.1.2.1;       # 域名服务器
        range dynamic-bootp 10.1.2.101 10.1.2.254;      # 可供分配的 IP 范围
}

服务器两块网卡分别配置对应网段的 IP:

ip a add 10.1.1.1/24 dev ens1
ip a add 10.1.2.1/24 dev ens3

dhcpd 会根据请求从哪块网卡进来(或中继的 giaddr),自动选择对应的 subnet 声明分配地址。

4.2.2 shared-network:同一物理网络上的多个逻辑子网

当一个物理网段(同一广播域)内需要同时使用多个 IP 网段时(例如原有网段地址池耗尽,需要扩容第二个网段),不能简单并列写两个 subnet,否则 dhcpd 无法判断该用哪个。这种情况必须用 shared-network 把它们归为同一物理网络:

shared-network office-lan {
    option domain-name         "abc.com";
    option domain-name-servers 223.5.5.5, 114.114.114.114;
    default-lease-time         600;
    max-lease-time             7200;

    subnet 192.168.10.0 netmask 255.255.255.0 {
        range          192.168.10.100 192.168.10.200;
        option routers 192.168.10.1;
    }

    subnet 192.168.11.0 netmask 255.255.255.0 {
        range          192.168.11.100 192.168.11.200;
        option routers 192.168.11.1;
    }
}

要点:

  • shared-network 内的多个 subnet 处于同一广播域,dhcpd 可从其中任意一个尚有空闲地址的池中取址;
  • 服务器所在网卡需要同时配置这两个网段的 IP(辅助 IP),否则第二个网段的地址下发后客户端无法与服务器通信;
  • 路由器(网关)也需要在该接口上同时配置两个网段的地址,否则第二网段客户端无法出网;
  • 公共参数(DNS、租期、域名)可以提到 shared-network 层,避免在每个 subnet 中重复书写。

4.3 DHCP 中继 dhcrelay 的部署

当客户端与 DHCP 服务器不在同一个广播域时,需要在客户端所在网段部署 DHCP 中继代理。

4.3.1 拓扑示例

客户端网段 A                中继主机(双网卡)              DHCP 服务器网段 B
192.168.10.0/24  ---- eth0:192.168.10.1  eth1:192.168.20.1 ---- 192.168.20.10
     客户端                  运行 dhcrelay                        运行 dhcpd

4.3.2 中继主机上的部署步骤

  1. 安装软件包(dhcrelay 由 dhcp 包提供,CentOS 8+ 为 dhcp-relay):
# CentOS 6 / 7
yum install dhcp -y

# CentOS 8 及以上
yum install dhcp-relay -y
  1. 开启内核 IP 转发(中继主机需要转发流量):
# 临时开启
echo 1 > /proc/sys/net/ipv4/ip_forward
sysctl -w net.ipv4.ip_forward=1

# 永久开启:编辑 /etc/sysctl.conf(CentOS 6)或 /etc/sysctl.d/99-ip.conf(CentOS 7)
# net.ipv4.ip_forward = 1
sysctl -p
  1. 命令行方式直接启动中继(指定 DHCP 服务器地址和侦听网卡):
# 语法:dhcrelay [-i 侦听网卡] ... DHCP服务器IP
dhcrelay 192.168.20.10

# 只在客户端侧网卡侦听请求
dhcrelay -i eth0 192.168.20.10

# 前台运行并输出调试信息(排错用)
dhcrelay -d -i eth0 192.168.20.10

# 指定多台 DHCP 服务器(冗余)
dhcrelay -i eth0 192.168.20.10 192.168.20.11

常用参数:

参数 说明
-i <接口> 指定侦听/转发所使用的网络接口,可多次指定
-d 前台运行并输出调试信息
-q 安静模式,减少启动输出
-c <跳数> 最大跳数(默认 10),超过则丢弃
-a 在转发的报文中追加 Relay Agent Information(option 82)
-p <端口> 指定监听端口(默认 67)
  1. 服务方式启动(CentOS 6,通过 /etc/sysconfig/dhcrelay 指定参数):
# /etc/sysconfig/dhcrelay
INTERFACES="eth0"
DHCPSERVERS="192.168.20.10"
service dhcrelay start
chkconfig dhcrelay on
  1. 服务方式启动(CentOS 7,需要在 systemd 单元中写明参数):
systemctl edit dhcrelay
[Service]
ExecStart=
ExecStart=/usr/sbin/dhcrelay -d --no-pid -i eth0 192.168.20.10
systemctl daemon-reload
systemctl enable --now dhcrelay
systemctl status dhcrelay

4.3.3 DHCP 服务器侧的配合配置

DHCP 服务器必须为中继过来的每一个远端网段都声明 subnet,否则会拒绝服务:

ddns-update-style none;
authoritative;
log-facility local7;

# 本机所在网段:即使不分配地址,也要声明一个空 subnet,否则 dhcpd 可能拒绝在该网卡启动
subnet 192.168.20.0 netmask 255.255.255.0 {
}

# 通过中继服务的远端网段
subnet 192.168.10.0 netmask 255.255.255.0 {
    range                      192.168.10.100 192.168.10.200;
    option routers             192.168.10.1;        # 客户端网段的网关(通常就是中继接口)
    option subnet-mask         255.255.255.0;
    option domain-name-servers 223.5.5.5;
    default-lease-time         600;
    max-lease-time            7200;
}

另外还要确保:

  • DHCP 服务器有到 192.168.10.0/24 的回程路由(通常指向中继主机);
  • 中继主机与 DHCP 服务器之间的防火墙放行 UDP 67;
  • 三层交换机/路由器上若使用厂商中继功能,对应命令通常是 dhcp select relay / ip helper-address 192.168.20.10。

4.3.4 中继排错

# 在中继主机上前台运行观察转发过程
dhcrelay -d -i eth0 192.168.20.10

# 在中继主机上抓包,确认既收到广播请求,又向服务器发出了单播
tcpdump -i eth0 -nn port 67 or port 68
tcpdump -i eth1 -nn port 67 or port 68

# 在服务器日志中确认请求带有 via 中继地址
grep DHCPDISCOVER /var/log/messages
# DHCPDISCOVER from 00:0c:29:.. via 192.168.10.1   ← via 后为 giaddr,说明中继生效

4.4 DHCP 与 PXE 网络装机的配合

PXE(Preboot Execution Environment)网络装机的第一步就是客户机通过 DHCP 获取 IP,并从 DHCP 应答中得知去哪台 TFTP 服务器、下载哪个引导文件。因此 DHCP 是 PXE 链路的入口。

关键的两个指令:

指令 作用
next-server <TFTP服务器IP>; 告诉客户机去哪台 TFTP 服务器下载引导文件。若省略,客户机会默认向 DHCP 服务器自身请求
filename "<引导文件名>"; 告诉客户机下载哪个引导文件(相对 TFTP 根目录 /var/lib/tftpboot)

BIOS(Legacy)引导的配置示例:

ddns-update-style none;
authoritative;
allow booting;                    # 允许响应引导请求
allow bootp;                      # 允许 BOOTP 客户端

subnet 192.168.0.0 netmask 255.255.255.0 {
    range                      192.168.0.100 192.168.0.200;
    option routers             192.168.0.1;
    option subnet-mask         255.255.255.0;
    option domain-name-servers 223.5.5.5;
    default-lease-time         600;
    max-lease-time            7200;

    next-server 192.168.0.10;         # TFTP 服务器地址
    filename    "pxelinux.0";         # BIOS 引导文件(由 syslinux 包提供)
}

同时兼容 BIOS 与 UEFI 引导(根据客户机上报的架构类型 option 93 判断):

option architecture-type code 93 = unsigned integer 16;

subnet 192.168.0.0 netmask 255.255.255.0 {
    range          192.168.0.100 192.168.0.200;
    option routers 192.168.0.1;

    next-server 192.168.0.10;

    if option architecture-type = 00:07 or option architecture-type = 00:09 {
        filename "uefi/shim.efi";        # x86-64 UEFI
    } else {
        filename "pxelinux.0";           # 传统 BIOS
    }
}

按 MAC 为特定机器指定不同引导文件(例如只给某台机器重装系统):

host newserver {
    hardware ethernet 00:0c:29:aa:bb:cc;
    fixed-address 192.168.0.150;
    next-server 192.168.0.10;
    filename "pxelinux.0";
}

配合要点:

  • PXE 装机网段内必须只有一台 DHCP 服务器,否则客户机可能从错误的服务器拿到地址而无法取得引导文件;
  • 需要同时部署 TFTP(tftp-server,UDP 69)与 HTTP/FTP/NFS 提供的安装源;
  • 若 DHCP 与 TFTP 不在同一台机器上,务必显式写 next-server;
  • 防火墙需同时放行 UDP 67/68(DHCP)与 UDP 69(TFTP)。

详见 14-05-PXE与Cobbler批量装机.md

4.5 客户端获取地址的验证方法

4.5.1 Linux 客户端

方式一:修改网卡配置文件(持久生效)

编辑 /etc/sysconfig/network-scripts/ifcfg-eth0(CentOS 6)或 ifcfg-ens3(CentOS 7),把 BOOTPROTO 设为 dhcp:

DEVICE="ens3"
BOOTPROTO="dhcp"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"

重启网络服务:

# CentOS 6
service network restart
/etc/init.d/network restart

# CentOS 7
systemctl restart network
# 或只重启单个接口
ifdown ens3 && ifup ens3
nmcli connection down ens3 && nmcli connection up ens3

方式二:使用 dhclient 命令临时测试

# 为指定网卡申请地址
dhclient eth0
dhclient ens3

# 前台运行并输出详细交互过程(推荐排错时使用,可直接看到 DISCOVER/OFFER/REQUEST/ACK)
dhclient -v ens3
dhclient -d -v ens3

# 释放当前租约(向服务器发送 DHCP RELEASE)
dhclient -r ens3

# 标准排错流程:先释放,再重新申请并观察过程
dhclient -r ens3
dhclient -v ens3

# 只申请不配置接口(测试服务器是否响应)
dhclient -T ens3

注意:dhclient 命令重复使用时,需要先 kill 掉上一次残留的进程,否则会出现多个 dhclient 争抢同一网卡:

ps -ef | grep dhclient
pkill dhclient
# 或
killall dhclient

验证获取结果:

# 1. 查看 IP 是否落在地址池范围内
ip a s
ifconfig                  # CentOS 6 常用
ifconfig eth0

# 2. 查看下发的 DNS 与搜索域
cat /etc/resolv.conf

# 3. 查看默认网关
route -n                  # CentOS 6
ip r                      # 通用
netstat -rn

# 4. 查看客户端租约文件(含服务器地址、租期、全部下发选项)
cat /var/lib/dhclient/dhclient-eth0.leases
cat /var/lib/dhclient/dhclient.leases
ls /var/lib/dhclient/

# 5. 查看客户端日志
cat /var/log/messages | grep dhcp
grep -i dhclient /var/log/messages
journalctl -u NetworkManager | grep -i dhcp     # CentOS 7

# 6. 连通性测试
ping -c 3 <网关IP>
ping -c 3 223.5.5.5

客户端租约文件典型内容:

lease {
  interface "ens3";
  fixed-address 192.168.0.100;
  option subnet-mask 255.255.255.0;
  option routers 192.168.0.1;
  option dhcp-lease-time 600;
  option dhcp-message-type 5;
  option domain-name-servers 223.5.5.5;
  option dhcp-server-identifier 192.168.0.5;
  option domain-name "abc.com";
  renew 4 2026/08/20 09:20:32;
  rebind 4 2026/08/20 09:23:47;
  expire 4 2026/08/20 09:25:32;
}

其中 renew 对应 T1(50%)、rebind 对应 T2(87.5%)、expire 为租约到期时刻,可直接印证前文的续约机制;option dhcp-server-identifier 表明地址是哪台服务器给的,排查"多台 DHCP 服务器争抢"时最关键的一行。

4.5.2 Windows 客户端

在命令提示符(建议以管理员身份运行)中操作:

:: 查看当前 IP 配置概要
ipconfig

:: 查看完整信息:含 MAC(物理地址)、DHCP 已启用、DHCP 服务器地址、租约获得/过期时间
ipconfig /all

:: 释放当前获得的地址(向服务器发送 DHCP RELEASE)
ipconfig /release

:: 重新向 DHCP 服务器申请地址(触发 DISCOVER)
ipconfig /renew

:: 指定网卡操作
ipconfig /release "以太网"
ipconfig /renew "以太网"

:: 刷新 DNS 缓存
ipconfig /flushdns

ipconfig /all 中需要重点核对的字段:

字段 期望值
DHCP 已启用 / DHCP Enabled 是 / Yes
IPv4 地址 落在服务端 range 范围内
子网掩码、默认网关 与 option subnet-mask、option routers 一致
DNS 服务器 与 option domain-name-servers 一致
DHCP 服务器 是你自己搭建的那台服务器的 IP(若不是,说明网络中有其他 DHCP 服务器)
获得租约的时间 / 租约过期的时间 时间差应等于 default-lease-time

若 Windows 显示 169.254.x.x(APIPA 地址),说明完全没有拿到 DHCP 地址,需按 4.7 节排错。

也可用 PowerShell 查看:

Get-NetIPConfiguration
Get-NetIPAddress -AddressFamily IPv4
Get-DhcpServerv4Lease -ComputerName <server>   :: Windows DHCP 服务器端

4.6 抓包观察 DHCP 交互过程

抓包是判断"到底是客户端没发、还是服务端没回"的最直接手段。DHCP 全过程都在 UDP 67/68 上。

# 基本抓包命令(在服务器或客户端上执行)
tcpdump -i eth0 port 67 or port 68

# 推荐写法:-nn 不解析主机名和端口名,-e 显示以太网头(可看到 MAC)
tcpdump -i eth0 -nn -e port 67 or port 68

# 抓所有网卡
tcpdump -i any -nn port 67 or port 68

# 显示详细内容与报文内部字段
tcpdump -i eth0 -nn -vvv port 67 or port 68

# 打印完整报文十六进制与 ASCII
tcpdump -i eth0 -nn -X port 67 or port 68

# 只抓某个客户端 MAC 的 DHCP 交互
tcpdump -i eth0 -nn ether host 00:0c:29:df:da:d4 and (port 67 or port 68)

# 抓包存盘,之后用 Wireshark 打开分析(过滤器输入 bootp 或 dhcp)
tcpdump -i eth0 -nn -w /tmp/dhcp.pcap port 67 or port 68

# 读取已保存的抓包文件
tcpdump -nn -r /tmp/dhcp.pcap

正常一次交互的抓包结果(简化):

IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:0c:29:df:da:d4, length 300   ← DISCOVER
IP 192.168.0.5.67 > 255.255.255.255.68: BOOTP/DHCP, Reply, length 300                        ← OFFER
IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:0c:29:df:da:d4, length 300   ← REQUEST
IP 192.168.0.5.67 > 255.255.255.255.68: BOOTP/DHCP, Reply, length 300                        ← ACK

抓包结果的判读:

抓到的现象 结论
完全没有任何 DHCP 报文 客户端根本没发请求:网卡未启用、BOOTPROTO 不是 dhcp、dhclient 未运行、链路不通(网线/虚拟网卡未连接)
只有 Request(DISCOVER)没有 Reply 服务端没响应:dhcpd 未启动、监听在错误的网卡、无匹配的 subnet、防火墙拦截 UDP 67、客户端与服务端不在同一广播域且无中继
出现两个不同源 IP 的 Reply 网络中存在多台 DHCP 服务器,需要定位并关闭多余的那台
有 Reply 但客户端仍无地址 可能收到 NAK,或客户端 ARP 检测发现冲突后发出了 DECLINE
反复出现 DISCOVER-OFFER 循环 客户端可能因地址冲突不断 DECLINE,或服务端地址池已耗尽

配合 Wireshark 时可使用显示过滤器:bootp、dhcp、dhcp.option.dhcp == 1(只看 DISCOVER)。

4.7 排错清单

场景一:客户端拿不到地址

按顺序逐项检查:

  1. 服务端进程是否在跑、端口是否监听
ps -ef | grep dhcpd
netstat -anup | grep 67
service dhcpd status        # CentOS 6
systemctl status dhcpd      # CentOS 7
  1. 配置文件语法是否正确
dhcpd -t
dhcpd -d -f          # 前台运行看具体报错
  1. 服务器网卡 IP 是否落在某个 subnet 声明的网段内(最高频原因)
ip a s
grep subnet /etc/dhcp/dhcpd.conf

日志中出现 No subnet declaration for eth0 即为此问题。

  1. dhcpd 是否监听在正确的网卡上:检查 /etc/sysconfig/dhcpd 的 DHCPDARGS(CentOS 6)或 systemd 单元中的 ExecStart(CentOS 7)。

  2. 防火墙与 SELinux 是否拦截

iptables -L -n                     # CentOS 6
firewall-cmd --list-all            # CentOS 7
getenforce
  1. 客户端与服务端是否在同一广播域:跨网段必须部署 dhcrelay;虚拟机需确认网卡接入了同一个虚拟网络/网桥。

  2. 地址池是否已耗尽

grep -c "binding state active" /var/lib/dhcpd/dhcpd.leases

地址池耗尽时日志会出现 no free leases。此时应扩大 range、缩短租期,或清理过期租约。

  1. 是否被 deny unknown-clients 拦住:若配置了 MAC 白名单,未登记的客户端不会得到地址。

  2. 抓包定位:tcpdump -i eth0 -nn port 67 or port 68,按 4.6 节的判读表定位。

  3. 客户端侧:确认 BOOTPROTO=dhcp、ONBOOT=yes,网卡已 up,没有残留的 dhclient 进程。

场景二:拿到了错误网段的地址

可能原因 排查与处理
网络中存在其他 DHCP 服务器(最常见:私接的家用路由器、VMware/VirtualBox 自带 DHCP) 查看客户端租约文件中的 option dhcp-server-identifier,或 ipconfig /all 中的"DHCP 服务器"字段,确认地址来自哪台;抓包看是否有多个源 IP 的 Reply
虚拟机网卡接到了错误的虚拟网络 检查虚拟机网卡归属的虚拟网络/网桥
VMware 自带 DHCP 未关闭 用 vmware-netcfg(Linux)或"虚拟网络编辑器"(Windows)取消 vmnet1 的"使用本地 DHCP 服务"
服务端 shared-network 内多个 subnet,从另一个池取了地址 属于预期行为,检查是否需要拆分
客户端接在错误的 VLAN / 交换机端口 核对交换机端口 VLAN 配置

处理:定位并关闭多余的 DHCP 服务;在正式服务器上配置 authoritative;,使其对非法请求主动回 NAK。

场景三:IP 地址冲突

现象:客户端提示"检测到 IP 地址冲突",或 dhcpd.leases 中出现 binding state abandoned,日志中出现 DHCPDECLINE / abandoning IP address。

原因 处理
地址池与手工静态配置的主机重叠 缩小 range,或把静态地址段从池中排除
fixed-address 的地址落在 range 池内,先被动态分配给了别人 把保留地址移出池范围
网络中有两台 DHCP 服务器分配相同网段 关闭多余服务器
租约文件与实际情况不符(例如客户端异常关机未释放) 开启 ping-check true;,让服务器分配前先探测;必要时重建租约数据库
# 服务端开启分配前探测
# dhcpd.conf 中加入:
# ping-check true;

# 查看被放弃的地址
grep -B3 abandoned /var/lib/dhcpd/dhcpd.leases

# 客户端排查冲突(谁占用了这个地址)
arping -I eth0 192.168.0.100
arp -n | grep 192.168.0.100
ip neigh

场景四:多台 DHCP 服务器争抢

危害:客户端接受最先到达的 Offer,导致地址网段随机、时通时不通,是企业网中排查难度最高的故障之一。

定位方法:

# 1. 抓包看有几个不同源 IP 在回 Reply
tcpdump -i eth0 -nn port 67 or port 68

# 2. 用 nmap 扫描网段内的 DHCP 服务器
nmap --script broadcast-dhcp-discover
nmap -sU -p 67 192.168.0.0/24

# 3. 反复发起请求,观察每次拿到的服务器标识是否一致
dhclient -r eth0; dhclient -v eth0
grep dhcp-server-identifier /var/lib/dhclient/dhclient-eth0.leases

# 4. 通过 MAC 在交换机 MAC 地址表中定位非法服务器所在端口
arp -n

预防措施:

  • 交换机上启用 DHCP Snooping,只信任连接合法 DHCP 服务器的端口;
  • 严禁私接家用路由器(其 LAN 口默认开启 DHCP);
  • 关闭虚拟化平台自带的 DHCP(VMware 的 vmnet DHCP、libvirt 的 default 网络);
  • 实验环境建议使用 host-only 网络(如 vmnet1),不要使用 bridge 桥接网络,以免与办公网中现有的 DHCP 服务器冲突,影响他人。

场景五:服务起不动的常见配置错误

报错/现象 原因 处理
Configuration file errors encountered -- exiting 配置文件语法错误 dhcpd -t 定位;重点检查漏写的分号 ; 与不匹配的大括号
/etc/dhcp/dhcpd.conf line N: semicolon expected. 该行或上一行漏写分号 补上分号
Not configured to listen on any interfaces! 没有任何网卡属于配置文件中声明的网段 给网卡配好静态 IP,或补充对应的 subnet 声明
No subnet declaration for eth0 (x.x.x.x) 该网卡所在网段没有 subnet 声明 添加对应 subnet(即使不分配地址也可写空块 subnet x.x.x.0 netmask 255.255.255.0 { })
Can't open lease database /var/lib/dhcpd/dhcpd.leases 租约文件缺失或权限不对 touch /var/lib/dhcpd/dhcpd.leases; chown dhcpd:dhcpd /var/lib/dhcpd/dhcpd.leases
Please write a subnet declaration for the network segment... 同上 补 subnet 声明
启动即退出,日志提示 ddns-update-style 未声明 DDNS 方式 全局加 ddns-update-style none;
range 报错或客户端拿不到地址 range 超出 subnet 网段范围 修正地址范围
Address already in use / 端口被占用 已有 dhcpd 实例在运行 ps -ef | grep dhcpd 后 pkill dhcpd,再重启服务
修改配置后不生效 只写了配置未重启服务 service dhcpd restart(CentOS 6)/ systemctl restart dhcpd(CentOS 7)

通用排错三步:

# 1. 语法检查
dhcpd -t

# 2. 前台运行看真实报错
dhcpd -d -f

# 3. 看日志
tail -50 /var/log/messages | grep dhcpd
journalctl -xe -u dhcpd            # CentOS 7

4.8 完整实验

实验一:为单个局域网分配 IP 地址

实验环境

  • 一台虚拟机作为服务器,另一台虚拟机作为客户机,两者都连接到同一个网桥 br0(或同一个 host-only 虚拟网络)。
  • 如需隔离实验网络,可把物理网卡从网桥 br0 中删除(注意:这样物理机将不能上网):
brctl delif br0 enp0s25
ip a del 192.168.0.183/24 dev br0
ip a add 192.168.0.183/24 dev enp0s25

步骤 1:准备本地 yum 源

实验环境虚拟机会断开外网,需使用本地 yum 源:

  1. 在虚拟化管理界面添加一个存储设备,设备类型选择 CDROM 设备,点击管理,把 ISO 镜像加进去。
  2. 挂载 ISO 文件:
mount -ro loop /dev/cdrom /mnt

步骤 2:服务器预备工作(关闭防火墙与 SELinux)

# CentOS 6
iptables -F
iptables -P INPUT ACCEPT

# CentOS 7
systemctl stop firewalld

# 通用:SELinux 置为 Permissive
setenforce 0
getenforce

若需永久关闭 SELinux,修改 /etc/selinux/config,把 SELINUX=enforcing 改为 SELINUX=disabled。

步骤 3:配置服务器网卡 IP

ip a add 3.3.3.1/24 dev ens3

步骤 4:安装 DHCP 软件包

yum install dhcp

步骤 5:编辑主配置文件 /etc/dhcp/dhcpd.conf

allow bootp;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;
subnet 3.3.3.0 netmask 255.255.255.0 {
        option routers                  3.3.3.1;        # 默认网关
        option subnet-mask              255.255.255.0;  # 子网掩码
        option domain-name              "abc.com";      # 搜索域
        option domain-name-servers      223.5.5.5;      # 域名服务器
        range dynamic-bootp 3.3.3.101 3.3.3.254;        # 可供分配的 IP 范围
}

注意:服务器网卡 IP 必须包含在 subnet 3.3.3.0 netmask 255.255.255.0 声明的范围之内;range 所设置的 IP 范围也必须在该子网范围之内。

步骤 6:启动 dhcpd 服务

# CentOS 6
service dhcpd restart
chkconfig dhcpd on

# CentOS 7
systemctl restart dhcpd
systemctl enable dhcpd

步骤 7:配置客户端获取 IP

方式一:写配置文件 /etc/sysconfig/network-scripts/ifcfg-ens3

DEVICE="ens3"
BOOTPROTO="dhcp"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"

然后重启客户机网络服务:

service network restart        # CentOS 6
systemctl restart network      # CentOS 7

方式二:临时使用 dhclient 命令

dhclient ens3

步骤 8:验证

# 客户端
ip a s
cat /etc/resolv.conf
ip r
cat /var/lib/dhclient/dhclient-ens3.leases

# 服务端
cat /var/lib/dhcpd/dhcpd.leases
tail -f /var/log/messages | grep dhcpd

实验二:为多个局域网分配 IP 地址

实验环境

  1. 创建两个虚拟网络 net1、net2,在这两个虚拟网络中不启用 DHCP。
  2. 一台虚拟机作为服务器,两台虚拟机作为客户机。服务器上有两块网卡,分别属于 net1 和 net2;第一台客户机属于 net1,第二台客户机属于 net2。
  3. IP 地址规划:
    • 服务器网卡一:10.1.1.1/24,提供 IP 段 10.1.1.101 - 10.1.1.254
    • 服务器网卡二:10.1.2.1/24,提供 IP 段 10.1.2.101 - 10.1.2.254

步骤 1:服务器预备工作

iptables -F
iptables -P INPUT ACCEPT
setenforce 0
getenforce

步骤 2:配置两块网卡的 IP

ip a add 10.1.1.1/24 dev ens1
ip a add 10.1.2.1/24 dev ens3

步骤 3:安装 DHCP 软件包

yum install dhcp

步骤 4:编辑 /etc/dhcp/dhcpd.conf,声明两个子网

allow bootp;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;
subnet 10.1.1.0 netmask 255.255.255.0 {
        option routers                  10.1.1.1;       # 默认网关
        option subnet-mask              255.255.255.0;  # 子网掩码
        option domain-name              "abc.com";      # 搜索域
        option domain-name-servers      10.1.1.1;       # 域名服务器
        range dynamic-bootp 10.1.1.101 10.1.1.254;      # 可供分配的 IP 范围
}
subnet 10.1.2.0 netmask 255.255.255.0 {
        option routers                  10.1.2.1;       # 默认网关
        option subnet-mask              255.255.255.0;  # 子网掩码
        option domain-name              "abc.com";      # 搜索域
        option domain-name-servers      10.1.2.1;       # 域名服务器
        range dynamic-bootp 10.1.2.101 10.1.2.254;      # 可供分配的 IP 范围
}

步骤 5:重启 dhcpd 服务

service dhcpd restart          # CentOS 6
systemctl restart dhcpd        # CentOS 7

步骤 6:分别在两台客户机上获取 IP 并验证

# 方式一:修改 /etc/sysconfig/network-scripts/ifcfg-ens3 后重启网络
systemctl restart network

# 方式二:临时测试
dhclient ens3

验证第一台客户机拿到 10.1.1.101 - 10.1.1.254 中的地址,第二台拿到 10.1.2.101 - 10.1.2.254 中的地址。

实验三:宿主机做 DHCP 服务器 + 虚拟机做客户端(host-only 网络)

建议使用宿主机模拟 DHCP 服务器、虚拟机模拟客户端,并使用 host-only(如 vmnet1)网络,不要使用 bridge 网络,避免与现有局域网中的 DHCP 服务器冲突。

第一步:配置客户端网络

  1. 虚拟机网卡连接到 vmnet1 网络;
  2. 使用 vmware-netcfg 关闭 VMware 自带的 DHCP;
  3. 将客户端网卡设置为通过 DHCP 获取 IP:
/etc/init.d/network restart
# 或
dhclient eth0

此时应获取不到 IP(VMware 自带 DHCP 已关闭,自己的 DHCP 服务器尚未配置)。

第二步:安装并配置 DHCP 服务端

确认宿主机 vmnet1 网卡地址(示例中为 192.168.62.1),然后安装:

yum install dhcp* -y

主配置文件为 /etc/dhcp/dhcpd.conf。默认文件中只有注释模板,可删除后重新编写:

rm -f /etc/dhcp/dhcpd.conf
vim /etc/dhcp/dhcpd.conf

配置示例:

subnet 1.1.1.0 netmask 255.255.255.0 {
    range 1.1.1.10 1.1.1.20;
    option domain-name-servers 8.8.8.8;
    option routers 1.1.1.1;
    option broadcast-address 1.1.1.255;
    default-lease-time 600;
    max-lease-time 7200;
    log-facility local7;
}

subnet 2.2.2.0 netmask 255.255.255.0 {
    range 2.2.2.100 2.2.2.200;
    option domain-name-servers 114.114.114.114;
    option routers 2.2.2.1;
    option broadcast-address 2.2.2.255;
    default-lease-time 600;
    max-lease-time 7200;
    log-facility local7;
}

注意:subnet 声明的网段必须与服务器某块网卡所在网段匹配,否则 dhcpd 无法启动。实际实验时应将 subnet 网段改为 vmnet1 所在网段(如 192.168.62.0/24)。

启动服务:

/etc/init.d/dhcpd restart        # CentOS 6
systemctl restart dhcpd          # CentOS 7

第三步:客户端获取 IP

/etc/init.d/network restart
# 或
dhclient eth0

这次应能成功获取 IP。

第四步:验证

客户端:

# 1. 查看 IP 是否在地址池范围内
ifconfig

# 2. 查看 DNS 与网关
cat /etc/resolv.conf
route -n

# 3. 查看客户端租约文件与日志
cat /var/lib/dhclient/dhclient-eth0.leases
cat /var/log/messages | grep dhcp

服务端:

# 4. 查看服务端分配记录
cat /var/lib/dhcpd/dhcpd.leases

第五步:追加固定地址保留并验证

在配置文件中追加:

host vmware {
    hardware ethernet 00:0c:29:df:da:d4;
    fixed-address 2.2.2.188;
}

重启服务后在客户端重新获取 IP,确认拿到的是 2.2.2.188:

/etc/init.d/dhcpd restart      # 服务端
dhclient -r eth0; dhclient -v eth0    # 客户端

4.9 运维注意事项

  1. 避免 IP 冲突:DHCP 地址池范围不要与已静态分配的 IP 重叠。
  2. 持久化网络配置:ip 和 brctl 命令均为临时配置,重启后需通过配置文件或网络管理工具持久化。
  3. 网卡归属唯一:同一网卡不能同时属于多个网桥。
  4. DHCP 服务器自身 IP 需静态配置:DHCP 服务器本身应使用静态 IP,不能依赖自己分配地址。
  5. 防火墙与 SELinux:确保 DHCP 端口(UDP 67/68)放行,必要时调整 SELinux 策略。
  6. 一个广播域内只应有一台 DHCP 服务器(除非做高可用主备),并在交换机上启用 DHCP Snooping 防私接。
  7. 租期设置要匹配场景:终端流动性大的网络用短租期,固定办公终端用长租期。
  8. 变更前先备份:修改 dhcpd.conf 前先 cp 备份,修改后先 dhcpd -t 检查再重启。

4.10 练习

练习一:搭建基本 DHCP 服务器

  1. 配置本地 yum 源(挂载 ISO)。
  2. 准备服务器和客户机环境,连接到同一网桥。
  3. 关闭防火墙并设置 SELinux 为 Permissive。
  4. 配置服务器网卡 IP 为 3.3.3.1/24。
  5. 安装 dhcp 软件包。
  6. 编辑 /etc/dhcp/dhcpd.conf,声明 3.3.3.0/24 子网,分配范围 3.3.3.101 - 3.3.3.254,并指定网关、子网掩码、DNS 等选项。
  7. 重启 dhcpd 服务(CentOS 6 用 service dhcpd restart,CentOS 7 用 systemctl restart dhcpd)。
  8. 在客户机上通过配置文件或 dhclient 获取 IP,验证分配结果。

参考答案(关键配置与命令):

mount -ro loop /dev/cdrom /mnt
iptables -F; iptables -P INPUT ACCEPT; setenforce 0
ip a add 3.3.3.1/24 dev ens3
yum install dhcp -y
vim /etc/dhcp/dhcpd.conf
dhcpd -t
systemctl restart dhcpd && systemctl enable dhcpd
# 客户端
dhclient -v ens3 && ip a s
allow bootp;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;
subnet 3.3.3.0 netmask 255.255.255.0 {
        option routers                  3.3.3.1;
        option subnet-mask              255.255.255.0;
        option domain-name              "abc.com";
        option domain-name-servers      223.5.5.5;
        range dynamic-bootp 3.3.3.101 3.3.3.254;
}

练习二:为多局域网分配 IP

  1. 创建 net1、net2 两个虚拟网络(不启用 DHCP)。
  2. 服务器配置双网卡,分别接入两个网络,IP 为 10.1.1.1/24、10.1.2.1/24。
  3. 两台客户机分别接入 net1、net2。
  4. 在 dhcpd.conf 中声明两个子网及其地址池。
  5. 重启 dhcpd 服务。
  6. 分别在两台客户机上获取 IP,验证属于各自网段。

参考答案:见 4.8 实验二的完整配置,关键点是并列书写两个 subnet 块,且服务器两块网卡的 IP 分别落在两个网段内。

练习三:固定地址保留(IP/MAC 绑定)

要求:让 MAC 为 00:0c:29:df:da:d4 的客户机每次都获得 2.2.2.188。

参考答案:

host vmware {
    hardware ethernet 00:0c:29:df:da:d4;
    fixed-address 2.2.2.188;
}

重启 dhcpd,客户端执行 dhclient -r eth0; dhclient -v eth0 后用 ip a s 验证。注意 2.2.2.188 不应落在 range 2.2.2.100 2.2.2.200 之内,本例中需把 range 改小(如 2.2.2.100 2.2.2.180)或把保留地址改到池外。

练习四:观察租约续订过程

要求:把租期设为 120 秒,抓包观察 T1(约第 60 秒)时客户端发起的单播续租。

参考答案:

default-lease-time 120;
max-lease-time 240;
# 服务端重启
systemctl restart dhcpd
# 客户端抓包(另开终端)
tcpdump -i eth0 -nn port 67 or port 68
# 客户端获取地址
dhclient -v eth0
# 查看 renew / rebind / expire 三个时间点
grep -E "renew|rebind|expire" /var/lib/dhclient/dhclient-eth0.leases

约 60 秒后可看到客户端向服务器发出的单播 REQUEST 与服务器的 ACK(无 DISCOVER/OFFER 阶段),验证 T1 = 50%。

练习五:部署 DHCP 中继

要求:DHCP 服务器在 192.168.20.10,客户端在 192.168.10.0/24,通过一台双网卡主机中继。

参考答案要点:

# 中继主机
sysctl -w net.ipv4.ip_forward=1
dhcrelay -d -i eth0 192.168.20.10
# DHCP 服务器 /etc/dhcp/dhcpd.conf
subnet 192.168.20.0 netmask 255.255.255.0 { }
subnet 192.168.10.0 netmask 255.255.255.0 {
    range 192.168.10.100 192.168.10.200;
    option routers 192.168.10.1;
    option domain-name-servers 223.5.5.5;
}

验证:服务端日志中出现 DHCPDISCOVER from ... via 192.168.10.1,客户端拿到 192.168.10.x 地址。

练习六:排错演练

分别人为制造以下故障并用本文的排错清单定位:

  1. 删掉某行末尾的分号 → dhcpd -t 报 semicolon expected;
  2. 把 subnet 网段改成与服务器网卡不匹配 → 日志报 No subnet declaration for ...;
  3. 打开 iptables 并拦截 UDP 67 → 抓包只见 Request 无 Reply;
  4. 在同网段另起一台 DHCP 服务器 → 客户端租约中 dhcp-server-identifier 随机变化。

附录 A:实验相关的网络基础命令

A.1 IP 地址与路由配置(ip 命令)

ip 命令支持缩写:l = link,a = address,r = route。

命令 作用
ip l 查看网卡(链路)信息
ip a s 查看 IP 地址信息
ip r 查看路由表
ip a add 192.168.0.183/24 dev enp0s25 给指定网卡添加 IP 地址
ip a del 192.168.0.183/24 dev enp0s25 删除指定网卡的 IP 地址
ip l set enp0s25 up 启用网卡
ip l set enp0s25 down 停用网卡
ip r add default via 192.168.0.1 添加默认路由
ip r del default 删除默认路由
ip r change default via 192.168.0.1 修改默认路由
ip l                                        # 查看网卡
ip a s                                      # 查看 IP
sudo ip a add 192.168.0.183/24 dev enp0s25  # 给网卡添加 IP
sudo ip a del 192.168.0.183/24 dev enp0s25  # 从网卡上删除 IP
sudo ip l set enp0s25 up                    # 启用网卡
sudo ip l set enp0s25 down                  # 停用网卡
sudo ip r add default via 192.168.0.1       # 添加默认路由
sudo ip r del default                       # 删除默认路由
sudo ip r change default via 192.168.0.1    # 修改默认路由

注意:ip 命令配置的地址和路由在系统重启后会失效。如需持久化,请写入网卡配置文件或配置网络管理工具(NetworkManager、/etc/network/interfaces、systemd-networkd)。

A.2 Linux 下网桥(Bridge)的设置

网桥(Bridge)用于将多个网络接口连接成一个二层局域网。在 KVM 虚拟化场景中,网桥可将虚拟机网络与物理网络桥接,使虚拟机与物理机处于同一个大的局域网,因此 DHCP 实验中常用网桥把服务器与客户机放在同一广播域。使用 brctl 命令管理网桥。

命令 作用
sudo brctl show 列出所有网桥
sudo brctl addbr br0 创建网桥 br0
sudo brctl delbr br0 删除网桥 br0
sudo brctl addif br0 enp0s25 将网卡加入网桥
sudo brctl delif br0 enp0s25 将网卡从网桥中移除
sudo brctl show                  # 列出所有的网桥
sudo brctl addbr br0             # 添加网桥
sudo brctl delbr br0             # 删除网桥
sudo brctl addif br0 enp0s25     # 把网卡加入网桥中
sudo brctl delif br0 enp0s25     # 从网桥中删除网卡

重要注意事项:

  • 一个网卡只能属于一个网桥。
  • 在 Linux 系统中创建桥并把网卡加入桥之后,后续所有联网操作都通过这个网桥,可以把网桥想象成原来的那个网卡。
  • 把网卡加入桥之后,应该给网桥设置 IP 地址,而不是继续给原物理网卡配置 IP。

配置范例

假设系统中没有网桥,只有一块网卡 enp0s25,IP 为 192.168.0.183/24,默认网关为 192.168.0.1。现创建桥 br0 使系统通过桥上网:

步骤 1:删除原网卡上的 IP 地址

sudo ip a del 192.168.0.183/24 dev enp0s25

步骤 2:创建网桥(br0 名称可自定义)

sudo brctl addbr br0

步骤 3:将原网卡加入网桥

sudo brctl addif br0 enp0s25

步骤 4:给网桥设置 IP 地址并启用,根据需要设置默认网关

sudo ip a add 192.168.0.183/24 dev br0
sudo ip l set br0 up                    # 某些环境下加 IP 后会自动激活,这一步可能不需要
sudo ip r add default via 192.168.0.1

附录 B:命令速查

# ===== 网络查看 =====
ip l                        # 查看网卡
ip a s                      # 查看 IP
ip r                        # 查看路由
ifconfig                    # CentOS 6 常用
route -n                    # 查看路由(旧命令)

# ===== 网桥管理 =====
sudo brctl show
sudo brctl addbr br0
sudo brctl delbr br0
sudo brctl addif br0 enp0s25
sudo brctl delif br0 enp0s25

# ===== 安装 =====
yum install dhcp -y                 # CentOS 6 / 7
yum install dhcp-server -y          # CentOS 8+
apt-get install -y isc-dhcp-server  # Debian / Ubuntu
cp /usr/share/doc/dhcp*/dhcpd.conf.example /etc/dhcp/dhcpd.conf

# ===== 配置检查 =====
dhcpd -t                            # 语法检查
dhcpd -t -cf /etc/dhcp/dhcpd.conf
dhcpd -d -f                         # 前台运行看报错

# ===== 服务管理(CentOS 6)=====
service dhcpd start|stop|restart|status
/etc/init.d/dhcpd restart
chkconfig dhcpd on
chkconfig --list dhcpd

# ===== 服务管理(CentOS 7)=====
systemctl start|stop|restart|status dhcpd
systemctl enable dhcpd
systemctl enable --now dhcpd
systemctl is-enabled dhcpd

# ===== 防火墙(CentOS 6 / iptables)=====
iptables -I INPUT -p udp --dport 67 -j ACCEPT
service iptables save
iptables -F; iptables -P INPUT ACCEPT
chkconfig iptables off

# ===== 防火墙(CentOS 7 / firewalld)=====
firewall-cmd --permanent --add-service=dhcp
firewall-cmd --permanent --add-port=67/udp
firewall-cmd --reload
firewall-cmd --list-all
systemctl stop firewalld

# ===== SELinux =====
getenforce
setenforce 0
sestatus

# ===== 状态与租约 =====
ps -ef | grep dhcpd
netstat -anup | grep 67
cat /var/lib/dhcpd/dhcpd.leases
cat /var/lib/dhclient/dhclient-eth0.leases

# ===== 日志 =====
tail -f /var/log/messages | grep dhcpd
journalctl -u dhcpd -f
tail -f /var/log/dhcpd.log          # 配置 local7 到独立文件后

# ===== 客户端(Linux)=====
dhclient eth0
dhclient -v ens3
dhclient -r ens3                    # 释放租约
pkill dhclient
service network restart             # CentOS 6
systemctl restart network           # CentOS 7

# ===== 客户端(Windows)=====
# ipconfig /all
# ipconfig /release
# ipconfig /renew
# ipconfig /flushdns

# ===== 中继 =====
sysctl -w net.ipv4.ip_forward=1
dhcrelay -i eth0 192.168.20.10
dhcrelay -d -i eth0 192.168.20.10

# ===== 抓包 =====
tcpdump -i eth0 port 67 or port 68
tcpdump -i eth0 -nn -e port 67 or port 68
tcpdump -i eth0 -nn -w /tmp/dhcp.pcap port 67 or port 68
nmap --script broadcast-dhcp-discover

附录 C:角色任务小结

角色 典型操作
DHCP 服务端 静态配置网卡 IP → 安装 dhcp → 配置 subnet / range / option → dhcpd -t 检查 → 启动并设开机自启 → 放行防火墙与 SELinux → 通过 /var/lib/dhcpd/dhcpd.leases 与 /var/log/messages 查看分配情况
DHCP 客户端 网卡 BOOTPROTO=dhcp 后重启网络,或用 dhclient -v eth0 临时获取;通过 ip a s、cat /etc/resolv.conf、ip r、/var/lib/dhclient/ 验证
DHCP 中继 开启 ip_forward → 运行 dhcrelay -i <客户端侧网卡> <服务器IP> → 服务端为远端网段声明 subnet
PXE 装机配合 DHCP 中加 next-server 与 filename,配合 TFTP 与安装源(详见 14-05-PXE与Cobbler批量装机.md)
最后修改:2026 年 09 月 20 日
如果觉得我的文章对你有用,请随意赞赏