Если вы пользовались моим LxBox или десктопным лаунчером, то могли натыкаться на оранжевый баннер: «с этим узлом, скорее всего, не соединится». Так клиент честно сознаётся, что наткнулся на узел с транспортом XHTTP, а ядро sing-box, на котором всё крутится, его не умеет. В этот момент лаунчер тихо даунгрейдит конфиг до HTTPUpgrade.
А еще сразу как я выпустил приложение пришли запросы с AWG/AWG2 и такие: сделай! а я сюда
В какой-то момент я устал ждать и собрал свой форк ядра — sing-box-lx. Сегодня расскажу, зачем он понадобился, что внутри, и почему главное в нём — не сами фичи, а то, как он сделан.
Сначала — кто на ком стоит
Чтобы было понятно, напомню конструкцию. Лаунчер (и десктопный, и LxBox) — это GUI-оркестратор: он собирает конфиг и рулит маршрутизацией. А всю сетевую работу делает ядро sing-box — по сути швейцарский нож сетевой маршрутизации. Я всегда делал к этому ножу удобную ручку. Ну лааадно, еще и вилку приделал и ложку… ну особенно на Андройде там..
singbox-launcher / LxBox (GUI, ручка) ↓ генерация конфига sing-box (ядро, нож) ← вот тут не хватало пары лезвий ↓ TUN / трафик
Проблема в том, что у ножа не хватало ровно двух лезвий. Причём именно тех, что нужны, когда обычный туннель уже не проходит. Я уже и sing-box связал в одну связку с ByeByeDPI, но все равно не хватало..
Чего не хватало — и почему именно этого
1. XHTTP — клиентский транспорт из мира Xray. Если совсем просто: он заворачивает трафик в обычные на вид HTTP-запросы, и со стороны DPI это выглядит как банальный веб-сёрфинг, а не «подозрительный туннель». У upstream sing-box клиентской поддержки XHTTP нет — поэтому лаунчер и вынужден был даунгрейдить такие узлы.
2. AmneziaWG 2.0 — обфусцированный WireGuard. Объясняю максимально просто: у обычного WireGuard рукопожатие имеет узнаваемую сигнатуру, и DPI её прекрасно режет. AmneziaWG подмешивает «мусорные» пакеты и магические заголовки (параметры Jc, S1–S4, H1–H4, I1–I5), и сигнатура ломается — туннель перестаёт выглядеть как WireGuard. В sing-box есть обычный wireguard, но обфускации AmneziaWG как клиентского endpoint — нет.
Обе фичи про одно: пройти там, где обычный туннель уже завернули. Это вся их суть.
Ну не с нуля же делать фичи?
Конечно нет. Писать сетевое ядро с нуля это просто не реально, да и фичи без рефренсов — это тонны работы и грабли на каждом шагу, а sing-box уже мощный, живой и активно развивается. Как мы обычно делаем? — форкнуть и допилить.
Вот только форки обычно гниют. Знакомая история: кто-то форкает крупный проект, добавляет пару своих хотелок, а через полгода апстрим уехал вперёд, смержиться уже невозможно, и форк превращается в заброшенную поделку с дырами в безопасности. Так вот и получается что все ядра что вы можете найти или перегнили или опухли или просто уродливы…
Я не хотел использовать форк. И вот тут начинается главная мысль, ради которой и затевалась статья.
Кардинальное отличие: форк — это набор патчей, а не новый проект
Я с самого начала строил sing-box-lx так, чтобы он не мог сгнить. Три правила:
Минимальное касание апстрима. Почти весь мой код — это новые файлы: Makefile.lx, воркфлоу .github/workflows/lx-*.yml, тестовые конфиги в lx-test/. Единственная правка апстрим-файла — один помеченный блок // lx в сборщике Android-библиотеки. Всё. Если завтра выйдет новый sing-box, мне почти нечего переносить руками.
Автоматический ребейз на апстрим. Раз в неделю CI сам берёт новейший стабильный тег upstream и пытается перенести на него мои коммиты:
свежий стабильный тег sing-box ↓ CI ребейзит мои патчи ↓ ┌─ чисто + собралось + прошло check → открыть PR ├─ конфликт → завести issue с точным списком // lx-швов └─ уже актуально → ничего не делаем
Важная деталь: воркфлоу никогда не делает force-push в мою основную ветку. Он лишь готовит ветку и зовёт меня глазами посмотреть. То есть машина делает скучную работу, а решение остаётся за человеком.
Воспроизводимые сборки. Как и в лаунчере, мой принцип: опубликованный релиз обязан соответствовать открытому коду. Все бинарники собираются только через GitHub CI/CD — никаких «я тут локально собрал, доверяйте».
Что я выкинул — это тоже фича
sing-box умеет кучу всего, в том числе серверные и совсем экзотические вещи. Мне в клиенте они не нужны, поэтому набор тегов сборки я осознанно урезал до клиентского: убрал серверную выдачу сертификатов (acme), tailscale и AI-прокси-модули. А добавил ровно три вещи — with_xhttp, with_awg и with_purego (последний — чтобы naive/cronet кросс-собирались без CGO).
Чтобы ничего не разъезжалось, строка тегов живёт в одном месте — Makefile.lx, и CI с релизом берут её оттуда же. Никакого копипаста тегов по десяти местам:
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_clash_api,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0,with_xhttp,with_awg
Собрал — проверил живьём
Я не верю в «скомпилировалось — значит работает», поэтому обе фичи гонял против реальных серверов, ой и спасибо тестерам, которые это гоняют со мной, господи, благослави энтузиастов OS:
-
XHTTP — против Xray (3x-ui). Режимы packet-up/auto работают: рукопожатие, DNS, HTTPS, скачивание файлов. Режим stream-one пока с известным багом по фреймингу — чиню, но это не блокер.
-
AmneziaWG 2.0 — против живого AWG2-сервера: рукопожатие, keepalive, реальный трафик. Обфускация на месте.
Итог собран в релиз v1.13.13-lx.3: 6 десктопных бинарников (linux/macOS/windows × amd64/arm64), две AAR-библиотеки (libbox для Android — да, та самая, что внутри LxBox) и SHA256SUMS. Всё зелёное в CI.
sing-box-lx ├─ desktop ×6 → singbox-launcher └─ libbox.aar → LxBox (Android)
То есть одно ядро готово кормить сразу оба моих клиента — и десктоп, и мобилку. Осталось подружить их по-настоящему: научить лаунчер собирать честный XHTTP вместо даунгрейда — и тот самый оранжевый баннер можно будет наконец убрать. Но это уже следующая история.
Чуть-чуть про дисциплину
Как и в лаунчере, тут всё ведётся через спеки: что и зачем меняется, какая зона касается апстрима, как закрывается задача. Для тонкого форка это критично — когда придёт время ребейза, я по маркерам // lx за минуту вижу все свои швы, а не вспоминаю «где я там что трогал полгода назад».
Забрать и потрогать
Репозиторий: https://github.com/Leadaxe/sing-box-lx — там релизы, теги сборки, воркфлоу CI/ребейза и тестовые конфиги XHTTP/AWG2.
Отдельная уважуха апстриму — SagerNet/sing-box за прекрасное ядро, команде Xray за XHTTP и Amnezia за идею обфускации WireGuard, ну понятно из этих небожителей никто не прочитает.
Ну а мне приятно их поблагодарить.
Если у вас есть сценарии, где XHTTP или AmneziaWG ведут себя не так, как ожидалось, — заводите issue, это ценнее любой новой фичи. Ну а если зашло — вы знаете: звёздочка ⭐, форк ↑↓ и, если совсем хорошо, pull request </>.
Всем, кто дочитал, — спасибо. Мне правда приятно делать штуки, которые вам заходят.
ссылка на оригинал статьи https://habr.com/ru/articles/1045706/