github Leadaxe/LxBox v2.18.0
LxBox v2.18.0

latest releases: v2.25.18-rc.1, v2.25.17, v2.25.16...
3 months ago

L×Box v2.18.0

The headline is DNS groups: several servers behind one tag, so name
resolution survives the failure of any single one. On top of that — Shield
DNS
, a ready-made group of five providers shipped as the default resolver,
and a group trace in the profiler showing who actually answered. Separately —
a fix for the confusing "Not found" on a node that is right there in the list,
and crash reports of the core, now readable from inside the app.

Главное — DNS-группы: несколько серверов под одним тегом, чтобы резолв
переживал сбой любого из них. Сверху — Shield DNS, готовая группа из пяти
провайдеров дефолтным резолвером, и трасса группы в профайлере: видно, кто
именно ответил. Отдельно — фикс сбивающего с толку «Not found» на узле,
который виден в списке, и краш-репорты ядра, читаемые прямо из приложения.

Core / Ядро: sing-box-lx v1.14.0-lx.16 (was / было lx.15).


🇬🇧 English

🆕 What's new

🛡️ DNS groups

A new DNS server type — Group. Several servers hide behind one tag with a
selection strategy, and resolution keeps working when one of them dies.

Three modes:

Mode Behaviour
Stable sticks to one server until it fails
Fastest races them, then sticks to the winner
Parallel races on every query

Members have no up/down state. Instead there are two kinds of records with
a lifetime: an error (lives for Error TTL) and a win (lives for
Win TTL, Fastest only). A successful exchange erases the server's errors,
an error erases its wins. A path that died therefore comes back on its own once
it recovers — no manual flipping, no permanent blacklist.

A group can be used anywhere a DNS server tag is accepted: as the default
server, as the domain resolver, or as a DNS rule target. Groups can even
contain other groups.

When the tunnel is up, the server list shows the group's live state: the
current target and, for every member, whether it is clean, how many live errors
it has and its last RTT.

Members that are not available do not break the config. A disabled server,
a typo in a tag, the group itself in its own member list — all of that is
dropped at build time with a warning, and the config stays valid. Turn the
server back on and the member returns on its own; nothing is rewritten behind
your back.

🌍 Shield DNS — five providers out of the box

A fresh install now gets a ready-made group, dns_shield, and it becomes both
the default DNS server and the domain resolver.

Member Transport Path Provider
google_udp UDP :53 direct Google
cloudflare_udp UDP :53 direct Cloudflare
opendns_udp UDP :53 direct OpenDNS
google_doh DoH :443 direct Google
google_dot DoT :853 via VPN Google
cloudflare_dot DoT :853 via VPN Cloudflare
quad9_doh DoH :443 via VPN Quad9
yandex_udp UDP :53 direct Yandex
yandex_dot DoT :853 via VPN Yandex

Five providers, three transports, two paths — deliberately crossed so that no
single failure takes out more than one member of a kind. A provider goes down —
the other four answer. UDP:53 gets hijacked — DoT/DoH still work. The tunnel
drops — the direct members carry on. Direct access is blocked — the tunnelled
ones do.

The mode is Fastest with both TTLs at 5 minutes: an election every five
minutes, a single server per query in between. The winner is naturally the
fastest path, so "direct first, through the VPN when blocked" happens by
itself.

The two Yandex members come from the Russian domains & IPs preset. Switch
that preset off and they quietly drop out of the group while the rest keeps
working.

🔍 Group trace in the profiler

Open a DNS event in Stats and you now see how the query actually went through
the group: which group it entered, every probe with its outcome
(answered / timeout / servfail) and RTT, whether the query fanned out to
several servers at once, and whether the group fell into survival mode — no
clean members left, answering on a last-resort attempt.

🧩 Xray array import

An Xray config that describes several nodes inside a single element used to be
imported only partially. All of its nodes are now picked up.

🩺 Core crash reports

When the core died, the reason used to be lost: Go writes its panic trace to
stderr, and on Android stderr goes to /dev/null. All logcat kept was a bare
address with no symbols. The core saves that trace to a file by itself — that
file is now reachable.

Debug → the Crashes tab: every past crash with its date
and time, tap one to share the file. After a crash the app also raises a banner
on the main screen — once per crash, not on every launch. The whole archive
goes into Share dump as crash_archive; the last 10 reports are kept.

The Profiling buttons moved to the same screen as a third tab — pprof
snapshots are a diagnostic tool, not a setting, so they now sit next to the
logs and crashes instead of among the toggles.

For development there are two Debug API routes: GET /files/crash/list and
GET /files/local?name=CrashReport-lxbox.log.

This covers Go panics — not JNI aborts, native segfaults or kills by the
system. An empty report next to a tombstone is therefore a finding in itself:
the crash did not come from Go.

🐛 Fixed

  • "Not found" on a node that is visible in the list. When a subscription
    refreshes or processing rules change, the config is rebuilt immediately while
    the core keeps running the previous one until restart. The node list comes
    from the core, but node details were looked up in the freshly built config —
    in the window between the rebuild and the restart the tags diverged and the
    app said "Not found" about a node right there on screen. Node data now comes
    from the config of the running core. Copy JSON also stopped silently
    doing nothing in that situation.
  • WARP generator nodes now get persistent_keepalive — without it the
    connection silently died behind NAT.
  • The subscription prefix no longer accumulates in tags. Nodes patched by
    processing rules used to gain another copy of the prefix on every refresh
    (L: L: L: Node).
  • Main-screen banners were never translated — "Settings changed…",
    "Config changed…" and "Config loading error" showed up in English whatever
    the app language was.
  • Minimising the app no longer interrupts a mass ping.
  • Deleting your own DNS rule now asks for confirmation.
  • "Run URLTest" on an auto group tests all members again and switches the
    group to a live node.

🇷🇺 Русский

🆕 Что нового

🛡️ DNS-группы

Новый тип DNS-сервера — Group. Несколько серверов прячутся за одним тегом
со стратегией выбора, и резолв продолжает работать, когда один из них умирает.

Три режима:

Режим Поведение
Stable держится за один сервер, пока тот не сбоит
Fastest гонка, затем липнет к победителю
Parallel гонка на каждый запрос

У участников нет состояний «работает / не работает». Вместо этого есть два
вида записей со сроком жизни: ошибка (живёт Error TTL) и победа
(живёт Win TTL, только в Fastest). Успешный обмен стирает ошибки сервера,
ошибка стирает его победы. Поэтому умерший путь возвращается в строй сам,
когда оживает, — без ручных переключений и без вечного чёрного списка.

Группу можно поставить всюду, где принимается тег DNS-сервера: дефолтным
сервером, резолвером доменов или целью DNS-правила. Группы можно вкладывать
друг в друга.

При поднятом туннеле в списке серверов видно живое состояние группы: текущая
цель и по каждому участнику — чистый ли он, сколько живых ошибок и последний
RTT.

Недоступные участники не ломают конфиг. Выключенный сервер, опечатка в
теге, сама группа в списке своих же членов — всё это выбрасывается при сборке
с предупреждением, конфиг остаётся валидным. Включите сервер обратно —
участник вернётся сам, за вашей спиной ничего не переписывается.

🌍 Shield DNS — пять провайдеров из коробки

Свежая установка получает готовую группу dns_shield, и она же становится
дефолтным DNS-сервером и резолвером доменов.

Участник Транспорт Путь Провайдер
google_udp UDP :53 напрямую Google
cloudflare_udp UDP :53 напрямую Cloudflare
opendns_udp UDP :53 напрямую OpenDNS
google_doh DoH :443 напрямую Google
google_dot DoT :853 через VPN Google
cloudflare_dot DoT :853 через VPN Cloudflare
quad9_doh DoH :443 через VPN Quad9
yandex_udp UDP :53 напрямую Yandex
yandex_dot DoT :853 через VPN Yandex

Пять провайдеров, три транспорта, два пути — намеренно накрест, чтобы ни один
отказ не вынес больше одного участника своего рода. Ляжет провайдер — ответят
остальные четыре. Подменят UDP:53 — работают DoT/DoH. Упадёт туннель —
работают прямые. Заблокируют прямой доступ — работают туннельные.

Режим — Fastest, оба TTL по 5 минут: выборы раз в пять минут, между ними
один сервер на запрос. Победителем естественно становится самый быстрый путь,
поэтому «сначала напрямую, при блокировке через VPN» получается само.

Два яндекс-участника приезжают из пресета Russian domains & IPs. Выключите
пресет — они тихо выпадут из группы, а остальные продолжат работать.

🔍 Трасса группы в профайлере

Откройте DNS-событие в Stats — теперь видно, как запрос реально прошёл через
группу: в какую группу зашёл, каждая проба со своим исходом
(answered / timeout / servfail) и RTT, был ли веер сразу по нескольким
серверам и не ушла ли группа в режим выживания — когда чистых участников не
осталось и ответ получен последней попыткой.

🧩 Импорт Xray-массивов

Конфиг Xray, где в одном элементе описано несколько узлов, раньше
импортировался частично. Теперь забираются все узлы.

🩺 Краш-репорты ядра

Когда ядро падало, причина терялась: Go пишет трейс паники в stderr, а тот на
Android уходит в /dev/null. В logcat оставался только адрес без символов.
Ядро сохраняет этот трейс файлом само — теперь до файла можно добраться.

Debug → вкладка Crashes: все прошлые падения с датой и
временем, тап отдаёт файл. После падения приложение ещё и показывает плашку
на главном — один раз на краш, а не при каждом запуске. Весь архив уезжает в
Share dump полем crash_archive; хранятся 10 последних отчётов.

Кнопки Profiling переехали на тот же экран третьей вкладкой:
pprof-слепки — инструмент диагностики, а не настройка, и теперь лежат рядом
с логами и падениями, а не среди тумблеров.

Для разработки — два роута Debug API: GET /files/crash/list и
GET /files/local?name=CrashReport-lxbox.log.

Оговорка: это про паники Go — не про JNI-abort, нативные segfault'ы и kill
системой. Поэтому пустой репорт рядом с tombstone — сам по себе вывод: краш
пришёл не из Go.

🐛 Исправлено

  • «Not found» на узле, который виден в списке. При обновлении подписки или
    правке правил обработки конфиг пересобирается сразу, а ядро продолжает
    работать на прежнем до перезапуска. Список узлов приходит из ядра, а «инфо
    по узлу» искалось в новом конфиге — в окне между пересборкой и перезапуском
    теги расходились, и приложение отвечало «Not found» на ноду, видимую строкой
    выше. Теперь данные узла берутся из конфига работающего ядра. Заодно
    Copy JSON перестал молча ничего не делать в такой ситуации.
  • Узлы WARP-генератора получают persistent_keepalive — без него
    соединение молча отваливалось за NAT.
  • Префикс подписки не накапливается в теге. Узлы, пропатченные правилами
    обработки, при каждом обновлении получали ещё одну копию префикса
    (L: L: L: Node).
  • Плашки на главном экране не переводились — «Settings changed…»,
    «Config changed…» и «Config loading error» показывались по-английски вне
    зависимости от языка приложения.
  • Сворачивание приложения больше не рвёт массовый пинг.
  • Удаление своего DNS-правила спрашивает подтверждение.
  • «Run URLTest» на auto-группе снова тестирует всех членов и переключает
    группу на живой узел.

📲 Install

adb install -r LxBox-v2.18.0-arm64-v8a.apk

No uninstall needed — installs over the existing app, settings and
subscriptions are preserved.

Без uninstall! Поверх существующей установки. Настройки и подписки сохранятся.


Previous release / Предыдущий релиз: v2.17.0.

Don't miss a new LxBox release

NewReleases is sending notifications on new releases.