v1.2.0
sleep3r/mtproto.zigv1.2.0Jun 9, 2026by sleep3r
Upgrading?
AI Summary
This release introduces a new egress provider that converts VPN share-links into tunnelling egress, utilizing sing-box for VLESS/VMess/Trojan/SS and native WireGuard. It also fixes a critical tunnel-pool failover bug and refactors the fronting domain validation logic into a shared helper.
Key Highlights
- New `mtbuddy setup egress <link>` command for VPN links
- Tunnel-pool failover now actually switches when a tunnel is disabled
- Refactored `fronting_domain.zig` helper for x25519 checks
- Hardening: Routing table exclusivity and link validation
New Features
- VPN-link tunnel egress (sing-box TUN mode)
- Tunnel-pool failover functionality
- Shared fronting domain validation helper
Full Release Notes
<details open> <summary>🇷🇺 Что нового (RU)</summary> ## Что добавляет этот релиз `v1.2.0` — релиз про **расширение апстрима**: новый провайдер egress превращает обычную VPN-ссылку в чистый, трудноблокируемый выход для хопа прокси→Telegram. Плюс — фикс автопереключения в туннель-пуле (по репорту [#323](https://github.com/sleep3r/mtproto.zig/discussions/323)) и рефактор проверки fronting-домена. > [!NOTE] > Новая фича включается **только явной командой** — обновление безопасно, существующие деплои ничего не меняют. Egress ложится в ту же абстракцию `type = tunnel`, что и AmneziaWG. ## Egress из VPN-ссылки — `mtbuddy setup egress <ссылка>` Одна команда превращает share-ссылку в **туннельный** egress (прозрачный L3 + policy-routing — ровно как AmneziaWG), на двух бэкендах: - **`vless:// vmess:// trojan:// ss://`** → локальный **sing-box в TUN-режиме** (интерфейс `sbx0`). DC-трафик прокси (`SO_MARK=200`) направляется через него (`fwmark 200 → table 200 → sbx0`) — тот же механизм, что у WG-туннеля. **VLESS-Reality маскирует хоп выхода под настоящий TLS** к реальному сайту — заметно труднее блокировать, чем фингерпринт WireGuard. - **`wireguard://`** → нативный kernel-WG/AmneziaWG-туннель (переиспользует существующий флоу; AmneziaWG-ручки `jc/s1/h1..` и presharedkey проносятся). Несколько ссылок → sing-box `urltest`-пул с failover. **Ядро прокси не меняется** — оно просто метит сокеты, как для любого туннеля; вся работа в `mtbuddy`. ## Автопереключение в туннель-пуле теперь работает ([#323](https://github.com/sleep3r/mtproto.zig/discussions/323)) **Проблема:** при двух WG-туннелях в пуле (`priority auto`) выключение активного туннеля **не приводило к переключению** на второй рабочий. **Причина:** контроллер пула (`setup_tunnel.sh`, раз в 30с) считал «здоровым» любой *поднятый* интерфейс — результат проверки достижимости Telegram логировался, но игнорировался (всегда `return 0`). Поэтому всегда выбирался первый поднятый интерфейс, а мёртвый-но-поднятый активный туннель никогда не пропускался. **Фикс:** двухфазный выбор — сперва туннель, который реально достаёт до Telegram (настоящий failover), иначе fallback на первый просто-рабочий (чтобы single-tunnel-деплой не ушёл в чёрную дыру — помечается `degraded`). Выбор стал «липким»: предпочитает текущий активный туннель, если он ещё здоров, чтобы не флапать каждые 30с. Покрыто новым installer-e2e-тестом. ## Проверка fronting-домена — общий хелпер x25519-проверка пригодности `tls_domain` вынесена из инсталлера в `fronting_domain.zig` и теперь шарится тремя точками: `mtbuddy install`, `mtbuddy setup masking --domain …` и `mtbuddy config doctor --network` (где рассинхрон теперь ещё и плюсует к счётчику предупреждений в summary). Плюс тесты на классификацию вывода openssl (single-round x25519 / доступен-без-x25519 / недоступен). ## Закалка (из самоаудита) Перед мержем — два независимых код-ревью + ручной проход; найденное закрыто: - **Эксклюзивность `table 200`:** sing-box-egress и WG-пул владеют одной таблицей маршрутизации/`fwmark 200` — теперь взаимоисключающие (поднятие одного снимает другой), иначе таймер пула каждые 30с молча уводил бы маршрут с `sbx0`. - **Валидация ссылок:** транспорты кроме `tcp/ws/grpc` и неизвестные sing-box'у SS-шифры **отклоняются с понятной ошибкой** на этапе разбора, а не молча вырождаются в plain-TCP / роняют весь конфиг sing-box. - **Порядок старта:** `mtproto-proxy` упорядочен `After=`/`Wants=` egress-юнита (drop-in) — на ребуте `sbx0` и его маршрут поднимаются раньше, чем прокси метит DC-сокеты. - **Тихий и проверенный uninstall:** удаление больше не сыпет ожидаемыми ошибками (`stop`/`flush`/`netns del` отсутствующих компонентов) поверх спиннера; в installer-e2e добавлена проверка удаления — и она сразу поймала **реальный баг**: юнит `mtproto-mask-health.service` никогда не удалялся (путь с двойным `.service`). ## Проверено - **Сквозная проверка egress** (systemd-контейнер ubuntu:20.04, arm64): `setup egress` с реальной VLESS-Reality-ссылкой → `sbx0` поднят, `table 200 default dev sbx0`, и запрос с `fwmark 200` (тот самый `SO_MARK` прокси) выходит **с IP сервера** сквозь Reality-туннель. - **Failover-e2e** (`verify_tunnel_pool_failover`): `awg0` (Telegram-проба заблокирована) + `awg1` (проба ок) → контроллер выбирает `awg1`. - `zig build test`, кросс-сборка `x86_64-linux` + `aarch64-linux`, `zig fmt` — зелёные; **installer-e2e на 5 ОС** (debian 11/12, ubuntu 20.04/22.04/24.04), включая новую проверку удаления. </details> --- <details> <summary>🇬🇧 Release notes (EN)</summary> ## What this release adds `v1.2.0` is an **upstream-egress** release: a new egress provider turns an ordinary VPN share-link into a clean, hard-to-block exit for the proxy→Telegram hop. Plus a tunnel-pool failover fix (reported in [#323](https://github.com/sleep3r/mtproto.zig/discussions/323)) and a fronting-domain-check refactor. > [!NOTE] > The new feature is opt-in via an **explicit command** — upgrading is safe and existing deployments change nothing. The egress slots into the same `type = tunnel` abstraction as AmneziaWG. ## VPN-link egress — `mtbuddy setup egress <link>` One command turns a share-link into a **tunnel** egress (transparent L3 + policy routing — exactly like AmneziaWG), on two backends: - **`vless:// vmess:// trojan:// ss://`** → a local **sing-box in TUN mode** (interface `sbx0`). The proxy's `SO_MARK=200` DC traffic is policy-routed through it (`fwmark 200 → table 200 → sbx0`) — the same mechanism the WG tunnel uses. **VLESS-Reality camouflages the egress hop as real TLS** to a real site — much harder to block than WireGuard's fingerprint. - **`wireguard://`** → the native kernel WG/AmneziaWG tunnel (reuses the existing flow; AmneziaWG knobs `jc/s1/h1..` and presharedkey are carried through). More than one link → a sing-box `urltest` failover pool. **The proxy relay is unchanged** — it just SO_MARKs, as for any tunnel; all the work lives in `mtbuddy`. ## Tunnel-pool failover actually switches now ([#323](https://github.com/sleep3r/mtproto.zig/discussions/323)) **The problem:** with two WG tunnels in the pool (`priority auto`), disabling the active tunnel **did not fail over** to the second working one. **Root cause:** the pool controller (`setup_tunnel.sh`, every 30s) treated *any up* interface as healthy — the Telegram-reachability probe result was logged but ignored (always `return 0`). So the first up interface always won, and a dead-but-up active tunnel was never skipped. **The fix:** two-pass selection — first a tunnel that actually reaches Telegram (real failover), else fall back to the first merely-usable one (so a single-tunnel deploy doesn't go dark — marked `degraded`). Selection is now sticky: it prefers the currently-active tunnel while it's still healthy, to avoid flapping every 30s. Covered by a new installer-e2e test. ## Fronting-domain check — a shared helper The x25519 `tls_domain` suitability check moves out of the installer into `fronting_domain.zig`, now shared by `mtbuddy install`, `mtbuddy setup masking --domain …`, and `mtbuddy config doctor --network` (where a mismatch now also bumps the summary warning count). Plus tests for the openssl-output classification (single-round x25519 / reachable-without-x25519 / unreachable). ## Hardening (from a self-audit) Before merge: two independent code reviews + a manual pass; findings closed: - **`table 200` exclusivity:** the sing-box egress and the WG pool both own the same routing table / `fwmark 200` — they're now mutually exclusive (setting one up retires the other), otherwise the pool timer would silently steal the route from `sbx0` every 30s. - **Link validation:** transports other than `tcp/ws/grpc` and shadowsocks ciphers sing-box doesn't accept are **rejected with a clear error** at parse time, instead of silently degrading to plain TCP / making sing-box refuse the whole config. - **Startup ordering:** `mtproto-proxy` is ordered `After=`/`Wants=` the egress unit (drop-in) so `sbx0` and its route exist before the proxy marks DC sockets on reboot. - **Quiet, verified uninstall:** uninstall no longer spews expected-failure noise (`stop`/`flush`/`netns del` of absent components) over the spinner; installer-e2e gained an uninstall check — which immediately caught a **real bug**: the `mtproto-mask-health.service` unit was never deleted (a double-`.service` path). ## Verified - **End-to-end egress** (ubuntu:20.04 systemd container, arm64): `setup egress` with a real VLESS-Reality link → `sbx0` up, `table 200 default dev sbx0`, and a `fwmark 200` request (the proxy's `SO_MARK`) egresses with the **server's IP** through the Reality tunnel. - **Failover e2e** (`verify_tunnel_pool_failover`): `awg0` (Telegram probe blocked) + `awg1` (probe ok) → the controller selects `awg1`. - `zig build test`, cross-builds for `x86_64-linux` + `aarch64-linux`, `zig fmt` — green; **installer-e2e across 5 OSes** (debian 11/12, ubuntu 20.04/22.04/24.04), including the new uninstall check. </details> ## Changelog * feat(egress): VPN-link tunnel egress + tunnel-pool failover fix + fronting x25519 helper ([#324](https://github.com/sleep3r/mtproto.zig/pull/324)) ([f8bca07](https://github.com/sleep3r/mtproto.zig/commit/f8bca0756de67a335db97df4d5aaaf48cacf5553))
Related Repositories
lightpanda-io/browser★ 36,853
Lightpanda: the headless browser designed for AI and automation
tigerbeetle/tigerbeetle★ 17,229
The financial transactions database designed for mission critical safety and performance.
nullclaw/nullclaw★ 8,131
Fastest, smallest, and fully autonomous AI assistant infrastructure written in Zig
zml/zml★ 4,194
Any model. Any hardware. Zero compromise. Built with @ziglang / @openxla / MLIR / @bazelbuild
dmtrKovalenko/odiff★ 3,280
A very fast SIMD-first image comparison library (with nodejs API)