Skip to content

fix: WS keepalive-пинги против обрыва простаивающих сессий (#646)#925

Open
f4rceful wants to merge 1 commit into
Flowseal:mainfrom
f4rceful:fix/ws-keepalive-646
Open

fix: WS keepalive-пинги против обрыва простаивающих сессий (#646)#925
f4rceful wants to merge 1 commit into
Flowseal:mainfrom
f4rceful:fix/ws-keepalive-646

Conversation

@f4rceful

Copy link
Copy Markdown
Contributor

Что сделано

  • Добавлен RawWebSocket.send_ping() — отправка WS-фрейма OP_PING (маскированного, как требует протокол для клиента).
  • Добавлен цикл _ws_keepalive() в bridge_ws_reencrypt, который шлёт PING на upstream каждые --ws-keepalive секунд (по умолчанию 30, 0 — отключить).
  • Флаг --ws-keepalive SEC в CLI и поле ws_keepalive_interval в ProxyConfig (дефолт 30с — фикс активен и для GUI/трея).

Зачем (разбор #646)

Долгие сессии рвались через случайный интервал простоя: Telegram показывал «прокси использует некорректные настройки», хотя сам прокси оставался жив, а мгновенное переподключение всё чинило.

Причина — тихий обрыв простаивающего соединения. Прокси отвечал на входящие PING, но сам не слал keepalive, и SO_KEEPALIVE не выставлялся. Stateful-устройство на пути (NAT-таблица домашнего роутера / мобильный CGNAT, либо idle-таймаут CF edge) выкидывает простаивающий поток; следующий пакет упирается в мёртвое соединение → RST. Тот же симптом в независимой go-реализации указывает на причину в транспорте/NAT, а не в Python-коде.

Периодический PING держит NAT-маппинги «тёплыми». Дополнительно: при сбое отправки пинга сессия теперь закрывается сразу, а не висит до следующего пакета клиента.

Поведение по умолчанию

Keepalive включён (30с). Отключить: --ws-keepalive 0.

Как проверить

  • py_compile для proxy/bridge.py, proxy/raw_websocket.py, proxy/config.py, proxy/tg_ws_proxy.py — без ошибок.
  • Полевая проверка пройдена: Telegram Desktop через прокси, простой 15 минут — сессия осталась живой, сообщения уходят мгновенно без переподключения (раньше на той же сети рвалось).
  • Локально проверено юнит-тестами: корректность фрейма PING (пустой и с payload под маской), исключение при закрытом сокете, цикл шлёт пинги повторно / чисто отменяется / выходит при ошибке отправки / отключён при interval<=0.

…eal#646)

Idle sessions could be silently torn down by NAT/firewall timeouts on the
upstream WS connection: with no traffic and no keepalive, the bridge only
noticed the dead connection on the next client packet, by which point
Telegram had already dropped the session.

Add an optional WS keepalive: RawWebSocket.send_ping() emits a masked PING
frame, and _ws_keepalive() runs alongside the bridge pumps, pinging every
ws_keepalive_interval seconds (--ws-keepalive, default 30, 0 to disable).
The loop exits on send failure so a dead upstream is detected promptly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant