552d51df772632ec67693e44ca37a5224842e10b
L2pcapListenSocket on Windows does not support 'stopper' kwarg. Replace with timeout=1.0 polling loop that respects stop_event.
WinDHCPD — Windows 原生 DHCP 服务器
基于 Python 3 + Scapy 实现的轻量级 DHCP 服务器,可在 Windows 上以管理员权限运行。
功能特性
| 功能 | 说明 |
|---|---|
| 完整 DORA 握手 | DISCOVER → OFFER → REQUEST → ACK,符合 RFC 2131 |
| 多作用域 | 支持多个网段(/24),可通过 DHCP Relay 跨网段服务 |
| 静态绑定 | MAC → IP 固定分配,优先于动态分配 |
| 租约管理 | 内存索引 + JSON 持久化,支持释放、续租、清理过期 |
| Web 管理面板 | Flask 面板,实时查看租约、作用域、统计(端口 8080) |
| NACK 拒绝 | 对不合法请求返回 NACK |
| 日志记录 | 控制台 + 文件双输出 |
架构
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 # 管理界面(深色主题,自动刷新)
前置条件
1. 安装 Python 3.8+
确保 Windows 上已安装 Python 3.8 或更高版本。
2. 安装 Npcap(scapy 依赖)
Scapy 在 Windows 上需要 Npcap 来捕获和发送网络数据包:
- 下载:https://nmap.org/npcap/
- 安装时 必须勾选 "Install Npcap in WinPcap API-compatible Mode"
- 默认安装即可
3. 安装依赖
pip install -r requirements.txt
依赖包:
- scapy (≥2.5) — 网络数据包捕获与发送
- flask (≥3.0) — Web 管理面板
- pyyaml (≥6.0) — 配置文件解析
快速开始
1. 创建配置文件
copy dhcpd.yaml.example dhcpd.yaml
编辑 dhcpd.yaml,修改作用域(网段、地址池、网关、DNS)为实际网络参数。
关键参数说明:
| 参数 | 说明 | 示例 |
|---|---|---|
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 |
2. 以管理员身份运行
必须使用管理员权限(捕获端口 67 的广播数据包需要特权):
# Windows 命令行
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
3. 访问 Web 面板
打开浏览器访问:
http://localhost:8080
配置文件详解
# ── 服务器设置 ──
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: "以太网" # 可选:指定监听网卡
网络拓扑要求
场景 1:单机 DHCP 服务器
客户端 ────── 交换机/集线器 ────── WinDHCPD (192.168.1.1)
↑ ↑
│ 广播 DISCOVER │ 响应 OFFER/ACK
└────────────────────────────────┘
- WinDHCPD 所在的网卡必须是 混杂模式 或连接在 Hub/支持组播的交换机上
- 同一网段 只能有一个 DHCP 服务器
场景 2:跨网段(DHCP Relay)
子网 A 客户端 ── 路由器(Relay) ── WinDHCPD (192.168.1.1)
↑
giaddr = 10.0.2.1
- 路由器需配置
ip helper-address <WinDHCPD_IP> - WinDHCPD 通过
giaddr字段确定客户端所在网段,选择对应作用域
工作原理
客户端 服务器
│ │
│ DHCPDISCOVER (广播) │
│ ─────────────────────► │
│ │ 分配 IP → 发 OFFER
│ DHCPOFFER (广播) │
│ ◄────────────────────── │
│ │
│ DHCPREQUEST (广播) │
│ ─────────────────────► │
│ │ 更新租约 → 发 ACK
│ DHCPACK (广播) │
│ ◄────────────────────── │
│ │
│ DHCPRELEASE │
│ ─────────────────────► │ 释放 IP
停止服务器
- 控制台:按
Ctrl+C - 任务管理器:结束
python.exe进程
租约数据自动保存到 leases.db,下次启动时自动加载。
常见问题
Q: 客户端获取不到 IP
- 必须以管理员身份运行 — 端口 67 需要特权
- 检查 Npcap 是否安装 — 且勾选了 WinPcap 兼容模式
- 确认网卡选择 — 用
-i "网卡名"指定正确的网卡 - 同一网段不能有另一个 DHCP 服务器 — Windows 自带的 DHCP Server 服务必须关闭
Q: 如何查看日志
# 实时查看
type dhcpd.log
# 修改日志级别(配置文件中)
log_level: "DEBUG"
Q: 支持 IPv6 吗
不支持。本服务器仅处理 IPv4 DHCP。
Q: 支持 DHCPv6 吗
不支持。如需 IPv6 分配,请配置 SLAAC 或单独的 DHCPv6 服务器。
安全注意事项
⚠️ 不要在生产网络中直接部署,除非你完全了解后果:
- 单点故障 — 这台机器挂了,所有 DHCP 客户端都无法获取 IP
- 冲突风险 — 同一网段有两个 DHCP 服务器会导致客户端随机获取 IP
- 端口监听 — 服务器会监听 UDP 67 的广播包,其他设备可能无法响应
- 建议 — 先用隔离网络测试,确认无误后再部署
许可
MIT License
Description
Languages
Python
85.1%
HTML
14.9%