Files
DHCP Service Bot 21e3d61871 Add network scan page (arp-scan)
New /scan page lists all active devices on the subnet (ARP scan):
- 静态绑定: matches a host declaration
- 动态分配: matches a dhcpd.leases entry
- 未知 / 外部: nothing matches (manually configured or from other DHCP server)

Click '转为静态绑定' to convert a discovered device to a static host binding.

Also includes:
- arp-scan wrapper in dhcp_ops.py (get_local_network, arp_scan, classify_devices)
- /scan route with optional auto-refresh every 30s
- README updated with arp-scan install step + new feature bullet
2026-07-09 17:37:50 +08:00

150 lines
4.7 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.
# DHCP Web Manager
一个用 Flask 写的轻量级 ISC DHCP (dhcpd) Web 管理界面,**底层直接复用系统自带的 isc-dhcp-server**
不引入额外 daemon。提供 Web 界面来管理 subnet / 静态 host 绑定 / 监听接口 / 查看租约 / 操作日志。
## 功能
- 🟢 子网(subnet)增删改:网段、掩码、网关、DNS、地址池、租期
- 🟢 静态绑定(host):MAC + 固定 IP + 主机名
- 🟢 监听接口配置(INTERFACESv4
- 🟢 租约查询(按 IP/MAC/主机名搜索)+ 地址池使用率
- 🟢 网络扫描(arp-scan):列出网段内活跃设备,标记 静态绑定 / 动态分配 / 未知
- 🟢 服务状态 + reload / restart + 语法检查
- 🟢 操作日志(谁在什么时间做了什么)
- 🟢 用户名密码登录 + 改密
- 🟢 所有变更自动:写文件 → 备份 → `dhcpd -t` 语法检查 → `systemctl restart isc-dhcp-server`(带 is-active 验证)
## 文件结构
```
dhcp-service/
├── app.py # Flask 主程序
├── dhcp_ops.py # dhcpd.conf 读写 + leases 解析 + 服务控制
├── requirements.txt
├── instance/dhcp.db # SQLite(用户、日志)
├── backups/ # dhcpd.conf 自动备份(最多保留 20 份)
├── templates/ # Jinja2 模板
└── static/style.css
```
## 安装
```bash
apt-get install -y isc-dhcp-server arp-scan dhcping # 后端 DHCP 服务 + 扫描工具
pip3 install -r requirements.txt --break-system-packages
```
## 启动
开发模式:
```bash
python3 app.py # 监听 0.0.0.0:5100
```
生产模式(推荐用 gunicorn):
```bash
gunicorn --workers 2 --bind 0.0.0.0:5100 'app:app'
```
默认账号:`admin` / `admin`(首次登录后请到「改密」修改)。
## 关键设计
### 配置文件组织
我们改写 `/etc/dhcp/dhcpd.conf`,但**只动我们管理的区段**——通过标记:
```
# 原有的通用配置(option domain-name 等)保持不变
option domain-name "example.org";
default-lease-time 600;
...
# >>> DHCP-WEB-MANAGER BEGIN >>>
authoritative;
subnet 192.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1;
...
}
host printer {
hardware ethernet aa:bb:cc:dd:ee:01;
fixed-address 192.168.1.50;
}
# <<< DHCP-WEB-MANAGER END <<<
```
系统原有的 option / 注释 / 不认识的配置都不丢。备份在 `backups/dhcpd.conf.<timestamp>.bak`(最多 20 份)。
### 变更流程
所有写操作都走同一个流程(在 `app.py: apply_and_reload`):
1. 读现有 subnets/hosts → 追加/替换 → 生成新的 conf 文本
2. **先备份到 backups/**
3. 写到 `/etc/dhcp/dhcpd.conf`
4.`dhcpd -t` 语法检查 — 失败则回滚到备份(不修改数据库)
5. 通过则 `systemctl reload isc-dhcp-server`(不丢连接)
### 接口绑定
`/etc/default/isc-dhcp-server` 中的 `INTERFACESv4="enp0s31f6"`
保存接口配置会**重启**(而非 reload)服务,因为接口绑定变更不支持热加载。
### 租约解析
直接读 `/var/lib/dhcp/dhcpd.leases` 并 regex 解析 lease 块。注意 dhcpd 每次写入 leases 文件时
会以临时名写入后 rename 替换,所以解析时可能短暂读到空内容——前端解析失败的话就是 0 条,不报错。
## 部署到生产
按本机惯例,dev 仓库在 `/root/dhcp-service/`,生产部署在 `/root/.openclaw/workspace/dhcp-service/`
```bash
# 1. 把代码复制到生产目录
mkdir -p /root/.openclaw/workspace/dhcp-service
cp -r /root/dhcp-service/{app.py,dhcp_ops.py,requirements.txt,templates,static} \
/root/.openclaw/workspace/dhcp-service/
# 2. systemd unit (示例)
cat > /etc/systemd/system/dhcp-web-manager.service <<EOF
[Unit]
Description=DHCP Web Manager (Flask)
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/root/.openclaw/workspace/dhcp-service
ExecStart=/usr/bin/gunicorn --workers 2 --bind 0.0.0.0:5100 'app:app'
Restart=on-failure
RestartSec=5
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now dhcp-web-manager
```
访问 `http://<server-ip>:5100`
## 注意事项
- 本程序必须以 root 跑,因为需要写 `/etc/dhcp/dhcpd.conf` 和控制 systemd 服务。
- 修改 subnet/host 走 reload(不丢现有租约),但改 INTERFACESv4 必须 restart。
- `dhcpd -t` 语法检查失败时**不会**回滚配置,但也不会 reload——服务继续按旧配置运行,
操作日志记录失败原因。修改者可以修正后重试。
- 数据库 `instance/dhcp.db` 不要 commit 到 git。
## 备份恢复
所有 conf 改动前会自动备份到 `backups/`,恢复:
```bash
ls backups/
cp backups/dhcpd.conf.20260709_120000.bak /etc/dhcp/dhcpd.conf
systemctl reload isc-dhcp-server
```