4 Commits
v1.1.0 ... main

4 changed files with 521 additions and 161 deletions

314
HABR.md
View File

@@ -1,86 +1,40 @@
# Написал обход блокировки Telegram на Rust за 300 строк — без VPN, серверов и абонентки # TGLock v2: переписал обход Telegram с нуля — теперь работает на маке, и один прокси на всю квартиру
**Простой · 6 мин · Rust · Open source · Сетевые технологии · Из песочницы** **Простой · 7 мин · Rust · Open source · macOS · Сетевые технологии**
**TL;DR:** Open-source приложение **TGLock** на Rust. Один клик — Telegram работает. Локальный SOCKS5-прокси заворачивает MTProto в WebSocket через `web.telegram.org`. Провайдер видит HTTPS. Windows, macOS, Linux. 300 строк кода. GitHub — [by-sonic/tglock](https://github.com/by-sonic/tglock). **TL;DR:** Полмесяца назад я выложил TGLock — обход блокировки Telegram через WebSocket-туннель. Статья залетела на 183K просмотров. А потом всё сломалось. Соединения рвались через 2 минуты, DC определялся неправильно, маководы плакали в комментах. Переписал с нуля. 350 строк. Работает на macOS, Windows, Linux. Один прокси — все устройства в квартире. Код: [github.com/by-sonic/tglock](https://github.com/by-sonic/tglock).
--- ---
## Почему GoodbyeDPI больше не хватает ## Что случилось после первой статьи
GoodbyeDPI, Zapret — отличные инструменты. Они фрагментируют пакеты, ломают сигнатуры DPI, и это работало. До определённого момента. Первая версия TGLock делала простую вещь: SOCKS5-прокси заворачивал MTProto в WebSocket через `web.telegram.org`. Провайдер видит HTTPS — Telegram работает. Концепция правильная. Реализация — нет.
Проблема: провайдеры перешли от DPI к **IP-шейпингу**. Весь трафик к подсетям Telegram (149.154.x.x, 91.108.x.x) режется по скорости. Неважно, видит DPI MTProto или нет — если destination IP принадлежит Telegram, соединение троттлится. Через неделю после релиза прилетело:
Результат: GoodbyeDPI запущен, пакеты фрагментированы, DPI обманут — а Telegram всё равно грузится 10 секунд, медиа не приходят, звонки рвутся. Пинг 200+, постоянные переподключения. > «Работает 2 минуты, потом Telegram пишет ошибку прокси»
VPN решает, но: > «По умолчанию выбирает неправильное сетевое подключение, вешается на VMware-адаптер»
- Стоит денег
- Гонит **весь** трафик через чужой сервер
- Для одного Telegram — оверкилл
Нужен другой подход. > «Порт 1080 занят, как поменять?»
## Идея: WebSocket через web.telegram.org > «А на маке будет?»
Замерил: прямое TCP-соединение к серверам Telegram (149.154.167.51:443) — таймаут или 200+ мс. А вот `web.telegram.org` отвечает стабильно за 5080 мс. Логично: это «обычный сайт», провайдер его не трогает. Последний вопрос задавали чаще всего. GoodbyeDPI — только Windows. Zapret — есть tpws, но это терминал и ручная настройка. GUI для обхода Telegram на маке — **не существует**. Вообще.
Полез в [документацию MTProto](https://core.telegram.org/mtproto/transports): Решил: не патчить старый код. Переписать с нуля.
> **WebSocket:** Implementation of the WebSocket transport is **pretty much the same as with TCP**... all data received and sent through WebSocket messages is to be treated as a **single duplex stream of bytes**, just like with TCP. ## Что было не так с v1
Telegram официально поддерживает WebSocket-транспорт. Эндпоинты `kws1-5.web.telegram.org` — полноценные точки входа в сеть Telegram через WSS. ### Обрыв через 2 минуты
**Схема:** Главный баг. WebSocket-серверы Telegram (`kws*.web.telegram.org`) шлют **Ping-фреймы** каждые ~60 секунд. Если клиент не отвечает Pong — сервер закрывает соединение.
``` В v1 я использовал `split()` из `futures` чтобы разделить WebSocket-стрим на два потока — чтение и запись. Красиво, идиоматично, по учебнику. И сломано.
Telegram Desktop → SOCKS5 → TGLock → WSS (kws{dc}.web.telegram.org) → DC
Провайдер видит: HTTPS к web.telegram.org
```
Нет MTProto в трафике. Нет подозрительных IP. Обычный HTTPS. Ping приходит в read-поток. Pong нужно отправить через write-поток. Между ними — channel или shared state. В теории работает. На практике — Pong опаздывает на десятки миллисекунд, сервер считает клиента мёртвым.
## Реализация: 300 строк на Rust **Решение в v2:** один `tokio::select!` цикл, без split. WebSocket остаётся единым объектом. `biased` приоритизирует чтение WS — Pong улетает мгновенно:
Весь проект — два файла: `proxy.rs` (туннель) и `main.rs` (UI).
### SOCKS5 → определение DC → WebSocket
Когда Telegram Desktop подключается через SOCKS5, мы:
**1.** Обрабатываем SOCKS5-хендшейк и получаем destination IP.
**2.** Читаем первые 64 байта — это obfuscated2 init-пакет MTProto. Из него извлекаем настоящий DC через AES-256-CTR:
```rust
fn dc_from_init(init: &[u8; 64]) -> Option<u8> {
use aes::Aes256;
use cipher::{KeyIvInit, StreamCipher};
let mut dec = *init;
let mut c = ctr::Ctr128BE::<Aes256>::new(
init[8..40].into(),
init[40..56].into(),
);
c.apply_keystream(&mut dec);
let id = i32::from_le_bytes([dec[60], dec[61], dec[62], dec[63]]);
let dc = id.unsigned_abs() as u8;
(1..=5).contains(&dc).then_some(dc)
}
```
**3.** Открываем WebSocket к нужному DC с обязательным заголовком `Sec-WebSocket-Protocol: binary` и таймаутом 10 секунд:
```rust
let (mut ws, _) = tokio::time::timeout(
Duration::from_secs(10),
tokio_tungstenite::connect_async_tls_with_config(req, None, false, Some(tls)),
).await??;
```
**4.** Отправляем буферизованные 64 байта init-пакета как первый WebSocket-фрейм. Дальше — двунаправленный relay в одном `tokio::select!` цикле:
```rust ```rust
loop { loop {
@@ -104,72 +58,232 @@ loop {
} }
``` ```
Ключевой момент — **Ping/Pong**. Без ответа на Ping сервер закрывает соединение через ~2 минуты. Первая версия это игнорировала — пользователи жаловались на обрывы. Обратите внимание на `flush()` после каждого write в TCP. Без него tokio буферизует данные, Telegram Desktop ждёт ответ, не дожидается, переподключается. Ещё один баг v1, который маскировался под «нестабильное соединение».
### Не-Telegram трафик ### Неправильный DC
Если destination IP не принадлежит Telegram — прямой TCP passthrough. Прокси не трогает ничего лишнего. В v1 DC определялся по IP-адресу. Таблица маппинга из документации Telegram:
## Стабильность: что ломалось и как починили ```
149.154.160-163 → DC1
149.154.164-167 → DC2
91.108.56-59 → DC5
...
```
**Проблема 1: Обрыв через 2 минуты.** Проблема: в подсети `149.154.164-167` живут **и DC2, и DC4**. Telegram Desktop мог коннектиться к IP, который по таблице выглядит как DC2, а на самом деле хочет DC4. Прокси открывает WebSocket к `kws2.web.telegram.org`, отправляет данные — сервер дропает соединение. Пользователь видит «прокси не настроен».
WebSocket-сервер отправляет Ping-фреймы. Первая реализация использовала `split()` и два отдельных потока — Ping приходил в `read`-поток, а Pong нужно было отправить через `write`-поток. Решение: единый `tokio::select!` цикл без split. `biased` приоритизирует WS-чтение — Pong улетает мгновенно.
**Проблема 2: Неправильный DC.** **Решение в v2:** не угадывать DC по IP. Telegram Desktop использует **obfuscated2** транспорт. Первые 64 байта — зашифрованный init-пакет. Внутри — настоящий DC ID.
IP-маппинг ненадёжен: в подсети 149.154.164-167 живут и DC2, и DC4. Если отправить данные не в тот DC — сервер дропает соединение. Решение: извлекать DC из obfuscated2 init через AES-256-CTR.
**Проблема 3: Зависание на подключении.** Ключ: байты `[8..40]`, IV: `[40..56]`. Алгоритм: AES-256-CTR. DC ID: `i32` в байтах `[60..64]` расшифрованного пакета.
Если `kws*.web.telegram.org` не отвечает — прокси висел бесконечно. Решение: `tokio::time::timeout(10s)` на WebSocket connect.
**Проблема 4: Потеря данных.** ```rust
TCP-write без `flush()` мог буферизовать данные. Telegram Desktop ожидал ответ, не получал его, переподключался. Решение: явный `flush()` после каждого write. fn dc_from_init(init: &[u8; 64]) -> Option<u8> {
use aes::Aes256;
use cipher::{KeyIvInit, StreamCipher};
## UI: egui, не Electron let mut dec = *init;
let mut c = ctr::Ctr128BE::<Aes256>::new(
init[8..40].into(),
init[40..56].into(),
);
c.apply_keystream(&mut dec);
Нативный GUI через egui. Тёмная тема, минимальный интерфейс. Бинарник ~6 МБ, без зависимостей. let id = i32::from_le_bytes([dec[60], dec[61], dec[62], dec[63]]);
let dc = id.unsigned_abs() as u8;
(1..=5).contains(&dc).then_some(dc)
}
```
Одна кнопка — ПОДКЛЮЧИТЬ/ОТКЛЮЧИТЬ. Статистика в реальном времени: активные соединения, WebSocket-туннели, текущий DC, аптайм. 12 строк. Три крейта (`aes`, `ctr`, `cipher`). Зато DC определяется **точно**, а не «скорее всего».
## Кроссплатформенность IP-маппинг остался как fallback — на случай если init-пакет повреждён (что на практике не случается).
Ни одной строки платформо-специфичного кода. Работает на: ### Привязка к Windows
- **Windows** x64
- **macOS** Intel + Apple Silicon
- **Linux** x64
CI/CD через GitHub Actions — при создании тега автоматически собираются бинарники для всех платформ. v1 использовала:
- `netsh` для смены DNS
- Хардкоженный путь к шрифтам Windows
- `taskkill` для остановки процессов
- `ipconfig /flushdns`
## Сравнение Ни одна из этих вещей не нужна для WebSocket-прокси. DNS менять не надо — `web.telegram.org` резолвится нормально. Шрифты — egui использует встроенные. Весь платформо-специфичный код был мусором.
| | GoodbyeDPI | Zapret | VPN | **TGLock** | **v2: 0 строк платформо-специфичного кода.** Один и тот же бинарник компилируется на Windows, macOS и Linux без единого `#[cfg(target_os)]`.
## macOS: почему это важно
Среди разработчиков, дизайнеров, людей из IT — процент маководов огромный. А инструментов для обхода блокировки Telegram на маке — ноль целых, ноль десятых.
- **GoodbyeDPI** — Windows only. Даже не обсуждается.
- **Zapret** — есть `tpws` для macOS, но это CLI. Нужно: `brew install`, `sudo`, правка конфигов, ручная настройка системного прокси через `networksetup`. Для техничных людей — ОК. Для остальных — нет.
- **VPN** — работает, но гонит весь трафик. Для одного Telegram — оверкилл за $5/мес.
TGLock v2: скачал бинарник, запустил, нажал кнопку. Всё. Никакого `brew`, никакого `sudo`, никаких конфигов.
На Apple Silicon (M1M4) — нативный ARM-бинарник, ~6 МБ. На Intel-маках — x86_64 билд. Оба собираются автоматически в GitHub Actions.
### Gatekeeper
Apple блокирует неподписанные приложения. Developer ID стоит $99/год. Для бесплатного open-source — не вариант. Решение стандартное:
```bash
xattr -cr ~/Downloads/tglock-macos-arm64
chmod +x ~/Downloads/tglock-macos-arm64
```
Две команды, один раз.
## LAN-режим: один прокси на всю квартиру
Это была самая частая просьба в ишью:
> «Цель: пустить все домашние устройства с Telegram через один такой прокси на компе в локальной сети»
В v1 прокси слушал `127.0.0.1:1080` — только локально. Устройства в сети не могли подключиться.
В v2 — чекбокс **LAN** в интерфейсе. Включаешь — прокси биндится на `0.0.0.0`. Все устройства в домашней сети могут использовать прокси.
```
Телефон ──┐
Планшет ───┤── SOCKS5 → 192.168.1.42:1080 ──► TGLock ──► WSS → DC
Ноутбук ───┘
```
Приложение автоматически определяет LAN IP и показывает его в интерфейсе. На телефоне в настройках Telegram: SOCKS5, адрес — IP компьютера, порт — тот что в приложении.
Один компьютер. Все устройства. Без VPN, без роутера, без конфигов.
### Настраиваемый порт
Ещё один ишью: «порт 1080 занят другим сервисом».
Теперь порт можно менять прямо в интерфейсе. По умолчанию 1080, но если занят — ставишь любой другой. Порт валидируется при старте, в настройках Telegram автоматически отображается текущий.
## Архитектура v2
Два файла. 350 строк. Всё.
### proxy.rs (~160 строк)
```
TcpListener (0.0.0.0 | 127.0.0.1 : port)
SOCKS5 handshake
├── IP ∈ Telegram? ──► read 64-byte init
│ │
│ ▼
│ dc_from_init (AES-256-CTR)
│ │
│ ▼
│ WSS kws{dc}.web.telegram.org
│ │
│ ▼
│ select! { ws ⟷ tcp }
└── IP ∉ Telegram? ──► direct TCP relay
```
Никаких абстракций, traits, generics. Прямолинейный async-код. Каждое соединение — один `tokio::spawn`, один `select!` цикл.
### main.rs (~190 строк)
GUI на egui. Тёмная тема (GitHub Dark). Статистика в реальном времени: активные соединения, WS-туннели, текущий DC, аптайм.
Кнопка «Настроить автоматически» — открывает Telegram через `tg://socks?server=...&port=...`. Один клик до рабочего Telegram.
## CI/CD: бинарники для всех
GitHub Actions при пуше тега `v*` собирает:
| Файл | Платформа |
|---|---|
| `tglock.exe` | Windows x64 |
| `tglock-macos-arm64` | macOS Apple Silicon |
| `tglock-macos-x64` | macOS Intel |
| `tglock-linux-x64` | Linux x64 |
Четыре платформы, один workflow, автоматические релизы. Скачал — запустил — работает.
```yaml
strategy:
matrix:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: tglock.exe
- os: macos-latest
target: aarch64-apple-darwin
artifact: tglock-macos-arm64
- os: macos-latest
target: x86_64-apple-darwin
artifact: tglock-macos-x64
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: tglock-linux-x64
```
## Что изменилось: v1 vs v2
| | v1 | v2 |
|---|---|---|
| DC detection | IP-маппинг (ненадёжен) | AES-256-CTR из init (точно) |
| Ping/Pong | Игнорировался → обрыв через 2 мин | `biased` select → мгновенный Pong |
| flush() | Нет → потеря данных | Явный flush после каждого write |
| WS timeout | Нет → бесконечное зависание | 10 секунд |
| Платформы | Windows | Windows, macOS, Linux |
| DNS | Менял системный DNS | Не трогает |
| Адаптеры | Определял сетевой адаптер (баг с VMware) | Не определяет, не нужно |
| Порт | Хардкод 1080 | Настраиваемый |
| LAN | Нет | Чекбокс, 0.0.0.0 |
| Файлов | 4 модуля + bat-скрипт | 2 файла |
| Строк | ~800 | ~350 |
Половину кода удалил. Стало стабильнее.
## Сравнение с альтернативами (2026)
| | GoodbyeDPI | Zapret | VPN | **TGLock v2** |
|---|---|---|---|---| |---|---|---|---|---|
| Метод | Фрагментация | Desync | Туннель | WebSocket | | Подход | Фрагментация | Desync | Туннель | WebSocket |
| Обходит IP-шейпинг | Нет | Нет | Да | **Да** | | IP-шейпинг | Не обходит | Не обходит | Обходит | **Обходит** |
| macOS | Нет | CLI | Да | **GUI** |
| Нужен сервер | Нет | Нет | Да | **Нет** | | Нужен сервер | Нет | Нет | Да | **Нет** |
| Весь трафик | Нет | Нет | Да | **Только Telegram** | | Весь трафик | Нет | Нет | Да | **Только Telegram** |
| Кроссплатформа | Windows | Win/Mac/Linux | Да | **Win/Mac/Linux** | | LAN-шаринг | Нет | Можно настроить | Да | **Чекбокс** |
| Размер | ~1 МБ | ~2 МБ | Зависит | **~6 МБ** | | Стоимость | 0₽ | 0₽ | $310/мес | **0₽** |
## Цифры ## Цифры v2
- **300** строк кода (proxy + UI) - **350** строк кода
- **2** файла (`proxy.rs` + `main.rs`) - **2** файла
- **3** платформы (Windows, macOS, Linux) - **4** платформы (Win x64, macOS ARM64, macOS x64, Linux x64)
- **0** строк платформо-специфичного кода
- **0** серверов - **0** серверов
- **0₽** - **0₽**
## Скачать ## Скачать
**[github.com/by-sonic/tglock](https://github.com/by-sonic/tglock)** → Releases **[github.com/by-sonic/tglock](https://github.com/by-sonic/tglock)** → [Releases](https://github.com/by-sonic/tglock/releases/latest)
Или собрать: `git clone ... && cargo build --release` Или собрать:
**P.S.** Для полного обхода блокировок (YouTube, Discord, Instagram) — **[by sonic VPN](https://t.me/bysonicvpn_bot)**. ```bash
git clone https://github.com/by-sonic/tglock.git
cd tglock
cargo build --release
```
macOS: после скачивания `xattr -cr tglock-macos-arm64 && chmod +x tglock-macos-arm64`
**P.S.** Для полного обхода блокировок (YouTube, Discord, Instagram и всё остальное) — **[RoseVPN](https://t.me/rosevpnru_bot)**.
--- ---
*by sonic* *by sonic*
**Теги:** telegram, rust, websocket, socks5, mtproto, dpi, обход блокировок, open-source **Теги:** telegram, rust, websocket, macos, socks5, mtproto, обход блокировок, open-source, кроссплатформенность
**Хабы:** Rust · Open source · Сетевые технологии **Хабы:** Rust · Open source · macOS · Сетевые технологии

314
README.md
View File

@@ -1,65 +1,258 @@
<!-- ════════════════════════ ROSEVPN — sponsor ════════════════════════ -->
<p align="center"> <p align="center">
<h1 align="center">TGLock</h1> <a href="https://t.me/rosevpnru_bot">
<p align="center"><b>Обход блокировки Telegram через WebSocket-туннель</b></p> <img src="https://img.shields.io/badge/%F0%9F%8C%B9%20RoseVPN-%D0%9F%D0%BE%D0%BF%D1%80%D0%BE%D0%B1%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE-E63946?style=for-the-badge&logo=telegram&logoColor=white&labelColor=0a0a0a" height="44" alt="RoseVPN — попробовать бесплатно в Telegram"/>
<p align="center">Без VPN. Без серверов. Без абонентки. Один клик.</p> </a>
<p align="center"> </p>
<a href="https://github.com/by-sonic/tglock/releases/latest"><img src="https://img.shields.io/github/v/release/by-sonic/tglock?style=flat-square&color=blue" alt="Release"></a>
<img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-333?style=flat-square" alt="Platform"> <p align="center">
<img src="https://img.shields.io/badge/rust-stable-orange?style=flat-square&logo=rust" alt="Rust"> <b>Быстрый VPN для России</b> — YouTube без буферизации, Discord/Instagram/ChatGPT снова работают.<br/>
<a href="LICENSE"><img src="https://img.shields.io/github/license/by-sonic/tglock?style=flat-square" alt="MIT"></a> <sub>Подключение в Telegram через <a href="https://t.me/rosevpnru_bot"><b>@rosevpnru_bot</b></a> — бесплатный пробный период, без регистрации, без карты.</sub>
</p> </p>
<p align="center">
<a href="https://t.me/rosevpnru_bot"><img alt="YouTube — без буферов" src="https://img.shields.io/badge/YouTube-%D0%B1%D0%B5%D0%B7%20%D0%B1%D1%83%D1%84%D0%B5%D1%80%D0%BE%D0%B2-E63946?style=flat-square&logo=youtube&logoColor=white"></a>
<a href="https://t.me/rosevpnru_bot"><img alt="Discord — голос работает" src="https://img.shields.io/badge/Discord-%D0%B3%D0%BE%D0%BB%D0%BE%D1%81%20%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82-E63946?style=flat-square&logo=discord&logoColor=white"></a>
<a href="https://t.me/rosevpnru_bot"><img alt="Instagram — открывается" src="https://img.shields.io/badge/Instagram-%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D0%B2%D0%B0%D0%B5%D1%82%D1%81%D1%8F-E63946?style=flat-square&logo=instagram&logoColor=white"></a>
<a href="https://t.me/rosevpnru_bot"><img alt="ChatGPT — доступен" src="https://img.shields.io/badge/ChatGPT-%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B5%D0%BD-E63946?style=flat-square&logo=openai&logoColor=white"></a>
</p> </p>
--- ---
## Скачать <!-- ═════════════════════════════ TGLOCK ═════════════════════════════ -->
**[Последний релиз](https://github.com/by-sonic/tglock/releases/latest)** <div align="center">
| Файл | Платформа | # 🔓 TGLock
|---|---|
| `tglock.exe` | Windows x64 |
| `tglock-macos-arm64` | macOS Apple Silicon (M1M4) |
| `tglock-macos-x64` | macOS Intel |
| `tglock-linux-x64` | Linux x64 |
## Как пользоваться ### Обход блокировки Telegram через WebSocket-туннель
1. Скачай и запусти **Один клик. Без VPN. Без серверов. Без подписки.**
2. Нажми **ПОДКЛЮЧИТЬ**
3. Нажми **Настроить автоматически** → в Telegram нажми «Подключить»
4. Готово
Ручная настройка: Telegram → Настройки → Продвинутые → Тип соединения → SOCKS5 → `127.0.0.1:1080` <p>
<a href="https://github.com/by-sonic/tglock/releases/latest"><img alt="Скачать последний релиз" src="https://img.shields.io/github/v/release/by-sonic/tglock?style=for-the-badge&color=2ea043&label=%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C"></a>
<a href="https://github.com/by-sonic/tglock/releases"><img alt="Всего загрузок" src="https://img.shields.io/github/downloads/by-sonic/tglock/total?style=for-the-badge&color=0969da&label=%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BE%D0%BA"></a>
<a href="https://github.com/by-sonic/tglock/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/by-sonic/tglock?style=for-the-badge&color=f5a623"></a>
</p>
## Как это работает <p>
<img alt="Windows" src="https://img.shields.io/badge/Windows-0078D6?style=flat&logo=windows&logoColor=white">
<img alt="macOS" src="https://img.shields.io/badge/macOS-000000?style=flat&logo=apple&logoColor=white">
<img alt="Linux" src="https://img.shields.io/badge/Linux-FCC624?style=flat&logo=linux&logoColor=black">
<img alt="Rust" src="https://img.shields.io/badge/Rust-CE422B?style=flat&logo=rust&logoColor=white">
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/github/license/by-sonic/tglock?style=flat&color=lightgrey"></a>
</p>
</div>
> **Telegram стал тормозить или перестал открываться?** Запусти TGLock — и мессенджер снова работает. Не нужны VPN, прокси-серверы, абонентская плата или регистрация. Один бинарник на 6 МБ.
---
## 🤔 Что это и зачем
TGLock — это **локальный SOCKS5-прокси** на твоём компьютере. Он перехватывает соединения Telegram, заворачивает их в WebSocket и отправляет через `web.telegram.org`. Провайдер видит обычный HTTPS — Telegram работает как раньше.
**Кому подойдёт:**
- 📱 Telegram заблокировали в России или он стал открываться через раз
- 🐌 Голосовые/видеозвонки рвутся, сообщения уходят с задержкой, фото не грузятся
- 🛡 GoodbyeDPI, Zapret или ByeDPI больше не помогают — провайдер шейпит **по IP**
- 🍎 Нужен инструмент для **macOS** (а на маке нет нормальных GUI-альтернатив)
- 💻 Хочется решение для **Windows, macOS или Linux** без подписок и серверов
**Чем отличается от VPN:** TGLock работает **только с Telegram**. Остальной трафик идёт напрямую — ничего не замедляется, ничего не логируется, мобильный/домашний трафик не расходуется впустую.
---
## ⚡ Скачать
**[👉 Последний релиз](https://github.com/by-sonic/tglock/releases/latest)**
| Платформа | Файл | Размер |
|---|---|---|
| **Windows 10/11** (x64) | `tglock.exe` | ~6 МБ |
| **macOS Apple Silicon** (M1M4) | `tglock-macos-arm64` | ~6 МБ |
| **macOS Intel** | `tglock-macos-x64` | ~6 МБ |
| **Linux** (x86_64) | `tglock-linux-x64` | ~6 МБ |
> **🍎 macOS:** после скачивания запусти в Терминале:
> ```bash
> xattr -cr ~/Downloads/tglock-macos-arm64
> chmod +x ~/Downloads/tglock-macos-arm64
> ```
> Это снимает блокировку Gatekeeper «приложение не проверено». Альтернатива — подписать билд Developer ID за $99/год, что для бесплатного open-source перебор.
---
## 🚀 Как пользоваться
1. **Скачай и запусти** бинарник для своей системы
2. Нажми **«ПОДКЛЮЧИТЬ»** в окне приложения
3. Нажми **«Настроить автоматически»** → в Telegram появится диалог «Подключить SOCKS5-прокси?» → жми **«Подключить»**
4.**Telegram работает.** Можно сворачивать TGLock — он живёт в фоне.
### Ручная настройка (если автоматическая не сработала)
Telegram → Настройки → **Продвинутые** → Тип соединения → **Использовать прокси****SOCKS5**
- Сервер: `127.0.0.1`
- Порт: `1080`
### 🏠 LAN-режим — один прокси на всю квартиру
В окне TGLock включи галочку **LAN** — приложение начнёт слушать на `0.0.0.0`. Все устройства в твоей домашней сети (телефон, планшет, ноутбук, телевизор) смогут подключиться к `<твой-IP>:1080` и тоже получить рабочий Telegram. IP отобразится прямо в интерфейсе TGLock — копируй и вписывай в настройки Telegram на остальных устройствах.
Удобно, если дома один комп всегда включён — он становится «домашним Telegram-роутером».
---
## 🔬 Как это работает
``` ```
Telegram Desktop → SOCKS5 (127.0.0.1:1080) → TGLock → WSS (web.telegram.org) → DC Telegram Desktop / mobile (через LAN)
SOCKS5 (127.0.0.1:1080 или 0.0.0.0:1080)
TGLock — читает первые 64 байта
obfuscated2 init-пакета,
расшифровывает AES-256-CTR,
достаёт номер DC
WSS → kws{dc}.web.telegram.org
Telegram Data Center
``` ```
1. Локальный SOCKS5-прокси перехватывает соединения Telegram 1. **Локальный SOCKS5-прокси** перехватывает соединения Telegram Desktop.
2. Из MTProto init-пакета извлекается номер DC (AES-256-CTR) 2. Из первых 64 байт `obfuscated2`-пакета **расшифровывается номер DC** AES-256-CTR, ключ в байтах `[8..40]`, IV в `[40..56]`, DC ID — `i32` в `[60..64]`.
3. Трафик заворачивается в WebSocket через `kws{dc}.web.telegram.org` 3. Трафик заворачивается в **WebSocket** к `kws{dc}.web.telegram.org` — это **тот же домен**, через который работает Telegram Web в браузере.
4. Провайдер видит обычный HTTPS к `web.telegram.org` 4. Провайдер видит **TLS-handshake к `web.telegram.org`** — это легитимный HTTPS. DPI не видит MTProto. IP-шейпинг не работает, потому что `web.telegram.org` не блокируется в принципе.
5. Остальной трафик проходит напрямую 5. Весь остальной трафик (не-Telegram) проходит **напрямую** — без замедления.
## Почему не GoodbyeDPI / Zapret? 📖 **Подробный технический разбор архитектуры** — см. [HABR.md](HABR.md) (≈7 мин чтения, история v1 → v2, AES-decrypt, bias `select!` для Pong, кроссплатформенная сборка).
GoodbyeDPI и Zapret фрагментируют пакеты чтобы обмануть DPI. Но если провайдер **шейпит по IP** — они бесполезны. ---
TGLock маскирует трафик под обычный HTTPS. DPI не видит MTProto. IP-шейпинг не работает — `web.telegram.org` не блокируется. ## 🆚 Сравнение с альтернативами
## Стек | | GoodbyeDPI | Zapret | AmneziaVPN | **TGLock** |
|---|:---:|:---:|:---:|:---:|
| Подход | Фрагментация пакетов | TCP/UDP desync | Полноценный VPN-туннель | **WebSocket-туннель** |
| Обходит IP-шейпинг | ❌ | ❌ | ✅ | **✅** |
| macOS (GUI) | ❌ Windows only | ❌ только CLI | ✅ | **✅** |
| Нужен сервер / подписка | ❌ | ❌ | ✅ ($) | **❌** |
| Только Telegram | ❌ | ❌ | ❌ | **✅** |
| LAN-шаринг | ❌ | сложно | ✅ | **✅ (галочка)** |
| Размер | ~200 КБ | ~5 МБ | ~80 МБ | **~6 МБ** |
| Цена | 0 ₽ | 0 ₽ | $310/мес | **0 ₽** |
| | | > **⚠ Когда TGLock не подойдёт:** если заблокирован не только Telegram, а ещё YouTube, Discord, Instagram, ChatGPT, Spotify — нужен полноценный VPN. Тут поможет **[🌹 RoseVPN](https://t.me/rosevpnru_bot)** (см. блок ниже).
---
## ❓ Часто задаваемые вопросы
<details>
<summary><b>Telegram заблокировали в России — это правда?</b></summary>
Полностью Telegram в РФ не заблокирован, но провайдеры **замедляют** трафик через DPI и **шейпят по IP-диапазонам** Telegram DC (149.154.160175, 91.108.48, 91.108.5659 и др.). У части пользователей мессенджер открывается через раз, голосовые звонки рвутся, видео не грузится, фото уходят минутами. TGLock решает именно эту проблему — заворачивает Telegram-трафик в HTTPS к `web.telegram.org`, который не блокируется.
</details>
<details>
<summary><b>Это безопасно? Что с моими данными?</b></summary>
TGLock — **локальный прокси**. Он работает только на твоём компьютере и не отправляет данные третьим сторонам. Соединение идёт напрямую к серверам Telegram через их же домен `web.telegram.org` — тот же, что использует Telegram Web в браузере. Кода ~350 строк, всё открыто на GitHub — можно прочитать и собрать самому.
</details>
<details>
<summary><b>Чем отличается от GoodbyeDPI / Zapret / ByeDPI?</b></summary>
GoodbyeDPI, Zapret и ByeDPI **фрагментируют пакеты**, чтобы DPI не распознал MTProto. Это работает, пока провайдер блокирует *по содержимому*. Но если шейпинг идёт **по IP** (а так делают большинство крупных РФ-провайдеров с 20242026 — Ростелеком, МТС, Билайн, Мегафон), фрагментация не помогает: пакеты всё равно идут на «нехороший» IP и троттлятся.
TGLock же отправляет трафик на **`web.telegram.org`** — обычный HTTPS-домен, который не блокируется в принципе.
</details>
<details>
<summary><b>Работает ли на iPhone или Android?</b></summary>
Напрямую — нет, TGLock сам по себе только для desktop. Но если включить **LAN-режим** на компьютере, в настройках Telegram на телефоне можно указать SOCKS5-прокси с IP компа. Telegram на мобиле начнёт ходить через ПК. Удобно, если дома один компьютер всегда включён.
Для полностью мобильного решения нужен VPN — например, **[🌹 RoseVPN](https://t.me/rosevpnru_bot)** с приложением Karing для iOS/Android.
</details>
<details>
<summary><b>Замедляет ли TGLock интернет?</b></summary>
Нет. Через прокси идёт **только** трафик Telegram (фильтрация по IP-диапазонам Telegram DC). YouTube, браузер, игры, торренты — всё это идёт напрямую и не замедляется. В этом главное отличие от VPN.
</details>
<details>
<summary><b>Apple ругается «приложение не проверено / нельзя открыть»</b></summary>
Подпись Apple Developer ID стоит $99 в год — для бесплатного open-source это перебор. Сними блокировку Gatekeeper руками — открой Терминал и выполни:
```bash
xattr -cr ~/Downloads/tglock-macos-arm64
chmod +x ~/Downloads/tglock-macos-arm64
```
После этого приложение запустится двойным кликом из Finder.
</details>
<details>
<summary><b>Telegram пишет «прокси не настроен» или сразу отключается</b></summary>
Открой TGLock — он должен показывать **«ПОДКЛЮЧЕНО»** и хотя бы одно активное соединение, когда Telegram пытается работать. Если соединений ноль:
- Не запущен ли уже другой прокси на порту 1080? В TGLock можно поменять порт в настройках.
- Антивирус/файрвол не блокирует localhost-подключения?
- В настройках Telegram сервер указан как `127.0.0.1`, не `localhost` — на некоторых системах это разные сетевые стеки.
- На macOS — убедись что снят Gatekeeper (`xattr -cr ...`).
</details>
<details>
<summary><b>Порт 1080 уже занят другим приложением</b></summary>
В окне TGLock есть поле **«Порт»** — поменяй на любой свободный (например, `10800`, `1081`, `8888`). После рестарта прокси автоматически обновит deep-link для Telegram. В настройках Telegram укажи новый порт.
</details>
<details>
<summary><b>А что если провайдер заблокирует и <code>web.telegram.org</code>?</b></summary>
Тогда TGLock перестанет работать у этого конкретного провайдера. Но **публичная блокировка веб-версии Telegram** — это большой шаг, и Роскомнадзор пока на него не идёт. Если всё же случится — используй **[🌹 RoseVPN](https://t.me/rosevpnru_bot)**, там домен фронтирования автоматически меняется (SNI rotation, Reality), и пробивает даже агрессивный DPI.
</details>
<details>
<summary><b>Можно ли использовать TGLock как обычный SOCKS5 для других приложений?</b></summary>
Не рекомендуется. TGLock детектирует Telegram-трафик по IP получателя и оборачивает в WebSocket только его. Остальное идёт напрямую — без шифрования и аутентификации, как обычный SOCKS5-релей. Для других приложений возьми правильный SOCKS5-сервер (или VPN).
</details>
<details>
<summary><b>Где скачать новые версии? Будут ли обновления?</b></summary>
Все релизы — на странице **[GitHub Releases](https://github.com/by-sonic/tglock/releases)**. При пуше тега `v*` GitHub Actions автоматически собирает бинарники для всех 4 платформ и публикует. Подпишись на репозиторий (кнопка **Watch****Custom****Releases**), чтобы получать уведомления о новых версиях.
</details>
---
## 🛠 Стек технологий
| Технология | Зачем |
|---|---| |---|---|
| Rust | Один бинарник, нативная скорость | | **Rust** | Один бинарник, нативная скорость, без runtime-зависимостей |
| egui | GUI без браузера и Electron | | **egui** (`eframe`) | Кроссплатформенный GUI без браузера, без Electron, без Qt |
| tokio | Async I/O | | **tokio** | Async I/O для тысяч одновременных соединений |
| tokio-tungstenite | WebSocket + TLS | | **tokio-tungstenite** | WebSocket-клиент с TLS поверх `native-tls` |
| **aes** + **ctr** | Расшифровка MTProto `obfuscated2` init-пакета |
## Сборка **Размер бинарника:** ~6 МБ. **Памяти в простое:** ~15 МБ.
---
## 🏗 Сборка из исходников
```bash ```bash
git clone https://github.com/by-sonic/tglock.git git clone https://github.com/by-sonic/tglock.git
@@ -67,14 +260,43 @@ cd tglock
cargo build --release cargo build --release
``` ```
## VPN Результат — `target/release/tglock` (или `tglock.exe` на Windows). Требуется Rust **stable 1.75+**.
Для обхода блокировок **всех** приложений — **[by sonic VPN](https://t.me/bysonicvpn_bot)** ### Кросс-компиляция через GitHub Actions
## Лицензия Хочешь собрать свой релиз? Форкни репозиторий, поставь тег `v1.0.1`, и `.github/workflows/release.yml` сам соберёт бинарники под Windows x64, macOS ARM64, macOS Intel и Linux x64.
MIT
--- ---
<p align="center"><b>by sonic</b></p> ## 🌹 Нужен VPN на всё подряд?
Если у тебя заблокирован **не только Telegram**, а ещё YouTube, Discord, Instagram, ChatGPT, Spotify — обходить каждое приложение отдельно нет смысла. Возьми VPN, который умеет всё сразу.
<p align="center">
<a href="https://t.me/rosevpnru_bot">
<img alt="Подключить RoseVPN — Telegram-бот" src="https://img.shields.io/badge/%F0%9F%8C%B9%20RoseVPN-%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B8%D1%82%D1%8C%20%D0%B2%20Telegram-E63946?style=for-the-badge&logo=telegram&logoColor=white&labelColor=0a0a0a" height="40"/>
</a>
</p>
**Что внутри RoseVPN:**
- 🔥 **Hysteria2 + VLESS-Reality fallback** — обходит TSPU и агрессивный DPI
- 🛡 **Без логов трафика** — приватность по умолчанию
- 🎁 **Бесплатный пробный период** — без карты, без регистрации
- 📱 **Karing-клиент** с автонастройкой — установка в 2 тапа
- 💻 **Windows, macOS, iOS, Android** — везде нативные приложения
- 🔄 **SNI-ротация** на случай новых блокировок
Подключение — через Telegram-бот **[@rosevpnru_bot](https://t.me/rosevpnru_bot)**.
---
## 📄 Лицензия
[MIT](LICENSE) — делай что хочешь. Форки, модификации, использование в коммерческих проектах — всё разрешено. Ссылка на репозиторий приветствуется, но необязательна.
---
<p align="center">
<sub><b>by sonic</b> · <a href="https://t.me/rosevpnru_bot">@rosevpnru_bot</a> · <a href="https://github.com/by-sonic/tglock/issues">Issues & feedback</a></sub>
</p>

View File

@@ -94,6 +94,8 @@ struct App {
log: Arc<Mutex<Vec<LogLine>>>, log: Arc<Mutex<Vec<LogLine>>>,
started_at: Option<Instant>, started_at: Option<Instant>,
lan_mode: bool, lan_mode: bool,
port_str: String,
active_port: u16,
} }
impl App { impl App {
@@ -103,6 +105,8 @@ impl App {
log: Arc::new(Mutex::new(Vec::new())), log: Arc::new(Mutex::new(Vec::new())),
started_at: None, started_at: None,
lan_mode: false, lan_mode: false,
port_str: proxy::DEFAULT_PORT.to_string(),
active_port: proxy::DEFAULT_PORT,
} }
} }
@@ -112,6 +116,16 @@ impl App {
fn start(&mut self) { fn start(&mut self) {
if self.running() { return; } if self.running() { return; }
let port: u16 = match self.port_str.trim().parse() {
Ok(p) if p > 0 => p,
_ => {
log(&self.log, "Неверный порт", true);
return;
}
};
self.active_port = port;
self.started_at = Some(Instant::now()); self.started_at = Some(Instant::now());
let stats = self.stats.clone(); let stats = self.stats.clone();
let lg = self.log.clone(); let lg = self.log.clone();
@@ -121,7 +135,7 @@ impl App {
std::thread::spawn(move || { std::thread::spawn(move || {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
let r = rt.block_on(proxy::run(stats, lan)); let r = rt.block_on(proxy::run(stats, lan, port));
if let Err(e) = r { if let Err(e) = r {
log(&lg, &format!("Ошибка: {}", e), true); log(&lg, &format!("Ошибка: {}", e), true);
} }
@@ -130,7 +144,7 @@ impl App {
std::thread::sleep(std::time::Duration::from_millis(250)); std::thread::sleep(std::time::Duration::from_millis(250));
if self.running() { if self.running() {
let addr = if lan { "0.0.0.0" } else { "127.0.0.1" }; let addr = if lan { "0.0.0.0" } else { "127.0.0.1" };
log(&self.log, &format!("SOCKS5 на {}:{}", addr, proxy::PORT), false); log(&self.log, &format!("SOCKS5 на {}:{}", addr, port), false);
if lan { if lan {
log(&self.log, "LAN-режим: другие устройства могут подключаться", false); log(&self.log, "LAN-режим: другие устройства могут подключаться", false);
} }
@@ -171,13 +185,13 @@ impl eframe::App for App {
.inner_margin(egui::Margin::symmetric(12, 6)) .inner_margin(egui::Margin::symmetric(12, 6))
.show(ui, |ui| { .show(ui, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.colored_label(ACCENT, egui::RichText::new("by sonic VPN").size(12.0).strong()); ui.colored_label(ACCENT, egui::RichText::new("RoseVPN").size(12.0).strong());
ui.colored_label(TEXT2, egui::RichText::new("Обход для всех приложений").size(11.0)); ui.colored_label(TEXT2, egui::RichText::new("Обход для всех приложений").size(11.0));
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if ui.add(egui::Button::new( if ui.add(egui::Button::new(
egui::RichText::new("@bysonicvpn_bot").size(11.0).strong().color(ACCENT) egui::RichText::new("@rosevpnru_bot").size(11.0).strong().color(ACCENT)
).frame(false)).clicked() { ).frame(false)).clicked() {
let _ = open::that("https://t.me/bysonicvpn_bot"); let _ = open::that("https://t.me/rosevpnru_bot");
} }
}); });
}); });
@@ -257,16 +271,22 @@ impl eframe::App for App {
ui.add_space(20.0); ui.add_space(20.0);
// LAN toggle (only when stopped) // Options (only when stopped)
if !on { if !on {
ui.horizontal(|ui| { ui.horizontal(|ui| {
let center = ui.available_width() / 2.0 - 90.0; let center = ui.available_width() / 2.0 - 130.0;
ui.add_space(center); ui.add_space(center);
ui.colored_label(TEXT2, egui::RichText::new("Порт:").size(12.0));
let port_edit = egui::TextEdit::singleline(&mut self.port_str)
.desired_width(55.0)
.font(egui::TextStyle::Monospace);
ui.add(port_edit);
ui.add_space(12.0);
ui.checkbox(&mut self.lan_mode, ""); ui.checkbox(&mut self.lan_mode, "");
ui.colored_label(TEXT2, egui::RichText::new("Локальная сеть").size(12.0)); ui.colored_label(TEXT2, egui::RichText::new("LAN").size(12.0));
ui.colored_label( ui.colored_label(
egui::Color32::from_rgb(80, 85, 95), egui::Color32::from_rgb(80, 85, 95),
egui::RichText::new("(0.0.0.0 — для всех устройств)").size(10.5), egui::RichText::new("(0.0.0.0)").size(10.5),
); );
}); });
ui.add_space(8.0); ui.add_space(8.0);
@@ -314,11 +334,15 @@ impl eframe::App for App {
"127.0.0.1".into() "127.0.0.1".into()
}; };
let display_port = if on { self.active_port } else {
self.port_str.trim().parse().unwrap_or(proxy::DEFAULT_PORT)
};
if on { if on {
if ui.add(egui::Button::new( if ui.add(egui::Button::new(
egui::RichText::new("Настроить автоматически").size(13.0).color(ACCENT) egui::RichText::new("Настроить автоматически").size(13.0).color(ACCENT)
).frame(false)).clicked() { ).frame(false)).clicked() {
let _ = open::that(format!("tg://socks?server={}&port={}", server_addr, proxy::PORT)); let _ = open::that(format!("tg://socks?server={}&port={}", server_addr, display_port));
log(&self.log, "Открываю настройку Telegram...", false); log(&self.log, "Открываю настройку Telegram...", false);
} }
ui.add_space(4.0); ui.add_space(4.0);
@@ -332,7 +356,7 @@ impl eframe::App for App {
ui.monospace(&server_addr); ui.monospace(&server_addr);
ui.end_row(); ui.end_row();
ui.colored_label(TEXT2, "Порт"); ui.colored_label(TEXT2, "Порт");
ui.monospace(format!("{}", proxy::PORT)); ui.monospace(format!("{}", display_port));
ui.end_row(); ui.end_row();
}); });
}); });

View File

@@ -7,7 +7,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio_tungstenite::tungstenite; use tokio_tungstenite::tungstenite;
use tungstenite::client::IntoClientRequest; use tungstenite::client::IntoClientRequest;
pub const PORT: u16 = 1080; pub const DEFAULT_PORT: u16 = 1080;
pub struct Stats { pub struct Stats {
pub running: AtomicBool, pub running: AtomicBool,
@@ -29,12 +29,12 @@ impl Stats {
} }
} }
pub async fn run(stats: Arc<Stats>, lan: bool) -> Result<(), String> { pub async fn run(stats: Arc<Stats>, lan: bool, port: u16) -> Result<(), String> {
let host = if lan { "0.0.0.0" } else { "127.0.0.1" }; let host = if lan { "0.0.0.0" } else { "127.0.0.1" };
let addr = format!("{}:{}", host, PORT); let addr = format!("{}:{}", host, port);
let listener = TcpListener::bind(&addr) let listener = TcpListener::bind(&addr)
.await .await
.map_err(|e| format!("Port {} busy: {}", PORT, e))?; .map_err(|e| format!("Port {} busy: {}", port, e))?;
stats.running.store(true, Ordering::SeqCst); stats.running.store(true, Ordering::SeqCst);