ZaStoGram_desktop/Telegram/SourceFiles/mtproto/proxy/mtproxy/client_hello_profile.h
loop-uh b334f9c137 Stop sending the fingerprint a filtered network refuses
Measured 26 July 2026 against one relay from two networks, twelve attempts
per profile per network, every hello built from the client's own templates.
Unfiltered, all six profiles are answered in under fifty milliseconds.
Filtered, the four that keep a fixed extension order are answered 12/12,
while chrome_modern and android_chrome are answered 3/12 and get silence
otherwise - same relay, same secret, same minutes, same machine. The
post-quantum key share is not the trait being refused: three of the four
that pass carry it too. Extension permutation is the only structural trait
the two refused ones share and the four survivors lack.

The client defaulted to chrome_modern, so on such a network no proxy ever
completed a handshake while a plain Python probe on the same machine in the
same minute did. That is what "our client breaks working proxies" was.

Auto now resolves to yandex, and a refused fingerprint is steered away from
at both places a setting becomes a hello, so a hand-picked chrome_modern
does not keep a client mute either. The templates stay in the table with
their capture metadata - the JA4 guard still checks one - they are simply
never sent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 15:55:21 +03:00

49 lines
1.6 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/proxy/data.h"
namespace MTP::details {
enum class ClientHelloProfileValidation {
Claimed,
Validated,
};
struct ClientHelloProfileInfo {
ProxyTlsProfile profile = ProxyTlsProfile::Auto;
const char *id = "";
ClientHelloProfileValidation validation
= ClientHelloProfileValidation::Claimed;
const char *captureSource = "";
const char *captureVersion = "";
const char *expectedJa4 = "";
// A fingerprint measured to be refused by a network the client has to
// work on. The template stays here - it is still a correct capture, and
// the JA4 guard still checks it - but nothing sends it any more. See
// kWithheldReason for what was measured.
bool withheld = false;
const char *withheldReason = "";
};
// Plain lookup: answers about the named profile, including a withheld one.
[[nodiscard]] const ClientHelloProfileInfo &ClientHelloProfile(
ProxyTlsProfile profile);
// What to actually send for a configured value: resolves the two auto names
// and steers away from a withheld fingerprint, so a setting saved before the
// measurement does not keep a client on a template no relay ever answers.
[[nodiscard]] ProxyTlsProfile EffectiveClientHelloProfile(
ProxyTlsProfile profile);
[[nodiscard]] ProxyTlsProfile DefaultClientHelloProfile();
[[nodiscard]] bool IsClientHelloProfileValidated(ProxyTlsProfile profile);
} // namespace MTP::details