diff --git a/scripts/local_test.sh b/scripts/local_test.sh index f365d77..c481ef4 100755 --- a/scripts/local_test.sh +++ b/scripts/local_test.sh @@ -4,7 +4,8 @@ # 用真正的 release 包(不是 dev 模拟),前台运行以便直接看内核(sing-box)日志。 # 改完代码直接跑此脚本即可。 # -# bash scripts/local_test.sh +# bash scripts/local_test.sh # 构建 release 并运行 +# bash scripts/local_test.sh --no-build # 跳过构建,直接跑上次的产物(快速重跑) # # 可选环境变量: # PANGOLIN_API_URL 控制面地址(默认连 racknerd 节点) @@ -19,28 +20,37 @@ REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" CLIENT="$REPO_ROOT/client" API_URL="${PANGOLIN_API_URL:-http://107.172.55.251:8080}" SINGBOX="${SINGBOX_BIN:-/opt/homebrew/bin/sing-box}" +NO_BUILD=0 +[ "${1:-}" = "--no-build" ] && NO_BUILD=1 command -v flutter >/dev/null 2>&1 || { echo "✗ 需要 flutter"; exit 1; } [ -x "$SINGBOX" ] || { echo "✗ 找不到 sing-box: $SINGBOX(brew install sing-box,或设 SINGBOX_BIN)"; exit 1; } -# ── 1. TUN 免密 sudoers(幂等;命令路径须与客户端解析到的一致)────────────────── -echo "==> [1/3] 配置 sing-box 免密 sudo(TUN 需 root)" -SUDO_FILE=/etc/sudoers.d/pangolin-singbox -WANT="$(whoami) ALL=(root) NOPASSWD: $SINGBOX" -TMP="$(mktemp)" -printf '%s\n' "$WANT" > "$TMP" -# 校验语法后安装(避免写坏 sudoers) -if sudo visudo -cf "$TMP" >/dev/null 2>&1; then - sudo install -m 440 -o root -g wheel "$TMP" "$SUDO_FILE" - echo " 已写入 $SUDO_FILE: $WANT" +# ── 1. TUN 免密 sudoers(已生效则跳过,避免反复要密码)───────────────────────── +echo "==> [1/3] sing-box 免密 sudo(TUN 需 root)" +if sudo -n "$SINGBOX" version >/dev/null 2>&1; then + echo " 已生效,跳过(无需密码)" else - echo "✗ sudoers 语法校验失败"; rm -f "$TMP"; exit 1 + SUDO_FILE=/etc/sudoers.d/pangolin-singbox + WANT="$(whoami) ALL=(root) NOPASSWD: $SINGBOX" + TMP="$(mktemp)" + printf '%s\n' "$WANT" > "$TMP" + if sudo visudo -cf "$TMP" >/dev/null 2>&1; then + sudo install -m 440 -o root -g wheel "$TMP" "$SUDO_FILE" + echo " 已写入 $SUDO_FILE: $WANT" + else + echo "✗ sudoers 语法校验失败"; rm -f "$TMP"; exit 1 + fi + rm -f "$TMP" fi -rm -f "$TMP" -# ── 2. 构建 release ─────────────────────────────────────────────────────────── -echo "==> [2/3] flutter build macos --release (API=$API_URL)" -( cd "$CLIENT" && flutter build macos --release --dart-define=PANGOLIN_API_URL="$API_URL" ) +# ── 2. 构建 release(--no-build 跳过,直接跑上次产物)───────────────────────── +if [ "$NO_BUILD" = "1" ]; then + echo "==> [2/3] 跳过构建(--no-build)" +else + echo "==> [2/3] flutter build macos --release (API=$API_URL)" + ( cd "$CLIENT" && flutter build macos --release --dart-define=PANGOLIN_API_URL="$API_URL" ) +fi APP="$(ls -d "$CLIENT"/build/macos/Build/Products/Release/*.app 2>/dev/null | head -1)" [ -n "$APP" ] || { echo "✗ 未找到构建产物 .app"; exit 1; } diff --git a/server/internal/httpapi/clientconfig.go b/server/internal/httpapi/clientconfig.go index ba4ea2e..67e9033 100644 --- a/server/internal/httpapi/clientconfig.go +++ b/server/internal/httpapi/clientconfig.go @@ -114,8 +114,10 @@ func BuildClientConfig(node *nodes.NodeRow, dpUUID, deriveKey string) ([]byte, e "outbound": "direct", }, }, - "final": "auto", - "auto_detect_interface": true, + "final": "auto", + "auto_detect_interface": true, + // sing-box 1.12+ 要求显式声明出站域名用哪个 DNS 解析,缺失即 FATAL。 + "default_domain_resolver": map[string]any{"server": "local"}, } // DNS: remote over tunnel, local for domestic.