feat(doctor): расширенная офлайн-диагностика (NTP, conntrack, deadlock, MTU) и аварийный возврат интернета

This commit is contained in:
Dushnilin
2026-08-15 17:18:23 +03:00
parent 56e847eceb
commit 528bc7b9db
6 changed files with 141 additions and 3 deletions
+16
View File
@@ -3910,3 +3910,19 @@ msgstr "Выбрать"
msgid "Switch to auto-selection"
msgstr "Вернуть автовыбор"
msgid "Restore Native Internet (Stop Tachyon)"
msgstr "Вернуть обычный интернет (остановить Tachyon)"
msgid "Sync System Time (NTP)"
msgstr "Синхронизировать время (NTP)"
msgid "Flush Conntrack Table"
msgstr "Очистить таблицу соед. (conntrack)"
msgid "Reset Bootstrap DNS"
msgstr "Сбросить Bootstrap DNS"
msgid "Optimize AWG MTU"
msgstr "Оптимизировать MTU AWG"
@@ -1083,6 +1083,11 @@ async function handleRunAiDoctor() {
switch_to_doh: _('Switch DNS to DoH'),
heal_network_stack: _('Auto-Heal Network Stack'),
enable_safe_bypass: _('Enable Direct WAN Bypass'),
restore_native_internet: _('Restore Native Internet (Stop Tachyon)'),
fix_system_time: _('Sync System Time (NTP)'),
flush_conntrack: _('Flush Conntrack Table'),
fix_bootstrap_dns: _('Reset Bootstrap DNS'),
optimize_mtu: _('Optimize AWG MTU'),
};
const renderRootCauseBanner = () => {
@@ -12626,7 +12626,12 @@ async function handleRunAiDoctor() {
optimize_memory: _("Optimize RAM memory"),
switch_to_doh: _("Switch DNS to DoH"),
heal_network_stack: _("Auto-Heal Network Stack"),
enable_safe_bypass: _("Enable Direct WAN Bypass")
enable_safe_bypass: _("Enable Direct WAN Bypass"),
restore_native_internet: _("Restore Native Internet (Stop Tachyon)"),
fix_system_time: _("Sync System Time (NTP)"),
flush_conntrack: _("Flush Conntrack Table"),
fix_bootstrap_dns: _("Reset Bootstrap DNS"),
optimize_mtu: _("Optimize AWG MTU")
};
const renderRootCauseBanner = () => {
return E(
+16
View File
@@ -3910,3 +3910,19 @@ msgstr "Выбрать"
msgid "Switch to auto-selection"
msgstr "Вернуть автовыбор"
msgid "Restore Native Internet (Stop Tachyon)"
msgstr "Вернуть обычный интернет (остановить Tachyon)"
msgid "Sync System Time (NTP)"
msgstr "Синхронизировать время (NTP)"
msgid "Flush Conntrack Table"
msgstr "Очистить таблицу соед. (conntrack)"
msgid "Reset Bootstrap DNS"
msgstr "Сбросить Bootstrap DNS"
msgid "Optimize AWG MTU"
msgstr "Оптимизировать MTU AWG"
+82 -1
View File
@@ -3403,6 +3403,26 @@ function apply_quick_fix(codes_str) {
command_status("uci set tachyon.settings.recovery_bypass='1'; uci commit tachyon; /etc/init.d/tachyon reload >/dev/null 2>&1");
status = true;
msg = "Safe Direct WAN bypass enabled";
} else if (c == "restore_native_internet") {
command_status("/usr/bin/tachyon restore_dnsmasq 2>/dev/null; /etc/init.d/tachyon stop >/dev/null 2>&1; nft delete table inet TachyonTable 2>/dev/null; ip -4 rule del fwmark 0x04000000/0x04000000 table tachyon 2>/dev/null; ip -6 rule del fwmark 0x04000000/0x04000000 table tachyon 2>/dev/null; ip route flush table tachyon 2>/dev/null; /etc/init.d/dnsmasq restart >/dev/null 2>&1; ip route flush cache 2>/dev/null");
status = true;
msg = "Tachyon stopped, stock dnsmasq and native direct internet routing restored";
} else if (c == "fix_system_time") {
command_status("ntpd -q -p pool.ntp.org 2>/dev/null || rdate -s time.cloudflare.com 2>/dev/null; /etc/init.d/sysntpd restart 2>/dev/null");
status = true;
msg = "System time synchronized with NTP";
} else if (c == "flush_conntrack") {
command_status("sysctl -w net.netfilter.nf_conntrack_max=65536 2>/dev/null; echo 1 > /proc/sys/net/netfilter/nf_conntrack_max 2>/dev/null || true; conntrack -F 2>/dev/null || true");
status = true;
msg = "Conntrack table limits expanded and flushed";
} else if (c == "fix_bootstrap_dns") {
command_status("uci set tachyon.settings.bootstrap_dns_server='77.88.8.8'; uci commit tachyon; /etc/init.d/tachyon reload >/dev/null 2>&1");
status = true;
msg = "Bootstrap DNS reset to reliable public resolver (77.88.8.8) and reloaded";
} else if (c == "optimize_mtu") {
command_status("/usr/bin/tachyon discover-awg-mtu 2>/dev/null; /etc/init.d/tachyon reload >/dev/null 2>&1");
status = true;
msg = "AWG MTU discovery executed and tunnels reloaded";
} else {
status = false;
msg = "Unknown fix code: " + c;
@@ -3448,20 +3468,25 @@ function ai_doctor_last() {
}
const DOCTOR_FIX_PRIORITIES = {
"fix_system_time": 5,
"fix_wan_interface": 10,
"restart_network": 15,
"fix_gateway": 20,
"fix_resolv_symlink": 30,
"fix_dnsmasq": 35,
"fix_bootstrap_dns": 38,
"switch_to_doh": 40,
"clear_dns_cache": 45,
"start_singbox": 50,
"restart_zapret": 60,
"optimize_mtu": 65,
"rebuild_rules": 70,
"update_subscriptions": 80,
"flush_conntrack": 85,
"optimize_memory": 90,
"enable_safe_bypass": 95,
"heal_network_stack": 100
"heal_network_stack": 100,
"restore_native_internet": 110
};
function doctor_fix_sort(a, b) {
@@ -3632,6 +3657,51 @@ function diagnose_system_conflicts(cfg, lang, causes, fn_add_fix) {
}
}
function diagnose_system_clock_and_conntrack(cfg, lang, causes, fn_add_fix) {
let current_t = time();
if (current_t < 1735689600) {
push(causes, {
probability: 98,
cause: lang == "en" ? "System clock is not synchronized (year < 2025 causes TLS/x509 certificate validation failures)"
: "Системное время роутера не синхронизировано (дата в прошлом ломает валидацию TLS/SSL сертификатов узлов)",
fix: "fix_system_time"
});
fn_add_fix("fix_system_time");
}
let count_raw = trim(fs.readfile("/proc/sys/net/netfilter/nf_conntrack_count") || "");
let max_raw = trim(fs.readfile("/proc/sys/net/netfilter/nf_conntrack_max") || "");
if (count_raw != "" && max_raw != "") {
let ct_count = int(count_raw);
let ct_max = int(max_raw);
if (ct_max > 0 && (ct_count * 100 / ct_max) >= 88) {
push(causes, {
probability: 89,
cause: lang == "en" ? sprintf("NAT/Firewall connection tracking table nearly full (%d/%d sessions)", ct_count, ct_max)
: sprintf("Таблица отслеживания соединений файрвола (conntrack) почти переполнена (%d/%d сессий)", ct_count, ct_max),
fix: "flush_conntrack"
});
fn_add_fix("flush_conntrack");
}
}
}
function diagnose_dns_deadlock_and_mtu(cfg, lang, causes, fn_add_fix) {
let raw_sb_log = trim(command_output("logread | grep -iE 'lookup.*no such host|lookup.*timeout|dns: lookup failed' | tail -n 10 2>/dev/null"));
if (raw_sb_log != "" && index(raw_sb_log, "lookup") >= 0) {
let b_dns = cfg.bootstrap_dns_server || "";
if (b_dns == "127.0.0.1" || b_dns == "127.0.0.42") {
push(causes, {
probability: 93,
cause: lang == "en" ? "DNS Deadlock: Bootstrap DNS resolver points to local loopback (resolver loop)"
: "DNS Deadlock: Bootstrap-DNS для sing-box указывает на локальный адрес (зацикливание)",
fix: "fix_bootstrap_dns"
});
fn_add_fix("fix_bootstrap_dns");
}
}
}
function local_rule_doctor() {
let cfg = uci_settings();
let lang = lc(trim(cfg.ai_doctor_lang || "ru"));
@@ -3784,6 +3854,17 @@ function local_rule_doctor() {
// ── 7. OpenWrt Service & Port Conflicts ──
try { diagnose_system_conflicts(cfg, lang, causes, add_fix); } catch(e) { warn("Conflict diag error: " + as_string(e) + "\n"); }
// ── 8. System Clock & Connection Tracking ──
try { diagnose_system_clock_and_conntrack(cfg, lang, causes, add_fix); } catch(e) { warn("Clock/Conntrack diag error: " + as_string(e) + "\n"); }
// ── 9. DNS Deadlock & MTU ──
try { diagnose_dns_deadlock_and_mtu(cfg, lang, causes, add_fix); } catch(e) { warn("DNS Deadlock/MTU diag error: " + as_string(e) + "\n"); }
// If multiple critical failures, provide emergency native internet restoration
if (verify.failed >= 2) {
add_fix("restore_native_internet");
}
// Sort fixes by priority order
try { quick_fixes = prioritize_quick_fixes(quick_fixes); } catch(e) { warn("Prioritize error: " + as_string(e) + "\n"); }
+16 -1
View File
@@ -30,7 +30,7 @@ echo "$output" | grep -Fq '"provider": "local_heuristic"' ||
fail "ai-doctor in offline mode must report provider local_heuristic"
# 3. Test apply-quick-fix for new codes
fix_out="$(ucode -L "$TACHYON_LIB" "$TACHYON_LIB/diagnostics/runtime.uc" apply-quick-fix "restart_zapret,optimize_memory" 2>/dev/null || true)"
fix_out="$(ucode -L "$TACHYON_LIB" "$TACHYON_LIB/diagnostics/runtime.uc" apply-quick-fix "restart_zapret,optimize_memory,restore_native_internet,fix_system_time,flush_conntrack,fix_bootstrap_dns,optimize_mtu" 2>/dev/null || true)"
echo "$fix_out" | grep -Fq '"code": "restart_zapret"' ||
fail "apply_quick_fix must handle restart_zapret"
@@ -38,6 +38,21 @@ echo "$fix_out" | grep -Fq '"code": "restart_zapret"' ||
echo "$fix_out" | grep -Fq '"code": "optimize_memory"' ||
fail "apply_quick_fix must handle optimize_memory"
echo "$fix_out" | grep -Fq '"code": "restore_native_internet"' ||
fail "apply_quick_fix must handle restore_native_internet"
echo "$fix_out" | grep -Fq '"code": "fix_system_time"' ||
fail "apply_quick_fix must handle fix_system_time"
echo "$fix_out" | grep -Fq '"code": "flush_conntrack"' ||
fail "apply_quick_fix must handle flush_conntrack"
echo "$fix_out" | grep -Fq '"code": "fix_bootstrap_dns"' ||
fail "apply_quick_fix must handle fix_bootstrap_dns"
echo "$fix_out" | grep -Fq '"code": "optimize_mtu"' ||
fail "apply_quick_fix must handle optimize_mtu"
# 4. Doctor must work with the service stopped (recovery mode: restore stock
# internet, never start Tachyon) and the AI Doctor must verify the system
# end-to-end instead of trusting a point-in-time snapshot.