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>
51 lines
1.8 KiB
C++
51 lines
1.8 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
|
|
*/
|
|
#include "mtproto/proxy/mtproxy/handshake_plan.h"
|
|
|
|
#include "mtproto/proxy/mtproxy/client_hello_profile.h"
|
|
|
|
namespace MTP::details::MtProxy {
|
|
namespace {
|
|
|
|
// A proxy behind a slow or congested link needs more than a couple of
|
|
// seconds to relay the ServerHello back; cutting the attempt off early only
|
|
// burns another handshake against the same box.
|
|
constexpr auto kServerHelloTimeout = crl::time(5000);
|
|
|
|
} // namespace
|
|
|
|
MtProxyAttemptPlan MakeAttemptPlan(const ProxyStealthOptions &stealth) {
|
|
// The two auto entries are names for "whatever the client defaults to",
|
|
// so they resolve to a concrete template here - the plan is what the
|
|
// diagnostics report as the profile that was actually sent. A withheld
|
|
// fingerprint resolves away as well, including one a user selected before
|
|
// it was measured as refused.
|
|
const auto effective = EffectiveClientHelloProfile(stealth.tlsProfile);
|
|
auto planned = stealth;
|
|
planned.tlsProfile = effective;
|
|
return {
|
|
.admitted = true,
|
|
.configuredTlsProfile = stealth.tlsProfile,
|
|
.effectiveTlsProfile = effective,
|
|
.stealth = planned,
|
|
.serverHelloTimeout = kServerHelloTimeout,
|
|
};
|
|
}
|
|
|
|
crl::time ConnectionSpacing(ProxyConnectionPattern pattern) {
|
|
switch (pattern) {
|
|
case ProxyConnectionPattern::Soft: return crl::time(150);
|
|
case ProxyConnectionPattern::Quiet: return crl::time(400);
|
|
case ProxyConnectionPattern::Strict: return crl::time(700);
|
|
case ProxyConnectionPattern::Browser: return crl::time(250);
|
|
case ProxyConnectionPattern::Off: break;
|
|
}
|
|
return crl::time(0);
|
|
}
|
|
|
|
} // namespace MTP::details::MtProxy
|