Add Habr article, LICENSE, CI/CD workflow

Made-with: Cursor:
This commit is contained in:
by-sonic 2026-03-16 23:56:40 +03:00
parent d0646af85d
commit 7d7a519365
1 changed files with 307 additions and 0 deletions

307
HABR_ARTICLE.md Normal file
View File

@ -0,0 +1,307 @@
# Как я написал обход блокировки Telegram на Rust — без VPN, без серверов, через WebSocket
**Простой · 7 мин · Rust · Open source · Windows · Сетевые технологии · Из песочницы**
**TL;DR:** Написал open-source десктопное приложение **TG Unblock** на Rust, которое в один клик обходит блокировку Telegram через локальный WebSocket-прокси. Трафик заворачивается в обычный HTTPS к `web.telegram.org` — DPI не видит MTProto, провайдер не может шейпить. Без VPN, без серверов, без абонентки. Код на GitHub — [by-sonic/tglock](https://github.com/by-sonic/tglock).
---
## Предыстория: почему GoodbyeDPI не спасает
С весны 2025 года Telegram в России стал работать, мягко говоря, через боль. Сообщения доходят по 10 секунд, медиа не грузятся, звонки рвутся. Классическая картина: провайдер + DPI = страдания.
Первое, что приходит в голову — **GoodbyeDPI**. Запустил, пакеты фрагментируются, DPI не узнаёт MTProto... и вроде работает. Но:
- **Пинг 200+ мс** — при норме 4060
- **Постоянные переподключения** — DPI переобучается и режет соединения
- **IP-шейпинг** — провайдер троттлит весь трафик к подсетям Telegram (149.154.x.x, 91.108.x.x)
GoodbyeDPI обманывает DPI на уровне пакетов, но **не решает проблему IP-шейпинга**. Если провайдер тупо режет скорость ко всем IP Telegram — хоть как фрагментируй, будет медленно.
VPN — вариант. Но:
- Платные стоят денег и сливают скорость
- Бесплатные сливают данные
- Не все работают стабильно
- Для одного Telegram гонять весь трафик через VPN — оверкилл
Нужно решение, которое **маскирует сам факт подключения к Telegram**, а не просто прячет протокол.
## Идея: WebSocket-туннель через web.telegram.org
Я провёл серию тестов. Прямое подключение к серверам Telegram (149.154.167.51:443) — либо таймаут, либо 200+ мс. А вот `web.telegram.org` отвечает стабильно за 5080 мс через HTTPS. Провайдер его не трогает — это же «обычный сайт».
И тут я полез в [документацию 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.
Telegram **официально поддерживает WebSocket-транспорт**. Серверы `pluto.web.telegram.org`, `venus.web.telegram.org` и т.д. — это не просто веб-клиент. Это **полноценные точки входа в сеть Telegram** через WSS.
Схема:
```
Telegram Desktop
▼ SOCKS5
┌──────────────────┐
│ TG Unblock │ 127.0.0.1:1080
│ WS-прокси │
└──────┬───────────┘
├── IP Telegram? ──► WSS к {dc}.web.telegram.org/apiws
│ (провайдер видит: HTTPS к web.telegram.org)
└── Другой IP? ────► Прямой TCP (без изменений)
```
Провайдер видит:
- Соединение к `venus.web.telegram.org` по порту 443
- Обычный TLS/HTTPS трафик
- Никакого MTProto
DPI видит:
- Ничего подозрительного
- Обычный WebSocket внутри HTTPS
Результат:
- **Полная скорость** — провайдер не шейпит web.telegram.org
- **Нет переподключений** — DPI не трогает HTTPS
- **Нулевая задержка** — нет промежуточных серверов, трафик идёт напрямую к Telegram
## Реализация: Rust, SOCKS5, WebSocket
### Почему Rust?
Не Electron. Не Python. Не Node.js. **Rust.** Потому что:
- Один бинарник ~6 МБ, без зависимостей
- Нативная скорость — прокси не должен добавлять задержку
- Async I/O через tokio — тысячи одновременных соединений
- Компилируется, запускается, работает
### Архитектура
Приложение состоит из 4 модулей:
| Модуль | Что делает |
|---|---|
| `main.rs` | GUI на egui + управление прокси |
| `ws_proxy.rs` | SOCKS5-сервер + WebSocket-туннель |
| `bypass.rs` | DNS-настройка, системные утилиты |
| `network.rs` | Сетевая диагностика |
### SOCKS5 → WebSocket: как это работает
Когда Telegram Desktop подключается через SOCKS5-прокси, происходит следующее:
**1. SOCKS5 handshake**
```rust
// Клиент: [0x05, 0x01, 0x00] — SOCKS5, 1 метод, no auth
// Сервер: [0x05, 0x00] — принято
// Клиент: [0x05, 0x01, 0x00, 0x01, IP, PORT] — CONNECT к IP:PORT
```
**2. Определение DC по IP**
Telegram использует фиксированные подсети для каждого Data Center. Из [документации](https://core.telegram.org/mtproto/transports):
```rust
fn telegram_dc(ip: Ipv4Addr) -> Option<u8> {
let o = ip.octets();
match (o[0], o[1]) {
(149, 154) => Some(match o[2] {
160..=163 => 1, // DC1
164..=167 => 2, // DC2
168..=171 => 3, // DC3
172..=175 => 1, // DC1 alt
_ => 2,
}),
(91, 108) => Some(match o[2] {
56..=59 => 5, // DC5
8..=11 => 3, // DC3
12..=15 => 4, // DC4
_ => 2,
}),
(91, 105) => Some(2),
(185, 76) => Some(2),
_ => None,
}
}
```
**3. WebSocket-туннель**
Каждый DC имеет именованный WebSocket-эндпоинт (имена из официальной документации Telegram):
| DC | Имя | URL |
|---|---|---|
| 1 | Pluto | `wss://pluto.web.telegram.org/apiws` |
| 2 | Venus | `wss://venus.web.telegram.org/apiws` |
| 3 | Aurora | `wss://aurora.web.telegram.org/apiws` |
| 4 | Vesta | `wss://vesta.web.telegram.org/apiws` |
| 5 | Flora | `wss://flora.web.telegram.org/apiws` |
Обязательный заголовок (из доки Telegram): `Sec-WebSocket-Protocol: binary`.
```rust
let mut request = ws_url.as_str().into_client_request()?;
request.headers_mut().insert(
"Sec-WebSocket-Protocol", "binary".parse()?,
);
let (ws, _) = tokio_tungstenite::connect_async_tls_with_config(
request, None, false, Some(connector),
).await?;
```
**4. Двунаправленный relay**
Ключевая цитата из документации Telegram:
> All data received and sent through WebSocket messages is to be treated as a **single duplex stream of bytes**, just like with TCP.
Это значит, что нам не нужно парсить MTProto. Просто relay байтов: TCP → WebSocket binary frame, WebSocket binary frame → TCP.
```rust
let up = async {
let mut buf = vec![0u8; 32768];
loop {
match tcp_rx.read(&mut buf).await {
Ok(0) => break,
Ok(n) => {
let msg = Message::Binary(buf[..n].to_vec());
if ws_tx.send(msg).await.is_err() { break; }
}
Err(_) => break,
}
}
};
let down = async {
while let Some(Ok(msg)) = ws_rx.next().await {
if let Message::Binary(data) = msg {
if tcp_tx.write_all(&data).await.is_err() { break; }
}
}
};
tokio::select! { _ = up => {}, _ = down => {} }
```
### GUI: egui, не Electron
Нативный GUI через `egui` / `eframe`. Никакого браузера, никакого DOM, никакого JavaScript. Вся отрисовка — immediate mode, 60 FPS.
Кнопка «Запустить обход» делает:
1. Меняет DNS на Cloudflare (1.1.1.1) — обходит DNS-блокировку
2. Запускает SOCKS5-прокси на 127.0.0.1:1080
3. Предлагает автонастройку Telegram через `tg://socks?server=127.0.0.1&port=1080`
Кнопка «Настроить автоматически» — открывает Telegram Desktop с готовой конфигурацией прокси. Один клик.
## Технические детали, которые пришлось решить
### Проблема 1: Не-Telegram трафик
Если Telegram Desktop пускает через SOCKS5 не только MTProto, но и запросы к CDN, стикер-серверам, обновлениям — их нельзя заворачивать в WebSocket. Решение: проверяем IP по маппингу Telegram-подсетей. Telegram IP → WebSocket. Всё остальное → прямой TCP passthrough.
### Проблема 2: Определение DC
Telegram Desktop использует obfuscated2 транспорт. Первые 64 байта — зашифрованный хендшейк, в котором закодирован DC ID. Парсить его — целый проект.
Решение проще: определяем DC по destination IP. Telegram использует фиксированные подсети для каждого DC — маппинг стабильный и документированный.
### Проблема 3: TLS к WebSocket-эндпоинтам
WebSocket-соединение идёт через WSS (TLS). Используем `native-tls` — системные сертификаты Windows, без привязки к OpenSSL.
```rust
let connector = tokio_tungstenite::Connector::NativeTls(
native_tls::TlsConnector::new()?,
);
```
### Проблема 4: Graceful shutdown
При остановке прокси нужно:
- Сбросить DNS обратно на DHCP
- Корректно закрыть все WebSocket-соединения
- Не оставить Telegram без связи
Используем `AtomicBool` для флага остановки — все задачи проверяют его и завершаются.
## Сравнение с альтернативами
| | GoodbyeDPI | Zapret | VPN | **TG Unblock** |
|---|---|---|---|---|
| Подход | Фрагментация пакетов | Desync пакетов | Туннель через сервер | WebSocket-туннель |
| DPI видит MTProto? | Нет | Нет | Нет | **Нет** |
| IP-шейпинг? | Не обходит | Не обходит | Обходит | **Обходит** |
| Нужен сервер? | Нет | Нет | Да | **Нет** |
| Скорость | Зависит от DPI | Зависит от DPI | Зависит от сервера | **Полная** |
| Весь трафик? | Нет | Нет | Да | **Только Telegram** |
| Стоимость | Бесплатно | Бесплатно | $310/мес | **Бесплатно** |
## Стек
| Технология | Зачем |
|---|---|
| **Rust** | Скорость, один бинарник, без зависимостей |
| **egui / eframe** | Нативный GUI без браузера |
| **tokio** | Async I/O, тысячи соединений |
| **tokio-tungstenite** | WebSocket-клиент с TLS |
| **native-tls** | Системные сертификаты Windows |
| **GitHub Actions** | CI/CD — автобилд при новом теге |
## Цифры
- **5 DC** — полный маппинг всех Telegram Data Center
- **1 бинарник** — ~6 МБ, без зависимостей
- **0 серверов** — всё работает локально
- **0₽** — полностью бесплатно и open-source
- **1 клик** — от запуска до работающего Telegram
## Как попробовать
### Скачать готовый .exe
1. Скачайте `tg_unblock.exe` из [Releases](https://github.com/by-sonic/tglock/releases)
2. Запустите (желательно от администратора — для DNS)
3. Нажмите **«Запустить обход»**
4. Нажмите **«Настроить автоматически»**
5. В Telegram нажмите «Подключить»
### Собрать из исходников
```bash
git clone https://github.com/by-sonic/tglock.git
cd tglock
cargo build --release
# Бинарник: target/release/tg_unblock.exe
```
## Что дальше
- **Автоопределение DC из obfuscated2** — парсинг первых 64 байт для точного маппинга
- **Fallback на GoodbyeDPI** — если WebSocket-эндпоинт недоступен
- **Linux / macOS** — porability через tokio + egui (уже почти готово)
- **Статистика** — скорость, задержка, количество туннелей в реальном времени
## Вместо заключения
Telegram — это не просто мессенджер. Для миллионов людей это рабочий инструмент, канал связи, источник информации. Когда он работает через боль — страдают все.
GoodbyeDPI — отличный инструмент, но у него есть потолок. Когда DPI побеждён, а трафик всё равно шейпится — нужен другой подход. WebSocket-туннель через `web.telegram.org` — это как проехать мимо камеры на легальной машине вместо того, чтобы заклеивать номера.
Код полностью открыт. Если пригодился — поставьте звезду на GitHub. Если нашли баг — PR приветствуются.
**GitHub:** [github.com/by-sonic/tglock](https://github.com/by-sonic/tglock)
**P.S.** Если нужен полный обход блокировок для всех приложений (YouTube, Discord, Instagram и др.) — попробуйте [by sonic VPN](https://t.me/bysonicvpn_bot). Быстрый, стабильный, без ограничений скорости.
---
*by sonic*
**Теги:** telegram, dpi bypass, websocket, rust, socks5, mtproto, обход блокировок, open-source
**Хабы:** Rust · Open source · Windows · Сетевые технологии