[GH-ISSUE #3150] VLESS+REALITY: приложение заливает VPN-сервер plain-TCP-пробами без TLS (до ~1700/мин) и залипает в циклах переподключения (5.0.1.5, Windows) #1462

Open
opened 2026-10-13 20:42:56 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coolswood on GitHub (Sep 10, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3150

Описание

AmneziaVPN 5.0.1.5 (Windows) при активном профиле VLESS+REALITY (ключ импортирован через «вставить vless://») непрерывно шлёт на endpoint VPN-сервера plain-TCP-соединения без TLS. Следствия:

  1. Приложение залипает в циклах переподключения: для пользователя выглядит как «10 минут работает / 10 минут не работает». В «мёртвой» фазе мы зафиксировали до ~1700 plain-TCP-соединений в минуту с IP клиента. Серверы REALITY по дизайну не отвечают на пробы без TLS, поэтому проверка доступности (а судя по поведению — это она) никогда не проходит, и приложение циклически глушит/поднимает туннель.
  2. Деградация сервера для всех клиентов. Xray-core (v26.3.27) на каждую невалидную соединялку по дизайну dial'ит REALITY-dest. Под таким штормом сервер накопил 2400+ открытых fd (утечка dest-dials) и в итоге перестал обслуживать даже легитимных клиентов, пока его не перезапустили.

Доказательства на стороне сервера

Сервер: Xray-core v26.3.27, один inbound vless + reality (xtls-rprx-vision), TCP 443, SNI www.apple.com. Профиль импортирован штатно (vless:// → вставить ключ). Других сервисов на порту нет.

Лог сервера в «мёртвой» фазе приложения (IP клиента обезличен):

[Info] transport/internet/tcp: REALITY: processed invalid connection from C.C.C.C:45544: failed to read client hello
[Info] transport/internet/tcp: REALITY: processed invalid connection from C.C.C.C:33146: failed to read client hello
... (сотни в минуту)

Замеры tcpdump в то же окно:

  • 1025 plain-TCP-попыток за 30 секунд на порт 443 (каждая с нового исходящего порта)
  • НИ ОДНОЙ с TLS ClientHello — все «failed to read client hello»
  • Пик ~34 соединения/сек; минутный максимум — 1685 соединений

В «рабочей» фазе тот же клиент давал корректные REALITY-хендшейки и обычный проксированный трафик без единого invalid — то есть ключи, конфиг сервера и сеть проверены и корректны.

Ключевой контрольный эксперимент

Клиент, порождающий шторм, заменили на сторонний Xray-клиент (Hiddify) с тем же vless:// ключом, на той же машине, в той же сети: шторм прекратился полностью (0 попыток соединения за 20 секунд tcpdump против ~34/сек), туннель стабилен. Поведение однозначно принадлежит AmneziaVPN.

Детали деградации сервера

  • Свежий старт xray: ~160 fd → ~2400 fd за ~30 минут под штормом → REALITY-inbound перестаёт завершать хендшейки (висит даже openssl s_client напрямую в контейнер). docker restart мгновенно восстанавливает сервис.
  • Внутри контейнера в момент деградации: ~1200 сокетов SYN-SENT к dest + ~1200 «висящих» ESTAB (dial'ы к сайту-маске копятся и не закрываются).
  • Повторяется из нескольких разных сетей (два мобильных оператора) — исключает per-network DPI-событие.

Просьба

Подскажите, какой компонент шлёт эти plain-TCP-пробы на endpoint сервера? В Qt-слое клиента мы не нашли подходящего connectToHost вне PayloadSender (тот активен только для API-конфигов) — подозреваем bundled Go-компоненты (обёртка xray-ядра / tun2socks / платформенный демон).

Предложения:

  • Если это health/availability-check: сделать его protocol-aware — для VLESS+REALITY профилей либо слать корректный TLS ClientHello с настроенным SNI, либо проверять связность через установленный туннель, либо считать «живым» успешный TCP-connect без требования ответа сервера.
  • Ограничить частоту периодического продёргивания сервера (наблюдали 34 conn/s минутами).
  • Задокументировать несовместимость текущего health-check с REALITY-серверами (по факту он их само-DoSит).

Готовы предоставить pcaps, более длинные выгрузки логов или прогнать инструментированную сборку.

Окружение

  • Приложение: AmneziaVPN 5.0.1.5, Windows (с мобильного клиента AmneziaVPN тоже наблюдали, с меньшей частотой)
  • Профиль: импортированный vless:// ключ, tcp + reality (xtls-rprx-vision), fingerprint chrome
  • Сервер: Xray-core v26.3.27, self-hosted (ставился не через AmneziaVPN), REALITY dest www.apple.com:443
Originally created by @coolswood on GitHub (Sep 10, 2026). Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3150 ### Описание AmneziaVPN 5.0.1.5 (Windows) при активном профиле **VLESS+REALITY** (ключ импортирован через «вставить vless://») непрерывно шлёт на endpoint VPN-сервера **plain-TCP-соединения без TLS**. Следствия: 1. **Приложение залипает в циклах переподключения**: для пользователя выглядит как «10 минут работает / 10 минут не работает». В «мёртвой» фазе мы зафиксировали до **~1700 plain-TCP-соединений в минуту** с IP клиента. Серверы REALITY по дизайну не отвечают на пробы без TLS, поэтому проверка доступности (а судя по поведению — это она) никогда не проходит, и приложение циклически глушит/поднимает туннель. 2. **Деградация сервера для всех клиентов.** Xray-core (v26.3.27) на каждую невалидную соединялку по дизайну dial'ит REALITY-`dest`. Под таким штормом сервер накопил 2400+ открытых fd (утечка dest-dials) и в итоге перестал обслуживать даже легитимных клиентов, пока его не перезапустили. ### Доказательства на стороне сервера Сервер: Xray-core v26.3.27, один inbound `vless + reality (xtls-rprx-vision), TCP 443`, SNI `www.apple.com`. Профиль импортирован штатно (vless:// → вставить ключ). Других сервисов на порту нет. Лог сервера в «мёртвой» фазе приложения (IP клиента обезличен): ``` [Info] transport/internet/tcp: REALITY: processed invalid connection from C.C.C.C:45544: failed to read client hello [Info] transport/internet/tcp: REALITY: processed invalid connection from C.C.C.C:33146: failed to read client hello ... (сотни в минуту) ``` Замеры tcpdump в то же окно: - **1025 plain-TCP-попыток за 30 секунд** на порт 443 (каждая с нового исходящего порта) - НИ ОДНОЙ с TLS ClientHello — все «failed to read client hello» - Пик ~34 соединения/сек; минутный максимум — **1685 соединений** В «рабочей» фазе тот же клиент давал корректные REALITY-хендшейки и обычный проксированный трафик без единого invalid — то есть ключи, конфиг сервера и сеть проверены и корректны. ### Ключевой контрольный эксперимент Клиент, порождающий шторм, заменили на сторонний Xray-клиент (Hiddify) **с тем же vless:// ключом, на той же машине, в той же сети: шторм прекратился полностью** (0 попыток соединения за 20 секунд tcpdump против ~34/сек), туннель стабилен. Поведение однозначно принадлежит AmneziaVPN. ### Детали деградации сервера - Свежий старт xray: ~160 fd → ~2400 fd за ~30 минут под штормом → REALITY-inbound перестаёт завершать хендшейки (висит даже `openssl s_client` напрямую в контейнер). `docker restart` мгновенно восстанавливает сервис. - Внутри контейнера в момент деградации: ~1200 сокетов SYN-SENT к dest + ~1200 «висящих» ESTAB (dial'ы к сайту-маске копятся и не закрываются). - Повторяется **из нескольких разных сетей** (два мобильных оператора) — исключает per-network DPI-событие. ### Просьба Подскажите, какой компонент шлёт эти plain-TCP-пробы на endpoint сервера? В Qt-слое клиента мы не нашли подходящего `connectToHost` вне `PayloadSender` (тот активен только для API-конфигов) — подозреваем bundled Go-компоненты (обёртка xray-ядра / tun2socks / платформенный демон). Предложения: - Если это health/availability-check: сделать его protocol-aware — для VLESS+REALITY профилей либо слать корректный TLS ClientHello с настроенным SNI, либо проверять связность **через** установленный туннель, либо считать «живым» успешный TCP-connect без требования ответа сервера. - Ограничить частоту периодического продёргивания сервера (наблюдали 34 conn/s минутами). - Задокументировать несовместимость текущего health-check с REALITY-серверами (по факту он их само-DoSит). Готовы предоставить pcaps, более длинные выгрузки логов или прогнать инструментированную сборку. ### Окружение - Приложение: AmneziaVPN 5.0.1.5, Windows (с мобильного клиента AmneziaVPN тоже наблюдали, с меньшей частотой) - Профиль: импортированный `vless://` ключ, `tcp + reality (xtls-rprx-vision)`, fingerprint `chrome` - Сервер: Xray-core v26.3.27, self-hosted (ставился не через AmneziaVPN), REALITY dest `www.apple.com:443`
Author
Owner

@ManguoLabsTech commented on GitHub (Sep 10, 2026):

Оценка

Проблема воспроизводима и хорошо задокументирована. Это взаимодействие двух независимых дефектов: некорректный health-check на стороне AmneziaVPN (Windows) и утечка dest-dial на стороне Xray-core при невалидных REALITY-соединениях.


Корневая причина — клиентская сторона

REALITY-сервер по дизайну не отвечает на соединения без TLS ClientHello и не посылает RST. AmneziaVPN (Windows) запускает проверку доступности endpoint, открывая raw TCP без инициации TLS-рукопожатия.

Алгоритм вырождается в лавину:

  1. Клиент открывает TCP → ждёт ответа → таймаут → закрывает
  2. Немедленно повторяет → ∞

Пик в 34 conn/sec и 1685 conn/min соответствует именно этому паттерну, а не трафику приложения.


Корневая причина — серверная сторона

Xray-core на каждое failed to read client hello dial'ит REALITY dest (www.apple.com:443) и не освобождает дескриптор до истечения TCP-таймаута исходящего соединения.

При 34 conn/sec и типичном таймауте 30–75 с:

34 conn/sec × 60 с = ~2040 полуоткрытых исходящих соединений

Это объясняет наблюдаемые 2400+ открытых fd и последующий отказ обслуживать легитимных клиентов.


Немедленные меры на сервере

1. Rate-limit новых соединений с одного IP (iptables):

iptables -I INPUT -p tcp --dport 443 -m state --state NEW \
  -m recent --set --name XRAY_RL

iptables -I INPUT -p tcp --dport 443 -m state --state NEW \
  -m recent --update --seconds 1 --hitcount 21 --name XRAY_RL \
  -j DROP

Порог --hitcount подобрать по реальной нагрузке легитимных клиентов; клиенты за NAT могут давать повышенный счётчик.

2. Увеличить лимит файловых дескрипторов (временная мера):


# /etc/systemd/system/xray.service — секция [Service]

# LimitNOFILE=65535

systemctl daemon-reload && systemctl restart xray

3. Проверить текущее состояние fd:

lsof -p $(pidof xray) | wc -l
cat /proc/$(pidof xray)/status | grep -i fd

Что требует исправления upstream

AmneziaVPN (Windows): health-check для REALITY-профиля должен выполнять полноценный TLS ClientHello с корректным SNI (идентично реальному подключению), либо быть отключён для этого типа inbound. Без этого исправления проблема воспроизводится при любой нестабильности сети.

Xray-core: при получении invalid connection (failed to read client hello) dest-dial не должен оставаться открытым дольше нескольких секунд. Проверьте, есть ли в ветке v1.8.x+ патч для этой утечки; если нет — отдельный issue в XTLS/Xray-core с приложенными счётчиками fd будет уместен.


Для уточнения диагностики

Если возможно, уточните:

  • Версию AmneziaVPN Windows-клиента

  • Включён ли в профиле split-tunneling или какой-либо режим «обхода» с отдельным connectivity check

  • Verbose-лог клиента в момент «мёртвой» фазы (фрагмент, инициирующий raw-TCP-запросы)

Это позволит точнее локализовать компонент, запускающий лавину соединений.

<!-- gh-comment-id:5621706726 --> @ManguoLabsTech commented on GitHub (Sep 10, 2026): ## Оценка Проблема воспроизводима и хорошо задокументирована. Это взаимодействие двух независимых дефектов: некорректный health-check на стороне AmneziaVPN (Windows) и утечка dest-dial на стороне Xray-core при невалидных REALITY-соединениях. --- ## Корневая причина — клиентская сторона REALITY-сервер по дизайну **не отвечает** на соединения без TLS ClientHello и не посылает RST. AmneziaVPN (Windows) запускает проверку доступности endpoint, открывая raw TCP без инициации TLS-рукопожатия. Алгоритм вырождается в лавину: 1. Клиент открывает TCP → ждёт ответа → таймаут → закрывает 2. Немедленно повторяет → ∞ Пик в **34 conn/sec** и **1685 conn/min** соответствует именно этому паттерну, а не трафику приложения. --- ## Корневая причина — серверная сторона Xray-core на каждое `failed to read client hello` **dial'ит REALITY dest** (`www.apple.com:443`) и не освобождает дескриптор до истечения TCP-таймаута исходящего соединения. При 34 conn/sec и типичном таймауте 30–75 с: ``` 34 conn/sec × 60 с = ~2040 полуоткрытых исходящих соединений ``` Это объясняет наблюдаемые **2400+ открытых fd** и последующий отказ обслуживать легитимных клиентов. --- ## Немедленные меры на сервере **1. Rate-limit новых соединений с одного IP (iptables):** ```bash iptables -I INPUT -p tcp --dport 443 -m state --state NEW \ -m recent --set --name XRAY_RL iptables -I INPUT -p tcp --dport 443 -m state --state NEW \ -m recent --update --seconds 1 --hitcount 21 --name XRAY_RL \ -j DROP ``` Порог `--hitcount` подобрать по реальной нагрузке легитимных клиентов; клиенты за NAT могут давать повышенный счётчик. **2. Увеличить лимит файловых дескрипторов (временная мера):** ```bash # /etc/systemd/system/xray.service — секция [Service] # LimitNOFILE=65535 systemctl daemon-reload && systemctl restart xray ``` **3. Проверить текущее состояние fd:** ```bash lsof -p $(pidof xray) | wc -l cat /proc/$(pidof xray)/status | grep -i fd ``` --- ## Что требует исправления upstream **AmneziaVPN (Windows):** health-check для REALITY-профиля должен выполнять полноценный TLS ClientHello с корректным SNI (идентично реальному подключению), либо быть отключён для этого типа inbound. Без этого исправления проблема воспроизводится при любой нестабильности сети. **Xray-core:** при получении `invalid connection` (failed to read client hello) dest-dial не должен оставаться открытым дольше нескольких секунд. Проверьте, есть ли в ветке v1.8.x+ патч для этой утечки; если нет — отдельный issue в XTLS/Xray-core с приложенными счётчиками fd будет уместен. --- ## Для уточнения диагностики Если возможно, уточните: - Версию AmneziaVPN Windows-клиента - Включён ли в профиле split-tunneling или какой-либо режим «обхода» с отдельным connectivity check - Verbose-лог клиента в момент «мёртвой» фазы (фрагмент, инициирующий raw-TCP-запросы) Это позволит точнее локализовать компонент, запускающий лавину соединений.
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amnezia-vpn/amnezia-client#1462
No description provided.