- 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.
- Добавлен warn-вывод при ошибках LLM: статус curl,/raw response, отсутствие
choices — теперь видно в logread почему AI Chat молча отдаёт оффлайн
- Добавлены HTTP-Referer и X-Title заголовки для OpenRouter (рекомендация
провайдера для rate-limit ranking)
renderResults() вызывался каждые 600мс и пересоздавал всю таблицу — при
100+ стратегиях UI зависал. Теперь таблица перерисовывается только при
появлении нового результата или завершении бенчмарка.
- DPI-детектор: перед бенчмарком определяет тип блокировки (RST/throttle/DNS)
и переранжирует стратегии по приоритету (badseq для RST, multisplit для
throttle, fake+TTL для DNS-блока)
- Авто-применение: галочка «Auto-apply best strategy» автоматически
применяет выигравшую стратегию после завершения бенчмарка
- История: результаты бенчмарков сохраняются в /etc/tachyon/fuzzer_history.json
(до 50 записей) — новая вкладка «History» в UI
- CLI: новые команды detect_dpi, auto_apply, history, clear_history
- Локализация: русские и английские строки для всех новых элементов UI
- Frontend: вкладка History, баннер DPI-детекции, чекбокс авто-применения
- удалён неподдерживаемый флаг --netfilter-mode=on, вызывавший ошибку старта на OpenWrt
- проба готовности парсит status --json (BackendState), а не exit-code: незалогиненный узел отвечает NeedsLogin с non-zero и раньше считался неготовым — корень «did not become ready» при первом входе
- перед стартом своего tailscaled останавливается и отключается init-скрипт официального пакета: его демон держал UDP 41641, из-за чего наш умирал мгновенно
- при сбое старта в лог пишется хвост tailscaled.log для диагностики
- генератор: при section_failover_enabled catch-all указывает на селектор tachyon-failover со всеми секциями-кандидатами
- выбор по умолчанию переживает рестарты через /etc/tachyon/failover_section, устаревшее имя откатывается на первую секцию
- service/failover.uc: пробер каждой секции через Clash API delay, порог N подряд — переключение на живую, TG-уведомление
- watchdog: вызов проверки в slow-тире (модуль сам отключён при выключенной опции)
- настройки: флаг + порог во вкладке Advanced, RU-локализация
- тесты: генерация вкл/выкл/персист/устаревшее состояние + логика переключения со стабом Clash API
- опция daily_quota_minutes у расписаний: лимит минут использования сети в сутки
- поминутный cron-тик: учёт активности через ip neigh, блок до полуночи при исчерпании
- nft-сеты tachyon_quota_block (MAC) и _ip (IPv4) с drop-правилами; самовосстановление после ребилдов таблицы
- сброс счётчиков после смены суток, TG-уведомление о блокировке
- validator: проверка диапазона 0..1440
- UI: поле и колонка квоты в Родительском контроле + RU-локализация
- watchdog: проверка native-секции в slow-тире, авторестарт демона после 2 сбоев, TG-алерт раз в час
- AI Doctor: узел Tailscale (готов/не установлен/упал) только при настроенном native
- провайдер: режим peers — парсинг status --json через per-section socket
- RPC get_tailscale_status/get_tailscale_peers/tailscale_restart
- дашборд: карточка Tailscale (состояние, IP роутера, до 5 пиров с онлайн-статусом)
- новый компонент Tailscale: установка пакета из фида, карточка в Обновлениях
- режим native для секций Tailscale: системный tailscaled вместо sing-box endpoint
- доступ к тейлнету с LAN без клиента: маршруты 100.64.0.0/10 и MagicDNS через dnsmasq
- masquerade и exit-node (opt-in) с обходом tproxy по зарезервированной маске
- validator: требование tailscaled и auth-key для native; bypass-правила в mangle
- тесты: генерация конфига, смоук рантайма с моками, обновлена сигнатура состояния
- news: gordonua.com → pravda.com.ua (gordonua.com нет в списке)
- anime: crunchyroll.com, anilist.co → bato.to, mangadex.org (crunchyroll в geoblock, anilist.co нет в списке)
Багфиксы:
- rag.uc: исправлен порядок аргументов push() — RAG-эмбеддинги снова строятся
- fix_uci_config: правильный путь бэкапа (/etc/backup/tachyon_config + fallback)
- apply_quick_fix: честные exit codes для всех 23 фиксов
- doctor(): прокидывается busy flag в JSON-вывод
- diagnose_json: строится из checks[] вместо парсинга эмодзи из текста
UI:
- Кнопка Telegram канал (https://t.me/tachyon_proxy) на странице диагностики
Тесты:
- 5 новых проверок в ai_doctor_local.sh (uci_backup, exit codes, busy, structured checks, rag push)
- Added get_mixed_port() to core/common.uc (reads sing-box config.json)
- agent_api.uc, api.uc: use common.get_mixed_port()
- warp_generator.uc: use config port instead of hardcoded fallback
- watchdog.uc: use mixed_ports_from_config() for Clash API calls
- runtime.uc: dynamic port in conflict checks and proxy probe
- Added ~120 new i18n keys to both en and ru sections
- Replaced all remaining hardcoded Russian strings in telegram.uc
- Menu, status, connections, diagnostics, help, subscriptions, quiet hours,
test rule, export, MAC blocking, devices, watchdog/AI, QoS, section
management, DNS presets, exec, daily digest, update notifications,
blocked activity, all navigation buttons
- All keys verified present via runtime check
- Add get_mixed_port() helper that reads config.json
- Replace all hardcoded 4534 in telegram.uc with get_mixed_port()
- mixed_port_alive() now checks the real port
- diagnose() checks the real port for proxy health
- Clash API calls use the real port
- Route failure alerts use i18n, remove hardcoded port number
- Fixes LuCI 'Check connection to Telegram' showing false negatives
when sing-box uses a non-default mixed-port (e.g. 1602)
- Добавлены недостающие /24 диапазоны: 162.159.195.0/24, 162.159.204.0/24,
188.114.96.0/24, 188.114.97.0/24 (ранее было только 4 из 8 диапазонов)
- probe_ips: 9 → 17 IP (по два представителя на каждый /24 + 8.6.112.0)
- resolve_ips/resolve_ips_probe для API-запросов: 4 → 8 IP
- engage.cloudflareclient.com DNS-резолв продолжает добавлять
динамические IP в пул автоматически
- getZapret2Status/getZapretStatus/getSingBoxStatus/getByedpiStatus:
добавлен allowNonZeroWithStdout — rpcd может вернуть не-zero exit при
наличии полезного stdout (модуль-провайдер не найден, но JSON-статус
всё равно отдан). Без этого флага callBaseMethod считал вызов
провалившимся → serviceStatus undefined → «Неизвестный»
- customProxyLatencies: сервисные секции (SING_BOX, ZAPRET, ZAPRET2,
BYEDPI) больше не перезаписываются кешем latency-теста. Ранее
неудачный тест кешировал -1, перезаписывая latency:0 из секции →
отображалось «-1ms» вместо статуса
- helpers.uc определяла write_text_file, но не экспортировала:
биндинг в telegram-воркере был null, write_heartbeat падал каждый
цикл — «Worker loop error: left-hand side is not a function»
каждые ~25с, heartbeat не писался, воркер зря перезапускался
- watchdog: mixed-порт теперь читается из сгенерённого конфига
sing-box (inbounds[].type=mixed), а не хардкод 4534. Когда mixed
выключен (Main.mixed_proxy_enabled=0) — вотч встаёт в сторону
вместо бесконечных «Restarting sing-box» с пересозданием nftables
каждые ~5 минут
- проверено на живом роутере: 0 рестартов и 0 ошибок воркера после
деплоя, E2E зелёный
В ветке mtproto тип инбаунда перезатирался на shadowsocks-2022,
и ee-секрет уходил в password: SS2022 парсит его как base64-PSK —
отсюда FATAL «decode psk: illegal base64 data at input byte 60»
у всех, у кого включён MTProto-сервер.
- mtproto снова эмитит type=mtproxy (как в схеме extended 2.6.x),
юзер — {name, secret}, а не password (регрессия fe0099a3)
- конфиг с MTProto и AWG проверен `sing-box check` на реальном
sing-box-extended 1.13.18-extended-2.6.5 — PASS
- warp-генератор: прямой префлайт-зонд с --resolve (DNS-отравление
больше не даёт ложное «API недоступен»), живость 4534 — локальная
по /proc/net/tcp вместо сквозного запроса через туннель
- багрепорт маскирует ai_doctor_api_key и tuic_password
- watchdog: command_output_from_args использовался без биндинга —
«Graceful degradation: check_mixed_proxy_port failed: left-hand
side is not a function» на каждом проходе
- telegram: write_heartbeat звал write_text_file из core.helpers,
который не импортировался — «Worker loop error» каждый цикл,
heartbeat не писалcя, воркер зря перезапускался по стейлу
- E2E: ноль «left-hand side» в логах OpenWrt-контейнера после фикса
- i1–i5/j1–j3: классический hex конвертируется в теги <b 0x…>;
userspace WireGuard extended/lx молча игнорирует голый hex,
handshake не завершался (#39#41#42)
- j1/j2/j3/itime эмитятся только для extended ≤2.6.0: в 2.6.1+
поля удалены из схемы, sing-box падает на unknown fields
- j1–j3 больше не ломаются uci_bin_to_hex
- h1–h4: диапазоны «min-max» на обеих ветках
- MTProto: секрет канонизируется в ee-hex из любой формы
(hex/base64), валидатор даёт понятную ошибку вместо
FATAL decode psk (#23)
- XHTTP v2: парсинг и экспорт ключей подписок
- валидатор: warp/masque/openvpn/snell/mieru/sudoku — только extended
- тесты: stat→ucode (busybox), раннеры исключены из E2E,
новые server_mtproto.sh и awg_variant_schema.sh
Жалобы вида «AWG не работает» (#39, #42) почти всегда означают: конфиг
секции применён корректно, но пир не отвечает (сервер лежит, провайдер
режет UDP до эндпоинта). Раньше доктор об этом молчал, и виноватым
выглядел Tachyon.
Новый чек 6c сканирует свежий лог ядра на ошибки outbound/wireguard
(operation timed out / handshake timeout): при свидетельствах мёртвого
туннеля - явный вердикт «проблема вне Tachyon» с подсказкой проверить
сервер и UDP-порт у провайдера. Если wireguard-трафика в логе нет вовсе,
чек не выдаёт ни одной строки - без шума для пользователей без AWG.
- has_outbound_section: туннельные секции (awg/warp/vpn/openvpn/masque/
anytls/snell/mieru/sudoku) теперь считаются исходящей конфигурацией -
одинокая AWG-секция больше не получает вводящее в заблуждение
«No proxy outbound sections found» (жалобы пользователей #39/#42)
- новая миграция orphan_section_interface_cleanup: удаление секции
маршрутизации раньше оставляло после себя дочерние section_interface,
ссылающиеся на несуществующего родителя (у пользователя - запись на
секцию '2' при живой только '1'); сироты удаляются через новую операцию
delete_section; функция объявлена до массива MIGRATIONS - ucode не
поднимает объявления
- strip_unmarked_tachyon_cron_lines: старые версии писали cron-строки без
маркер-комментария, они переживали фильтрацию по маркерам, копились при
обновлениях и crond запускал component_updates_if_due дважды за тик;
немаркированные строки с нашими командами теперь вычищаются при каждом
refresh и remove
На сетях, где api.cloudflareclient.com недоступен (типичный случай из
issue #39), генератор сжигал весь временной бюджет - фронтенд умирал по
XHR timeout через 30 секунд, не показывая причины.
- префлайт: одна проба (4с connect / 6с max) напрямую и через доступный
транспорт; если Cloudflare недостижим - мгновенная понятная ошибка
«Cloudflare API недоступен...» вместо минутного зависания
- бюджеты ужаты до 20с на call_api и 20с на всю регистрацию, чтобы
худший случай укладывался в XHR-таймаут LuCI
- все ошибочные выходы теперь печатают JSON-конверт и exit(0): фронтенд
парсит data.message и показывает настоящую причину (ненулевой код
заставлял его писать безликое Unknown error)
- новая slow-проверка (раз в 5 мин): sing-box запущен, но mixed-порт 4534
не слушается две проверки подряд (~10 мин) -> один авторестарт ядра;
если не помогло - уведомление админу не чаще раза в час, без циклов
бесконечных рестартов
- проверка живости телеграм-воркера: бот включён, pid жив, но heartbeat
старше 15 минут (зависший long-poll/мёртвый цикл) или pid отсутствует ->
рестарт воркера через telegram_start с ограничением раз в час
- обе проверки добавлены в perform_slow_checks через safe_call
Корень «бот молчит»: get_proxy_args считал достаточным условием маршрутизации
через 4534 сам факт запущенного sing-box - если mixed-inbound не поднялся,
каждый запрос вечно падал, воркер уходил в бесконечный backoff (468 ретраев
подряд у пользователя), хотя api.telegram.org был доступен напрямую.
- mixed_port_alive(): TCP-проба слушается ли 4534 (netstat) с кэшем 30с;
маршрут через прокси выдаётся только при живом порте
- tg_request разделён на tg_request_via + fallback-цепочку: прокси не ответил -
повтор без прокси; отключается UCI telegram.bot_direct_fallback='0'
- алерт админу однократно за эпизод после 5 неудачных опросов подряд с
указанием причины; сбрасывается при восстановлении опроса
- heartbeat /var/run/tachyon_telegram.heartbeat после каждого успешного
цикла - основа для вотчдог-проверки живости (следующий коммит)
- ротация tmpfs-лога воркера: потолок 512KB, хвост 100KB, проверка раз в час
- /doctor в боте рендерит человекочитаемую сводку (проблемы/исправлено/
запланировано) вместо сырого JSON
- config_version убран из человекочитаемого вывода конфига (внутренний
маркер миграций)
Upstream openwrt/luci убрал template_lmo.c из дерева: po2lmo теперь
линкуется с src/lib/lmo и генерируемым lemon plural_formula, поэтому
прямой вызов gcc больше не работает - только in-tree Makefile.
Проверка наличия template_lmo.c заменена на сборку make po2lmo,
проверено на свежем клоне master.
- build_backend_root ставил defaults/config до создания родительского
каталога usr/lib/tachyon/defaults - релизная сборка падала на install
(обнаружено сборкой тега 1.2.89)
- ensure_po2lmo: частичный клон feeds/luci приводил к компиляции без
template_lmo.c; теперь при отсутствии исходников делается чистый
переклон, а финальный fallback больше не печатает путь к несуществующему
бинарнику - сразу явная ошибка
tachyon/files/usr/bin/tachyon - ucode-скрипт с shebang #!/usr/bin/ucode,
shellcheck умеет проверять только sh/bash/dash/ksh и падает на нём.
Покрытие cgi-bin и hotplug остаётся.
В репозитории лежит package-lock.json и нет yarn.lock, поэтому yarn-workflow
не кэшировал ничего (hashFiles по отсутствующему файлу) и ставил неразрешимые
деревья зависимостей заново каждый раз. Переведено на npm ci с npm-кэшем по
lockfile; проверка diff сборки ограничена выходной директорией LuCI htdocs,
которую build реально производит. Применена prettier-нормализация недавно
правленных исходников.
UTF-8 BOM раньше прятал shebang CGI от скана инвентаря; после удаления BOM
скрипт (корректно) определяется как shell, поэтому ожидаемый список
пополняется tachyon/files/usr/lib/cgi-bin/tachyon-agent.
- workflow shellcheck теперь покрывает агентский CGI, hotplug WAN-монитор и
точки входа usr/bin; в CGI перед shebang стоял UTF-8 BOM, из-за которого
Linux вообще не мог исполнить скрипт (bad interpreter) - удалён вместе со
случайными BOM в исходниках фронтенда
- новый rag_embeddings.sh фиксирует исправленный порядок аргументов push(),
инвалидацию кэша по отпечатку индекса, нормализацию null model_override и
порядок объявлений - ни один из починенных багов RAG не сможет вернуться
незаметно
- hosts_li