4 Commits

Author SHA1 Message Date
4b0eee3eb5 Release PronBox v1.12.0 from NIH TechnoPron.
Rename Magisk branding to PronBox (author: TechnoPron team), stop customize.sh from forcing Box for Magisk, and ship wg-obfuscator plus Manage Profiles templates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 09:09:32 +03:00
7298a36e38 Обновить README.md 2026-08-13 08:56:47 +03:00
89d0adb27c Release VeilBox v1.11.0: switchable TrustTunnel/olcrtc profiles.
Rename display name to VeilBox, add box.profile + sbfr p switcher, and ship scrubbed sing-box profile templates for quick TT/olcrtc flips.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 20:34:21 +03:00
62f2414c12 docs: add Gitea release and push instructions
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 15:13:31 +03:00
80 changed files with 3774 additions and 188 deletions

12
.gitignore vendored
View File

@@ -3,3 +3,15 @@
docs/
build.sh
*.zip
*.lf
*.tar.gz
tools/binaries/
tools/src/
tools/apks/
phone_*/
phone_backup*/
*.toml
!box/sidecar/*.example.toml
__pycache__/
*.pyc

View File

@@ -1,18 +1,23 @@
# BFR Stealth Mod — v1.10.2-stealth.1
# PronBox — v1.12.0
Разработано в стенах **НИИ «ТехноПрон»**. Magisk `id` остаётся `box_for_root` (апгрейд поверх старого модуля).
## Renamed
- Display name: **PronBox** (больше не VeilBox / «Box for Magisk»)
- Author: **команда НИИ «ТехноПрон»**
- ZIP: `pronbox-v1.12.0.zip`
- Fix: `customize.sh` больше не переименовывает модуль в stock «Box for Magisk»
## Added
- **Stealth layer** (`box.stealth`): iptables port-hide for observer apps without LSPosed
- **Sidecar support** (`box.sidecar`): olcrtc and TrustTunnel via local SOCKS5 chain
- Auto-hardening: REST API disable, TUN forbid, optional QUIC block
- `upsidercar` command in `box.tool` for TrustTunnel client download
- Example configs: `config.stealth.example.json`, `olcrtc.example.yaml`, `trusttunnel.example.toml`
- `stealth.list.cfg` for bank/checker package UID blocking
- **wg-obfuscator** ([ClusterM](https://github.com/ClusterM/wg-obfuscator)): `box.wgobfs`, профиль `config-wg-obfs.json`, `box.tool upwgobfs`
- Manage Profiles: `config-trusttunnel` / `config-olcrtc` / `config-wg-obfs`
- Sidecar `both` + `sidecar_set_final=false` для переключения в BFR Manager
- Restore при апгрейде: `trusttunnel_client`, `olcrtc`, `wg-obfuscator`, sidecar configs
## Changed
- Default core: **sing-box** (was clash)
- Default stealth settings enabled in `settings.ini`
- Module name: **BFR Stealth Mod**
- Full README rewrite
## Notes
- wg-obfuscator нужен и на VPS (тот же `key`)
- Repo-шаблоны без секретов WG/Hysteria
## Based on
- PronBox / VeilBox v1.11.0
- [taamarin/box_for_magisk](https://github.com/taamarin/box_for_magisk) v1.10.2

130
README.md
View File

@@ -1,8 +1,9 @@
# BFR Stealth Mod
# PronBox
Форк [box_for_magisk](https://github.com/taamarin/box_for_magisk) — прозрачный прокси для Android (root) с **anti-detection hardening без LSPosed** и поддержкой **sidecar-протоколов** [olcrtc](https://github.com/openlibrecommunity/olcrtc) / [TrustTunnel](https://github.com/TrustTunnel/TrustTunnel).
Форк [box_for_magisk](https://github.com/taamarin/box_for_magisk) — прозрачный прокси для Android (root).
Собрано в стенах **НИИ «ТехноПрон»**. Отображаемое имя в Magisk: **PronBox**; module id: `box_for_root` (апгрейд совместим).
Работает через Magisk, KernelSU и APatch. Ядра: `sing-box` (по умолчанию), `clash`, `xray`, `v2ray`, `hysteria`.
Работает через Magisk, KernelSU и APatch. Ядро по умолчанию: **sing-box**. Anti-detection без LSPosed + sidecar: [olcrtc](https://github.com/openlibrecommunity/olcrtc) / [TrustTunnel](https://github.com/TrustTunnel/TrustTunnel) / [wg-obfuscator](https://github.com/ClusterM/wg-obfuscator).
---
@@ -10,24 +11,27 @@
Stock [Box for Root](https://github.com/taamarin/box_for_magisk) хорошо проксирует трафик через TPROXY, но:
1. **Не поддерживает** новые протоколы вроде olcrtc и TrustTunnel «из коробки».
1. **Не поддерживает** новые протоколы вроде olcrtc, TrustTunnel и WG-obfuscation «из коробки».
2. **Легко детектится** проверщиками вроде [RKNHardering](https://github.com/xtclovver/RKNHardering): REST API на `9090`, скан localhost, TUN-интерфейсы.
BFR Stealth Mod решает обе проблемы **без LSPosed** через iptables port-hide, hardening конфигов и sidecar-цепочку.
PronBox решает это **без LSPosed** — iptables port-hide, hardening конфигов и sidecar-цепочка. Разработано командой НИИ «ТехноПрон».
---
## Отличия от stock BFR
| Функция | Stock BFR | BFR Stealth Mod |
|---------|-----------|-----------------|
| Функция | Stock BFR | PronBox |
|---------|-----------|---------|
| Ядро по умолчанию | clash | **sing-box** |
| Режим сети | tproxy | **tproxy** (TUN блокируется) |
| REST API (9090) | `0.0.0.0` | **отключён** или только `127.0.0.1` |
| TUN mode | доступен | **запрещён** (`stealth_forbid_tun`) |
| Localhost scan | не защищён | **iptables port-hide** для observer apps |
| olcrtc / TrustTunnel | нет | **sidecar → SOCKS → sing-box** |
| WG obfuscator | нет | **wg-obfuscator → WireGuard** |
| Быстрый профиль | — | **Manage Profiles / `sbfr p …`** |
| LSPosed / VPN Hide | — | **не требуется** |
| Автор | — | **команда НИИ «ТехноПрон»** |
---
@@ -82,43 +86,65 @@ Observer app (банк, RKNHardering)
### Из релиза
1. Скачайте `box_for_root-v*.zip` из [Releases](../../releases).
1. Скачайте `pronbox-v*.zip` из [Releases](../../releases).
2. Magisk / KernelSU / APatch → **Modules** → Install from storage.
3. При установке выберите загрузку **sing-box** (Vol+).
4. Перезагрузите устройство.
### Сборка из исходников
**Windows / любая ОС (рекомендуется):**
```powershell
python tools/build_zip.py
# → pronbox-v1.12.0.zip
```
**Linux / Git Bash:**
```bash
sh build.sh
# → box_for_root-v1.10.2-stealth.1.zip
```
**Windows (PowerShell):**
```powershell
$v = (Get-Content module.prop | Where-Object { $_ -match '^version=' }) -replace 'version=',''
Compress-Archive -Path (Get-ChildItem . -Force | Where-Object { $_.Name -notin '.git','.github','docs','CHANGELOG.md','update.json','build.sh' }) -DestinationPath "box_for_root-$v.zip" -Force
```
---
## Быстрый старт
> Перед правкой конфигов **остановите** сервис BFR.
> Перед правкой конфигов **остановите** сервис PronBox.
### 1. Конфиг sing-box
### 1. Профили TrustTunnel / olcrtc (быстрое переключение)
Скопируйте шаблон и настройте outbound:
В модуле лежат два готовых шаблона:
| Профиль | Файл | SOCKS | `route.final` |
|---------|------|-------|---------------|
| TrustTunnel | `config.trusttunnel.json` | `:10800` | `sidecar-proxy` |
| olcrtc | `config.olcrtc.json` | `:10801` | `olcrtc-proxy` |
Подставьте свои пароли/ключи (шаблоны в репозитории scrubbed) или на устройстве:
```bash
# клонировать текущий рабочий конфиг в оба профиля
su -c '/data/adb/box/scripts/box.profile seed'
# переключение (меняет name_sing_config + sidecar_* и рестартит сервис)
sbfr p use trusttunnel
sbfr p use olcrtc
sbfr p status
```
В Magisk/терминале то же самое: `su -c '/data/adb/box/scripts/box.profile use olcrtc'`.
### 2. Конфиг sing-box (с нуля)
Скопируйте минимальный шаблон и настройте outbound:
```bash
cp /data/adb/box/sing-box/config.stealth.example.json /data/adb/box/sing-box/config.json
# добавьте свой VLESS / другой outbound
```
### 2. Observer-приложения (stealth)
### 3. Observer-приложения (stealth)
Файл `/data/adb/box/stealth.list.cfg` — приложения, которым **скрываем** localhost-прокси:
@@ -130,7 +156,7 @@ ru.rostel
com.notcvnt.rknhardering
```
### 3. Blacklist для checker'а
### 4. Blacklist для checker'а
Чтобы RKNHardering **не шёл через прокси**, добавьте в `/data/adb/box/package.list.cfg`:
@@ -139,7 +165,7 @@ mode:blacklist
com.notcvnt.rknhardering
```
### 4. Запуск
### 5. Запуск
```bash
su -c /data/adb/box/scripts/box.service start
@@ -238,10 +264,53 @@ cp /data/adb/box/sidecar/olcrtc.example.yaml /data/adb/box/sidecar/olcrtc.yaml
```ini
sidecar_enable="true"
sidecar_protocol="olcrtc"
sidecar_listen_port="10800"
sidecar_listen_port="10801"
sidecar_outbound_tag="olcrtc-proxy"
```
> **Важно:** порт в sidecar-конфиге (`socks.port` / listener) должен совпадать с `sidecar_listen_port`.
> **Важно:** порт в sidecar-конфиге (`socks.port`) должен совпадать с `sidecar_listen_port` (TT `:10800`, olcrtc `:10801`).
> Для olcrtc в `olcrtc.yaml` задайте LAN DNS: `net.dns: "192.168.0.1:53"` (публичные DNS через PreferGo от root часто виснут).
---
## WireGuard Obfuscator ([ClusterM/wg-obfuscator](https://github.com/ClusterM/wg-obfuscator))
Это **не VPN**, а UDP-обфускатор WireGuard (маскировка под STUN и т.п.). Нужен **на обоих концах** — телефон + VPS с тем же `key`. Со сторонним WG-сервером без своего obfuscator не заработает.
```text
sing-box WireGuard peer
→ 127.0.0.1:41320
→ wg-obfuscator (client)
→ VPS:public_udp
→ wg-obfuscator (server)
→ WireGuard на VPS
```
### Клиент (Android / PronBox)
```bash
su -c /data/adb/box/scripts/box.tool upwgobfs
cp /data/adb/box/sidecar/wg-obfuscator.example.conf /data/adb/box/sidecar/wg-obfuscator.conf
# key=... target=VPS_IP:PORT (порт публичного obfuscator на сервере)
```
В `settings.ini`:
```ini
wgobfs_enable="true"
wgobfs_listen_port="41320"
wgobfs_patch_config="true"
```
Или профиль в **Manage Profiles**: `config-wg-obfs.json` (авто-старт wgobfs).
### Сервер (VPS)
См. `box/sidecar/wg-obfuscator.server.example.conf`:
1. Сдвинуть WireGuard `ListenPort` (например на `51820`).
2. Поставить `wg-obfuscator` на старый публичный порт (`13232`).
3. `target = 127.0.0.1:51820`, тот же `key`, `masking = AUTO`.
---
@@ -252,12 +321,15 @@ sidecar_listen_port="10800"
| `/data/adb/box/settings.ini` | Главный конфиг |
| `/data/adb/box/stealth.list.cfg` | Observer apps для port-hide |
| `/data/adb/box/package.list.cfg` | Blacklist/whitelist приложений |
| `/data/adb/box/sing-box/config.json` | Конфиг sing-box |
| `/data/adb/box/sing-box/config.trusttunnel.json` | Профиль TrustTunnel |
| `/data/adb/box/sing-box/config.olcrtc.json` | Профиль olcrtc |
| `/data/adb/box/sing-box/config.json` | Активный конфиг (или через `name_sing_config`) |
| `/data/adb/box/sidecar/` | Конфиги olcrtc / TrustTunnel |
| `/data/adb/box/bin/` | Бинарники (sing-box, sidecar) |
| `/data/adb/box/run/` | Логи, PID, UID-списки |
| `/data/adb/box/scripts/box.stealth` | Stealth iptables |
| `/data/adb/box/scripts/box.sidecar` | Sidecar lifecycle |
| `/data/adb/box/scripts/box.profile` | Переключение TT / olcrtc |
| `/data/adb/box/scripts/box.service` | Старт/стоп ядра |
| `/data/adb/box/scripts/box.iptables` | TPROXY правила |
@@ -306,6 +378,8 @@ sbfr start # start + iptables
sbfr stop # disable + stop
sbfr s status # статус сервиса
sbfr i enable # iptables
sbfr p use trusttunnel # профиль TT
sbfr p use olcrtc # профиль olcrtc
sbfr t check # box.tool
```
@@ -316,7 +390,7 @@ sbfr t check # box.tool
1. `com.notcvnt.rknhardering``stealth.list.cfg`
2. Тот же package → `package.list.cfg` **blacklist** (checker вне прокси)
3. `stealth_disable_api="true"`, `network_mode="tproxy"`
4. Запустить BFR → запустить RKNHardering
4. Запустить PronBox → запустить RKNHardering
Ожидаемый результат: модули **Bypass Check** (Clash API, localhost proxy) и **Indirect Signs** (TUN) не должны давать hard detect. GeoIP/hosting и root-следы могут остаться.
@@ -326,11 +400,11 @@ sbfr t check # box.tool
```text
Magisk / KernelSU / APatch
└── BFR Stealth Mod
└── PronBox (НИИ «ТехноПрон»)
├── network_mode=tproxy, bin_name=sing-box
├── stealth.list.cfg → банки, маркетплейсы
├── package.list.cfg → whitelist нужных app ИЛИ blacklist checker'ов
└── sidecar (опционально) → olcrtc / TrustTunnel
└── sidecar → TrustTunnel / olcrtc / wg-obfuscator
```
---

33
RELEASE.md Normal file
View File

@@ -0,0 +1,33 @@
# Release PronBox v1.12.0
Продукт **НИИ «ТехноПрон»**. Magisk id: `box_for_root`.
## Локально
- Ветка `main`
- Тег: `v1.12.0`
- ZIP: `pronbox-v1.12.0.zip``python tools/build_zip.py`
- Remote: `gitea@10.2.0.2:M1rs3m/BFR.git`
- Display name: **PronBox**
- Author: **команда НИИ «ТехноПрон»**
## Push + tag
```powershell
cd E:\bfr_mod
git push -u origin main
git push origin v1.12.0
```
## Release на Gitea
1. `http://10.2.0.2/M1rs3m/BFR`**Releases****New Release**
2. Tag: `v1.12.0`
3. Title: `PronBox v1.12.0 — НИИ «ТехноПрон»`
4. Description: `CHANGELOG_STEALTH.md`
5. Attach: `pronbox-v1.12.0.zip`
6. Publish
OTA (`update.json`):
`http://10.2.0.2/M1rs3m/BFR/releases/download/v1.12.0/pronbox-v1.12.0.zip`

168
box/scripts/box.profile Normal file
View File

@@ -0,0 +1,168 @@
#!/system/bin/sh
# VeilBox profile switcher — trusttunnel | olcrtc
# Usage:
# su -c '/data/adb/box/scripts/box.profile list'
# su -c '/data/adb/box/scripts/box.profile use trusttunnel'
# su -c '/data/adb/box/scripts/box.profile use olcrtc'
# su -c '/data/adb/box/scripts/box.profile status'
if ! /system/bin/sh -n /data/adb/box/settings.ini 2>/dev/null; then
echo "Err: settings.ini syntax error" >&2
exit 1
fi
scripts_dir="${0%/*}"
. /data/adb/box/settings.ini
profiles_dir="${box_dir}/sing-box"
ini=/data/adb/box/settings.ini
profile_apply_settings() {
name="$1"
case "${name}" in
trusttunnel|tt)
sed -i 's/^name_sing_config=.*/name_sing_config="config-trusttunnel.json"/' "${ini}"
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' "${ini}"
# both + set_final=false → BFR Manager can also flip without breaking finals
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="both"/' "${ini}"
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10800"/' "${ini}"
sed -i 's/^sidecar_outbound_tag=.*/sidecar_outbound_tag="sidecar-proxy"/' "${ini}"
sed -i 's/^sidecar_set_final=.*/sidecar_set_final="false"/' "${ini}"
echo "trusttunnel"
;;
olcrtc|olc)
sed -i 's/^name_sing_config=.*/name_sing_config="config-olcrtc.json"/' "${ini}"
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' "${ini}"
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="both"/' "${ini}"
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10801"/' "${ini}"
sed -i 's/^sidecar_outbound_tag=.*/sidecar_outbound_tag="sidecar-proxy"/' "${ini}"
sed -i 's/^sidecar_set_final=.*/sidecar_set_final="false"/' "${ini}"
# Prefer LAN DNS for olcrtc PreferGo resolver under root:net_admin
if [ -f "${box_dir}/sidecar/olcrtc.yaml" ] && [ -x "${box_dir}/bin/yq" ]; then
"${box_dir}/bin/yq" -i '.net.dns = "192.168.0.1:53"' "${box_dir}/sidecar/olcrtc.yaml" 2>/dev/null || true
fi
echo "olcrtc"
;;
wg-obfs|wgobfs|wg)
sed -i 's/^name_sing_config=.*/name_sing_config="config-wg-obfs.json"/' "${ini}"
sed -i 's/^wgobfs_enable=.*/wgobfs_enable="true"/' "${ini}"
grep -q '^wgobfs_enable=' "${ini}" || echo 'wgobfs_enable="true"' >> "${ini}"
echo "wg-obfs"
;;
*)
echo "Unknown profile: ${name}" >&2
echo "Available: trusttunnel | olcrtc | wg-obfs" >&2
return 1
;;
esac
}
profile_seed_from_active() {
# If profile json missing, clone current sing config and patch final/dns
src="${sing_config}"
[ -f "${src}" ] || src="${profiles_dir}/config.json"
[ -f "${src}" ] || return 1
yq="${box_dir}/bin/yq"
[ -x "${yq}" ] || return 1
if [ ! -f "${profiles_dir}/config-trusttunnel.json" ]; then
cp -f "${src}" "${profiles_dir}/config-trusttunnel.json"
"${yq}" -i -o=json '
.route.final = "sidecar-proxy" |
(.dns.servers[] | select(.tag == "dns-remote") | .detour) = "sidecar-proxy" |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only"
' "${profiles_dir}/config-trusttunnel.json"
if ! "${yq}" -e '.outbounds[] | select(.tag == "sidecar-proxy")' "${profiles_dir}/config-trusttunnel.json" >/dev/null 2>&1; then
"${yq}" -i -o=json '.outbounds += [{"type":"socks","tag":"sidecar-proxy","server":"127.0.0.1","server_port":10800,"version":"5"}]' "${profiles_dir}/config-trusttunnel.json"
fi
if ! "${yq}" -e '.outbounds[] | select(.tag == "olcrtc-proxy")' "${profiles_dir}/config-trusttunnel.json" >/dev/null 2>&1; then
"${yq}" -i -o=json '.outbounds += [{"type":"socks","tag":"olcrtc-proxy","server":"127.0.0.1","server_port":10801,"version":"5"}]' "${profiles_dir}/config-trusttunnel.json"
fi
log Info "[Profile] seeded config-trusttunnel.json"
fi
if [ ! -f "${profiles_dir}/config-olcrtc.json" ]; then
cp -f "${src}" "${profiles_dir}/config-olcrtc.json"
"${yq}" -i -o=json '
.route.final = "olcrtc-proxy" |
(.dns.servers[] | select(.tag == "dns-remote") | .detour) = "olcrtc-proxy" |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only"
' "${profiles_dir}/config-olcrtc.json"
if ! "${yq}" -e '.outbounds[] | select(.tag == "sidecar-proxy")' "${profiles_dir}/config-olcrtc.json" >/dev/null 2>&1; then
"${yq}" -i -o=json '.outbounds += [{"type":"socks","tag":"sidecar-proxy","server":"127.0.0.1","server_port":10800,"version":"5"}]' "${profiles_dir}/config-olcrtc.json"
fi
if ! "${yq}" -e '.outbounds[] | select(.tag == "olcrtc-proxy")' "${profiles_dir}/config-olcrtc.json" >/dev/null 2>&1; then
"${yq}" -i -o=json '.outbounds += [{"type":"socks","tag":"olcrtc-proxy","server":"127.0.0.1","server_port":10801,"version":"5"}]' "${profiles_dir}/config-olcrtc.json"
fi
log Info "[Profile] seeded config-olcrtc.json"
fi
}
profile_list() {
echo "Profiles (also visible in BFR Manager → Manage Profiles):"
echo " trusttunnel -> config-trusttunnel.json (final=sidecar-proxy :10800)"
echo " olcrtc -> config-olcrtc.json (final=olcrtc-proxy :10801)"
echo " wg-obfs -> config-wg-obfs.json (WG via wg-obfuscator :41320)"
echo " sidecar mode -> both (set_final=false) so app switching keeps finals"
echo " NOTE: wg-obfs needs matching obfuscator on the VPS (same key)"
echo
echo "Files in ${profiles_dir}:"
ls -1 "${profiles_dir}"/config*.json 2>/dev/null
echo
echo "Active:"
grep -E '^name_sing_config=|^sidecar_protocol=|^sidecar_listen_port=|^sidecar_outbound_tag=' "${ini}"
}
profile_status() {
. /data/adb/box/settings.ini
echo "name_sing_config=${name_sing_config}"
echo "sing_config=${sing_config}"
echo "sidecar_protocol=${sidecar_protocol} port=${sidecar_listen_port} tag=${sidecar_outbound_tag}"
if [ -x "${box_dir}/bin/yq" ] && [ -f "${sing_config}" ]; then
echo "route.final=$(${box_dir}/bin/yq -r '.route.final' "${sing_config}")"
fi
echo "tt=$(pidof trusttunnel_client 2>/dev/null)"
echo "olc=$(pidof olcrtc 2>/dev/null)"
echo "sb=$(pidof sing-box 2>/dev/null)"
}
profile_use() {
name="$1"
[ -n "${name}" ] || { echo "usage: $0 use {trusttunnel|olcrtc}"; exit 1; }
profile_seed_from_active || true
applied=$(profile_apply_settings "${name}") || exit 1
# reload settings after sed
. /data/adb/box/settings.ini
if [ ! -f "${sing_config}" ]; then
log Error "[Profile] missing ${sing_config}"
exit 1
fi
log Info "[Profile] switching to ${applied} (${name_sing_config})"
"${scripts_dir}/box.service" restart
sleep 2
"${scripts_dir}/box.iptables" renew >/dev/null 2>&1 || true
profile_status
}
case "$1" in
list)
profile_list
;;
status)
profile_status
;;
use|switch)
profile_use "$2"
;;
seed)
profile_seed_from_active
;;
*)
echo "usage: $0 {list|status|use trusttunnel|use olcrtc|seed}"
exit 1
;;
esac

View File

@@ -486,6 +486,16 @@ box_run_bin() {
;;
sing-box)
prepare_singbox
# Auto-enable WG obfuscator when Manage Profiles picks config-wg-obfs.json
case "${name_sing_config}" in
*wg-obfs*|*wgobfs*)
wgobfs_enable="true"
;;
esac
if [ "${wgobfs_enable}" = "true" ]; then
"${scripts_dir}/box.wgobfs" start || exit 1
prepare_stealth_singbox
fi
if [ "${sidecar_enable}" = "true" ]; then
"${scripts_dir}/box.sidecar" start || exit 1
prepare_stealth_singbox
@@ -818,6 +828,7 @@ start_box() {
stop_box() {
stop_cron
"${scripts_dir}/box.wgobfs" stop >/dev/null 2>&1
"${scripts_dir}/box.sidecar" stop >/dev/null 2>&1
"${scripts_dir}/box.stealth" disable >/dev/null 2>&1
# Kill each binary using a loop

View File

@@ -11,39 +11,32 @@ scripts_dir="${0%/*}"
sidecar_dir="${box_dir}/sidecar"
sidecar_pid="${box_run}/sidecar.pid"
sidecar_pid_olc="${box_run}/sidecar-olcrtc.pid"
sidecar_pid_tt="${box_run}/sidecar-trusttunnel.pid"
sidecar_log="${box_run}/sidecar.log"
sidecar_bin_path() {
case "${sidecar_protocol}" in
olcrtc) echo "${box_dir}/bin/olcrtc" ;;
trusttunnel) echo "${box_dir}/bin/trusttunnel_client" ;;
*) echo "" ;;
esac
}
sidecar_config_path() {
case "${sidecar_protocol}" in
olcrtc) echo "${sidecar_dir}/olcrtc.yaml" ;;
trusttunnel) echo "${sidecar_dir}/trusttunnel.toml" ;;
*) echo "" ;;
esac
}
# Defaults for dual mode
: "${sidecar_tt_port:=10800}"
: "${sidecar_olc_port:=10801}"
: "${sidecar_olc_tag:=olcrtc-proxy}"
sidecar_stop() {
if [ -f "${sidecar_pid}" ]; then
spid=$(cat "${sidecar_pid}" 2>/dev/null)
[ -n "${spid}" ] && kill -15 "${spid}" >/dev/null 2>&1
rm -f "${sidecar_pid}"
fi
for pf in "${sidecar_pid}" "${sidecar_pid_olc}" "${sidecar_pid_tt}"; do
if [ -f "${pf}" ]; then
spid=$(cat "${pf}" 2>/dev/null)
[ -n "${spid}" ] && kill -15 "${spid}" >/dev/null 2>&1
rm -f "${pf}"
fi
done
for bin in olcrtc trusttunnel_client; do
busybox pkill -15 "${bin}" >/dev/null 2>&1
done
}
sidecar_wait_ready() {
port="${sidecar_listen_port}"
sidecar_wait_port() {
port="$1"
i=0
while [ "${i}" -lt 30 ]; do
while [ "${i}" -lt 45 ]; do
if busybox nc -z 127.0.0.1 "${port}" 2>/dev/null; then
return 0
fi
@@ -53,90 +46,192 @@ sidecar_wait_ready() {
return 1
}
sidecar_start_process() {
_bin=$(sidecar_bin_path)
_cfg=$(sidecar_config_path)
if [ "${sidecar_enable}" != "true" ]; then
return 0
fi
if [ -z "${sidecar_protocol}" ]; then
log Error "[Sidecar] sidecar_protocol is empty (olcrtc | trusttunnel)"
return 1
fi
sidecar_start_one() {
# $1=protocol $2=bin $3=cfg $4=port $5=pidfile $6=extra_args...
_proto="$1"; _bin="$2"; _cfg="$3"; _port="$4"; _pf="$5"
shift 5
if [ ! -x "${_bin}" ]; then
log Error "[Sidecar] Binary not found: ${_bin}"
log Error "[Sidecar] Run: su -c /data/adb/box/scripts/box.tool upsidercar"
return 1
fi
if [ ! -f "${_cfg}" ]; then
log Error "[Sidecar] Config not found: ${_cfg}"
log Error "[Sidecar] Copy example from ${sidecar_dir}/*.example.*"
return 1
fi
sidecar_stop
mkdir -p "${sidecar_dir}" "${box_run}"
: > "${sidecar_log}"
case "${sidecar_protocol}" in
case "${_proto}" in
olcrtc)
nohup busybox setuidgid "${box_user_group}" "${_bin}" "${_cfg}" >> "${sidecar_log}" 2>&1 &
;;
trusttunnel)
nohup busybox setuidgid "${box_user_group}" "${_bin}" -c "${_cfg}" >> "${sidecar_log}" 2>&1 &
nohup busybox setuidgid "${box_user_group}" "${_bin}" -s -c "${_cfg}" >> "${sidecar_log}" 2>&1 &
;;
*)
log Error "[Sidecar] Unknown protocol: ${sidecar_protocol}"
log Error "[Sidecar] Unknown protocol: ${_proto}"
return 1
;;
esac
echo -n "$!" > "${_pf}"
# Also keep legacy sidecar.pid pointing at last/primary
echo -n "$!" > "${sidecar_pid}"
log Info "[Sidecar] Starting ${sidecar_protocol} on 127.0.0.1:${sidecar_listen_port}"
log Info "[Sidecar] Starting ${_proto} on 127.0.0.1:${_port} (pid $!)"
if sidecar_wait_ready; then
log Info "[Sidecar] ${sidecar_protocol} SOCKS ready"
if sidecar_wait_port "${_port}"; then
log Info "[Sidecar] ${_proto} SOCKS ready on :${_port}"
return 0
fi
log Error "[Sidecar] Timeout waiting for port ${sidecar_listen_port}"
log Error "[Sidecar] Log: ${sidecar_log}"
tail -n 15 "${sidecar_log}" 2>/dev/null | while read -r line; do log Error "[Sidecar] ${line}"; done
log Error "[Sidecar] Timeout waiting for ${_proto} port ${_port}"
tail -n 20 "${sidecar_log}" 2>/dev/null | while read -r line; do log Error "[Sidecar] ${line}"; done
return 1
}
sidecar_inject_socks() {
# $1=tag $2=port
tag="$1"
port="$2"
yq="${box_dir}/bin/yq"
[ -x "${yq}" ] || yq="yq"
if ! "${yq}" ".outbounds[] | select(.tag == \"${tag}\")" "${sing_config}" 2>/dev/null | grep -q .; then
"${yq}" ".outbounds += [{
\"type\": \"socks\",
\"tag\": \"${tag}\",
\"server\": \"127.0.0.1\",
\"server_port\": ${port},
\"version\": \"5\"
}]" -i --output-format=json "${sing_config}" && \
log Info "[Sidecar] Injected socks '${tag}' -> 127.0.0.1:${port}"
else
# Keep port in sync
"${yq}" "(.outbounds[] | select(.tag == \"${tag}\") | .server_port) = ${port}" -i --output-format=json "${sing_config}" 2>/dev/null
log Info "[Sidecar] Outbound '${tag}' already present (port=${port})"
fi
}
sidecar_patch_dns() {
tag="$1"
yq="${box_dir}/bin/yq"
[ -x "${yq}" ] || yq="yq"
"${yq}" '
( [.dns.servers[]? | select(.tag == "dns-direct")] | length) as $n |
if $n == 0 then .dns.servers = [{"type":"local","tag":"dns-direct"}] + (.dns.servers // []) else . end
' -i --output-format=json "${sing_config}" 2>/dev/null || true
"${yq}" '(.dns.servers[] | select(.detour == "proxy" or .tag == "dns-remote") | .detour) = "'"${tag}"'"' -i --output-format=json "${sing_config}" 2>/dev/null && \
log Info "[Sidecar] dns-remote detour -> ${tag}"
"${yq}" '
(.dns.servers[] | select(.tag == "dns-remote")) = {"type":"https","tag":"dns-remote","detour":"'"${tag}"'","server":"1.1.1.1","path":"/dns-query"} |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only"
' -i --output-format=json "${sing_config}" 2>/dev/null && \
log Info "[Sidecar] dns-remote -> https/1.1.1.1 via ${tag}, strategy ipv4_only"
}
sidecar_inject_singbox() {
[ "${sidecar_enable}" != "true" ] && return 0
[ "${bin_name}" != "sing-box" ] && return 0
[ ! -f "${sing_config}" ] && return 0
yq="${box_dir}/bin/yq"
command -v yq >/dev/null 2>&1 || yq="yq"
tag="${sidecar_outbound_tag}"
port="${sidecar_listen_port}"
if ! ${yq} ".outbounds[] | select(.tag == \"${tag}\")" "${sing_config}" 2>/dev/null | grep -q .; then
${yq} ".outbounds += [{
\"type\": \"socks\",
\"tag\": \"${tag}\",
\"server\": \"127.0.0.1\",
\"server_port\": ${port},
\"version\": \"5\"
}]" -i --output-format=json "${sing_config}"
log Info "[Sidecar] Injected socks outbound '${tag}' -> 127.0.0.1:${port}"
if [ ! -x "${yq}" ]; then
if command -v yq >/dev/null 2>&1; then
yq="yq"
else
log Error "[Sidecar] yq not found — cannot inject socks outbound"
return 1
fi
fi
case "${sidecar_protocol}" in
both)
# Fixed tags for BFR Manager profiles (ignore mis-set sidecar_outbound_tag)
sidecar_inject_socks "sidecar-proxy" "${sidecar_tt_port}"
sidecar_inject_socks "${sidecar_olc_tag}" "${sidecar_olc_port}"
# Prefer final already set in the active profile (BFR Manager Manage Profiles)
cur_final=$("${yq}" -r '.route.final // ""' "${sing_config}" 2>/dev/null)
case "${cur_final}" in
"${sidecar_olc_tag}"|sidecar-proxy|"${sidecar_outbound_tag}")
final_tag="${cur_final}"
;;
*)
final_tag="sidecar-proxy"
;;
esac
;;
olcrtc)
sidecar_inject_socks "${sidecar_outbound_tag}" "${sidecar_listen_port}"
final_tag="${sidecar_outbound_tag}"
;;
trusttunnel|*)
sidecar_inject_socks "${sidecar_outbound_tag}" "${sidecar_listen_port}"
final_tag="${sidecar_outbound_tag}"
;;
esac
if [ "${sidecar_set_final}" = "true" ]; then
${yq} ".route.final = \"${tag}\"" -i --output-format=json "${sing_config}"
log Info "[Sidecar] route.final -> ${tag}"
"${yq}" ".route.final = \"${final_tag}\"" -i --output-format=json "${sing_config}" && \
log Info "[Sidecar] route.final -> ${final_tag}"
sidecar_patch_dns "${final_tag}"
else
log Info "[Sidecar] sidecar_set_final=false — keep profile route.final (BFR Manager switch)"
fi
}
sidecar_start_process() {
if [ "${sidecar_enable}" != "true" ]; then
return 0
fi
if [ -z "${sidecar_protocol}" ]; then
log Error "[Sidecar] sidecar_protocol is empty (olcrtc | trusttunnel | both)"
return 1
fi
sidecar_stop
mkdir -p "${sidecar_dir}" "${box_run}" /data/adb/box/run/olcrtc-data
: > "${sidecar_log}"
case "${sidecar_protocol}" in
olcrtc)
sidecar_start_one olcrtc "${box_dir}/bin/olcrtc" "${sidecar_dir}/olcrtc.yaml" \
"${sidecar_listen_port}" "${sidecar_pid_olc}" || return 1
;;
trusttunnel)
sidecar_start_one trusttunnel "${box_dir}/bin/trusttunnel_client" "${sidecar_dir}/trusttunnel.toml" \
"${sidecar_listen_port}" "${sidecar_pid_tt}" || return 1
;;
both)
# TT + olcrtc for BFR Manager profile flipping; missing one must not block the other
sidecar_start_one trusttunnel "${box_dir}/bin/trusttunnel_client" "${sidecar_dir}/trusttunnel.toml" \
"${sidecar_tt_port}" "${sidecar_pid_tt}" || \
log Warning "[Sidecar] trusttunnel failed/missing — continue without it"
sleep 2
sidecar_start_one olcrtc "${box_dir}/bin/olcrtc" "${sidecar_dir}/olcrtc.yaml" \
"${sidecar_olc_port}" "${sidecar_pid_olc}" || {
log Warning "[Sidecar] olcrtc failed to start — continuing without it"
log Warning "[Sidecar] Tip: telemost room.id = full https://telemost.yandex.ru/j/<id> URL (or numeric id)"
log Warning "[Sidecar] Tip: under root:net_admin set net.dns to LAN resolver (e.g. gateway:53)"
}
# Only hard-fail if neither SOCKS came up
if ! busybox nc -z 127.0.0.1 "${sidecar_tt_port}" 2>/dev/null && \
! busybox nc -z 127.0.0.1 "${sidecar_olc_port}" 2>/dev/null; then
log Error "[Sidecar] neither trusttunnel nor olcrtc is listening"
return 1
fi
;;
*)
log Error "[Sidecar] Unknown protocol: ${sidecar_protocol}"
return 1
;;
esac
return 0
}
case "$1" in
start)
sidecar_start_process && sidecar_inject_singbox
@@ -149,11 +244,16 @@ case "$1" in
sidecar_inject_singbox
;;
status)
if [ -f "${sidecar_pid}" ] && kill -0 "$(cat "${sidecar_pid}")" 2>/dev/null; then
log Info "[Sidecar] Running PID $(cat "${sidecar_pid}") protocol=${sidecar_protocol}"
else
log Info "[Sidecar] Not running"
fi
echo "protocol=${sidecar_protocol}"
for pf in "${sidecar_pid_tt}" "${sidecar_pid_olc}" "${sidecar_pid}"; do
[ -f "${pf}" ] || continue
spid=$(cat "${pf}" 2>/dev/null)
if [ -n "${spid}" ] && kill -0 "${spid}" 2>/dev/null; then
log Info "[Sidecar] alive pid=${spid} file=$(basename "${pf}")"
fi
done
busybox nc -z 127.0.0.1 "${sidecar_tt_port}" 2>/dev/null && echo "port ${sidecar_tt_port} open" || true
busybox nc -z 127.0.0.1 "${sidecar_olc_port}" 2>/dev/null && echo "port ${sidecar_olc_port} open" || true
;;
*)
echo "usage: $0 {start|stop|inject|status}"

View File

@@ -1197,15 +1197,50 @@ upsidercar() {
if [ "${target}" = "olcrtc" ] || [ "${target}" = "all" ]; then
if [ -x "${bin_dir}/olcrtc" ]; then
log Info "olcrtc already present: ${bin_dir}/olcrtc"
"${bin_dir}/olcrtc" 2>&1 | head -1 || true
else
log Warning "olcrtc has no official Android release bundle."
log Warning "Build with: mage mobile (https://github.com/openlibrecommunity/olcrtc)"
log Warning "Or copy binary to ${bin_dir}/olcrtc and chmod 755"
log Warning "Example config: ${box_dir}/sidecar/olcrtc.example.yaml -> olcrtc.yaml"
log Warning "On PC build linux/arm64: tools/build_olcrtc_arm64.ps1"
log Warning "Then: adb push olcrtc-linux-arm64 /data/local/tmp/olcrtc && su -c 'cp /data/local/tmp/olcrtc ${bin_dir}/olcrtc && chmod 755 ${bin_dir}/olcrtc'"
log Warning "Config: ${box_dir}/sidecar/olcrtc.example.yaml -> olcrtc.yaml (socks.port 10801 for dual mode)"
fi
fi
}
upwgobfs() {
# su -c /data/adb/box/scripts/box.tool upwgobfs
mkdir -p "${bin_dir}" "${box_dir}/sidecar"
case $(uname -m) in
aarch64) asset="wg-obfuscator-v1.5-linux-arm64.tar.gz" ;;
armv7l|armv8l) asset="wg-obfuscator-v1.5-linux-armv7-hf.tar.gz" ;;
x86_64) asset="wg-obfuscator-v1.5-linux-x64.tar.gz" ;;
*) log Error "Unsupported arch for wg-obfuscator: $(uname -m)"; return 1 ;;
esac
url="https://github.com/ClusterM/wg-obfuscator/releases/download/v1.5/${asset}"
log Info "Downloading ${asset}"
if upfile "${box_dir}/${asset}" "${url}"; then
tar -xzf "${box_dir}/${asset}" -C "${box_dir}" 2>/dev/null
find "${box_dir}" -maxdepth 3 -name 'wg-obfuscator' -type f 2>/dev/null | while read -r f; do
cp -f "${f}" "${bin_dir}/wg-obfuscator"
chmod 755 "${bin_dir}/wg-obfuscator"
done
rm -f "${box_dir}/${asset}"
if [ -x "${bin_dir}/wg-obfuscator" ]; then
log Info "Installed ${bin_dir}/wg-obfuscator"
"${bin_dir}/wg-obfuscator" -V 2>&1 | head -2 || true
else
log Error "wg-obfuscator binary not found after extract"
fi
if [ ! -f "${box_dir}/sidecar/wg-obfuscator.conf" ] && [ -f "${box_dir}/sidecar/wg-obfuscator.example.conf" ]; then
cp -f "${box_dir}/sidecar/wg-obfuscator.example.conf" "${box_dir}/sidecar/wg-obfuscator.conf"
log Warning "Created sidecar/wg-obfuscator.conf — set key= and target="
fi
else
log Error "Download failed: ${url}"
return 1
fi
}
case "$1" in
check)
check
@@ -1232,6 +1267,9 @@ case "$1" in
upsidercar)
upsidercar
;;
upwgobfs)
upwgobfs
;;
geosub)
upgeox
upsubs
@@ -1288,6 +1326,7 @@ case "$1" in
echo " subs - Update subscription (only for clash), then reload if running"
echo " upkernel - Update kernel-related components"
echo " upsidercar - Install sidecar binaries (olcrtc / trusttunnel)"
echo " upwgobfs - Install ClusterM wg-obfuscator (WireGuard UDP obfuscation)"
echo " upxui - Update XUI panel"
echo " upyq - Update yq binary"
echo " upcurl - Update curl binary"

177
box/scripts/box.wgobfs Normal file
View File

@@ -0,0 +1,177 @@
#!/system/bin/sh
# VeilBox — WireGuard Obfuscator (ClusterM/wg-obfuscator) lifecycle
# Docs: https://github.com/ClusterM/wg-obfuscator
#
# Client flow:
# sing-box WireGuard peer → 127.0.0.1:wgobfs_listen_port
# → wg-obfuscator → real server obfuscator (or server WG via obfuscator)
#
# REQUIRED: the same key + matching ports on the VPS (server-side obfuscator).
# Without the server half this cannot work.
if ! /system/bin/sh -n /data/adb/box/settings.ini 2>/dev/null; then
echo "Err: settings.ini syntax error" >&2
exit 1
fi
scripts_dir="${0%/*}"
. /data/adb/box/settings.ini
: "${wgobfs_enable:=false}"
: "${wgobfs_bin:=${box_dir}/bin/wg-obfuscator}"
: "${wgobfs_config:=${box_dir}/sidecar/wg-obfuscator.conf}"
: "${wgobfs_listen_port:=41320}"
: "${wgobfs_masking:=AUTO}"
: "${wgobfs_patch_config:=true}"
wgobfs_pid="${box_run}/wg-obfuscator.pid"
wgobfs_log="${box_run}/wg-obfuscator.log"
wgobfs_stop() {
if [ -f "${wgobfs_pid}" ]; then
spid=$(cat "${wgobfs_pid}" 2>/dev/null)
[ -n "${spid}" ] && kill -15 "${spid}" >/dev/null 2>&1
rm -f "${wgobfs_pid}"
fi
busybox pkill -15 wg-obfuscator >/dev/null 2>&1
}
wgobfs_wait_udp() {
# UDP listen is hard to probe with nc -z; rely on process + brief sleep
sleep 1
if [ -f "${wgobfs_pid}" ]; then
spid=$(cat "${wgobfs_pid}" 2>/dev/null)
kill -0 "${spid}" 2>/dev/null && return 0
fi
busybox pidof wg-obfuscator >/dev/null 2>&1
}
# Rewrite sing-box wireguard peers to localhost obfuscator listen port.
# Saves originals into .peers[]._veilbox_real_address / _veilbox_real_port (ignored by sing-box).
wgobfs_patch_singbox() {
[ "${wgobfs_patch_config}" = "true" ] || return 0
[ "${bin_name}" != "sing-box" ] && return 0
[ ! -f "${sing_config}" ] && return 0
yq="${box_dir}/bin/yq"
[ -x "${yq}" ] || yq="yq"
if ! command -v "${yq}" >/dev/null 2>&1 && [ ! -x "${yq}" ]; then
log Warning "[wgobfs] yq missing — cannot patch WireGuard endpoint"
return 1
fi
# Ensure we have at least one wireguard endpoint
if ! "${yq}" -e '.endpoints[] | select(.type == "wireguard")' "${sing_config}" >/dev/null 2>&1; then
log Warning "[wgobfs] no wireguard endpoint in ${sing_config}"
return 1
fi
# Stash real address/port once, then point peers at local obfuscator
"${yq}" -i -o=json '
(.endpoints[] | select(.type == "wireguard") | .peers[] |
select(._veilbox_real_address == null) |
._veilbox_real_address) = .address |
(.endpoints[] | select(.type == "wireguard") | .peers[] |
select(._veilbox_real_port == null) |
._veilbox_real_port) = .port |
(.endpoints[] | select(.type == "wireguard") | .peers[] | .address) = "127.0.0.1" |
(.endpoints[] | select(.type == "wireguard") | .peers[] | .port) = '"${wgobfs_listen_port}"'
' "${sing_config}" && \
log Info "[wgobfs] WireGuard peers → 127.0.0.1:${wgobfs_listen_port}"
# Direct route for real WG/obfuscator server IPs (avoid TPROXY loop)
real_ips=$("${yq}" -r '
.endpoints[]? | select(.type == "wireguard") | .peers[]? |
(._veilbox_real_address // empty)
' "${sing_config}" 2>/dev/null | sort -u)
for ip in ${real_ips}; do
case "${ip}" in
127.*|"" ) continue ;;
esac
if ! "${yq}" -e ".route.rules[] | select(.ip_cidr[] == \"${ip}/32\")" "${sing_config}" >/dev/null 2>&1; then
"${yq}" -i -o=json ".route.rules = [{\"ip_cidr\":[\"${ip}/32\"],\"outbound\":\"direct\"}] + (.route.rules // [])" "${sing_config}" && \
log Info "[wgobfs] route direct ${ip}/32"
fi
done
}
wgobfs_ensure_conf() {
mkdir -p "$(dirname "${wgobfs_config}")" "${box_run}"
if [ -f "${wgobfs_config}" ]; then
return 0
fi
if [ -f "${box_dir}/sidecar/wg-obfuscator.example.conf" ]; then
cp -f "${box_dir}/sidecar/wg-obfuscator.example.conf" "${wgobfs_config}"
log Warning "[wgobfs] created ${wgobfs_config} from example — edit key/target"
return 0
fi
log Error "[wgobfs] missing ${wgobfs_config}"
return 1
}
wgobfs_start() {
if [ "${wgobfs_enable}" != "true" ]; then
return 0
fi
if [ ! -x "${wgobfs_bin}" ]; then
log Error "[wgobfs] binary not found: ${wgobfs_bin}"
log Error "[wgobfs] download linux-arm64 from https://github.com/ClusterM/wg-obfuscator/releases"
return 1
fi
wgobfs_ensure_conf || return 1
wgobfs_stop
# Prefer source-if / source-lport from settings if config still has placeholders
# Launch with config file (multi-section supported)
nohup busybox setuidgid "${box_user_group}" \
"${wgobfs_bin}" -c "${wgobfs_config}" >> "${wgobfs_log}" 2>&1 &
echo -n "$!" > "${wgobfs_pid}"
log Info "[wgobfs] starting pid=$! config=${wgobfs_config}"
if wgobfs_wait_udp; then
log Info "[wgobfs] running (listen see config source-lport, default ${wgobfs_listen_port})"
else
log Error "[wgobfs] process died — see ${wgobfs_log}"
tail -n 15 "${wgobfs_log}" 2>/dev/null | while read -r line; do log Error "[wgobfs] ${line}"; done
return 1
fi
wgobfs_patch_singbox
return 0
}
wgobfs_status() {
echo "wgobfs_enable=${wgobfs_enable}"
echo "config=${wgobfs_config}"
echo "bin=${wgobfs_bin}"
if busybox pidof wg-obfuscator >/dev/null 2>&1; then
echo "pid=$(busybox pidof wg-obfuscator)"
echo "state=running"
else
echo "state=stopped"
fi
[ -f "${wgobfs_log}" ] && tail -n 8 "${wgobfs_log}"
}
case "$1" in
start)
wgobfs_start
;;
stop)
wgobfs_stop
log Info "[wgobfs] stopped"
;;
patch)
wgobfs_patch_singbox
;;
status)
wgobfs_status
;;
*)
echo "usage: $0 {start|stop|patch|status}"
exit 1
;;
esac

View File

@@ -102,6 +102,13 @@ name_provide_clash_rules="rules.yaml"
clash_provide_rules="${box_dir}/clash/subscription/${name_provide_clash_rules}"
# Sing configuration
# BFR Manager → Manage Profiles lists *.json here. Switchable profiles:
# config-trusttunnel.json — final → sidecar-proxy (:10800 TrustTunnel)
# config-olcrtc.json — final → olcrtc-proxy (:10801 olcrtc)
# config-wg-obfs.json — WireGuard via local wg-obfuscator (:41320)
# config-hy2-wg.json — your hysteria/wg base (etc.)
# For TT/olcrtc app switching keep sidecar_protocol=both and sidecar_set_final=false
# For WG obfuscation set wgobfs_enable=true (needs VPS-side obfuscator)
name_sing_config="config.json"
sing_config="${box_dir}/sing-box/${name_sing_config}"
@@ -215,7 +222,7 @@ wifi_ssids_list=("WiFi1" "WiFi-2" "WiFi 3")
inotify_log_enabled="true"
# -----------------------------------------------------------------
# BFR Stealth — anti-detection without LSPosed (iptables port-hide)
# PronBox stealth — anti-detection without LSPosed (iptables port-hide)
# -----------------------------------------------------------------
# Master switch: enables loopback port-hide for observer apps + API lockdown
@@ -241,7 +248,7 @@ stealth_block_quic="false"
stealth_forbid_tun="true"
# Extra ports to hide from external INPUT (space-separated in stealth_extra_ports)
stealth_extra_ports=("7890" "7891" "1080" "10808" "2080")
stealth_extra_ports=("7890" "7891" "1080" "10808" "2080" "41320")
# Observer apps — packages that probe for VPN/proxy (see stealth.list.cfg)
stealth_config=$(dirname "$settings")/stealth.list.cfg
@@ -262,17 +269,36 @@ stealth_packages_list=($(sed -n '/^[^#]/s/^\([^ ]*\.[^ ]*\).*/\1/p' ${stealth_co
# -----------------------------------------------------------------
sidecar_enable="false"
# olcrtc | trusttunnel
# olcrtc | trusttunnel | both
# Use "both" so BFR Manager Manage Profiles can flip TT ↔ olcrtc without CLI
sidecar_protocol=""
# Local SOCKS port (must match sidecar config socks.port / trusttunnel client)
# Local SOCKS port for single-protocol mode (must match sidecar config)
sidecar_listen_port="10800"
# sing-box outbound tag injected when sidecar_set_final=true
# Dual mode ports/tags (sidecar_protocol=both)
sidecar_tt_port="10800"
sidecar_olc_port="10801"
sidecar_olc_tag="olcrtc-proxy"
# sing-box outbound tag for TT (primary tag name in configs)
sidecar_outbound_tag="sidecar-proxy"
# Set route.final to sidecar outbound (sing-box only)
sidecar_set_final="true"
# true = force route.final to sidecar tag (overrides profile)
# false = keep route.final from the selected Manage Profiles config (recommended for TT/olcrtc flip)
sidecar_set_final="false"
sidecar_dir="${box_dir}/sidecar"
# -----------------------------------------------------------------
# WireGuard Obfuscator — https://github.com/ClusterM/wg-obfuscator
# Requires matching obfuscator on the VPS (same key). Not a VPN itself.
# -----------------------------------------------------------------
wgobfs_enable="false"
wgobfs_bin="${box_dir}/bin/wg-obfuscator"
wgobfs_config="${box_dir}/sidecar/wg-obfuscator.conf"
# Local UDP port sing-box WireGuard peers should use (must match source-lport in conf)
wgobfs_listen_port="41320"
wgobfs_masking="STUN"
# When true, rewrite active sing-box WG peer address/port → 127.0.0.1:wgobfs_listen_port
wgobfs_patch_config="true"
notify() {
true
@@ -309,6 +335,6 @@ log() {
fi
if [[ $TOAST ]]; then
notify "box_for_root" "${message}"
notify "PronBox" "${message}"
fi
}

View File

@@ -1,17 +1,22 @@
# Copy to /data/adb/box/sidecar/olcrtc.yaml and edit
# Docs: https://github.com/openlibrecommunity/olcrtc/blob/master/docs/configuration.md
# Docs: https://github.com/openlibrecommunity/olcrtc (docs/settings.md)
# Telemost: room.id = numeric conference id (NOT full https://telemost.yandex.ru/j/... URL)
mode: cnc
auth:
provider: jitsi
provider: telemost
room:
id: "https://meet.example.org/YOUR_ROOM_ID"
id: "YOUR_TELEMOST_NUMERIC_ROOM_ID"
crypto:
key: "REPLACE_WITH_64_HEX_CHARS_FROM_openssl_rand_hex_32"
net:
transport: datachannel
dns: "8.8.8.8:53"
transport: vp8channel
dns: "192.168.0.1:53"
socks:
host: "127.0.0.1"
port: 10800
# Prefer 10801 when TrustTunnel already uses 10800 (sidecar_protocol=both)
port: 10801
data: /data/adb/box/run/olcrtc-data
vp8:
fps: 30
batch_size: 64

View File

@@ -0,0 +1,28 @@
# VeilBox client — WireGuard Obfuscator (ClusterM)
# https://github.com/ClusterM/wg-obfuscator
#
# CRITICAL: the same `key` must be configured on the VPS obfuscator.
# Without a server-side wg-obfuscator this will NOT connect.
#
# Typical server layout (on VPS):
# public UDP 13232 → wg-obfuscator → 127.0.0.1:<real WireGuard ListenPort>
# Client target below must point at that public obfuscator host:port.
[client]
# Listen only on loopback (sing-box WireGuard peer connects here)
source-if = 127.0.0.1
source-lport = 41320
# Real remote: your VPS wg-obfuscator public endpoint
# Example uses the previous raw WG host — after you wrap WG with obfuscator on the VPS,
# keep the public host:port here (obfuscator listens where WG used to).
target = YOUR_VPS_IP:13232
# Shared obfuscation key (plain string, same on both sides)
key = CHANGE_ME_WG_OBFS_KEY
# STUN masking helps against DPI that only allows "video call" UDP
# AUTO | STUN | NONE
masking = STUN
verbose = INFO

View File

@@ -0,0 +1,14 @@
# Example VPS (server) config for ClusterM/wg-obfuscator
# Install linux binary on the VPS, run as systemd/docker, then point public UDP here.
#
# 1) Move WireGuard ListenPort from 13232 → e.g. 51820 (localhost only if possible)
# 2) Run obfuscator with source-lport=13232, target=127.0.0.1:51820
# 3) Client uses target=VPS_IP:13232 and the SAME key
[server]
source-if = 0.0.0.0
source-lport = 13232
target = 127.0.0.1:51820
key = CHANGE_ME_WG_OBFS_KEY
masking = AUTO
verbose = INFO

View File

@@ -1,42 +1,17 @@
## 🧱 Sing-box Documentation
# PronBox sing-box profiles
🔹 **Sing-box (Universal Proxy Core by SagerNet)**
📚 Official Docs: [sing-box.sagernet.org/configuration](http://sing-box.sagernet.org/configuration)
| File | Sidecar | SOCKS / UDP | `route.final` / note |
|------|---------|-------------|----------------------|
| `config-trusttunnel.json` | TrustTunnel | `127.0.0.1:10800` | `sidecar-proxy` |
| `config-olcrtc.json` | olcrtc | `127.0.0.1:10801` | `olcrtc-proxy` |
| `config-wg-obfs.json` | wg-obfuscator | UDP `:41320` | WG peers → localhost obfuscator |
| `config.stealth.example.json` | — | — | minimal template |
## ⚙️ Sample Sing-box Configuration (VMess over WS + TLS)
These files appear in **BFR Manager → Manage Profiles** (all `*.json` in `/data/adb/box/sing-box/`).
```json
{
"log": {
"level": "info"
},
"inbounds": [
{
"type": "mixed",
"listen": "::",
"listen_port": 7890
}
],
"outbounds": [
{
"type": "vmess",
"tag": "vmess-ws",
"server": "example.com",
"server_port": 443,
"uuid": "abcdefgh-1234-5678-90ab-cdef12345678",
"security": "auto",
"transport": {
"type": "ws",
"path": "/websocket",
"headers": {
"Host": "example.com"
}
},
"tls": {
"enabled": true,
"server_name": "example.com",
"insecure": true
}
}
]
}
For TT/olcrtc flipping in the app:
- `sidecar_protocol="both"` + `sidecar_set_final="false"`
For WG obfuscation (`config-wg-obfs.json`):
- matching [wg-obfuscator](https://github.com/ClusterM/wg-obfuscator) on the VPS with the same `key`
- client conf: `/data/adb/box/sidecar/wg-obfuscator.conf`

View File

@@ -0,0 +1,215 @@
{
"log": {
"level": "info",
"timestamp": true
},
"dns": {
"servers": [
{
"type": "local",
"tag": "dns-direct"
},
{
"type": "https",
"tag": "dns-remote",
"detour": "olcrtc-proxy",
"server": "1.1.1.1",
"path": "/dns-query"
}
],
"final": "dns-remote",
"strategy": "ipv4_only",
"independent_cache": true
},
"inbounds": [
{
"type": "tproxy",
"tag": "tproxy-in",
"listen": "::",
"listen_port": 9898
},
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 7890
}
],
"outbounds": [
{
"type": "hysteria2",
"tag": "proxy",
"server": "YOUR_SERVER_IP",
"server_port": 443,
"password": "YOUR_HYSTERIA2_PASSWORD",
"tls": {
"enabled": true,
"server_name": "assets.m1rs3m.org",
"alpn": "h3"
}
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "socks",
"tag": "sidecar-proxy",
"server": "127.0.0.1",
"server_port": 10800,
"version": "5"
},
{
"type": "socks",
"tag": "olcrtc-proxy",
"server": "127.0.0.1",
"server_port": 10801,
"version": "5"
}
],
"route": {
"rules": [
{
"domain_suffix": [
"yandex.ru",
"yandex.net",
"yandex.com",
"ya.ru"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"action": "sniff"
},
{
"protocol": "dns",
"action": "hijack-dns"
},
{
"ip_cidr": [
"YOUR_VPS_IP/32",
"YOUR_VPS_IP/32"
],
"outbound": "direct"
},
{
"ip_cidr": [
"192.168.0.0/16",
"172.16.0.0/12",
"127.0.0.0/8",
"169.254.0.0/16"
],
"outbound": "direct"
},
{
"rule_set": "geoip-private",
"outbound": "direct"
},
{
"domain_suffix": [
".ru",
".su",
".xn--p1ai"
],
"outbound": "direct"
},
{
"rule_set": "geosite-category-ru",
"outbound": "direct"
},
{
"rule_set": "geoip-ru",
"outbound": "direct"
}
],
"rule_set": [
{
"type": "local",
"tag": "geoip-private",
"path": "ruleset/geoip-private.srs"
},
{
"type": "local",
"tag": "geoip-ru",
"path": "ruleset/geoip-ru.srs"
},
{
"type": "local",
"tag": "geosite-category-ru",
"path": "ruleset/geosite-category-ru.srs"
}
],
"final": "olcrtc-proxy",
"auto_detect_interface": false,
"default_domain_resolver": "dns-direct"
},
"experimental": {
"cache_file": {
"enabled": true,
"path": "cache.db"
}
}
}

View File

@@ -0,0 +1,215 @@
{
"log": {
"level": "info",
"timestamp": true
},
"dns": {
"servers": [
{
"type": "local",
"tag": "dns-direct"
},
{
"type": "https",
"tag": "dns-remote",
"detour": "sidecar-proxy",
"server": "1.1.1.1",
"path": "/dns-query"
}
],
"final": "dns-remote",
"strategy": "ipv4_only",
"independent_cache": true
},
"inbounds": [
{
"type": "tproxy",
"tag": "tproxy-in",
"listen": "::",
"listen_port": 9898
},
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 7890
}
],
"outbounds": [
{
"type": "hysteria2",
"tag": "proxy",
"server": "YOUR_SERVER_IP",
"server_port": 443,
"password": "YOUR_HYSTERIA2_PASSWORD",
"tls": {
"enabled": true,
"server_name": "assets.m1rs3m.org",
"alpn": "h3"
}
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "socks",
"tag": "sidecar-proxy",
"server": "127.0.0.1",
"server_port": 10800,
"version": "5"
},
{
"type": "socks",
"tag": "olcrtc-proxy",
"server": "127.0.0.1",
"server_port": 10801,
"version": "5"
}
],
"route": {
"rules": [
{
"domain_suffix": [
"yandex.ru",
"yandex.net",
"yandex.com",
"ya.ru"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"action": "sniff"
},
{
"protocol": "dns",
"action": "hijack-dns"
},
{
"ip_cidr": [
"YOUR_VPS_IP/32",
"YOUR_VPS_IP/32"
],
"outbound": "direct"
},
{
"ip_cidr": [
"192.168.0.0/16",
"172.16.0.0/12",
"127.0.0.0/8",
"169.254.0.0/16"
],
"outbound": "direct"
},
{
"rule_set": "geoip-private",
"outbound": "direct"
},
{
"domain_suffix": [
".ru",
".su",
".xn--p1ai"
],
"outbound": "direct"
},
{
"rule_set": "geosite-category-ru",
"outbound": "direct"
},
{
"rule_set": "geoip-ru",
"outbound": "direct"
}
],
"rule_set": [
{
"type": "local",
"tag": "geoip-private",
"path": "ruleset/geoip-private.srs"
},
{
"type": "local",
"tag": "geoip-ru",
"path": "ruleset/geoip-ru.srs"
},
{
"type": "local",
"tag": "geosite-category-ru",
"path": "ruleset/geosite-category-ru.srs"
}
],
"final": "sidecar-proxy",
"auto_detect_interface": false,
"default_domain_resolver": "dns-direct"
},
"experimental": {
"cache_file": {
"enabled": true,
"path": "cache.db"
}
}
}

View File

@@ -0,0 +1,239 @@
{
"log": {
"level": "info",
"timestamp": true
},
"dns": {
"servers": [
{
"type": "local",
"tag": "dns-direct"
},
{
"type": "https",
"tag": "dns-remote",
"detour": "olcrtc-proxy",
"server": "1.1.1.1",
"path": "/dns-query"
},
{
"type": "https",
"tag": "dns-hy2",
"detour": "sidecar-proxy",
"server": "1.1.1.1",
"path": "/dns-query"
}
],
"final": "dns-remote",
"strategy": "ipv4_only",
"independent_cache": true
},
"endpoints": [
{
"type": "wireguard",
"tag": "wg-home",
"mtu": 1280,
"address": "10.0.10.16/32",
"private_key": "YOUR_WIREGUARD_PRIVATE_KEY",
"peers": [
{
"address": "127.0.0.1",
"port": 41320,
"public_key": "YOUR_PEER_PUBLIC_KEY",
"allowed_ips": "10.0.0.0/8",
"persistent_keepalive_interval": 25,
"_example_real_address": "YOUR_VPS_IP"
}
]
}
],
"inbounds": [
{
"type": "tproxy",
"tag": "tproxy-in",
"listen": "::",
"listen_port": 9898
},
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 7890
}
],
"outbounds": [
{
"type": "hysteria2",
"tag": "proxy",
"server": "YOUR_SERVER_IP",
"server_port": 443,
"password": "YOUR_HYSTERIA2_PASSWORD",
"tls": {
"enabled": true,
"server_name": "assets.m1rs3m.org",
"alpn": "h3"
}
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "socks",
"tag": "sidecar-proxy",
"server": "127.0.0.1",
"server_port": 10800,
"version": "5"
},
{
"type": "socks",
"tag": "olcrtc-proxy",
"server": "127.0.0.1",
"server_port": 10801,
"version": "5"
}
],
"route": {
"rules": [
{
"domain_suffix": [
"yandex.ru",
"yandex.net",
"yandex.com",
"ya.ru"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"ip_cidr": [
"1",
"3",
".",
"1",
"4",
"0",
".",
"1",
"7",
".",
"1",
"6",
"3",
"/",
"3",
"2"
],
"outbound": "direct"
},
{
"action": "sniff"
},
{
"protocol": "dns",
"action": "hijack-dns"
},
{
"ip_cidr": [
"YOUR_VPS_IP/32"
],
"outbound": "direct"
},
{
"ip_cidr": [
"192.168.0.0/16",
"172.16.0.0/12",
"127.0.0.0/8",
"169.254.0.0/16"
],
"outbound": "direct"
},
{
"rule_set": "geoip-private",
"outbound": "direct"
},
{
"domain_suffix": [
".ru",
".su",
".xn--p1ai"
],
"outbound": "direct"
},
{
"rule_set": "geosite-category-ru",
"outbound": "direct"
},
{
"rule_set": "geoip-ru",
"outbound": "direct"
}
],
"rule_set": [
{
"type": "local",
"tag": "geoip-private",
"path": "ruleset/geoip-private.srs"
},
{
"type": "local",
"tag": "geoip-ru",
"path": "ruleset/geoip-ru.srs"
},
{
"type": "local",
"tag": "geosite-category-ru",
"path": "ruleset/geosite-category-ru.srs"
}
],
"final": "olcrtc-proxy",
"default_domain_resolver": "dns-direct"
},
"experimental": {
"cache_file": {
"enabled": true,
"path": "cache.db"
}
}
}

View File

@@ -1,4 +1,4 @@
#!/bin/sh
# sed -i "s/$(grep -oP 'version=\K[^ ]+' module.prop)/$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}')($(git log --oneline -n 1 | awk '{print $1}'))/g" module.prop
zip -r -o -X -ll box_for_root-$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}').zip ./ -x '.git/*' -x 'CHANGELOG.md' -x 'update.json' -x 'build.sh' -x '.github/*' -x 'docs/*'
zip -r -o -X -ll pronbox-$(cat module.prop | grep 'version=' | awk -F '=' '{print $2}').zip ./ -x '.git/*' -x 'CHANGELOG.md' -x 'update.json' -x 'build.sh' -x '.github/*' -x 'docs/*' -x 'tools/*' -x 'phone_configs/*' -x '*.zip'

View File

@@ -38,7 +38,7 @@ if [ -d "/data/adb/modules/box_for_magisk" ]; then
fi
# Extract files and configure directories
ui_print "— Installing Box for Magisk/KernelSU/APatch"
ui_print "— Installing PronBox (НИИ «ТехноПрон»)"
unzip -o "$ZIPFILE" -x 'META-INF/*' -x 'webroot/*' -d "$MODPATH" >&2
if [ -d "/data/adb/box" ]; then
ui_print "— Backup existing box data"
@@ -192,7 +192,7 @@ restore_ini() {
target_ini="/data/adb/box/settings.ini"
# List of keys to restore (separate with spaces)
keys="network_mode bin_name ipv6 xclash_option renew update_subscription subscription_url_clash subscription_url_singbox name_clash_config clash_config name_provide_clash_config clash_provide_path enable_network_service_control use_module_on_wifi_disconnect use_module_on_wifi use_ssid_matching use_wifi_list_mode wifi_ssids_list inotify_log_enabled stealth_mode stealth_hide_loopback stealth_block_external_api stealth_disable_api stealth_api_bind stealth_api_port stealth_block_quic stealth_forbid_tun sidecar_enable sidecar_protocol sidecar_listen_port sidecar_outbound_tag sidecar_set_final"
keys="network_mode bin_name ipv6 xclash_option renew update_subscription subscription_url_clash subscription_url_singbox name_clash_config clash_config name_provide_clash_config clash_provide_path name_sing_config enable_network_service_control use_module_on_wifi_disconnect use_module_on_wifi use_ssid_matching use_wifi_list_mode wifi_ssids_list inotify_log_enabled stealth_mode stealth_hide_loopback stealth_block_external_api stealth_disable_api stealth_api_bind stealth_api_port stealth_block_quic stealth_forbid_tun sidecar_enable sidecar_protocol sidecar_listen_port sidecar_tt_port sidecar_olc_port sidecar_olc_tag sidecar_outbound_tag sidecar_set_final wgobfs_enable wgobfs_listen_port wgobfs_masking wgobfs_patch_config"
for key in $keys; do
value=$(grep "^$key=" "$backup_ini")
@@ -264,10 +264,18 @@ if [ "${backup_box}" = "true" ]; then
fi
}
for kernel in curl yq xray sing-box v2fly hysteria xclash/mihomo xclash/premium; do
for kernel in curl yq xray sing-box v2fly hysteria xclash/mihomo xclash/premium trusttunnel_client olcrtc wg-obfuscator; do
restore_kernel "$kernel"
done
# Sidecar configs (TrustTunnel / olcrtc) — not shipped with secrets in ZIP
if [ -d "${temp_dir}/sidecar" ]; then
ui_print "— Restoring sidecar configs..."
mkdir -p /data/adb/box/sidecar
cp -rf "${temp_dir}/sidecar/"* "/data/adb/box/sidecar/" 2>/dev/null
fi
[ -f "${temp_dir}/stealth.list.cfg" ] && cp -f "${temp_dir}/stealth.list.cfg" "/data/adb/box/stealth.list.cfg"
ui_print "— Restoring..."
ui_print " ↳ *.logs"
ui_print " ↳ box.pid"
@@ -302,14 +310,16 @@ fi
# Update module description if no kernel binaries are found
[ -z "$(find /data/adb/box/bin -type f)" ] && sed -Ei 's/^description=(\[.*][[:space:]]*)?/description=[ 😱 Module installed but manual Kernel download required ] /g' $MODPATH/module.prop
# Customize module name based on environment
# Keep PronBox branding (do not rewrite to stock "Box for Magisk")
if [ "$KSU" = "true" ]; then
sed -i "s/name=.*/name=Box for KernelSU/g" $MODPATH/module.prop
sed -i "s/^name=.*/name=PronBox (KernelSU)/g" $MODPATH/module.prop
elif [ "$APATCH" = "true" ]; then
sed -i "s/name=.*/name=Box for APatch/g" $MODPATH/module.prop
sed -i "s/^name=.*/name=PronBox (APatch)/g" $MODPATH/module.prop
else
sed -i "s/name=.*/name=Box for Magisk/g" $MODPATH/module.prop
sed -i "s/^name=.*/name=PronBox/g" $MODPATH/module.prop
fi
# Always pin author to НИИ ТехноПрон
sed -i "s/^author=.*/author=команда НИИ «ТехноПрон»/g" $MODPATH/module.prop
unzip -o "$ZIPFILE" 'webroot/*' -d "$MODPATH" >&2
# Clean up temporary files

View File

@@ -1,6 +1,6 @@
id=box_for_root
name=BFR Stealth Mod
version=v1.10.2-stealth.1
versionCode=2026081201
author=bfr_mod (fork of taamarin)
description=Transparent proxy with stealth hardening (no LSPosed), olcrtc/TrustTunnel sidecar, sing-box tproxy. Fork of Box for Root.
name=PronBox
version=v1.12.0
versionCode=2026081301
author=команда НИИ «ТехноПрон»
description=PronBox — прозрачный TPROXY-прокси из стен НИИ «ТехноПрон». Stealth без LSPosed, TrustTunnel/olcrtc/wg-obfuscator, sing-box. Magisk id: box_for_root.

11
sbfr
View File

@@ -15,11 +15,12 @@ fi
# Help function
help() {
echo -e "${CYAN}Usage: $0 {start|stop|s <args>|i <args>|u|x|r|t <args>}${RESET}\n"
echo -e " ${YELLOW}start${RESET} : Start Box (service and iptables)"
echo -e " ${YELLOW}stop${RESET} : Stop Box (iptables and service)"
echo -e "${CYAN}Usage: $0 {start|stop|s <args>|i <args>|p <args>|u|x|r|t <args>}${RESET}\n"
echo -e " ${YELLOW}start${RESET} : Start PronBox (service and iptables)"
echo -e " ${YELLOW}stop${RESET} : Stop PronBox (iptables and service)"
echo -e " ${YELLOW}s <args>${RESET} : Run command to box.service with extra arguments"
echo -e " ${YELLOW}i <args>${RESET} : Run command to box.iptables with extra arguments"
echo -e " ${YELLOW}p <args>${RESET} : Profile switch — list | status | use trusttunnel | use olcrtc"
echo -e " ${YELLOW}t <args>${RESET} : Run tools from box.tool with extra arguments"
echo -e " ${YELLOW}u${RESET} : API to upgrade core[clash] (POST to /upgrade)"
echo -e " ${YELLOW}x${RESET} : API to upgrade Dashboard UI [clash/sing] (POST to /upgrade/ui)"
@@ -65,6 +66,10 @@ case "$1" in
t)
su -c "/data/adb/box/scripts/box.tool $2"
;;
p|profile)
shift
su -c "/data/adb/box/scripts/box.profile $*"
;;
help|-h|--help)
help
;;

View File

@@ -0,0 +1,33 @@
# Build olcrtc linux/arm64 static binary for Android Magisk sidecar
# Requires: Go 1.26+, git
#
# Local Android fixes live in tools/src/olcrtc (see tools/patches/olcrtc-android-ca.md):
# - load Android CA store for TLS
# - prefer IPv4 / no env proxy / no HTTP2 force
param(
[string]$OutDir = "E:\bfr_mod\tools\binaries",
[string]$SrcDir = "E:\bfr_mod\tools\src\olcrtc"
)
$ErrorActionPreference = "Stop"
$env:Path = "C:\Program Files\Go\bin;$env:USERPROFILE\go\bin;" + $env:Path
if (-not (Test-Path "$SrcDir\.git")) {
New-Item -ItemType Directory -Force -Path (Split-Path $SrcDir) | Out-Null
git clone --recurse-submodules --depth 1 https://github.com/openlibrecommunity/olcrtc.git $SrcDir
Write-Host "NOTE: re-apply Android CA patch from tools/patches/olcrtc-android-ca.md to internal/protect/protect.go"
}
Push-Location $SrcDir
try {
New-Item -ItemType Directory -Force -Path $OutDir, "build" | Out-Null
$env:CGO_ENABLED = "0"
$env:GOOS = "linux"
$env:GOARCH = "arm64"
$out = Join-Path $OutDir "olcrtc-linux-arm64"
go build -trimpath -ldflags "-s -w -checklinkname=0" -o $out ./cmd/olcrtc
Get-Item $out | Format-List FullName, Length, LastWriteTime
Write-Host "Push: adb push $out /data/local/tmp/olcrtc"
Write-Host "Install: su -c 'cp /data/local/tmp/olcrtc /data/adb/box/bin/olcrtc && chmod 755 /data/adb/box/bin/olcrtc'"
} finally {
Pop-Location
}

93
tools/build_zip.py Normal file
View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python3
"""Build Magisk ZIP with LF scripts (Android unzip-safe)."""
from __future__ import annotations
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
EXCLUDE_DIRS = {
".git",
".github",
"docs",
"tools",
"phone_configs",
"__pycache__",
}
EXCLUDE_FILES = {
"CHANGELOG.md",
"update.json",
"build.sh",
".gitignore",
"RELEASE.md",
}
EXCLUDE_GLOBS_SUFFIX = (".zip", ".pyc", ".lf", ".tar.gz", ".bak")
def version() -> str:
for line in (ROOT / "module.prop").read_text(encoding="utf-8").splitlines():
if line.startswith("version="):
return line.split("=", 1)[1].strip()
raise SystemExit("version= missing in module.prop")
def should_skip(rel: Path) -> bool:
parts = rel.parts
if any(p in EXCLUDE_DIRS for p in parts):
return True
if any(p.startswith("phone_") for p in parts):
return True
if rel.name in EXCLUDE_FILES:
return True
if rel.name.endswith(EXCLUDE_GLOBS_SUFFIX):
return True
return False
def normalize_bytes(path: Path, data: bytes) -> bytes:
# Force LF for shell/scripts installed on Android
text_ext = {".sh", ".ini", ".cfg", ".prop", ".md", ".json", ".yaml", ".yml", ".toml", ".example"}
name = path.name
if (
path.suffix.lower() in text_ext
or name in {"sbfr", "box.stealth", "box.sidecar", "box.service", "box.iptables", "box.tool", "box.profile", "customize.sh", "uninstall.sh", "box_service.sh", "service.sh", "post-fs-data.sh"}
or name.startswith("box.")
):
try:
text = data.decode("utf-8")
except UnicodeDecodeError:
return data
return text.replace("\r\n", "\n").replace("\r", "\n").encode("utf-8")
return data
def main() -> None:
ver = version()
out = ROOT / f"pronbox-{ver}.zip"
if out.exists():
out.unlink()
count = 0
with zipfile.ZipFile(out, "w", compression=zipfile.ZIP_DEFLATED) as zf:
for path in sorted(ROOT.rglob("*")):
if not path.is_file():
continue
rel = path.relative_to(ROOT)
if should_skip(rel):
continue
data = normalize_bytes(path, path.read_bytes())
# Unix paths inside zip
arc = rel.as_posix()
info = zipfile.ZipInfo(arc)
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 0o755 << 16 if (
path.parent.name == "scripts"
or path.name in {"sbfr", "customize.sh", "uninstall.sh", "box_service.sh", "service.sh"}
or path.suffix == ".sh"
) else (0o644 << 16)
zf.writestr(info, data)
count += 1
print(f"Wrote {out.name} ({count} files, {out.stat().st_size} bytes)")
if __name__ == "__main__":
main()

13
tools/check_olc_now.sh Normal file
View File

@@ -0,0 +1,13 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
echo "protocol=$(grep '^sidecar_protocol=' /data/adb/box/settings.ini)"
echo "final=$(/data/adb/box/bin/yq -r '.route.final' "$sing_config")"
echo "tt=$(pidof trusttunnel_client) olc=$(pidof olcrtc) sb=$(pidof sing-box)"
/data/adb/magisk/busybox nc -z 127.0.0.1 10801 && echo 10801_open || echo 10801_closed
curl -m 20 -sS -o /dev/null -w "google %{http_code} %{time_total}\n" https://www.google.com/ || true
curl -m 15 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
echo "=== live olcrtc ==="
grep -E 'SOCKS5 server listening|control alive|Shutdown|opened' /data/adb/box/run/sidecar.log 2>/dev/null | tail -8
tail -8 /data/adb/box/run/olcrtc.log 2>/dev/null
ps -A 2>/dev/null | grep -E 'olcrtc|trusttunnel' || /data/adb/magisk/busybox ps | grep -E 'olcrtc|trusttunnel'

18
tools/check_route.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== yq ==="
ls -la /data/adb/box/bin/yq
/data/adb/box/bin/yq --version 2>&1 | head -2
echo "=== OUTBOUNDS TAGS ==="
/data/adb/box/bin/yq '.outbounds[].tag' /data/adb/box/sing-box/config.json 2>&1
echo "=== ROUTE FINAL ==="
/data/adb/box/bin/yq '.route.final' /data/adb/box/sing-box/config.json 2>&1
echo "=== HAS SIDECAR ==="
/data/adb/box/bin/yq '.outbounds[] | select(.tag == "sidecar-proxy")' /data/adb/box/sing-box/config.json 2>&1
echo "=== WHICH CONFIG ==="
# prepare may use directory
ls /data/adb/box/sing-box/*.json
echo "=== SYSTEM IP AGAIN ==="
curl -m 10 -sS https://1.1.1.1/cdn-cgi/trace | head -5
echo "=== SOCKS IP ==="
curl -x socks5h://127.0.0.1:10800 -m 10 -sS https://1.1.1.1/cdn-cgi/trace | head -5

7
tools/check_scripts.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/ksu/bin:/system/bin:$PATH"
echo "=== SCRIPTS DIR ==="
ls -la /data/adb/box/scripts/ 2>&1 | head -30
echo "=== MODULE ==="
ls /data/adb/modules/box_for_root/ 2>&1 | head -20
cat /data/adb/modules/box_for_root/module.prop 2>&1 | head -8

10
tools/debug_exec.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/system/bin:$PATH"
file /data/adb/box/scripts/box.service 2>/dev/null || true
head -1 /data/adb/box/scripts/box.service | od -An -tx1 | head -2
# try execute
sh /data/adb/box/scripts/box.service status 2>&1 | head -20
echo EXIT=$?
# check mount options
mount | grep ' /data '
ls -la /system/bin/sh

View File

@@ -0,0 +1,64 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
# Install updated sidecar script if staged
if [ -f /data/local/tmp/box.sidecar ]; then
cp /data/local/tmp/box.sidecar /data/adb/box/scripts/box.sidecar
chmod 755 /data/adb/box/scripts/box.sidecar
fi
# Ensure olcrtc binary
chmod 755 /data/adb/box/bin/olcrtc 2>/dev/null || true
mkdir -p /data/adb/box/run/olcrtc-data
# Enable dual sidecar on device settings (preserve other keys)
INI=/data/adb/box/settings.ini
grep -q 'sidecar_tt_port=' "$INI" || cat >> "$INI" <<'EOF'
# Dual sidecar ports (added by deploy)
sidecar_tt_port="10800"
sidecar_olc_port="10801"
sidecar_olc_tag="olcrtc-proxy"
EOF
# Flip protocol to both (sed-safe)
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' "$INI"
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="both"/' "$INI"
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10800"/' "$INI"
grep -q '^sidecar_set_final=' "$INI" || echo 'sidecar_set_final="true"' >> "$INI"
# Add RKNHardering to stealth observer list
STEALTH=/data/adb/box/stealth.list.cfg
touch "$STEALTH"
pkg=$(pm list packages | sed -n 's/^package://p' | grep -iE 'rknharden|notcvnt|rkn' | head -1)
echo "detected_rkn_pkg=${pkg}"
if [ -n "$pkg" ] && ! grep -qxF "$pkg" "$STEALTH" 2>/dev/null; then
echo "$pkg" >> "$STEALTH"
echo "added to stealth.list.cfg"
fi
# known package id from project docs
if ! grep -qxF 'com.notcvnt.rknhardering' "$STEALTH" 2>/dev/null; then
echo 'com.notcvnt.rknhardering' >> "$STEALTH"
fi
echo "=== settings sidecar ==="
grep -E '^sidecar_' "$INI"
echo "=== stealth list ==="
cat "$STEALTH"
echo "=== restart ==="
sh /data/adb/box/scripts/box.service restart
sleep 5
echo "tt=$(pidof trusttunnel_client) olc=$(pidof olcrtc) sb=$(pidof sing-box)"
sh /data/adb/box/scripts/box.sidecar status || true
echo "=== ports ==="
busybox nc -z 127.0.0.1 10800 && echo 10800_open || echo 10800_closed
busybox nc -z 127.0.0.1 10801 && echo 10801_open || echo 10801_closed
echo "=== olcrtc log tail ==="
tail -30 /data/adb/box/run/sidecar.log
echo "=== connectivity via TT final ==="
curl -m 15 -sS -o /dev/null -w "google %{http_code}\n" https://www.google.com/ || true
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
echo "=== socks test olcrtc :10801 ==="
curl -x socks5://127.0.0.1:10801 -m 20 -sS -o /dev/null -w "olc_ipgoogle %{http_code} %{time_total}\n" https://1.1.1.1/cdn-cgi/trace || true
curl -x socks5h://127.0.0.1:10801 -m 25 -sS -o /dev/null -w "olc_google %{http_code} %{time_total}\n" https://www.google.com/ || true

28
tools/diag_routing.sh Normal file
View File

@@ -0,0 +1,28 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
YQ=/data/adb/box/bin/yq
CFG=/data/adb/box/sing-box/config.json
echo "=== ROUTE FINAL ==="
$YQ '.route.final' "$CFG"
echo "=== ROUTE RULES ==="
$YQ '.route.rules' "$CFG"
echo "=== DNS ==="
$YQ '.dns' "$CFG"
echo "=== OUTBOUNDS ==="
$YQ '.outbounds[] | {"tag":.tag,"type":.type}' "$CFG"
echo "=== IP RULES ==="
ip rule list 2>/dev/null | head -30
echo "=== IPTABLES MANGLE BOX ==="
iptables -t mangle -S 2>/dev/null | grep -iE 'BOX|TPROXY|9898|mark' | head -40
echo "=== TEST RU ==="
curl -m 10 -sS -o /dev/null -w "yandex:%{http_code} ip=" https://ya.ru/ 2>&1
curl -m 10 -sS https://api.ipify.org?format=text 2>&1; echo
echo "=== TEST FOREIGN ==="
curl -m 12 -sS -o /dev/null -w "google:%{http_code}\n" https://www.google.com/ 2>&1
curl -m 12 -sS -o /dev/null -w "cf:%{http_code}\n" https://1.1.1.1/cdn-cgi/trace 2>&1
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -5
echo "=== SING-BOX RECENT ERRORS ==="
grep -iE 'ERROR|FATAL|reject|closed' /data/adb/box/run/sing-box.log 2>/dev/null | tail -25
echo "=== SIDECAR RECENT ==="
grep -iE 'ERROR|DISCONNECTED|CONNECTED|Failed' /data/adb/box/run/sidecar.log 2>/dev/null | tail -15

16
tools/diag_tt.sh Normal file
View File

@@ -0,0 +1,16 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:/system/bin:$PATH"
echo "=== PROCESS ==="
pidof trusttunnel_client || echo "NOT_RUNNING"
ps -A 2>/dev/null | grep -i trust || true
echo "=== PORT 10800 ==="
grep -E ':2A30 ' /proc/net/tcp /proc/net/tcp6 2>/dev/null || echo "NOT_LISTENING"
echo "=== LAST LOG ==="
tail -n 40 /data/adb/box/run/sidecar.log 2>/dev/null || echo "NO_LOG"
echo "=== SOCKS TEST ==="
curl -x socks5h://127.0.0.1:10800 -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -8
echo "CURL_EXIT=$?"
echo "=== DIRECT TEST ==="
curl -m 8 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -5
echo "=== BOX ==="
pidof sing-box || echo "sing-box not running"

12
tools/dns_deep.sh Normal file
View File

@@ -0,0 +1,12 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
echo "=== socks doh via curl ==="
# resolve via DoH manually through socks
curl -x socks5h://127.0.0.1:10800 -m 10 -sS 'https://1.1.1.1/dns-query?name=www.google.com&type=A' -H 'accept: application/dns-json' 2>&1 | head -c 400; echo
echo "=== system google ==="
curl -m 15 -v https://www.google.com/ -o /dev/null 2>&1 | tail -20
echo "=== recent dns errors ==="
grep -i 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -10
echo "=== config dns ==="
/data/adb/box/bin/yq '.dns' /data/adb/box/sing-box/config.json

14
tools/dns_ipt.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== mangle local/tproxy ==="
iptables -t mangle -S 2>/dev/null | grep -E '127\.0\.0\.1|RETURN|MARK|TPROXY|10800|BOX' | head -50
echo "=== filter related ==="
iptables -t nat -S 2>/dev/null | grep -E '127\.0\.0\.1|10800|RED|BOX' | head -30
echo "=== ip rule ==="
ip rule | head -20
echo "=== outbounds ==="
yq -o=json '.outbounds[] | {"tag":.tag,"type":.type,"server":.server,"server_port":.server_port}' /data/adb/box/sing-box/config.json
echo "=== route final ==="
yq -o=json '.route | {"final":.final,"rules_count":(.rules|length)}' /data/adb/box/sing-box/config.json
echo "=== last google dns log ==="
grep -i 'www.google.com' /data/adb/box/run/sing-box.log | tail -15

33
tools/dns_probe2.sh Normal file
View File

@@ -0,0 +1,33 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== raw udp53 from root (will be hijacked) ==="
# use busybox nslookup if available
busybox nslookup google.com 77.88.8.8 2>&1 | head -20 || true
echo "=== udp53 via sing-box owner? test with nc ==="
# Direct connect test: can we reach DNS/UDP and TT socks
echo | busybox nc -w 2 -u 77.88.8.8 53; echo "nc_udp_exit=$?"
echo "=== socks connect test ==="
curl -x socks5h://127.0.0.1:10800 -m 8 -sS -o /dev/null -w "socks_google %{http_code} %{time_total}\n" https://www.google.com/ || true
curl -x socks5://127.0.0.1:10800 -m 8 -sS -o /dev/null -w "socks_ipgoogle %{http_code} %{time_total}\n" https://142.251.150.119/ --resolve www.google.com:443:142.251.150.119 || true
echo "=== tt log ==="
tail -30 /data/adb/box/run/sidecar.log 2>/dev/null || tail -30 /data/adb/box/run/trusttunnel*.log 2>/dev/null || ls -la /data/adb/box/run/
echo "=== try dns detour=direct DoH ==="
CFG=/data/adb/box/sing-box/config.json
yq -i -o=json '(.dns.servers[] | select(.tag=="dns-remote") | .detour) = "direct"' "$CFG"
# also add pure tcp dns via sidecar as dns-tcp
yq -i -o=json '
.dns.servers += [{"type":"tcp","tag":"dns-tcp-socks","detour":"sidecar-proxy","server":"1.1.1.1"}] |
.dns.final = "dns-tcp-socks" |
.dns.strategy = "ipv4_only"
' "$CFG"
kill -HUP "$(pidof sing-box)" 2>/dev/null || true
sleep 1
# hard restart sing-box only (keep TT)
sh /data/adb/box/scripts/box.service restart
sleep 4
echo "=== dns cfg ==="
yq -o=json '.dns' "$CFG"
echo "=== test ==="
curl -m 15 -sS -o /dev/null -w "google %{http_code} %{time_total}\n" https://www.google.com/ || true
curl -m 12 -sS -o /dev/null -w "ya %{http_code} %{time_total}\n" https://ya.ru/ || true
grep 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -8

22
tools/export_cfg_shape.sh Normal file
View File

@@ -0,0 +1,22 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
CFG="$sing_config"
echo "CFG=$CFG"
echo "=== files ==="
ls -la /data/adb/box/sing-box/
echo "=== settings sidecar ==="
grep -E 'name_sing|sidecar_|bin_name' /data/adb/box/settings.ini
echo "=== dump redacted ==="
# redact passwords/keys from json for template base
yq -o=json '
(.outbounds[] | select(has("password")) | .password) = "REDACTED" |
(.outbounds[] | select(has("uuid")) | .uuid) = "REDACTED" |
(.outbounds[] | select(.tls.server_name != null) | .tls.server_name) = .tls.server_name
' "$CFG" 2>/dev/null | head -c 8000
echo
echo "=== route/dns/outbounds summary ==="
yq -r '"final=" + .route.final' "$CFG"
yq -r '.dns.servers[] | "dns:" + .tag + " type=" + .type + " detour=" + (.detour // "-")' "$CFG"
yq -r '.outbounds[] | "out:" + .tag + " type=" + .type + " port=" + ((.server_port // 0)|tostring)' "$CFG"
yq -r '.route.rules[] | "rule_out=" + (.outbound // .action // "?")' "$CFG" 2>/dev/null | head -20

55
tools/fix_active_cfg.sh Normal file
View File

@@ -0,0 +1,55 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
CFG="${sing_config}"
YQ=/data/adb/box/bin/yq
echo "ACTIVE_CFG=$CFG"
cp -f "$CFG" "${CFG}.bak-activedns-$(date +%Y%m%d_%H%M%S)"
"$YQ" -i -o=json '
.dns.servers = [
{"type":"https","tag":"dns-remote","detour":"sidecar-proxy","server":"1.1.1.1","path":"/dns-query"},
{"type":"https","tag":"dns-hy2","detour":"proxy","server":"1.1.1.1","path":"/dns-query"},
{"type":"udp","tag":"dns-direct","detour":"direct","server":"192.168.0.1"}
] |
.dns.rules = [] |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only" |
.dns.independent_cache = true
' "$CFG"
if ! "$YQ" -e '.route.rules[] | select(.ip_cidr[] == "13.140.17.163/32")' "$CFG" >/dev/null 2>&1; then
"$YQ" -i -o=json '.route.rules = [{"ip_cidr":["13.140.17.163/32"],"outbound":"direct"}] + .route.rules' "$CFG"
fi
"$YQ" -i -o=json 'del(.route.rules[] | select(.outbound == "wg-home"))' "$CFG" 2>/dev/null || true
echo "=== dns pre-start ==="
"$YQ" -o=json '.dns' "$CFG"
# Install updated sidecar script if present
if [ -f /data/local/tmp/box.sidecar ]; then
cp /data/local/tmp/box.sidecar /data/adb/box/scripts/box.sidecar
chmod 755 /data/adb/box/scripts/box.sidecar
echo "updated box.sidecar"
fi
sh /data/adb/box/scripts/box.service restart
sleep 4
echo "=== dns post-start (should stay https) ==="
"$YQ" -o=json '.dns.servers,.dns.final,.dns.strategy' "$CFG"
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
echo "cmdline: $(tr '\0' ' ' < /proc/$(pidof sing-box)/cmdline)"
for h in www.google.com ya.ru github.com 2ip.ru; do
echo "=== $h ==="
curl -m 18 -sS -o /dev/null -w "%{http_code} %{time_total}\n" "https://$h/" || true
sleep 1
done
echo "=== ip ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
echo "=== fails ==="
grep 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -8 || echo none
echo "=== doh dials ==="
grep -i '1.1.1.1' /data/adb/box/run/sing-box.log | tail -15

40
tools/fix_active_cfg2.sh Normal file
View File

@@ -0,0 +1,40 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
CFG="${sing_config}"
YQ=/data/adb/box/bin/yq
echo "ACTIVE_CFG=$CFG"
"$YQ" -i -o=json '
.dns.servers = [
{"type":"https","tag":"dns-remote","detour":"sidecar-proxy","server":"1.1.1.1","path":"/dns-query"},
{"type":"https","tag":"dns-hy2","detour":"proxy","server":"1.1.1.1","path":"/dns-query"}
] |
.dns.rules = [] |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only" |
.dns.independent_cache = true
' "$CFG"
if ! "$YQ" -e '.route.rules[] | select(.ip_cidr[] == "13.140.17.163/32")' "$CFG" >/dev/null 2>&1; then
"$YQ" -i -o=json '.route.rules = [{"ip_cidr":["13.140.17.163/32"],"outbound":"direct"}] + .route.rules' "$CFG"
fi
echo "=== dns ==="
"$YQ" -o=json '.dns' "$CFG"
sh /data/adb/box/scripts/box.service restart
sleep 4
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
"$YQ" -o=json '.dns.servers,.dns.final' "$CFG"
for h in www.google.com ya.ru github.com 2ip.ru; do
echo "=== $h ==="
curl -m 18 -sS -o /dev/null -w "%{http_code} %{time_total}\n" "https://$h/" || true
sleep 1
done
echo "=== ip ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
grep 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -6 || echo none
grep '1.1.1.1' /data/adb/box/run/sing-box.log | tail -12

51
tools/fix_active_cfg3.sh Normal file
View File

@@ -0,0 +1,51 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
CFG="${sing_config}"
YQ=/data/adb/box/bin/yq
echo "ACTIVE_CFG=$CFG"
echo "=== refs to dns-direct ==="
grep -n 'dns-direct\|domain_resolver' "$CFG" || true
"$YQ" -o=json '.. | select(has("domain_resolver"))' "$CFG" 2>/dev/null || true
"$YQ" -o=json '.outbounds' "$CFG" | head -c 2000; echo
# dns-direct as local (no empty direct detour); remote DoH via TT
"$YQ" -i -o=json '
.dns.servers = [
{"type":"local","tag":"dns-direct"},
{"type":"https","tag":"dns-remote","detour":"sidecar-proxy","server":"1.1.1.1","path":"/dns-query"},
{"type":"https","tag":"dns-hy2","detour":"proxy","server":"1.1.1.1","path":"/dns-query"}
] |
.dns.rules = [] |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only" |
.dns.independent_cache = true
' "$CFG"
if ! "$YQ" -e '.route.rules[] | select(.ip_cidr[] == "13.140.17.163/32")' "$CFG" >/dev/null 2>&1; then
"$YQ" -i -o=json '.route.rules = [{"ip_cidr":["13.140.17.163/32"],"outbound":"direct"}] + .route.rules' "$CFG"
fi
echo "=== dns ==="
"$YQ" -o=json '.dns' "$CFG"
sh /data/adb/box/scripts/box.service restart
sleep 4
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
if [ -z "$(pidof sing-box)" ]; then
echo "START FAILED"
tail -30 /data/adb/box/run/sing-box.log
exit 1
fi
for h in www.google.com ya.ru github.com 2ip.ru; do
echo "=== $h ==="
curl -m 18 -sS -o /dev/null -w "%{http_code} %{time_total}\n" "https://$h/" || true
sleep 1
done
echo "=== ip ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
grep 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -6 || echo none
grep 'outbound/socks.*1.1.1.1\|dns-remote\|exchange' /data/adb/box/run/sing-box.log | tail -20

43
tools/fix_dns_tcp.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/system/bin/sh
# Stabilize DNS: all resolution via TCP→SOCKS→1.1.1.1 (UDP53/direct often blocked; HTTPS-DoH via socks flaky)
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sing-box/config.json
YQ=/data/adb/box/bin/yq
TS=$(date +%Y%m%d_%H%M%S)
cp -f "$CFG" "/data/adb/box/sing-box/config.json.bak-dnsok-$TS"
"$YQ" -i -o=json '
.dns.servers = [
{"type":"tcp","tag":"dns-remote","detour":"sidecar-proxy","server":"1.1.1.1"},
{"type":"udp","tag":"dns-direct","detour":"direct","server":"192.168.0.1"},
{"type":"https","tag":"dns-doh-yandex","detour":"direct","server":"77.88.8.8","path":"/dns-query"}
] |
.dns.rules = [] |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only" |
.dns.independent_cache = true
' "$CFG"
# Keep TT endpoint direct
if ! "$YQ" -e '.route.rules[] | select(.ip_cidr[] == "13.140.17.163/32")' "$CFG" >/dev/null 2>&1; then
"$YQ" -i -o=json '.route.rules = [{"ip_cidr":["13.140.17.163/32"],"outbound":"direct"}] + .route.rules' "$CFG"
fi
"$YQ" -i -o=json 'del(.route.rules[] | select(.outbound == "wg-home"))' "$CFG" 2>/dev/null || true
echo "=== dns ==="
"$YQ" -o=json '.dns' "$CFG"
# Restart sing-box; sidecar inject will keep dns-remote detour on sidecar
sh /data/adb/box/scripts/box.service restart
sleep 4
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
for h in www.google.com ya.ru github.com 2ip.ru; do
echo "=== $h ==="
curl -m 15 -sS -o /dev/null -w "%{http_code} %{time_total}\n" "https://$h/" || true
done
echo "=== ip ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
echo "=== dns fail tail ==="
grep 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -5 || echo none

59
tools/fix_dns_tt.sh Normal file
View File

@@ -0,0 +1,59 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
YQ=/data/adb/box/bin/yq
CFG=/data/adb/box/sing-box/config.json
# backup
cp "$CFG" "/data/adb/box/sing-box/config.json.bak.$(date +%H%M%S)"
# 1) DNS remote must use sidecar-proxy, not old hysteria "proxy"
$YQ '(.dns.servers[] | select(.tag == "dns-remote") | .detour) = "sidecar-proxy"' -i --output-format=json "$CFG"
# 2) ensure dns-direct has no broken detour (use direct)
$YQ '(.dns.servers[] | select(.tag == "dns-direct") | .detour) = "direct"' -i --output-format=json "$CFG"
$YQ '(.dns.servers[] | select(.tag == "dns-backup-direct") | .detour) = "direct"' -i --output-format=json "$CFG"
# 3) TT endpoint must bypass proxy (anti-loop)
# add 13.140.17.163/32 to first ip_cidr direct rule if missing
if ! $YQ '.route.rules[] | select(.outbound == "direct") | .ip_cidr // [] | .[]' "$CFG" | grep -q '13.140.17.163'; then
$YQ '(.route.rules[] | select(.outbound == "direct" and (.ip_cidr | type) == "!!seq") | .ip_cidr) += ["13.140.17.163/32"]' -i --output-format=json "$CFG" 2>/dev/null || \
$YQ '.route.rules = [{"ip_cidr":["13.140.17.163/32"],"outbound":"direct"}] + .route.rules' -i --output-format=json "$CFG"
fi
# 4) remove broken wg-home rule (outbound missing)
$YQ 'del(.route.rules[] | select(.outbound == "wg-home"))' -i --output-format=json "$CFG"
# 5) final must stay sidecar
$YQ '.route.final = "sidecar-proxy"' -i --output-format=json "$CFG"
# ensure sidecar outbound exists
if ! $YQ '.outbounds[] | select(.tag == "sidecar-proxy")' "$CFG" | grep -q .; then
$YQ '.outbounds += [{"type":"socks","tag":"sidecar-proxy","server":"127.0.0.1","server_port":10800,"version":"5"}]' -i --output-format=json "$CFG"
fi
echo "=== DNS servers ==="
$YQ '.dns.servers' "$CFG"
echo "=== route.final ==="
$YQ '.route.final' "$CFG"
echo "=== direct ip rules (first) ==="
$YQ '[.route.rules[] | select(.outbound == "direct" and .ip_cidr)]' "$CFG" | head -40
# restart stack
sh /data/adb/box/scripts/box.iptables disable 2>/dev/null || true
sh /data/adb/box/scripts/box.service stop 2>/dev/null || true
kill -9 $(pidof trusttunnel_client) 2>/dev/null || true
kill -9 $(pidof sing-box) 2>/dev/null || true
sleep 2
sh /data/adb/box/scripts/box.service start
sleep 3
sh /data/adb/box/scripts/box.iptables enable
sleep 2
echo "=== PIDS tt=$(pidof trusttunnel_client) sb=$(pidof sing-box) ==="
echo "=== DNS TEST google ==="
curl -m 15 -sS -o /dev/null -w "google:%{http_code} time:%{time_total}\n" https://www.google.com/ 2>&1
echo "=== DNS TEST yandex ==="
curl -m 12 -sS -o /dev/null -w "yandex:%{http_code} time:%{time_total}\n" https://ya.ru/ 2>&1
echo "=== IP ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -5
curl -m 12 -sS https://ifconfig.me/ip 2>&1; echo

64
tools/fix_dns_v2.sh Normal file
View File

@@ -0,0 +1,64 @@
#!/system/bin/sh
# Fix DNS for BFR+TrustTunnel: ipv4_only, RU via direct, remote DoH via sidecar
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sing-box/config.json
YQ=/data/adb/box/bin/yq
TS=$(date +%Y%m%d_%H%M%S)
cp -f "$CFG" "/data/adb/box/sing-box/config.json.bak-dnsfix-$TS"
# Rebuild dns block: direct UDP for RU-ish, DoH via sidecar for rest
"$YQ" -i -o=json '
.dns.servers = [
{"type":"udp","tag":"dns-direct","detour":"direct","server":"77.88.8.8"},
{"type":"udp","tag":"dns-backup-direct","detour":"direct","server":"8.8.8.8"},
{"type":"https","tag":"dns-remote","detour":"sidecar-proxy","server":"1.1.1.1","path":"/dns-query"}
] |
.dns.rules = [
{"rule_set":"geosite-category-ru","server":"dns-direct"},
{"domain_suffix":[".ru",".su",".xn--p1ai"],"server":"dns-direct"},
{"rule_set":"geoip-ru","server":"dns-direct"}
] |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only" |
.dns.independent_cache = true
' "$CFG"
# Ensure TT server IP stays direct (anti-loop / keep tunnel up)
"$YQ" -i -o=json '
(.route.rules[] | select(.ip_cidr == ["13.140.17.163/32"]) | .outbound) = "direct"
' "$CFG" 2>/dev/null || true
# If rule missing, prepend it
if ! "$YQ" -e '.route.rules[] | select(.ip_cidr[] == "13.140.17.163/32")' "$CFG" >/dev/null 2>&1; then
"$YQ" -i -o=json '
.route.rules = [{"ip_cidr":["13.140.17.163/32"],"outbound":"direct"}] + .route.rules
' "$CFG"
fi
# Drop dead wg-home rule if present
"$YQ" -i -o=json 'del(.route.rules[] | select(.outbound == "wg-home"))' "$CFG" 2>/dev/null || true
echo "=== dns after ==="
"$YQ" -o=json '.dns' "$CFG"
echo "=== restart stack ==="
sh /data/adb/box/scripts/box.service stop || true
killall trusttunnel_client 2>/dev/null || true
sleep 1
sh /data/adb/box/scripts/box.service start
sleep 3
sh /data/adb/box/scripts/box.iptables renew
sleep 2
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
echo "=== google ==="
curl -m 20 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://www.google.com/ || true
echo "=== yandex ==="
curl -m 15 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://ya.ru/ || true
echo "=== github ==="
curl -m 20 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://github.com/ || true
echo "=== ip ==="
curl -m 15 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc|colo)=' || true
echo "=== dns errs (last) ==="
grep -i 'dns: exchange failed' /data/adb/box/run/sing-box.log | tail -5 || true

40
tools/fix_doh_debug.sh Normal file
View File

@@ -0,0 +1,40 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sing-box/config.json
YQ=/data/adb/box/bin/yq
# Use HTTPS DoH via sidecar (port 443 — TT allows this; TCP/53 often blocked by SOCKS policy)
# Also try DoH via legacy hysteria outbound as fallback dns-hy2
"$YQ" -i -o=json '
.dns.servers = [
{"type":"https","tag":"dns-remote","detour":"sidecar-proxy","server":"1.1.1.1","path":"/dns-query"},
{"type":"https","tag":"dns-hy2","detour":"proxy","server":"1.1.1.1","path":"/dns-query"},
{"type":"udp","tag":"dns-direct","detour":"direct","server":"192.168.0.1"}
] |
.dns.rules = [] |
.dns.final = "dns-remote" |
.dns.strategy = "ipv4_only" |
.dns.independent_cache = true |
.log.level = "debug"
' "$CFG"
# Restart quietly
sh /data/adb/box/scripts/box.service restart
sleep 5
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
echo "=== dns cfg ==="
"$YQ" -o=json '.dns.servers,.dns.final,.dns.strategy' "$CFG"
# One hostname at a time with pauses
sleep 2
echo "=== google ==="
curl -m 20 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://www.google.com/ 2>&1 || true
sleep 2
echo "=== ya ==="
curl -m 15 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://ya.ru/ 2>&1 || true
sleep 2
echo "=== github ==="
curl -m 15 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://github.com/ 2>&1 || true
echo "=== dial/dns debug lines ==="
grep -iE 'dns-remote|dns:|sidecar|1\.1\.1\.1|exchange' /data/adb/box/run/sing-box.log | tail -40

80
tools/fix_olc_room.sh Normal file
View File

@@ -0,0 +1,80 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sidecar/olcrtc.yaml
cp -f "$CFG" "${CFG}.bak-$(date +%H%M%S)"
# Normalize telemost room.id: full URL -> trailing numeric id
python3 - <<'PY' 2>/dev/null || true
import re, pathlib
p = pathlib.Path("/data/adb/box/sidecar/olcrtc.yaml")
t = p.read_text(encoding="utf-8")
m = re.search(r'(room:\s*\n\s*id:\s*")([^"]+)(")', t)
if m:
rid = m.group(2)
num = re.search(r'(\d{8,})', rid)
if num and rid != num.group(1):
t2 = t[:m.start(2)] + num.group(1) + t[m.end(2):]
p.write_text(t2, encoding="utf-8")
print("normalized_room_id_len", len(num.group(1)))
else:
print("room_id_unchanged_len", len(rid))
else:
print("room_id_not_found")
PY
# Fallback without python: busybox sed extract
if ! grep -q 'normalized_room' /proc/self/fd/0 2>/dev/null; then
rid=$(sed -n 's/.*id: *"\([^"]*\)".*/\1/p' "$CFG" | head -1)
case "$rid" in
http*|https*)
num=$(echo "$rid" | grep -oE '[0-9]{8,}' | tail -1)
if [ -n "$num" ]; then
# replace id line
sed -i "s|id: \".*\"|id: \"$num\"|" "$CFG"
echo "sed_normalized_to_len=${#num}"
fi
;;
*)
echo "room_already_plain_len=${#rid}"
;;
esac
fi
# Prefer RU DNS for telemost bootstrap (8.8.8.8 often blocked)
sed -i 's|dns: "8.8.8.8:53"|dns: "77.88.8.8:53"|' "$CFG"
echo "=== cfg shape ==="
grep -E 'provider:|transport:|port:|dns:|id:' "$CFG" | sed -E 's/(id: ").+/\1***"/'
echo "=== yandex reachability ==="
curl -m 12 -sS -o /dev/null -w "cloud-api %{http_code} %{time_total}\n" https://cloud-api.yandex.ru/ || true
echo "=== restart olcrtc ==="
killall olcrtc 2>/dev/null || true
mkdir -p /data/adb/box/run/olcrtc-data
: > /data/adb/box/run/olcrtc.log
nohup busybox setuidgid root:net_admin /data/adb/box/bin/olcrtc "$CFG" >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo "pid=$!"
i=0
while [ $i -lt 90 ]; do
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then
echo "10801_open after ${i}s"
break
fi
# bail early if process died
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then
echo "olcrtc_exited early at ${i}s"
break
fi
sleep 1
i=$((i+1))
done
busybox nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
echo "=== log ==="
tail -50 /data/adb/box/run/olcrtc.log
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then
echo "=== socks test ==="
curl -x socks5://127.0.0.1:10801 -m 30 -sS https://1.1.1.1/cdn-cgi/trace | grep -E '^(ip|loc)=' || true
fi

58
tools/fix_olc_yq.sh Normal file
View File

@@ -0,0 +1,58 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== raw id line ==="
grep -n 'id:' /data/adb/box/sidecar/olcrtc.yaml | head -5
echo "=== hexdump id vicinity ==="
grep -n 'id:' /data/adb/box/sidecar/olcrtc.yaml | head -1
# show exact bytes of id value
sed -n '/room:/,/crypto:/p' /data/adb/box/sidecar/olcrtc.yaml | od -c | head -20
echo "=== force numeric id with yq/python ==="
YQ=/data/adb/box/bin/yq
if [ -x "$YQ" ]; then
old=$("$YQ" -r '.room.id' /data/adb/box/sidecar/olcrtc.yaml)
echo "old=$old"
num=$(echo "$old" | grep -oE '[0-9]{8,}' | tail -1)
echo "num=$num"
"$YQ" -i ".room.id = \"$num\"" /data/adb/box/sidecar/olcrtc.yaml
"$YQ" -i '.net.dns = "77.88.8.8:53"' /data/adb/box/sidecar/olcrtc.yaml
echo "new=$("$YQ" -r '.room.id' /data/adb/box/sidecar/olcrtc.yaml)"
fi
# Clear olcrtc runtime cache
rm -rf /data/adb/box/run/olcrtc-data
mkdir -p /data/adb/box/run/olcrtc-data
# Add direct routes for telemost bootstrap if missing
CFG=/data/adb/box/sing-box/config-hy2-wg.json
"$YQ" -i -o=json '
.route.rules = (
[{"domain_suffix":["yandex.ru","yandex.net","yandex.com","ya.ru"],"outbound":"direct"}]
+ [.route.rules[] | select(.domain_suffix != ["yandex.ru","yandex.net","yandex.com","ya.ru"])]
)
' "$CFG" 2>/dev/null || true
# Restart sing-box briefly to apply route, keep TT
kill -HUP "$(pidof sing-box)" 2>/dev/null || true
sleep 1
# soft reload may not reload route; restart service is safer but heavy — kill/start sing-box only
# Use full renew
sh /data/adb/box/scripts/box.service restart
sleep 6
echo "=== start olcrtc after stack ==="
killall olcrtc 2>/dev/null || true
: > /data/adb/box/run/olcrtc.log
nohup busybox setuidgid root:net_admin /data/adb/box/bin/olcrtc /data/adb/box/sidecar/olcrtc.yaml >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo pid=$!
i=0
while [ $i -lt 75 ]; do
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then echo open_at_$i; break; fi
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then echo dead_at_$i; break; fi
sleep 1; i=$((i+1))
done
busybox nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
tail -30 /data/adb/box/run/olcrtc.log
# Show what URL it tried
grep -o 'conferences/[^/]*' /data/adb/box/run/olcrtc.log | tail -3

33
tools/fix_ru_dns.sh Normal file
View File

@@ -0,0 +1,33 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
YQ=/data/adb/box/bin/yq
CFG=/data/adb/box/sing-box/config.json
# RU DNS also via sidecar DoH — route rules still send .ru traffic direct after resolve
# (old dns-direct to 77.88.8.8 was timing out under tproxy)
$YQ '(.dns.rules[] | .server) = "dns-remote"' -i --output-format=json "$CFG"
$YQ '.dns.final = "dns-remote"' -i --output-format=json "$CFG"
echo "DNS rules now:"
$YQ '.dns.rules' "$CFG"
$YQ '.dns.final' "$CFG"
# reload sing-box without killing TT if possible
kill -15 $(pidof sing-box) 2>/dev/null
sleep 1
kill -9 $(pidof sing-box) 2>/dev/null
sleep 1
# start only core
sh /data/adb/box/scripts/box.service start
sleep 2
sh /data/adb/box/scripts/box.iptables renew >/dev/null 2>&1
echo "tt=$(pidof trusttunnel_client) sb=$(pidof sing-box)"
echo "=== google ==="
curl -m 12 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://www.google.com/
echo "=== yandex ==="
curl -m 12 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://ya.ru/
echo "=== 2ip ==="
curl -m 12 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://2ip.ru/
echo "=== ip ==="
curl -m 10 -sS https://1.1.1.1/cdn-cgi/trace | head -4

View File

@@ -0,0 +1,53 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
YQ=/data/adb/box/bin/yq
CFG=/data/adb/box/sing-box/config.json
echo "Before:"
$YQ '.outbounds[].tag' "$CFG"
$YQ '.route.final' "$CFG"
# inject if missing
if ! $YQ '.outbounds[] | select(.tag == "sidecar-proxy")' "$CFG" | grep -q .; then
$YQ '.outbounds += [{"type":"socks","tag":"sidecar-proxy","server":"127.0.0.1","server_port":10800,"version":"5"}]' -i --output-format=json "$CFG"
echo INJECTED
else
echo ALREADY
fi
$YQ '.route.final = "sidecar-proxy"' -i --output-format=json "$CFG"
echo "After:"
$YQ '.outbounds[].tag' "$CFG"
$YQ '.route.final' "$CFG"
$YQ '.outbounds[] | select(.tag == "sidecar-proxy")' "$CFG"
# restart sing-box only (keep TT)
kill -15 $(pidof sing-box) 2>/dev/null
sleep 1
kill -9 $(pidof sing-box) 2>/dev/null
sleep 1
# ensure TT still up
if ! pidof trusttunnel_client >/dev/null; then
echo "TT dead, restarting"
/data/adb/box/bin/trusttunnel_client -s -c /data/adb/box/sidecar/trusttunnel.toml >> /data/adb/box/run/sidecar.log 2>&1 &
sleep 3
fi
# start sing-box with same prepare path
sh /data/adb/box/scripts/box.service start
sleep 2
sh /data/adb/box/scripts/box.iptables renew
echo "=== PIDS ==="
echo "tt=$(pidof trusttunnel_client)"
echo "sb=$(pidof sing-box)"
echo "=== FINAL CHECK IN CONFIG ==="
$YQ '.route.final' /data/adb/box/sing-box/config.json
$YQ '.outbounds[] | select(.tag == "sidecar-proxy") | .server_port' /data/adb/box/sing-box/config.json
echo "=== SYSTEM IP (should be TT exit) ==="
curl -m 15 -sS https://1.1.1.1/cdn-cgi/trace | head -6
echo "=== SOCKS IP ==="
curl -x socks5h://127.0.0.1:10800 -m 12 -sS https://1.1.1.1/cdn-cgi/trace | head -6

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""Build BFR Managervisible profiles (hyphen names) from live config."""
from __future__ import annotations
import copy
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
LIVE = ROOT / "phone_configs" / "live" / "config-hy2-wg.json"
OUT_LIVE = ROOT / "phone_configs" / "live"
OUT_REPO = ROOT / "box" / "sing-box"
def scrub_for_repo(cfg: dict) -> dict:
c = copy.deepcopy(cfg)
c.pop("endpoints", None)
for o in c.get("outbounds", []):
if "password" in o:
o["password"] = "YOUR_HYSTERIA2_PASSWORD"
if "uuid" in o:
o["uuid"] = "YOUR_UUID"
return c
def build(live: dict, final: str, *, scrub: bool) -> dict:
c = scrub_for_repo(live) if scrub else copy.deepcopy(live)
tags = {o.get("tag") for o in c.get("outbounds", [])}
extras = [
{
"type": "socks",
"tag": "sidecar-proxy",
"server": "127.0.0.1",
"server_port": 10800,
"version": "5",
},
{
"type": "socks",
"tag": "olcrtc-proxy",
"server": "127.0.0.1",
"server_port": 10801,
"version": "5",
},
]
for e in extras:
if e["tag"] not in tags:
c.setdefault("outbounds", []).append(e)
rules = []
for r in c.get("route", {}).get("rules", []):
if r.get("outbound") == "wg-home":
continue
rules.append(r)
if not any("yandex.ru" in (r.get("domain_suffix") or []) for r in rules):
rules.insert(
0,
{
"domain_suffix": ["yandex.ru", "yandex.net", "yandex.com", "ya.ru"],
"outbound": "direct",
},
)
if not any(
(isinstance(r.get("ip_cidr"), list) and "13.140.17.163/32" in r["ip_cidr"])
or r.get("ip_cidr") == "13.140.17.163/32"
for r in rules
):
rules.insert(0, {"ip_cidr": ["13.140.17.163/32"], "outbound": "direct"})
c.setdefault("route", {})["rules"] = rules
c["route"]["final"] = final
c["route"]["default_domain_resolver"] = "dns-direct"
c["route"]["auto_detect_interface"] = False
c["dns"] = {
"servers": [
{"type": "local", "tag": "dns-direct"},
{
"type": "https",
"tag": "dns-remote",
"detour": final,
"server": "1.1.1.1",
"path": "/dns-query",
},
],
"final": "dns-remote",
"strategy": "ipv4_only",
"independent_cache": True,
}
c.setdefault("log", {})["level"] = "info"
c["log"]["timestamp"] = True
return c
def write(path: Path, cfg: dict) -> None:
path.write_text(json.dumps(cfg, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
print(path, path.stat().st_size)
def main() -> None:
live = json.loads(LIVE.read_text(encoding="utf-8"))
OUT_LIVE.mkdir(parents=True, exist_ok=True)
OUT_REPO.mkdir(parents=True, exist_ok=True)
pairs = [
("config-trusttunnel.json", "sidecar-proxy"),
("config-olcrtc.json", "olcrtc-proxy"),
]
for name, final in pairs:
write(OUT_LIVE / name, build(live, final, scrub=False))
write(OUT_REPO / name, build(live, final, scrub=True))
# remove old dotted names from module templates if present
for old in ("config.trusttunnel.json", "config.olcrtc.json"):
p = OUT_REPO / old
if p.exists():
p.unlink()
print("removed", p)
if __name__ == "__main__":
main()

105
tools/gen_profiles.py Normal file
View File

@@ -0,0 +1,105 @@
import json
import copy
from pathlib import Path
live = json.loads(Path(r"E:\bfr_mod\phone_configs\live\config-hy2-wg.json").read_text(encoding="utf-8"))
def scrub(cfg):
c = copy.deepcopy(cfg)
# Do not ship WireGuard private keys in the module repo
c.pop("endpoints", None)
for o in c.get("outbounds", []):
if "password" in o:
o["password"] = "YOUR_HYSTERIA2_PASSWORD"
if "uuid" in o:
o["uuid"] = "YOUR_UUID"
rules = []
seen = set()
for r in c.get("route", {}).get("rules", []):
key = json.dumps(r, sort_keys=True)
if key in seen:
continue
seen.add(key)
if r.get("outbound") == "wg-home":
continue
rules.append(r)
c.setdefault("route", {})["rules"] = rules
tags = {o.get("tag") for o in c.get("outbounds", [])}
if "sidecar-proxy" not in tags:
c["outbounds"].append(
{
"type": "socks",
"tag": "sidecar-proxy",
"server": "127.0.0.1",
"server_port": 10800,
"version": "5",
}
)
if "olcrtc-proxy" not in tags:
c["outbounds"].append(
{
"type": "socks",
"tag": "olcrtc-proxy",
"server": "127.0.0.1",
"server_port": 10801,
"version": "5",
}
)
c["dns"] = {
"servers": [
{"type": "local", "tag": "dns-direct"},
{
"type": "https",
"tag": "dns-remote",
"detour": "PLACEHOLDER",
"server": "1.1.1.1",
"path": "/dns-query",
},
],
"final": "dns-remote",
"strategy": "ipv4_only",
"independent_cache": True,
}
c["route"]["default_domain_resolver"] = "dns-direct"
c["route"]["auto_detect_interface"] = False
return c
def apply_profile(cfg, final_tag):
c = scrub(cfg)
c["route"]["final"] = final_tag
for s in c["dns"]["servers"]:
if s.get("tag") == "dns-remote":
s["detour"] = final_tag
rules = c["route"]["rules"]
has_tt = any(
r.get("ip_cidr") in ("13.140.17.163/32", ["13.140.17.163/32"]) for r in rules
)
if not has_tt:
rules.insert(0, {"ip_cidr": ["13.140.17.163/32"], "outbound": "direct"})
has_ya = any("yandex.ru" in (r.get("domain_suffix") or []) for r in rules)
if not has_ya:
rules.insert(
0,
{
"domain_suffix": ["yandex.ru", "yandex.net", "yandex.com", "ya.ru"],
"outbound": "direct",
},
)
c.setdefault("log", {})["level"] = "info"
c["log"]["timestamp"] = True
return c
out = Path(r"E:\bfr_mod\box\sing-box")
tt = apply_profile(live, "sidecar-proxy")
olc = apply_profile(live, "olcrtc-proxy")
(out / "config.trusttunnel.json").write_text(
json.dumps(tt, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
)
(out / "config.olcrtc.json").write_text(
json.dumps(olc, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
)
print("tt final", tt["route"]["final"])
print("olc final", olc["route"]["final"])

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Build config-wg-obfs.json for BFR Manager from live hy2-wg (local secrets stay on device/live dir)."""
from __future__ import annotations
import copy
import json
from pathlib import Path
LIVE = Path(r"E:\bfr_mod\phone_configs\live\config-hy2-wg.json")
OUT_LIVE = Path(r"E:\bfr_mod\phone_configs\live\config-wg-obfs.json")
OUT_REPO = Path(r"E:\bfr_mod\box\sing-box\config-wg-obfs.json")
LISTEN = 41320
def scrub(cfg: dict) -> dict:
c = copy.deepcopy(cfg)
for ep in c.get("endpoints", []) or []:
if "private_key" in ep:
ep["private_key"] = "YOUR_WIREGUARD_PRIVATE_KEY"
for p in ep.get("peers", []) or []:
if "public_key" in p:
p["public_key"] = "YOUR_PEER_PUBLIC_KEY"
# keep structure but scrub host in repo template
if p.get("address") and p["address"] != "127.0.0.1":
p["_example_real_address"] = p["address"]
p["address"] = "127.0.0.1"
p["port"] = LISTEN
for o in c.get("outbounds", []):
if "password" in o:
o["password"] = "YOUR_HYSTERIA2_PASSWORD"
return c
def make_live(cfg: dict) -> dict:
c = copy.deepcopy(cfg)
for ep in c.get("endpoints", []) or []:
if ep.get("type") != "wireguard":
continue
for p in ep.get("peers", []) or []:
real_addr = p.get("address")
real_port = p.get("port")
if real_addr and real_addr != "127.0.0.1":
p["_veilbox_real_address"] = real_addr
p["_veilbox_real_port"] = real_port
p["address"] = "127.0.0.1"
p["port"] = LISTEN
# direct for real server
rules = c.setdefault("route", {}).setdefault("rules", [])
for ep in c.get("endpoints", []) or []:
for p in ep.get("peers", []) or []:
rip = p.get("_veilbox_real_address")
if rip and rip != "127.0.0.1":
cidr = f"{rip}/32"
if not any(cidr in (r.get("ip_cidr") or []) for r in rules):
rules.insert(0, {"ip_cidr": [cidr], "outbound": "direct"})
return c
def main() -> None:
if not LIVE.exists():
raise SystemExit(f"missing {LIVE}")
live = json.loads(LIVE.read_text(encoding="utf-8"))
OUT_LIVE.parent.mkdir(parents=True, exist_ok=True)
OUT_REPO.parent.mkdir(parents=True, exist_ok=True)
OUT_LIVE.write_text(json.dumps(make_live(live), indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
OUT_REPO.write_text(json.dumps(scrub(live), indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
print("wrote", OUT_LIVE)
print("wrote", OUT_REPO)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,41 @@
#!/system/bin/sh
# Install BFR Manager profiles + enable both sidecars for UI switching
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
INI=/data/adb/box/settings.ini
SB=/data/adb/box/sing-box
SCR=/data/adb/box/scripts
cp -f /sdcard/Download/config-trusttunnel.json "$SB/config-trusttunnel.json"
cp -f /sdcard/Download/config-olcrtc.json "$SB/config-olcrtc.json"
cp -f /sdcard/Download/box.sidecar "$SCR/box.sidecar"
cp -f /sdcard/Download/box.profile "$SCR/box.profile"
sed -i 's/\r$//' "$SCR/box.sidecar" "$SCR/box.profile"
chmod 700 "$SCR/box.sidecar" "$SCR/box.profile"
# BFR Manager flip: both SOCKS up, do not overwrite profile finals
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' "$INI"
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="both"/' "$INI"
sed -i 's/^sidecar_set_final=.*/sidecar_set_final="false"/' "$INI"
grep -q '^sidecar_tt_port=' "$INI" || echo 'sidecar_tt_port="10800"' >> "$INI"
grep -q '^sidecar_olc_port=' "$INI" || echo 'sidecar_olc_port="10801"' >> "$INI"
grep -q '^sidecar_olc_tag=' "$INI" || echo 'sidecar_olc_tag="olcrtc-proxy"' >> "$INI"
# Keep current active if already hy2-wg; user picks TT/olcrtc in app
# Optional: leave name_sing_config as-is
chown root:net_admin "$SB/config-trusttunnel.json" "$SB/config-olcrtc.json" 2>/dev/null || true
chmod 644 "$SB/config-trusttunnel.json" "$SB/config-olcrtc.json"
echo "=== sing-box profiles ==="
ls -la "$SB"/config*.json
echo "=== sidecar settings ==="
grep -E '^name_sing|^sidecar_' "$INI"
echo "=== restart ==="
/data/adb/box/scripts/box.service restart
sleep 3
/data/adb/box/scripts/box.iptables renew >/dev/null 2>&1 || true
echo "tt=$(pidof trusttunnel_client) olc=$(pidof olcrtc) sb=$(pidof sing-box)"
echo "final=$(/data/adb/box/bin/yq -r '.route.final' "$SB/$(grep '^name_sing_config=' "$INI" | cut -d\" -f2)")"
busybox nc -z 127.0.0.1 10800 && echo 10800_open || echo 10800_closed
busybox nc -z 127.0.0.1 10801 && echo 10801_open || echo 10801_closed

View File

@@ -0,0 +1,67 @@
#!/system/bin/sh
set -e
ZIP=/sdcard/Download/box_for_root-v1.10.2-stealth.1.zip
TMP=/data/local/tmp/bfr_stealth_install
rm -rf "$TMP"
mkdir -p "$TMP"
cd "$TMP"
unzip -o "$ZIP" >/dev/null
MOD=/data/adb/modules/box_for_root
mkdir -p "$MOD" "$MOD/system/bin" "$MOD/webroot"
cp -f module.prop customize.sh uninstall.sh action.sh "$MOD/"
cp -f sbfr "$MOD/system/bin/sbfr"
cp -rf webroot/. "$MOD/webroot/" 2>/dev/null || true
mkdir -p /data/adb/service.d
cp -f box_service.sh /data/adb/service.d/box_service.sh
chmod 755 /data/adb/service.d/box_service.sh "$MOD/uninstall.sh" "$MOD/system/bin/sbfr"
mkdir -p /data/adb/box/scripts /data/adb/box/sidecar /data/adb/box/run /data/adb/box/sing-box
cp -f box/scripts/* /data/adb/box/scripts/
chmod 700 /data/adb/box/scripts/*
cp -f box/sidecar/* /data/adb/box/sidecar/ 2>/dev/null || true
cp -f box/sing-box/config.stealth.example.json /data/adb/box/sing-box/ 2>/dev/null || true
if ! grep -q '^stealth_mode=' /data/adb/box/settings.ini; then
echo "Appending stealth+sidecar settings"
cat >> /data/adb/box/settings.ini <<'EOF'
# -----------------------------------------------------------------
# BFR Stealth — anti-detection without LSPosed (iptables port-hide)
# -----------------------------------------------------------------
stealth_mode="true"
stealth_hide_loopback="true"
stealth_block_external_api="true"
stealth_disable_api="true"
stealth_api_bind="127.0.0.1"
stealth_api_port="19090"
stealth_block_quic="false"
stealth_forbid_tun="true"
stealth_extra_ports=("7890" "7891" "1080" "10808" "2080")
stealth_config=$(dirname "$settings")/stealth.list.cfg
[ -d "${stealth_config}" ] && rm -rf "${stealth_config}"
[ ! -f "${stealth_config}" ] && cat > "${stealth_config}"<<'stealth_init'
# Apps that scan for localhost proxy / VPN (one package per line)
stealth_init
stealth_packages_list=($(sed -n '/^[^#]/s/^\([^ ]*\.[^ ]*\).*/\1/p' ${stealth_config}))
sidecar_enable="false"
sidecar_protocol=""
sidecar_listen_port="10800"
sidecar_outbound_tag="sidecar-proxy"
sidecar_set_final="true"
sidecar_dir="${box_dir}/sidecar"
EOF
fi
chown -R root:net_admin /data/adb/box
chmod 755 /data/adb/box/scripts/*
rm -f "$MOD/disable"
echo INSTALL_OK
cat "$MOD/module.prop"
ls /data/adb/box/scripts/box.stealth /data/adb/box/scripts/box.sidecar
test -f /data/adb/box/sing-box/config.json && echo CONFIG_PRESERVED
test -x /data/adb/box/bin/sing-box && echo BIN_PRESERVED || ls /data/adb/box/bin/
grep -q '^stealth_mode=' /data/adb/box/settings.ini && echo STEALTH_KEYS_OK
rm -rf "$TMP"

57
tools/install_wgobfs.sh Normal file
View File

@@ -0,0 +1,57 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
BIN=/data/adb/box/bin
SC=/data/adb/box/sidecar
SB=/data/adb/box/sing-box
SCR=/data/adb/box/scripts
cp -f /data/local/tmp/wg-obfuscator "$BIN/wg-obfuscator"
chmod 755 "$BIN/wg-obfuscator"
"$BIN/wg-obfuscator" -V 2>&1 | head -2 || true
cp -f /data/local/tmp/box.wgobfs "$SCR/box.wgobfs"
cp -f /data/local/tmp/box.service "$SCR/box.service"
cp -f /data/local/tmp/box.profile "$SCR/box.profile"
cp -f /data/local/tmp/box.tool "$SCR/box.tool"
sed -i 's/\r$//' "$SCR/box.wgobfs" "$SCR/box.service" "$SCR/box.profile" "$SCR/box.tool"
chmod 700 "$SCR/box.wgobfs" "$SCR/box.service" "$SCR/box.profile" "$SCR/box.tool"
cp -f /data/local/tmp/wg-obfuscator.example.conf "$SC/wg-obfuscator.example.conf"
cp -f /data/local/tmp/wg-obfuscator.server.example.conf "$SC/wg-obfuscator.server.example.conf"
cp -f /data/local/tmp/config-wg-obfs.json "$SB/config-wg-obfs.json"
chown root:net_admin "$SB/config-wg-obfs.json" 2>/dev/null || true
chmod 644 "$SB/config-wg-obfs.json"
# Seed client conf once (do not overwrite existing key)
if [ ! -f "$SC/wg-obfuscator.conf" ]; then
cat > "$SC/wg-obfuscator.conf" <<'EOF'
[client]
source-if = 127.0.0.1
source-lport = 41320
target = 188.120.251.220:13232
key = CHANGE_ME_WG_OBFS_KEY
masking = STUN
verbose = INFO
EOF
echo "CREATED $SC/wg-obfuscator.conf — set key= to match VPS"
else
echo "keep existing $SC/wg-obfuscator.conf"
fi
# Ensure settings keys exist (disabled until VPS ready)
INI=/data/adb/box/settings.ini
grep -q '^wgobfs_enable=' "$INI" || echo 'wgobfs_enable="false"' >> "$INI"
grep -q '^wgobfs_listen_port=' "$INI" || echo 'wgobfs_listen_port="41320"' >> "$INI"
grep -q '^wgobfs_patch_config=' "$INI" || echo 'wgobfs_patch_config="true"' >> "$INI"
grep -q '^wgobfs_config=' "$INI" || echo 'wgobfs_config="${box_dir}/sidecar/wg-obfuscator.conf"' >> "$INI"
grep -q '^wgobfs_bin=' "$INI" || echo 'wgobfs_bin="${box_dir}/bin/wg-obfuscator"' >> "$INI"
echo "=== installed ==="
ls -la "$BIN/wg-obfuscator" "$SB/config-wg-obfs.json" "$SC/wg-obfuscator.conf" "$SCR/box.wgobfs"
echo
echo "NEXT:"
echo "1) On VPS: install wg-obfuscator, wrap WG port, SAME key"
echo "2) Edit $SC/wg-obfuscator.conf key=..."
echo "3) BFR Manager → Manage Profiles → config-wg-obfs.json"
echo " (auto-starts wgobfs) OR: sed -i 's/wgobfs_enable=.*/wgobfs_enable=\"true\"/' $INI && box.service restart"

20
tools/olc_diag2.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
URL='https://cloud-api.yandex.ru/telemost_front/v2/telemost/conferences/https%3A%2F%2Ftelemost.yandex.ru%2Fj%2F41001894292350/connection?display_name=test&next_gen_media_platform_allowed=true&waiting_room_supported=true'
echo "=== curl as root:net_admin ==="
busybox setuidgid root:net_admin curl -m 20 -sS -o /tmp/tm.json -w "%{http_code} %{time_total}\n" \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0' \
-H 'Accept: */*' \
-H 'Origin: https://telemost.yandex.ru' \
-H 'Referer: https://telemost.yandex.ru/' \
-H 'X-Telemost-Client-Version: 187.1.0' \
"$URL" || true
head -c 200 /tmp/tm.json; echo
echo "=== openssl/s_client quick ==="
echo | busybox timeout 8 openssl s_client -connect 213.180.204.127:443 -servername cloud-api.yandex.ru 2>&1 | head -20
echo "=== verify binary has our patch strings ==="
strings /data/adb/box/bin/olcrtc | grep -E 'ForceAttempt|Magisk/su|Prefer IPv4' | head
# show build id / size
ls -la /data/adb/box/bin/olcrtc

19
tools/olc_http1.sh Normal file
View File

@@ -0,0 +1,19 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sidecar/olcrtc.yaml
killall olcrtc 2>/dev/null || true
: > /data/adb/box/run/olcrtc.log
nohup env \
GODEBUG=http2client=0 \
-u all_proxy -u ALL_PROXY -u http_proxy -u https_proxy -u HTTP_PROXY -u HTTPS_PROXY \
busybox setuidgid root:net_admin /data/adb/box/bin/olcrtc "$CFG" >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo pid=$!
i=0
while [ $i -lt 45 ]; do
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then echo OPEN_at_$i; break; fi
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then echo DEAD_at_$i; break; fi
sleep 1; i=$((i+1))
done
busybox nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
tail -40 /data/adb/box/run/olcrtc.log

27
tools/olc_notproxy.sh Normal file
View File

@@ -0,0 +1,27 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sidecar/olcrtc.yaml
killall olcrtc 2>/dev/null || true
echo "=== disable tproxy temporarily ==="
sh /data/adb/box/scripts/box.iptables disable
sleep 1
: > /data/adb/box/run/olcrtc.log
nohup env -u all_proxy -u ALL_PROXY -u http_proxy -u https_proxy -u HTTP_PROXY -u HTTPS_PROXY \
busybox setuidgid root:net_admin /data/adb/box/bin/olcrtc "$CFG" >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo pid=$!
i=0
while [ $i -lt 45 ]; do
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then echo OPEN_at_$i; break; fi
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then echo DEAD_at_$i; break; fi
sleep 1; i=$((i+1))
done
busybox nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
tail -40 /data/adb/box/run/olcrtc.log
echo "=== re-enable tproxy ==="
sh /data/adb/box/scripts/box.iptables enable
sleep 2
curl -m 12 -sS -o /dev/null -w "google_after %{http_code}\n" https://www.google.com/ || true

View File

@@ -0,0 +1,14 @@
# Local patch applied when building olcrtc for Magisk/Android sidecar
#
# File: internal/protect/protect.go
#
# 1) Load Android system CA store into tls.Config.RootCAs
# (/system/etc/security/cacerts, /apex/com.android.conscrypt/cacerts)
# Static linux/arm64 Go binaries have an empty SystemCertPool on Android.
#
# 2) Prefer IPv4 dials; disable env HTTP(S)_PROXY / ALL_PROXY; ForceAttemptHTTP2=false
#
# 3) On device, prefer net.dns = LAN resolver (e.g. 192.168.0.1:53).
# PreferGo UDP to 8.8.8.8 / 77.88.8.8 as root:net_admin can hang on some phones.
#
# Rebuild: powershell -File tools/build_olcrtc_arm64.ps1

11
tools/phone_state.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/system/bin/sh
uname -m
getprop ro.product.cpu.abi
echo "=== bin ==="
ls -la /data/adb/box/bin/ | head -40
echo "=== sidecar ==="
ls -la /data/adb/box/sidecar/
echo "=== settings sidecar ==="
grep -E 'sidecar_|olcrtc|trusttunnel' /data/adb/box/settings.ini
echo "=== packages rkn ==="
pm list packages 2>/dev/null | grep -iE 'rkn|harden|detect|vpn' || true

18
tools/probe_tt3.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:$PATH"
echo "alive=$(pidof trusttunnel_client)"
# check listening: port 10800 = 0x2A30 -> little endian in /proc = 302A0000?
# actually format is hex IP:PORT where PORT is big-endian hex
# 10800 = 0x2A30
grep -E ':2A30 ' /proc/net/tcp /proc/net/tcp6 2>/dev/null && echo PORT_10800_LISTEN
# try magisk busybox wget/curl
which curl; which busybox
if command -v curl >/dev/null; then
curl -x socks5h://127.0.0.1:10800 -m 20 -sS https://1.1.1.1/cdn-cgi/trace | head -5
elif [ -x /data/adb/box/bin/curl ]; then
/data/adb/box/bin/curl -x socks5h://127.0.0.1:10800 -m 20 -sS https://1.1.1.1/cdn-cgi/trace | head -5
else
# minimal SOCKS5 handshake via toybox/dd? skip
echo "NO_CURL — checking CONNECTED in log"
grep 'Successfully connected' /data/adb/box/run/sidecar.log | tail -3
fi

12
tools/probe_tt_socks.sh Normal file
View File

@@ -0,0 +1,12 @@
#!/system/bin/sh
echo "alive=$(pidof trusttunnel_client)"
# test SOCKS with curl if present
CURL=/data/adb/box/bin/curl
if [ -x "$CURL" ]; then
"$CURL" -x socks5h://127.0.0.1:10800 -m 15 -sS https://ifconfig.me/ip && echo
echo CURL_EXIT=$?
else
echo no_curl
fi
# show recent connected status
grep -E 'Successfully connected|VPN_SS_CONNECTED|Listening on 127.0.0.1:10800|ERROR' /data/adb/box/run/sidecar.log | tail -15

View File

@@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""Build real (secret-bearing) profiles from phone live config and optional adb push."""
from __future__ import annotations
import argparse
import copy
import json
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
LIVE = ROOT / "phone_configs" / "live" / "config-hy2-wg.json"
OUT = ROOT / "phone_configs" / "live"
ADB = Path(r"C:\Program Files\SuperDisplay\adb\adb.exe")
def build(final: str) -> dict:
cfg = json.loads(LIVE.read_text(encoding="utf-8"))
c = copy.deepcopy(cfg)
tags = {o.get("tag") for o in c.get("outbounds", [])}
if "sidecar-proxy" not in tags:
c["outbounds"].append(
{
"type": "socks",
"tag": "sidecar-proxy",
"server": "127.0.0.1",
"server_port": 10800,
"version": "5",
}
)
if "olcrtc-proxy" not in tags:
c["outbounds"].append(
{
"type": "socks",
"tag": "olcrtc-proxy",
"server": "127.0.0.1",
"server_port": 10801,
"version": "5",
}
)
# drop dead wg-home rules
rules = []
for r in c.get("route", {}).get("rules", []):
if r.get("outbound") == "wg-home":
continue
rules.append(r)
# ensure yandex + TT IP direct
if not any("yandex.ru" in (r.get("domain_suffix") or []) for r in rules):
rules.insert(
0,
{
"domain_suffix": ["yandex.ru", "yandex.net", "yandex.com", "ya.ru"],
"outbound": "direct",
},
)
if not any(
(isinstance(r.get("ip_cidr"), list) and "13.140.17.163/32" in r["ip_cidr"])
or r.get("ip_cidr") == "13.140.17.163/32"
for r in rules
):
rules.insert(0, {"ip_cidr": ["13.140.17.163/32"], "outbound": "direct"})
c.setdefault("route", {})["rules"] = rules
c["route"]["final"] = final
c["route"]["default_domain_resolver"] = "dns-direct"
c["route"]["auto_detect_interface"] = False
c["dns"] = {
"servers": [
{"type": "local", "tag": "dns-direct"},
{
"type": "https",
"tag": "dns-remote",
"detour": final,
"server": "1.1.1.1",
"path": "/dns-query",
},
],
"final": "dns-remote",
"strategy": "ipv4_only",
"independent_cache": True,
}
c.setdefault("log", {})["level"] = "info"
c["log"]["timestamp"] = True
return c
def adb(*args: str) -> None:
cmd = [str(ADB), *args]
print("+", " ".join(cmd))
subprocess.check_call(cmd)
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--push", action="store_true", help="adb push to /data/adb/box/sing-box/")
ap.add_argument("--use", choices=["trusttunnel", "olcrtc"], help="switch profile on device")
args = ap.parse_args()
if not LIVE.exists():
raise SystemExit(f"missing {LIVE}")
tt = build("sidecar-proxy")
ol = build("olcrtc-proxy")
OUT.mkdir(parents=True, exist_ok=True)
tt_path = OUT / "config.trusttunnel.json"
ol_path = OUT / "config.olcrtc.json"
tt_path.write_text(json.dumps(tt, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
ol_path.write_text(json.dumps(ol, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
print("wrote", tt_path)
print("wrote", ol_path)
if args.push or args.use:
for p in (tt_path, ol_path):
adb("push", str(p), "/sdcard/Download/" + p.name)
adb(
"shell",
"su",
"-c",
"cp -f /sdcard/Download/config.trusttunnel.json /data/adb/box/sing-box/ && "
"cp -f /sdcard/Download/config.olcrtc.json /data/adb/box/sing-box/ && "
"cp -f /data/local/tmp/box.profile /data/adb/box/scripts/box.profile 2>/dev/null; "
"chmod 700 /data/adb/box/scripts/box.profile 2>/dev/null; "
"ls -l /data/adb/box/sing-box/config.trusttunnel.json /data/adb/box/sing-box/config.olcrtc.json",
)
if args.use:
# also push profile script
profile = ROOT / "box" / "scripts" / "box.profile"
adb("push", str(profile), "/sdcard/Download/box.profile")
adb(
"shell",
"su",
"-c",
"cp -f /sdcard/Download/box.profile /data/adb/box/scripts/box.profile && "
"chmod 700 /data/adb/box/scripts/box.profile && "
"sed -i 's/\\r$//' /data/adb/box/scripts/box.profile && "
f"/data/adb/box/scripts/box.profile use {args.use}",
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,42 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:/system/bin:$PATH"
set -x
# clean restart
/data/adb/box/scripts/box.iptables disable 2>/dev/null || true
/data/adb/box/scripts/box.service stop 2>/dev/null || true
pkill -9 trusttunnel_client 2>/dev/null || true
pkill -9 sing-box 2>/dev/null || true
sleep 1
# ensure sidecar settings
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="trusttunnel"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10800"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_set_final=.*/sidecar_set_final="true"/' /data/adb/box/settings.ini
sed -i 's/^bin_name=.*/bin_name="sing-box"/' /data/adb/box/settings.ini
sed -i 's/^network_mode=.*/network_mode="tproxy"/' /data/adb/box/settings.ini
# start service (includes sidecar)
/data/adb/box/scripts/box.service start
echo "SERVICE_EXIT=$?"
sleep 2
/data/adb/box/scripts/box.iptables enable
echo "IPTABLES_EXIT=$?"
echo "=== STATUS ==="
pidof trusttunnel_client && echo TT_OK || echo TT_FAIL
pidof sing-box && echo SB_OK || echo SB_FAIL
grep -E ':2A30 ' /proc/net/tcp && echo SOCKS_OK || echo SOCKS_FAIL
echo "=== SIDECAR LOG TAIL ==="
tail -n 25 /data/adb/box/run/sidecar.log 2>/dev/null
echo "=== SING-BOX LOG TAIL ==="
tail -n 25 /data/adb/box/run/sing-box.log 2>/dev/null
echo "=== RUNS LOG TAIL ==="
tail -n 30 /data/adb/box/run/runs.log 2>/dev/null
echo "=== PROXY IP TEST ==="
curl -x socks5h://127.0.0.1:10800 -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -6
echo "=== SYSTEM IP TEST (via tproxy if up) ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -6

View File

@@ -0,0 +1,37 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/ksu/bin:/system/bin:$PATH"
sh /data/adb/box/scripts/box.iptables disable 2>/dev/null || true
sh /data/adb/box/scripts/box.service stop 2>/dev/null || true
kill -9 $(pidof trusttunnel_client) 2>/dev/null || true
kill -9 $(pidof sing-box) 2>/dev/null || true
sleep 2
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="trusttunnel"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10800"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_set_final=.*/sidecar_set_final="true"/' /data/adb/box/settings.ini
echo "=== START SERVICE ==="
sh /data/adb/box/scripts/box.service start
echo "SERVICE_EXIT=$?"
sleep 3
echo "=== ENABLE IPTABLES ==="
sh /data/adb/box/scripts/box.iptables enable
echo "IPTABLES_EXIT=$?"
sleep 2
echo "=== PIDS ==="
echo "tt=$(pidof trusttunnel_client)"
echo "sb=$(pidof sing-box)"
grep -E ':2A30 ' /proc/net/tcp && echo SOCKS_LISTEN || echo SOCKS_MISSING
echo "=== SIDECAR TAIL ==="
tail -n 20 /data/adb/box/run/sidecar.log
echo "=== RUNS TAIL ==="
tail -n 25 /data/adb/box/run/runs.log
echo "=== SOCKS IP ==="
curl -x socks5h://127.0.0.1:10800 -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -6
echo "=== SYSTEM IP ==="
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | head -6

11
tools/retest_tt.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/system/bin/sh
cp /sdcard/Download/trusttunnel.toml /data/adb/box/sidecar/trusttunnel.toml
chmod 600 /data/adb/box/sidecar/trusttunnel.toml
pkill -9 trusttunnel_client 2>/dev/null
: > /data/adb/box/run/sidecar.log
/data/adb/box/bin/trusttunnel_client -c /data/adb/box/sidecar/trusttunnel.toml >> /data/adb/box/run/sidecar.log 2>&1 &
echo "PID=$!"
sleep 4
echo "pidof=$(busybox pidof trusttunnel_client)"
busybox netstat -lntp 2>/dev/null | grep 10800 || true
grep -E 'ERROR|Listening|CONNECTED|DISCONNECTED|Using endpoint|Successfully' /data/adb/box/run/sidecar.log | tail -30

22
tools/retest_tt2.sh Normal file
View File

@@ -0,0 +1,22 @@
#!/system/bin/sh
grep skip_verification /data/adb/box/sidecar/trusttunnel.toml
pkill -9 trusttunnel_client 2>/dev/null
sleep 1
: > /data/adb/box/run/sidecar.log
# use -s to skip cert verify
/data/adb/box/bin/trusttunnel_client -s -c /data/adb/box/sidecar/trusttunnel.toml >> /data/adb/box/run/sidecar.log 2>&1 &
echo "PID=$!"
sleep 5
PIDOF=$(pidof trusttunnel_client)
echo "pidof=$PIDOF"
cat /proc/net/tcp | head -1
# 10800 = 0x2A30 little endian in /proc/net/tcp = 302A
grep -i '302A' /proc/net/tcp /proc/net/tcp6 2>/dev/null || true
grep -E 'ERROR|Listening on 127.0.0.1:10800|CONNECTED|Successfully|DISCONNECTED' /data/adb/box/run/sidecar.log | tail -20
# quick socks probe via toybox/busybox if available
if [ -n "$PIDOF" ]; then
echo STILL_ALIVE
else
echo DEAD
tail -n 15 /data/adb/box/run/sidecar.log
fi

View File

@@ -0,0 +1,46 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
CFG=/data/adb/box/sidecar/olcrtc.yaml
# Restore full telemost room URL (API expects encoded full URL; numeric alone = 404)
YQ=/data/adb/box/bin/yq
num=$("$YQ" -r '.room.id' "$CFG")
num=$(echo "$num" | grep -oE '[0-9]{8,}' | tail -1)
"$YQ" -i ".room.id = \"https://telemost.yandex.ru/j/${num}\"" "$CFG"
"$YQ" -i '.net.dns = "77.88.8.8:53"' "$CFG"
"$YQ" -i '.debug = true' "$CFG" 2>/dev/null || true
# Convert CRLF->LF
busybox sed -i 's/\r$//' "$CFG"
echo "room=$("$YQ" -r '.room.id' "$CFG")"
# Clear proxy env that can break protect.NewHTTPClient (ProxyFromEnvironment)
unset all_proxy ALL_PROXY http_proxy https_proxy HTTP_PROXY HTTPS_PROXY no_proxy NO_PROXY
rm -rf /data/adb/box/run/olcrtc-data
mkdir -p /data/adb/box/run/olcrtc-data
killall olcrtc 2>/dev/null || true
: > /data/adb/box/run/olcrtc.log
# Run in foreground briefly with timeout to capture more logs, then background
# Prefer GODEBUG
export GODEBUG=netdns=go+2
nohup env -u all_proxy -u ALL_PROXY -u http_proxy -u https_proxy -u HTTP_PROXY -u HTTPS_PROXY \
busybox setuidgid root:net_admin /data/adb/box/bin/olcrtc "$CFG" >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo pid=$!
# Parallel: verify API still ok from same uid context
curl -m 15 -sS -o /dev/null -w "curl_api %{http_code} %{time_total}\n" \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0' \
-H 'Origin: https://telemost.yandex.ru' \
-H 'Referer: https://telemost.yandex.ru/' \
"https://cloud-api.yandex.ru/telemost_front/v2/telemost/conferences/https%3A%2F%2Ftelemost.yandex.ru%2Fj%2F${num}/connection?display_name=test&next_gen_media_platform_allowed=true&waiting_room_supported=true" || true
i=0
while [ $i -lt 60 ]; do
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then echo OPEN_at_$i; break; fi
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then echo DEAD_at_$i; break; fi
sleep 1; i=$((i+1))
done
busybox nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
tail -60 /data/adb/box/run/olcrtc.log

36
tools/retry_olcrtc.sh Normal file
View File

@@ -0,0 +1,36 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== room id shape (redacted) ==="
# show only length / whether full URL vs numeric
awk '/^room:/{p=1} p&&/id:/{
gsub(/[" ]/,"",$2);
id=$2;
printf "len=%d starts_https=%s looks_numeric=%s\n", length(id), (id ~ /^https/?"yes":"no"), (id ~ /^[0-9]+$/"yes":"no")
exit
}' /data/adb/box/sidecar/olcrtc.yaml
echo "=== direct yandex api ==="
curl -m 15 -sS -o /dev/null -w "cloud-api %{http_code} %{time_total}\n" https://cloud-api.yandex.ru/ || true
curl -m 15 -sS -o /dev/null -w "telemost %{http_code} %{time_total}\n" https://telemost.yandex.ru/ || true
echo "=== start olcrtc alone (stack already up) ==="
killall olcrtc 2>/dev/null || true
mkdir -p /data/adb/box/run/olcrtc-data
: > /data/adb/box/run/olcrtc.log
nohup busybox setuidgid root:net_admin /data/adb/box/bin/olcrtc /data/adb/box/sidecar/olcrtc.yaml >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo "pid=$!"
i=0
while [ $i -lt 60 ]; do
if busybox nc -z 127.0.0.1 10801 2>/dev/null; then
echo "10801_open after ${i}s"
break
fi
sleep 1
i=$((i+1))
done
busybox nc -z 127.0.0.1 10801 2>/dev/null || echo "10801_still_closed"
echo "=== olcrtc.log ==="
tail -40 /data/adb/box/run/olcrtc.log
echo "=== socks via olcrtc ==="
curl -x socks5://127.0.0.1:10801 -m 25 -sS https://1.1.1.1/cdn-cgi/trace 2>&1 | grep -E '^(ip|loc=|curl:)' || true

View File

@@ -0,0 +1,31 @@
#!/system/bin/sh
set -e
cp /sdcard/Download/trusttunnel_client /data/adb/box/bin/trusttunnel_client
chmod 755 /data/adb/box/bin/trusttunnel_client
cp /sdcard/Download/trusttunnel.toml /data/adb/box/sidecar/trusttunnel.toml
cp /sdcard/Download/olcrtc.yaml /data/adb/box/sidecar/olcrtc.yaml
chmod 600 /data/adb/box/sidecar/trusttunnel.toml /data/adb/box/sidecar/olcrtc.yaml
# enable trusttunnel sidecar
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="trusttunnel"/' /data/adb/box/settings.ini
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10800"/' /data/adb/box/settings.ini
grep -E '^sidecar_' /data/adb/box/settings.ini || true
echo '--- binary test ---'
file /data/adb/box/bin/trusttunnel_client 2>/dev/null || true
/data/adb/box/bin/trusttunnel_client --help 2>&1 | head -25 || true
echo "help_exit=$?"
# try short run
/data/adb/box/bin/trusttunnel_client -c /data/adb/box/sidecar/trusttunnel.toml >/data/adb/box/run/sidecar.log 2>&1 &
SPID=$!
echo "started_pid=$SPID"
sleep 3
if kill -0 "$SPID" 2>/dev/null; then
echo SIDECAR_RUNNING
busybox netstat -lntp 2>/dev/null | grep 10800 || ss -lntp 2>/dev/null | grep 10800 || true
kill -15 "$SPID" 2>/dev/null || true
else
echo SIDECAR_FAILED
tail -n 40 /data/adb/box/run/sidecar.log 2>/dev/null || true
fi

6
tools/show_final.sh Normal file
View File

@@ -0,0 +1,6 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
echo "route.final=$(yq -r '.route.final' "$sing_config")"
echo "dns-remote.detour=$(yq -r '.dns.servers[] | select(.tag=="dns-remote") | .detour' "$sing_config")"
yq -r '.outbounds[] | select(.tag=="sidecar-proxy" or .tag=="olcrtc-proxy") | .tag + " -> " + .server + ":" + (.server_port|tostring)' "$sing_config"

7
tools/show_olc_cfg.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/system/bin/sh
# Show olcrtc config shape without secrets
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== olcrtc.yaml redacted ==="
sed -E 's/(key:|password:|token:|secret:).*/\1 ***REDACTED***/I; s/(id: ").*(")/\1***\2/' /data/adb/box/sidecar/olcrtc.yaml
echo "=== ports in yaml ==="
grep -E 'port:|host:|mode:|transport:|provider:' /data/adb/box/sidecar/olcrtc.yaml

4
tools/show_settings.sh Normal file
View File

@@ -0,0 +1,4 @@
#!/system/bin/sh
grep '^bin_name=' /data/adb/box/settings.ini
grep '^network_mode=' /data/adb/box/settings.ini
grep '^sidecar_' /data/adb/box/settings.ini

29
tools/start_olc.sh Normal file
View File

@@ -0,0 +1,29 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
BB=/data/adb/magisk/busybox
cp /data/local/tmp/olcrtc /data/adb/box/bin/olcrtc
chmod 755 /data/adb/box/bin/olcrtc
killall olcrtc 2>/dev/null || true
mkdir -p /data/adb/box/run/olcrtc-data
: > /data/adb/box/run/olcrtc.log
$BB setuidgid root:net_admin /data/adb/box/bin/olcrtc /data/adb/box/sidecar/olcrtc.yaml >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo "pid=$(cat /data/adb/box/run/sidecar-olcrtc.pid)"
i=0
while [ $i -lt 90 ]; do
if $BB nc -z 127.0.0.1 10801 2>/dev/null; then
echo "OPEN_at_$i"
break
fi
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then
echo "DEAD_at_$i"
break
fi
sleep 1
i=$((i+1))
done
$BB nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
tail -40 /data/adb/box/run/olcrtc.log
if $BB nc -z 127.0.0.1 10801 2>/dev/null; then
curl -x socks5://127.0.0.1:10801 -m 25 -sS https://1.1.1.1/cdn-cgi/trace | grep -E '^(ip|loc)=' || true
fi

33
tools/start_olc_dnsfix.sh Normal file
View File

@@ -0,0 +1,33 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
BB=/data/adb/magisk/busybox
YQ=/data/adb/box/bin/yq
CFG=/data/adb/box/sidecar/olcrtc.yaml
# PreferGo UDP to 77.88.8.8 hangs for root:net_admin on this device; router DNS works.
$YQ -i '.net.dns = "192.168.0.1:53"' "$CFG"
busybox sed -i 's/\r$//' "$CFG" 2>/dev/null || true
echo "dns=$($YQ -r '.net.dns' "$CFG")"
echo "room=$($YQ -r '.room.id' "$CFG" | sed 's/.*/***len='"$( $YQ -r '.room.id' "$CFG" | wc -c)"'***/')"
cp /data/local/tmp/olcrtc /data/adb/box/bin/olcrtc
chmod 755 /data/adb/box/bin/olcrtc
killall olcrtc 2>/dev/null || true
mkdir -p /data/adb/box/run/olcrtc-data
: > /data/adb/box/run/olcrtc.log
$BB setuidgid root:net_admin /data/adb/box/bin/olcrtc "$CFG" >> /data/adb/box/run/olcrtc.log 2>&1 &
echo $! > /data/adb/box/run/sidecar-olcrtc.pid
echo "pid=$(cat /data/adb/box/run/sidecar-olcrtc.pid)"
i=0
while [ $i -lt 90 ]; do
if $BB nc -z 127.0.0.1 10801 2>/dev/null; then echo "OPEN_at_$i"; break; fi
if ! kill -0 "$(cat /data/adb/box/run/sidecar-olcrtc.pid)" 2>/dev/null; then echo "DEAD_at_$i"; break; fi
sleep 1
i=$((i+1))
done
$BB nc -z 127.0.0.1 10801 && echo OPEN || echo CLOSED
tail -30 /data/adb/box/run/olcrtc.log
if $BB nc -z 127.0.0.1 10801 2>/dev/null; then
echo "=== socks via olcrtc ==="
curl -x socks5://127.0.0.1:10801 -m 30 -sS https://1.1.1.1/cdn-cgi/trace | grep -E '^(ip|loc)=' || true
fi

49
tools/switch_to_olcrtc.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/system/bin/sh
set -e
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
YQ=/data/adb/box/bin/yq
INI=/data/adb/box/settings.ini
CFG="$sing_config"
BB=/data/adb/magisk/busybox
echo "ACTIVE_CFG=$CFG"
# Point primary sidecar at olcrtc for tests (keep yaml port 10801)
sed -i 's/^sidecar_enable=.*/sidecar_enable="true"/' "$INI"
sed -i 's/^sidecar_protocol=.*/sidecar_protocol="olcrtc"/' "$INI"
sed -i 's/^sidecar_listen_port=.*/sidecar_listen_port="10801"/' "$INI"
sed -i 's/^sidecar_outbound_tag=.*/sidecar_outbound_tag="olcrtc-proxy"/' "$INI"
sed -i 's/^sidecar_set_final=.*/sidecar_set_final="true"/' "$INI"
# Ensure DNS in olcrtc yaml is LAN resolver (net_admin + 77.88 hangs)
if [ -f /data/adb/box/sidecar/olcrtc.yaml ]; then
"$YQ" -i '.net.dns = "192.168.0.1:53"' /data/adb/box/sidecar/olcrtc.yaml
fi
# Pre-seed outbound so inject is happy
if ! "$YQ" -e '.outbounds[] | select(.tag == "olcrtc-proxy")' "$CFG" >/dev/null 2>&1; then
"$YQ" -i -o=json '.outbounds += [{"type":"socks","tag":"olcrtc-proxy","server":"127.0.0.1","server_port":10801,"version":"5"}]' "$CFG"
fi
echo "=== settings ==="
grep -E '^sidecar_' "$INI"
sh /data/adb/box/scripts/box.service restart
sleep 5
echo "=== after restart ==="
echo "tt=$(pidof trusttunnel_client) olc=$(pidof olcrtc) sb=$(pidof sing-box)"
echo "final=$("$YQ" -r '.route.final' "$CFG")"
echo "dns_detour=$("$YQ" -r '.dns.servers[] | select(.tag=="dns-remote") | .detour' "$CFG")"
$BB nc -z 127.0.0.1 10801 && echo 10801_open || echo 10801_closed
$BB nc -z 127.0.0.1 10800 && echo 10800_open || echo 10800_closed
echo "=== system IP (should be via olcrtc) ==="
curl -m 25 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc|colo)=' || true
echo "=== google ==="
curl -m 25 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://www.google.com/ || true
echo "=== ya.ru ==="
curl -m 20 -sS -o /dev/null -w "%{http_code} %{time_total}\n" https://ya.ru/ || true
echo "=== olcrtc log ==="
tail -15 /data/adb/box/run/olcrtc.log 2>/dev/null || tail -15 /data/adb/box/run/sidecar.log

View File

@@ -0,0 +1,12 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
URL='https://cloud-api.yandex.ru/telemost_front/v2/telemost/conferences/https%3A%2F%2Ftelemost.yandex.ru%2Fj%2F41001894292350/connection?display_name=test&next_gen_media_platform_allowed=true&waiting_room_supported=true'
echo "=== exact telemost connection URL ==="
curl -m 20 -sS -o /tmp/tm.json -w "%{http_code} %{time_total}\n" -H 'Accept: application/json' -H 'User-Agent: Mozilla/5.0' "$URL" || true
head -c 400 /tmp/tm.json; echo
echo "=== as numeric only path ==="
URL2='https://cloud-api.yandex.ru/telemost_front/v2/telemost/conferences/41001894292350/connection?display_name=test&next_gen_media_platform_allowed=true&waiting_room_supported=true'
curl -m 20 -sS -o /tmp/tm2.json -w "%{http_code} %{time_total}\n" -H 'Accept: application/json' -H 'User-Agent: Mozilla/5.0' "$URL2" || true
head -c 400 /tmp/tm2.json; echo
echo "=== resolve cloud-api ==="
busybox nslookup cloud-api.yandex.ru 77.88.8.8 2>&1 | head -15

17
tools/tt_check.sh Normal file
View File

@@ -0,0 +1,17 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== tt toml ==="
cat /data/adb/box/sidecar/trusttunnel.toml
echo
echo "=== sidecar start cmd / settings ==="
grep -E 'sidecar|trusttunnel|skip' /data/adb/box/settings.ini
echo "=== process cmdline ==="
tr '\0' ' ' < /proc/$(pidof trusttunnel_client)/cmdline; echo
echo "=== socks5 IP DoH again ==="
curl -x socks5://127.0.0.1:10800 -m 10 -sS 'https://1.1.1.1/dns-query?name=www.google.com&type=A' -H 'accept: application/dns-json' 2>&1 | head -c 300; echo
echo "=== socks5h google ==="
curl -x socks5h://127.0.0.1:10800 -m 10 -sS -o /dev/null -w "%{http_code}\n" https://www.google.com/ 2>&1 | tail -5
echo "=== test results from prior ==="
# read end was truncated in previous - quick retest with current final dns
curl -m 12 -sS -o /dev/null -w "google %{http_code} %{time_total}\n" https://www.google.com/ || true
curl -m 10 -sS -o /dev/null -w "ya %{http_code} %{time_total}\n" https://ya.ru/ || true

View File

@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""Decode TrustTunnel tt:// deep link -> client TOML (SOCKS mode)."""
import base64
import sys
def read_tls_varint(b, i):
first = b[i]
prefix = first >> 6
length = 1 << prefix
raw = int.from_bytes(b[i : i + length], "big")
mask = (1 << (8 * length - 2)) - 1
return raw & mask, i + length
def decode_tt(uri: str) -> dict:
payload = uri.split("?", 1)[1] if "?" in uri else uri[5:]
pad = "=" * ((4 - len(payload) % 4) % 4)
data = base64.urlsafe_b64decode(payload + pad)
i = 0
fields = {"addresses": []}
tags = {
0: "version",
1: "hostname",
2: "addresses",
3: "custom_sni",
4: "has_ipv6",
5: "username",
6: "password",
7: "skip_verification",
8: "certificate",
9: "upstream_protocol",
10: "anti_dpi",
11: "client_random_prefix",
12: "name",
13: "dns_upstreams",
}
while i < len(data):
tag, i = read_tls_varint(data, i)
length, i = read_tls_varint(data, i)
val = data[i : i + length]
i += length
name = tags.get(tag, f"tag_{tag}")
if tag == 2:
fields["addresses"].append(val.decode("utf-8"))
elif tag in (4, 7, 10):
fields[name] = bool(val[0])
elif tag == 0:
v, _ = read_tls_varint(val, 0)
fields[name] = v
elif tag == 9:
v, _ = read_tls_varint(val, 0)
fields[name] = {1: "http2", 2: "http3"}.get(v, str(v))
elif tag == 8:
fields[name] = val # raw DER
elif tag == 13:
# string[]
j = 0
ups = []
while j < len(val):
ln, j = read_tls_varint(val, j)
ups.append(val[j : j + ln].decode("utf-8"))
j += ln
fields[name] = ups
else:
fields[name] = val.decode("utf-8")
return fields
def to_toml(fields: dict, socks_port: int = 10800) -> str:
hostname = fields["hostname"]
username = fields["username"]
password = fields["password"]
addresses = fields.get("addresses") or []
addr_list = ", ".join(f'"{a}"' for a in addresses)
has_ipv6 = str(fields.get("has_ipv6", True)).lower()
skip = str(fields.get("skip_verification", False)).lower()
proto = fields.get("upstream_protocol", "http2")
anti = str(fields.get("anti_dpi", False)).lower()
name = fields.get("name", "trusttunnel")
return f'''# Generated from tt:// deep link — {name}
loglevel = "info"
vpn_mode = "general"
killswitch_enabled = false
post_quantum_group_enabled = true
exclusions = []
[endpoint]
hostname = "{hostname}"
addresses = [{addr_list}]
has_ipv6 = {has_ipv6}
username = "{username}"
password = "{password}"
skip_verification = {skip}
upstream_protocol = "{proto}"
anti_dpi = {anti}
dns_upstreams = ["tls://1.1.1.1"]
[listener.socks]
address = "127.0.0.1:{socks_port}"
'''
def main():
uri = sys.argv[1]
out = sys.argv[2] if len(sys.argv) > 2 else "-"
fields = decode_tt(uri)
text = to_toml(fields)
if out == "-":
# redact password in stdout preview
preview = text
if "password =" in preview:
import re
preview = re.sub(r'password = ".*"', 'password = "***"', preview)
print(preview)
print("# fields:", {k: ("***" if k == "password" else v) for k, v in fields.items()}, file=sys.stderr)
else:
open(out, "w", encoding="utf-8").write(text)
print(f"wrote {out}", file=sys.stderr)
if __name__ == "__main__":
main()

25
tools/tt_seq.sh Normal file
View File

@@ -0,0 +1,25 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== tt toml ==="
cat /data/adb/box/sidecar/trusttunnel.toml
echo
echo "=== cmdline ==="
tr '\0' ' ' < /proc/$(pidof trusttunnel_client)/cmdline; echo
echo "=== sequential socks DoH x5 ==="
i=1
while [ $i -le 5 ]; do
code=$(curl -x socks5://127.0.0.1:10800 -m 8 -sS -o /tmp/doh.json -w "%{http_code}" 'https://1.1.1.1/dns-query?name=example.com&type=A' -H 'accept: application/dns-json' 2>/tmp/doh.err || echo err)
echo "#$i http=$code $(head -c 80 /tmp/doh.json 2>/dev/null)"
cat /tmp/doh.err 2>/dev/null | tail -1
i=$((i+1))
sleep 1
done
echo "=== system sequential ==="
for h in www.google.com ya.ru github.com; do
curl -m 12 -sS -o /dev/null -w "$h %{http_code} %{time_total}\n" "https://$h/" || echo "$h fail"
sleep 1
done
echo "=== tt log tail ==="
tail -20 /data/adb/box/run/sidecar.log
echo "=== dns strategy now ==="
yq -o=json '.dns.strategy,.dns.final,.dns.servers' /data/adb/box/sing-box/config.json

14
tools/verify_dual.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
BB=/data/adb/magisk/busybox
echo "tt=$(pidof trusttunnel_client) olc=$(pidof olcrtc) sb=$(pidof sing-box)"
$BB nc -z 127.0.0.1 10800 && echo 10800_ok || echo 10800_down
$BB nc -z 127.0.0.1 10801 && echo 10801_ok || echo 10801_down
echo "=== via olcrtc socks ==="
curl -x socks5h://127.0.0.1:10801 -m 20 -sS -o /dev/null -w "google %{http_code} %{time_total}\n" https://www.google.com/ || true
curl -x socks5://127.0.0.1:10801 -m 15 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc|colo)=' || true
echo "=== system via TT final ==="
curl -m 15 -sS -o /dev/null -w "google %{http_code}\n" https://www.google.com/ || true
curl -m 12 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc)=' || true
echo "=== rkn ==="
pm path com.notcvnt.rknhardering

10
tools/which_cfg.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
echo "=== which config ==="
grep -E 'config|bin_name|name_box' /data/adb/box/settings.ini | head -40
ls -la /data/adb/box/sing-box/*.json
echo "=== process cwd/open config? ==="
# sing-box cmdline
tr '\0' ' ' < /proc/$(pidof sing-box)/cmdline; echo
echo "=== runs.log config lines ==="
grep -i config /data/adb/box/run/runs.log | tail -20

21
tools/which_path.sh Normal file
View File

@@ -0,0 +1,21 @@
#!/system/bin/sh
export PATH="/data/adb/magisk:/data/adb/box/bin:/system/bin:$PATH"
. /data/adb/box/settings.ini
echo "=== settings ==="
grep -E '^sidecar_' /data/adb/box/settings.ini
echo "=== active sing config ==="
echo "sing_config=$sing_config"
yq -o=json '.route.final, (.outbounds[] | select(.tag=="sidecar-proxy" or .tag=="olcrtc-proxy") | {tag,type,server,server_port})' "$sing_config"
echo "=== processes / ports ==="
echo "tt=$(pidof trusttunnel_client) olc=$(pidof olcrtc) sb=$(pidof sing-box)"
/data/adb/magisk/busybox nc -z 127.0.0.1 10800 && echo 10800_open || echo 10800_closed
/data/adb/magisk/busybox nc -z 127.0.0.1 10801 && echo 10801_open || echo 10801_closed
echo "=== IP via TT socks :10800 ==="
curl -x socks5://127.0.0.1:10800 -m 15 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc|colo|http)=' || echo FAIL_TT
echo "=== IP via olcrtc socks :10801 ==="
curl -x socks5://127.0.0.1:10801 -m 20 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc|colo|http)=' || echo FAIL_OLC
echo "=== IP via SYSTEM (follows route.final) ==="
curl -m 15 -sS https://1.1.1.1/cdn-cgi/trace 2>/dev/null | grep -E '^(ip|loc|colo|http)=' || echo FAIL_SYS
echo "=== olcrtc log (last session lines) ==="
grep -E 'SOCKS5|telemost|session|opened|listening|peer latched' /data/adb/box/run/olcrtc.log 2>/dev/null | tail -15
grep -E 'SOCKS5|telemost|session|opened|listening|peer latched' /data/adb/box/run/sidecar.log 2>/dev/null | tail -10

View File

@@ -1,6 +1,6 @@
{
"version": "v1.10.2-stealth.1",
"versionCode": "2026081201",
"zipUrl": "http://10.2.0.2/M1rs3m/BFR/releases/download/v1.10.2-stealth.1/box_for_root-v1.10.2-stealth.1.zip",
"changelog": "http://10.2.0.2/M1rs3m/BFR/src/branch/main/README.md"
"version": "v1.12.0",
"versionCode": "2026081301",
"zipUrl": "http://10.2.0.2/M1rs3m/BFR/releases/download/v1.12.0/pronbox-v1.12.0.zip",
"changelog": "http://10.2.0.2/M1rs3m/BFR/src/branch/main/CHANGELOG_STEALTH.md"
}