11 KiB
Архитектура PrivStack / RKNnoVPN
Назначение
PrivStack - прозрачный прокси-стек для rooted Android. Цель проекта: маршрутизировать трафик выбранных приложений через прокси без Android VpnService, TUN-интерфейса и системной VPN-индикации.
Система состоит из двух частей:
- Magisk/KernelSU/APatch-модуль с root-демоном
privd, CLIprivctl, скриптами iptables и бинарникомsing-box. - Android APK без сетевых разрешений, который управляет демоном через
su -c privctl.
Основной поток трафика
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. - Не давать APK разрешение
INTERNET. - Не полагаться на 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:
tproxyinbound;- 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
- Magisk/KSU/APatch запускает
post-fs-data.sh. - Скрипт создаёт каталоги, проверяет права, настраивает sysctl.
- На
late_start serviceзапускаетсяservice.sh. service.shждёт boot completed и стартуетprivd.privdподнимает Unix socket.- APK подключается через
privctl. - При команде
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
Логика:
- Считать
panel.nodes. - Преобразовать каждый node в
NodeProfile. - Сгенерировать отдельный outbound tag для каждого node.
- Если node один, tag
proxyуказывает прямо на него. - Если nodes несколько, создаётся
urltestoutbound с tagproxy. - Route
finalуказывает наproxy. - 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
Главный режим перехвата:
OUTPUTmangle помечает локальный трафик выбранных UID;PREROUTINGmangle отправляет отмеченный трафик в 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; - слушает ли
tproxyport; - применены ли 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
Для этого нужно:
- Хранить mapping
package -> outboundTagилиpackage -> group. - Рендерить несколько
urltest/selectoroutbounds. - Добавить route rules по UID.
- Расширить UI приложений: выбор группы/сервера для приложения.
- Добавить массовые тесты и сортировку по 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 правами.
- Ошибки запуска должны логироваться, а не скрываться за таймаутами.