From 689e051a58c1136b93cffb0118b83530f9d6723b Mon Sep 17 00:00:00 2001 From: ded_ikar Date: Mon, 17 Aug 2026 20:13:41 +0500 Subject: [PATCH] PROTOCOL.md: update for v0.2.2 (self-signed, email, REALITY, examples) --- PROTOCOL.md | 228 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 162 insertions(+), 66 deletions(-) diff --git a/PROTOCOL.md b/PROTOCOL.md index 837e165..fcaa923 100755 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -1,48 +1,95 @@ # sdm-xray: stealth transport — спецификация для интеграции -Версия: v0.2.1 (черновик). Статус: работает (клиент/сервер — форк Xray-core). +Версия: v0.2.2. Статус: работает (клиент/сервер — форк Xray-core). ## 1. Что это + `stealth` — кастомный сетевой транспорт для Xray-core (поле `network: "stealth"` в `streamSettings`). Каждая туннельная сессия = **один долгоживущий HTTP/2 POST-стрим** (ALPN `h2`): тело запроса несёт кадры клиент→сервер, тело ответа — кадры сервер→клиент -(двунаправленно, как gRPC/стриминговые загрузки). Снаружи выглядит как обычный HTTPS -к API-эндпоинту реального сайта. +(двунаправленно). Снаружи выглядит как обычный POST-запрос к API реального сайта. -Цель — анти-DPI: ротация путей на каждое соединение, браузерный TLS (uTLS chrome), -padding/pacing, ретрай со сменой identity, зеркало реального сайта для зондов. +Для зондов/DPI: сервер отдаёт реальный сайт (зеркало) на GET/HEAD запросы. +Клиент автоматически ротирует пути, padding/pacing маскирует размеры и тайминги. -## 2. Конфигурация (streamSettings) +## 2. Quick-start + +### Сервер (минимальный конфиг) ```json { - "network": "stealth", - "stealthSettings": { - "key": "<общий секрет, клиент и сервер совпадают>", - "padMax": 2048, - "padProb": 50, - "paceMs": 0, - "paceJitterMs": 0, - "path": "/", // один путь (fallback) - "paths": ["/api/t04d12b46/", "/api/v2/telemetry/", "/collect/", "/ingest/"], - "ports": [443], // опция: ротация портов - "bps": 0, // опция: rate-limit, 0 = выкл - "target": "https://www.iana.org", // опция: зеркало (сервер) - "decoy": false, // опция: фоновый трафик - "decoyEverySecs": 60, - "decoyTarget": "https://www.cloudflare.com/cdn-cgi/trace", - "padProfile": "browser", // "browser" | "uniform" - "retries": 3 - }, - "security": "tls", // или "reality" - "tlsSettings": {"serverName": "...", "fingerprint": "chrome"} + "log": {"loglevel": "warning"}, + "inbounds": [{ + "listen": "0.0.0.0", "port": 443, + "protocol": "vless", + "settings": {"clients": [{"id": "", "level": 0}], "decryption": "none"}, + "streamSettings": { + "network": "stealth", + "stealthSettings": { + "key": "< hex-ключ >", "padMax": 2048, "padProb": 50, + "paceMs": 0, "paceJitterMs": 0, + "paths": ["/api/t04d12b46/", "/api/v2/telemetry/", "/collect/", "/ingest/"], + "ports": [443], "bps": 0, + "target": "https://www.iana.org", + "padProfile": "browser", "retries": 3 + }, + "security": "tls", + "tlsSettings": {"certificates": [{"certificateFile": "fullchain.pem", "keyFile": "privkey.pem"}]} + } + }], + "outbounds": [{"protocol": "freedom", "tag": "direct"}] } ``` -Клиент и сервер должны иметь одинаковые `key`, `paths` (список путей). Порты — только -на клиенте (сервер слушает каждый порт отдельным inbound). -## 3. Wire-протокол (поверх TLS+HTTP/2) +### Клиент (минимальный конфиг) +```json +{ + "log": {"loglevel": "warning"}, + "inbounds": [ + {"listen": "127.0.0.1", "port": 10808, "protocol": "socks"}, + {"listen": "127.0.0.1", "port": 10809, "protocol": "http"} + ], + "outbounds": [{ + "protocol": "vless", + "settings": {"vnext": [{"address": "<домен или IP>", "port": 443, + "users": [{"id": "", "encryption": "none"}]}]}, + "streamSettings": { + "network": "stealth", + "stealthSettings": { + "key": "< hex-ключ >", "padMax": 2048, "padProb": 50, + "paceMs": 0, "paceJitterMs": 0, + "paths": ["/api/t04d12b46/", "/api/v2/telemetry/", "/collect/", "/ingest/"], + "ports": [443], "bps": 0 + }, + "security": "tls", + "tlsSettings": {"serverName": "<домен>", "fingerprint": "chrome"} + } + }] +} +``` -### 3.1 Установка сессии +## 3. Конфигурация (streamSettings) + +| Параметр | Тип | По умолчанию | Описание | +|----------|-----|-------------|----------| +| `key` | string | — | Общий секрет (hex). Клиент и сервер должны совпадать | +| `paths` | []string | `["/api/t04d12b46/"]` | Туннельные пути (ротация на каждое соединение) | +| `ports` | []uint32 | `[443]` | Порты (ротация, опция) | +| `padMax` | int64 | 2048 | Максимальный размер PAD-кадра | +| `padProb` | int64 | 50 | Вероятность PAD после DATA (%) | +| `paceMs` | int64 | 0 | Минимальный интервал между кадрами (мс) | +| `paceJitterMs` | int64 | 0 | Случайный довесок к paceMs (мс) | +| `bps` | int64 | 0 | Rate-limit (0 = выкл) | +| `target` | string | — | URL зеркала (сервер). Пустой = встроенная заглушка | +| `retries` | int64 | 3 | Количество ретраев при неудаче | +| `padProfile` | string | "browser" | "browser" (перекос к мелким) или "uniform" | +| `decoy` | bool | false | Фоновый трафик к CDN (клиент) | +| `decoyEverySecs` | int64 | 60 | Интервал decoy-запросов | +| `decoyTarget` | string | cloudflare CDN | URL для decoy | +| `path` | string | — | Один путь (fallback, если paths пуст) | + +## 4. Wire-протокол (поверх TLS+HTTP/2) + +### 4.1 Установка сессии 1. Клиент: TLS 1.3 (uTLS, fingerprint chrome, ALPN h2) к серверу:443. 2. HTTP/2: клиент открывает **один POST** на один из `paths`. 3. Тело запроса (клиент→сервер) — поток кадров. **Первый кадр = AUTH**: @@ -52,52 +99,101 @@ padding/pacing, ретрай со сменой identity, зеркало реал - ключ неверный/нет → `404` + закрытие. 5. После 200 обе стороны обмениваются кадрами DATA/PAD двунаправленно. -### 3.2 Формат кадра +### 4.2 Формат кадра ``` [4 байта, big-endian длина = 1 + len(payload)] [1 байт type] [payload] ``` -Типы: -| type | значение | смысл | -|---|---|---| -| DATA | 0x01 | данные туннеля (VLESS-поток) | -| PAD | 0x02 | padding (читатель пропускает) | -| AUTH | 0xFE | первый кадр тела запроса, payload = ключ | -| CLOSE| 0xFF | закрытие | -Лимит кадра: 64 КБ. Поток байтов в DATA-кадрах сохраняет порядок (VLESS видит обычный -поток); PAD-кадры прозрачны для читателя. -### 3.3 Сервер: зеркало для зондов -Не-туннельные запросы (GET/HEAD к любым путям) сервер **реверсивно проксирует на -`target`** (реальный сайт): переписывает `Location`, HTML `href/src/content`, -CSS `url(...)` на свой домен. POST на туннельные пути без валидного AUTH → 404. -Пустой `target` → встроенная страница-заглушка. +| type | Значение | Смысл | +|------|----------|-------| +| DATA | 0x01 | Данные туннеля (VLESS-поток) | +| PAD | 0x02 | Padding (читатель пропускает) | +| AUTH | 0xFE | Первый кадр тела запроса (ключ) | +| CLOSE | 0xFF | Закрытие | -## 4. Клиент: ротация и ретрай -- Клиент на каждое соединение выбирает **случайный путь** из `paths`. -- При неудаче — ретрай со свежим путём/портом (`retries`). -- Padding: после каждого DATA-кадра с вероятностью `padProb` идёт PAD-кадр размера - до `padMax` (профиль `browser` — перекос к мелким). -- Pacing: `paceMs` + `paceJitterMs` (мин. интервал между кадрами). -- Мультиплекс: несколько сессий идут по одному TLS+HTTP/2 каналу (несколько POST-стримов). +Лимит кадра: 64 КБ. PAD-кадры прозрачны для читателя (пропускаются). -## 5. Требования к сборке -- Go 1.26, golang.org/x/net/http2, golang.org/x/time/rate, refraction-networking/utls. -- `config.proto` → `config.pb.go` генерится: `protoc -I. --go_out=. --go_opt=paths=source_relative transport/internet/stealth/config.proto`. -- Бинарь: `go build ./main` (клиент и сервер — один бинарь). +### 4.3 Сервер: зеркало для зондов +Не-туннельные запросы (GET/HEAD) сервер реверсивно проксирует на `target`: +- Location переписывается на свой домен +- HTML href/src/content переписываются на свой домен +- CSS url() переписываются на свой домен +- POST на туннельные пути без AUTH → 404 +- Пустой `target` → встроенная страница-заглушка + +## 5. Безопасность + +### TLS (по умолчанию) +Сертификат: Let's Encrypt (домен) или self-signed (IP). + +### Self-signed режим +Для работы без домена: `install.sh --selfsigned` генерирует сертификат (RSA 2048, 10 лет). +Клиент доверяет по `pinnedPeerCertSha256` — hex SHA256 от DER-кода сертификата. + +Клиентский конфиг: +```json +"tlsSettings": { + "serverName": "", + "fingerprint": "chrome", + "pinnedPeerCertSha256": "" +} +``` + +Важно: `pinnedPeerCertSha256` — **hex**, не base64. Поддерживает OpenSSL-колонки. + +### REALITY +Опционально: `security: "reality"` вместо `security: "tls"`. +Сертификат не нужен — клиент доверяет по `publicKey` (X25519). +Таргет: `www.apple.com` (microsoft.com режет подключения). + +## 6. Статистика + +xray считает трафик по **email** пользователя. Если email пустой — счётчики не создаются. +По умолчанию панель присваивает email = UUID (уникальный для каждого клиента). + +Для включения статистики на сервере (добавляется автоматически при первом запросе): +```json +"api": {"tag": "api", "listen": "127.0.0.1:10085", "services": ["StatsService"]}, +"stats": {}, +"policy": {"levels": {"0": {"statsUserUplink": true, "statsUserDownlink": true, "statsUserOnline": true}}} +``` + +## 7. Файлы транспорта -## 6. Файлы, которые нужно добавить/изменить в Xray-core **Новые** (пакет транспорта): -- `transport/internet/stealth/config.proto` (+ сгенерированный `config.pb.go`) -- `transport/internet/stealth/config.go` — регистрация конфига +- `transport/internet/stealth/config.proto` (+ `config.pb.go`) +- `transport/internet/stealth/config.go` — регистрация - `transport/internet/stealth/framing.go` — кадры -- `transport/internet/stealth/conn.go` — h2Conn (net.Conn поверх POST-стрима) -- `transport/internet/stealth/dialer.go` — клиент (TLS/REALITY, ротация, ретрай) -- `transport/internet/stealth/hub.go` — сервер (http.Server, зеркало, AUTH) +- `transport/internet/stealth/conn.go` — net.Conn поверх HTTP/2 стрима +- `transport/internet/stealth/dialer.go` — клиент +- `transport/internet/stealth/hub.go` — сервер **Изменённые** (в `infra/conf`): -- `infra/conf/transport_internet.go` — `case "stealth"`, поле `StealthSettings`, - ветка сборки, разрешение stealth в REALITY-проверке +- `infra/conf/transport_internet.go` — `case "stealth"`, REALITY-проверка - `infra/conf/transport_method.go` — struct `StealthConfig` + `Build()` -Полный исходник и изменения — в репозитории (публичном): -https://git.my-handbook.ru/ded_ikar/sdm-xray +## 8. Требования к сборке + +- Go 1.26 +- golang.org/x/net/http2 +- golang.org/x/time/rate +- refraction-networking/utls +- protoc + protoc-gen-go (для config.proto) + +Регенерация protobuf: +```bash +protoc -I. --go_out=. --go_opt=paths=source_relative transport/internet/stealth/config.proto +``` + +## 9. Известные ограничения + +- HTTP/2 — один поток, throughput ~140 Мбит (bulk), ~22 Мбит (веб) +- Клиент и сервер должны быть одной версии форка +- `pinnedPeerCertSha256` — нестандартный параметр (поддерживается только нашим форком) +- REALITY: таргет microsoft.com режет — использовать apple.com + +## 10. Ссылки + +- Репозиторий: https://git.my-handbook.ru/ded_ikar/sdm-xray +- Релизы: https://git.my-handbook.ru/ded_ikar/sdm-xray/releases +- Лицензия: MPL-2.0