Commit Graph
2034 Commits
Author SHA1 Message Date
Dushnilin 2f36cf495c chore(release): trigger release build for 1.2.59 2026-08-06 22:01:06 +03:00
Dushnilin 3e5a2560e8 fix(dns): refine sing-box runtime PID detection comments 2026-08-06 21:19:41 +03:00
Dushnilin 35f1c76a01 fix(dns): multi-fallback sing-box PID detection (ubus/procd/pidof/pidfile) resolving 'dhcp contains dns server' error on start 2026-08-06 19:53:49 +03:00
Dushnilin 131d8ea8c5 feat(awg): add j1-j3 and itime support for sing-box-extended v1.13.16-extended-2.6.0 2026-08-06 16:57:34 +03:00
Dushnilin 89ae37ea4b fix(ci): synchronize PO catalogs, fix DNS action UI, state aggregate signature, and uci array parsing 2026-08-06 16:39:53 +03:00
Dushnilin 39b253bd66 fix(diagnostic): use serviceStatus for zapret/zapret2/byedpi outbound checks instead of Clash API latency probe 2026-08-06 15:00:19 +03:00
Dushnilin 7125e1a48e feat: карточки сервисов на дашборде + секция Hosts в правилах + скрытие вкладки Conditions для Hosts
Дашборд:
- Добавлены карточки статуса Zapret, Zapret2, ByeDpi на панель мониторинга
- Показывают статус (работает/остановлен), количество перезапусков, предупреждения
- Баг: API возвращает boolean а не число — исправлено сравнение

Секция Hosts:
- Перенесены опции hosts из глобальных настроек в отдельный тип секции (action=hosts)
- Опции: пользовательские DNS записи, удалённые списки хостов, автообновление, интервал
- Миграция: автоматический перенос глобальных настроек hosts в секцию
- Вкладка «Условия» скрыта для секций типа Hosts (hosts записи применяются глобально)
- Возвращена кнопка «Import Hosts File» с модальным окном загрузки из файла
- Убраны неиспользуемые опции из settings.js (~280 строк)

Локализация:
- Переведены 6 новых строк для превью импорта hosts
2026-08-06 14:16:18 +03:00
Dushnilin 488bbfefd5 fix: комплексный аудит и исправление ucode кодовой базы
Критические исправления:
- safe_proxy_restart: удаление lock-файла после фонового перезапуска
  с защитой от stale lock (>300 сек)
- write_json_file: атомарная запись через tmp+mv вместо прямой
- write_reload_state: атомарная запись через tmp+mv
- state_add_list: отклонение значений с пробелами

Исправления безопасности:
- killall logread заменён на pkill -f 'logread -f'
- SIGTERM→SIGKILL для Telegram и sing-box при остановке
- Recover OOM scale: инкремент +0.05 каждые 10 минут
- nfqueue и byedpi: trap для корректного завершения дочерних процессов
- nfqueue: валидация стратегий и откат при ошибке запуска
- nfqueue: flush mangle_output перед добавлением правил
- Исправлен парсинг exit code в 14 файлах (status & 127)

Улучшения стабильности:
- init.d: trap для start_service/stop_service
- watchdog: signal traps для legacy fallback loop
- lifecycle: логирование ошибок при остановке компонентов
- singbox/priority: SIGTERM→SIGKILL при остановке
- telegram: exponential backoff (1x→300s) при ошибках API
- telegram: process_updates возвращает boolean для отслеживания успеха
- watchdog: кэш proxy port для уменьшения чтения конфига sing-box
- singbox/generator: упрощён atomic_write_json_file
- packages.uc: переупорядочивание apk_version (лёгкие запросы первыми)
- dns/apply: проверка PID sing-box перед настройкой dnsmasq
- server/service: cleanup_orphaned_server_certs перед вызовом
2026-08-06 00:03:51 +03:00
Dushnilin cb62d7e006 feat(installer): comprehensive command and system execution audit logging 2026-08-05 17:14:11 +03:00
Dushnilin f4bc3255c6 i18n(installer): full Russian localization support for installer steps and status summary 2026-08-05 16:47:32 +03:00
Dushnilin c38dfc792d fix(installer): fallback to run_with_deadline when timeout binary is missing 2026-08-05 16:15:54 +03:00
Dushnilin 0eda44e26c installer: show package manager errors on failure
pkg_list_update, pkg_install_name, and pkg_install_files now capture
stderr and display last 10 lines when package operations fail.
2026-08-05 15:31:56 +03:00
Dushnilin efe002b43d installer: reliability improvements
- Abort on failed package removal instead of continuing
- Improve run_with_deadline with process group kill (kill -- -PID)
- Add timeout 120s for package install/update/remove (apk/opkg)
- Add timeout 10-30s for all service operations (enabled/running/status)
- installer_deactivate_legacy_base returns false on failure
2026-08-05 14:35:48 +03:00
Dushnilin ab606ff166 hosts: restyle remote hosts lists widget to native LuCI look
Replaced custom colored rows/badges with standard CBI table layout:
cbi-section-table, cbi-input-checkbox, cbi-input-text,
cbi-button-action, cbi-button-remove. No custom colors or borders.
2026-08-05 12:45:31 +03:00
Dushnilin d38d42b08a hosts: rewrite remote hosts lists widget with per-URL toggle
Completely replaced DynamicList with a custom renderWidget that shows
each URL as a row with: checkbox toggle, URL label, ON/OFF badge, and
delete button. Disabled URLs are stored in hosts_list_disabled UCI list.
Backend filters them out before downloading. URLs stay in settings
when disabled — they just don't get applied.
2026-08-05 12:27:49 +03:00
Dushnilin 969937428f hosts: add per-URL enable/disable toggle for remote hosts lists
- Backend: get_hosts_urls() now reads hosts_list_disabled list and
  filters out disabled URLs before downloading.
- Backend: hosts_list_status() now returns total and disabled counts.
- Frontend: Added hidden hosts_list_disabled DynamicList option.
- Frontend: Overrode renderWidget on hosts_list_urls to prepend a
  toggle switch (ON/OFF) next to each URL. Toggle syncs with
  hosts_list_disabled via uci.set().
2026-08-05 12:24:39 +03:00
Dushnilin a32ad76285 telegram: fix regex injection, state race, and oversized callback_data (BUG7/8, BUG9, BUG13)
- BUG7/8 CRITICAL: view_test_rule() used escape_html() as regex escape,
  allowing user input injection. Now uses plain string suffix matching.
- BUG9 HIGH: set_tg_state(chat_id, null) ran BEFORE action execution,
  so if the action threw an exception the user lost their state context.
  Now state is cleared only after successful UCI commit in each branch.
  sec_create with invalid name preserves state for retry.
- BUG13 LOW: /set_arr_del and /sec_del_it callback_data could exceed
  Telegram's 64-byte limit with long domain names. Added cb_data()
  helper that truncates and appends a hash when over limit.
2026-08-05 11:45:01 +03:00
Dushnilin bddd0a972b fix: 10 bugs in Telegram bot
- CRITICAL: /dns_apply substr offset 12→11 was always applying preset 0
- CRITICAL: /test_rule IP CIDR match now checks subnet, not just format
- HIGH: check_notified_updates now iterates data.results (was iterating
  top-level object keys, so update notifications were completely broken)
- HIGH: exec_support_bundle cleanup now deletes /etc/.tachyon/ paths
  (was deleting /tmp/ paths that didn't exist)
- HIGH: command_status() now uses command_from_args() for ai_heal,
  watchdog_start, watchdog_stop (was passing raw strings)
- HIGH: set_tg_state fs.unlink now wrapped in try/catch
- MEDIUM: close_connections now reports error when curl fails
- MEDIUM: view_connections validates page >= 0
- LOW: /noop callback now silently ignored instead of falling through
- LOW: > command HTML output now uses <code> instead of backticks
2026-08-05 11:38:14 +03:00
Dushnilin a21a818ea5 fix: dns_hosts predefined rules now fall after FakeIP/section DNS rules; fix parse_text_domains for // comments
- dns_hosts and hosts cache predefined DNS rules are now appended AFTER
  section-level FakeIP routing rules, preventing third-party hosts entries
  (e.g. from Unlock AI projects) from short-circuiting FakeIP for domains
  already routed through proxy via section rules
- parse_text_domains now properly handles // comments and multi-domain
  comma-separated lines from option domain
2026-08-05 10:37:21 +03:00
Dushnilin 7b6f607257 installer: don't fail when apk reports non-critical errors
- Capture apk output to log file instead of /dev/null
- Show last 5 lines of apk output on screen when installation fails
- Fix package name parsing to strip version (tachyon_1.2.58 -> tachyon)
- Continue installation if package is actually installed despite apk errors
- Apply same resilience to backend, luci-app, and i18n packages
2026-08-05 08:18:18 +03:00
Dushnilin 4d4bdb16d0 fix: watchdog rpcd FD leak heal + updates show outdated_same_release
- watchdog: add ai_heal_rpcd() - monitors rpcd file descriptor count,
  restarts rpcd when FD count exceeds 512 (threshold of 1024 limit).
  Prevents LuCI from showing all services as 'stopped' due to FD exhaustion
  when rpcd can no longer fork to execute /usr/bin/tachyon commands.
  Runs on every watchdog health audit cycle (~15s).

- watchdog: move safe_reload_firewall() definition before ai_heal_nftables()
  and ai_heal_qos() to fix 'left-hand side is not a function' error.
  ucode does not hoist function declarations.

- updates: show Update button for outdated_same_release status (same version
  number but different commit SHA). Previously the button was hidden when
  current_version == latest_version even if SHAs differed.
2026-08-04 22:57:39 +03:00
Dushnilin 7b8114bef1 fix: незаустановленные компоненты (zapret/byedpi/zapret2) не возвращают ошибку при check_update
- action.uc: для zapret, zapret2 и byedpi при check_update,
  если компонент не установлен, возвращаем success:true со статусом '' вместо action_fail,
  предотвращая красные toast-уведомления в LuCI
2026-08-04 21:12:01 +03:00
Dushnilin 9815198585 fix: исправлена команда /check_updates в Telegram боте
- exec_check_updates в telegram.uc: исправлен парсинг JSON ответа component_update_check_cache
  (формат { enabled, results: [] } вместо словаря по имени компонента)
- исправлено поле installed_version -> current_version
- добавлена обработка случая disabled/пустой кэш/ошибка success
- добавлено отображение zapret2 и других компонентов
2026-08-04 21:03:24 +03:00
Dushnilin 888a9633d4 fix: исправление синтаксических ошибок повторного объявления переменных в watchdog.uc 2026-08-04 20:54:40 +03:00
Dushnilin 9551c18d8c fix: устранение ложноположительных срабатываний OOM в watchdog
- watchdog.uc: добавлен фильтр сообщений OOM (учитывает только системный OOM killer и аварийное завершение sing-box, исключает сетевые предупреждения буферов типа nlbwmon),
  игнорирование устаревшего буфера логов при старте подписки logread -f,
  инициализация переменных last_oom_time и syslog_start_time
2026-08-04 19:22:55 +03:00
Dushnilin 1b6cda9c8d fix: исправление подвисания Telegram бота и ошибок AI Watchdog
- telegram.uc: добавлены таймауты --max-time 35 и --connect-timeout 10 для всех запросов curl,
  ограничение длины сообщений до 3900 символов (предотвращение 400 Bad Request от Telegram API),
  безопасная обработка callback_query в try...catch с гарантированным вызовом answerCallbackQuery,
  защита основного цикла worker от падений при сбоях сети
- api.uc: добавлены таймауты --max-time и --connect-timeout для всех curl вызовов,
  устраняющие зависание подпроцессов при опросе Clash API и проверках соединения через прокси
- watchdog.uc: добавлена функция safe_reload_firewall, устранившая ошибки
  'left-hand side is not a function' в процессах ai_heal_nftables и ai_heal_qos
2026-08-04 19:03:01 +03:00
Dushnilin ff627cfb52 fix: FD-cascade при reinstall + SHA версии в UI + тип outdated_same_release
- action.uc: killall logread перед restart_tachyon_after_successful_change,
  предотвращает FD-каскад при reinstall/update (orphan logread pipe FD)
- action.uc: current_sha/latest_sha в ответе check_update для Tachyon
- updates.uc: SHA пробрасывается через кэш проверки обновлений
- fe/types.ts: outdated_same_release добавлен в union статусов,
  поля current_sha/latest_sha в ComponentActionResult,
  AI Watchdog поля в ConfigSection (pre-existing TS2339 fix)
- fe/store.service.ts: outdated_same_release и SHA в состоянии updatesChecks
- fe/initController.ts: рендер SHA hash-badge для outdated_same_release,
  setCheckResult принимает SHA, applyCachedCheckResults/handleCheckResult обновлены
- fe/styles.ts: .sha-info — monospace badge для отображения коммит-хешей
2026-08-04 16:03:07 +03:00
Dushnilin b7d05034c8 исправление: утечки ФД и временных файлов, переполнение ОЗУ
Проблема с FD-каскадом (зависание sing-box):
watchdog.uc открывал logread -f через popen() без O_CLOEXEC. Каждый
фоновый system('... &') порождал дочерний процесс, наследующий read-end
logread pipe. После kill watchdog — дочерний процесс держал pipe, logread
не получал SIGPIPE и оставался живым. За N перезапусков накапливалось
N orphan-процессов logread → исчерпание лимита 1024 FD → генератор
конфига sing-box не мог открыть .uc файлы → sing-box не стартовал.

Исправления FD-утечки:
- watchdog.uc: добавлена переменная logread_pipe_fd + помощник bg_system(),
  который закрывает FD logread перед запуском фоновых процессов
- watchdog.uc: killall logread перед открытием нового logread -f в
  setup_syslog_listener() для очистки orphan-процессов от предыдущих экземпляров
- watchdog.uc: все 7 вызовов system('... &') переведены на bg_system():
  restart, reload_firewall (x3), WAN ifdown/ifup, subscription_update_async (x3)
- initd.uc: killall logread в stop_service() после остановки tachyon
- nft/apply.uc: добавлены </dev/null >/dev/null 2>&1 к голому reload_firewall &
- updates.uc: добавлены редиректы к tachyon reload &
- telegram.uc: добавлен </dev/null к reload_firewall &

Проблема с утечкой временных файлов (500MB в /tmp):
При каждом tachyon restart (SIGKILL) процессы-генераторы умирали на
полуслове, оставляя /tmp/tmp.* файлы (sing-box config JSON ~3.4MB,
reload state). За 8 дней накопилось 227 файлов = 506MB в tmpfs,
что занимало 25% всего ОЗУ (519MB из 2007MB shared).

Исправления утечки временных файлов:
- temp_path() в runtime.uc и updates.uc теперь создаёт /tmp/tachyon-XXXXXX
  вместо /tmp/tmp.XXXXXX (безопасный для очистки префикс)
- nft/apply.uc и lifecycle.uc: аналогичное изменение mktemp
- lifecycle.uc start_impl(): автоматическая очистка /tmp/tachyon-* файлов
  старше 30 минут при каждом старте сервиса

Результат на роутере 192.168.2.1:
  logread после stop  = 0 (было 1+)
  logread после start = 1 (было 2+ в каскаде)
  sing-box = запущен
  /tmp shared         = 27MB (было 519MB, освобождено ~490MB)
  ОЗУ available       = 1691MB (было 1195MB)
2026-08-04 15:36:37 +03:00
Dushnilin a3de505a9a chore: switch zapret2 repo to Dushnilin/zapret2-openwrt 2026-08-04 14:04:29 +03:00
Dushnilin 2c31a62e4d fix: same-release SHA prefix compare + sing-box generator error detail
- action.uc: compare release target_commitish (full 40-char SHA) with
  installed short SHA by prefix instead of exact match; fixes false
  'same release update found' when commit is actually the same
- runtime.uc: generator_failure_reason now returns the first error line
  instead of the ucode 'Near here ---^' position marker, and logs full
  generator output at debug level on failure for better diagnostics
2026-08-04 11:31:51 +03:00
Dushnilin ea40ce1e93 fix: upgrade postcss 8.5.20 → 8.5.23 (GHSA-6g55-p6wh-862q)
Arbitrary .map file read via untrusted sourceMappingURL when from is
unset. Added npm overrides to force postcss@8.5.23 across all transitive
deps (tsup, vitest→vite).
2026-08-04 09:12:20 +03:00
Dushnilin 56480443b4 feat: dynamic sing-box repo links + expanded README
- runtime.uc: add sing_box_repo_url to build_system_info() based on
  installed variant (extended→shtorm-7, lx→Leadaxe, stable→SagerNet)
- main.js: use systemInfo.sing_box_repo_url instead of hardcoded URL
- README.md / README.en.md: expanded Watchdog section with all 14 fixes,
  atomic operations, restart protection, data correctness, Telegram
  rate limits, firewall improvements, dynamic repo links, commit-level
  update tracking
2026-08-03 21:52:49 +03:00
Dushnilin 22a236e5d1 feat: commit-level version tracking for same-release updates
Backend:
- constants.uc: add TACHYON_COMMIT_SHA constant (placeholder __COMPILED_COMMIT_SHA__)
- build.sh: capture git rev-parse HEAD and sed-replace commit SHA placeholder
- Makefile: same commit SHA sed replacement for OpenWrt builds
- action.uc: modify check_tachyon() to compare installed commit SHA with
  target_commitish from GitHub release, new status 'outdated_same_release'
- action.uc: reuse release_json for both version and commit SHA extraction
- updater.uc: add release_commit_sha helper to extract target_commitish
- updates.uc: extend cacheable status to include outdated_same_release

Frontend:
- main.js: handle outdated_same_release status in renderComponentCard
- main.js: include outdated_same_release in shouldShowInstallAfterCheck
- main.js: include outdated_same_release in applyCachedCheckResults

i18n:
- Add 'Update is available for current release' and 'Update is available
  for current release:' to .pot and .ru.po files

78 tests pass.
2026-08-03 21:35:06 +03:00
Dushnilin e67cd066b2 feat(i18n): Russian translations for Remote Hosts Lists settings
- Remote Hosts Lists → Удалённые списки хостов
- Auto-update Hosts Lists → Автообновление списков хостов
- Hosts Lists Update Interval → Интервал обновления списков хостов
- Description strings translated
2026-08-03 20:43:09 +03:00
Dushnilin a1c6cdd86a fix: migration.uc uses warn() not log_message() (undefined function) 2026-08-03 20:14:10 +03:00
Dushnilin 2d13e295b8 chore: gitignore tmp test artifacts 2026-08-03 20:07:10 +03:00
Dushnilin 6c7ceb0873 chore: remove test artifacts from tracking 2026-08-03 20:06:42 +03:00
Dushnilin a3f877c960 fix: file handle safety, orphan cleanup, error logging edge cases
generator.uc: try/catch around hosts cache file read with guaranteed close
hosts.uc: try/catch around parse_hosts_file with guaranteed close
migration.uc: try/catch around remove_cache_path, checked unlink in remove_legacy
runtime.uc: cleanup stale temp config files on init_config startup
lifecycle.uc: log warning on nft table delete failure in stop_main
2026-08-03 20:06:18 +03:00
Dushnilin 4e12681179 fix: migration error handling + updates retry mechanism
migration.uc:
- try/catch around migration.run() with error logging
- try/catch around apply_operations() with error logging
- Error checking for UCI cursor operations in apply_operations
- Checked fs.writefile return values in ensure_runtime_cache_format

updates.uc:
- Write pending marker on lock acquisition failure for next retry
2026-08-03 20:01:09 +03:00
Dushnilin 5f5031e4db fix: watchdog remaining bugs + atomic writes across 6 files
watchdog.uc:
- H-8: keepalive timestamp for init.d supervision
- H-14: save config backup after successful start
- M-1: empty_sections check domain/domain_suffix/ip_cidr
- M-2: dns_loop re-enable cooldown (5 min)
- M-11: reload_firewall always dedup
- M-12: merge wan+gateway heal into one function
- M-13: telegram rate limit (max 10 per 5 min)

nft/apply.uc: background reload_firewall to avoid blocking
subscription/cache.uc: write_text → write_text_if_changed (atomic)
dns_prefetch.uc: blocking sleep 10 → poll with early exit
diagnostics/runtime.uc: atomic uci_backup_save/restore, atomic scale writes, nslookup -port fix
wan-monitor: rate limit notifications (60s cooldown)
2026-08-03 19:54:50 +03:00
Dushnilin c7febcb0dc fix: atomic writes, crash safety, deadlock prevention across 10 files
watchdog.uc:
- H-4: ai_heal_uci_config atomic write (tmp → rename)
- H-5: backup validation via uci valid before restart
- H-6: proxy restart cooldown (max 3 per 10 min)
- H-7: restart lock file prevents parallel restarts
- H-13: ai_heal_wan_interface reads 'network' not 'tachyon' config
- M-3: nslookup -port=53 → plain nslookup (BusyBox compat)

generator.uc: atomic_write_json_file for main config output
hosts.uc: atomic cache write (tmp + mv), TOCTOU double stat fix
telegram.uc: atomic config restore, persistent /etc/.tachyon/ paths
migration.uc: UCI commit before cache removal
updates.uc: background reload inside locked section (deadlock prevention)
lifecycle.uc: uci commit return check, watchdog/telegram failure logging
package.uc: postinst_restore returns actual start result
build.sh/install.sh: Wave 1 backup/restore fixes
2026-08-03 19:43:10 +03:00
Dushnilin 0a428083af fix: watchdog/state/telegram crash bugs (ucode JS-isms + SIGHUP race)
- watchdog: fix 'left-hand side is not a function' tick crashes
  - safe_call: replace String(e)/instanceof Error with as_string(e)
  - ai_heal_empty_sections: list_option/read_json_file -> common.*
  - read_dns_recovery_state/ai_heal_dns_loop: read_json_file -> common.*
  - common.is_connections_action -> connections.is_connections_action
    (add missing 'config.connections' module import)
  - wrap check_singbox_process/check_auto_resume_pause/ai_full_health_audit
    in safe_call to prevent uncaught exceptions in tick loop
- state: SIGHUP race condition: fall back to sing-box start instead of
  exit(1) when process dies between config generation and signal delivery
- telegram: fix String(e)/instanceof Error crash in update catch block
2026-08-03 16:50:08 +03:00
Dushnilin 2965277877 feat: custom hosts lists — remote URL download, dnsmasq addn-hosts, sing-box DNS rules, LuCI UI 2026-08-03 16:05:53 +03:00
Dushnilin 51f9f1e43e installer: fix shellcheck SC1072 in tui_progress 2026-08-03 15:17:49 +03:00
Dushnilin 0cbbf3bd15 installer: fix TUI colors on OpenWrt busybox, clean output 2026-08-03 15:13:26 +03:00
Dushnilin 7a10fc9486 installer: inline TUI, remove tools dir, remove installer_tui.sh 2026-08-03 14:55:02 +03:00
Dushnilin e371f7a52e installer: TUI without ASCII logo 2026-08-03 14:48:04 +03:00
Dushnilin 280aa2bfac fix(install): tolerate apk non-critical errors when package is actually installed
On some OpenWrt builds (e.g., FriendlyWRT with ip-full conflict), apk
reports '1 error' even though the package installed successfully
(pre/post scripts ran). The install script now checks if the package
is actually installed after apk returns non-zero, and continues if so.
2026-08-03 14:22:20 +03:00
Dushnilin 5eef78b877 fix: DNS петля + watchdog автоисправление + централизация file_is_usable
Ключевые изменения:

1. core/helpers.uc: file_is_usable(path, min_bytes) + file_size_value(path)
   для единообразной проверки файлов (минимальный размер порог).

2. singbox/dns.uc: WAN fallback DNS серверы (fallback_wan_main) теперь
   используют прямой UDP без detour — исправлена петля когда
   DNS шёл через мёртвую прокси-секцию.
   Health probes для ВСЕХ DNS серверов (включая DoH) идут direct —
   failover может определить доступность DNS серверов.

3. watchdog.uc: ai_heal_empty_sections() — автообнаружение пустых
   proxy-секций с подписками → запуск subscription_update_async.
   ai_heal_dns_loop() — при обнаружении DNS-петли (dead proxy +
   dead DNS) → временно отключает DNS detour → загружает подписку →
   восстанавливает настройки.

4. Единая file_is_usable: nft/apply.uc, generator_routes.uc,
   components/{updates,action}.uc, config/validator.uc,
   subscription/cache.uc — все используют helpers.file_is_usable.

5. Тест tests/file_usable.sh для проверки helpers CLI.

6. Исправлен components_updater_job.sh mock lib — добавлен core/helpers.uc
2026-08-03 14:07:57 +03:00
Dushnilin 9b956e1bb4 fix(singbox+nft): skip broken local .srs/.lst rulesets and raise size guards
- generator_routes.uc: ensure_custom_ruleset() returns null and local
  file references with size <100 bytes are skipped (previously would
  silently reference a nonexistent/broken path, leaving sing-box with
  no domain matchers)
- generator_routes.uc: ruleset/rule_sets_with_subnets loops guard
  against null ensured result before accessing .tag/.kind
- nft/apply.uc: community-subnets .lst files with size <50 bytes are
  skipped before handing data to nftables
2026-08-03 09:37:37 +03:00