Kotlin + Jetpack Compose VPN proxy client (Shadowsocks AEAD SIP004, SOCKS5 RFC1928/1929, HTTP/HTTPS CONNECT) with per-app whitelist via VpnService and the vendored hev-socks5-tunnel engine (JNI). Includes the post-review fixes to the connection lifecycle, reconnect teardown, journal, app-filter auto-reconnect, and the tab/timeline layout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
5 KiB
Markdown
75 lines
5 KiB
Markdown
# vojo proxy
|
||
|
||
Нативный Android-клиент для прокси: **Shadowsocks**, **SOCKS5**, **HTTP**, **HTTPS**.
|
||
Per-app whitelist, минимальный расход батареи, маленький размер (release APK ≈ 2.4 МБ).
|
||
Дизайн — в стиле мессенджера vojo (Dawn/Fleet: тёмные поверхности, hairline-границы,
|
||
один фиолетовый акцент, monospace для технических данных).
|
||
|
||
## Стек
|
||
|
||
- **Kotlin + Jetpack Compose + Material3**, Coroutines, DataStore, kotlinx.serialization.
|
||
- **VpnService** для создания tun-интерфейса и per-app whitelist (`addAllowedApplication`).
|
||
- **tun2socks**: нативный движок [`hev-socks5-tunnel`](https://github.com/heiher/hev-socks5-tunnel)
|
||
(C, event-loop, ~320 КБ) — самый экономичный по CPU/батарее способ конвертировать
|
||
IP-пакеты из tun в потоки.
|
||
- minSdk 28, targetSdk 35, только `arm64-v8a` (Samsung S23).
|
||
|
||
## Архитектура потока данных
|
||
|
||
```
|
||
Выбранные приложения
|
||
│ (per-app whitelist через VpnService.addAllowedApplication)
|
||
▼
|
||
tun-интерфейс ──fd──► hev-socks5-tunnel (нативный, JNI)
|
||
│ говорит SOCKS5 на 127.0.0.1:<port>
|
||
▼
|
||
LocalSocks5Server (Kotlin, loopback)
|
||
│ мост на нужный апстрим
|
||
┌─────────────────────┼─────────────────────┬───────────────┐
|
||
▼ ▼ ▼ ▼
|
||
Shadowsocks SOCKS5 HTTP CONNECT HTTPS CONNECT
|
||
(AEAD SIP004) (RFC 1928/1929) (RFC 7231) (TLS + CONNECT)
|
||
```
|
||
|
||
- **TCP** проксируется для всех 4 протоколов. Цель приходит уже как IP/домен в SOCKS5-форме.
|
||
- **UDP/DNS**: `hev` отдаёт UDP через SOCKS5 UDP ASSOCIATE. Для SS/SOCKS5 — полноценный
|
||
UDP-релей; для HTTP/HTTPS (UDP не поддерживается протоколом) — DNS-over-TCP fallback (порт 53).
|
||
- Все апстрим-сокеты защищены `VpnService.protect()`, чтобы не зацикливаться обратно в tun.
|
||
|
||
## Ключевые модули
|
||
|
||
| Путь | Назначение |
|
||
|------|-----------|
|
||
| `core/Tun2Socks.kt`, `jni/tun2socks.c` | JNI-мост к нативному движку |
|
||
| `core/crypto/ShadowsocksCrypto.kt`, `ShadowsocksStream.kt` | AEAD (HKDF-SHA1, AES-GCM, ChaCha20-Poly1305), TCP-framing, UDP seal/open |
|
||
| `core/socks/LocalSocks5Server.kt` | Локальный SOCKS5-сервер: CONNECT + UDP ASSOCIATE |
|
||
| `core/upstream/*` | Апстримы SS / SOCKS5 / HTTP(S) |
|
||
| `service/ProxyVpnService.kt` | VpnService, whitelist, foreground-уведомление, статистика, журнал событий |
|
||
| `service/ProxyTileService.kt` | Тайл быстрых настроек (вкл/выкл из шторки) |
|
||
| `data/ConfigStore.kt`, `AppRepository.kt` | Персист конфигов (DataStore) и список приложений |
|
||
| `core/ConfigImport.kt` | Импорт ссылок `ss://` (SIP002/legacy), `socks5://`, `http(s)://` |
|
||
| `ui/*` | Compose-экраны: Туннель (журнал событий на timeline rail), Серверы, Приложения, Опции |
|
||
|
||
## Сборка
|
||
|
||
```bash
|
||
./gradlew :app:assembleRelease # → app/build/outputs/apk/release/app-release.apk (~2.4 МБ)
|
||
./gradlew :app:assembleDebug
|
||
```
|
||
|
||
Требуется Android SDK (platform-35, build-tools 35), NDK 27.2.x. Путь к SDK — в `local.properties`.
|
||
|
||
## Оптимизация батареи
|
||
|
||
- Нативный event-loop tun2socks вместо userspace TCP/IP-стека на JVM (нет GC-давления на пакет).
|
||
- Блокирующий I/O на эластичном пуле потоков — простаивающие соединения паркуют поток (0% CPU).
|
||
- `setUnderlyingNetworks` + отслеживание смены сети, `setMetered(false)`.
|
||
- Низкоприоритетное foreground-уведомление, поллинг статистики раз в 2 с (без wakelock).
|
||
- Секундный тикер UI работает только при CONNECTED и только пока активити RESUMED.
|
||
|
||
## Безопасность / ограничения
|
||
|
||
- Не реализованы VLESS/Reality (намеренно).
|
||
- Shadowsocks: AEAD-шифры (`aes-128-gcm`, `aes-256-gcm`, `chacha20-ietf-poly1305`).
|
||
Legacy stream-шифры и SS-2022 не поддерживаются.
|
||
- HTTP/HTTPS-прокси не могут передавать UDP — для них работает только DNS-over-TCP.
|