Part of #147 (epic: DNS mode enable state desync)
范围
src-tauri/crates/mhost-dns/src/platform.rs::enable_dns_mode
Fix A — kill_orphan_dns_proxies 改 sudo 提权 kill
当前 (line 503):
let rc = unsafe { libc::kill(pid as libc::pid_t, SIGTERM) };
问题: proxy 是 with administrator privileges 起 root 进程,user 态 libc::kill 在 macOS 默认被 EACCES 静默丢弃,pgrep 找得到但 SIGTERM 杀不掉。
改为:
- 用
run_with_privileges 跑一个简单脚本:for pid in $pids; do kill $pid 2>/dev/null || true; done(整段 sudo 提权)
- 放在
kill_orphan_dns_proxies 之前:必须先用 sudo 杀,再进 enable_dns_mode 主流程
- pids 来源继续用 pgrep -x
Fix B — AppleScript sh 脚本加 trap
当前 (line 523-550):
#!/bin/sh
set -e
"{proxy}" --listen 53 --target {dns_port} &
proxy_pid=$!
echo "$proxy_pid {proxy}" > {pid_file}
disown
# ... 等 ready 文件 ...
networksetup -setdnsservers {interface} 127.0.0.1
改为:
#!/bin/sh
set -e
cleanup() {
if [ -n "$proxy_pid" ]; then
kill "$proxy_pid" 2>/dev/null || true
wait "$proxy_pid" 2>/dev/null || true
fi
rm -f {pid_file} {ready_file}
}
trap cleanup EXIT INT TERM
"{proxy}" --listen 53 --target {dns_port} &
proxy_pid=$!
echo "$proxy_pid {proxy}" > {pid_file}
disown
# 等 ready 文件(5s timeout)...
# 失败时 trap 自动 kill proxy_pid + cleanup 文件
networksetup -setdnsservers {interface} 127.0.0.1
# networksetup 成功后正常退出 → trap 也会跑(杀 proxy? 不行!)
# → 需要 trap 在成功路径跳过 kill:
要点:networksetup 成功之后必须主动 trap - EXIT(取消 EXIT trap),否则脚本正常退出也会把刚启动的 proxy 杀掉。
实际更稳的写法:
trap 'cleanup_on_failure' EXIT INT TERM # 默认 = 失败路径
# 主流程
# ...
# 成功标记 + 取消 trap
trap - EXIT INT TERM # 成功路径不清理 proxy,留给正常 disable 路径管
exit 0
cleanup_on_failure 里 kill proxy_pid + cleanup pid_file + ready_file。
regression test
platform.rs 加单元测试 + 集成测试:
test_kill_orphan_via_sudo_helper_signature — run_with_privileges 跑一段 kill <pid> 脚本的 wrapper 函数存在 + 接受 pids vec
test_enable_script_has_proxy_trap_cleanup — 断言生成的 sh 脚本:
- 包含
trap 子句 + cleanup 函数
- 包含
trap - EXIT 在 setdnsservers 成功路径之后
cleanup 函数引用 $proxy_pid
- 集成测试 (macOS CI,加 ignore):真跑 enable → 模拟 networksetup 拒绝 → 验证 proxy 已死
Acceptance criteria
不做
依赖
无前置依赖。可独立 ship。
Part of #147 (epic: DNS mode enable state desync)
范围
src-tauri/crates/mhost-dns/src/platform.rs::enable_dns_modeFix A —
kill_orphan_dns_proxies改 sudo 提权 kill当前 (line 503):
问题: proxy 是
with administrator privileges起 root 进程,user 态libc::kill在 macOS 默认被 EACCES 静默丢弃,pgrep 找得到但 SIGTERM 杀不掉。改为:
run_with_privileges跑一个简单脚本:for pid in $pids; do kill $pid 2>/dev/null || true; done(整段 sudo 提权)kill_orphan_dns_proxies之前:必须先用 sudo 杀,再进enable_dns_mode主流程Fix B — AppleScript sh 脚本加 trap
当前 (line 523-550):
改为:
要点:
networksetup成功之后必须主动trap - EXIT(取消 EXIT trap),否则脚本正常退出也会把刚启动的 proxy 杀掉。实际更稳的写法:
cleanup_on_failure里 kill proxy_pid + cleanup pid_file + ready_file。regression test
platform.rs加单元测试 + 集成测试:test_kill_orphan_via_sudo_helper_signature—run_with_privileges跑一段kill <pid>脚本的 wrapper 函数存在 + 接受 pids vectest_enable_script_has_proxy_trap_cleanup— 断言生成的 sh 脚本:trap子句 +cleanup函数trap - EXIT在 setdnsservers 成功路径之后cleanup函数引用$proxy_pidAcceptance criteria
ps aux | grep mhost-dns-proxy无输出-setdnsservers拒绝)→ proxy 必须被 killcargo clippy --workspace -- -D warningscleancargo test --workspace --all-featuresclean不做
依赖
无前置依赖。可独立 ship。