mirror of
https://gitverse.ru/kpa39l/networking-proxy.git
synced 2026-09-29 09:15:02 +00:00
210 lines
14 KiB
Markdown
210 lines
14 KiB
Markdown
# Session reference — Диагностика XRay Reality 2026-07-14
|
||
|
||
## Контекст сессии
|
||
|
||
- **Сервер:** VPS vps03 (80.209.240.167), XRay Reality на портах 443 и 8443
|
||
- **Клиент:** Android, v2rayNG (версия не уточнена)
|
||
- **Оператор:** мобильный, IP клиента 46.159.34.212
|
||
- **Проблема:** Яндекс.Диск якобы работает через VPN, браузер — нет
|
||
- **Реальное положение дел (выяснилось позже):** Пользователь отключал VPN, когда проверял Яндекс.Диск. VPN был реально выключен. Классический самообман.
|
||
|
||
## Хронология диагностики
|
||
|
||
### Фаза 1 — Подтверждение работоспособности сервера
|
||
|
||
1. `systemctl status xray` → active ✅
|
||
2. `ss -tlnp | grep 443/8443` → LISTEN ✅
|
||
3. `journalctl -u xray --since ... | grep <user-ip>` → видно `REALITY: invalid connection from 46.159.34.212: failed to read client hello`
|
||
4. `curl -v https://google.com` с сервера → работает ✅ (через IPv4, IPv6 недоступен)
|
||
5. `curl -v -4 https://google.com` с сервера → TLS handshake OK ✅
|
||
|
||
**Вывод:** Сервер жив, конфиг валиден, outbound freedom работает.
|
||
|
||
### Фаза 2 — Анализ логов
|
||
|
||
```
|
||
accepted udp:46.159.34.212:XXXXX:53 [direct] ← DNS проходит
|
||
REALITY: invalid connection from 46.159.34.212:XXXXX: failed to read client hello ← TCP не проходит
|
||
```
|
||
|
||
**Ключевое наблюдение:** DNS-запросы (UDP:53) видны в логах как `accepted udp:...:53 [direct]`, а TCP-соединения — только как `REALITY: failed to read client hello`. Ни одного `accepted tcp:` из этого IP не было.
|
||
|
||
## Полезные наблюдения
|
||
|
||
### `curl` зависает, а не таймаутит
|
||
|
||
Обычно curl на Android при недоступности пишет `curl: (28) Connection timed out after X ms`.
|
||
В этой сессии curl просто висел бесконечно — не было ни ответа, ни таймаута. Это нестандартное поведение, указывающее на то, что TCP SYN достигает сервера, но дальнейшее взаимодействие обрывается.
|
||
|
||
### `REALITY: failed to read client hello` — что это значит
|
||
|
||
Ошибка означает:
|
||
1. TCP трёхстороннее рукопожатие **состоялось** (SYN → SYN-ACK → ACK прошли)
|
||
2. После ACK сервер ожидает TLS ClientHello для проверки REALITY
|
||
3. Клиент отправляет что-то, что непохоже на ClientHello, или отправляет ClientHello с неверными параметрами
|
||
|
||
Возможные причины (по вероятности):
|
||
1. **Клиент использует V2Ray-core вместо XRay-core** — REALITY — эксклюзив XRay. V2Ray-core не умеет REALITY, соединение приходит но TLS-рукопожатие неправильное.
|
||
2. **Неверный publicKey или shortId** — REALITY проверяет их на уровне ClientHello.
|
||
3. **Профиль v2rayNG не выбран** — телефон шлёт трафик на порт 443, но не через v2rayNG.
|
||
|
||
### Стратегия доменов IPIfNonMatch
|
||
|
||
Пользователь заметил, что смена `Domain Strategy` с `ASIS` на `IPIfNonMatch` один раз помогла, но потом перестала.
|
||
|
||
**IPIfNonMatch** — v2rayNG резолвит домен в IP, и только потом применяет правила маршрутизации. Если DNS на телефоне возвращает корректный IP, это может помочь обойти проблемы с DNS-перехватом.
|
||
|
||
**Почему могло помочь один раз:**
|
||
- DNS-кеш на телефоне был пуст, первый запрос вернул правильный IP
|
||
- После кеширования — запросы пошли по старому пути
|
||
|
||
### IPv4 vs IPv6
|
||
|
||
При проверке `curl https://google.com` на сервере:
|
||
- IPv6 адреса google.com резолвятся, но `connect fails: Network is unreachable`
|
||
- IPv4 (`-4`) работают нормально
|
||
|
||
Это значит, что на VPS нет IPv6-связности. Если клиент резолвит google.com в IPv6 и пытается идти через XRay — соединение может не установиться.
|
||
|
||
### Продолжение сессии — Обновление сервера и новая ошибка
|
||
|
||
#### Фаза 3 — `proxy/vless/encoding: invalid request version`
|
||
|
||
После обновления сервера с 26.3.27 до 26.7.11 (клиент: Xray-core 26.6.27) ошибка `REALITY: failed to read client hello` сменилась на:
|
||
|
||
```
|
||
rejected proxy/vless/encoding: invalid request version
|
||
```
|
||
|
||
**Значение:** REALITY-рукопожатие прошло успешно, но VLESS-протокол на клиенте использует другой формат запроса, чем сервер.
|
||
|
||
**Корень:** версия Xray на сервере (26.3.27) и на клиенте (26.6.27) различаются. Между ними изменился VLESS-протокол. При этом `install-release.sh` не обновляет сервер, потому что проверяет только GitHub `latest` релиз (который всё ещё 26.3.27), а клиент (v2rayNG) имеет более новую сборку.
|
||
|
||
**Как обновить сервер вручную:**
|
||
|
||
```bash
|
||
# Найти последнюю версию
|
||
curl -sL https://api.github.com/repos/XTLS/Xray-core/releases | grep -E '"tag_name"' | head -5
|
||
|
||
# Скачать и распаковать
|
||
curl -sL -o /tmp/xray.zip "https://github.com/XTLS/Xray-core/releases/download/v26.7.11/Xray-linux-64.zip"
|
||
unzip -o /tmp/xray.zip xray -d /usr/local/bin/
|
||
chmod +x /usr/local/bin/xray
|
||
systemctl restart xray
|
||
```
|
||
|
||
**Важно:** `unzip` кладёт файлы рядом с xray (geoip.dat, geosite.dat). Если извлекать всё (`unzip -o` целиком) — перезаписываются актуальные geoip/geosite свежими из архива (что может быть ок, но лучше извлекать только бинарник).
|
||
|
||
#### Результат
|
||
|
||
После обновления сервера до 26.7.11 (новее клиента 26.6.27) ошибка `invalid request version` должна исчезнуть. Если остаётся — обновить и клиент (v2rayNG → последняя версия).
|
||
|
||
### Продолжение сессии 2026-07-15 — Порто-независимая блокировка XRay Reality на Ростелеком
|
||
|
||
#### Контекст
|
||
|
||
- **Провайдер:** Ростелеком (домашний WiFi)
|
||
- **Клиент:** Android, v2rayNG 2.2.6 (Xray-core 26.6.27, Lib v38)
|
||
- **Сервер:** XRay 26.7.11, Reality, VLESS+XTLS+Vision
|
||
- **Параметры:** flow=xtls-rprx-vision, fingerprint=chrome (потом random), encryption=none
|
||
|
||
#### Симптом
|
||
|
||
Вечером предыдущего дня соединение работало. На следующее утро/день:
|
||
- "Internet check failed" в v2rayNG
|
||
- `curl` зависает без ответа (не таймаут, не connection refused)
|
||
- В логах сервера: `failed to read client hello` с IP клиента
|
||
|
||
#### Попробованные меры
|
||
|
||
| Мера | Что изменили | Результат |
|
||
|------|-------------|-----------|
|
||
| Порт | 443 → 8443 → 50000 | `failed to read client hello` на всех |
|
||
| dest | reddit.com → microsoft.com → discord.com | `failed to read client hello` на всех |
|
||
| serverNames | reddit.com → microsoft.com → discord.com | `failed to read client hello` (сначала `server name mismatch`, после исправления — `failed to read client hello`) |
|
||
| fingerprint | chrome → random | Без изменений |
|
||
| Всё вместе | 50000 + discord.com + random | Без изменений |
|
||
|
||
Ни одно изменение не дало ни одного успешного `accepted tcp:` в логах. Все соединения обрывались на `failed to read client hello`.
|
||
|
||
#### Вывод
|
||
|
||
DPI на Ростелекоме научился распознавать **ClientHello от XRay-core** независимо от:
|
||
- Порта назначения (443, 8443, 50000 — все под фильтром)
|
||
- SNI (reddit.com, microsoft.com, discord.com — все под фильтром)
|
||
- Настройки `fingerprint` (chrome и random — одинаково под фильтром)
|
||
|
||
**Эскалация:** В такой ситуации менять параметры Reality бесполезно. Нужно менять транспорт/протокол:
|
||
1. WebSocket + TLS через nginx reverse proxy
|
||
2. Trojan protocol
|
||
3. AmneziaWG
|
||
4. Shadowsocks + v2ray-plugin (WebSocket)
|
||
|
||
#### Ссылка на статью
|
||
|
||
Статья [Конец удобства? Почему MTProxy начал ломаться](https://habr.com/ru/articles/1018672/) (s4q, 2 апр 2026) описывает похожую ситуацию — TLS fingerprint DPI на уровне ClientHello. Хотя статья про MTProxy, механизм детекта тот же: DPI анализирует ClientHello и принимает решение до установки TLS-сессии. Разница: MTProxy использует Fake-TLS (поддельный ServerHello), Reality использует настоящий сервер. Но fingerprinter самого ClientHello может быть распознан независимо от того, что происходит после.
|
||
|
||
#### Решение: WebSocket plain (без TLS)
|
||
|
||
**Шаг 1 — Добавить WS inbound на сервере:**
|
||
|
||
```json
|
||
{
|
||
"port": 50002,
|
||
"protocol": "vless",
|
||
"settings": {
|
||
"clients": [
|
||
{ "id": "cf4d32e5-9c19-460e-a5de-f881b01dcfe1" }
|
||
],
|
||
"decryption": "none"
|
||
},
|
||
"streamSettings": {
|
||
"network": "ws",
|
||
"security": "none",
|
||
"wsSettings": {
|
||
"path": "/",
|
||
"headers": { "Host": "discord.com" }
|
||
}
|
||
},
|
||
"sniffing": { "enabled": false }
|
||
}
|
||
```
|
||
|
||
**Ключевые моменты:**
|
||
- `security: "none"` — **нет TLS**. WS идёт через HTTP Upgrade, ClientHello не отправляется.
|
||
- `flow` не указывается — для WS без TLS flow не нужен.
|
||
- `sniffing: false` — для WS без TLS сниффинг не работает (нечего сниффать).
|
||
- `Host: "discord.com"` в заголовках — для маскировки HTTP-запроса.
|
||
|
||
**Шаг 2 — Проверить что порт слушается:**
|
||
```
|
||
ss -tlnp | grep 50002
|
||
```
|
||
|
||
**Шаг 3 — Настроить клиент (v2rayNG):**
|
||
|
||
| Поле | Значение |
|
||
|------|----------|
|
||
| address | IP сервера |
|
||
| port | 50002 |
|
||
| id | как на сервере |
|
||
| flow | (пусто) |
|
||
| encryption | none |
|
||
| network | ws |
|
||
| security | none (не TLS!) |
|
||
| ws path | / |
|
||
| ws Host | discord.com |
|
||
|
||
**Результат:** Соединение установилось, 2ip.io показывает IP сервера (80.209.240.167). ✅
|
||
|
||
**Почему это работает:** WS без TLS не отправляет ClientHello. DPI не с чем сравнивать fingerprint. HTTP Upgrade-запрос не имеет характерных признаков прокси-трафика. VLESS шифрует содержимое внутри WS, так что конфиденциальность сохраняется.
|
||
|
||
**Trade-off:** WS без TLS виден как HTTP-трафик (не TLS), поэтому не маскируется под HTTPS. Пройдёт DPI, но может быть замечен провайдером как не-TLS трафик на нестандартном порту. Для дополнительной защиты можно использовать TLS-версию WS через nginx reverse proxy.
|
||
|
||
#### Выводы по сессии
|
||
|
||
1. **Самое вероятное объяснение (первоначальное):** v2rayNG на телефоне использует V2Ray-core (старый), а не XRay-core. REALITY не поддерживается старым core. Решение: обновить v2rayNG до 1.8.13+ (там встроен XRay-core).
|
||
2. **Фактическая проблема:** версионное несоответствие Xray между сервером (26.3.27) и клиентом (26.6.27). `install-release.sh` не обновляет до не-latest версий, требуется ручное обновление.
|
||
3. **Самое тривиальное объяснение:** VPN был выключен при проверке Яндекс.Диска (подтверждено пользователем).
|
||
4. **Для будущей диагностики:** Всегда проверять реальное состояние VPN на клиенте, не полагаться на слова пользователя. Лучший индикатор — логи сервера.
|
||
5. **Новый паттерн:** `proxy/vless/encoding: invalid request version` → обновить сервер Xray до версии >= клиентской. |