从零搭建多子网 DHCP 服务:CentOS 双网卡多作用域实战与原理解析

摘要

本文把你给出的片段整理成一篇完整的技术文章:在一台 CentOS/RHEL 系列服务器上部署一个支持两个子网(192.168.10.0/24 和 192.168.100.0/24)的 DHCP 服务。文章会给出实用场景、完整且修正后的 dhcpd.conf 配置、网卡持久化配置方法、逐行代码解析、测试示例与结果,以及 DHCP 服务在运行时的复杂度分析。语言尽量口语化,像在写给同组同学的运维笔记------能看懂、能上手、能复现。

描述

假设你在一个院系实验室或一个小型公司里,需要把两片网络同时交给同一台 DHCP 服务器管理:

  • 子网 A(教师/管理网络)192.168.10.0/24,网关 192.168.10.2,DHCP 分配范围 192.168.10.5--192.168.10.254
  • 子网 B(学生/访客网络)192.168.100.0/24,网关 192.168.100.2,DHCP 分配范围 192.168.100.5--192.168.100.254

服务器有两块网卡 ens160(连接子网 A)和 ens36(连接子网 B)。我们要做到:

  1. 网卡地址配置持久化(否则 ifconfig / ip addr add 重启后会丢失)。
  2. 配置 dhcpd 来为两个子网提供地址池、网关、DNS、域名等信息。
  3. 启动并使 DHCP 服务随系统启动,同时给出测试方法和预期结果。

适用场景举例:

  • 大学实验室:教师与学生分网,教师网段用于教师机和服务器,学生网段用于学生终端。
  • 小公司:办公网和访客网共用一台机箱式设备提供 DHCP。
  • 虚拟化环境:一台虚拟机管理多张虚拟网卡,将多个 VLAN/子网的 DHCP 服务统一管理。

题解答案

要点如下:

  1. 持久配置网卡 :不要只用 ifconfig / ip 命令即时配置。编辑网卡配置文件(CentOS7/8 通常在 /etc/sysconfig/network-scripts/ifcfg-<ifname>)或用 nmcli/NetworkManager 来做持久化配置。
  2. 修正并写好 dhcpd.conf:原文中有语法和数字错误(例如 netmask 写错、逗号和点混用、括号不配对)。需要一份合法的、能同时定义两个 subnet 的配置文件。
  3. 启动并设置开机自启systemctl enable --now dhcpd;同时根据网络环境调整防火墙(允许 UDP 67/68)和 SELinux(必要时配置策略或设置 permissive)。
  4. 测试 :在客户端 dhclient -v 或在服务器上用 dhcpd -t 测试配置语法,用 journalctl -u dhcpd -f 查看运行日志。

接下来给出完整示例和逐行分析。

题解代码

下面包含:网卡持久化配置示例(CentOS 风格)、dhcpd.conf 文件内容、启动与防火墙操作、测试命令。

网卡持久化配置(CentOS 系列,/etc/sysconfig/network-scripts/ifcfg-*

ens160(192.168.10.1) 和 ens36(192.168.100.1)做持久配置:

/etc/sysconfig/network-scripts/ifcfg-ens160

复制代码
TYPE=Ethernet
BOOTPROTO=none
NAME=ens160
DEVICE=ens160
ONBOOT=yes
IPADDR=192.168.10.1
PREFIX=24
GATEWAY=192.168.10.2
DNS1=192.168.10.2
NM_CONTROLLED=no

/etc/sysconfig/network-scripts/ifcfg-ens36

复制代码
TYPE=Ethernet
BOOTPROTO=none
NAME=ens36
DEVICE=ens36
ONBOOT=yes
IPADDR=192.168.100.1
PREFIX=24
GATEWAY=192.168.100.2
DNS1=192.168.100.2
NM_CONTROLLED=no

说明:

  • BOOTPROTO=none:静态地址。
  • ONBOOT=yes:开机激活。
  • PREFIX=24 等同 netmask=255.255.255.0
  • NM_CONTROLLED=no 表示不被 NetworkManager 管控(如果使用 NetworkManager 可用 nmcli 配置替代)。

应用:

bash 复制代码
# 重新加载网卡配置(或重启网络服务)
nmcli connection reload  # 如果使用 NetworkManager
# 或
ifdown ens160 && ifup ens160
ifdown ens36 && ifup ens36
# 或重启网络(CentOS7+)
systemctl restart network

DHCP 主配置文件 /etc/dhcp/dhcpd.conf

下面是修正、格式良好的 dhcpd.conf

conf 复制代码
ddns-update-style none;
ignore client-updates;

option domain-name "test.org";
option domain-name-servers 192.168.10.2, 192.168.100.2;

default-lease-time 21600;    # 默认租约 6 小时
max-lease-time 43200;        # 最大租约 12 小时

# 子网 A:192.168.10.0/24
subnet 192.168.10.0 netmask 255.255.255.0 {
    option routers 192.168.10.2;
    option subnet-mask 255.255.255.0;
    option nis-domain "test.org";
    option time-offset -18000;    # 时间偏移,示例值
    range dynamic-bootp 192.168.10.5 192.168.10.254;
}

# 子网 B:192.168.100.0/24
subnet 192.168.100.0 netmask 255.255.255.0 {
    option routers 192.168.100.2;
    option subnet-mask 255.255.255.0;
    option nis-domain "test.org";
    option time-offset -18000;
    range dynamic-bootp 192.168.100.5 192.168.100.254;
}

注意点

  • 保证括号 {} 成对出现并语法正确。
  • option domain-name-servers 我用两个地址,用逗号分隔。
  • range 的 IP 要写成 192.168.x.5 形式,之前原文有逗号或错别字。
  • 如果服务器只有一块网卡并且通过 VLAN/路由去管理多个子网,则需要确保 DHCP 请求能到达服务器(通常需要中继 agent / DHCP relay)。本示例假设服务器同时直连两个子网(两张网卡)。

启动 DHCP 服务并设置开机自启

bash 复制代码
# 安装(如果还没装)
# yum install -y dhcp-server    # CentOS/RHEL
# 或 dnf install -y dhcp-server

# 启动并设置开机自启
systemctl enable --now dhcpd

# 指定监听接口(可选):
# 编辑 /etc/sysconfig/dhcpd,将 INTERFACES="ens160 ens36" 写入
echo 'INTERFACES="ens160 ens36"' > /etc/sysconfig/dhcpd
systemctl restart dhcpd

防火墙开放

bash 复制代码
# 允许 DHCP 服务端口(UDP 67, 客户端 68)
firewall-cmd --add-port=67/udp --permanent
firewall-cmd --add-port=68/udp --permanent
firewall-cmd --reload

或者使用服务名:

bash 复制代码
firewall-cmd --add-service=dhcp --permanent
firewall-cmd --reload

SELinux 注意

如果 SELinux 启用并阻止 dhcpd,可以查看 audit.log 并针对性放行或临时设为 permissive 测试。不要轻易永久关闭 SELinux,推荐按审计告警配置策略。

题解代码分析

下面把关键片段逐项解释,方便理解每项配置的作用与为什么要这样写。

ifcfg 文件

  • TYPE=Ethernet:接口类型。
  • BOOTPROTO=none:不使用 DHCP 客户端,使用静态 IP。
  • DEVICE=ens160:设备名。
  • ONBOOT=yes:系统启动时启用该接口。
  • IPADDR / PREFIX:IP 与前缀长度。PREFIX=24 等同 NETMASK=255.255.255.0
  • GATEWAY:默认网关;如果机器本身不做路由,可省略或配置在路由表。
  • NM_CONTROLLED=no:如果这个设置为 yes,NetworkManager 会管理该接口;根据你的运维习惯选用。

为什么这样?直接 ifconfig/ip addr add 的改动只在内存中,重启后丢失。写入系统的配置文件可以保证重启生效。

dhcpd.conf 主体

  • ddns-update-style none;:禁用动态 DNS 更新(如果没有 DNS 动态更新需求可以关)。
  • ignore client-updates;:服务器忽略客户端试图更新 DNS 的请求。
  • option domain-name "test.org";:下发给客户端的域名配置。
  • option domain-name-servers 192.168.10.2, 192.168.100.2;:DNS 服务器地址(多个用逗号)。
  • default-lease-time / max-lease-time:默认与最大租期,以秒计。根据使用场景调整(比如访客网用短租期,管理网用长租期)。
  • subnet ... { ... }:定义一个子网作用域。每个 subnet 块里可以指定路由器(网关)、子网掩码、时间偏移、地址分配范围等。
  • range dynamic-bootp x.x.x.5 x.x.x.254;:地址池,这里给出从 .5.254 的可分配地址。.1.2 等通常留给静态设备(服务器、网关)。

常见错误来源:

  • 写错 netmask(例如 255.285.495.0)或把点改成逗号(192,168,100.5),会导致 dhcpd 启动失败。启动前用 dhcpd -t 检查语法。

/etc/sysconfig/dhcpd 的 INTERFACES

有时 dhcpd 会监听所有接口或指定接口。把 INTERFACES="ens160 ens36" 写进去可以避免 dhcpd 在不希望的接口上监听或者在系统上没有自动发现接口时失败。

示例测试及结果

下面给出实际验证步骤与预期输出示例(你可以在服务器和一台客户端上执行这些命令来验证)。

检查配置语法

bash 复制代码
# 语法检查(注意:dhcpd -t 需要 root 权限)
dhcpd -t -cf /etc/dhcp/dhcpd.conf

预期:没有输出且返回码 0;如果有语法错误会报告具体行号。

启动并查看日志

bash 复制代码
systemctl restart dhcpd
journalctl -u dhcpd -f

预期日志片段(大概类似):

复制代码
dhcpd[1234]: DHCPDISCOVER from 00:11:22:33:44:55 via ens160
dhcpd[1234]: DHCPOFFER on 192.168.10.10 to 00:11:22:33:44:55 via ens160
dhcpd[1234]: DHCPREQUEST for 192.168.10.10 (192.168.10.1) from 00:11:22:33:44:55 via ens160
dhcpd[1234]: DHCPACK on 192.168.10.10 to 00:11:22:33:44:55 via ens160

这说明客户端通过 ens160 成功申请到 IP。

在客户端请求 DHCP

bash 复制代码
# 先释放再请求
dhclient -r
dhclient -v

预期输出片段

复制代码
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3
DHCPOFFER from 192.168.10.1
DHCPREQUEST on eth0 to 255.255.255.255 port 67
DHCPACK from 192.168.10.1
bound to 192.168.10.10 -- renewal in 10800 seconds.

然后用 ip addr show eth0 能看到分配到的 IP。

查看租约文件

DHCP 的租约通常保存在 /var/lib/dhcpd/dhcpd.leases(路径可能因系统不同而异):

bash 复制代码
cat /var/lib/dhcpd/dhcpd.leases

你会看到类似下面的块:

复制代码
lease 192.168.10.10 {
  starts 2 2025/11/01 10:00:00;
  ends 2 2025/11/01 16:00:00;
  tstp 2 2025/11/01 16:00:00;
  cltt 2 2025/11/01 10:00:00;
  binding state active;
  next binding state free;
  hardware ethernet 00:11:22:33:44:55;
}

这能帮助你核查租约分配历史。

时间复杂度

在这里的"算法复杂度"我们用来衡量 DHCP 服务器在处理租约和请求时的伸缩性,主要关注以下操作:

  1. 查找已存在租约(按 MAC 或 IP):多数 DHCP 实现会把活跃租约放到哈希表或类似结构里以便快速查找。

    • 平均复杂度:O(1)(哈希查找)
    • 最坏情况:O(n)(极端哈希冲突或没有哈希结构时线性查找)
  2. 分配一个新地址:如果实现用位图或池并记录下一个可用指针,分配通常很快。

    • 平均复杂度:O(1)
    • 最坏情况:O(n)(如果需要扫描整个池来找一个空闲地址)
  3. 回收租约 / 清理过期租约:如果周期性进行线性扫描则为 O(n),若采用事件驱动或时间轮(priority queue),可做得更优。

    • 常见实现:保留一个时间索引或优先队列,回收操作是 O(log n)(优先队列)或 amortized O(1)。

总结:现实中对常见规模的网络(几百到几千台)来说,DHCP 的查找与分配操作基本上是常数平均时间;只有在数万设备且实现不佳时,性能问题才显现。

空间复杂度

空间开销主要来自以下几部分:

  1. 租约表:通常按客户端数(n)存储记录,每条记录包含 IP、MAC、租约时间、状态等信息。

    • 空间复杂度:O(n)。
  2. 地址池本身:地址池可以视作固定大小(m = 地址数量),通常是位图或区间列表。

    • 空间复杂度:O(m)。

总体:O(n + m)。在大多数小规模场景(几百台客户端、池大小数百)内,内存消耗极小。

总结

最后总结一些在实际部署时常遇到的问题和建议:

  1. 不要用即时命令替代持久化配置ifconfig/ ip addr add 仅临时,开机会丢。养成编辑 /etc/sysconfig/network-scripts/ifcfg-* 或使用 nmcli 的习惯。

  2. 配置文件语法检查 :配置 dhcpd.conf 后先用 dhcpd -tdhcpd -cf /etc/dhcp/dhcpd.conf -t 做语法检查,避免服务无法启动。

  3. 接口监听问题 :如果 dhcpd 没有在正确接口上监听,检查 /etc/sysconfig/dhcpdINTERFACES 配置,或系统日志里面的错误提示。

  4. 防火墙 / 中继(relay):如果客户端和服务器不在同一网段,需要在路由器上配置 DHCP 中继(DHCP relay),否则 DHCP 请求不会穿子网。并确保防火墙放通 UDP 67/68。

  5. 租期策略 :对访客网使用较短租期(例如 1 小时),对固定办公设备使用长租期或直接静态分配和保留(host 配置块)。

  6. 静态保留(按 MAC) :如果某些设备必须获得固定 IP,可以在 dhcpd.conf 中使用 host 块绑定 MAC 与 IP。示例:

    conf 复制代码
    host printer01 {
        hardware ethernet 00:11:22:33:44:66;
        fixed-address 192.168.10.20;
    }
  7. 日志排查journalctl -u dhcpd -f/var/log/messages(或系统对应日志)是最直接的排查点。检查常见错误比如 "no subnet declaration for " 表示请求来自未配置的子网。

相关推荐
A小辣椒20 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式