PROTOCOL.md: update for v0.2.2 (self-signed, email, REALITY, examples)
This commit is contained in:
+162
-66
@@ -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": "<UUID>", "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": "<UUID>", "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": "<IP VPS>",
|
||||
"fingerprint": "chrome",
|
||||
"pinnedPeerCertSha256": "<hex sha256 сертификата>"
|
||||
}
|
||||
```
|
||||
|
||||
Важно: `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
|
||||
|
||||
Reference in New Issue
Block a user