Персона строится детерминированно из FingerprintSeed (Client ID) и живёт
между перезапусками; при отказе captcha сжигается, и цепочка проходится
заново новой личностью с чистыми куками.
Телеметрия captcha (internal/captcha/telemetry.go) собирает аналитику
виджета: сэмплы сенсоров, connection-поля, курсор/тапы. Жест проживается
в реальном времени, иначе тайминги массивов не сходятся.
internal/personanet - TLS-клиент персоны (JA3 + split ClientHello), общий
для VK-auth и ручной captcha; порядок заголовков задаёт browserprofile.
BREAKING CHANGE: флаг -browser убран, семейство персоны всегда Chrome -
только Chromium даёт NetworkInformation и Generic Sensors, без которых
телеметрия captcha неполна. Класс устройства по-прежнему за -platform.
Флаг -browser chrome|firefox (default firefox, Chrome - escape-hatch), client-local для VK-auth, в freeturn:// URI не идёт. browserprofile.ForKind даёт канонные UA/JA3/Accept-Language; ApplyFhttp шлёт sec-ch-ua* только для Chrome (Firefox их не отправляет). dial.go выбирает profiles.Firefox_147 / Chrome_146 под UA.
Control-plane TLS-dial переведён на MultiSplitWriteConn (фрагментация SNI).
rtpopus2 несёт RTP header extension (RFC 8285 one-byte: X=1,
ssrc-audio-level + transport-cc) - ближе к современному WebRTC, чем
rtpopus (X=0). Wire несовместим с rtpopus, overhead 52 против 40.
wire.Codec - общий контракт профиля; NewClientCodec/Listen диспатчат
по -obf-profile, RelayPacketConn обобщён по Codec. Профиль тянется
в pipeline (раньше шёл только ключ obf).
Попутно: tcpfwd на 1-based streamID (единый базис с udprelay для
CacheID); cmd/client задаёт probe-host login.vk.ru для vk.
freeturn:// теперь несёт base64url(json) вместо query-string. Поля:
v, provider, peer, transport, mode, bond, obf, key, n, spc, cid,
listen, dns, dnss, mcap, name. Версионирован полем v=1.
config.PeekSubURL: pre-parse -sub до ParseClient, URI первой ноды
подсовывается позиционным аргументом - применение общим путём.
ParseClient применяет все новые поля URI (N, StreamsPerCred,
ClientID, Listen, DNSMode, DNSServers, ManualCaptcha, transport).
VK отдаёт несколько relay-адресов, но стрим использовал ровно один
(streamID%n). Если этот IP душит DPI/RST — allocate падает без альтернативы.
Credentials несёт список адресов (primary-first по streamID), DialTURN
пробует кандидатов по очереди и берёт первый успешный allocate. Балансировка
relay-IP по стримам сохранена, остальные адреса — фоллбэк. HostOverride (-turn)
схлопывает список до одного адреса.
На Android каталог рядом с бинарём read-only, ID не сохранялся и
ротировался на каждый запуск, ломая allowlist. Пробуем каталог бинаря,
UserConfigDir и TempDir по порядку.
Клиент всегда отправляет Client ID первой DTLS app-record, сервер
всегда читает. Флаг -auth и URI-параметр auth удалены — рассинхрон
client/server невозможен. -clients-file на сервере включает только
проверку ID по allowlist clients.json.
Также:
- clients.json и client_config.json пишутся с правами 0o600
- исправлены все находки golangci-lint (errcheck, gosec, govet shadow)
Примечание: удалён флаг -auth и URI-параметр auth; Client ID теперь
всегда в первой записи туннеля — старые клиенты/серверы несовместимы.
- internal/clientsdb: БД клиентов с hot-reload + length-prefixed ID wire
- internal/uri: parse/encode share-ссылок freeturn://
- internal/sub: загрузка и парсинг подписок (sub.md)
- client: флаги -auth, -client-id, -sub; позиционный URI; ID через crypto/rand
- server: подкоманда clients (add/remove/list), чтение ID под -clients-file
- запись/чтение ID учитывают DTLS record-orientation (буфер на запись целиком)
- docs: uri.md, sub.md; правки flags/deploy/quickstart
- снят UTF-8 BOM по всем исходникам
ParseClient/ParseServer возвращают flag.ErrHelp после печати usage, но main
трактовал это как фатальную ошибку: log.Fatalf печатал лишнюю строку
"flag: help requested" и выходил с кодом 1. Ловим flag.ErrHelp и выходим с 0
в обоих бинарях.
Сейчас нужен только VK-провайдер. internal/provider/static и связанные флаги
-static-user/-static-pass/-static-addr удалены, валидация и тесты обновлены.
Интерфейс provider.Provider остаётся — слот для будущих реализаций сохранён в
нейтральных формулировках doc-комментариев.
Переносит VK-specific пакеты под internal/provider/vk/internal/* — теперь
недоступны для импорта извне provider/vk (Go internal/ rule). ish остался в
internal/client/ish — не VK-specific.
vk.SetCaptchaLoggers удалён: логгеры captcha/manual подключаются внутри vk.New,
debug-флаг передаётся через новое поле Config.Debug. cmd/client/main.go больше
не импортирует captcha-пакеты.
Документация обновлена.
Вытаскивает источник TURN-creds из захардкоженной привязки к VK в интерфейс
internal/provider.Provider. Pipeline (proxy/udprelay, proxy/tcpfwd) работает
только через интерфейс — без VK-specific импортов и sentinel'ов.
Реализации:
- internal/provider/vk: фасад над client/vkauth (требует -link)
- internal/provider/static: фиксированные creds для self-hosted coturn /
metered / любого RFC 5766/8656 TURN (флаги -static-user/-static-pass/
-static-addr)
Изменения интерфейса:
- common.GetCredsFunc дропнула link (provider держит сам)
- udprelay AuthHandler: LockoutUntilUnix → BackoffUntilUnix
- vkauth sentinels обёрнуты в provider.ErrBackoffActive / ErrFatalNoStreams
через errors.Join (backward-compat сохранён)
Документация: docs/providers.md (новый), docs/glossary.md и docs/flags.md
обновлены.
dtlsdial.Dialer в VLESS-режиме теперь несёт тот же HandshakeSem (cap-3), что и
UDP-диалер, предотвращая неограниченное число конкурентных DTLS-handshake на
пути VLESS/bond.
Все N стримов теперь стартуют конкурентно. okchan оставлен только как лог-сигнал
первого успешного handshake; стримы 2..N больше не ждут завершения
DTLS-handshake стрима 1.
runCaptchaServerAndWait теперь делает select на ctx.Done вместе с keyCh и
закрывает listener в defer. Без этого, когда родительский manualCtx истекал
(3m), внутренняя горутина блокировалась на keyCh навсегда, оставляя
127.0.0.1:8765 занятым до выхода процесса. SolveViaProxy/SolveViaHTTP принимают
ctx и протягивают его; manualCaptchaSolver в cmd/client/main.go форвардит ctx
вместо того, чтобы его терять.