diff --git a/tachyon/files/usr/lib/service/event_controller.uc b/tachyon/files/usr/lib/service/event_controller.uc index 125cc47e..c09fd0b9 100644 --- a/tachyon/files/usr/lib/service/event_controller.uc +++ b/tachyon/files/usr/lib/service/event_controller.uc @@ -235,7 +235,9 @@ function proxy_port() { if (cached_proxy_port !== null) return as_string(cached_proxy_port); - let port = "4534"; + // Empty when the generated config has no http/mixed inbound: probing the + // default port would measure a dead listener and report the proxy broken. + let port = ""; let sb_cfg = parse_singbox_config(); if (sb_cfg && sb_cfg.inbounds) { for (let inb in sb_cfg.inbounds) { @@ -508,6 +510,9 @@ function controller(bus, opts) { if (pid == "" || !process_running(pid, "sing-box")) return; let port = proxy_port(); + // No http/mixed inbound in the generated config: there is nothing to + // measure, so the proxy must not be declared broken on a dead port. + if (port == "") return; let check_url = setting("ai_proxy_health_url", "https://cp.cloudflare.com/generate_204"); let started = time(); diff --git a/tachyon/files/usr/lib/service/watchdog.uc b/tachyon/files/usr/lib/service/watchdog.uc index 2260dd9f..20a4b2f2 100644 --- a/tachyon/files/usr/lib/service/watchdog.uc +++ b/tachyon/files/usr/lib/service/watchdog.uc @@ -1313,6 +1313,8 @@ function smart_detect_process_pending() { // Reuse the controller's cached port value: re-parsing config.json here // would duplicate the work event_controller already does (and caches). let proxy_addr = "127.0.0.1:" + controller.proxy_port(); + // No http/mixed inbound in the generated config: probing is pointless. + if (proxy_addr == "127.0.0.1:") return; let detect_sections = []; let raw_list = cfg.smart_detect_sections; diff --git a/tests/heal_suppression.sh b/tests/heal_suppression.sh index 77a80d64..b2218020 100644 --- a/tests/heal_suppression.sh +++ b/tests/heal_suppression.sh @@ -105,6 +105,19 @@ echo "$wan_heal_body" | grep -q 'if (settings().recovery_bypass == "1") return;' echo "$wan_heal_body" | grep -q '/sbin/ubus call network.interface.wan renew' \ || fail "heal_wan_and_gateway no longer tries a graceful renew before ifdown/ifup" +# ── no http/mixed inbound → the proxy probe must not declare it broken ─────── +# proxy_port() used to fall back to the hardcoded 4534, so a config without +# any http/mixed inbound (economy mode, all mixed proxies off) measured a dead +# listener and the watchdog restarted sing-box every ~minute (issue #31). +proxy_port_body="$(sed -n '/^function proxy_port()/,/^}$/p' "$CONTROLLER_UC")" +echo "$proxy_port_body" | grep -q 'let port = "";' \ + || fail "proxy_port() still defaults to a fake port instead of signalling 'no proxy inbound'" +proxy_probe_body="$(sed -n '/function probe_proxy()/,/^ }$/p' "$CONTROLLER_UC")" +echo "$proxy_probe_body" | grep -q 'if (port == "") return;' \ + || fail "probe_proxy() probes a dead default port when the config has no http/mixed inbound" +grep -q 'if (proxy_addr == "127.0.0.1:") return;' "$WATCHDOG_UC" \ + || fail "smart-detect probes the empty proxy address when the config has no http/mixed inbound" + # ── the consequences actually check ─────────────────────────────────────────── for healer in heal_dns_stall heal_proxy_connectivity heal_proxy_health heal_dns_continuous; do grep -q "suppressed_by_root_cause(\"$healer\")" "$WATCHDOG_UC" \