# olcRTC - полная документация > **olcRTC** (OpenLibreCommunity RTC) - инструмент обхода интернет-блокировок через паразитирование на легальных WebRTC-сервисах видеозвонков, уже находящихся в российских белых списках. > > Проект: [github.com/openlibrecommunity/olcrtc](https://github.com/openlibrecommunity/olcrtc) > Лицензия: WTFPL > Статус: **Beta** --- ## Содержание 1. [Почему olcRTC существует](#1-почему-olcrtc-существует) 2. [Идея и история создания](#2-идея-и-история-создания) 3. [Как это работает](#3-как-это-работает) 4. [Архитектура](#4-архитектура) 5. [Структура репозитория](#5-структура-репозитория) 6. [Auth-провайдеры](#6-auth-провайдеры) 7. [Transports - транспорты](#7-transports--транспорты) 8. [Шифрование](#8-шифрование) 9. [Мультиплексирование](#9-мультиплексирование) 10. [SOCKS5 прокси](#10-socks5-прокси) 11. [Mobile / Android](#11-mobile--android) 12. [Go-либа (pkg/olcrtc)](#12-go-либа-pkgolcrtc) 13. [Python PoC скрипты](#13-python-poc-скрипты) 14. [Сборка и деплой](#14-сборка-и-деплой) 15. [CLI - все флаги](#15-cli--все-флаги) 16. [URI-формат и подписки](#16-uri-формат-и-подписки) 17. [Матрица совместимости](#17-матрица-совместимости) 18. [CI/CD](#18-cicd) 19. [Что планируется сделать - Issues](#19-что-планируется-сделать--issues) 20. [Контрибуторы](#20-контрибуторы) 21. [Частые ошибки](#21-частые-ошибки) --- ## 1. Почему olcRTC существует В России работают ТСПУ (технические средства противодействия угрозам). В мобильных сетях провайдеры перешли в режим **белых списков**: ТСПУ дропает все пакеты, кроме явно разрешённых IP-адресов и SNI. Фильтрация двухуровневая: - **L3** - по IP-адресу назначения. Не разрешён → пакет физически не уходит дальше второго хопа. - **L7** - по SNI в TLS ClientHello. Есть в чёрном списке → RST. Классические обходы через VPS ломаются когда VPS не попадает в белый список. Yandex Cloud, VK Cloud, Timeweb в списке - но провайдеры активно банят инстансы используемые как прокси. **Решение olcRTC**: не пытаться попасть в белый список - использовать сервисы, которые там уже есть навсегда. Телемост, SaluteJazz и WB Stream - сервисы видеозвонков крупных российских компаний. Пока они живы, olcRTC работает. Чтобы их заблокировать - нужно заблокировать сам сервис. Трафик идёт через WebRTC SFU этих сервисов: ``` Клиент (cnc) → SFU Яндекса/Сбера/WB → Сервер (srv, ваш VPS) ``` Для ТСПУ это выглядит как обычный видеозвонок. --- ## 2. Идея и история создания ### Хронология **2025-04-03** - первый коммит `init repo`. Идея. **2025-04-06** - `remove text`. Единственная правка за целый год. **2026-04-04** - `Initialize project with base configuration and assets`. Реальный перезапуск с нуля. **2026-04-05** - За один день появляются Python PoC: - `telemost_poc_datachannel.py` - первое рабочее соединение через Telemost DataChannel - `vcsend.py` - передача данных QR-кодами через видеопоток - `flood.py` - стресс-тест соединений - `limits.py` - обнаружен лимит Telemost DataChannel: 8KB на сообщение, всё что выше молча дропается - `info.py` - исследование API Telemost **2026-04-06** - QR-код двусторонняя передача (`invicible`), первые замеры: **44 Mbps** через DataChannel. **2026-04-07** - первый Go бинарник: WebRTC туннель с ChaCha20-Poly1305 шифрованием, SOCKS5 прокси, деплой через Podman. Провайдер: только Telemost. **2026-04-08..09** - активная Go разработка: клиент-серверная архитектура, кастомный мультиплексор с sequence numbering, имена участников из файла, graceful shutdown, DNS поддержка, Android мост. **2026-04-10..11** - простой UI, Docker образ сервера, SaluteJazz PoC от community-контрибутора `0xcodepunk`. **2026-04-12..14** - большой рефакторинг: golangci-lint, Jazz провайдер с protobuf-style пакетами, автогенерация Room ID для Jazz, Windows скрипты от `DeNcHiK3713`. **2026-04-19..20** - архитектурный рефакторинг: выделение слоёв `auth` / `transport` / `link` (архитектурно `carrier` слой отвечает за WebRTC сессию), WB Stream провайдер через LiveKit SDK, видеоканальный PoC на Python. **2026-04-21..22** - `videochannel` транспорт (данные кодируются в QR-коды внутри VP8 видеопотока через ffmpeg), `vp8channel` транспорт (данные в VP8 payload), NVENC поддержка. **2026-04-25..30** - tile кодек для videochannel с Reed-Solomon коррекцией ошибок, `vp8channel` поверх KCP для надёжной доставки, замена самописного мультиплексора на smux. **2026-05-01..06** - `seichannel` (данные в H264 SEI NAL-юнитах), E2E тесты на реальных провайдерах, URI-формат и формат подписок, `-client-id` для привязки клиента к серверу, SOCKS5 аутентификация. **2026-05-07..10** - финальная полировка: исправлен throughput bug в vp8channel (ограничение было в 32 раза ниже реального), документация, SEI конфигурация, `-socks-user`/`-socks-pass`. ### Статья на Хабре Проект описан в двух статьях на Хабре: - *«Это - всё что вам надо знать о белых списках»* - технический анализ как работает фильтрация, 63k IP в белом списке из 46 млн российских, методы обхода - *«BAREBONE2022: чтобы заблокировать этот протокол придётся запретить MAX и Yandex»* - описание идеи olcRTC, первые замеры скорости --- ## 3. Как это работает ``` Браузер/приложение │ (обычные TCP соединения) ▼ SOCKS5 :8808 ← cnc (клиент), работает на вашей машине │ │ ChaCha20-Poly1305 │ smux поверх muxconn │ ▼ Transport (datachannel / vp8channel / seichannel / videochannel) │ ▼ Auth (jazz / wbstream / telemost) │ WebRTC DataChannel или VideoTrack ▼ SFU Яндекса / Сбера / WB ← сервер в белом списке у всех провайдеров │ ▼ Transport (datachannel / vp8channel / seichannel / videochannel) │ ▼ srv (сервер), работает на вашем VPS │ (обычный TCP/DNS) ▼ Интернет ``` Клиент (`cnc`) стоит на устройстве, интернет-подключение которого работает по белому списку - чаще всего это мобильный телефон - и поднимает локальный SOCKS5. Любой браузер или приложение подключается к нему как к обычному прокси. Трафик мультиплексируется через smux, шифруется ChaCha20-Poly1305 и передаётся через выбранный транспорт поверх WebRTC SFU. Сервер (`srv`) можно установить на любое устройство с интернетом без белого списка - ваш VPS, домашний компьютер или даже другой телефон. Он подключается к той же комнате видеозвонка, получает зашифрованный поток и от своего имени делает TCP соединения к нужным адресам в интернете. ТСПУ видит трафик к IP Яндекса/Сбера/WB с корректным TLS и SNI - ничем не отличается от обычного видеозвонка. --- ## 4. Архитектура Проект разбит на чёткие слои. Каждый слой можно заменить независимо. ``` pkg/olcrtc/ публичная Go-либа (net.Conn, CreateRoom) │ cmd/olcrtc/ CLI entrypoint, парсинг флагов │ internal/app/session/ конфигурация, валидация, роутинг в server/client │ │ internal/server/ internal/client/ бизнес-логика: SOCKS5, smux │ internal/muxconn/ io.ReadWriteCloser поверх link.Link + AEAD │ internal/link/direct/ pass-through, пробрасывает в transport │ internal/transport/ интерфейс Transport + реестр ├── datachannel/ WebRTC DataChannel как byte stream ├── vp8channel/ VP8 видео + KCP поверх него ├── seichannel/ H264 SEI NAL-юниты └── videochannel/ QR-коды / тайлы в VP8 видеофрейме через ffmpeg │ internal/auth/ реестр auth-провайдеров ├── builtin/ регистрация engine/auth адаптеров └── bytestream.go ByteStream, VideoTrack capability │ internal/engine/ WebRTC движки (wire-level SFU протоколы) ├── livekit/ LiveKit SDK (wbstream использует) ├── salutejazz/ SaluteJazz (salutejazz.ru) └── goolom/ Yandex Goolom (telemost.yandex.ru) │ internal/auth/ сервисные auth-провайдеры (HTTP login flows) ├── telemost/ Yandex Telemost → engine/goolom ├── salutejazz/ SaluteJazz → engine/salutejazz └── wbstream/ WB Stream → engine/livekit │ internal/crypto/ ChaCha20-Poly1305 AEAD internal/names/ генератор имён участников internal/protect/ Android VPN protect() интеграция internal/logger/ структурированное логирование internal/link/ интерфейс Link + реестр internal/e2e/ E2E тесты на реальных провайдерах ``` --- ## 5. Структура репозитория ### Корень | Файл/папка | Что это | |---|---| | `readme.md` | Краткое описание, команды сборки, ссылки | | `about.md` | Этот документ | | `SECURITY.md` | Политика безопасности | | `magefile.go` | Система сборки на Mage (аналог Makefile для Go). Таргеты: `build`, `cross`, `mobile`, `docker`, `podman`, `lint`, `test`, `e2e` | | `Dockerfile` | Многоэтапный образ: Alpine build → Alpine runtime с непривилегированным пользователем `olcrtc` | | `docker-compose.server.yml` | Compose для серверного режима | | `.gitmodules` | Субмодуль `internal/transport/videochannel/gr` - кастомные кодеки QR и tile | | `.golangci.yml` | Конфиг линтера golangci-lint | | `.github/workflows/ci.yml` | CI: тесты, покрытие, E2E, lint, сборка CLI для всех платформ, сборка Android AAR | ### `cmd/olcrtc/` | Файл | Что делает | |---|---| | `main.go` | Точка входа. Парсит флаги (`flag.FlagSet`), настраивает логирование, подавляет шум LiveKit/pion в не-debug режиме, запускает `session.Run` или `session.Gen`. Graceful shutdown по SIGTERM/SIGINT с 5-секундным таймаутом | | `main_test.go` | Юнит-тесты CLI: валидация флагов, режимы, edge cases | ### `internal/app/session/` | Файл | Что делает | |---|---| | `session.go` | Главная точка конфигурации. `RegisterDefaults()` регистрирует все engines, auth-провайдеры, links, transports. `Validate()` проверяет все флаги. `Run()` роутит в `server.Run` или `client.Run`. `Gen()` генерирует Room ID для jazz/wbstream с ретраями через `auth.RoomCreator` | | `session_test.go` | Тесты валидации конфига | ### `internal/server/` | Файл | Что делает | |---|---| | `server.go` | Серверная сторона туннеля. Подключается к комнате как второй участник звонка. Создаёт `muxconn` → `smux.Session`. Для каждого входящего smux-стрима читает JSON `ConnectRequest` от клиента с адресом назначения, устанавливает TCP соединение и гоняет байты туда-обратно. Поддерживает SOCKS5 прокси для исходящего трафика. Умеет переподключаться при разрыве | | `server_test.go` | Тесты серверной логики | ### `internal/client/` | Файл | Что делает | |---|---| | `client.go` | Клиентская сторона. Поднимает SOCKS5-сервер. Для каждого входящего подключения: SOCKS5 handshake (поддержка RFC 1929 username/password auth), создаёт smux-стрим, шлёт JSON `ConnectRequest` с адресом, гоняет байты. Переподключается при разрыве WebRTC сессии | | `client_test.go` | Тесты клиентской логики | ### `internal/muxconn/` | Файл | Что делает | |---|---| | `conn.go` | Адаптер `link.Link` → `io.ReadWriteCloser`. Каждый `Write` шифрует блок ChaCha20-Poly1305 и отдаёт в link как одно сообщение. Входящие сообщения дешифруются и буферизуются; `Read` дренирует буфер в произвольных кусках (smux не знает о границах сообщений). Синхронизация через `sync.Cond` | | `conn_test.go` | Тесты | ### `internal/link/` | Файл | Что делает | |---|---| | `link.go` | Интерфейс `Link` (`Send`, `SetOnData`, `Connect`, `Close` и т.д.) + реестр | | `link_test.go` | Тесты реестра | | `direct/direct.go` | Единственная реализация Link. Pass-through: создаёт Transport и форвардит вызовы. Называется "direct" потому что нет промежуточного relay - данные идут прямо в transport | | `direct/direct_test.go` | Тесты | ### `internal/transport/` | Файл | Что делает | |---|---| | `transport.go` | Интерфейс `Transport` + реестр. `Features` описывает: надёжность, упорядоченность, message-oriented или stream, макс. размер payload | | `transport_test.go` | Тесты реестра | | `datachannel/transport.go` | Самый простой транспорт. Открывает ByteStream у auth-провайдера (DataChannel), просто форвардит байты. Лимит payload: 12KB | | `vp8channel/transport.go` | Данные кодируются в VP8 видеофреймы. Поверх auth-провайдера строится KCP (надёжный UDP-подобный протокол) для реорганизации и ретрансмиссии. Данные батчатся по N фреймов за тик. Keepalive через keyframe | | `vp8channel/kcp.go` | KCP сессия: conv ID = `0xC0FFEE01`, MTU 1400, окно 4096 сегментов. Length-prefix framing поверх KCP stream mode (workaround бага kcp-go с фрагментацией) | | `vp8channel/kcpconn.go` | `io.ReadWriteCloser` адаптер для KCP | | `seichannel/transport.go` | Данные передаются в SEI NAL-юнитах внутри H264 видеопотока. Собственный бинарный протокол с magic `OVC1`, версией, типами фреймов Data/Ack, CRC32, sequence numbers. ACK timeout, фрагментация, ретрансмиссия | | `seichannel/h264.go` | Сборка H264 Access Unit с SEI payload. UUID для SEI: `5dc03ba8-450f-4b55-9a77-1f916c5b0739`. Статичные SPS/PPS/IDR как базовые заголовки | | `videochannel/transport.go` | Данные визуально кодируются в кадры (QR-коды или тайлы), кадры транслируются через VP8 видеопоток. ffmpeg запускается как subprocess для кодирования/декодирования. ACK-based flow control с sequence numbers | | `videochannel/visual.go` | Рендеринг кадров: QR-коды через `gr/qr`, тайлы через `gr/tile` с Reed-Solomon. Декодирование входящих кадров | | `videochannel/ffmpeg.go` | ffmpeg encoder/decoder как subprocess с pipe. Поддержка VP8, H264. Hardware acceleration через NVENC. Таймаут на получение фрейма | | `videochannel/frame.go` | Протокол фреймов videochannel | ### `internal/carrier/` | Файл | Что делает | |---|---| | `carrier.go` | Интерфейс `Session` + реестр. `Capabilities` описывает что умеет auth-провайдер: ByteStream и/или VideoTrack | | `bytestream.go` | `ByteStream` и `VideoTrack` интерфейсы | | `carrier_test.go` | Тесты | | `builtin/register.go` | Регистрирует все engine/auth комбинации в реестре auth | | `builtin/engine_adapter.go` | Адаптер `engine.Session` → `auth.Provider` + `registerDirect()` для режима без auth | ### `internal/engine/` Wire-level SFU протоколы. Каждый умеет Connect/Send/Close/WatchConnection/SetEndedCallback. | Пакет | Что делает | |---|---| | `engine.go` | Интерфейс `Session` + реестр. `New()` создаёт сессию по имени | | `livekit/` | LiveKit SDK. Самый стабильный движок — минимальная прослойка поверх lksdk | | `salutejazz/` | SaluteJazz. Signaling через HTTP API. Protobuf-style DataChannel пакеты. KCP, автопереподключение | | `goolom/` | Yandex Goolom (Telemost backend). Signaling через WebSocket. Двухуровневый keepalive. Автопереподключение с refresh токена | ### `internal/auth/` Сервисные HTTP auth-провайдеры. Каждый реализует `auth.Provider` (`Engine() string`, `Issue() Credentials`). Опционально — `auth.RoomCreator` (`CreateRoom()`). | Пакет | Что делает | |---|---| | `auth.go` | Интерфейсы `Provider`, `RoomCreator`, `Credentials`. Реестр | | `telemost/` | Yandex Telemost: логин гостя, получение Goolom токена. Не поддерживает создание комнат | | `salutejazz/` | SaluteJazz: создание комнаты, получение SDP токена. Поддерживает `CreateRoom()` | | `wbstream/` | WB Stream: регистрация гостя, создание стрима. Поддерживает `CreateRoom()` | ### `pkg/olcrtc/` Публичная Go-либа для встраивания olcrtc в другие приложения (sing-box и т.п.). | Файл | Что делает | |---|---| | `olcrtc.go` | `Config`, `Session`, `New()`, `Dial() net.Conn`, `CreateRoom()`, `RegisterDefaults()` | | `conn.go` | `net.Conn` реализация: `Read` из io.Pipe (кормится из `OnData`), `Write` → `engine.Send`, `Close` закрывает пайп и сессию. При `SetEndedCallback` пайп закрывается с `ErrSessionEnded` | ### `internal/crypto/` | Файл | Что делает | |---|---| | `chacha.go` | ChaCha20-Poly1305 AEAD. 32-байтовый ключ. Каждый Encrypt генерирует случайный nonce и prepend его к ciphertext. Decrypt проверяет AEAD тег | | `chacha_test.go` | Тесты | ### `internal/names/` | Файл | Что делает | |---|---| | `names.go` | Генератор случайных имён участников для WebRTC комнаты. Имена загружаются из `data/names` и `data/surnames` (встроены через `//go:embed`). Можно переопределить внешними файлами. `Generate()` возвращает "Имя Фамилия" с крипто-рандомом | | `names_test.go` | Тесты | ### `internal/protect/` | Файл | Что делает | |---|---| | `protect.go` | Android VPN protect() интеграция. `Protector func(fd int) bool` - если установлен, вызывается перед каждым connect чтобы сокет не роутился через VPN (нужно для корректной работы в связке с VPN-приложением на Android) | | `protect_test.go` | Тесты | ### `internal/logger/` | Файл | Что делает | |---|---| | `logger.go` | Структурированный логгер с уровнями Info/Warn/Error/Debug/Verbose. В не-debug режиме подавляет шум pion/LiveKit | | `logger_test.go` | Тесты | ### `internal/e2e/` | Файл | Что делает | |---|---| | `tunnel_test.go` | E2E тесты на реальных провайдерах. Матрица всех auth × transport комбинаций. Запускается с флагом `-olcrtc.real-e2e`. В CI запускается на каждый push | ### `mobile/` | Файл | Что делает | |---|---| | `mobile.go` | gomobile-совместимый API для Android/iOS. Синглтон: `Start()`, `Stop()`, `IsRunning()`. `SocketProtector` интерфейс для Android VPN bypass. `LogWriter` интерфейс для получения логов в Kotlin/Java. По умолчанию использует `vp8channel` транспорт | | `mobile_test.go` | Тесты mobile API | ### `code/` - Python PoC скрипты | Файл | Что делает | |---|---| | `telemost_poc_datachannel.py` | Базовый PoC: два гостя в одной Telemost комнате, обмен данными через DataChannel | | `telemost_poc_videochannel.py` | Передача данных QR-кодами в видеопотоке Telemost | | `telemost_info.py` | Сбор полной информации о Telemost конференции: участники, кодеки, ICE серверы, SDP | | `jazz_poc_datachannel.py` | PoC DataChannel через SaluteJazz | | `jazz_info.py` | Информация о Jazz конференции | | `wbstream_poc_datachannel.py` | PoC DataChannel через WB Stream | | `wbstream_poc_videochannel.py` | PoC видеоканала через WB Stream | | `wbstream_info.py` | Информация о WB Stream комнате | | `secretny_ddoos.py` | Утилита для стресс-тестирования (flood) | | `init.sh` | Скрипт инициализации окружения | | `requirements.txt` | Python зависимости: aiortc, opencv, pyzbar и др. | ### `script/` | Файл | Что делает | |---|---| | `srv.sh` | Интерактивный скрипт запуска сервера через Podman. Задаёт вопросы про auth/transport/room/key, собирает образ, запускает контейнер. Флаги: `--branch=` (сменить ветку), `--no-cache` (очистить Go-кеш перед сборкой) | | `cnc.sh` | Интерактивный скрипт запуска клиента через Podman | | `docker/olcrtc-entrypoint.sh` | Docker entrypoint: читает env переменные, формирует CLI флаги, запускает `olcrtc` | | `docker/olcrtc-healthcheck.sh` | Docker healthcheck: проверяет что процесс запущен | ### `data/` | Файл | Что делает | |---|---| | `names` | Список русских имён для генератора имён участников | | `surnames` | Список русских фамилий | ### `docs/` | Файл | Что делает | |---|---| | `fast.md` | Быстрый старт через скрипты (Podman) | | `manual.md` | Мануальная сборка: Go, mage, кросс-компиляция, все шаги | | `settings.md` | Матрица совместимости auth×transport, все CLI флаги с описанием, готовые команды | | `uri.md` | URI формат для клиентских приложений: `olcrtc://?@#%$` | | `sub.md` | Формат подписок: список серверов в одном файле с метаданными | --- ## 6. Auth-провайдеры Auth-провайдер — это WebRTC сервис видеозвонков, через который идёт туннель. Все три в белых списках у российских провайдеров. ### SaluteJazz (`jazz`) - Сервис видеозвонков от Сбера: `salutejazz.ru` - Не требует регистрации для участника (только организатор) - DataChannel работает, но Jazz **банит IP** за паттерны трафика характерные для DataChannel туннеля - VideoTrack работает стабильно - Поддерживает автогенерацию Room ID (`-mode gen`) - Инициализация звонка изнутри автоматически реализована ### Yandex Telemost (`telemost`) - Сервис видеозвонков от Яндекса: `telemost.yandex.ru` - **Удалил DataChannel** - его больше нет в Telemost - VideoTrack работает - Требует создания комнаты вручную через сайт (нет автогенерации) - Двухуровневый keepalive: WebSocket ping + app-level ping ### WB Stream (`wbstream`) - Сервис трансляций от Wildberries: `stream.wb.ru` - **Рекомендуется** - самый стабильный - Минимальная прослойка, почти прямой relay - Работает со всеми транспортами: datachannel, vp8channel, seichannel, videochannel - Поддерживает автогенерацию Room ID (`-mode gen`) - Инициализация звонка автоматически --- ## 7. Transports - транспорты Transport определяет как именно данные упаковываются в WebRTC поток. ### datachannel Самый простой и быстрый. Данные идут напрямую через WebRTC DataChannel (SCTP over DTLS). - Лимит payload: 12KB на сообщение (ограничение SFU) - Надёжный, упорядоченный (SCTP гарантирует) - Работает с jazz (нежелательно - банят) и wbstream - **Лучшая комбинация: `wbstream + datachannel`** ### vp8channel Данные упаковываются в VP8 видеофреймы. Поверх этого строится KCP - надёжный протокол с повторной передачей, работающий поверх ненадёжного канала. - Работает везде где есть VideoTrack (jazz, telemost, wbstream) - Большой пинг из-за батчинга фреймов - KCP параметры: MTU 1400, окно 4096, conv ID `0xC0FFEE01` - Рекомендуется: `-vp8-fps 60 -vp8-batch 64` (если возникают проблемы с производительностью или стабильностью, попробуйте снизить FPS вдвое, например до 30) ### seichannel Данные передаются в SEI (Supplemental Enhancement Information) NAL-юнитах H264 видеопотока. SEI - стандартный механизм для метаданных в H264. - Собственный бинарный протокол: magic `OVC1` (0x4f564331), версия, тип Data/Ack, CRC32, sequence numbers - UUID для SEI payload: `5dc03ba8-450f-4b55-9a77-1f916c5b0739` - ACK timeout (по умолчанию 3с), фрагментация, ретрансмиссия до 4 попыток - Не работает с telemost - Рекомендуется: `-fps 60 -batch 64 -frag 900 -ack-ms 2000` ### videochannel Данные визуально кодируются в видеофреймы через ffmpeg. Два визуальных кодека: **qrcode** - данные кодируются в QR-код, QR рендерится в VP8 кадр. На приёмнике VP8 декодируется и QR сканируется. Использует библиотеку `gr/qr` (субмодуль). Настройки: разрешение, ECC уровень (`low`/`medium`/`high`/`highest`), размер фрагмента. **tile** - тайловый кодек, только 1080x1080. Пиксели кодируют биты напрямую. Reed-Solomon коррекция ошибок. Параметры: размер тайла в пикселях (1..270), процент избыточности (0..200). Быстрее QR но нестабильнее. Общее: ffmpeg как subprocess, поддержка NVENC, VP8 видеопоток. Самый медленный транспорт, но работает везде. --- ## 8. Шифрование Весь туннельный трафик шифруется **ChaCha20-Poly1305** (XChaCha20-Poly1305 через `golang.org/x/crypto`). - Ключ: 32 байта, передаётся как hex строка (64 символа) - Генерация: `openssl rand -hex 32` - Каждое сообщение: случайный nonce (24 байта) prepend к ciphertext + AEAD тег - Ключ должен совпадать на сервере и клиенте - Шифрование происходит в `muxconn` - до передачи в transport/auth WebRTC сам по себе шифрует трафик через DTLS-SRTP, но olcRTC добавляет поверх свой слой - провайдер видит только зашифрованный blob. --- ## 9. Мультиплексирование Через один WebRTC DataChannel / VideoTrack одновременно могут идти сотни TCP соединений браузера. Реализация через **smux** (`github.com/xtaci/smux`) - библиотека мультиплексирования потоков, аналог HTTP/2 multiplexing. До мая 2026 был самописный мультиплексор с sequence numbering и ручным out-of-order handling. Заменён на smux поверх KCP для vp8channel, и smux напрямую для datachannel. `muxconn.Conn` адаптирует `link.Link` (message-oriented) в `io.ReadWriteCloser` (stream-oriented) который нужен smux. Каждый `Write` = одно зашифрованное сообщение в link. --- ## 10. SOCKS5 прокси Клиент (`cnc`) поднимает локальный SOCKS5-сервер. **Поддерживается:** - SOCKS5 (RFC 1928) с командой CONNECT - Аутентификация username/password (RFC 1929) через `-socks-user`/`-socks-pass` - SOCKS5h (hostname resolution на стороне сервера) - DNS запросы идут через туннель - Без аутентификации (по умолчанию) **Адрес по умолчанию:** `127.0.0.1:8808` **Использование:** ```sh curl --socks5-hostname 127.0.0.1:8808 https://icanhazip.com export all_proxy=socks5h://127.0.0.1:8808 export all_proxy=socks5h://user:pass@127.0.0.1:8808 # с авторизацией ``` **Сервер** (`srv`) может сам ходить через SOCKS5 прокси для исходящего трафика (`-socks-proxy`, `-socks-proxy-port`). --- ## 11. Mobile / Android `mobile/mobile.go` - gomobile-совместимый API. Собирается в `olcrtc.aar` через `mage mobile` (`gomobile bind`). Community Android клиент: [alananisimov/olcbox](https://github.com/alananisimov/olcbox) **API:** - `Start(auth, roomID, clientID, keyHex string)` - запустить туннель - `Stop()` - остановить - `IsRunning() bool` - `SetProtector(p SocketProtector)` - Android VPN bypass (VpnService.protect) - `SetLogWriter(w LogWriter)` - получать логи в Kotlin/Java По умолчанию использует `vp8channel` транспорт (наиболее совместимый). Если auth - wbstream или jazz и DataChannel доступен - переключается на `datachannel`. `protect.go` - механизм Android VPN protect: перед каждым `connect()` вызывается Kotlin-коллбэк который вызывает `VpnService.protect(fd)`. Без этого трафик olcRTC может рекурсивно идти через тот же VPN. --- ## 12. Go-либа (pkg/olcrtc) `pkg/olcrtc` - публичная Go-либа для встраивания olcrtc в другие Go-программы (sing-box, кастомные клиенты). Каждый провайдер реализует метод `DefaultServiceURL()`, что позволяет библиотеке автоматически заполнять адрес SFU при выборе провайдера. ```go import "github.com/openlibrecommunity/olcrtc/pkg/olcrtc" olcrtc.RegisterDefaults() // создать комнату (wbstream или jazz) roomID, err := olcrtc.CreateRoom(ctx, "wbstream") // подключиться через auth-провайдер sess, err := olcrtc.New(ctx, olcrtc.Config{ Auth: "wbstream", RoomID: roomID, DNSServer: "1.1.1.1:53", }) // или напрямую к SFU без auth sess, err := olcrtc.New(ctx, olcrtc.Config{ Engine: "livekit", URL: "wss://sfu.example/", Token: "", }) // получить net.Conn (блокирует до готовности data channel) conn, err := sess.Dial(ctx) // conn реализует net.Conn — передаётся в sing-box или любой io.ReadWriter // когда сессия умирает — Read() возвращает ErrSessionEnded ``` **`CreateRoom`** поддерживается только провайдерами `wbstream` и `jazz`. Telemost не поддерживает создание комнат (возвращает `ErrRoomCreationUnsupported`). **`WatchConnection`** запускается автоматически внутри `Dial` — при падении сессии `Read` разблокируется с ошибкой. --- ## 13. Python PoC скрипты Исторический слой - с этого всё начиналось. Используются для исследования API провайдеров и проверки гипотез. **Telemost:** - `telemost_poc_datachannel.py` - первый рабочий туннель, обнаружен лимит 8KB DataChannel (молча дропает больше) - `telemost_poc_videochannel.py` - QR в видео, `vcsend.py` - передача файлов - `telemost_info.py` - полный дамп SDP, ICE серверов, участников **Jazz:** - `jazz_poc_datachannel.py` - DataChannel через Jazz SFU - `jazz_info.py` - информация о конференции **WB Stream:** - `wbstream_poc_datachannel.py` - DataChannel - `wbstream_poc_videochannel.py` - видеоканал - `wbstream_info.py` - информация Для запуска: `pip install -r code/requirements.txt` --- ## 14. Сборка и деплой ### Зависимости - Go 1.25+ - Mage (`go install github.com/magefile/mage@latest`) - ffmpeg (для videochannel транспорта) - git с `--recurse-submodules` (субмодуль `gr` для videochannel кодеков) - gomobile (для Android сборки) ### Mage таргеты ```sh mage build # текущая платформа mage buildCLI # только CLI mage buildCLIB # CLI + b-codec (клонирует внешний репо, собирает libb.so) mage cross # все платформы: linux/amd64, linux/arm64, windows/amd64, # darwin/amd64, darwin/arm64, freebsd/amd64, freebsd/arm64, # openbsd/amd64, openbsd/arm64 mage mobile # Android AAR через gomobile mage podman # Docker образ через podman mage docker # Docker образ через docker mage lint # golangci-lint mage test # go test -race ./... mage e2e # E2E тесты (нужны реальные провайдеры) mage clean # удалить build/ ``` ### Быстрый старт через скрипты (Podman) ```sh git clone https://github.com/openlibrecommunity/olcrtc --recurse-submodules cd olcrtc # на сервере (VPS): ./script/srv.sh # на клиенте: ./script/cnc.sh ``` ### Мануальный запуск ```sh # генерация ключа openssl rand -hex 32 # генерация room ID (для jazz/wbstream) ./olcrtc -mode gen -auth wbstream -dns 1.1.1.1:53 -amount 1 -data data # сервер ./olcrtc -mode srv -auth wbstream -transport datachannel \ -id ROOM_ID -client-id default -key HEX_KEY \ -link direct -dns 1.1.1.1:53 -data data # клиент ./olcrtc -mode cnc -auth wbstream -transport datachannel \ -id ROOM_ID -client-id default -key HEX_KEY \ -link direct -dns 1.1.1.1:53 -data data \ -socks-host 127.0.0.1 -socks-port 8808 ``` ### Docker ```sh docker run -e OLCRTC_AUTH=wbstream \ -e OLCRTC_ROOM_ID=... \ -e OLCRTC_KEY=... \ olcrtc/server:local ``` --- ## 15. CLI - все флаги ### Обязательные (для всех режимов) | Флаг | Описание | |---|---| | `-mode` | `srv` - сервер, `cnc` - клиент, `gen` - генерация Room ID | | `-auth` | `telemost`, `jazz`, `wbstream`, `none` | | `-transport` | `datachannel`, `vp8channel`, `seichannel`, `videochannel` | | `-id` | Room ID | | `-client-id` | Идентификатор клиента, должен совпадать на srv и cnc. Один client-id может держать бесконечное количество соединений, но SFU ограничивает полосу на участника — оптимально 1 client-id = 1 пользователь (не обязательно) | | `-key` | Ключ шифрования hex 64 символа | | `-link` | Всегда `direct` | | `-data` | Всегда `data` | | `-dns` | DNS сервер, например `1.1.1.1:53` | ### Прямой режим Позволяет подключиться напрямую к любому LiveKit/Goolom/SaluteJazz SFU. При использовании `-auth none` флаги `-engine`, `-url` и `-token` обязательны. При использовании именованного провайдера эти флаги заполняются автоматически из `DefaultServiceURL()`, но могут быть переопределены вручную. | Флаг | Описание | |---|---| | `-engine` | Движок: `livekit`, `goolom`, `salutejazz` | | `-url` | WebSocket URL SFU | | `-token` | Токен доступа | ### Необязательные | Флаг | Описание | |---|---| | `-debug` | Verbose логи | ### Только для клиента (`-mode cnc`) | Флаг | По умолчанию | Описание | |---|---|---| | `-socks-host` | `127.0.0.1` | Адрес SOCKS5 | | `-socks-port` | `1080` | Порт SOCKS5 | | `-socks-user` | - | Логин (опционально) | | `-socks-pass` | - | Пароль (опционально) | ### Только для сервера (`-mode srv`) | Флаг | Описание | |---|---| | `-socks-proxy` | Адрес SOCKS5 прокси для исходящего трафика | | `-socks-proxy-port` | Порт этого прокси | ### Режим генерации (`-mode gen`) | Флаг | Описание | |---|---| | `-auth` | `jazz` или `wbstream` (telemost не поддерживает) | | `-amount` | Количество комнат для генерации | ### vp8channel | Флаг | Default | Описание | |---|---|---| | `-vp8-fps` | 25 | FPS VP8 потока | | `-vp8-batch` | 1 | Кадров за тик | ### seichannel | Флаг | Default | Описание | |---|---|---| | `-fps` | 20 | FPS H264 потока | | `-batch` | 1 | Кадров за тик | | `-frag` | 900 | Размер фрагмента в байтах | | `-ack-ms` | 2000 | ACK timeout в мс | ### videochannel | Флаг | Default | Описание | |---|---|---| | `-video-codec` | `qrcode` | `qrcode` или `tile` | | `-video-w` | 1920 | Ширина | | `-video-h` | 1080 | Высота | | `-video-fps` | 30 | FPS | | `-video-bitrate` | `2M` | Битрейт | | `-video-hw` | `none` | `none` или `nvenc` | | `-video-qr-recovery` | `low` | ECC: `low`/`medium`/`high`/`highest` | | `-video-qr-size` | 0 (авто) | Размер фрагмента QR в байтах | | `-video-tile-module` | 4 | Размер тайла в пикселях 1..270 | | `-video-tile-rs` | 20 | Reed-Solomon паритет % 0..200 | --- ## 16. URI-формат и подписки ### URI формат Соглашение для клиентских приложений. Сам `olcrtc` не парсит - используется в сторонних клиентах. ``` olcrtc://?@#%$ ``` Где `` - опциональный блок `` с параметрами транспорта. **Примеры:** ``` olcrtc://wbstream?datachannel@room-01#d823fa...%android-01$RU / olc free sub olcrtc://wbstream?vp8channel@room-01#d823fa...%android-01$RU olcrtc://telemost?seichannel@room-01#d823fa...%client$RU ``` ### Формат подписки (sub.md) Текстовый файл со списком серверов. Хостится на сервере как plain text. ```text #name: Zarazaex Free RU #update: 1778011200 #refresh: 10m #icon: 🇷🇺 olcrtc://wbstream?datachannel@room-01#key%client-id$RU / free ##name: RU-1 ##ip: 1.2.3.4 ##comment: basic free node ``` Клиентские приложения читают этот файл и предлагают список серверов пользователю (аналог подписок в v2ray/sing-box). --- ## 17. Матрица совместимости | Transport | telemost | jazz | wbstream | |---|:---:|:---:|:---:| | datachannel | - | `*` | `+` | | vp8channel | `+` | `+` | `+` | | seichannel | - | `+` | `+` | | videochannel | `+` | `+` | `+` | - `+` работает - `-` не поддерживается - `*` работает, но jazz банит IP за паттерны datachannel трафика **Рекомендуется:** `wbstream + datachannel` - максимальная скорость, минимальный пинг, без бана. **Скорость по убыванию:** `datachannel` > `vp8channel` > `seichannel` > `videochannel` **Рекордный замер:** на связке `wbstream + datachannel` (test by `x2827262628281872727`) зафиксированы пинг **7 мс** и скорость **792.62 Mbps на вход / 749.69 Mbps на выход** - максимум, измеренный через olcRTC. speedtest --- ## 18. CI/CD `.github/workflows/ci.yml` - GitHub Actions, запускается на каждый push/PR в master. | Job | Что делает | |---|---| | `test` | `go test -count=1 ./...` | | `coverage` | `go test --cover ./...` | | `real-e2e` | E2E матрица всех auth×transport на реальных провайдерах (25 мин таймаут) | | `lint` | golangci-lint | | `build-cli` | `mage cross` - кросс-компиляция для 9 платформ, артефакты в Actions | | `build-android` | `mage mobile` - Android AAR, артефакт в Actions | Go версия в CI: 1.25.x --- ## 19. Что планируется сделать - Issues ### Открытые **Issue #22 - реализовать поддержку stream.wb.ru** `enhancement` WB Stream - текущий приоритет. Основа уже реализована, остаётся: - [ ] Симуляция XHR телеметрии (маскировка под легитимный клиент) - [ ] Симуляция задержек и обрезание до размера реальных сообщений - [ ] Система завершения звонка - [ ] Авто перезапуск звонка если идёт слишком долго - [ ] Юзать TLS стек Chrome как naiveproxy **Issue #2 - реализовать поддержку telemost.yandex.ru** `enhancement` - [ ] Симуляция XHR телеметрии - [ ] Симуляция задержек - [ ] Инициализация звонка изнутри автоматически - [ ] Система завершения звонка - [ ] Авто перезапуск звонка - [ ] TLS стек Chrome **Issue #1 - реализовать поддержку salutejazz.ru** `enhancement` - [ ] Симуляция XHR телеметрии - [ ] Симуляция задержек - [ ] Система завершения звонка - [ ] Авто перезапуск звонка - [ ] TLS стек Chrome ### Закрытые (уже сделано) | Issue | Что было | |---|---| | #44 | Very high ping - исправлен throughput bug vp8channel | | #40 | Подключение нескольких устройств - реализовано через client-id | | #39 | Oracle VPS поддержка | | #38 | Стандартный URI формат - реализован | | #37 | Jitsi Meet - не планируется | | #33 | iOS клиент - в планах | | #27 | Инструкция - написана | | #26 | SIP003 transport - не планируется | | #25 | TLS/DTLS фингерпринтинг | | #9 | Нормальный мультиплексор - реализован (smux) | | #3 | macOS/Linux/Android/Windows поддержка - реализована | --- ## 20. Контрибуторы | Контрибутор | Коммиты | Вклад | |---|---|---| | **zarazaex69** (zarazaex@tuta.io) | 417 | Автор проекта. Вся архитектура, все транспорты, auth-providers, crypto, mobile API, CI, документация | | **zowue** (heminpo49@gmail.com) | 24 | Соавтор. Упомянут в оригинальной статье на Хабре | | **TheDevisi** (devisinov@gmail.com) | 20 | UI, SOCKS5 улучшения, Windows поддержка, фиксы | | **Qtozdec** | 10 | Фиксы, URI добавление | | **Alexander Anisimov** / alananisimov | 6 | Android клиент [olcbox](https://github.com/alananisimov/olcbox), mobile.go фиксы, mobile provider config | | **s0me0ne-25** | 4 | Расширение датасета имён и фамилий, правки документации | | **Kot-nikot** | 3 | Фиксы | | **HLNikNiky** / Sesdear | 2 | URI добавление, фиксы | | **Denis Suchok** / DeNcHiK3713 | 1 | Windows Podman скрипты | | **0xcodepunk** | 1 | SaluteJazz PoC DataChannel (issue #10) | | **scalebb2** | 1 | - | --- ## 21. Частые ошибки ### `i/o timeout` при резолве или "днслик" (DNS leak) **Симптомы:** - Клиент не может зарезолвить адрес SFU (например `stream.wb.ru`). - DNS запросы "утекают" мимо туннеля. **Причина:** порт 53 (стандартный DNS) может перехватываться или блокироваться провайдером. **Решение:** использовать DNS сервер на 443 порту. Многие публичные DNS серверы (например Google) поддерживают запросы на 443 порту. ```sh # в скрипте или через флаг -dns укажите: 8.8.8.8:443 ``` --- ### Сборка вылетает / Ошибка компиляции (не хватает ОЗУ) **Симптомы:** процесс сборки (`mage build`, `go build` или внутри Docker/Podman) внезапно прерывается с ошибкой `signal: killed` или `out of memory`. **Причина:** для сборки проекта (особенно с тяжелыми зависимостями или в контейнере) может не хватать оперативной памяти (нужно минимум 2ГБ, лучше 4ГБ+). **Решение:** включите **SWAP** (файл подкачки). На Linux это делается так: ```bash sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # чтобы сохранить после перезагрузки: echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab ``` --- ### `Connection refused` на порту SOCKS5 + `i/o timeout` при резолве **Симптомы:** ``` curl: (7) Failed to connect to 127.0.0.1 port 8808 after 0 ms: Connection refused ``` Клиент сообщает `[+] Client started successfully!`, но SOCKS5 порт не слушает. В логах контейнера: ``` client: failed to connect link: transport connect: stream connect: connect: get room token: register guest: do request: Post "https://stream.wb.ru/...": dial tcp: lookup stream.wb.ru: i/o timeout ``` **Причина:** клиент не смог зарезолвить `stream.wb.ru` через указанный DNS сервер. Соединение не установилось, SOCKS5 не поднялся. **Решение:** указать другой DNS сервер в скрипте. Вместо дефолтного `1.1.1.1` попробовать `8.8.8.8` или `77.88.8.8`: ```sh # при запуске cnc.sh - в поле DNS ввести: 8.8.8.8:53 # или 77.88.8.8:53 ``` При ручном запуске: ```sh ./olcrtc -mode cnc ... -dns 8.8.8.8:53 ``` После смены DNS в логах должна появиться строка: ``` SOCKS5 server listening on 0.0.0.0:8808 ``` ### `dial tcp4 : i/o timeout` на сервере (VPS блокирует исходящий трафик) **Симптомы:** В логах сервера (`-mode srv`) появляются строки вида: ``` sid=59 dial 157.240.205.60:443 failed (10.000774052s): dial failed: dial tcp4 157.240.205.60:443: i/o timeout sid=69 dial 194.221.250.50:443 failed (10.002092858s): dial failed: dial tcp4 194.221.250.50:443: i/o timeout sid=81 dial 149.154.167.41:5222 failed (10.000219783s): dial failed: dial tcp4 149.154.167.41:5222: i/o timeout ``` Таймаут всегда ровно 10 секунд (это дефолтный `Timeout: 10 * time.Second` в `server.go`). Затронутые сайты открываются нормально с локального браузера через прокси, но сервер до них не добирается. **Причина:** хостинг-провайдер или фаервол VPS блокирует исходящие соединения к определённым IP-адресам или портам. Типичные жертвы: - `157.240.x.x` - Facebook/Meta (порты 80, 443) - `194.221.x.x`, `149.154.x.x`, `91.108.x.x`, `91.105.x.x` - Telegram (порты 80, 443, 5222) Российские VPS-провайдеры блокируют исходящий трафик к этим сайтам на уровне фаервола хостинга - независимо от настроек iptables на самой машине. **Диагностика:** выполнить прямо на сервере: ```sh curl -v --connect-timeout 5 https://157.240.205.60 curl -v --connect-timeout 5 https://149.154.167.41 ``` Если таймаут - проблема на уровне хостинга. **Решение:** 1. Сменить хостинг-провайдера или локацию на того, кто не блокирует исходящий трафик. 2. Использовать на сервере исходящий SOCKS5 прокси (`-socks-proxy`/`-socks-proxy-port`), который не заблокирован: ```sh ./olcrtc -mode srv ... -socks-proxy 1.2.3.4 -socks-proxy-port 1080 ``` Это ошибка не на стороне olcRTC - он корректно логирует ошибки и продолжает работу. Соединения к незаблокированным адресам проходят без проблем. Проблема на стороне хостинга или фаервола. --- ## Контакты - Telegram канал: [@openlibrecommunity](https://t.me/openlibrecommunity) - бесплатный прокси в закрепе, обновления, анонсы - Telegram автора: [@zarazaexe](https://t.me/zarazaexe) - Email: [zarazaex@tuta.io](mailto:zarazaex@tuta.io) - GitHub: [openlibrecommunity](https://github.com/openlibrecommunity) - Android клиент: [alananisimov/olcbox](https://github.com/alananisimov/olcbox) - Белые списки (еженедельное обновление): [openlibrecommunity/twl](https://github.com/openlibrecommunity/twl)