feat: WinDHCPD — Windows-native DHCP server

Python 3 + Scapy DHCP server with:
- Full DORA handshake (DISCOVER/OFFER/REQUEST/ACK)
- Multi-scope support with DHCP relay
- Static MAC-to-IP bindings
- Lease persistence (JSON) with auto-prune
- NACK for invalid requests
- Flask web management panel (dark theme, live refresh)
- Admin-privileged scapy sniff on UDP 67
This commit is contained in:
Your Name
2026-07-13 16:22:19 +08:00
commit ea8eb2b5f9
12 changed files with 1737 additions and 0 deletions
+223
View File
@@ -0,0 +1,223 @@
# 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. 安装 Npcapscapy 依赖)
Scapy 在 Windows 上需要 Npcap 来捕获和发送网络数据包:
- 下载:https://nmap.org/npcap/
- 安装时 **必须勾选 "Install Npcap in WinPcap API-compatible Mode"**
- 默认安装即可
### 3. 安装依赖
```bash
pip install -r requirements.txt
```
依赖包:
- **scapy** (≥2.5) — 网络数据包捕获与发送
- **flask** (≥3.0) — Web 管理面板
- **pyyaml** (≥6.0) — 配置文件解析
## 快速开始
### 1. 创建配置文件
```bash
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 的广播数据包需要特权):
```bash
# 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
```
## 配置文件详解
```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: "以太网" # 可选:指定监听网卡
```
## 网络拓扑要求
### 场景 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
1. **必须以管理员身份运行** — 端口 67 需要特权
2. **检查 Npcap 是否安装** — 且勾选了 WinPcap 兼容模式
3. **确认网卡选择** — 用 `-i "网卡名"` 指定正确的网卡
4. **同一网段不能有另一个 DHCP 服务器** — Windows 自带的 DHCP Server 服务必须关闭
### Q: 如何查看日志
```bash
# 实时查看
type dhcpd.log
# 修改日志级别(配置文件中)
log_level: "DEBUG"
```
### Q: 支持 IPv6 吗
不支持。本服务器仅处理 IPv4 DHCP。
### Q: 支持 DHCPv6 吗
不支持。如需 IPv6 分配,请配置 SLAAC 或单独的 DHCPv6 服务器。
## 安全注意事项
⚠️ **不要在生产网络中直接部署**,除非你完全了解后果:
1. **单点故障** — 这台机器挂了,所有 DHCP 客户端都无法获取 IP
2. **冲突风险** — 同一网段有两个 DHCP 服务器会导致客户端随机获取 IP
3. **端口监听** — 服务器会监听 UDP 67 的广播包,其他设备可能无法响应
4. **建议** — 先用隔离网络测试,确认无误后再部署
## 许可
MIT License