diff options
| author | levlam <levlam@telegram.org> | 2026-03-17 12:30:53 +0300 |
|---|---|---|
| committer | levlam <levlam@telegram.org> | 2026-03-17 12:30:53 +0300 |
| commit | 0ae923c493bceb75433de2682ba8ae29cc7bf88d (patch) | |
| tree | 75f0d9228943f0a10e9f3eb4728b94838fbd46da | |
| parent | 338e4e5e45359f9338c98d584ecb9485bf59dd1c (diff) | |
Add class ProxyChecker.
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | td/telegram/Requests.cpp | 5 | ||||
| -rw-r--r-- | td/telegram/Td.cpp | 4 | ||||
| -rw-r--r-- | td/telegram/Td.h | 2 | ||||
| -rw-r--r-- | td/telegram/net/ConnectionCreator.cpp | 132 | ||||
| -rw-r--r-- | td/telegram/net/ConnectionCreator.h | 26 | ||||
| -rw-r--r-- | td/telegram/net/ProxyChecker.cpp | 161 | ||||
| -rw-r--r-- | td/telegram/net/ProxyChecker.h | 63 |
8 files changed, 237 insertions, 158 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f675365a7..f341d25b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -541,6 +541,7 @@ set(TDLIB_SOURCE_PART2 td/telegram/net/NetQueryVerifier.cpp td/telegram/net/NetStatsManager.cpp td/telegram/net/Proxy.cpp + td/telegram/net/ProxyChecker.cpp td/telegram/net/PublicRsaKeySharedCdn.cpp td/telegram/net/PublicRsaKeySharedMain.cpp td/telegram/net/PublicRsaKeyWatchdog.cpp @@ -933,6 +934,7 @@ set(TDLIB_SOURCE_PART2 td/telegram/net/NetStatsManager.h td/telegram/net/NetType.h td/telegram/net/Proxy.h + td/telegram/net/ProxyChecker.h td/telegram/net/PublicRsaKeySharedCdn.h td/telegram/net/PublicRsaKeySharedMain.h td/telegram/net/PublicRsaKeyWatchdog.h diff --git a/td/telegram/Requests.cpp b/td/telegram/Requests.cpp index 5979b075f..360807086 100644 --- a/td/telegram/Requests.cpp +++ b/td/telegram/Requests.cpp @@ -109,6 +109,7 @@ #include "td/telegram/net/NetStatsManager.h" #include "td/telegram/net/NetType.h" #include "td/telegram/net/Proxy.h" +#include "td/telegram/net/ProxyChecker.h" #include "td/telegram/NotificationGroupId.h" #include "td/telegram/NotificationId.h" #include "td/telegram/NotificationManager.h" @@ -9003,8 +9004,8 @@ void Requests::on_request(uint64 id, const td_api::testProxy &request) { return send_closure(td_actor_, &Td::send_error, id, r_proxy.move_as_error()); } CREATE_OK_REQUEST_PROMISE(); - send_closure(G()->connection_creator(), &ConnectionCreator::test_proxy, r_proxy.move_as_ok(), request.dc_id_, - request.timeout_, std::move(promise)); + send_closure(td_->proxy_checker_, &ProxyChecker::test_proxy, r_proxy.move_as_ok(), request.dc_id_, request.timeout_, + std::move(promise)); } void Requests::on_request(uint64 id, const td_api::testGetDifference &request) { diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 86087da25..810efbf16 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -60,6 +60,7 @@ #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetStatsManager.h" #include "td/telegram/net/Proxy.h" +#include "td/telegram/net/ProxyChecker.h" #include "td/telegram/net/TempAuthKeyWatchdog.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettingsManager.h" @@ -446,6 +447,7 @@ void Td::start_up() { inc_actor_refcnt(); // guard alarm_manager_ = create_actor<AlarmManager>("AlarmManager", create_reference()); + proxy_checker_ = create_actor<ProxyChecker>("ProxyChecker", create_reference()); CHECK(state_ == State::WaitParameters); for (auto &update : get_fake_current_state()) { @@ -671,6 +673,7 @@ void Td::clear() { reset_actor(ActorOwn<Actor>(std::move(language_pack_manager_))); reset_actor(ActorOwn<Actor>(std::move(net_stats_manager_))); reset_actor(ActorOwn<Actor>(std::move(password_manager_))); + reset_actor(ActorOwn<Actor>(std::move(proxy_checker_))); reset_actor(ActorOwn<Actor>(std::move(secure_manager_))); reset_actor(ActorOwn<Actor>(std::move(secret_chats_manager_))); reset_actor(ActorOwn<Actor>(std::move(storage_manager_))); @@ -770,6 +773,7 @@ void Td::close_impl(bool destroy_flag) { G()->set_close_flag(); clear_requests(); alarm_manager_.reset(); + proxy_checker_.reset(); send_update(td_api::make_object<td_api::updateAuthorizationState>( td_api::make_object<td_api::authorizationStateClosing>())); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 1ad9f4b61..42b1afd4d 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -84,6 +84,7 @@ class PhoneNumberManager; class PollManager; class PrivacyManager; class PromoDataManager; +class ProxyChecker; class QuickReplyManager; class ReactionManager; class ReferralProgramManager; @@ -300,6 +301,7 @@ class Td final : public Actor { ActorOwn<LanguagePackManager> language_pack_manager_; ActorOwn<NetStatsManager> net_stats_manager_; ActorOwn<PasswordManager> password_manager_; + ActorOwn<ProxyChecker> proxy_checker_; ActorOwn<SecretChatsManager> secret_chats_manager_; ActorOwn<SecureManager> secure_manager_; ActorOwn<StateManager> state_manager_; diff --git a/td/telegram/net/ConnectionCreator.cpp b/td/telegram/net/ConnectionCreator.cpp index 66010b278..f029b7b32 100644 --- a/td/telegram/net/ConnectionCreator.cpp +++ b/td/telegram/net/ConnectionCreator.cpp @@ -371,138 +371,6 @@ void ConnectionCreator::ping_proxy_buffered_socket_fd(IPAddress ip_address, Buff create_reference(token))}; } -void ConnectionCreator::test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise) { - auto start_time = Time::now(); - - IPAddress ip_address; - auto status = ip_address.init_host_port(proxy.server(), proxy.port()); - if (status.is_error()) { - return promise.set_error(400, status.public_message()); - } - auto r_socket_fd = SocketFd::open(ip_address); - if (r_socket_fd.is_error()) { - return promise.set_error(400, r_socket_fd.error().public_message()); - } - - auto dc_options = get_default_dc_options(false); - IPAddress mtproto_ip_address; - for (auto &dc_option : dc_options.dc_options) { - if (dc_option.get_dc_id().get_raw_id() == dc_id) { - mtproto_ip_address = dc_option.get_ip_address(); - break; - } - } - if (!mtproto_ip_address.is_valid()) { - return promise.set_error(400, "Invalid datacenter identifier specified"); - } - - auto request_id = ++test_proxy_request_id_; - auto request = make_unique<TestProxyRequest>(); - request->proxy_ = std::move(proxy); - request->dc_id_ = static_cast<int16>(dc_id); - request->promise_ = std::move(promise); - - auto connection_promise = - PromiseCreator::lambda([actor_id = actor_id(this), request_id](Result<ConnectionData> r_data) { - send_closure(actor_id, &ConnectionCreator::on_test_proxy_connection_data, request_id, std::move(r_data)); - }); - request->child_ = prepare_connection(ip_address, r_socket_fd.move_as_ok(), request->proxy_, mtproto_ip_address, - request->get_transport(), "Test", "TestPingDC2", nullptr, {}, false, - std::move(connection_promise)); - - test_proxy_requests_.emplace(request_id, std::move(request)); - - create_actor<SleepActor>("TestProxyTimeoutActor", timeout + start_time - Time::now(), - PromiseCreator::lambda([actor_id = actor_id(this), request_id](Unit) { - send_closure(actor_id, &ConnectionCreator::on_test_proxy_timeout, request_id); - })) - .release(); -} - -void ConnectionCreator::on_test_proxy_connection_data(uint64 request_id, Result<ConnectionData> r_data) { - auto it = test_proxy_requests_.find(request_id); - if (it == test_proxy_requests_.end()) { - return; - } - auto *request = it->second.get(); - if (r_data.is_error()) { - auto promise = std::move(request->promise_); - test_proxy_requests_.erase(it); - return promise.set_error(r_data.move_as_error()); - } - - class HandshakeContext final : public mtproto::AuthKeyHandshakeContext { - public: - mtproto::DhCallback *get_dh_callback() final { - return nullptr; - } - mtproto::PublicRsaKeyInterface *get_public_rsa_key_interface() final { - return public_rsa_key_.get(); - } - - private: - std::shared_ptr<mtproto::PublicRsaKeyInterface> public_rsa_key_ = PublicRsaKeySharedMain::create(false); - }; - auto handshake = make_unique<mtproto::AuthKeyHandshake>(request->dc_id_, 3600); - auto data = r_data.move_as_ok(); - auto raw_connection = mtproto::RawConnection::create(data.ip_address, std::move(data.buffered_socket_fd), - request->get_transport(), nullptr); - request->child_ = create_actor<mtproto::HandshakeActor>( - "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique<HandshakeContext>(), 10.0, - PromiseCreator::lambda( - [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::RawConnection>> raw_connection) { - send_closure(actor_id, &ConnectionCreator::on_test_proxy_handshake_connection, request_id, - std::move(raw_connection)); - }), - PromiseCreator::lambda( - [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::AuthKeyHandshake>> handshake) { - send_closure(actor_id, &ConnectionCreator::on_test_proxy_handshake, request_id, std::move(handshake)); - })); -} - -void ConnectionCreator::on_test_proxy_handshake_connection( - uint64 request_id, Result<unique_ptr<mtproto::RawConnection>> r_raw_connection) { - if (r_raw_connection.is_error()) { - auto it = test_proxy_requests_.find(request_id); - if (it == test_proxy_requests_.end()) { - return; - } - auto promise = std::move(it->second->promise_); - test_proxy_requests_.erase(it); - return promise.set_error(400, r_raw_connection.move_as_error().public_message()); - } -} - -void ConnectionCreator::on_test_proxy_handshake(uint64 request_id, - Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake) { - auto it = test_proxy_requests_.find(request_id); - if (it == test_proxy_requests_.end()) { - return; - } - auto promise = std::move(it->second->promise_); - test_proxy_requests_.erase(it); - - if (r_handshake.is_error()) { - return promise.set_error(400, r_handshake.move_as_error().public_message()); - } - auto handshake = r_handshake.move_as_ok(); - if (!handshake->is_ready_for_finish()) { - return promise.set_error(400, "Handshake is not ready"); - } - promise.set_value(Unit()); -} - -void ConnectionCreator::on_test_proxy_timeout(uint64 request_id) { - auto it = test_proxy_requests_.find(request_id); - if (it == test_proxy_requests_.end()) { - return; - } - auto promise = std::move(it->second->promise_); - test_proxy_requests_.erase(it); - - promise.set_error(400, "Timeout expired"); -} - void ConnectionCreator::set_active_proxy_id(int32 proxy_id, bool from_binlog) { active_proxy_id_ = proxy_id; if (proxy_id == 0) { diff --git a/td/telegram/net/ConnectionCreator.h b/td/telegram/net/ConnectionCreator.h index 222dc7841..f61af57c2 100644 --- a/td/telegram/net/ConnectionCreator.h +++ b/td/telegram/net/ConnectionCreator.h @@ -84,9 +84,9 @@ class ConnectionCreator final : public NetQueryCallback { void ping_proxy(td_api::object_ptr<td_api::proxy> input_proxy, Promise<double> promise); - void test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise); - private: + friend class ProxyChecker; + ActorShared<> parent_; DcOptionsSet dc_options_set_; bool network_flag_ = false; @@ -182,19 +182,6 @@ class ConnectionCreator final : public NetQueryCallback { unique_ptr<mtproto::RawConnection::StatsCallback> stats_callback; }; - struct TestProxyRequest { - Proxy proxy_; - int16 dc_id_ = -1; - ActorOwn<> child_; - Promise<Unit> promise_; - - mtproto::TransportType get_transport() const { - return mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, dc_id_, proxy_.secret()}; - } - }; - uint64 test_proxy_request_id_ = 0; - FlatHashMap<uint64, unique_ptr<TestProxyRequest>> test_proxy_requests_; - uint64 next_token() { return ++current_token_; } @@ -271,15 +258,6 @@ class ConnectionCreator final : public NetQueryCallback { mtproto::TransportType transport_type, string debug_str, Promise<double> promise); void on_ping_main_dc_result(uint64 token, Result<double> result); - - void on_test_proxy_connection_data(uint64 request_id, Result<ConnectionData> r_data); - - void on_test_proxy_handshake_connection(uint64 request_id, - Result<unique_ptr<mtproto::RawConnection>> r_raw_connection); - - void on_test_proxy_handshake(uint64 request_id, Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake); - - void on_test_proxy_timeout(uint64 request_id); }; } // namespace td diff --git a/td/telegram/net/ProxyChecker.cpp b/td/telegram/net/ProxyChecker.cpp new file mode 100644 index 000000000..1cf16a083 --- /dev/null +++ b/td/telegram/net/ProxyChecker.cpp @@ -0,0 +1,161 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/net/ProxyChecker.h" + +#include "td/telegram/net/PublicRsaKeySharedMain.h" + +#include "td/mtproto/DhCallback.h" +#include "td/mtproto/HandshakeActor.h" +#include "td/mtproto/RSA.h" +#include "td/mtproto/TlsInit.h" + +#include "td/actor/SleepActor.h" + +#include "td/utils/port/IPAddress.h" +#include "td/utils/port/SocketFd.h" +#include "td/utils/Time.h" + +#include <memory> + +namespace td { + +ProxyChecker::ProxyChecker(ActorShared<> parent) : parent_(std::move(parent)) { +} + +void ProxyChecker::test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise) { + auto start_time = Time::now(); + + IPAddress ip_address; + auto status = ip_address.init_host_port(proxy.server(), proxy.port()); + if (status.is_error()) { + return promise.set_error(400, status.public_message()); + } + auto r_socket_fd = SocketFd::open(ip_address); + if (r_socket_fd.is_error()) { + return promise.set_error(400, r_socket_fd.error().public_message()); + } + + auto dc_options = ConnectionCreator::get_default_dc_options(false); + IPAddress mtproto_ip_address; + for (auto &dc_option : dc_options.dc_options) { + if (dc_option.get_dc_id().get_raw_id() == dc_id) { + mtproto_ip_address = dc_option.get_ip_address(); + break; + } + } + if (!mtproto_ip_address.is_valid()) { + return promise.set_error(400, "Invalid datacenter identifier specified"); + } + + auto request_id = ++test_proxy_request_id_; + auto request = make_unique<TestProxyRequest>(); + request->proxy_ = std::move(proxy); + request->dc_id_ = static_cast<int16>(dc_id); + request->promise_ = std::move(promise); + + auto connection_promise = + PromiseCreator::lambda([actor_id = actor_id(this), request_id](Result<ConnectionCreator::ConnectionData> r_data) { + send_closure(actor_id, &ProxyChecker::on_test_proxy_connection_data, request_id, std::move(r_data)); + }); + request->child_ = ConnectionCreator::prepare_connection( + ip_address, r_socket_fd.move_as_ok(), request->proxy_, mtproto_ip_address, request->get_transport(), "Test", + "TestPingDC2", nullptr, {}, false, std::move(connection_promise)); + + test_proxy_requests_.emplace(request_id, std::move(request)); + + create_actor<SleepActor>("TestProxyTimeoutActor", timeout + start_time - Time::now(), + PromiseCreator::lambda([actor_id = actor_id(this), request_id](Unit) { + send_closure(actor_id, &ProxyChecker::on_test_proxy_timeout, request_id); + })) + .release(); +} + +void ProxyChecker::on_test_proxy_connection_data(uint64 request_id, Result<ConnectionCreator::ConnectionData> r_data) { + auto it = test_proxy_requests_.find(request_id); + if (it == test_proxy_requests_.end()) { + return; + } + auto *request = it->second.get(); + if (r_data.is_error()) { + auto promise = std::move(request->promise_); + test_proxy_requests_.erase(it); + return promise.set_error(r_data.move_as_error()); + } + + class HandshakeContext final : public mtproto::AuthKeyHandshakeContext { + public: + mtproto::DhCallback *get_dh_callback() final { + return nullptr; + } + mtproto::PublicRsaKeyInterface *get_public_rsa_key_interface() final { + return public_rsa_key_.get(); + } + + private: + std::shared_ptr<mtproto::PublicRsaKeyInterface> public_rsa_key_ = PublicRsaKeySharedMain::create(false); + }; + auto handshake = make_unique<mtproto::AuthKeyHandshake>(request->dc_id_, 3600); + auto data = r_data.move_as_ok(); + auto raw_connection = mtproto::RawConnection::create(data.ip_address, std::move(data.buffered_socket_fd), + request->get_transport(), nullptr); + request->child_ = create_actor<mtproto::HandshakeActor>( + "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique<HandshakeContext>(), 10.0, + PromiseCreator::lambda( + [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::RawConnection>> raw_connection) { + send_closure(actor_id, &ProxyChecker::on_test_proxy_handshake_connection, request_id, + std::move(raw_connection)); + }), + PromiseCreator::lambda( + [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::AuthKeyHandshake>> handshake) { + send_closure(actor_id, &ProxyChecker::on_test_proxy_handshake, request_id, std::move(handshake)); + })); +} + +void ProxyChecker::on_test_proxy_handshake_connection(uint64 request_id, + Result<unique_ptr<mtproto::RawConnection>> r_raw_connection) { + if (r_raw_connection.is_error()) { + auto it = test_proxy_requests_.find(request_id); + if (it == test_proxy_requests_.end()) { + return; + } + auto promise = std::move(it->second->promise_); + test_proxy_requests_.erase(it); + return promise.set_error(400, r_raw_connection.move_as_error().public_message()); + } +} + +void ProxyChecker::on_test_proxy_handshake(uint64 request_id, + Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake) { + auto it = test_proxy_requests_.find(request_id); + if (it == test_proxy_requests_.end()) { + return; + } + auto promise = std::move(it->second->promise_); + test_proxy_requests_.erase(it); + + if (r_handshake.is_error()) { + return promise.set_error(400, r_handshake.move_as_error().public_message()); + } + auto handshake = r_handshake.move_as_ok(); + if (!handshake->is_ready_for_finish()) { + return promise.set_error(400, "Handshake is not ready"); + } + promise.set_value(Unit()); +} + +void ProxyChecker::on_test_proxy_timeout(uint64 request_id) { + auto it = test_proxy_requests_.find(request_id); + if (it == test_proxy_requests_.end()) { + return; + } + auto promise = std::move(it->second->promise_); + test_proxy_requests_.erase(it); + + promise.set_error(400, "Timeout expired"); +} + +} // namespace td diff --git a/td/telegram/net/ProxyChecker.h b/td/telegram/net/ProxyChecker.h new file mode 100644 index 000000000..cca8189af --- /dev/null +++ b/td/telegram/net/ProxyChecker.h @@ -0,0 +1,63 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/net/ConnectionCreator.h" +#include "td/telegram/net/NetQuery.h" +#include "td/telegram/net/Proxy.h" + +#include "td/mtproto/Handshake.h" +#include "td/mtproto/RawConnection.h" +#include "td/mtproto/TransportType.h" + +#include "td/actor/actor.h" + +#include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/Promise.h" +#include "td/utils/Status.h" + +namespace td { + +class ProxyChecker final : public NetQueryCallback { + public: + explicit ProxyChecker(ActorShared<> parent); + ProxyChecker(const ProxyChecker &) = delete; + ProxyChecker &operator=(const ProxyChecker &) = delete; + ProxyChecker(ProxyChecker &&other) = delete; + ProxyChecker &operator=(ProxyChecker &&other) = delete; + ~ProxyChecker() final = default; + + void test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise); + + private: + ActorShared<> parent_; + + struct TestProxyRequest { + Proxy proxy_; + int16 dc_id_ = -1; + ActorOwn<> child_; + Promise<Unit> promise_; + + mtproto::TransportType get_transport() const { + return mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, dc_id_, proxy_.secret()}; + } + }; + uint64 test_proxy_request_id_ = 0; + FlatHashMap<uint64, unique_ptr<TestProxyRequest>> test_proxy_requests_; + + void on_test_proxy_connection_data(uint64 request_id, Result<ConnectionCreator::ConnectionData> r_data); + + void on_test_proxy_handshake_connection(uint64 request_id, + Result<unique_ptr<mtproto::RawConnection>> r_raw_connection); + + void on_test_proxy_handshake(uint64 request_id, Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake); + + void on_test_proxy_timeout(uint64 request_id); +}; + +} // namespace td |
