WinDHCPD 教程:Windows 原生 DHCP 服务器(Python + Scapy)
局域网里没有 DHCP 服务器,几十台电脑就得一台一台手工配 IP;换了网段、加了新设备,改配置能改到手软。WinDHCPD 就是为了解决这个问题的:一个基于 Python 3 + Scapy 的轻量级 DHCP 服务器,跑在 Windows 上,不用装 Windows Server,不用配复杂的 DHCP 角色,改一个 YAML 配置文件就能给整个网段自动分配 IP,还自带 Web 管理面板看租约和统计。本教程从前置条件、安装、配置讲到跨网段 Relay 和故障排查,照着做就能跑起来。
一、项目简介
WinDHCPD 是 AI-Agent 组织下的开源项目(Python,master 分支),在 Windows 上以管理员权限运行,用 Scapy 捕获和发送 DHCP 数据包,用 Flask 提供 Web 管理面板。它的定位很明确:轻量、可移植、够用——不是要替代 Windows Server DHCP 或 ISC DHCP,而是给实验室、临时组网、小型办公网、装机现场这些场景提供一个随开随用的 DHCP 服务。
整个项目结构非常简单,只有十几个文件,核心逻辑集中在 dhcpd/ 目录:
win-dhcpd/
├── run.py # 入口脚本
├── dhcpd.yaml.example # 配置文件示例
├── requirements.txt # Python 依赖
├── dhcpd/
│ ├── config.py # 配置加载与校验
│ ├── lease.py # 租约数据库(内存 + JSON 持久化)
│ ├── parser.py # DHCP 包解析与构建(Scapy)
│ ├── server.py # DHCP 服务器主循环(Sniffer + 响应)
│ └── web/
│ ├── app.py # Flask Web 面板
│ └── templates/
│ └── index.html # 管理界面(深色主题,自动刷新)
注意:WinDHCPD 只处理 IPv4 DHCP,不支持 IPv6 和 DHCPv6。如果网络需要 IPv6 地址分配,请配置 SLAAC 或单独部署 DHCPv6 服务器。
二、功能特性
| 功能 | 说明 |
|---|---|
| 完整 DORA 握手 | DISCOVER → OFFER → REQUEST → ACK,符合 RFC 2131 |
| 多作用域 | 支持多个网段(/24),可通过 DHCP Relay 跨网段服务 |
| 静态绑定 | MAC → IP 固定分配,优先于动态分配 |
| 租约管理 | 内存索引 + JSON 持久化,支持释放、续租、清理过期 |
| Web 管理面板 | Flask 面板,实时查看租约、作用域、统计(端口 8080) |
| NACK 拒绝 | 对不合法请求返回 NACK |
| 日志记录 | 控制台 + 文件双输出 |
其中最值得说的是两点。第一是多作用域 + Relay:一个 WinDHCPD 实例可以同时服务多个网段,配合路由器的 DHCP Relay(ip helper-address),跨网段的客户端也能拿到地址。第二是静态绑定优先:打印机、服务器、NAS 这类需要固定 IP 的设备,用 MAC 绑定写死,动态池再怎么分配也不会抢走它的地址。
三、适用场景
- 实验室与测试环境:临时搭一个网段做测试,几分钟就能让所有测试机自动获取 IP,用完即停。
- 装机与 PXE 批量部署现场:配合 PXE 引导做批量装机,DHCP 是前置条件,WinDHCPD 比现搭一套 Windows Server DHCP 快得多。
- 小型办公网 / 门店网络:没有专业网管设备时,一台常开的 Windows 电脑就能承担 DHCP 职责。
- 教学与协议学习:代码量小、结构清晰,读
parser.py和server.py就能理解 DHCP 协议的完整交互过程。 - 多网段分支机构:总部一台 WinDHCPD,通过各分支路由器的 Relay 统一给多个网段分配地址。
不适用场景也要说清楚:大型生产网络、需要高可用(主备切换)的环境、需要与 AD 域深度集成的场景,应该用 Windows Server DHCP 或 ISC DHCP。WinDHCPD 是单进程服务,没有高可用机制,机器一挂,整个网段的客户端就拿不到新地址(已拿到租约的客户端在租期内不受影响)。
四、工作原理:DORA 四步握手
DHCP 分配地址的过程叫 DORA,是四个报文的往返。理解这个流程,排障时才知道该看哪一步。
| 步骤 | 报文 | 方向 | 作用 |
|---|---|---|---|
| 1. Discover | DHCPDISCOVER | 客户端 → 广播 | 客户端上线,大喊“有没有 DHCP 服务器?” |
| 2. Offer | DHCPOFFER | 服务器 → 广播 | WinDHCPD 从地址池挑一个空闲 IP 发过去 |
| 3. Request | DHCPREQUEST | 客户端 → 广播 | 客户端确认“我就要这个 IP” |
| 4. Ack | DHCPACK | 服务器 → 广播 | WinDHCPD 确认分配,写入租约数据库 |
客户端 服务器
│ │
│ DHCPDISCOVER (广播) │
│ ─────────────────────► │
│ │ 分配 IP → 发 OFFER
│ DHCPOFFER (广播) │
│ ◄────────────────────── │
│ │
│ DHCPREQUEST (广播) │
│ ─────────────────────► │
│ │ 更新租约 → 发 ACK
│ DHCPACK (广播) │
│ ◄────────────────────── │
│ │
│ DHCPRELEASE │
│ ─────────────────────► │ 释放 IP
租约到期前客户端会主动续租(REQUEST),WinDHCPD 更新租约即可;客户端关机或执行 ipconfig /release 时会发 RELEASE,服务器把地址放回地址池。租约过期后也会被清理,地址重新进入可分配状态。
五、前置条件:Python 与 Npcap
跑 WinDHCPD 之前要装好两样东西,缺一不可。
5.1 安装 Python 3.8+
Windows 上安装 Python 3.8 或更高版本,安装时勾选 Add Python to PATH,装完验证:
python --version
# Python 3.11.x
pip --version
5.2 安装 Npcap(Scapy 的依赖)
Scapy 在 Windows 上需要 Npcap 来捕获和发送网络数据包。下载地址是 https://nmap.org/npcap/,安装时必须勾选 "Install Npcap in WinPcap API-compatible Mode",否则 Scapy 找不到发包接口。其他选项默认安装即可。
5.3 安装 Python 依赖
pip install -r requirements.txt
依赖只有三个,作用各不相同:
- scapy(≥2.5):网络数据包捕获与发送,DHCP 报文的解析与构建都靠它。
- flask(≥3.0):Web 管理面板。
- pyyaml(≥6.0):配置文件解析。
六、安装与快速开始
6.1 创建配置文件
copy dhcpd.yaml.example dhcpd.yaml
编辑 dhcpd.yaml,把作用域(网段、地址池、网关、DNS)改成实际网络参数。配置格式见第七节。
6.2 以管理员身份运行
必须使用管理员权限,因为捕获 UDP 67 端口的广播数据包需要特权。右键命令提示符选择“以管理员身份运行”,再执行:
# 默认启动(使用 dhcpd.yaml)
python run.py
# 指定配置文件
python run.py dhcpd.yaml
# 指定监听网卡(多网卡机器必备)
python run.py dhcpd.yaml -i "以太网"
# 禁用 Web 面板
python run.py dhcpd.yaml --no-web
# 指定 Web 端口
python run.py dhcpd.yaml --web-port 9000
6.3 访问 Web 面板
服务启动后,打开浏览器访问 http://localhost:8080,就能看到租约、作用域和统计信息。面板是深色主题、自动刷新,不用手动点刷新就能看到新上线的客户端。
6.4 客户端验证
# 客户端先释放旧地址,再重新获取
ipconfig /release
ipconfig /renew
# 查看拿到的地址、网关、DNS 和租期
ipconfig /all
七、配置文件详解
一份完整的 dhcpd.yaml 如下,覆盖了服务器、作用域、静态绑定和日志的全部配置项:
# ── 服务器设置 ──
server:
ip: "192.168.1.1" # DHCP 服务器 IP(响应包中的 server_id)
# ── 作用域 ──
scopes:
- name: "Office-LAN" # 作用域名称
network: "192.168.1.0/24"
start_ip: "192.168.1.100"
end_ip: "192.168.1.200"
subnet_mask: "255.255.255.0"
router: "192.168.1.1"
dns_servers:
- "8.8.8.8"
- "114.114.114.114"
lease_seconds: 86400 # 租期 24 小时
domain: "local"
enable: true
# ── 静态绑定 ──
bindings:
- mac: "aa:bb:cc:dd:ee:01"
ip: "192.168.1.10"
scope: "Office-LAN"
hostname: "printer"
# ── 其他 ──
log_file: "dhcpd.log"
log_level: "INFO" # DEBUG / INFO / WARNING / ERROR
web_host: "0.0.0.0"
web_port: 8080
# interface: "以太网" # 可选:指定监听网卡
| 参数 | 说明 | 示例 |
|---|---|---|
| server.ip | DHCP 服务器自身 IP | 192.168.1.1 |
| scopes[].network | 网段(CIDR) | 192.168.1.0/24 |
| scopes[].start_ip | 地址池起始 | 192.168.1.100 |
| scopes[].end_ip | 地址池结束 | 192.168.1.200 |
| scopes[].router | 默认网关 | 192.168.1.1 |
| scopes[].dns_servers | DNS 服务器列表 | [8.8.8.8, 114.114.114.114] |
| scopes[].lease_seconds | 租期(秒) | 86400(24 小时) |
| bindings[].mac | 静态绑定 MAC | aa:bb:cc:dd:ee:01 |
| bindings[].ip | 静态绑定 IP | 192.168.1.10 |
几个配置要点:地址池不要和静态绑定的 IP 重叠,否则动态分配可能把绑定地址发出去;租期按场景调,流动性大的临时网络可以设短一点(如 3600 秒),固定设备多的办公网设 86400 秒;多网卡机器一定要用 interface 或 -i 指定监听网卡,否则 Scapy 可能监听到错误的网卡上,客户端收不到 OFFER。
八、Web 管理面板
Web 面板默认监听 8080 端口(web_host 默认 0.0.0.0,局域网内其他机器也能访问;只想本机访问可以改成 127.0.0.1)。面板提供三类实时信息:
- 租约列表:当前已分配的 IP、对应 MAC、主机名、租期到期时间。
- 作用域:每个作用域的网段、地址池范围、已用/可用数量。
- 统计:收到的 DISCOVER / REQUEST 数量、分配成功与失败计数。
面板是深色主题、自动刷新,适合挂在第二块屏幕上实时观察。如果不需要面板(比如纯后台运行),启动时加 --no-web 即可;想换端口用 --web-port 9000。
九、网络拓扑:单网段与 DHCP Relay
9.1 场景一:单机 DHCP 服务器
客户端 ────── 交换机/集线器 ────── WinDHCPD (192.168.1.1)
↑ ↑
│ 广播 DISCOVER │ 响应 OFFER/ACK
└────────────────────────────────┘
WinDHCPD 所在的网卡必须是混杂模式或连接在 Hub / 支持组播的交换机上,并且同一网段只能有一个 DHCP 服务器,Windows 自带的 DHCP Server 服务必须关闭,否则两个服务器抢答,客户端会随机拿到其中一方的地址。
9.2 场景二:跨网段(DHCP Relay)
子网 A 客户端 ── 路由器(Relay) ── WinDHCPD (192.168.1.1)
↑
giaddr = 10.0.2.1
跨网段时,DHCP 广播到不了服务器,需要路由器做 DHCP Relay:路由器收到客户端的广播后,把它单播转发给 WinDHCPD,并在报文的 giaddr 字段填上客户端所在网段的网关地址(例如 10.0.2.1)。WinDHCPD 根据 giaddr 判断客户端属于哪个网段,再从对应的作用域里分配地址。路由器上的配置以 Cisco 为例:
# 在客户端所在网段的网关接口上配置
interface GigabitEthernet0/0
ip helper-address 192.168.1.1 # WinDHCPD 的 IP
多作用域的配置方法就是在 scopes 里再加一个网段,network、start_ip、end_ip、router 按新网段填写即可,WinDHCPD 会根据 giaddr 自动选择。
十、常见问题与排查
10.1 客户端获取不到 IP
- 必须以管理员身份运行:UDP 67 端口需要特权,普通权限启动会收不到广播。
- 检查 Npcap 是否安装,且安装时勾选了 WinPcap 兼容模式。
- 确认网卡选择:多网卡机器用
-i "网卡名"指定正确的网卡。 - 同一网段不能有另一个 DHCP 服务器:Windows 自带的 DHCP Server 服务必须关闭。
10.2 如何查看日志
# 实时查看
type dhcpd.log
# 排障时把日志级别改成 DEBUG(配置文件中)
log_level: "DEBUG"
日志是控制台 + 文件双输出,DEBUG 级别会记录每个收发报文的细节,适合定位“客户端发了 DISCOVER 但服务器没响应”这类问题。
10.3 支持 IPv6 吗?支持 DHCPv6 吗?
都不支持。本服务器仅处理 IPv4 DHCP。如需 IPv6 地址分配,请配置 SLAAC 或单独部署 DHCPv6 服务器。
10.4 停止服务器
- 控制台:按
Ctrl+C。 - 任务管理器:结束
python.exe进程。
租约数据自动保存到 leases.db,下次启动时自动加载,已经分配出去的租约不会因为重启而丢失。
十一、安全注意事项与运维建议
DHCP 服务的破坏力比看起来大:一个配错的 DHCP 服务器能让整个网段断网。所以部署前请牢记以下几点:
- 不要在生产网络中直接部署,除非你完全了解后果。先用隔离网络测试,确认无误后再部署。
- 单点故障:这台机器挂了,所有 DHCP 客户端都无法获取新 IP。重要网络请考虑备用方案。
- 冲突风险:同一网段有两个 DHCP 服务器会导致客户端随机获取 IP,网关、DNS 可能被发错。
- 端口监听:服务器会监听 UDP 67 的广播包,Web 面板默认监听 0.0.0.0:8080,内网可达,不需要对外暴露时请把
web_host改成127.0.0.1或用防火墙限制访问来源。 - 定期备份配置和租约:
dhcpd.yaml和leases.db是恢复服务的关键文件,定期备份。 - 日志轮转:长期运行时注意
dhcpd.log的大小,定期清理或轮转。
十二、总结
WinDHCPD 用不到二十个文件就实现了一个完整可用的 DHCP 服务器:RFC 2131 的 DORA 握手、多作用域、静态绑定、租约持久化、Web 面板,一样不少。它的优势是轻——Python + Scapy,不用装 Windows Server 角色,改个 YAML 就能跑;代价是没有高可用和 AD 集成,适合实验室、装机现场、小型办公网这些“够用就好”的场景。按本文的步骤:装 Python 和 Npcap → 复制配置文件 → 管理员身份运行 → 客户端 ipconfig /renew 验证,十分钟就能让一个网段自动分配起地址来。





