Initial commit: Hermes skill networking-proxy

This commit is contained in:
estorozhenko
2026-09-06 13:51:04 +00:00
commit be86a3ff2b
8 changed files with 1389 additions and 0 deletions
@@ -0,0 +1,210 @@
# 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 до версии >= клиентской.