liuzhuohua
|
2f8f09604b
|
release: 1.0.8 — VPN 页把「模块没加载」误报成「内核不支持 WireGuard」
版本号 1.0.7 → 1.0.8(19 个文件 55 处,逐条过;历史陈述不动)。
顺带补上1.0.7 漏掉的更新日志小节(那一版只改了版本号)。
## 本轮修的缺陷
**先说结论:Debian 13 虚拟机上跑 drouter,KVM 不是容器,
内核里一直有 WireGuard —— 是面板自己判错了。**
原 _vpn_installed() 只看两件事:/sys/module/wireguard 在不在(模块当前
已加载)、/usr/bin/wg 在不在(工具已安装)。**从没查过 /lib/modules 下
有没有模块文件** → 「模块文件在但没加载」被压进「内核真没这个模块」。
而 Debian 走 udev 按需加载,/etc/modules 与 /etc/modules-load.d 默认都
不写 wireguard,模块在磁盘上但没进内存。本机实测:内核 6.12.107+deb13-amd64,
wireguard.ko.xz 在,未加载;wireguard-tools 也没装。
前端还配了一句写死的文案把它坐实:「通常说明跑在精简容器里」——
而这台是 PVE 上的 KVM 虚拟机。排查方向被这句话整个带偏。
修法:
- 判据扩到四态(ready / need_module / need_tool / unsupported),
每态给可执行的下一步。unsupported 明确说装不了且不给一键修复。
- 模块文件名覆盖 .ko / .ko.xz / .ko.zst(Debian 默认压成 .ko.xz,
只认 .ko 会把正常机器也判成 unsupported)
- 新增「一键修复」:modprobe → 写 /etc/modules-load.d/ 开机自启 →
缺工具则 apt-get install,确认弹窗写清三步并告知不动网络
- apply 改为先自愈再报错,不再直接弹「内核不支持」把人挡在门外
- 老后端兜底 unknown 而非把旧的 no 猜成 unsupported(猜错=复活本 bug)
- 页面新增「运行环境」行;改掉「不需要装任何第三方软件」这句误导
## 测试基建:这轮抓出 3 条恒绿断言 + 1 处死分支
反向验证(把 bug 注入回去看它变红)逮到三条永远不会红的断言:
把探测路径改成 /nonexistent 仍全绿(docstring 里就写着那句话);
把 'env': _vpn_env() 注释掉仍全绿(我写的是 #注释,正则照样匹配);
把 if (!confirm( 改成 if (false && confirm( 仍全绿(提示文案里有那句话)。
根因:习惯在注释里引用被删掉的旧代码来解释 bug 来历,这些字面量让
「这段代码还在吗」类的判据永远成立。修法:t-107 统一走 py_code_only() /
js_code_only()(先按ast 判语义剥 docstring,再剥行注释),16 个注入全部被抓住。
死分支:用小锚点 Edit 只替换 if (d.installed === 'no') { 这一行时,
旧 body 与它的 } else if (!d.has_systemd) { 原样留在原地,拼出一个
「没有 systemd → 报内核不支持」的假分支——语法合法、静态检查也过。
防线:断言 } else if ( 的数量恰好等于分支数。
另有 4 处判据写错导致假红,共同形态是「脚本假设了一个修好之后就不成立
的前提」——比如「模块必须未加载」这条,fix 一跑完就假红。
## 验证
- t-107:126 → 167 项
- 反向验证 16/16 被抓住
- 新增 devtools/check-vpn-render.js 36 项(挂进 sync.sh 预检链)
- 新增 _dev/live-108-wg.py 真机验收 43 项;真机 _vpn_env 从 need_module
修到 ready,wg 装上(v1.0.20210914),modules-load.d 已写入
- t-*.py 51 个全绿 / 静态检查器 39 个全绿 / 前端四查全绿 / md 0 死链
- 容器冒烟新增第 14 节:镜像里真跑 _vpn_env() 验四态判定
(不 grep 字面量——注释里也会写这些词)
- deb 内 helper 与 app.js sha256 与本地逐字节一致
|
2026-10-03 12:28:21 +08:00 |
|
liuzhuohua
|
e1125e3978
|
release: 1.0.7 — 备份/告警/配额三模块收尾 + 真机再抓 3 个真缺陷
版本号 1.0.6 → 1.0.7(13 个文件 55 处,逐条过;历史陈述不动)。
## 本轮又修的 3 个真缺陷(都是真机 API 验收才暴露的)
静态检查全绿、函数级测试 29/29 全过,接口一打就红:
1. 备份包名校验正则比命名规则窄 → 导出的包自己都认不出
命名 charset 是 [A-Za-z0-9_-],校验只写 [a-z0-9]+,
而 Debian 默认主机名 debian-primaryrouter 带连字符
→ 导出了、界面显示「已导出」,但列表里看不到、永远还原不了。
修完才发现 _bk_list_entries 里还有第二份同样的正则(漏改),
已让它直接调用 _bk_safe_name()。
2. inspect 把 manifest 的 sha256 弄丢了→ 20 项全部标「已损坏」
重建 row 时没搬 sha256,下一行又拿 row.get('sha256') 比实际哈希
→ 恒为 None ≠ 哈希。还原也被「内容与清单不符」挡死。
3. 清单重叠 → 同一个文件进包两次
SNAPSHOT_ETC_FILES 含 rescue.conf、SNAPSHOT_ETC_DIRS 含整个
/etc/drouter → 同一 arcname 写两遍 tar(后者覆盖,不报错),
file_count / total_bytes 虚高一倍。真机证据:22 项 → 20 项。
## 测试防线(新增 7 条断言,全部做过反向验证)
把 bug 注入回去看它变红、还原后变绿 —— 没反向验证过的断言
可能因抽取失败而恒绿:
- 校验规则与命名规则同源(charset + 长度)
- 该正则在 helper 里只有一份(列表不再自抄)
- inspect 把 sha256 带进了 row / 比对的是 row 里那个 / 还原侧仍用 it.get
- 打包时按 arcname 跨组去重 + 清单确有「文件 ⊂ 目录」重叠项
- OK_NAMES 补真实主机名形态(原用例只有无连字符的 debian)
t-107:119 → 126 项。
## 真机验收
- 新增 _dev/live-107-api.py(26 项,HTTP 接口层)
- _dev/live-107.py 29 项、live-107-api.py 26 项,全绿
- 基线零变化:网关 192.168.7.2 / nft 0 行 / dnsmasq inactive+disabled
/ rescue inactive / ip_forward=1 / netavark 表已回收
- deb 511,624 B;解包抽查三个新守护在 backend/、helper sha 与本地一致
## 产物校验
- 离线包 sha256sum -c 238/238 通过
- 包内 deb 与独立产物 sha256 一致(c1ebcf17…)
- deb / 离线包 远端↔本地 sha256 逐一对齐
## 顺手
- README 体积数字按 stat 实算改成 500 KB(原文写的是 453 KB)
- smoke-docker-106.sh → smoke-docker-107.sh,新增第 12/13 节
(容器里三个新守护有不依赖 init 的拉起路径 + 镜像 Python 必须是 3.13)
- wireguard-tools 补进 DEPS 三处(helper / make-offline-deps / deb control)
|
2026-10-03 02:54:04 +08:00 |
|
liuzhuohua
|
3d028f5188
|
release: v1.0.6 打包校验发现 sync-isp-dns.sh 装错位置,一并修掉
产物校验时进容器抽查,发现 1.0.6 的 PPPoE 断网修复自己有三个问题:
1. 脚本装错位置。初版由 deploy.sh 用 heredoc 写进 $OPT/bin/,而
build-deb.sh 与 Dockerfile 都是 install scripts/*.sh → $OPT/scripts/。
结果装 deb、跑容器的机器上 ip-up-script 指向不存在的文件,DNS 选
「仅运营商/两者合并」时照样全家断网。改为 scripts/ 下的实体文件,
三条部署路径共用一份;deploy.sh 顺带迁移存量占位文件里的旧路径
(只换注释行,不碰已拿到的 nameserver)。
2. 容器里重载不掉。脚本只 systemctl reload dnsmasq,容器形态没有
systemd,等于什么都不做。改为检测不到 /run/systemd/system 时回退
kill -HUP $(pidof dnsmasq),与 helper 内部处理方式一致。
3. 写盘失败仍返回 0。pppd 只看 ip-up-script 的退出码来决定要不要记
日志,原来目录不可写时脚本照样 exit 0,把「DNS 没同步」彻底藏起来。
现在写临时文件或 mv 失败一律非零退出。
另把 deb 体积 447→452 KB、compose/guide 体积按实测更新到 README 与
RELEASE_NOTES。
真机(192.168.7.3)实测四条路径:拨号成功两条 nameserver 落盘 rc=0;
重复执行内容不变 rc=0 不重载;断线写占位 rc=0;目录不可写 rc=1。
回归 8 模块全绿,安全不变量(53/67 端口 0 占用、服务未启动、
ens18 IP 不变、VNC 5900 完好)全部保持。
|
2026-10-02 20:57:32 +08:00 |
|
liuzhuohua
|
7b321bfdce
|
fix: 第二轮深度审计 —— 堵提权/注入、收口资源生命周期、低配置性能水位,版本号 1.0.5
安全:
- chpasswd 换行注入可改 root 密码:用户名/密码拒绝换行与控制字符
- 删用户保护从写死两个名字改为 UID<1000 系统账号
- WOL 接口名白名单 + 目标地址 IPv4 校验,去 sh -c 管道
- ACL hosts 改 ipaddress 严格校验;存储挂载点限定 /mnt|/media|/srv
- 文件管理器拒绝清单扩到目录级 + 按文件名拦截(authorized_keys/shadow 等)
- 前端 201 处 value="${...}" 补 esc();href 只放行 http/https;
主题导出注释同时剥 /* 与 */
丢数据/假功能:
- ACL/文件共享/DDNS 三页切走再回来草稿被静默覆盖:新增 PAGE_DIRTY 脏页登记
- LAN 页网关/域名写进 system 死键,改绑 dnsmasq 同源
- UPnP 映射表按钮不再顺手起服务,走只读接口 read:upnpmap
资源:
- PTY 缓冲 8MB 封顶 + 会话信号量 + 后台空闲回收 + 离开页面主动断开
- Web 工作线程 48 封顶、请求体 16MB 封顶、会话 500 封顶改单调时钟、
审计 2 万行裁剪、helpd 并发 6 封顶
- helper 日志 32MB 轮转;快照前查磁盘余量;fs 下载 512MB→20MB
(通道单条响应 32MB,超限只会静默失败)
- 11 处配置写入改原子写;rescue/snapshot 单元补 MemoryMax(三处同步)
性能:
- /api/config 16 次开库 → 1 次 IN 查询
- cleanup 状态扫描 30s 缓存;gzip 缓存加 24MB 字节闸
- 后台标签页心跳暂停、终端轮询降频
杂项:DHCPv6 停用只留注释;租约回收用 dhcp_release(DEPS 可选登记);
VLAN 只删自建接口;公网探测清残留结果文件;快照根白名单;
心跳定时器防重复;keep_days/keep_rows 不吞 0
|
2026-10-02 10:25:40 +08:00 |
|
liuzhuohua
|
cd5ef7411f
|
fix: 清「假输入框 / 隐身字段」这批前后端缺陷,版本号 1.0.4
把全量代码(后端 9 模块 + 前端单文件 SPA,约 4.5 万行)过了一遍,用 AST 抽出
渲染器读取的每个配置键,与页面上输入框绑定的字段做双向差集,专门找两类问题:
前端发了后端从不读(假输入框)、后端读了前端没有入口(隐身字段)。
会写坏系统的:
- render_network 违反 render() 契约返回字典,调用方按二元组解包后把字典的键
当成路径和内容 —— 迁移 networkd 会生成文件名叫 name、内容写着 content 的垃圾文件
- DMZ 规则方向写反:注释写「排除到本机自身」,条件写成反面,管理口流量也一并 DNAT
五个「填了等于没填」的输入框:
- WAN 的 MTU 与「是否接受上游 DNS」后端零消费,现真正写入 MTUBytes= / UseDNS=
- DHCPv6 的「子网 ID」绑的是不存在的键,真生效字段是 sla_id
- Samba WINS 要求一个从不回填的字段同时为真,勾了永不生效
- 网桥「启用 STP」未绑定事件,勾完保存不进去
- 主题设计器「按主色生成配色」按钮无 handler
其余:
- RA 页补齐 rdnss_life / dnssl_life 输入框(1.0.3 修了错位却没给入口)
- 迁移预览只发 lan,必报「WAN 网卡不能为空」且网桥从不出现 → 补发 wan + bridge
- dnsmasq / miniupnpd / ppp / dhcpcd IPv6 / RA 地址池 / NFS 等插值零校验
- chrony 服务器校验只认域名和 IPv4,IPv6 NTP 服务器被误拒
- v_int 改用 try/except:上标数字能通过 isdigit() 却让 int() 抛异常导致 500
- ensure_cert 删掉硬编码的开发机 IP,改为本机地址 + 默认路由推导;补 openssl 失败检测
- DDNS 面板 XSS(记录名/服务商未转义);主题 CSS 注释注入(前后端各一处)
测试:render 返回值契约断言、CSS 注释注入回归、模板孤儿控件守卫,
_dev/t-*.py 42/42、前端三查 + md 链接检查全绿。
|
2026-10-02 00:23:30 +08:00 |
|
liuzhuohua
|
79f24aa264
|
fix: 部署静默回退用户设置 + radvd RDNSS 未校验等 5 处缺陷
1.0.3 为纯修复版本,五个问题全部来自真机(192.168.7.3)深度排查:
翻 journal 与统一日志的 error 记录、全盘扫描文件名控制字符、把现行配置库
里每个模块的渲染结果重新交给对应真守护进程做语法校验。
- render(radvd): RDNSS 字段原先完全不校验(同段代码里 prefix 校验网段、
DNSSL 校验域名,唯独漏了它),填 IPv4 地址会原样写进 radvd.conf 导致
radvd 起不来,界面只回一句 radvd.conf:18 error: syntax error。
现逐项按 IPv6 地址校验并给中文提示;多值支持逗号/空格并统一按空格输出
(逗号形式 radvd 本就不认);DNSSL 同样支持多域名;修正 DNSSL 生命期
误读 rdnss_life 的字段错位。
- cleanup: 自动清理的「每天 00:00」根本存不下来——前端 `Number(v) || 4`
与后端 `int(cfg.get('hour') or 4)` 都把 0 当成「没填」,叠加后保存即变
04:00 且改不回来。两处改为显式判断 None/''。执行时刻判定由「正好等于」
放宽为「不早于」,避免计划时刻恰好关机/重启导致当天彻底跳过。
- deploy.sh: 三处无条件覆写改为「只在文件不存在时初始化」——
active-theme(自定义主题每次部署被打回默认)、generated/isp-dns.conf
(PPPoE 上游 DNS 被擦、解析变空直到下次拨号)、cleanup enabled=true
(唯一会真删文件的模块被静默重新打开)。另补兜底:生效主题指向已不
存在的主题时回退 default 并打印说明。
- drouter-web: socketserver 默认 handle_error 把任何异常连整段 traceback
打进 journal,浏览器切页/关标签抛的 BrokenPipeError / ConnectionReset
属「对面先挂了」,三日攒数十条足以淹没真报错。新增 _Server 子类只静默
这几类,其余照旧抛出。
- devtools: 新增 fix-crlf-names.py 清理 CRLF 环境残留的名字带 \r 脏条目
(保守:默认只预演、仅删有同名兄弟者、目录需相对文件集合为子集、
跳过 snapshots/);sync.sh 发布预检增加「文件名不得含控制字符」。
|
2026-10-01 17:43:28 +08:00 |
|
liuzhuohua
|
a49b4d7771
|
fix(dnsmasq): 合并重复的 option 3/6,并诊断 /dev 节点缺失
DHCP 页有「专属字段」和「自定义 Options 表」两处能写同一个 option code。
两处都填 3/6 时会各自渲染一遍,而 dnsmasq 对列表型 option 是追加语义,
于是客户端收到重复的网关,DNS 列表也被搅乱(公网 DNS 排在本机前面,
本机 dnsmasq 形同虚设)。
改为按 code 合并成一行并顺序去重;带「强制」的 3/6 语义不同,仍单独输出
为 dhcp-option-force;其它 code(43/121…)完全不受影响。新建配置也不再
预置与专属字段重复的 code 3/6 行。
顺带:
- code 6 的占位符原本写上游 DNS,容易误导 —— option 6 是下发给客户端的
「去哪台机器查 DNS」,应填本机。占位符与说明已改正。
- dnsmasq 预检失败时不再直抛英文原文。像
「failed to seed the random number generator」其实与配置无关,是宿主机
/dev 设备节点缺失,现在会分诊成系统层面的中文提示。
版本号 1.0.1 → 1.0.2。注意区分「产物版本」与「功能引入版本」的表述:
容器里无 systemd 时回退子进程拉起守护,是 1.0.1 引入的,文案保持 1.0.1。
新增 _dev/t-render.py 对 3/6 合并的回归断言(含 force、留空、顺序、
其它 code 不受影响、预览路径一致性)。全量回归 42/42 通过。
|
2026-10-01 16:49:49 +08:00 |
|
liuzhuohua
|
7d646b5f2b
|
fix(helper): dnsmasq 预检失败时诊断出「/dev 节点缺失」
用户在 DHCP 页点「保存并应用」,弹出:
配置语法检查未通过:dnsmasq: failed to seed the random number
generator: 没有那个文件或目录
根因不是配置写错,而是目标机的 /dev 标准设备节点被误删过。
/dev 是 devtmpfs,由内核维护,但**已删除的节点内核不会重建**。
2026-09-30 一次 chroot 的 `mount --bind /dev` 变量写错,把宿主机 /dev
挂到了自己身上,随后的清理清空了整个 /dev —— 当时只补回了 /dev/null
一个节点。urandom / random / zero / full / tty / console / kmsg 以及
全部块设备(sda、sda1、sda2、zram0)和 /dev/net/tun 一直缺到今天,
直到 dnsmasq 预检要读随机数才暴露。
内核那句话里既没有 "dev" 也没有「设备」字样,用户只会以为是自己把
地址池填错了。新增 _missing_dev_nodes() 做分诊:命中该错误时返回中文
提示,指明这是系统层面的 /dev 问题、不是配置问题。
- backend/drouter-helper.py:新增 _missing_dev_nodes();_verify 的
dnsmasq 分支做错误分诊(其它语法错误仍走原路径)
- devtools/fix-dev-nodes.sh:新增。幂等地补齐被删的标准设备节点,
设备号分别取自内核 devices.txt(字符设备)、/proc/partitions
(块设备)、/sys/class/input(输入设备);已存在的一律不动
- _dev/t-verify.py:新增 15 项回归,覆盖「节点齐全不误报」「缺谁报谁」
「随机数错误被翻译」「其它错误不受影响」「合法配置通过」五条路径
- devtools/sync.sh:预检链挂上 t-verify.py
目标机 192.168.7.3 实测:
- fix-dev-nodes.sh 新建 32 个节点、0 失败;二次执行 32 跳过(幂等)
- dnsmasq --test 从「failed to seed the random number generator」
变为「syntax check OK.」(退出码 0)
- 网络基线零变化:网关仍 192.168.7.2、ip_forward=1、
5900 仍在听、网卡集合不变、dnsmasq 仍 inactive/disabled、
nft 表 0 个
|
2026-10-01 16:01:45 +08:00 |
|
liuzhuohua
|
147a402eca
|
fix(webshell): 修复 PTY 故障与终端满员自锁,补容器形态守护拉起
Web 终端「任何账号都连不上」的两个真实故障,以及容器形态下终端完全打不开。
- shelld: 根因是 /dev/ptmx 符号链接丢失(/dev/pts/ptmx 还在),
pty.openpty() 找不到入口,内核却报 "out of pty devices" ——
把「少一个设备节点」说成了「设备耗尽」,排查方向被带偏。
新增 ensure_ptmx():启动时与创建失败时都探测,先补 symlink,
不行再 mknod 兜底;仍失败则回 PTY_FAIL 并给出可照抄的命令
- shelld: 会话锁由 threading.Lock 改为 RLock。原锁不可重入,而
connect 在持锁状态下调用 _reap_idle() 会二次取同一把锁 ——
同线程二次 acquire 不报错不超时、直接睡死,锁永不释放,
第 9 个连接起整个终端服务冻死且日志无痕。
connect 不再持锁调回收;_reap_idle() 的 close() 移到锁外
- helper: 容器里没有 systemd,拉起终端守护原来只有 systemctl 一条路径,
导致容器形态 Web 终端永远「终端守护未运行」。新增 _shelld_spawn() 回退:
直接以子进程启动守护(start_new_session 脱离父进程);
错误文案改为「容器形态无 systemd,重启容器即可」
- 前端: 终端去掉滚动条(仅隐藏外观,滚动能力保留)、
高度改为随视口 clamp 自适应;新增「清屏」与「↓ 最新」按钮
- 打包: build-deb.sh 与 Dockerfile 不再整体拷 docs/ ——
install/COPY 撞上 docs/screenshots/ 目录会报错(install 遇目录返回非 0,
在 set -e 下直接中断整个打包);截图本就不该进 deb/镜像
- 修正两处不一致: index.html 页脚误写「GPL v3」→ MIT(与 LICENSE 对齐);
README 中 deb 体积 421 KB → 427 KB(实测 437584 字节)
- 版本号 1.0.0 → 1.0.1(源码、打包脚本、文档、镜像标签、编排文件)
测试: _dev/t-pty.py 扩到 45 项,含「_lock 必须是 RLock」的行首断言
(原先用子串匹配被 self.buf_lock 误伤);t-webshell.py 补 16 项外观契约。
真机 192.168.7.3 实测:第 9 个连接 0.01s 干净返回 BUSY,
断开 8 会话 0.87s 全清、残留 0,PTY/fd 回落基线;
自愈验证(删掉 /dev/ptmx 重启服务可自动补回)。
容器冒烟 12/0:无 systemd 环境下守护成功拉起、
root shell 建会话并跑通命令回显。41 个单测文件全绿。
|
2026-10-01 03:09:19 +08:00 |
|
liuzhuohua
|
2859705cee
|
fix(webshell): 修复终端满员自锁 + 去掉滚动条并加清屏按钮
一、修 PTY 不可用(Web 终端报「创建终端失败:out of pty devices」)
根因是目标机上 /dev/ptmx 这个符号链接丢了(devpts 里 /dev/pts/ptmx
还在,但入口没了),于是 pty.openpty() 抛出误导性的「out of pty devices」。
- 新增 ensure_ptmx():探测 -> ln -sf pts/ptmx /dev/ptmx -> mknod 兜底
- 新增 _open_pty():首次失败先自愈再重试一次,仍失败就把真实原因
(_pty_diagnose() 的结论)包进异常,不再只留一句天书
- 服务启动时也自愈一次,开机即修,不等用户踩坑
- 前端识别 PTY_FAIL 并给出可照抄的修复命令
二、修会话满员时的死锁(连到第 9 个会话整个终端服务冻死)
connect 需要「看是否满员 -> 满了就回收 -> 再看一次」,这个序列必然
在持锁时调到内部也要拿锁的 _reap_idle()。而 _lock 是普通 Lock,
同线程二次 acquire 永久阻塞 —— 不报错、不超时,直接锁死;而且锁
一直不放,其他会话的 read/write 也一起堵住,整个 Web 终端报废。
- _lock 改为 RLock
- connect 不再把 _reap_idle() 放在 with _lock 里面
- _reap_idle() 锁内只做登记摘除,close() 移到锁外:
close() 要等子进程退出(SIGHUP 后最多轮询 3 秒),持锁做同样会
把并发请求堵死
三、终端外观(按需求)
- 去掉右侧滚动条(scrollbar-width:none + ::-webkit-scrollbar),
但保留滚动能力 —— 直接关掉 overflow 会让人再也翻不了历史
- 高度改为 clamp(260px,54vh,560px) 随视口自适应;内容多了自动跟随
最新输出。刻意不做「高度随内容增长」:wsMeasure() 用 box.h 算行数,
内容撑高容器会反过来改变 PTY 行数,形成反馈环
- 标题栏加「清屏」小按钮;滚上去离开底部时另出现「↓ 最新」——
滚动条没了,总得留个回到底部的入口
- 跟随阈值收敛成唯一的 WS_TAIL_GAP:wsAutoScroll 与 wsSyncTailBtn
各写一份会出现「按钮没出现、输出也不跟着滚了」的死角
四、顺带清理
- 删掉 app.css 里整套失效的旧终端样式(.tdot/.tt/.term-in/.tk-*,
app.js 中 0 引用),它们已被新结构完全覆盖,留着只会让人改错地方
- 合并 .term-wrap / .term-body 各自重复的第二条声明
测试:
_dev/t-pty.py 扩到 37 项,含「不得自锁」的结构检查 + _reap_idle
行为验证(摘除/关闭/返回条数);_dev/t-webshell.py 加 16 项外观契约。
两者都挂进 devtools/sync.sh 预检链。
新增 devtools/preview-webshell.py:用真实 app.css + 从 viewWebShell()
抠出的 DOM 生成离线预览页,不手抄样式以免预览与线上不一致。
真机验收(192.168.7.3):
8 个会话满员后第 9 个 0.01s 干净返回 BUSY(修复前是永久卡死);
8 个会话 0.87s 全部断开、残留 0(修复前残留 8 个且后续全卡);
/dev/pts 与 pty/nr 回落到 0,无 fd 泄漏;root shell 正常执行命令。
|
2026-10-01 01:29:09 +08:00 |
|
liuzhuohua
|
9b4ffce9a5
|
feat(devtools): 生成截图图床外链清单(Markdown / BBCode / HTML 三格式)
用户问「能不能当图床、转成论坛可用的格式」。
实测结论:可以。四种直链形式全部 200,且
- Content-Type 正确(image/jpeg)
- Access-Control-Allow-Origin: *(CORS 全开,网页引用无阻)
- 无防盗链:带外部 Referer、无 UA 均正常返回
新增 devtools/gen-image-urls.py,一次性产出三种论坛格式:
① Markdown  GitHub / 语雀 / Discourse / Obsidian
② BBCode [img]url[/img] Discuz / phpBB / NGA / 恩山 / Chiphell / v2ex
③ HTML <img src="url"> 博客 / 自建站 / 富文本编辑器
域名默认用 cdn.jsdelivr.net/gh —— 国内可达性明显好于
raw.githubusercontent.com,且缓存 7 天(raw 只有 5 分钟)。
文档里附了换域名对照表(gcore 备用节点 / statically / raw)。
同时支持 @<commit-sha> 冻结写法,把内容锁定在某个提交上,
避免后续提交把已发出去的帖子里的图改掉。
产物同时落在 docs/图床链接清单.md(进仓库)和桌面(方便直接用)。
顺带记录一个失败:想生成「纯格式版」和「带文件名版」两份,
判断逻辑写错导致两份内容相同;改用一次生成、分节呈现,
反而更适合「整段复制」的用法。别为了参数化而增加无意义的重复产物。
|
2026-09-30 23:14:19 +08:00 |
|
liuzhuohua
|
3f5f31701e
|
feat(devtools): 新增截图覆盖度检查,README 标明待补页面
核对用户打包发来的 78 张截图,与仓库已入库的 78 张 md5 集合完全一致
(互相零差异),确认上一轮提交已是完整状态,本次不需改动任何图片。
本次补充的是「防漂移」能力:
1. 新增 devtools/check-shots.py —— 功能页 ↔ 截图 ↔ README 引用 三方对账
- 43 个功能页逐个报告有无截图(当前 40 有 / 3 缺)
- 映射表登记的截图 vs docs/screenshots/ 实际文件,双向查差异
- README 引用的 vs 实际存在的,双向查差异
为什么不用中文页名做子串匹配:「防火墙 IPv4」会命中「防火墙 IPv6」的
规则说明,误判是静默的假绿。宁可手工维护一张映射表。
2. sync.sh 里原来那段内联的截图清单校验,替换为调用 check-shots.py
(功能被完整覆盖,且现在多了功能页覆盖度这一维)。
3. sync.sh 的 CRLF 检查改为只扫 git 已追踪的文件。
原来用 glob('**/*.html') 会扫到未追踪的本地临时预览页
(_preview-shots.html),它既不会进仓库也不会被 deploy.sh 上传,
为它报错是纯噪音。
4. README 截图章节新增「还没截图的 3 个页面」折叠块:
新手向导 / 主题之家 / 升级与保护,附补图流程。
项目结构章节补充两个新工具。
验证:check-md-links 98 个引用 0 死链;check-shots 三方一致;
t-audit / t-packaging 全部通过。
|
2026-09-30 23:05:51 +08:00 |
|
liuzhuohua
|
a8659dfb98
|
docs(readme): 用 78 张真实界面截图替换 SVG 占位图
原文里 docs/screenshots/ 放的是 6 张同尺寸 SVG 占位图,只为让 README
在仓库刚建好时能完整渲染。现在换成 78 张真实运行截图(1272x900,
取自一台 2 核 4G 的 Debian 13 虚拟机)。
改动:
- 新增 docs/screenshots/ 78 张 jpg,按 9 个功能分组编号命名
(01-login / 02-overview… / 09-settings-4),覆盖全部 43 个功能页
- 删除 6 张 SVG 占位图与 devtools/make-placeholder-shots.py
- README「截图」章节重写:首屏放 8 张精选大图,其余 70 张按功能分
组放进 9 个 <details> 折叠块,每组内用两列表格 + 图注
- README 项目结构补充 docs/screenshots 与 devtools/shots-map.py
- dist/RELEASE_NOTES.md 同步「截图已全部为真图」
为什么文件名必须 ASCII:
GitHub Releases 资产名已被实测证明会静默剥离非 ASCII 字符
(DOCKER-使用说明.md → DOCKER-.md);且原始文件名含 &(如
AC&AP管理中心.jpg、UPnp&NAT-PMP.jpg)在 shell / CI 里都要额外转义。
devtools/shots-map.py 负责「中文名 → ASCII 名」的映射与复制,
并做完整性校验(漏拷/多余/重名都会中止)。
新增两项预检,挂进 devtools/sync.sh:
- devtools/check-md-links.py:所有 md 的本地引用逐条查存在性
- 截图清单双向校验:README 引用的 78 张与目录里的 78 个文件必须一一对应
验证:check-md-links 扫 10 个 md / 98 个本地引用,0 死链;
78 张图与源目录 md5 集合完全一致;
t-packaging / t-audit / t-deps / t-cachebust 全部通过。
|
2026-09-30 22:46:43 +08:00 |
|
liuzhuohua
|
5150f4c2e6
|
feat(docker): 补 compose 编排与使用说明,修正镜像标签与 license
新增
· packaging/docker/docker-compose.yml 现成编排,含健康检查与命名卷
· packaging/docker/DOCKER-使用说明.md 完整使用文档(含常见问题)
· devtools/retag-docker-image.py 镜像重打标签工具
修正三个真实缺陷
1. 镜像标签
原本是 buildah 留下的 `localhost/drouter:1.0.0`。`localhost/` 是 Podman
的本地镜像约定,Docker 用户拿到会很困惑(像某个私服地址)。
改为 `drouter:1.0.0` + 别名 `liuzhuohua/drouter:1.0.0`。
2. license 标签写错
镜像 LABEL 里 `org.opencontainers.image.licenses` 是 **GPL-3.0**,
但项目实际是 **MIT**(Dockerfile 与镜像 config 都已改)。
3. 缺 HEALTHCHECK
没有它,compose 里 `depends_on: condition: service_healthy` 无从等起,
`docker ps` 也看不出容器是否真的活着。
补上探活 /api/health —— 注意面板走 HTTPS + 自签证书,curl 必须 -k,
否则永远 unhealthy。
compose 要点
· network_mode: host 是硬要求(bridge 下看不到真实网卡、管不了宿主 NAT)
· cap_add 只给 NET_ADMIN + NET_RAW,不用 privileged
· host 模式下 ports 会被忽略,端口由 /etc/drouter/web-port 决定,
故用 expose 表达意图而非 ports
· 四个命名卷必须挂:配置 / 数据 / 快照 / 日志
重打标签采用流式重写 tar(只替换 manifest.json、repositories 与 config
三个小文件,layer.tar 原样透传),已逐层校验 3 个 layer 的 sha256 与
原包完全一致。
|
2026-09-30 21:25:28 +08:00 |
|
liuzhuohua
|
64df3cf331
|
feat: Drouter 1.0.0 —— Debian 13 软路由管理系统
一套跑在 Debian 13 (trixie) 上的软路由管理系统,提供 43 个功能页面的
Web 管理面板:WAN 接入、PPPoE 多拨、DHCP/DNS、IPv6、防火墙、QoS 限速、
访问控制、DDNS、文件共享、Docker 管理等。
核心设计原则:不重新实现任何协议
PPPoE 交给 ppp,DHCP 交给 dnsmasq,IPv6 RA 交给 radvd,NAT 交给 nftables。
Web 面板只做三件事:渲染原生配置文件 → 语法预检 → 原子写入并 reload。
面板删掉后,系统仍是一台配置完好的 Debian 路由器。
安全默认值
· 安装后不接管网络:不改默认路由、不开 IP 转发、不启动 DHCP 服务
· 所有改网络的动作都需要用户在面板上亲手点「应用」
· 避开 5900 端口,不触碰 VNC / X 会话
· 配置写入前先做语法预检,失败则回滚
架构
· backend/ Python 3 标准库,零第三方依赖(9 个模块)
· web/ 原生 JS/CSS,无构建步骤
· 常驻 helper 通过 Unix socket 提供 75 个动作,socket 不可用时回退 subprocess
· 鉴权走 X-Token 请求头
打包
· packaging/build-deb.sh → drouter_1.0.0_all.deb(含 6 个 systemd 单元)
· scripts/make-offline-deps.sh → 236 个依赖 .deb + 本地仓库索引
· packaging/build-offline-bundle.sh → 自包含离线包,目标机零外网可装
· packaging/build-docker.sh → 容器镜像(体验用)
测试
40 套单元测试 + 3 个前端检查脚本(菜单映射 / 离线渲染 / 手机适配),
全部挂在 devtools/sync.sh 的预检链里。
许可:MIT
|
2026-09-30 19:26:24 +08:00 |
|