mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-10-10 04:03:04 +08:00
Unify TUN status classification around policy-routing evidence and wait for the controller before post-restart verification. Add a regression check for Issue #303.
This commit is contained in:
+54
-15
@@ -621,11 +621,14 @@ status_tun_effective_status() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
result="$(tun_effective_check 2>/dev/null || true)"
|
result="$(tun_current_effective_result 2>/dev/null || true)"
|
||||||
case "${result:-unknown}" in
|
case "${result:-unknown}" in
|
||||||
ok)
|
ok)
|
||||||
echo "effective"
|
echo "effective"
|
||||||
;;
|
;;
|
||||||
|
policy-routing-likely-effective)
|
||||||
|
echo "likely-effective"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ineffective"
|
echo "ineffective"
|
||||||
;;
|
;;
|
||||||
@@ -638,6 +641,7 @@ status_tun_effective_text() {
|
|||||||
|
|
||||||
case "$s" in
|
case "$s" in
|
||||||
effective) echo "🐱 已生效" ;;
|
effective) echo "🐱 已生效" ;;
|
||||||
|
likely-effective) echo "🟡 很可能已生效" ;;
|
||||||
*) echo "❗ 未生效" ;;
|
*) echo "❗ 未生效" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -2001,7 +2005,7 @@ print_tun_off_feedback() {
|
|||||||
ui_blank
|
ui_blank
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_on_verify_result() {
|
tun_resolve_effective_result() {
|
||||||
local result auto_redirect
|
local result auto_redirect
|
||||||
|
|
||||||
result="${1:-unknown}"
|
result="${1:-unknown}"
|
||||||
@@ -2018,13 +2022,31 @@ tun_on_verify_result() {
|
|||||||
|
|
||||||
auto_redirect="$(runtime_config_tun_auto_redirect 2>/dev/null || echo false)"
|
auto_redirect="$(runtime_config_tun_auto_redirect 2>/dev/null || echo false)"
|
||||||
if [ "${auto_redirect:-false}" = "true" ] && tun_has_policy_routing_evidence 2>/dev/null; then
|
if [ "${auto_redirect:-false}" = "true" ] && tun_has_policy_routing_evidence 2>/dev/null; then
|
||||||
echo "policy-routing-likely-effective"
|
if tun_log_tun_source_line >/dev/null 2>&1; then
|
||||||
|
echo "ok"
|
||||||
|
else
|
||||||
|
echo "policy-routing-likely-effective"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$result"
|
echo "$result"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tun_current_effective_result() {
|
||||||
|
local result
|
||||||
|
|
||||||
|
result="$(tun_effective_check 2>/dev/null || true)"
|
||||||
|
[ -n "${result:-}" ] || result="unknown"
|
||||||
|
tun_resolve_effective_result "$result"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backward-compatible helper retained for callers that already captured the
|
||||||
|
# low-level Tun result.
|
||||||
|
tun_on_verify_result() {
|
||||||
|
tun_resolve_effective_result "${1:-unknown}"
|
||||||
|
}
|
||||||
|
|
||||||
status_subscription_health_summary() {
|
status_subscription_health_summary() {
|
||||||
local active health fail_count auto_disabled
|
local active health fail_count auto_disabled
|
||||||
|
|
||||||
@@ -2146,8 +2168,17 @@ status_risk_reason_lines() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$tun_enabled" = "true" ] && [ "$tun_effective" != "effective" ]; then
|
if [ "$tun_enabled" = "true" ]; then
|
||||||
echo "• Tun 未生效"
|
case "$tun_effective" in
|
||||||
|
effective)
|
||||||
|
;;
|
||||||
|
likely-effective)
|
||||||
|
echo "• Tun policy routing 已安装,尚未观察到明确 Tun 流量"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "• Tun 未生效"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$tun_container_mode" = "container-risky" ]; then
|
if [ "$tun_container_mode" = "container-risky" ]; then
|
||||||
@@ -5343,11 +5374,17 @@ cmd_tun_status() {
|
|||||||
echo "🚨 环境检查:当前不满足基础开启条件"
|
echo "🚨 环境检查:当前不满足基础开启条件"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$effective_status" = "effective" ]; then
|
case "$effective_status" in
|
||||||
echo "🐱 已生效"
|
effective)
|
||||||
else
|
echo "🐱 已生效"
|
||||||
echo "❗ 未生效"
|
;;
|
||||||
fi
|
likely-effective)
|
||||||
|
echo "🟡 很可能已生效(已检测到 Tun 与 policy routing,尚未观察到明确 Tun 流量)"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "❗ 未生效"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ "$enabled" = "true" ]; then
|
if [ "$enabled" = "true" ]; then
|
||||||
echo "👉 下一步:clash tun doctor"
|
echo "👉 下一步:clash tun doctor"
|
||||||
@@ -5425,11 +5462,13 @@ cmd_tun_on() {
|
|||||||
|
|
||||||
if status_is_running; then
|
if status_is_running; then
|
||||||
service_restart
|
service_restart
|
||||||
|
if ! wait_runtime_controller_ready 15; then
|
||||||
|
ui_warn "控制器未在预期时间内就绪,将保留 Tun 开启状态并报告当前验证结果"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
verify_result="$(tun_effective_check 2>/dev/null || true)"
|
verify_result="$(tun_current_effective_result 2>/dev/null || true)"
|
||||||
[ -n "${verify_result:-}" ] || verify_result="unknown"
|
[ -n "${verify_result:-}" ] || verify_result="unknown"
|
||||||
verify_result="$(tun_on_verify_result "$verify_result")"
|
|
||||||
|
|
||||||
case "$verify_result" in
|
case "$verify_result" in
|
||||||
ok)
|
ok)
|
||||||
@@ -5715,7 +5754,7 @@ doctor_tun_checks() {
|
|||||||
|
|
||||||
echo "【生效验证】"
|
echo "【生效验证】"
|
||||||
if [ "$(tun_enabled 2>/dev/null || echo false)" = "true" ]; then
|
if [ "$(tun_enabled 2>/dev/null || echo false)" = "true" ]; then
|
||||||
effective_result="$(tun_effective_check 2>/dev/null || true)"
|
effective_result="$(tun_current_effective_result 2>/dev/null || true)"
|
||||||
primary_reason="$(tun_doctor_primary_reason "$effective_result" "$backend" "$route_takeover")" || {
|
primary_reason="$(tun_doctor_primary_reason "$effective_result" "$backend" "$route_takeover")" || {
|
||||||
rc=$?
|
rc=$?
|
||||||
tun_doctor_report_failure "tun_doctor_primary_reason" "$rc" "derive primary reason"
|
tun_doctor_report_failure "tun_doctor_primary_reason" "$rc" "derive primary reason"
|
||||||
@@ -6476,7 +6515,7 @@ tun_recommendation_lines() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$enabled" = "true" ]; then
|
if [ "$enabled" = "true" ]; then
|
||||||
effective_result="$(tun_effective_check 2>/dev/null || true)"
|
effective_result="$(tun_current_effective_result 2>/dev/null || true)"
|
||||||
[ -n "${effective_result:-}" ] || effective_result="unknown"
|
[ -n "${effective_result:-}" ] || effective_result="unknown"
|
||||||
[ -n "${primary_reason:-}" ] || primary_reason="$(tun_doctor_primary_reason "$effective_result" "$backend" "$route_takeover")"
|
[ -n "${primary_reason:-}" ] || primary_reason="$(tun_doctor_primary_reason "$effective_result" "$backend" "$route_takeover")"
|
||||||
|
|
||||||
@@ -6625,7 +6664,7 @@ tun_problem_lines() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$enabled" = "true" ]; then
|
if [ "$enabled" = "true" ]; then
|
||||||
effective_result="$(tun_effective_check 2>/dev/null || true)"
|
effective_result="$(tun_current_effective_result 2>/dev/null || true)"
|
||||||
if [ "$effective_result" != "ok" ]; then
|
if [ "$effective_result" != "ok" ]; then
|
||||||
if tun_has_policy_routing_evidence 2>/dev/null; then
|
if tun_has_policy_routing_evidence 2>/dev/null; then
|
||||||
if tun_log_tun_source_line >/dev/null 2>&1; then
|
if tun_log_tun_source_line >/dev/null 2>&1; then
|
||||||
|
|||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
source_clashctl_for_tests() {
|
||||||
|
set -- ""
|
||||||
|
# Source the real functions; suppress the no-arg usage printed by the command dispatcher.
|
||||||
|
source "$PROJECT_DIR/scripts/core/clashctl.sh" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
source_clashctl_for_tests
|
||||||
|
|
||||||
|
assert_equal() {
|
||||||
|
local name="$1"
|
||||||
|
local expected="$2"
|
||||||
|
local actual="$3"
|
||||||
|
|
||||||
|
if [ "$actual" != "$expected" ]; then
|
||||||
|
echo "not ok - $name: got '$actual', expected '$expected'" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ok - $name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reproduce Issue #303: policy routing sends both direct-looking probes through
|
||||||
|
# Tun, so comparing their public IPs alone reports traffic-same-as-host.
|
||||||
|
tun_enabled() { printf 'true\n'; }
|
||||||
|
runtime_config_tun_enabled() { printf 'true\n'; }
|
||||||
|
status_is_running() { return 0; }
|
||||||
|
proxy_controller_reachable() { return 0; }
|
||||||
|
tun_public_ip_without_proxy_env() { printf '203.0.113.10\n'; }
|
||||||
|
tun_public_ip_with_current_route() { printf '203.0.113.10\n'; }
|
||||||
|
runtime_config_tun_auto_redirect() { printf 'true\n'; }
|
||||||
|
tun_has_policy_routing_evidence() { return 0; }
|
||||||
|
tun_log_tun_source_line() { printf '[TCP] 28.0.0.1:1234 --> example.com:443\n'; }
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"accepts policy routing with observed Tun traffic" \
|
||||||
|
"ok" \
|
||||||
|
"$(tun_current_effective_result)"
|
||||||
|
|
||||||
|
# The same classifier must drive both status commands. Without observed traffic,
|
||||||
|
# keep the result explicit instead of presenting a false negative.
|
||||||
|
tun_log_tun_source_line() { return 1; }
|
||||||
|
assert_equal \
|
||||||
|
"reports policy routing without traffic as likely effective" \
|
||||||
|
"policy-routing-likely-effective" \
|
||||||
|
"$(tun_current_effective_result)"
|
||||||
|
assert_equal \
|
||||||
|
"maps likely policy routing to a distinct status" \
|
||||||
|
"likely-effective" \
|
||||||
|
"$(status_tun_effective_status)"
|
||||||
|
|
||||||
|
# Reproduce the restart race: verification must happen only after waiting for
|
||||||
|
# the controller following service_restart.
|
||||||
|
tmp_dir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$tmp_dir"' EXIT
|
||||||
|
events_file="$tmp_dir/events"
|
||||||
|
: > "$events_file"
|
||||||
|
|
||||||
|
record_event() {
|
||||||
|
printf '%s\n' "$1" >> "$events_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
guard_sudo_on_user_install() { return 0; }
|
||||||
|
prepare() { :; }
|
||||||
|
tun_container_mode() { printf 'host\n'; }
|
||||||
|
tun_container_risk_reason() { :; }
|
||||||
|
can_manage_tun_safely() { return 0; }
|
||||||
|
tun_kernel_support_level() { printf 'full\n'; }
|
||||||
|
sync_tun_target_state() { return 0; }
|
||||||
|
service_restart() { record_event restart; }
|
||||||
|
wait_runtime_controller_ready() { record_event wait; return 0; }
|
||||||
|
tun_current_effective_result() { record_event verify; printf 'ok\n'; }
|
||||||
|
mark_tun_last_action() { :; }
|
||||||
|
mark_tun_last_verification() { :; }
|
||||||
|
print_tun_on_feedback() { :; }
|
||||||
|
|
||||||
|
cmd_tun_on
|
||||||
|
assert_equal \
|
||||||
|
"waits for controller before Tun verification" \
|
||||||
|
"restart,wait,verify" \
|
||||||
|
"$(paste -sd, "$events_file")"
|
||||||
Reference in New Issue
Block a user