# 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. 安装依赖 ```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 通过 `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