RKNnoVPN/PRIVSTACK_ARCHITECTURE.md
2026-04-23 18:18:19 +03:00

12 KiB
Raw Permalink Blame History

Архитектура PrivStack / RKNnoVPN

Назначение

PrivStack - прозрачный прокси-стек для rooted Android. Цель проекта: маршрутизировать трафик выбранных приложений через прокси без Android VpnService, TUN-интерфейса и системной VPN-индикации.

Система состоит из двух частей:

  1. Magisk/KernelSU/APatch-модуль с root-демоном privd, CLI privctl, скриптами iptables и бинарником sing-box.
  2. Android APK, который управляет демоном через su -c privctl и в v2 использует сеть только для control-plane операций, не зависящих от rooted data-plane.

Основной поток трафика

Android app
  -> iptables mangle OUTPUT / PREROUTING
  -> fwmark
  -> policy route table
  -> local TPROXY socket
  -> sing-box tproxy inbound
  -> urltest/selector/outbound
  -> upstream proxy

В текущей реализации маршрут по умолчанию внутри sing-box указывает на outbound proxy. Если сохранён один node, proxy является прямым outbound этого node. Если nodes несколько, proxy становится urltest outbound, который выбирает один из node-outbounds.

Главные принципы

  • Не использовать Android VPN API.
  • Не создавать tun0.
  • В v2 разрешить APK INTERNET только для control-plane трафика, не зависящего от rooted data-plane.
  • Не полагаться на Xposed/хуки как основную защиту.
  • Всё сетевое состояние держать в root-слое.
  • Любая ошибка запуска core должна быть диагностируема через sing-box.log.
  • Конфиг должен быть машинно-валидируемым JSON, а не shell-sourced ini.

Компоненты

APK Controller

Пакет: com.privstack.panel

Задачи:

  • отображать статус подключения;
  • импортировать nodes;
  • управлять списком приложений;
  • запускать проверки;
  • показывать аудит;
  • вызывать privctl через su.

APK намеренно не имеет:

  • INTERNET;
  • ACCESS_NETWORK_STATE;
  • VpnService;
  • VPN permissions.

privctl

CLI-клиент, который:

  • формирует JSON-RPC запрос;
  • подключается к Unix socket /data/adb/privstack/run/daemon.sock;
  • печатает JSON-ответ;
  • используется APK и пользователем из Termux/root shell.

Примеры:

su -c '/data/adb/privstack/bin/privctl status'
su -c '/data/adb/privstack/bin/privctl start'
su -c '/data/adb/privstack/bin/privctl node-test'

privd

Root-демон. Основные обязанности:

  • хранить и валидировать /data/adb/privstack/config/config.json;
  • принимать JSON-RPC команды;
  • рендерить конфиг sing-box;
  • запускать и останавливать sing-box;
  • применять iptables/DNS/routing scripts;
  • выполнять health checks;
  • возвращать audit findings;
  • скачивать подписки и обновления, потому что APK не имеет сети.

sing-box

Транспортный core:

  • tproxy inbound;
  • outbounds для VLESS/Trojan/VMess/Shadowsocks/SOCKS/Hysteria2/TUIC;
  • urltest для выбора быстрого outbound;
  • Clash API для delay-тестов;
  • WireGuard build tag включён для будущей поддержки WireGuard outbound.

Сборка статическая. Workflow проверяет, что бинарник не требует системный dynamic loader.

Каталоги

Module directory

/data/adb/modules/privstack/
  module.prop
  customize.sh
  post-fs-data.sh
  service.sh
  uninstall.sh
  sepolicy.rule
  scripts/
    iptables.sh
    dns.sh
    routing.sh
    net_handler.sh
  defaults/
    config.json

Runtime data directory

/data/adb/privstack/
  bin/
    privd
    privctl
    sing-box
  config/
    config.json
    config.defaults.json
    rendered/
      singbox.json
  logs/
    privd.log
    sing-box.log
  run/
    daemon.sock
    privd.pid
    singbox.pid
  profiles/
  backup/

Boot sequence

  1. Magisk/KSU/APatch запускает post-fs-data.sh.
  2. Скрипт создаёт каталоги, проверяет права, настраивает sysctl.
  3. На late_start service запускается service.sh.
  4. service.sh ждёт boot completed и стартует privd.
  5. privd поднимает Unix socket.
  6. APK подключается через privctl.
  7. При команде start демон рендерит singbox.json, запускает sing-box, ждёт порт 10853, применяет iptables и DNS.

Если sing-box завершается до открытия порта, privd возвращает ошибку с хвостом /data/adb/privstack/logs/sing-box.log.

Конфигурация

Основной файл:

/data/adb/privstack/config/config.json

Ключевые секции:

  • proxy - порты, GID core, fwmark;
  • node - legacy/active node;
  • panel - APK-facing состояние, включая список nodes;
  • routing - routing mode и domain/IP rules;
  • apps - package whitelist/blacklist;
  • dns - remote/direct DNS;
  • health - URL проверки и интервалы;
  • rescue - политика восстановления;
  • autostart.

Nodes

APK хранит полный список nodes в panel.nodes. Каждый node содержит:

  • id;
  • name;
  • protocol;
  • server;
  • port;
  • link;
  • outbound;
  • group;
  • latency/response test metadata.

outbound хранится в xray-like форме на стороне APK, а renderer демона переводит его в sing-box outbound.

Renderer sing-box

Renderer находится в:

daemon/internal/config/renderer.go

Логика:

  1. Считать panel.nodes.
  2. Преобразовать каждый node в NodeProfile.
  3. Сгенерировать отдельный outbound tag для каждого node.
  4. Если node один, tag proxy указывает прямо на него.
  5. Если nodes несколько, создаётся urltest outbound с tag proxy.
  6. Route final указывает на proxy.
  7. DNS-секция генерируется в новом формате sing-box 1.12+.

Пример концепции:

{
  "outbounds": [
    { "type": "vless", "tag": "node-a", "...": "..." },
    { "type": "trojan", "tag": "node-b", "...": "..." },
    {
      "type": "urltest",
      "tag": "proxy",
      "outbounds": ["node-a", "node-b"],
      "url": "https://www.gstatic.com/generate_204"
    },
    { "type": "direct", "tag": "direct" }
  ],
  "route": {
    "final": "proxy"
  }
}

iptables / routing

Главный режим перехвата:

  • OUTPUT mangle помечает локальный трафик выбранных UID;
  • PREROUTING mangle отправляет отмеченный трафик в TPROXY;
  • policy routing доставляет отмеченные пакеты на local socket;
  • loop-prevention делается через GID 23333, чтобы трафик самого sing-box не зацикливался.

IPv4 и IPv6 должны быть зеркальны. ICMP/ICMPv6 не проксируются через TPROXY и должны идти напрямую.

DNS

DNS работает через sing-box DNS и локальный inbound:

  • classic DNS перехватывается на порт 10856;
  • sing-box резолвит remote/direct DNS;
  • legacy DNS server format не используется;
  • independent_cache, address, address_resolver не должны генерироваться.

Новый DNS format обязателен для sing-box 1.12+ и будущего 1.14.

Health и audit

Health проверяет:

  • жив ли sing-box;
  • слушает ли tproxy port;
  • применены ли iptables/routing rules;
  • работает ли DNS;
  • нет ли критичных ошибок core.

Audit превращает health и config состояние в findings, пригодные для UI.

Node tests

Команда:

privctl node-test

Возвращает:

  • TCP connect time до server:port;
  • URL delay через конкретный outbound tag через Clash API;
  • ошибки TCP/URL.

Зачем две метрики:

  • TCP connect показывает доступность endpoint.
  • URL delay показывает реальную отзывчивость через профиль.

Для белых списков второго типа важен именно URL delay / response duration. Ping может быть низким, но реальный трафик может душиться ограничением скорости.

Текущие ограничения

  • Per-app multi-proxy ещё не завершён: сейчас все выбранные приложения идут через общий proxy/urltest.
  • Раздача/VPN sharing пока не реализована.
  • WireGuard build tag включён, но import/render WireGuard профилей ещё нужно добавить.
  • AmneziaWG требует отдельной проверки runtime/core.
  • Speed-throttle probe пока не реализован как отдельный mini-download test.

Планируемая multi-proxy архитектура

Целевой вариант:

package uid A -> outbound group A / urltest A
package uid B -> outbound group B / urltest B
package uid C -> direct

Для этого нужно:

  1. Хранить mapping package -> outboundTag или package -> group.
  2. Рендерить несколько urltest/selector outbounds.
  3. Добавить route rules по UID.
  4. Расширить UI приложений: выбор группы/сервера для приложения.
  5. Добавить массовые тесты и сортировку по TCP/URL/response metrics.

Сборка

sing-box резолвится из последнего GitHub release и собирается статически.

Активные build tags:

with_quic,with_wireguard,with_utls,with_clash_api,badlinkname,tfogo_checklinkname0

Не включены без необходимости:

  • with_gvisor;
  • with_dhcp.

Это уменьшает размер бинарника, но сохраняет нужные текущие и ближайшие протоколы.

Безопасность

  • APK без сети.
  • API sing-box должен быть доступен только локально/root-контролю.
  • iptables защищает API-порт от non-root.
  • Конфиги с credential хранятся с root-only правами.
  • Ошибки запуска должны логироваться, а не скрываться за таймаутами.