- sleepCtx helper (NewTimer+Stop) replaces time.After in long backoff sites:
DTLS reconnect (10-30s), captcha 60s ban backoff, lockout sleep. Avoids
long-lived timer leak when ctx cancels mid-wait.
- startIdentityJanitor: prunes expired identityStore entries every 5 min.
Two-phase with TryLock so an in-flight acquireVkIdentity (which can hold
entry.mu for tens of seconds during captcha) never blocks the janitor or
other acquires.
- getYandexCreds: cap ws read loop at 64 messages so a chatty/malformed peer
cannot keep us reading until the 15s deadline burns down.
Two related changes ported from main, adapted to the flat client/ layout:
1. Identity caching + per-slot TURN creds (vkauth)
- Split the monolithic getTokenChain into:
* acquireVkIdentity — captcha-gated steps 1-3 (anonym_token,
getCallPreview, getAnonymousToken). Cached per (link, client_id)
for identityLifetime=8m, globally serialised via vkRequestMu +
3-6s cooldown.
* acquireVkTurnSlot — lightweight steps 4-5 (auth.anonymLogin
with fresh device_id, vchat.joinConversationByLink). Each call
returns a distinct (username, password) pair, so multiple
streams under the same identity each get their own VK-side
slot — bypasses per-username throttling without re-solving
captcha.
- vkCredentialsList trimmed from 5 to 2: VKVIDEO_* and VK_ID_AUTH_APP
started returning error_code:3 "Unknown method" on
calls.getAnonymousToken (observed 2026-04-28) and only burned
throttle budget if kept in rotation.
- streamsPerCache 10 -> 1: each stream now caches its own slot
creds because slots are unique per call.
- Credential rotation starts at streamID%n offset so concurrent
streams spread across the credential list instead of all hitting
the same client_id first.
- identityStore + identityEntry give per-(link, client_id)
serialisation: only one stream solves captcha per identity.
- turn_server.urls picking is transport-aware (prefers urls whose
?transport= matches udpMode, falls back to the full list when
nothing matches to preserve -port override) and round-robins
within an identity via urlCounter — streamID%len(pool) collapses
every stream of an identity onto the same parity.
2. Multiple TURN allocations per stream (oneTurnConnection)
- New -allocs-per-stream flag (default 1).
- dialTurn extracted as a helper that returns a turnAllocation
(dialConn, turn.Client, relay PacketConn).
- relayPool wraps the live relays with sync.RWMutex + atomic
counter for round-robin pick on the outbound hot path.
- Outbound goroutine (conn2 -> relay) uses pool.pick() round-robin.
Per-relay inbound goroutine (relay -> conn2) is spawned via
spawnInbound; they all feed the same conn2 keyed by
internalPipeAddr.
- Primary allocation opens immediately. Extras are deferred 3s so
the DTLS handshake completes over the primary first, letting the
server install the Connection ID; subsequent multi-path packets
are then matched to the existing session via CID rather than
5-tuple. Each extra is jittered 200ms apart.
- Allocation tracking + deadline-on-cancel + close-on-exit handle
clean shutdown of all relays.
A new udpMode global mirrors the -udp flag so acquireVkTurnSlot
(called from the credential layer, which doesn't have access to
turnParams) can filter URLs by transport.
Brings the captcha-solver improvements from main into feat/doh while keeping
the flat client/ layout (no internal/* refactor pulled in).
- Persistent SavedProfile (UA + Sec-CH-UA + device JSON + browser_fp) captured
during manual solve and replayed by auto/slider so VK sees a consistent
fingerprint across runs. Stored under $VK_PROFILE_PATH | UserCacheDir |
TempDir | CWD.
- callCaptchaNotRobot: per-session adFp, sha256 debug_info, jittered
connectionRtt/connectionDownlink, cursor "[]" on first check, headers
switched to Origin api.vk.ru / Referer not_robot_captcha.
- Slider session: per-session adFp + debugInfo, savedProfile injection,
ApplyBrowserProfileFhttp + same captcha headers on every request,
getContent fallback with/without captcha_settings, second componentDone
before getContent (matches real widget lifecycle).
- Manual proxy: strip WebView identity headers (X-Requested-With and friends),
server-side rewrite of src/href/action attributes (skipping <script>/<style>
spans), inject helper script at <head> opening, sendBeacon + form fallback
for token delivery on mobile WebView, /generic_proxy SSRF allowlist +
scheme check + security-header strip + server-side success_token extract,
loggingTransport that captures the real browser fingerprint and persists
it as SavedProfile, best-effort 3s Shutdown, Windows rundll32 launcher,
PII redaction in logs.
- solvePoW returns an error instead of an empty string.
- Manual captcha timeout bumped 60s -> 3m on context.Background so a human
has time to solve regardless of the auth-level deadline; non-empty
token/key from the manual goroutine is treated as success even if the
server cleanup returned an error.
Добавлено кэширование success_token для капчи.
Установлен размер пула 1 для использования одной учетной записи во всех потоках.
Дополнительно устранил warnings от golangcli-lint:
Удален rand.Seed
Реализована проверка ошибки в endSession
Реализована обработка Body.Close()
Distribute incoming TCP connections across N parallel TURN+DTLS+KCP+smux
sessions in round-robin fashion, aggregating bandwidth of multiple relays.
Add sessionPool with thread-safe add/remove/pick operations.
Each session is maintained by its own goroutine with auto-reconnect.
The -n flag now controls session count in TCP mode (default 16 for VK).
Refactor: extract createSmuxSession from runTCPSession for reuse.
Add -tcp flag to client and server for forwarding TCP connections
(VLESS, etc.) through the TURN tunnel instead of UDP packets (WireGuard).
Stack: TCP → smux (mux) → KCP (reliability) → DTLS (encryption) → TURN
New dependencies: xtaci/kcp-go/v5, xtaci/smux