ZaStoGram/Tools/check_wss_official_default.py
loop-uh c7575323d7
Some checks failed
Build three ZaStoGram APKs / build (arm64-v8a, ZaStoGram-standalone-arm64-v8a, Arm64, arm64) (push) Failing after 2m44s
Build three ZaStoGram APKs / build (armeabi-v7a, ZaStoGram-standalone-armeabi-v7a, Armv7, armv7) (push) Failing after 2m16s
Build three ZaStoGram APKs / build (x86, ZaStoGram-standalone-x86, X86, x86) (push) Failing after 2m30s
ZaStoGram source guards / guards (push) Failing after 57s
WSS: прямой TCP — последняя ступень с охраной, перед фронтами без учёта паузы
Прямой TCP убрали из лестницы в сентябре: без охраны он держал DC2 в
«подключении» минутами (logs (1) (8)). Но там, где закрыт только
Cloudflare, а Telegram открыт, он единственный путь. Теперь он снова
стоит после туннеля, но под охраной:

- свой ключ здоровья direct-dc<N> по сети (Wi-Fi/мобильная), пауза после
  первой же неудачи 2 → 4 → 8 → 16 → 30 мин, сохраняется между запусками;
- сторожа WSS вместо общих 8–12 с: TCP за 2,5 с, первый ответ за 5,5 с
  (медиа 20 с) — DirectStepSubstate в ConnectionSocket;
- вердикт один раз при закрытии: 32 КБ ответа — доказательство, снимает
  историю пауз; ошибка, таймаут или сессия короче 32 КБ — неудача
  (ТСПУ пропускает начало и душит); намеренное закрытие ответившего
  сокета ничего не значит.

Лестница: релей → фронты → туннель → прямой TCP (если не на паузе) →
фронты без учёта паузы; DC203 так же. Гард check_wss_official_default это
закрепляет. Та же схема в Desktop и ZapretGUI (605d76f3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 21:47:36 +03:00

96 lines
5.8 KiB
Python

#!/usr/bin/env python3
from pathlib import Path
import sys
ROOT = Path(__file__).resolve().parents[1]
SHARED_CONFIG = ROOT / "TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java"
PROXY_LIST = ROOT / "TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java"
WSS_CPP = ROOT / "TMessagesProj/jni/tgnet/wss/WssSocket.cpp"
CONNECTION_CPP = ROOT / "TMessagesProj/jni/tgnet/Connection.cpp"
SOCKET_CPP = ROOT / "TMessagesProj/jni/tgnet/ConnectionSocket.cpp"
CONNECTIONS_JAVA = ROOT / "TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java"
FILE_LOADER = ROOT / "TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java"
def require(condition: bool, message: str) -> None:
if not condition:
print(f"FAIL: {message}", file=sys.stderr)
sys.exit(1)
def main() -> None:
shared_config = SHARED_CONFIG.read_text(encoding="utf-8", errors="replace")
proxy_list = PROXY_LIST.read_text(encoding="utf-8", errors="replace")
wss_cpp = WSS_CPP.read_text(encoding="utf-8", errors="replace")
connection_cpp = CONNECTION_CPP.read_text(encoding="utf-8", errors="replace")
socket_cpp = SOCKET_CPP.read_text(encoding="utf-8", errors="replace")
connections_java = CONNECTIONS_JAVA.read_text(encoding="utf-8", errors="replace")
file_loader = FILE_LOADER.read_text(encoding="utf-8", errors="replace")
require('preferences.getBoolean("wssTransportEnabled", true)' in shared_config
and "WSS включён по умолчанию" in shared_config,
"WSS must be enabled by default while keeping an explicit user choice")
require('preferences.getInt("wssTransportMode"' in shared_config,
"legacy WSS mode must migrate to the checkbox")
require('.remove("wssHost")' in shared_config and '.remove("wssPath")' in shared_config,
"custom gateway keys must be removed during migration")
require("UseWssTransport" in proxy_list and "wssTransportEnabled" in proxy_list,
"the official transport must be exposed as a normal checkbox")
require('prefix = "kws" + std::to_string(dcId)' in wss_cpp,
"official WSS must generate Telegram DC1-DC5 relay names")
require("dcId < 1 || dcId > 5" in wss_cpp,
"official WSS relay catalog must cover exactly DC1-DC5")
require('mediaConnection ? "-1.web.telegram.org"' in wss_cpp,
"official WSS must select the media relay variant")
require("getDatacenterId(), isMediaConnection);" in connection_cpp
and "wssMediaRoute" not in connection_cpp,
"WSS relay selection must follow the selected auth realm; uploads use regular kwsN")
require("forceProxyLikeInitForWss" not in connection_cpp
and "if (useSecret != 0)" in connection_cpp,
"direct WSS must not inject the MTProxy-only DC marker")
require("dcId < 1 || dcId > 5" in wss_cpp and "testBackend" in wss_cpp,
"unsupported/test DCs must stay on their normal transport")
require("officialRelayIpsForDc" in wss_cpp
and '{"149.154.167.220", "149.154.167.99"}' in wss_cpp
and "result.relayHost = selectRelayAddress(result.network, dcId)" in wss_cpp
and "result.relayHostFallback = result.domain" in wss_cpp
and "result.viaFallback = preferFallback(result)" in wss_cpp,
"official WSS must use direct Telegram ingress with an automatic hostname fallback")
require("if (!moveToNextRelayAddress(routeConfig))" in wss_cpp
and "!isCdn(routeConfig) && !moveToNextRelayAddress(routeConfig)" in wss_cpp,
"a failed relay address must hand the DC to its other ingress before the DNS name")
require("dcId == kNoRelayDcId" in wss_cpp
and "return CdnRoute(network, dcId, route) || TunnelRoute(network, dcAddress, route)\n"
" || DirectRoute(network, dcId, route) || CdnRoute(network, dcId, route, true);" in wss_cpp,
"DC203 must go fronts -> tunnel -> guarded direct -> fronts ignoring suppression")
require("if (CdnRoute(result.network, dcId, route) || TunnelRoute(result.network, dcAddress, route)\n"
" || DirectRoute(result.network, dcId, route)) {" in wss_cpp
and "return CdnRoute(result.network, dcId, route, true);" in wss_cpp,
"a DC with a closed relay must try guarded direct TCP only after the fronts and the tunnel, "
"and fall back to the fronts, never to unguarded direct TCP")
require("if (routeSuppressed(network, name)) {" in wss_cpp
and '"direct-dc"' in wss_cpp
and "suppressLocked(route, health, now, failure);" in wss_cpp
and "kDirectProofBytes" in wss_cpp,
"direct TCP must be paused after one failure per DC and network and proven only by volume")
require("selectedWssRoute.direct" in socket_cpp
and "checkDirectStepTimeout(now)" in socket_cpp
and "WSS_TCP_CONNECT_TIMEOUT_MS" in socket_cpp
and "finishDirectStep(reason);" in socket_cpp
and "noteDirectStepSent((uint32_t) sentLength);" in socket_cpp,
"the direct step must get the WSS watchdogs and report one verdict when it closes")
require("if (isCurrentTransportWss())" in connection_cpp
and "useSecret = 0" in connection_cpp,
"direct WSS must not inherit a TCP dcOption or MTProxy secret")
require("supportsCdnFileRedirects()" in connections_java
and "return !isWssTransportActive()" in connections_java,
"network layer must disable CDN redirects when WSS cannot route CDN DC ids")
require("req.cdn_supported = ConnectionsManager.supportsCdnFileRedirects()" in file_loader,
"file downloads must advertise the active transport's CDN capability")
print("WSS official route guard passed.")
if __name__ == "__main__":
main()