Files
Your Name ea8eb2b5f9 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
2026-07-13 16:22:19 +08:00

224 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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