docs: переместить route-скрипты в scripts/, исправить пайп с -debug 2>&1

- routes.{sh,ps1,macos.sh} → scripts/; старые файлы из корня удалены
- унифицирован парсинг: TURN server IP, relayed-address=, CIDR, plain IP
- исправлен баг доки: логи клиента идут в stderr, пайп требует -debug 2>&1
- quickstart.md переписан: секция маршрутов, команды трёх платформ
- troubleshooting.md: обновлены пути и примечание про -debug
This commit is contained in:
samosvalishe
2026-05-21 16:22:51 +03:00
parent d1e80751c7
commit f3166c0bae
13 changed files with 423 additions and 433 deletions
+13 -390
View File
@@ -1,401 +1,24 @@
# VK TURN Proxy
<div align="center">
VK TURN Proxy - клиент и сервер для прокидывания локального UDP/TCP-трафика через TURN-реле, получаемые из ссылки на VK Calls. Типичный сценарий - поднять небольшой `server` на VPS рядом с WireGuard или Xray, а на клиентском устройстве запустить `client`, который слушает локальный адрес вроде `127.0.0.1:9000`.
<img src="logo.webp" width="250" height="250">
> [!CAUTION]
> Проект предназначен для обучения, исследований и администрирования собственных стендов. Используйте его только там, где у вас есть право запускать такой трафик и менять сетевую конфигурацию.
![License](https://img.shields.io/badge/license-GPL--3.0-0D1117?style=flat-square&logo=gnu&logoColor=A42E2B&labelColor=0D1117)
![Go](https://img.shields.io/badge/-Go-0D1117?style=flat-square&logo=go&logoColor=00ADD8)
</div>
## Содержание
## О проекте
- [Как это работает](#как-это-работает)
- [Возможности](#возможности)
- [Что нужно](#что-нужно)
- [Быстрый старт: WireGuard](#быстрый-старт-wireguard)
- [Запуск сервера на VPS](#1-запустите-сервер-на-vps)
- [Настройка WireGuard](#2-настройте-wireguard-на-клиенте)
- [Запуск клиента](#3-запустите-клиент)
- [Android через Termux](#android-через-termux)
- [iOS через iSH](#ios-через-ish)
- [systemd-сервис](#сервер-как-systemd-сервис)
- [Docker](#docker)
- [VLESS / Xray](#vless--xray)
- [WRAP-режим](#wrap-режим)
- [Яндекс Телемост](#яндекс-телемост)
- [Флаги клиента](#флаги-клиента)
- [Флаги сервера](#флаги-сервера)
- [Captcha](#captcha)
- [Сборка из исходников](#сборка-из-исходников)
- [Решение проблем](#решение-проблем)
- [Похожие проекты](#похожие-проекты)
- [Лицензия](#лицензия)
**btp** - туннель UDP/TCP через TURN-реле VK Calls. Клиент берёт временные TURN-учётки из ссылки на звонок и гонит ваш
трафик (WireGuard, Xray/VLESS) до сервера на VPS поверх DTLS.
## Как Это Работает
## Быстрый старт
Схема для WireGuard:
```text
WireGuard client -> 127.0.0.1:9000 -> VK TURN Proxy client
-> VK TURN relay -> VK TURN Proxy server на VPS
-> 127.0.0.1:<порт WireGuard> -> WireGuard server
```
Клиент берет временные TURN-учетные данные из ссылки VK Calls, открывает одно или несколько соединений к TURN-реле и отправляет через них трафик к вашему `server`. Между `client` и `server` используется DTLS. Для WireGuard сервер пересылает данные в UDP backend, для VLESS/Xray - в TCP backend через KCP и smux.
<div align="center">
## Возможности
---
- VK Calls как основной источник TURN-учетных данных.
- TCP или UDP подключение клиента к TURN-реле.
- Несколько параллельных TURN-потоков через `-n`.
- WireGuard/Hysteria-подобный UDP backend.
- VLESS/Xray TCP backend через `-vless`.
- Bonding для VLESS через `-vless-bond`.
- Дополнительная WRAP-обфускация DTLS-пакетов через `-wrap`.
- Автоматическое и ручное прохождение VK captcha.
- Docker-образ для серверной части.
Telegram канал: [Free Turn](https://t.me/+5BdkU4q_CGQyNTdi)
## Что Нужно
- VPS с публичным IP.
- На VPS уже должен слушать backend:
- WireGuard: обычно `127.0.0.1:51820/udp`;
- Xray/VLESS: обычно `127.0.0.1:443/tcp`.
- Ссылка на активный VK Calls вида `https://vk.com/call/join/...`.
- На клиенте: WireGuard, Xray или другой локальный клиент, который будет ходить в `127.0.0.1:9000`.
Ссылку VK Calls лучше создать самостоятельно. Не завершайте звонок для всех, если хотите использовать эту ссылку дальше.
## Быстрый Старт: WireGuard
### 1. Запустите Сервер На VPS
Скачайте бинарник для Linux amd64:
```bash
curl -L -o server https://github.com/samosvalishe/btp/releases/latest/download/server-linux-amd64
chmod +x server
```
Запустите `server`, указав локальный адрес WireGuard:
```bash
./server -listen 0.0.0.0:56000 -connect 127.0.0.1:51820
```
Порт `56000/udp` должен быть доступен снаружи. Если WireGuard слушает другой порт, замените `51820`.
### 2. Настройте WireGuard На Клиенте
В клиентском конфиге WireGuard замените endpoint сервера на локальный адрес VK TURN Proxy:
```ini
Endpoint = 127.0.0.1:9000
MTU = 1280
```
На Android добавьте Termux или приложение-клиент в исключения WireGuard. На Windows, Linux и macOS перед включением WireGuard нужно добавить маршрут до TURN-реле, иначе клиент может попытаться подключаться к TURN уже через сам VPN.
### 3. Запустите Клиент
Linux:
```bash
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-linux-amd64
chmod +x client
./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>" | ./routes.sh
```
Windows PowerShell от администратора:
```powershell
Invoke-WebRequest -Uri https://github.com/samosvalishe/btp/releases/latest/download/client-windows-amd64.exe -OutFile client.exe
.\client.exe -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>" | .\routes.ps1
```
macOS:
```bash
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-darwin-arm64
chmod +x client
./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>" | ./routes-macos.sh
```
После появления соединения включите WireGuard.
Если вы скачали только бинарник, но не клонировали репозиторий, возьмите нужный route-скрипт из этого репозитория: `routes.sh`, `routes.ps1` или `routes-macos.sh`.
## Android Через Termux
1. Установите Termux из F-Droid.
2. В WireGuard укажите `Endpoint = 127.0.0.1:9000` и `MTU = 1280`.
3. Добавьте Termux в исключения WireGuard.
4. Запустите в Termux:
```bash
termux-wake-lock
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-android-arm64
chmod +x client
./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>"
```
Чтобы снять wake lock:
```bash
termux-wake-unlock
```
## iOS Через iSH
Это запасной вариант, если нет нативного клиента.
```bash
apk update
apk add curl
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-linux-386
chmod +x client
GOMAXPROCS=1 GODEBUG=asyncpreemptoff=1 ./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>"
```
Чтобы iSH дольше жил в фоне, можно в начале сессии выполнить:
```bash
cat /dev/location > /dev/null &
```
## Сервер Как systemd-Сервис
Пример `/etc/systemd/system/btp.service`:
```ini
[Unit]
Description=VK TURN Proxy server
After=network.target
[Service]
Type=simple
ExecStart=/opt/btp/server -listen 0.0.0.0:56000 -connect 127.0.0.1:51820
Restart=always
RestartSec=5
User=nobody
Group=nogroup
[Install]
WantedBy=multi-user.target
```
Применить:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now btp.service
sudo systemctl status btp.service
```
## Docker
Образ публикуется в GitHub Container Registry:
```bash
docker pull ghcr.io/samosvalishe/btp:latest
```
Если backend слушает на хосте, удобнее использовать host network:
```bash
docker run --rm --network host \
-e CONNECT_ADDR=127.0.0.1:51820 \
ghcr.io/samosvalishe/btp:latest
```
Bridge mode:
```bash
docker run --rm -p 56000:56000/udp \
-e CONNECT_ADDR=<host-ip>:51820 \
ghcr.io/samosvalishe/btp:latest
```
Переменные окружения:
| Переменная | По умолчанию | Описание |
| --- | --- | --- |
| `CONNECT_ADDR` | обязательна | backend, куда сервер пересылает трафик |
| `LISTEN_ADDR` | `0.0.0.0:56000` | адрес прослушивания сервера |
| `VLESS_MODE` | `false` | включает `-vless` |
| `VLESS_BOND` | `false` | включает `-vless-bond` |
| `WRAP_MODE` | `false` | включает `-wrap` |
| `WRAP_KEY` | пусто | ключ для `-wrap-key` |
| `VK_TURN_KCP_PROFILE` | `balanced` | профиль KCP (`fast`, `balanced`, `slow`) |
| `VK_TURN_KCP_MTU` | `1200` | переопределить MTU для KCP |
Сборка образа вручную:
```bash
docker build -t btp .
```
## VLESS / Xray
В режиме `-vless` VK TURN Proxy прокидывает TCP-соединения. На VPS `server` подключается к локальному TCP backend, например к Xray inbound на `127.0.0.1:443`. На клиенте `client` слушает локальный TCP адрес, на который должен смотреть ваш Xray/v2rayN/sing-box клиент.
Сервер:
```bash
./server -listen 0.0.0.0:56000 -connect 127.0.0.1:443 -vless
```
Клиент:
```bash
./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>" -vless
```
С bonding:
```bash
./server -listen 0.0.0.0:56000 -connect 127.0.0.1:443 -vless
./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>" -vless -vless-bond -n 4
```
## WRAP-Режим
`-wrap` маскирует TURN-payload под SRTP: добавляет RTP/opus-заголовок и шифрует тело ChaCha20-Poly1305 AEAD. Это не защита (DTLS уже шифрует внутренний канал), а обфускация под голосовой трафик, чтобы content-filter VK не дропал пакеты. Ключ должен совпадать на клиенте и сервере.
Сгенерировать ключ:
```bash
./server -gen-wrap-key
```
Запуск:
```bash
./server -listen 0.0.0.0:56000 -connect 127.0.0.1:51820 -wrap -wrap-key <64-hex-key>
./client -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>" -wrap -wrap-key <64-hex-key>
```
> **Breaking change (V2-0):** удалены клиентский `-no-dtls` и **серверный** `-vless-bond`.
> Клиентский `-vless-bond` сохранён — это и есть переключатель bonding.
> `-no-dtls` помечался DO NOT USE и в проде не работал (VK дропает пакеты без DTLS-handshake).
> Серверный `-vless-bond` больше не нужен: сервер автоопределяет bond по magic-префиксу в каждом стриме.
## Настройка KCP (VLESS)
В режиме `-vless` для передачи данных поверх DTLS используется KCP. Его можно настроить через переменные окружения (работает и для клиента, и для сервера):
| Переменная | Профили / Значения | Описание |
| --- | --- | --- |
| `VK_TURN_KCP_PROFILE` | `fast`, `balanced`, `slow` | Предустановленные режимы работы KCP. |
| `VK_TURN_KCP_MTU` | например, `1200` | Максимальный размер пакета. |
**Профили:**
- `fast` (или `legacy`): Минимальные задержки, активная переотправка, MTU 1280.
- `balanced` (или `cc`): Оптимальный баланс для большинства сетей, MTU 1200.
- `slow` (или `conservative`): Для очень нестабильных каналов, MTU 1150.
Для более тонкой настройки доступны переменные: `VK_TURN_KCP_NODELAY`, `VK_TURN_KCP_INTERVAL`, `VK_TURN_KCP_RESEND`, `VK_TURN_KCP_NC`, `VK_TURN_KCP_SNDWND`, `VK_TURN_KCP_RCVWND`, `VK_TURN_KCP_ACK_NODELAY`.
**FEC (Reed-Solomon):** `VK_TURN_KCP_FEC=data:parity` (например, `10:3`) — упреждающая коррекция ошибок. На каждые `data` пакетов добавляется `parity` избыточных, потери до `parity` из `data+parity` восстанавливаются без ретрансмита. Overhead по полосе: `parity/data` (для `10:3` — 30%). Должно совпадать на клиенте и сервере. По умолчанию выключено (`0:0`). Включай только при случайных потерях; при шейпе по полосе FEC ухудшит goodput.
## Флаги Клиента
| Флаг | По умолчанию | Описание |
| --- | --- | --- |
| `-listen` | `127.0.0.1:9000` | локальный адрес `ip:port`, куда подключается WireGuard или Xray клиент |
| `-peer` | обязательный | адрес сервера VK TURN Proxy на VPS, `host:port` (например `<ip-vps>:56000`) |
| `-vk-link` | обязательный | ссылка VK Calls вида `https://vk.com/call/join/...` |
| `-n` | `10` | количество параллельных TURN-потоков (соединений к TURN-реле) |
| `-udp` | `false` | подключаться к TURN-реле по UDP (по умолчанию TCP/TLS) |
| `-turn` | из ссылки | переопределить IP TURN-сервера |
| `-port` | из ссылки | переопределить порт TURN-сервера |
| `-vless` | `false` | режим TCP-форвардера (VLESS/Xray) вместо UDP-релея для WireGuard |
| `-vless-bond` | `false` | распределять одно VLESS TCP-соединение по всем активным smux-сессиям (только с `-vless`) |
| `-wrap` | `false` | маскировать TURN-payload под SRTP (см. [WRAP-режим](#wrap-режим)); ключ должен совпадать с сервером |
| `-wrap-key` | пусто | общий ключ для `-wrap`, 32 байта в hex (64 символа) |
| `-gen-wrap-key` | `false` | напечатать новый ключ для `-wrap-key` и выйти |
| `-manual-captcha` | `false` | пропустить авто-решение captcha и сразу открыть ручной режим в локальном браузере |
| `-streams-per-cred` | `10` | сколько TURN-потоков делят один кеш VK-учёток |
| `-dns` | `auto` | режим DNS-резолвинга: `udp` \| `doh` \| `auto` (UDP/53, sticky-fallback на DoH) |
| `-dns-servers` | пусто | список UDP/53 DNS-серверов через запятую вместо встроенных, формат `ip[:port][,ip[:port]...]` |
| `-debug` | `false` | включить подробные debug-логи |
## Флаги Сервера
| Флаг | По умолчанию | Описание |
| --- | --- | --- |
| `-listen` | `0.0.0.0:56000` | локальный адрес прослушивания `ip:port` |
| `-connect` | обязательный | адрес локального бэкенда `host:port` (WireGuard `127.0.0.1:51820` или Xray `127.0.0.1:443`) |
| `-vless` | `false` | режим TCP-форвардера (VLESS/Xray) вместо UDP-релея; bond определяется автоматически по magic-префиксу в стриме |
| `-wrap` | `false` | маскировать TURN-payload под SRTP (см. [WRAP-режим](#wrap-режим)); ключ должен совпадать с клиентом |
| `-wrap-key` | пусто | общий ключ для `-wrap`, 32 байта в hex (64 символа) |
| `-gen-wrap-key` | `false` | напечатать новый ключ для `-wrap-key` и выйти |
| `-debug` | `false` | включить подробные debug-логи |
## Captcha
Для VK Calls клиент умеет автоматически проходить captcha. Если автоматика не сработала, включается ручной сценарий через локальный браузер. Можно сразу запросить ручной режим:
```bash
./client -manual-captcha -listen 127.0.0.1:9000 -peer <ip-vps>:56000 -vk-link "<vk-call-link>"
```
Профиль браузера сохраняется в `vk_profile.json` рядом с бинарником и может помочь последующим запросам выглядеть последовательнее.
## Сборка Из Исходников
Нужен Go 1.25.x.
```bash
go build -o client ./cmd/client
go build -o server ./cmd/server
go test ./...
```
Кросс-сборка примера для Linux amd64:
```bash
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o server-linux-amd64 ./cmd/server
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o client-linux-amd64 ./cmd/client
```
Android arm64 клиент как `.so` для упаковки в приложение (PowerShell):
```powershell
$env:GOOS="android"; $env:GOARCH="arm64"; $env:CGO_ENABLED="0"; go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn.so .\cmd\client
```
То же из bash:
```bash
GOOS=android GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn.so ./cmd/client
```
Linux arm64 клиент как `.so` (для упаковки в Android-приложение в обход NDK; ABI совпадает):
```bash
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn.so ./cmd/client
```
Linux amd64 клиент/сервер как `.so`:
```bash
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn-client.so ./cmd/client
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn-server.so ./cmd/server
```
Все `.so` выше — обычные ELF-бинари под `.so`-именем (`CGO_ENABLED=0`, не настоящий shared library). Если нужен настоящий `c-shared` — `CGO_ENABLED=1` + NDK toolchain (см. `.github/workflows/release.yml`).
## Решение Проблем
- Сначала запускайте VK TURN Proxy client, потом включайте WireGuard.
- Если WireGuard забирает весь трафик, добавьте маршрут до IP TURN-реле через `routes.sh`, `routes.ps1` или `routes-macos.sh`.
- Если TCP до TURN не работает, попробуйте `-udp`.
- Если соединение нестабильное, попробуйте уменьшить `-n`, например `-n 1`.
- Если VK просит captcha слишком часто, попробуйте `-manual-captcha`, затем повторите обычный запуск.
- Если клиент зависает на получении TURN-данных, проверьте, что ссылка VK Calls живая и не была завершена для всех.
- Если сервер запущен в Docker bridge mode, `CONNECT_ADDR=127.0.0.1:51820` укажет внутрь контейнера, а не на хост. Используйте host network или IP хоста.
- Если включен `-wrap`, убедитесь, что и клиент, и сервер используют одинаковый `-wrap-key`.
## Лицензия
GPL-3.0. См. [LICENSE](LICENSE).
</div>
+10
View File
@@ -0,0 +1,10 @@
# Документация
- [Быстрый старт (WireGuard)](quickstart.md)
- [Режимы: UDP / VLESS / WRAP / KCP](modes.md)
- [Флаги клиента и сервера](flags.md)
- [Развёртывание: systemd, Docker](deploy.md)
- [Мобильные: Android (Termux), iOS (iSH)](mobile.md)
- [Сборка из исходников](build.md)
- [Решение проблем](troubleshooting.md)
- [Глоссарий](GLOSSARY.md)
+46
View File
@@ -0,0 +1,46 @@
# Сборка
Нужен Go 1.25.x.
```bash
go build -o client ./cmd/client
go build -o server ./cmd/server
go test ./...
```
## Кросс-Сборка
**Linux amd64:**
```bash
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o server-linux-amd64 ./cmd/server
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o client-linux-amd64 ./cmd/client
```
**Android arm64 как `.so`** (упаковка в приложение, PowerShell):
```powershell
$env:GOOS="android"; $env:GOARCH="arm64"; $env:CGO_ENABLED="0"
go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn.so .\cmd\client
```
Bash:
```bash
GOOS=android GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn.so ./cmd/client
```
**Linux arm64 как `.so`** (в обход NDK, ABI совпадает):
```bash
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn.so ./cmd/client
```
**Linux amd64 как `.so`:**
```bash
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn-client.so ./cmd/client
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -checklinkname=0" -trimpath -o libvkturn-server.so ./cmd/server
```
> Все `.so` выше — обычные ELF под `.so`-именем (`CGO_ENABLED=0`, не настоящий shared library). Настоящий `c-shared` — `CGO_ENABLED=1` + NDK toolchain (см. `.github/workflows/release.yml`).
+74
View File
@@ -0,0 +1,74 @@
# Развёртывание
## systemd
`/etc/systemd/system/btp.service`:
```ini
[Unit]
Description=VK TURN Proxy server
After=network.target
[Service]
Type=simple
ExecStart=/opt/btp/server -listen 0.0.0.0:56000 -connect 127.0.0.1:51820
Restart=always
RestartSec=5
User=nobody
Group=nogroup
[Install]
WantedBy=multi-user.target
```
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now btp.service
sudo systemctl status btp.service
```
## Docker
Образ:
```bash
docker pull ghcr.io/samosvalishe/btp:latest
```
**Host network** (backend на хосте):
```bash
docker run --rm --network host \
-e CONNECT_ADDR=127.0.0.1:51820 \
ghcr.io/samosvalishe/btp:latest
```
**Bridge mode:**
```bash
docker run --rm -p 56000:56000/udp \
-e CONNECT_ADDR=<host-ip>:51820 \
ghcr.io/samosvalishe/btp:latest
```
> В bridge `CONNECT_ADDR=127.0.0.1:...` указывает внутрь контейнера. Используйте host network или IP хоста.
**Переменные:**
| Переменная | По умолчанию | Описание |
| --- | --- | --- |
| `CONNECT_ADDR` | **обязательна** | backend сервера |
| `LISTEN_ADDR` | `0.0.0.0:56000` | адрес прослушивания |
| `VLESS_MODE` | `false` | включает `-vless` |
| `WRAP_MODE` | `false` | включает `-wrap` |
| `WRAP_KEY` | пусто | значение `-wrap-key` |
| `VK_TURN_KCP_PROFILE` | `balanced` | профиль KCP |
| `VK_TURN_KCP_MTU` | `1200` | MTU для KCP |
> `VLESS_BOND` в `docker-entrypoint.sh` ещё передаёт `-vless-bond` серверу, но серверный флаг удалён в V2-0 (bond автоопределяется по magic-префиксу). Не устанавливайте `VLESS_BOND=true` — сервер не запустится.
Сборка образа:
```bash
docker build -t btp .
```
+39
View File
@@ -0,0 +1,39 @@
# Флаги
## Клиент
| Флаг | По умолчанию | Описание |
| --- | --- | --- |
| `-listen` | `127.0.0.1:9000` | локальный адрес `ip:port`, куда подключается WireGuard или Xray клиент |
| `-peer` | **обязательный** | адрес сервера на VPS, `host:port` |
| `-vk-link` | **обязательный** | ссылка VK Calls `https://vk.com/call/join/...` |
| `-n` | `10` | параллельных TURN-потоков |
| `-udp` | `false` | TURN по UDP вместо TCP/TLS |
| `-turn` | из ссылки | переопределить IP TURN-сервера |
| `-port` | из ссылки | переопределить порт TURN-сервера |
| `-vless` | `false` | TCP-форвардер (VLESS/Xray) вместо UDP-релея |
| `-vless-bond` | `false` | распределять TCP-соединение по smux-сессиям (только с `-vless`) |
| `-wrap` | `false` | SRTP-мимикрия payload |
| `-wrap-key` | пусто | общий ключ, 32 байта hex (64 символа) |
| `-gen-wrap-key` | `false` | напечатать новый ключ и выйти |
| `-manual-captcha` | `false` | сразу ручной режим captcha |
| `-streams-per-cred` | `10` | потоков на один кеш VK-учёток |
| `-dns` | `auto` | `udp` \| `doh` \| `auto` |
| `-dns-servers` | пусто | свои UDP/53 резолверы, `ip[:port][,ip[:port]...]` |
| `-debug` | `false` | debug-логи |
## Сервер
| Флаг | По умолчанию | Описание |
| --- | --- | --- |
| `-listen` | `0.0.0.0:56000` | адрес прослушивания `ip:port` |
| `-connect` | **обязательный** | локальный backend `host:port` (WG `127.0.0.1:51820` / Xray `127.0.0.1:443`) |
| `-vless` | `false` | TCP-форвардер; bond автоопределяется |
| `-wrap` | `false` | SRTP-мимикрия payload |
| `-wrap-key` | пусто | общий ключ, 32 байта hex |
| `-gen-wrap-key` | `false` | напечатать новый ключ и выйти |
| `-debug` | `false` | debug-логи |
## Переменные Окружения (KCP)
См. [modes.md → KCP](modes.md#kcp-только-в--vless).
+35
View File
@@ -0,0 +1,35 @@
# Мобильные
## Android (Termux)
1. Termux из F-Droid.
2. WireGuard: `Endpoint = 127.0.0.1:9000`, `MTU = 1280`.
3. Termux в исключения WireGuard.
4. В Termux:
```bash
termux-wake-lock
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-android-arm64
chmod +x client
./client -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>"
```
Снять wake lock: `termux-wake-unlock`.
## iOS (iSH)
Запасной вариант без нативного клиента.
```bash
apk update
apk add curl
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-linux-386
chmod +x client
GOMAXPROCS=1 GODEBUG=asyncpreemptoff=1 ./client -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>"
```
Дольше в фоне:
```bash
cat /dev/location > /dev/null &
```
+81
View File
@@ -0,0 +1,81 @@
# Режимы
## UDP-Релей (WireGuard / Hysteria)
Дефолт. Клиент слушает локальный UDP, сервер форвардит UDP в backend (WG `127.0.0.1:51820`).
## VLESS / Xray (TCP)
Флаг `-vless` на обеих сторонах. Сервер коннектит локальный TCP backend (Xray inbound `127.0.0.1:443`). Клиент слушает локальный TCP, на него смотрит Xray/v2rayN/sing-box.
Поверх DTLS — KCP + smux.
```bash
./server -listen 0.0.0.0:56000 -connect 127.0.0.1:443 -vless
./client -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>" -vless
```
**Bonding** — распределение одного TCP-соединения по всем активным smux-сессиям, флаг только клиентский:
```bash
./client -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>" -vless -vless-bond -n 4
```
> **Breaking (V2-0):** серверный `-vless-bond` удалён, сервер автоопределяет bond по magic-префиксу в стриме. Клиентский `-no-dtls` тоже удалён (VK дропает не-DTLS).
## WRAP (SRTP-Мимикрия)
`-wrap` маскирует TURN-payload под SRTP: RTP/opus-заголовок + ChaCha20-Poly1305 AEAD на теле. Не защита (DTLS уже шифрует), а обфускация под голос — иначе VK content-filter дропает. Ключ должен совпадать.
Сгенерировать ключ:
```bash
./server -gen-wrap-key
```
Запуск:
```bash
./server ... -wrap -wrap-key <64-hex>
./client ... -wrap -wrap-key <64-hex>
```
## KCP (Только В `-vless`)
Переменные окружения (клиент и сервер):
| Переменная | Значения | Описание |
| --- | --- | --- |
| `VK_TURN_KCP_PROFILE` | `fast` \| `balanced` \| `slow` | Предустановка. |
| `VK_TURN_KCP_MTU` | напр. `1200` | Размер пакета. |
| `VK_TURN_KCP_FEC` | `data:parity`, напр. `10:3` | Reed-Solomon FEC. |
**Профили:**
- `fast` (`legacy`) — минимальные задержки, активная переотправка, MTU 1280.
- `balanced` (`cc`) — баланс для большинства сетей, MTU 1200.
- `slow` (`conservative`) — нестабильные каналы, MTU 1150.
Тонкая настройка: `VK_TURN_KCP_NODELAY`, `_INTERVAL`, `_RESEND`, `_NC`, `_SNDWND`, `_RCVWND`, `_ACK_NODELAY`.
**FEC:** на каждые `data` пакетов — `parity` избыточных. Потери до `parity` из `data+parity` восстанавливаются без ретрансмита. Overhead полосы: `parity/data` (для `10:3` — 30%). Включайте при случайных потерях; при шейпе по полосе FEC ухудшит goodput. По умолчанию `0:0`.
## Captcha
Клиент сам проходит VK captcha. Если автоматика не справилась — открывается локальный браузер. Принудительно ручной:
```bash
./client -manual-captcha ...
```
Профиль браузера: `vk_profile.json` рядом с бинарником.
## DNS
Флаг `-dns`:
- `udp` — только UDP/53;
- `doh` — только DNS-over-HTTPS;
- `auto` (дефолт) — сначала UDP/53, sticky-fallback на DoH при полном отказе.
Свои резолверы: `-dns-servers ip[:port][,ip[:port]...]`.
+55
View File
@@ -0,0 +1,55 @@
# Быстрый Старт (WireGuard)
## Что Нужно
- VPS с публичным IP, WireGuard слушает `127.0.0.1:51820/udp`.
- Активная ссылка VK Calls: `https://vk.com/call/join/...` — создайте сами, не завершайте звонок для всех.
- WireGuard на клиенте: `Endpoint = 127.0.0.1:9000`, `MTU = 1280`.
## 1. Сервер На VPS
```bash
curl -L -o server https://github.com/samosvalishe/btp/releases/latest/download/server-linux-amd64
chmod +x server
./server -listen 0.0.0.0:56000 -connect 127.0.0.1:51820
```
Порт `56000/udp` открыт снаружи.
## 2. Маршруты (Split Tunneling)
WireGuard забирает весь трафик, включая трафик к TURN-реле — туннель замыкается сам на себя. Скрипт маршрутов добавляет исключение: трафик к TURN идёт напрямую через шлюз ISP.
Флаг `-debug` включает debug-логи, из которых скрипт читает IP TURN-сервера. `2>&1` перенаправляет их в пайп.
> **Android:** маршруты не нужны — добавьте Termux в исключения WireGuard.
## 3. Клиент
**Linux:**
```bash
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-linux-amd64
chmod +x client
./client -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>" -debug 2>&1 | ./scripts/routes.sh
```
**Windows (PowerShell от администратора):**
```powershell
Invoke-WebRequest -Uri https://github.com/samosvalishe/btp/releases/latest/download/client-windows-amd64.exe -OutFile client.exe
.\client.exe -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>" -debug 2>&1 | .\scripts\routes.ps1
```
**macOS:**
```bash
curl -L -o client https://github.com/samosvalishe/btp/releases/latest/download/client-darwin-arm64
chmod +x client
./client -listen 127.0.0.1:9000 -peer <vps>:56000 -vk-link "<vk-link>" -debug 2>&1 | ./scripts/routes-macos.sh
```
Когда скрипт напечатает `Ensuring route to ...` — включайте WireGuard.
> Скачали только бинарник без репо? Возьмите скрипты отдельно:
> [`scripts/routes.sh`](../scripts/routes.sh) · [`scripts/routes.ps1`](../scripts/routes.ps1) · [`scripts/routes-macos.sh`](../scripts/routes-macos.sh)
+12
View File
@@ -0,0 +1,12 @@
# Решение Проблем
- Сначала запускайте client, потом включайте WireGuard.
- WireGuard забирает весь трафик → пайп с `-debug 2>&1` и скриптом маршрутов обязателен: `scripts/routes.sh` / `scripts/routes.ps1` / `scripts/routes-macos.sh`.
- Маршруты не добавляются → убедитесь, что в команде есть `-debug 2>&1 |` перед скриптом.
- TCP до TURN не работает → попробуйте `-udp`.
- Соединение нестабильное → уменьшите `-n` (например, `-n 1`).
- VK часто требует captcha → `-manual-captcha`, затем обычный запуск.
- Клиент висит на получении TURN-данных → ссылка VK Calls умерла / звонок завершён для всех.
- Docker bridge mode → `CONNECT_ADDR=127.0.0.1:...` указывает внутрь контейнера. Используйте `--network host` или IP хоста.
- `-wrap` включён → ключ должен совпадать на клиенте и сервере.
- `VLESS_BOND=true` в docker → не ставьте, серверный флаг удалён в V2-0.
-26
View File
@@ -1,26 +0,0 @@
#!/bin/bash
set -euo pipefail
gateway="$(ip -o -4 route show to default | awk '/via/ {print $3}' | head -1)"
if [[ -z "${gateway}" ]]; then
echo "Could not determine default gateway" >&2
exit 1
fi
ip_cmd=(ip)
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
ip_cmd=(sudo ip)
fi
while IFS= read -r remote; do
remote="${remote%$'\r'}"
[[ -z "$remote" ]] && continue
if [[ ! "$remote" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
echo "Skipping unexpected input: $remote" >&2
continue
fi
echo "Ensuring route to $remote via $gateway"
"${ip_cmd[@]}" route replace "$remote" via "$gateway"
done
+3 -4
View File
@@ -1,4 +1,5 @@
#!/bin/zsh
# Usage: ./client -debug ... 2>&1 | ./scripts/routes-macos.sh
set -u
default_info="$(route -n get default 2>/dev/null || true)"
@@ -18,11 +19,9 @@ fi
while IFS= read -r line; do
line="${line//$'\r'/}"
# Try to extract:
# - plain IPv4
# - IPv4/CIDR
# - relayed-address=IPv4:port -> use only IPv4
remote="$(printf '%s\n' "$line" | sed -nE '
s/.*TURN server IP: (([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p
t done
s/.*relayed-address=(([0-9]{1,3}\.){3}[0-9]{1,3}):[0-9]+.*/\1/p
t done
s/^(([0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2})$/\1/p
+21 -13
View File
@@ -1,42 +1,51 @@
# Получаем default gateway (IPv4)
# Usage: .\client.exe -debug ... 2>&1 | .\scripts\routes.ps1
# Requires Administrator privileges.
$gateway = Get-NetRoute `
-DestinationPrefix "0.0.0.0/0" `
| Sort-Object RouteMetric `
| Select-Object -First 1 -ExpandProperty NextHop
if (-not $gateway) {
Write-Error "Не удалось определить default gateway"
Write-Error "Could not determine default gateway"
exit 1
}
Write-Host "Default gateway: $gateway"
# Читаем адреса из stdin
$input | ForEach-Object {
$addr = $_.Trim()
if ($addr -eq "") { return }
$line = $_.Trim()
if ($line -eq "") { return }
if ($addr -notmatch '^\d{1,3}(\.\d{1,3}){3}$') {
Write-Warning "Пропускаем неожиданный ввод: $addr"
return
$prefix = $null
if ($line -match 'TURN server IP: ((\d{1,3}\.){3}\d{1,3})') {
$prefix = "$($Matches[1])/32"
} elseif ($line -match 'relayed-address=((\d{1,3}\.){3}\d{1,3}):\d+') {
$prefix = "$($Matches[1])/32"
} elseif ($line -match '^((\d{1,3}\.){3}\d{1,3}/\d{1,2})$') {
$prefix = $Matches[1]
} elseif ($line -match '^((\d{1,3}\.){3}\d{1,3})$') {
$prefix = "$line/32"
}
$prefix = "$addr/32"
if (-not $prefix) { return }
$existingRoutes = @(Get-NetRoute `
-DestinationPrefix $prefix `
-PolicyStore ActiveStore `
-ErrorAction SilentlyContinue)
if ($existingRoutes | Where-Object { $_.NextHop -eq $gateway }) {
Write-Host "Маршрут к $addr через $gateway уже существует"
Write-Host "Route to $prefix via $gateway already exists"
return
}
if ($existingRoutes.Count -gt 0) {
Write-Host "Обновляем маршрут к $addr через $gateway"
Write-Host "Updating route to $prefix via $gateway"
$existingRoutes | Remove-NetRoute -Confirm:$false -ErrorAction Stop
} else {
Write-Host "Добавляем маршрут к $addr через $gateway"
Write-Host "Ensuring route to $prefix via $gateway"
}
New-NetRoute `
@@ -45,4 +54,3 @@ $input | ForEach-Object {
-PolicyStore ActiveStore `
-ErrorAction Stop | Out-Null
}
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# Usage: ./client -debug ... 2>&1 | ./scripts/routes.sh
set -euo pipefail
gateway="$(ip -o -4 route show to default | awk '/via/ {print $3}' | head -1)"
if [[ -z "${gateway}" ]]; then
echo "Could not determine default gateway" >&2
exit 1
fi
ip_cmd=(ip)
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
ip_cmd=(sudo ip)
fi
while IFS= read -r line; do
line="${line%$'\r'}"
remote=""
if [[ "$line" =~ TURN\ server\ IP:\ (([0-9]{1,3}\.){3}[0-9]{1,3}) ]]; then
remote="${BASH_REMATCH[1]}"
elif [[ "$line" =~ relayed-address=(([0-9]{1,3}\.){3}[0-9]{1,3}):[0-9]+ ]]; then
remote="${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^(([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2})$ ]]; then
remote="$line"
elif [[ "$line" =~ ^(([0-9]{1,3}\.){3}[0-9]{1,3})$ ]]; then
remote="$line"
fi
[[ -z "$remote" ]] && continue
echo "Ensuring route to $remote via $gateway"
"${ip_cmd[@]}" route replace "$remote" via "$gateway"
done