github Leadaxe/singbox-launcher v2.4.0
release v2.4.0

4 hours ago

Release v2.4.0

Downloads

macOS (Universal) - Supports both Apple Silicon and Intel

Option 1: Installation Script (Recommended)

Install with a single command (version v2.4.0):

curl -fsSL https://raw.githubusercontent.com/Leadaxe/singbox-launcher/develop/scripts/install-macos.sh | bash -s -- v2.4.0

The script will:

  • Download the release archive
  • Extract and install to /Applications/
  • Fix macOS quarantine attributes and permissions
  • Launch the application automatically

Option 2: Homebrew (stable releases only, available a few hours after the release)

brew install --cask leadaxe/tap/singbox-launcher

Update later with brew upgrade --cask singbox-launcher. The Cask installs the latest stable release, not a pre-release.

Option 3: Manual Installation

  1. Download: singbox-launcher-v2.4.0-macos.zip
  2. Extract the ZIP file
  3. Remove quarantine attribute (required):
    xattr -cr "singbox-launcher.app" && chmod +x "singbox-launcher.app/Contents/MacOS/singbox-launcher"
  4. Double-click singbox-launcher.app to run
    • If macOS blocks the app, go to System Settings → Privacy & Security and click "Open Anyway"
    • Alternatively, right-click the app and select "Open" (first time only)

Windows (amd64)

Option 1: Installer (Recommended)

  1. Download: singbox-launcher-v2.4.0-win64-setup.exe
  2. Run it and confirm the administrator prompt once. The launcher goes to C:\Program Files\singbox-launcher, your data to %LOCALAPPDATA%\singbox-launcher; sing-box.exe, wintun.dll, the config template and Mesa3D are included, nothing is downloaded on first launch
    • Tasks: desktop shortcut, Start with Windows, software OpenGL (Mesa3D) for RDP / VMs without a GPU
    • Installing over a previous version keeps your data; uninstall from Settings → Apps asks whether to remove the data too
    • The installer is not code-signed yet: if SmartScreen shows "Windows protected your PC", click More info → Run anyway

Option 2: Portable ZIP

  1. Download: singbox-launcher-v2.4.0-win64.zip
    • or singbox-launcher-v2.4.0-win64-full.zip — full bundle: sing-box.exe, wintun.dll, the config template and Mesa3D (mesa3d/, used only when no hardware OpenGL — RDP, VMs) are already inside, nothing is downloaded on first launch
  2. Extract the ZIP file to a folder your account can write to, for example D:\Tools\singbox-launcher\ — settings stay next to the program (portable.txt)
    • Under C:\Program Files\ the launcher keeps its data in %LOCALAPPDATA%\singbox-launcher instead
  3. Run singbox-launcher.exe from that folder — no administrator rights, no UAC prompt
    • TUN needs administrator rights: Start offers Restart as administrator or Switch to proxy mode
    • The regular archive downloads sing-box and wintun.dll on first launch

Windows 7 (x86, legacy)

  1. Download: singbox-launcher-v2.4.0-win7-32.zip
  2. Extract the ZIP file to a folder and run singbox-launcher-win7-32.exe
    • For Windows 7 / 32-bit or legacy compatibility only
    • Runs as administrator (UAC prompt on every start), settings stay next to the program (portable.txt); no installer and no daemon service

Linux Support

⚠️ Linux build temporarily unavailable - мы ищем тестировщика для ручного тестирования перед включением автоматической сборки.

Checksums

See checksums.txt for SHA256 checksums of all files.

Release notes — v2.4.0 (2026-10-16)

EN

A minor release after v2.3.10. Core sing-box-lx 1.14.3-lx.21 (was 1.14.3-lx.18), contract 1.1.130 (was 1.1.119).

New

  • Tunnel ingress protection. A client tunnel is a two-way channel: the server on the other side of a WireGuard/AWG, OpenVPN or OpenConnect node could open connections to your router, your LAN or the internet through you, because the core's userspace stack accepts packets for any address. The new Tunnel ingress preset (on by default, added once to existing setups, placed right after the locked head of the rules) rejects every connection arriving from such a tunnel, except what the node allows: the node window of these types gets Allow access to this device (services on the tunnel address; they see the peer as 127.0.0.1), Expose local network (private networks) and Allow as gateway (anything). The preset form has just three settings: what happens to the rest (Incoming from tunnels, reject by default, or drop, or an outbound), where allowed device/LAN traffic goes (direct-out) and where gateway traffic goes (proxy-out). While the rest is rejected, peers that are not gateways also get their DNS queries rejected. Tailscale is not covered: tailnet peers are your own devices and already follow Tailscale ACLs and what you announce with advertise_routes / advertise_exit_node. Contract 1.1.126 / 1.1.129, TEMPLATE_LANG §6.5.2, decisions D-134, D-136.
  • DNS follows the rule. The window of your own rule (domains, processes or SRS) has a DNS tab: Send DNS to a dedicated server sends DNS queries that match the rule to the chosen server, Force IPv4 (drop AAAA) answers AAAA for them with an empty reply. The build derives the DNS rules from the routing rule and places them before the first library preset with a later position; the DNS tab shows them as read-only 📎 rows, the Rules list marks the rule. Unavailable for rules with ports, protocols or network and for IP-only rules. A disabled DNS server the rule needs stays in the config (📎 in the server list); a deleted one drops the DNS rule with a warning in the build report. The option is the same as in LxBox and now travels in backups both ways — before, the launcher dropped it on import and on save. Contract 1.1.130, TEMPLATE_LANG §6.11, decision D-137 (#140).
  • Add server: forms for VLESS, Hysteria2, Trojan, WireGuard (AWG), Naive and MASQUE. VLESS: security None / TLS / Reality, uTLS fingerprint, transports ws, gRPC, HTTP, HTTPUpgrade, XHTTP. Hysteria2: obfuscation and port hopping. WireGuard (AWG): a collapsed AmneziaWG block (jc…i5). SOCKS5, HTTP and WireGuard moved to the same registry-driven form. The type list is VLESS · Hysteria2 · Trojan · WireGuard (AWG) · Naive · MASQUE · SOCKS5 · HTTP · OpenConnect (SSL VPN) · Tailscale · Source. The same form edits an existing node of these types in the node window. The WireGuard form no longer has a DNS field: tunnel DNS was never applied (the launcher's DNS is global).
  • OpenConnect (FortiGate, Cisco AnyConnect, GlobalProtect, F5, Pulse, Juniper NC). A form in Add server and in the node editor: gateway type, server, username and password, server certificate check (system CAs / pinned fingerprint / do not verify), SNI and group, and an Advanced block (TCP only, User-Agent, Hostcheck for FortiGate, MTU, DPD interval, reconnect timeout, disable IPv6, legacy crypto). An empty field writes no key. In the server list the node is labelled like openconnect·fortinet.
  • OpenConnect second factor and browser (SAML) sign-in — daemon mode (lxd) and remote machines only. When the gateway asks for a code, a dialog shows the gateway's own form fields; "Not now" closes it and sends nothing, "Request a new code" asks the gateway again. FortiGate browser sign-in works through a link and a temporary local callback on 127.0.0.1 (port from the gateway's answer, or 8020). In classic mode the node shows a hint that code prompts are unavailable. SSO that returns a cookie (AnyConnect) is not supported yet.
  • Sources: Add with an empty field opens the Add server form; the field's hint names OpenVPN among accepted inputs.
  • DNS servers: the server form covers DoQ (quic, port 853) and DoH3 (h3, port 443, with path) alongside UDP/TCP/DoT/DoH, as in LxBox.
  • Detour picker is a two-level tree: "(none — direct)" on top and expandable Directions and Nodes branches; the branch with the current choice opens by itself. A chosen target that is no longer in the config stays visible with a ⚠ (missing) mark.
  • Template language: short #if form. {"#if": [cond, value, else]} is now the canonical spelling; the long {"#and": […], "#value": …, "#else": …} form is still read indefinitely, and the stock template is rewritten to the short form with byte-identical output. A #do operation in a node loop can be conditional: {"#if": [cond, {"#append": "@node"}]} skips nodes where the condition is false. Contract 1.1.125, TEMPLATE_LANG §4.1 / §6.7.1, decision D-133.
  • Core builds for linux/386 and linux/riscv64. "Download core" now finds them for a machine whose daemon has not reported its platform yet, riscv64 is offered in the machine and Target architecture lists (Target also gains mips/mipsle), and a Linux machine on 386 or riscv64 without a passport defaults to the procd service recipe, as these builds target OpenWrt. A machine whose daemon reports packed (core 1.14.3-lx.21+, the running core is UPX-packed) gets the .upx.tar.gz copy from "Download core", saved as …-upx beside the plain one; if the release has no packed copy, the plain binary is downloaded with a warning that it is 4–5 times larger.
  • Homebrew on macOS: brew install --cask leadaxe/tap/singbox-launcher. The Cask lives in Leadaxe/homebrew-tap and follows stable releases on its own; the install script stays the recommended option.
  • Compact JSON in the Preset tab. The preset window's Preset tab shows short constructs on one line ({"#if": ["@node.allow_local", {"#append": "@node"}]}, "#in": [...]) instead of spreading them over five to eight lines; objects and arrays up to 100 characters stay on one line.

Changed

  • "Skip presets" is now "Skip Tailscale presets". The node field skip_presets became skip_tailscale_presets, is shown for Tailscale nodes only and affects only the tailscale preset — it can no longer switch off the tunnel protection. Old state.json files and backups with skip_presets are read as before; only the new key is written.
  • Your SRS rules keep their place in the rule order. In the built config an SRS rule ignored its position and went above every other rule of yours and every library preset, so a rule shown below it in Rules could never match first. It now stands where the list puts it. If you relied on the old order, check the rules list after updating.
  • The "Split all traffic 50/50" preset is gone. It was no longer relevant; a saved rule that referenced it is kept disabled with a warning rather than lost.

Fixed

  • DNS rule editor no longer drops rule_set references. Opening "Edit DNS Rule" rebuilt the JSON from the form, whose picker held one value from a fixed list, so "rule_set": ["user:custom", "user:dpi"] came back as nothing (or as its first tag). The picker is now a multi-select, keeps tags that are not in the list (a disabled rule, a hand-written tag) and a server that is not enabled, and edits made in the JSON tab carry over to the form instead of being overwritten. Fields of the other rule type are cleared only when you switch the type yourself (#140).
  • A preset's DNS rule now appears where its routing rule stands. Routing rules live on a numbered axis, DNS rules are ordered by hand, and a newly enabled preset's DNS rule used to be appended after every DNS rule you already had. For the new Tunnel ingress preset that meant its DNS reject landed behind the FakeIP catch-all (A/AAAA → fakeip) on existing setups, so closed tunnel peers still had their DNS answered although their connections were rejected. A preset's DNS rule is now inserted in front of the first preset DNS rule with a higher routing number (late defaults, presets enabled from the library, backups that lack the entry, the Debug API and a build that runs before the first save alike); your own DNS rules and the rules already in the list are not moved. Fresh installs are unchanged. Contract 1.1.127, TEMPLATE_LANG §6.10, decision D-135.
  • OpenConnect nodes added as sing-box JSON ("type": "openconnect") land in endpoints[], where the core expects them. Before, they went to outbounds[] and the core rejected the whole config with unknown outbound type: openconnect. On a core built without with_openconnect the node is dropped with a build-report warning instead.
  • A node whose body the core cannot even decode (for example an old MASQUE body with network) is turned off automatically like any other node the core rejects, and the config is rebuilt. Before, this error named no tag, the safety net stayed silent and the VPN did not start.
  • DNS rules: the "SRS (existing rule_set)" picker lists the rule sets of your own SRS rules (user:<name>, user:<name>:2, …), not only those of enabled library presets (#140).
  • Detour picker and rule/DNS target lists no longer offer template Direction stubs you deleted (vpn ①, vpn ②), and block-out is no longer offered as a detour.
  • Tailscale: the "Keep local network reachable while using the exit node" checkbox is gone from Add server and the node's Settings block — it had no effect (LAN traffic bypasses the exit node through the "Private IPs" rule preset). exit_node_allow_lan_access is still accepted from JSON.
  • macOS release ZIPs keep the executable bit. The launcher binary was packed as 0644, so an app extracted by hand did not start without chmod +x.

Core

  • sing-box-lx 1.14.3-lx.21 (was 1.14.3-lx.18). lx.19: lxd update from the launcher no longer rolls back with TUNSETIFF: device or resource busy (the updater no longer inherits the core's TUN descriptor). From lx.17/lx.18 the first update needs one manual step: stop the core, press Update, start the core — or run sing-box lxd update over SSH once; later updates work with the core running. lx.20: lxd update prints download progress, shown in the Service window.
  • lx.21: router builds for linux-386 (SSE2) and linux-riscv64; UPX-packed copies for linux-arm64 and linux-mipsle-softfloat (~17 MB on flash instead of 75–90 MB, at the cost of RAM and a slower start). lxd update keeps a packed core packed and checks free space against the new binary before writing; the daemon reports packed, which the launcher's "Download core" uses. The core also gains an experimental trusttunnel outbound/inbound (AdGuard TrustTunnel); the launcher does not offer it yet.

Technical / Internal

  • Contract 1.1.120–1.1.124: openconnect as a known endpoint type; the core's decode-error form names the node by index; wildcard * in the registry, the form attribute and the variant role (fields_unchecked removed); forms on scheme ref fields and shared tls/transports fields, form.fixed, form.implies, exclude_fields/exclude_variants, array element [0] in form paths, active choice by the longest match; an empty described object is dropped, an empty pass-through object is kept. Corpus corpus/form/*_form.json.
  • Fyne 2.8.1 → 2.8.2 (#142); GLFW 3.4 on the tagged pre.2.
  • golangci-lint CI takes Go from go.mod, golangci-lint 2.14.0, action v9; 36 errcheck/unused/bodyclose findings fixed.
  • internal/jsonfmt.FormatCompact — order-preserving compact JSON printer (one-line containers up to 100 characters, number literals as written, no HTML escaping); bin/wizard_template.json is kept in this form (go run ./tools/tplfmt -w|-check, guarded by TestWizardTemplateFormatted), 2250 → 1383 lines with the same content.
  • The #if body is parsed in one place (core/template/if_form.go); map-spread, array-element, EvalIfScalar, default_value, the load validator and #do all go through it. Corpus: 28 new cases (short_*, do_if_*), paired with the long form.
  • Rule DNS mirror: state.Rule.DNS (RuleDNS, record key dns), build.RuleDNSMirrorMatch (matcher and gate from the registry allowlists rule_dns_mirror_match / rule_dns_mirror_gate, shared by the build and the rule window), build.RuleDNSMirrorIndex (placement, shared by the build and the DNS tab); mirrors are inserted in MergePresetsIntoDNS and never stored in state.DNS.Rules. Test TestRuleDNSMirror (backup → state.json → export round trip and the built dns section).
  • state.PresetDNSSlotIndex is the single place that computes where a new preset DNS slot goes; SyncDNSOptionsWithActivePresets, the DNS tab's ReconcileDNSRuleOrder and ResolveDNS (which now walks a synced copy of dns.rules instead of appending unlisted presets at the end) all use it. One named test: TestLatePresetDNSRuleTakesAxisPosition.
  • Node record fields travel as one configtypes.NodeRecordFlags (state → emission → build cache → template.PresetNode.Record → @node.<field>), instead of a per-field map. Corpus: for_each_node* cases renamed to skip_tailscale_presets, new tunnel_ingress_mixed / tunnel_ingress_no_nodes.

RU

Минорный релиз после v2.3.10. Ядро sing-box-lx 1.14.3-lx.21 (было 1.14.3-lx.18), контракт 1.1.130 (было 1.1.119).

Новое

  • Защита от входящих из туннеля. Клиентский туннель — двусторонний канал: сервер на той стороне узла WireGuard/AWG, OpenVPN или OpenConnect мог открыть соединение к роутеру, в вашу LAN или в интернет через вас — userspace-стек ядра принимает пакеты на любой адрес. Новый пресет Tunnel ingress (включён по умолчанию, у существующих настроек появляется один раз, стоит сразу после запертой головы правил) отклоняет всё, что приходит из такого туннеля, кроме разрешённого узлом: в окне узла этих типов переключатели Allow access to this device (сервисы на туннельном адресе; пира они видят как 127.0.0.1), Expose local network (частные сети) и Allow as gateway (всё). В форме пресета всего три настройки: что делать с остальным (Incoming from tunnels, по умолчанию reject, либо drop, либо outbound), куда идёт разрешённое к устройству и LAN (direct-out) и куда — трафик шлюза (proxy-out). Пока остальное отклоняется, пирам, которые не шлюз, отклоняются и DNS-запросы. Tailscale пресет не трогает: пиры tailnet — ваши же устройства, их ограничивают ACL Tailscale и то, что вы анонсируете через advertise_routes / advertise_exit_node. Контракт 1.1.126 / 1.1.129, TEMPLATE_LANG §6.5.2, решения D-134, D-136.
  • DNS следует за правилом. В окне своего правила (домены, процессы или SRS) появилась вкладка DNS: Send DNS to a dedicated server отправляет DNS-запросы, подходящие под правило, на выбранный сервер, Force IPv4 (drop AAAA) отвечает на их AAAA пустым ответом. Сборка выводит DNS-правила из маршрутного и ставит их перед первым пресетом библиотеки с более поздней позицией; во вкладке DNS они видны строками 📎 только для чтения, в списке Rules правило помечено. Недоступно для правил с портами, протоколами или network и для правил только по IP. Выключенный DNS-сервер, нужный правилу, остаётся в конфиге (📎 в списке серверов); удалённый — DNS-правило не выпускается, в отчёте сборки предупреждение. Опция та же, что в LxBox, и теперь ездит в бэкапах в обе стороны — раньше лаунчер терял её при импорте и сохранении. Контракт 1.1.130, TEMPLATE_LANG §6.11, решение D-137 (#140).
  • «Add server»: формы для VLESS, Hysteria2, Trojan, WireGuard (AWG), Naive и MASQUE. VLESS: безопасность None / TLS / Reality, отпечаток uTLS, транспорты ws, gRPC, HTTP, HTTPUpgrade, XHTTP. Hysteria2: обфускация и port hopping. WireGuard (AWG): свёрнутый блок AmneziaWG (jc…i5). SOCKS5, HTTP и WireGuard переведены на ту же форму по реестру. Список типов: VLESS · Hysteria2 · Trojan · WireGuard (AWG) · Naive · MASQUE · SOCKS5 · HTTP · OpenConnect (SSL VPN) · Tailscale · Source. Та же форма правит готовый узел этих типов в окне узла. В форме WireGuard больше нет поля DNS: DNS туннеля и раньше не применялся (DNS у лаунчера общий).
  • OpenConnect (FortiGate, Cisco AnyConnect, GlobalProtect, F5, Pulse, Juniper NC). Форма в «Add server» и в правке узла: тип шлюза, сервер, логин и пароль, проверка сертификата сервера (системные CA / отпечаток / без проверки), SNI и группа, блок Advanced (TCP only, User-Agent, Hostcheck для FortiGate, MTU, DPD, reconnect timeout, отключение IPv6, legacy crypto). Пустое поле ключ не пишет. В списке серверов узел подписан как openconnect·fortinet.
  • OpenConnect: второй фактор и вход через браузер (SAML) — только в daemon-режиме (lxd) и на удалённых машинах. Если шлюз просит код, открывается диалог с полями, которые отдал сам шлюз; «Not now» закрывает его и ничего не шлёт, «Request a new code» запрашивает код заново. Браузерный вход для FortiGate идёт через ссылку и временный локальный callback на 127.0.0.1 (порт из ответа шлюза или 8020). В классическом режиме на узле подсказка, что запрос кода недоступен. SSO через cookie (AnyConnect) пока не поддерживается.
  • Sources: Add при пустом поле открывает форму «Add server»; подсказка поля называет OpenVPN среди принимаемых форматов.
  • DNS-серверы: форма сервера умеет DoQ (quic, порт 853) и DoH3 (h3, порт 443, с путём) наряду с UDP/TCP/DoT/DoH — как в LxBox.
  • Выбор detour — двухуровневое дерево: сверху «(нет — напрямую)», под ним раскрываемые ветки «Направления» и «Узлы»; ветка с текущим выбором раскрыта сразу. Выбранная цель, которой больше нет в конфиге, остаётся видна с пометкой ⚠ (нет в конфиге).
  • Язык шаблонов: короткая форма #if. {"#if": [cond, value, else]} — теперь канон; длинная {"#and": […], "#value": …, "#else": …} читается бессрочно, штатный шаблон переписан на короткую форму с байт-в-байт тем же конфигом. Операция #do обхода узлов может быть условной: {"#if": [cond, {"#append": "@node"}]} пропускает узлы, где условие ложно. Контракт 1.1.125, TEMPLATE_LANG §4.1 / §6.7.1, решение D-133.
  • Сборки ядра linux/386 и linux/riscv64. «Download core» находит их и для машины, чей демон ещё не сообщил платформу; riscv64 есть в выборе архитектуры машины и вкладки Target (там же добавлены mips/mipsle); Linux-машина на 386 или riscv64 без паспорта по умолчанию получает рецепт службы procd — эти сборки под OpenWrt. Машина, чей демон сообщает packed (ядро 1.14.3-lx.21+, работающее ядро сжато UPX), получает в «Download core» копию .upx.tar.gz — файл с суффиксом -upx рядом с обычным; если сжатой копии в релизе нет, качается обычный бинарь с предупреждением, что он в 4–5 раз крупнее.
  • Homebrew на macOS: brew install --cask leadaxe/tap/singbox-launcher. Cask живёт в Leadaxe/homebrew-tap и сам следует за стабильными релизами; install-скрипт остаётся рекомендуемым способом.
  • Компактный JSON на вкладке Preset. Вкладка Preset окна пресета показывает короткие конструкции в строку ({"#if": ["@node.allow_local", {"#append": "@node"}]}, "#in": [...]), а не на пяти–восьми строках; объекты и массивы до 100 символов остаются в одной строке.

Изменено

  • «Skip presets» стал «Skip Tailscale presets». Поле узла skip_presets переименовано в skip_tailscale_presets, показывается только у узлов Tailscale и действует только на пресет tailscale — выключить им защиту туннеля больше нельзя. Старые state.json и бэкапы с skip_presets читаются как раньше, пишется только новый ключ.
  • Собственные SRS-правила стоят на своём месте в порядке правил. В собранном конфиге SRS-правило не учитывало свою позицию и вставало выше всех остальных ваших правил и пресетов библиотеки, так что правило, стоящее в Rules под ним, не могло сработать первым. Теперь оно стоит там, где его ставит список. Если вы полагались на прежний порядок, проверьте список правил после обновления.
  • Пресет «Split all traffic 50/50» снят. Он потерял актуальность; сохранённое правило с ссылкой на него остаётся выключенным с предупреждением, а не теряется.

Исправлено

  • Редактор DNS-правил больше не теряет ссылки rule_set. «Edit DNS Rule» при открытии пересобирал JSON из формы, где выбор набора был одним значением из фиксированного списка, и "rule_set": ["user:custom", "user:dpi"] превращался в пустоту (или в первый тег). Теперь выбор множественный, теги не из списка (выключенное правило, ручной ввод) и невключённый сервер сохраняются, а правки на вкладке JSON переносятся в форму, а не затираются ею. Поля другого типа правила вычищаются только при ручной смене типа (#140).
  • DNS-правило пресета появляется там, где стоит его маршрутное правило. Маршрутные правила живут на нумерованной оси, DNS-правила упорядочены вручную, и DNS-правило только что включённого пресета дописывалось после всех ваших DNS-правил. Для нового пресета Tunnel ingress это означало, что его DNS-reject у существующих настроек вставал за «ловящим всё» правилом FakeIP (A/AAAA → fakeip): закрытым пирам туннеля всё ещё отвечал DNS, хотя их соединения отклонялись. Теперь DNS-правило пресета вставляется перед первым DNS-правилом пресета с бо́льшим номером маршрута (поздние дефолты, включение из Library, бэкап без такой записи, Debug API и сборка до первого сохранения — одинаково); ваши DNS-правила и уже стоящие в списке не двигаются. Чистая установка не меняется. Контракт 1.1.127, TEMPLATE_LANG §6.10, решение D-135.
  • Узлы OpenConnect, добавленные как sing-box JSON ("type": "openconnect"), попадают в endpoints[], где их ждёт ядро. Раньше они уходили в outbounds[], и ядро отвергало весь конфиг с unknown outbound type: openconnect. На ядре без with_openconnect узел снимается с предупреждением в отчёте сборки.
  • Узел, тело которого ядро не может даже декодировать (например, старое тело MASQUE с network), выключается автоматически, как любой узел, отвергнутый ядром, и конфиг пересобирается. Раньше в такой ошибке не было тега, страховка молчала, и VPN не поднимался.
  • DNS-правила: в выборе «SRS (existing rule_set)» есть наборы ваших собственных SRS-правил (user:<имя>, user:<имя>:2, …), а не только наборы включённых пресетов библиотеки (#140).
  • Выбор detour и списки целей правил/DNS больше не предлагают удалённые заготовки Направлений шаблона (vpn ①, vpn ②), а block-out больше не предлагается как detour.
  • Tailscale: из «Add server» и блока узла в Settings убрана галка «Keep local network reachable while using the exit node» — она ничего не делала (локальную сеть мимо exit node пускает пресет «Private IPs»). Поле exit_node_allow_lan_access по-прежнему принимается из JSON.
  • В macOS-архивах релиза у бинаря есть бит исполнения. Бинарь лаунчера упаковывался как 0644, и распакованное вручную приложение не запускалось без chmod +x.

Ядро

  • sing-box-lx 1.14.3-lx.21 (было 1.14.3-lx.18). lx.19: lxd update из лаунчера больше не откатывается с TUNSETIFF: device or resource busy (апдейтер больше не наследует TUN-дескриптор ядра). С lx.17/lx.18 первое обновление требует одного ручного шага: остановить ядро, нажать Update, запустить ядро — либо один раз sing-box lxd update по SSH; дальше обновление работает при работающем ядре. lx.20: lxd update показывает прогресс скачивания, он виден в окне Service.
  • lx.21: роутерные сборки linux-386 (нужен SSE2) и linux-riscv64; копии linux-arm64 и linux-mipsle-softfloat, сжатые UPX (~17 МБ на флеше вместо 75–90 МБ ценой RAM и более долгого старта). lxd update оставляет сжатое ядро сжатым и до записи проверяет место под новый бинарь; демон сообщает packed, по нему «Download core» в лаунчере выбирает сжатую копию. В ядре также появились экспериментальные outbound/inbound trusttunnel (AdGuard TrustTunnel); в лаунчере их пока нет.

Техническое / Внутреннее

  • Контракт 1.1.120–1.1.124: openconnect как известный тип endpoint; ошибка декодирования ядра называет узел по индексу; wildcard * в реестре, атрибут form и роль variant (fields_unchecked снят); формы у ref-полей схем и у полей общих tls/transports, form.fixed, form.implies, exclude_fields/exclude_variants, элемент массива [0] в путях формы, активный вариант по самому длинному совпадению; пустой описанный объект снимается, пустой сквозной — остаётся. Корпус corpus/form/*_form.json.
  • Fyne 2.8.1 → 2.8.2 (#142); GLFW 3.4 на теге pre.2.
  • CI golangci-lint берёт Go из go.mod, golangci-lint 2.14.0, action v9; исправлены 36 замечаний errcheck/unused/bodyclose.
  • internal/jsonfmt.FormatCompact — компактный печатник JSON с сохранением порядка ключей (контейнер в строку до 100 символов, литералы чисел как в исходнике, без HTML-экранирования); bin/wizard_template.json держится в этом виде (go run ./tools/tplfmt -w|-check, стережёт TestWizardTemplateFormatted), 2250 → 1383 строки при том же содержимом.
  • Тело #if разбирается в одном месте (core/template/if_form.go); map-spread, элемент массива, EvalIfScalar, default_value, валидатор загрузки и #do идут через него. Корпус: 28 новых кейсов (short_*, do_if_*), парных с длинной формой.
  • DNS-зеркало правила: state.Rule.DNS (RuleDNS, ключ записи dns), build.RuleDNSMirrorMatch (матчер и гейт по спискам реестра rule_dns_mirror_match / rule_dns_mirror_gate, общий для сборки и окна правила), build.RuleDNSMirrorIndex (место, общее для сборки и вкладки DNS); зеркала вставляются в MergePresetsIntoDNS и в state.DNS.Rules не хранятся. Тест TestRuleDNSMirror (круг бэкап → state.json → экспорт и собранная секция dns).
  • state.PresetDNSSlotIndex — единственное место, где считается позиция нового DNS-слота пресета; им пользуются SyncDNSOptionsWithActivePresets, ReconcileDNSRuleOrder DNS-вкладки и ResolveDNS (теперь обходит синхронизированную копию dns.rules, а не дописывает неучтённые пресеты в конец). Один именованный тест: TestLatePresetDNSRuleTakesAxisPosition.
  • Поля записи узла едут одной структурой configtypes.NodeRecordFlags (состояние → эмиссия → кэш сборки → template.PresetNode.Record → @node.<поле>) вместо карты на каждое поле. Корпус: кейсы for_each_node* на skip_tailscale_presets, новые tunnel_ingress_mixed / tunnel_ingress_no_nodes.

Don't miss a new singbox-launcher release

NewReleases is sending notifications on new releases.