Commit Graph
23 Commits
Author SHA1 Message Date
Dushnilin 7375e26b44 fix(qos): harmonize SQM and CAKE cooperation, resolve bufferbloat degradation 2026-09-14 17:03:45 +03:00
Dushnilin 22ec19b49b fix(watchdog): eliminate WAN false alarms on bridge/Tailscale and restore domain/subnet lists (.lst/.txt) 2026-09-13 20:47:22 +03:00
Dushnilin 70bb7280c1 fix(fuzzer): eliminate fuzzer hangs, preserve DNS flags, and optimize probing performance 2026-09-13 10:03:56 +03:00
Dushnilin 2019ddd12a release: 1.3.26 — Watchdog proxy restart protection, WAN monitor debounce, and subscription bootstrap resilience
- Fix #52: Watchdog proxy restart on single URL failure:
  * Validate failure against secondary independent probe URL before declaring proxy down
  * Skip restart when direct WAN is also degraded or down (!direct_ok)
  * Implement 120s cooldown between automated proxy restarts
  * Fix Telegram notification to accurately state 'Перезапуск sing-box' instead of 'Перезапуск роутера'
- Fix #51: Telegram bot spamming WAN up/down notifications:
  * Filter hotplug events strictly by badwan_monitored_interfaces (defaults to wan)
  * Add atomic directory lock with debounce delay and real ubus state query
  * Prevent repeated notifications when interface state has not transitioned
- Feat: 2-VPN deadlock elimination & self-download subscription proxy:
  * Isolate unbootstrapped dependent subscription sections on initial boot (deferred_sections)
  * Allow self-download proxy target for subscriptions with explicit UI hint '(текущее правило при активности)'
  * Enable automatic local proxy fallback for subscription refresh when direct WAN download fails while sing-box is active
  * Add regression test in tests/subscription_bootstrap_deadlock.sh
- Fix: Parental control quota enforcement:
  * Correct route rule filtering when daily quota minutes are exhausted without a fixed time interval
- i18n & Version bump:
  * Bump fe-app-tachyon to 1.3.26 and update Russian PO/POT translations
2026-09-12 16:50:04 +03:00
Dushnilin 11925e7ec5 fix(updates): resolve tag commit SHA and format build fingerprints; fix telegram, watchdog and logs 2026-09-05 23:52:16 +03:00
Dushnilin 7cfd737d21 fix(watchdog): bind probe_wan to configured output_network_interface 2026-09-05 12:50:15 +03:00
Dushnilin 529db5fc6c fix(watchdog,priority,dns_failover,providers): reduce CPU/memory footprint on low-end routers (1.3.20)
- priority.uc: replace 1s tight sleep loop with dynamic interval based on group config (5s default)
- dns_failover.uc: replace 1s sleep with min(active_interval, recovery_interval)
- watchdog.uc: cap pending_smart_domains at 500 entries, add 300s TTL expiry
- event_controller.uc: batch is_dns_working nslookup calls into single shell process
- byedpi/runtime.uc: add crash-loop backoff (up to 6x base delay after 5 rapid crashes)
- nfqueue/runtime.uc: same crash-loop backoff for nfqws supervisors
2026-09-04 19:44:20 +03:00
Dushnilin 78bdd0b412 fix(core): optimize sing-box memory limits, eliminate SIGHUP memory thrashing, and harden zapret2 recovery (1.3.20) 2026-09-04 18:58:31 +03:00
Dushnilin b3358f77a3 fix(stability): optimize Go memory tiers, prevent nftables degradation deadlock, harden NTP & process supervision
- singbox/runtime.uc: add dynamic 4-tier GOMEMLIMIT and GOGC limits based on RAM, enforce /etc/tachyon/mem_scale, and install managed init script across all binary variants
- service/event_controller.uc: guard probe_nftables() with recovery_bypass and native_internet_restored checks to prevent 5-minute network drop deadlock
- service/watchdog.uc: reduce Telegram worker heartbeat timeout from 900s to 300s and add nslookup fallback to Zero-RTT prefetcher
- diagnostics/runtime.uc & service/lifecycle.uc: use direct-IP NTP pool to eliminate circular DNS/TLS deadlocks, and step clock forward on cold boot if RTC desynced
- service/failover.uc & diagnostics/runtime.uc: flush conntrack states on proxy group switch so client connections immediately migrate
2026-09-03 06:13:30 +03:00
Dushnilin 123f5e6ccf release: 1.3.7 - Telegram alert deduplication & rate limiting, DNS detour deadlock resolution, ucode fs.opendir fixes 2026-08-29 21:28:41 +03:00
Dushnilin 404db8ae05 fix(dpi-bypass): TCP keepalive + conntrack tuning + nfqueue watchdog
- sysctl: tcp_keepalive=60/10/3, conntrack_established=600s (was 5 days)
- nfqws/nfqws2: --ctrack-timeouts=30,30,600,30,30,30,30,30 in default strategy
- watchdog: probe_nfqueue checks nfqws/nfqws2 process health every 300s
- watchdog: heal_nfqueue_stopped restarts tachyon if DPI bypass processes die

This eliminates the need for manual DNS flush + device restart when DPI
starts blocking connections. Dead connections are now detected in ~90s
instead of hours, and stale conntrack entries expire in 10 min instead
of 5 days.
2026-08-28 20:05:03 +03:00
Dushnilin a4bb9d060d fix(watchdog): исправить вызов json-парсера в probe_wan 2026-08-17 21:09:22 +03:00
Dushnilin 5adda4bba7 fix(i18n,watchdog): полная актуализация русской локализации интерфейса и исправление детекции WAN в Watchdog 2026-08-16 16:01:37 +03:00
Dushnilin 1437997153 fix(core): повышение стабильности, фоновый поиск MTU AWG, zero-fork проверка WAN и защита от OOM 2026-08-15 15:51:10 +03:00
Dushnilin 1e406c3e06 fix(updates): предотвратить повторное открытие и зависание модального окна обновления
- Исключить повторное открытие окна прогресса для уже завершенных задач (handledComponentJobs)

- Актуализировать состояние фоновых задач в get_ui_state и нормализовать таймаут stale PID

- Исправить определение WAN интерфейса в event_controller во избежание ложного перезапуска (#31)

- Улучшить сверку версий при самообновлении
2026-08-15 09:23:07 +03:00
Dushnilin 25c9160b38 fix(watchdog): не проверять прокси без http/mixed-инбаунда (issue #31) 2026-08-13 22:44:03 +03:00
Dushnilin ac3fbc90fc fix(watchdog): не перезапускать WAN по одиночному сбою пробы (issue #31) 2026-08-13 21:24:43 +03:00
Dushnilin b194666b84 ponytail: chistka watchdog + event_controller
event_controller.uc:
- check_tachyon_cli_running: zamenen polnyy /proc-skan na pgrep -f
- tproxy_port(): dobavlen kesh cached_tproxy_port

watchdog.uc:
- Udaleny 7 delegatov-oborotok
- active_root_causes zamenen dvumya var wan_repair_until/singbox_repair_until
- watch_recovery: ubrano mertvoe pole event
- ai_setting/ai_enabled udaleny, UCI chitaetsya napryamuyu
- safe_call: ubran flag ai_graceful_degradation_enabled

Testy: 511/511
2026-08-11 11:00:36 +03:00
Dushnilin 7ad428ddc8 refactor(watchdog): оптимизация и устранение дублирования кода
- watchdog: удалён дублирующий check_tachyon_cli_running(), везде используется controller.check_tachyon_cli_running()
- watchdog: smart_detect_process_pending использует controller.proxy_port() вместо повторного парсинга config.json
- watchdog: удалена однострочная обёртка is_dns_dead() — заменена is_dns_working() напрямую
- watchdog: heal_proxy_connectivity требует streak >= 2 перед очисткой cache.db — устраняет ложные ночные уведомления при кратких просадках прокси-ноды
- event_controller: push_history переведён на slice() вместо ручного цикла
- event_controller: direct_ok использует тот же check_url что и proxy check — корректность при кастомном ai_proxy_health_url
- event_controller: добавлен subscription_fail_streak — одиночный таймаут сети больше не триггерит Telegram
- telegram: tg_request больше не создаёт временные файлы в /tmp — JSON передаётся напрямую через curl -d, устранена утечка tg_payload_*.json при kill процесса
- telegram: worker() при старте удаляет оставшиеся tg_payload_*.json от предыдущих сессий
- tests: исправлен шаблон mktemp в background_spawn_fds.sh — busybox не поддерживает двойное расширение (.XXXXXX.uc)
2026-08-11 08:47:47 +03:00
Dushnilin 106ce9352a fix(memory): ограничить чтения неограниченного вывода в память
На роутере со 128 МБ несколько мест читали в память вывод, размер которого
ничем не ограничен. Распаковка gzip подписки шла через пайп с чтением целиком:
скачивание curl ограничено 15 МБ, но коэффициент сжатия base64-текста высокий,
так что пик доходил до десятков мегабайт. Оба вызывающих места передают файл и
ждут файл, поэтому распакованный поток теперь уходит редиректом сразу в
выходной файл, а успех определяется по коду возврата и ненулевому размеру.

Таблица nftables содержит сеты с десятками тысяч элементов из списков, и
`nft list table` печатает их все. Проба контроллера делала это каждый тик,
хотя ищет только имена цепочек и правил; четыре проверки доктора и вывод
чужих меток из полного рулесета — то же самое. Везде добавлен grep на
источнике, отбирающий только те строки, которые код потом и разбирает.

Два просмотра логов читали кольцевой буфер syslog целиком, чтобы показать
несколько сотен строк; теперь количество строк ограничено на стороне logread.
2026-08-08 23:02:18 +03:00
Dushnilin e6e3853f05 fix(errors): перестать глотать сбои записи состояния в пустых catch
Пустых catch в кодовой базе около полусотни, и они не одинаковые. Большинство
выражает намерение: fs.unlink бросает на ENOENT, а вызывающий говорит «пусть
этого файла не будет», и отсутствующий файл это условие уже выполняет; разбор
json в цикле пропускает мусорную строку и берёт следующую. Такие места теперь
несут пояснение, почему пустое тело здесь и есть правильный ответ.

Семь мест к этому классу не относились: там сбой означал потерю состояния, а
дальше код шёл так, будто всё получилось.

Watchdog писал через пустой catch файл лока перезапуска прокси, шкалу
GOMEMLIMIT после OOM, бэкап конфига и метку keepalive. Не лёгший лок означает,
что следующий тик перезапустит прокси заново, а счётчик rate-limit об этом не
узнает; не записанная метка keepalive заставляет init.d считать watchdog мёртвым
и перезапускать его. Все четыре теперь идут через write_state_file, который
логирует отказ. Метка пишется на каждом тике uloop, поэтому безусловная строка
залила бы syslog именно при переполненной файловой системе — там, где лог нужнее
всего; вместо этого каждый путь сообщает о первом отказе и молчит до следующего
успеха, что заодно делает видимым восстановление.

Контроллер разбирал /etc/sing-box/config.json ради портов http и tproxy и при
неудаче молча брал 4534 и 4530. Watchdog после этого опрашивает не тот порт,
вечно считает прокси нерабочим и лечит его по кругу — при том, что в логе нет
ничего, что связало бы это с конфигом. Разбор вынесен в общую функцию, которая
сообщает о непарсящемся конфиге один раз на процесс.

Telegram молча терял карту callback-токенов: токен уже вшит в клавиатуру к
моменту записи, поэтому провал отдаёт пользователю кнопку, которая на нажатие
ответит «кнопка устарела». Обновление списков молча теряло маркер отложенного
применения nft — списки обновлены на диске и до nftables не доехали никогда,
а строкой выше в лог написано, что маркер сохраняется. urltest молча выкидывал
битое регулярное выражение из конфига пользователя, отчего группа тихо
подхватывала меньше outbound-ов, чем сказано в конфиге.

tests/heal_escalation.sh проверял порядок строк по литералу fs.writefile для
лока и обновлён под новый вызов.
2026-08-08 22:32:09 +03:00
Dushnilin 5a10cc158b feat(watchdog): приостановка вторичных ремонтов во время устранения первопричины
Падение WAN-интерфейса влечет за собой сбой прокси, DNS и проверок доступности. У каждого из них был свой подписчик, и каждый независимо решал перезапустить службу — три ремонта на один сбой, ни один из которых не мог сработать до восстановления WAN. Ограничение частоты в safe_proxy_restart() сдерживало этот каскад только постфактум, но в коде не было явной связи, что сбои прокси и DNS — последствия сбоя WAN.

Шина уже ранжирует восстановители: WAN выполняется первым с приоритетом 10, sing-box с 20, прокси и DNS — с 40 и 50. Чтобы не вводить вторую иерархию, эти ранги вынесены в именованные константы (PRIORITY_WAN, PRIORITY_SINGBOX, PRIORITY_PROXY, PRIORITY_DNS), используемые как при подписке, так и при проверке подавления.

Восстановитель, устраняющий первопричину, удерживает свой ранг на время ремонта. Вторичный восстановитель приостанавливает работу и выводит сообщение в лог. Три свойства гарантируют надежность: причина никогда не подавляет сама себя; следствие не может подавить причину; срок удержания ограничен, поэтому зависший ремонт не заблокирует вочдог навсегда.

Удержание снимается по событию восстановления, не дожидаясь таймаута. Для этого добавлено новое событие EV.WAN_UP — ранее probe_wan публиковал только сбои.

Удержание WAN захватывается до `ifdown wan`, так как сам ifdown вызовет ошибки прокси и DNS ещё до завершения работы ifup.

Тест `tests/heal_suppression.sh` проверяет ранги, точки захвата/освобождения, защиту восстановителей и логирование пропусков.
2026-08-08 12:47:23 +03:00
Dushnilin 2647061646 refactor(watchdog): разделение наблюдения и восстановления через шину событий
Ранее вочдог опрашивал состояние системы и устранял проблемы в едином смешанном цикле. Добавление новой проверки или действия по восстановлению требовало изменения монолитной функции, где мониторинг и ремонт были переплетены, что затрудняло аудит порядка выполнения и изолированное тестирование.

Вводится `usr/lib/service/event_controller.uc` — шина событий pub/sub для вочдога. Теперь зонды публикуют факты (`EV.PROXY_DOWN`, `EV.DNS_DOWN`, `EV.SINGBOX_STOPPED`, `EV.OOM_DETECTED`, `EV.WAN_DOWN` и т.д.), не зная, кто их обрабатывает. Восстановители (healers) подписываются на эти факты и независимо выполняют ремонт.

Ключевые изменения:
- `event_controller.uc` управляет словарём событий, регистрацией подписчиков, сортировкой по приоритетам и синхронной отправкой.
- Зонды (`probe_proxy`, `probe_dns`, `probe_singbox`, `probe_oom`, `probe_wan`) публикуют события вместо прямого вызова функций ремонта.
- Восстановители регистрируются как подписчики с явными приоритетами, чтобы первопричины устранялись раньше вторичных сбоев.
- `tests/event_bus.sh` добавляет интеграционные тесты для отправки событий, сортировки приоритетов и обработки подписчиков.
2026-08-08 11:01:09 +03:00