diff --git a/README.md b/README.md index 972f251..d840141 100644 --- a/README.md +++ b/README.md @@ -1,401 +1,24 @@ -# VK TURN Proxy +
-VK TURN Proxy - клиент и сервер для прокидывания локального UDP/TCP-трафика через TURN-реле, получаемые из ссылки на VK Calls. Типичный сценарий - поднять небольшой `server` на VPS рядом с WireGuard или Xray, а на клиентском устройстве запустить `client`, который слушает локальный адрес вроде `127.0.0.1:9000`. + -> [!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) +
-## Содержание +## О проекте -- [Как это работает](#как-это-работает) -- [Возможности](#возможности) -- [Что нужно](#что-нужно) -- [Быстрый старт: 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. +
-## Возможности +--- -- 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 :56000 -vk-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 :56000 -vk-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 :56000 -vk-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 :56000 -vk-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 :56000 -vk-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=: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 :56000 -vk-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 :56000 -vk-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 :56000 -vk-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` (например `: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 :56000 -vk-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). +
\ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..9ce45ed --- /dev/null +++ b/docs/README.md @@ -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) diff --git a/docs/build.md b/docs/build.md new file mode 100644 index 0000000..7ca9fb8 --- /dev/null +++ b/docs/build.md @@ -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`). diff --git a/docs/deploy.md b/docs/deploy.md new file mode 100644 index 0000000..a566c3d --- /dev/null +++ b/docs/deploy.md @@ -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=: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 . +``` diff --git a/docs/flags.md b/docs/flags.md new file mode 100644 index 0000000..2cdbb3c --- /dev/null +++ b/docs/flags.md @@ -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). diff --git a/docs/mobile.md b/docs/mobile.md new file mode 100644 index 0000000..5c2d0f3 --- /dev/null +++ b/docs/mobile.md @@ -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 :56000 -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 :56000 -vk-link "" +``` + +Дольше в фоне: + +```bash +cat /dev/location > /dev/null & +``` diff --git a/docs/modes.md b/docs/modes.md new file mode 100644 index 0000000..8ec0330 --- /dev/null +++ b/docs/modes.md @@ -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 :56000 -vk-link "" -vless +``` + +**Bonding** — распределение одного TCP-соединения по всем активным smux-сессиям, флаг только клиентский: + +```bash +./client -listen 127.0.0.1:9000 -peer :56000 -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]...]`. diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 0000000..58a5998 --- /dev/null +++ b/docs/quickstart.md @@ -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 :56000 -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 :56000 -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 :56000 -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) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..d4784b7 --- /dev/null +++ b/docs/troubleshooting.md @@ -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. diff --git a/routes.sh b/routes.sh deleted file mode 100644 index d660e9c..0000000 --- a/routes.sh +++ /dev/null @@ -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 diff --git a/routes-macos.sh b/scripts/routes-macos.sh similarity index 89% rename from routes-macos.sh rename to scripts/routes-macos.sh index 8a09471..31e5301 100644 --- a/routes-macos.sh +++ b/scripts/routes-macos.sh @@ -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 diff --git a/routes.ps1 b/scripts/routes.ps1 similarity index 50% rename from routes.ps1 rename to scripts/routes.ps1 index 0e34b6c..0b2012b 100644 --- a/routes.ps1 +++ b/scripts/routes.ps1 @@ -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 } - diff --git a/scripts/routes.sh b/scripts/routes.sh new file mode 100644 index 0000000..a4979bb --- /dev/null +++ b/scripts/routes.sh @@ -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