Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ $ clashsecret
- 可通过浏览器打开 `Web` 控制台进行可视化操作,例如切换节点、查看日志等。
- `clashctl secret` 与 `clashsecret` 都支持无参数查看、有参数直接设置。
- 默认使用 [zashboard](https://github.com/Zephyruso/zashboard) 作为控制台前端,如需更换可自行配置。
- 运行配置会把 `external-ui` 指向本地 Dashboard 目录,并把 `external-ui-url` 指向 zashboard 的 `dist.zip` 下载地址;面板内 `/upgrade/ui` 会使用该地址更新前端。
- 若需将控制台暴露到公网,建议定期更换访问密钥,或通过 `SSH` 端口转发方式进行安全访问。

------
Expand Down Expand Up @@ -445,11 +446,17 @@ clashctl relay remove 多跳-示例
```bash
clashctl tun on
clashctl tun off
clashctl tun on-proxy-off
clashctl tun off-proxy-on
clashctl tun doctor
clashctl tun logs
```

Tun 用于透明接管链路。`tun on` 是动作反馈,展示当前关键配置和简短状态;完整证据请看:
Tun 用于透明接管链路。`tun on` 只负责开启 Tun,不会自动关闭系统代理;如需切换到 Tun 接管并关闭系统代理,使用 `clashctl tun on-proxy-off`。如需关闭 Tun 并恢复普通系统代理模式,使用 `clashctl tun off-proxy-on`。

`clashctl doctor` 会检查 Tun 与系统代理是否同时开启;如果同时开启,会提示 `clashctl tun on-proxy-off`,避免流量接管路径重复或排障混淆。

`tun on` 是动作反馈,展示当前关键配置和简短状态;完整证据请看:

```bash
clashctl tun doctor
Expand Down
103 changes: 102 additions & 1 deletion scripts/core/clashctl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3241,6 +3241,32 @@ doctor_container_tun() {
esac
}

doctor_tun_system_proxy() {
local tun_state system_proxy_state

doctor_print_title "Tun 与系统代理检查"

tun_state="$(tun_enabled 2>/dev/null || echo false)"
system_proxy_state="$(system_proxy_status 2>/dev/null || echo off)"

if [ "$tun_state" = "true" ]; then
doctor_ok "Tun 模式:已开启"
else
doctor_ok "Tun 模式:已关闭"
fi

if [ "$system_proxy_state" = "on" ]; then
doctor_ok "系统代理持久接管:已开启"
else
doctor_ok "系统代理持久接管:已关闭"
fi

if [ "$tun_state" = "true" ] && [ "$system_proxy_state" = "on" ]; then
doctor_warn "Tun 模式与系统代理同时开启,可能造成流量接管路径重复或排障混淆"
echo " 建议:clashctl tun on-proxy-off"
fi
}

doctor_dependencies() {
local dashboard_source

Expand Down Expand Up @@ -3843,6 +3869,7 @@ cmd_doctor() {
doctor_install_context
doctor_dependencies
doctor_container_tun
doctor_tun_system_proxy
doctor_config
doctor_subscription
doctor_build
Expand Down Expand Up @@ -4571,6 +4598,11 @@ doctor_problem_lines() {
if [ "$(status_build_last_status 2>/dev/null || true)" = "failed" ]; then
echo "🚨 最近一次编译失败"
fi

if [ "$(tun_enabled 2>/dev/null || echo false)" = "true" ] \
&& [ "$(system_proxy_status 2>/dev/null || echo off)" = "on" ]; then
echo "🚨 Tun 模式与系统代理同时开启"
fi
}

doctor_primary_conclusion() {
Expand Down Expand Up @@ -4653,6 +4685,13 @@ doctor_recommendation_lines() {
return 0
fi

if [ "$(tun_enabled 2>/dev/null || echo false)" = "true" ] \
&& [ "$(system_proxy_status 2>/dev/null || echo off)" = "on" ]; then
echo "💡 clashctl tun on-proxy-off"
echo "💡 如需恢复普通系统代理模式:clashctl tun off-proxy-on"
return 0
fi

case "$system_proxy_text" in
unsupported|off)
if [ -n "${mixed_port:-}" ] && [ "$mixed_port" != "null" ]; then
Expand All @@ -4672,7 +4711,7 @@ doctor_recommendation_lines() {

doctor_evidence_lines() {
local active_sub mixed_port controller bind_failure_kind bind_failure_line dns_port
local system_proxy_text process_proxy_env
local system_proxy_text process_proxy_env tun_state system_proxy_state

active_sub="$(active_subscription_name 2>/dev/null || true)"
mixed_port="$(runtime_mixed_port_bind_failure_port 2>/dev/null || status_read_mixed_port 2>/dev/null || true)"
Expand All @@ -4682,6 +4721,8 @@ doctor_evidence_lines() {
dns_port="$(runtime_config_dns_port 2>/dev/null || true)"
system_proxy_text="$(persistent_system_proxy_text 2>/dev/null || echo unknown)"
process_proxy_env="$(current_process_proxy_env_text 2>/dev/null || echo unknown)"
tun_state="$(tun_enabled 2>/dev/null || echo false)"
system_proxy_state="$(system_proxy_status 2>/dev/null || echo off)"

if runtime_config_exists; then
echo "🔍 运行配置:存在"
Expand Down Expand Up @@ -4744,6 +4785,7 @@ doctor_evidence_lines() {

echo "🔍 系统代理持久接管:${system_proxy_text}"
echo "🔍 当前命令环境代理:${process_proxy_env}"
echo "🔍 Tun 与系统代理:tun=${tun_state}, system_proxy=${system_proxy_state}"
}

set_controller_secret() {
Expand Down Expand Up @@ -4978,6 +5020,53 @@ cmd_tun_off() {
print_tun_off_feedback "$verify_result"
}

cmd_tun_on_proxy_off() {
local system_proxy_rc

cmd_tun_on || return $?

if boot_proxy_keep_disable; then
ui_blank
ui_ok "系统代理已关闭,当前使用 Tun 模式接管"
ui_blank
return 0
fi

system_proxy_rc=$?
if [ "$system_proxy_rc" -eq 2 ]; then
ui_warn "当前环境不支持清理系统代理持久块,Tun 已按前序结果处理"
else
ui_warn "系统代理持久块清理失败,Tun 已按前序结果处理"
fi
ui_next "clashctl doctor"
ui_blank
return "$system_proxy_rc"
}

cmd_tun_off_proxy_on() {
local system_proxy_rc

cmd_tun_off || return $?

if system_proxy_enable; then
ui_blank
ui_ok "系统代理已开启,当前使用本地代理接管"
ui_blank
return 0
fi

system_proxy_rc=$?
write_runtime_value "RUNTIME_BOOT_PROXY_KEEP" "false" 2>/dev/null || true
if [ "$system_proxy_rc" -eq 2 ]; then
ui_warn "当前环境不支持系统代理持久接管,Tun 已按前序结果处理"
else
ui_warn "系统代理持久接管写入失败,Tun 已按前序结果处理"
fi
ui_next "clashctl doctor"
ui_blank
return "$system_proxy_rc"
}

tun_runtime_status_text() {
if [ "$(tun_enabled)" = "true" ]; then
echo "已开启"
Expand Down Expand Up @@ -6024,6 +6113,15 @@ cmd_tun() {
off)
cmd_tun_off
;;
on-proxy-off|proxy-off)
cmd_tun_on_proxy_off
;;
off-proxy-on|proxy-on)
cmd_tun_off_proxy_on
;;
log|logs)
cmd_logs mihomo
;;
doctor)
doctor_tun_checks
;;
Expand All @@ -6034,7 +6132,10 @@ cmd_tun() {
echo " clashctl tun status"
echo " clashctl tun on"
echo " clashctl tun off"
echo " clashctl tun on-proxy-off"
echo " clashctl tun off-proxy-on"
echo " clashctl tun doctor"
echo " clashctl tun logs"
echo
echo "🧩 说明:"
echo " Tun 属于高级接管能力"
Expand Down
1 change: 1 addition & 0 deletions scripts/core/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ DEFAULT_MIHOMO_VERSION="${MIHOMO_VERSION:-v1.19.23}"
DEFAULT_CLASH_VERSION="${CLASH_VERSION:-v1.18.0}"
DEFAULT_SUBCONVERTER_VERSION="${SUBCONVERTER_VERSION:-v0.9.9}"
DEFAULT_YQ_VERSION="${YQ_VERSION:-v4.52.4}"
DEFAULT_DASHBOARD_UI_URL="${DASHBOARD_UI_URL:-https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip}"

log() { printf '%s\n' "$*"; }
info() { printf 'ℹ %s\n' "$*"; }
Expand Down
2 changes: 1 addition & 1 deletion scripts/core/completion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ _clash_for_linux_complete_tun() {
COMPREPLY=()

if [ "$rel_index" -eq 1 ]; then
_clash_for_linux_add_matches "$cur" status on off doctor
_clash_for_linux_add_matches "$cur" status on off on-proxy-off off-proxy-on proxy-off proxy-on doctor log logs
fi
}

Expand Down
6 changes: 4 additions & 2 deletions scripts/core/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ normalize_runtime_config() {
local file="$1"
local mixed_port controller tun_enable_value tun_stack_value dns_port_value controller_secret_value
local tun_auto_route_value tun_auto_redirect_value tun_strict_route_value tun_dns_hijack_value
local dashboard_dir_value allow_lan_value
local dashboard_dir_value dashboard_url_value allow_lan_value
local resolved_ports err_file output

[ -s "$file" ] || die "待规范化的配置文件不存在:$file"
Expand All @@ -820,6 +820,7 @@ normalize_runtime_config() {
dns_port_value="$CLASH_DNS_PORT_RESOLVED"
controller_secret_value="$(ensure_controller_secret)"
dashboard_dir_value="$(runtime_dashboard_dir)"
dashboard_url_value="$DEFAULT_DASHBOARD_UI_URL"
allow_lan_value="$(config_allow_lan 2>/dev/null || echo true)"

err_file="$(mktemp)"
Expand All @@ -834,13 +835,14 @@ normalize_runtime_config() {
tun_dns_hijack_value="$tun_dns_hijack_value" \
controller_secret_value="$controller_secret_value" \
dashboard_dir_value="$dashboard_dir_value" \
dashboard_url_value="$dashboard_url_value" \
dns_listen_value="0.0.0.0:${dns_port_value}" \
"$(yq_bin)" eval -i '
.["mixed-port"] = (env(mixed_port) | tonumber) |
.["external-controller"] = env(controller) |
.secret = env(controller_secret_value) |
.["external-ui"] = env(dashboard_dir_value) |
.["external-ui-url"] = "/ui" |
.["external-ui-url"] = env(dashboard_url_value) |
.["allow-lan"] = (env(allow_lan_value) == "true") |
.mode = "rule" |
.["log-level"] = (.["log-level"] // "info") |
Expand Down