New ConfigRecoverer scheme.

GitOrigin-RevId: 1101ddc56b0836387faf089ca52fe7376db9f88f
This commit is contained in:
levlam 2018-05-24 18:09:27 +03:00
parent ede1d58e0f
commit 0e48dd8a81
9 changed files with 105 additions and 83 deletions

View File

@ -14,8 +14,10 @@ vector#1cb5c415 {t:Type} # [ t ] = Vector t;
error#c4b9f9bb code:int text:string = Error; error#c4b9f9bb code:int text:string = Error;
ipPort ipv4:int port:int = IpPort; ipPort#d433ad73 ipv4:int port:int = IpPort;
help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;
---functions--- ---functions---
@ -1093,7 +1095,7 @@ help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getInviteText#4d392343 = help.InviteText; help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support; help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
help.getTermsOfService#350170f3 = help.TermsOfService; help.getTermsOfService#fa796a44 country_iso2:string lang_code:string = help.TermsOfService;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig; help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;

Binary file not shown.

View File

@ -124,15 +124,11 @@ static ActorOwn<> get_simple_config_impl(Promise<SimpleConfig> promise, int32 sc
} }
ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id) { ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id) {
string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod") << "/config.txt"; string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod")
<< "v2/config.txt";
return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "tcdnb.azureedge.net"); return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "tcdnb.azureedge.net");
} }
ActorOwn<> get_simple_config_google_app(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id) {
string url = PSTRING() << "https://www.google.com/" << (is_test ? "test/" : "");
return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "dns-telegram.appspot.com");
}
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id) { ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id) {
VLOG(config_recoverer) << "Request simple config from Google DNS"; VLOG(config_recoverer) << "Request simple config from Google DNS";
#if TD_EMSCRIPTEN // FIXME #if TD_EMSCRIPTEN // FIXME
@ -171,7 +167,7 @@ ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, bool is_t
return decode_config(data); return decode_config(data);
}()); }());
}), }),
PSTRING() << "https://google.com/resolve?name=" << (is_test ? "t" : "") << "ap.stel.com&type=16", PSTRING() << "https://www.google.com/resolve?name=" << (is_test ? "t" : "") << "apv2.stel.com&type=16",
std::vector<std::pair<string, string>>({{"Host", "dns.google.com"}}), 10 /*timeout*/, 3 /*ttl*/, std::vector<std::pair<string, string>>({{"Host", "dns.google.com"}}), 10 /*timeout*/, 3 /*ttl*/,
SslFd::VerifyPeer::Off)); SslFd::VerifyPeer::Off));
#endif #endif
@ -370,25 +366,54 @@ class ConfigRecoverer : public Actor {
loop(); loop();
} }
static bool check_phone_number_rules(Slice phone_number, Slice rules) {
bool found = false;
for (auto prefix : full_split(rules, ',')) {
if (prefix.empty()) {
found = true;
} else if (prefix[0] == '+' && begins_with(phone_number, prefix.substr(1))) {
found = true;
} else if (prefix[0] == '-' && begins_with(phone_number, prefix.substr(1))) {
return false;
} else {
LOG(ERROR) << "Invalid prefix rule " << prefix;
}
}
return found;
}
void on_simple_config(Result<SimpleConfig> r_simple_config, bool dummy) { void on_simple_config(Result<SimpleConfig> r_simple_config, bool dummy) {
simple_config_query_.reset(); simple_config_query_.reset();
auto r_dc_options = [&]() -> Result<DcOptions> {
if (r_simple_config.is_error()) {
return r_simple_config.move_as_error();
}
return DcOptions(*r_simple_config.ok());
}();
dc_options_i_ = 0; dc_options_i_ = 0;
if (r_dc_options.is_ok()) { if (r_simple_config.is_ok()) {
simple_config_ = r_dc_options.move_as_ok(); auto config = r_simple_config.move_as_ok();
VLOG(config_recoverer) << "Got SimpleConfig " << simple_config_; LOG(ERROR) << to_string(config);
if (config->expires_ >= G()->unix_time()) {
string phone_number = G()->shared_config().get_option_string("my_phone_number");
simple_config_.dc_options.clear();
for (auto &rule : config->rules_) {
if (check_phone_number_rules(phone_number, rule->phone_prefix_rules_) && DcId::is_valid(rule->dc_id_)) {
DcId dc_id = DcId::internal(rule->dc_id_);
for (auto &ip_port : rule->ips_) {
DcOption option(dc_id, *ip_port);
if (option.is_valid()) {
simple_config_.dc_options.push_back(std::move(option));
}
}
}
}
VLOG(config_recoverer) << "Got SimpleConfig " << simple_config_;
LOG(ERROR) << "Got SimpleConfig " << simple_config_;
}
simple_config_expire_at_ = get_config_expire_time(); simple_config_expire_at_ = get_config_expire_time();
simple_config_at_ = Time::now_cached(); simple_config_at_ = Time::now_cached();
for (size_t i = 1; i < simple_config_.dc_options.size(); i++) { for (size_t i = 1; i < simple_config_.dc_options.size(); i++) {
std::swap(simple_config_.dc_options[i], simple_config_.dc_options[Random::fast(0, static_cast<int>(i))]); std::swap(simple_config_.dc_options[i], simple_config_.dc_options[Random::fast(0, static_cast<int>(i))]);
} }
} else { } else {
VLOG(config_recoverer) << "Get SimpleConfig error " << r_dc_options.error(); VLOG(config_recoverer) << "Get SimpleConfig error " << r_simple_config.error();
simple_config_ = DcOptions(); simple_config_ = DcOptions();
simple_config_expire_at_ = get_failed_config_expire_time(); simple_config_expire_at_ = get_failed_config_expire_time();
} }
@ -515,10 +540,9 @@ class ConfigRecoverer : public Actor {
}); });
auto get_simple_config = [&]() { auto get_simple_config = [&]() {
switch (simple_config_turn_ % 3) { switch (simple_config_turn_ % 3) {
case 0:
return get_simple_config_azure;
case 1: case 1:
return get_simple_config_google_app; return get_simple_config_azure;
case 0:
case 2: case 2:
default: default:
return get_simple_config_google_dns; return get_simple_config_google_dns;

View File

@ -24,11 +24,9 @@ using SimpleConfig = tl_object_ptr<telegram_api::help_configSimple>;
Result<SimpleConfig> decode_config(Slice input); Result<SimpleConfig> decode_config(Slice input);
ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, bool is_test = false, int32 scheduler_id = -1); ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_google_app(Promise<SimpleConfig> promise, bool is_test = false, int32 scheduler_id = -1); ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, bool is_test, int32 scheduler_id);
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, bool is_test = false, int32 scheduler_id = -1);
using FullConfig = tl_object_ptr<telegram_api::config>; using FullConfig = tl_object_ptr<telegram_api::config>;

View File

@ -4933,6 +4933,9 @@ void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr,
if (flags & USER_FLAG_IS_ME) { if (flags & USER_FLAG_IS_ME) {
set_my_id(user_id); set_my_id(user_id);
td_->auth_manager_->set_is_bot(is_bot); td_->auth_manager_->set_is_bot(is_bot);
if (!is_bot) {
G()->shared_config().set_option_string("my_phone_number", user->phone_);
}
} else { } else {
/* /*
if (!(flags & USER_FLAG_HAS_ACCESS_HASH) && !(flags & USER_FLAG_IS_DELETED) && if (!(flags & USER_FLAG_HAS_ACCESS_HASH) && !(flags & USER_FLAG_IS_DELETED) &&

View File

@ -4204,7 +4204,7 @@ bool Td::is_internal_config_option(Slice name) {
return name == "call_ring_timeout_ms" || name == "call_receive_timeout_ms" || name == "channels_read_media_period" || return name == "call_ring_timeout_ms" || name == "call_receive_timeout_ms" || name == "channels_read_media_period" ||
name == "edit_time_limit" || name == "revoke_pm_inbox" || name == "revoke_time_limit" || name == "edit_time_limit" || name == "revoke_pm_inbox" || name == "revoke_time_limit" ||
name == "revoke_pm_time_limit" || name == "rating_e_decay" || name == "saved_animations_limit" || name == "revoke_pm_time_limit" || name == "rating_e_decay" || name == "saved_animations_limit" ||
name == "recent_stickers_limit" || name == "expect_blocking" || name == "auth"; name == "recent_stickers_limit" || name == "expect_blocking" || name == "my_phone_number" || name == "auth";
} }
void Td::on_config_option_updated(const string &name) { void Td::on_config_option_updated(const string &name) {

View File

@ -671,6 +671,7 @@ void ConnectionCreator::request_raw_connection_by_ip(IPAddress ip_address,
Result<SocketFd> ConnectionCreator::find_connection(const ConnectionCreator::ProxyInfo &proxy, DcId dc_id, Result<SocketFd> ConnectionCreator::find_connection(const ConnectionCreator::ProxyInfo &proxy, DcId dc_id,
bool allow_media_only, FindConnectionExtra &extra) { bool allow_media_only, FindConnectionExtra &extra) {
extra.debug_str = PSTRING() << "Failed to find valid IP for " << dc_id;
TRY_RESULT(info, dc_options_set_.find_connection(dc_id, allow_media_only, proxy.use_proxy())); TRY_RESULT(info, dc_options_set_.find_connection(dc_id, allow_media_only, proxy.use_proxy()));
extra.stat = info.stat; extra.stat = info.stat;
int32 int_dc_id = dc_id.get_raw_id(); int32 int_dc_id = dc_id.get_raw_id();
@ -680,10 +681,11 @@ Result<SocketFd> ConnectionCreator::find_connection(const ConnectionCreator::Pro
int16 raw_dc_id = narrow_cast<int16>(info.option->is_media_only() ? -int_dc_id : int_dc_id); int16 raw_dc_id = narrow_cast<int16>(info.option->is_media_only() ? -int_dc_id : int_dc_id);
if (proxy.use_mtproto_proxy()) { if (proxy.use_mtproto_proxy()) {
extra.debug_str = PSTRING() << "Mtproto " << proxy.ip_address() << " to DC" << raw_dc_id;
TRY_RESULT(secret, hex_decode(proxy.proxy().secret())); TRY_RESULT(secret, hex_decode(proxy.proxy().secret()));
extra.transport_type = {mtproto::TransportType::ObfuscatedTcp, raw_dc_id, std::move(secret)}; extra.transport_type = {mtproto::TransportType::ObfuscatedTcp, raw_dc_id, std::move(secret)};
extra.debug_str = PSTRING() << "Mtproto " << proxy.ip_address() << " to DC" << raw_dc_id;
LOG(INFO) << "Create: " << extra.debug_str; LOG(INFO) << "Create: " << extra.debug_str;
return SocketFd::open(proxy.ip_address()); return SocketFd::open(proxy.ip_address());
} }
@ -787,7 +789,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
auto r_socket_fd = find_connection(proxy, client.dc_id, client.allow_media_only, extra); auto r_socket_fd = find_connection(proxy, client.dc_id, client.allow_media_only, extra);
check_mode |= extra.check_mode; check_mode |= extra.check_mode;
if (r_socket_fd.is_error()) { if (r_socket_fd.is_error()) {
LOG(WARNING) << r_socket_fd.error(); LOG(WARNING) << extra.debug_str << ": " << r_socket_fd.error();
if (extra.stat) { if (extra.stat) {
extra.stat->on_error(); // TODO: different kind of error extra.stat->on_error(); // TODO: different kind of error
} }

View File

@ -81,9 +81,28 @@ class DcOption {
init_ip_address(ip, port); init_ip_address(ip, port);
} }
DcOption(DcId new_dc_id, const telegram_api::ipPort &ip_port) { DcOption(DcId new_dc_id, const telegram_api::IpPort &ip_port_ref) {
switch (ip_port_ref.get_id()) {
case telegram_api::ipPort::ID: {
auto &ip_port = static_cast<const telegram_api::ipPort &>(ip_port_ref);
init_ip_address(IPAddress::ipv4_to_str(ip_port.ipv4_), ip_port.port_);
break;
}
case telegram_api::ipPortSecret::ID: {
auto &ip_port = static_cast<const telegram_api::ipPortSecret &>(ip_port_ref);
if (ip_port.secret_.size() != 16u) {
return;
}
flags_ |= Flags::HasSecret;
secret_ = ip_port.secret_.as_slice().str();
init_ip_address(IPAddress::ipv4_to_str(ip_port.ipv4_), ip_port.port_);
break;
}
default:
UNREACHABLE();
}
flags_ |= Flags::ObfuscatedTcpOnly;
dc_id_ = new_dc_id; dc_id_ = new_dc_id;
init_ip_address(IPAddress::ipv4_to_str(ip_port.ipv4_), ip_port.port_);
} }
DcId get_dc_id() const { DcId get_dc_id() const {
@ -204,15 +223,7 @@ class DcOptions {
} }
} }
} }
explicit DcOptions(const telegram_api::help_configSimple &config_simple) {
auto dc_id = DcId::is_valid(config_simple.dc_id_) ? DcId::internal(config_simple.dc_id_) : DcId();
for (auto &ip_port : config_simple.ip_port_list_) {
DcOption option(dc_id, *ip_port);
if (option.is_valid()) {
dc_options.push_back(std::move(option));
}
}
}
template <class StorerT> template <class StorerT>
void store(StorerT &storer) const { void store(StorerT &storer) const {
::td::store(dc_options, storer); ::td::store(dc_options, storer);

View File

@ -31,67 +31,49 @@ REGISTER_TESTS(mtproto);
using namespace td; using namespace td;
using namespace mtproto; using namespace mtproto;
#if !TD_WINDOWS && !TD_EMSCRIPTEN // TODO
TEST(Mtproto, config) { TEST(Mtproto, config) {
ConcurrentScheduler sched; ConcurrentScheduler sched;
int threads_n = 0; int threads_n = 0;
sched.init(threads_n); sched.init(threads_n);
int cnt = 3; int cnt = 1;
{ {
auto guard = sched.get_current_guard(); auto guard = sched.get_current_guard();
get_simple_config_azure(PromiseCreator::lambda([&](Result<SimpleConfig> r_simple_config) {
if (r_simple_config.is_ok()) {
LOG(ERROR) << to_string(r_simple_config.ok());
} else {
LOG(ERROR) << r_simple_config.error();
}
if (--cnt == 0) {
Scheduler::instance()->finish();
}
}))
.release();
get_simple_config_google_app(PromiseCreator::lambda([&](Result<SimpleConfig> r_simple_config) { auto run = [&](auto &func, bool is_test) {
if (r_simple_config.is_ok()) { cnt++;
LOG(ERROR) << to_string(r_simple_config.ok()); auto promise = PromiseCreator::lambda([&](Result<SimpleConfig> r_simple_config) {
} else { if (r_simple_config.is_ok()) {
LOG(ERROR) << r_simple_config.error(); LOG(ERROR) << to_string(r_simple_config.ok());
} } else {
if (--cnt == 0) { LOG(ERROR) << r_simple_config.error();
Scheduler::instance()->finish(); }
} if (--cnt == 0) {
})) Scheduler::instance()->finish();
.release(); }
});
func(std::move(promise), is_test, -1).release();
};
get_simple_config_google_dns(PromiseCreator::lambda([&](Result<SimpleConfig> r_simple_config) { run(get_simple_config_azure, false);
if (r_simple_config.is_ok()) { run(get_simple_config_google_dns, false);
LOG(ERROR) << to_string(r_simple_config.ok()); run(get_simple_config_azure, true);
} else { run(get_simple_config_google_dns, true);
LOG(ERROR) << r_simple_config.error();
}
if (--cnt == 0) {
Scheduler::instance()->finish();
}
}))
.release();
} }
cnt--;
sched.start(); sched.start();
while (sched.run_main(10)) { while (sched.run_main(10)) {
// empty; // empty;
} }
sched.finish(); sched.finish();
} }
#endif
TEST(Mtproto, encrypted_config) { TEST(Mtproto, encrypted_config) {
string data = string data =
" LQ2 \b\n\tru6xVXpHHckW4eQWK0X3uThupVOor5sXT8t298IjDksYeUseQTOIrnUqiQj7o" " hO//tt \b\n\tiwPVovorKtIYtQ8y2ik7CqfJiJ4pJOCLRa4fBmNPixuRPXnBFF/3mTAAZoSyHq4SNylGHz0Cv1/"
"+ZgPfhnfe+lfcQA+naax9akgllimjlJtL5riTf3O7iqZSnJ614qmCucxqqVTbXk/" "FnWWdEV+BPJeOTk+ARHcNkuJBt0CqnfcVCoDOpKqGyq0U31s2MOpQvHgAG+Tlpg02syuH0E4dCGRw5CbJPARiynteb9y5fT5x/"
"hY2KaJTtsMqk7cShJjM3aQ4DD40h2InTaG7uyVO2q7K0GMUTeY3AM0Rt1lUjKHLD" "kmdp6BMR5tWQSQF0liH16zLh8BDSIdiMsikdcwnAvBwdNhRqQBqGx9MTh62MDmlebjtczE9Gz0z5cscUO2yhzGdphgIy6SP+"
"g4RwjTzZaG8TwfgL/mZ7jsvgTTTATPWKUo7SmxQ9Hsj+07NMGqr6JKZS6aiU1Knz" "bwaqLWYF0XdPGjKLMUEJW+rou6fbL1t/EUXPtU0XmQAnO0Fh86h+AqDMOe30N4qKrPQ== ";
"VGCZ3OJEyRYocktN4HjaLpkguilaHWlVM2UNFUd5a+ajfLIiiKlH0FRC3XZ12CND"
"Y+NBjv0I57N2O4fBfswTlA== ";
auto config = decode_config(data).move_as_ok(); auto config = decode_config(data).move_as_ok();
} }