ConfigRecoverer: support tls obfuscation
GitOrigin-RevId: 9a924ee86fe042a9fd1acf44eeeb25c0ab4e8bbb
This commit is contained in:
parent
64517c9165
commit
8fdd8910e7
@ -53,9 +53,85 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
int VERBOSITY_NAME(config_recoverer) = VERBOSITY_NAME(INFO);
|
int VERBOSITY_NAME(config_recoverer) = VERBOSITY_NAME(INFO);
|
||||||
|
Result<int64> HttpDate::to_unix_time(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second) {
|
||||||
|
int64 res = 0;
|
||||||
|
if (year < 1970 || year > 2037) {
|
||||||
|
return td::Status::Error("invalid year");
|
||||||
|
}
|
||||||
|
if (month < 1 || month > 12) {
|
||||||
|
return td::Status::Error("invalid month");
|
||||||
|
}
|
||||||
|
if (day < 1 || day > days_in_month(year, month)) {
|
||||||
|
return td::Status::Error("invalid day");
|
||||||
|
}
|
||||||
|
if (hour < 0 || hour > 24) { // is hour == 24 possible?
|
||||||
|
return td::Status::Error("invalid hour");
|
||||||
|
}
|
||||||
|
if (minute < 0 || minute > 60) {
|
||||||
|
return td::Status::Error("invalid minute");
|
||||||
|
}
|
||||||
|
if (second < 0 || second > 60) {
|
||||||
|
return td::Status::Error("invalid second");
|
||||||
|
}
|
||||||
|
for (int y = 1970; y < year; y++) {
|
||||||
|
res += (is_leap(y) + 365) * seconds_in_day();
|
||||||
|
}
|
||||||
|
for (int m = 1; m < month; m++) {
|
||||||
|
res += days_in_month(year, m) * seconds_in_day();
|
||||||
|
}
|
||||||
|
res += (day - 1) * seconds_in_day();
|
||||||
|
res += hour * 60 * 60;
|
||||||
|
res += minute * 60;
|
||||||
|
res += second;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<int64> HttpDate::parse_http_date(std::string slice) {
|
||||||
|
td::Parser p(slice);
|
||||||
|
p.read_till(','); // ignore week day
|
||||||
|
p.skip(',');
|
||||||
|
p.skip_whitespaces();
|
||||||
|
TRY_RESULT(day, to_integer_safe<int32>(p.read_word()));
|
||||||
|
auto month_name = p.read_word();
|
||||||
|
to_lower_inplace(month_name);
|
||||||
|
TRY_RESULT(year, to_integer_safe<int32>(p.read_word()));
|
||||||
|
p.skip_whitespaces();
|
||||||
|
p.skip_nofail('0');
|
||||||
|
TRY_RESULT(hour, to_integer_safe<int32>(p.read_till(':')));
|
||||||
|
p.skip(':');
|
||||||
|
p.skip_nofail('0');
|
||||||
|
TRY_RESULT(minute, to_integer_safe<int32>(p.read_till(':')));
|
||||||
|
p.skip(':');
|
||||||
|
p.skip_nofail('0');
|
||||||
|
TRY_RESULT(second, to_integer_safe<int32>(p.read_word()));
|
||||||
|
auto gmt = p.read_word();
|
||||||
|
TRY_STATUS(std::move(p.status()));
|
||||||
|
if (gmt != "GMT") {
|
||||||
|
return Status::Error("timezone must be GMT");
|
||||||
|
}
|
||||||
|
|
||||||
|
Slice month_names[12] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
|
||||||
|
|
||||||
|
int month = 0;
|
||||||
|
|
||||||
|
for (int m = 1; m <= 12; m++) {
|
||||||
|
if (month_names[m - 1] == month_name) {
|
||||||
|
month = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (month == 0) {
|
||||||
|
return Status::Error("Unknown month name");
|
||||||
|
}
|
||||||
|
|
||||||
|
return HttpDate::to_unix_time(year, month, day, hour, minute, second);
|
||||||
|
}
|
||||||
|
|
||||||
Result<SimpleConfig> decode_config(Slice input) {
|
Result<SimpleConfig> decode_config(Slice input) {
|
||||||
static auto rsa = td::RSA::from_pem(
|
static auto rsa = td::RSA::from_pem(
|
||||||
@ -117,8 +193,8 @@ Result<SimpleConfig> decode_config(Slice input) {
|
|||||||
return std::move(config);
|
return std::move(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ActorOwn<> get_simple_config_impl(Promise<SimpleConfig> promise, int32 scheduler_id, string url, string host,
|
static ActorOwn<> get_simple_config_impl(Promise<SimpleConfigResult> promise, int32 scheduler_id, string url,
|
||||||
bool prefer_ipv6) {
|
string host, bool prefer_ipv6) {
|
||||||
VLOG(config_recoverer) << "Request simple config from " << url;
|
VLOG(config_recoverer) << "Request simple config from " << url;
|
||||||
#if TD_EMSCRIPTEN // FIXME
|
#if TD_EMSCRIPTEN // FIXME
|
||||||
return ActorOwn<>();
|
return ActorOwn<>();
|
||||||
@ -128,9 +204,12 @@ static ActorOwn<> get_simple_config_impl(Promise<SimpleConfig> promise, int32 sc
|
|||||||
return ActorOwn<>(create_actor_on_scheduler<Wget>(
|
return ActorOwn<>(create_actor_on_scheduler<Wget>(
|
||||||
"Wget", scheduler_id,
|
"Wget", scheduler_id,
|
||||||
PromiseCreator::lambda([promise = std::move(promise)](Result<unique_ptr<HttpQuery>> r_query) mutable {
|
PromiseCreator::lambda([promise = std::move(promise)](Result<unique_ptr<HttpQuery>> r_query) mutable {
|
||||||
promise.set_result([&]() -> Result<SimpleConfig> {
|
promise.set_result([&]() -> Result<SimpleConfigResult> {
|
||||||
TRY_RESULT(http_query, std::move(r_query));
|
TRY_RESULT(http_query, std::move(r_query));
|
||||||
return decode_config(http_query->content_);
|
SimpleConfigResult res;
|
||||||
|
res.r_http_date = HttpDate::parse_http_date(http_query->get_arg("date").str());
|
||||||
|
res.r_config = decode_config(http_query->content_);
|
||||||
|
return res;
|
||||||
}());
|
}());
|
||||||
}),
|
}),
|
||||||
std::move(url), std::vector<std::pair<string, string>>({{"Host", std::move(host)}}), timeout, ttl, prefer_ipv6,
|
std::move(url), std::vector<std::pair<string, string>>({{"Host", std::move(host)}}), timeout, ttl, prefer_ipv6,
|
||||||
@ -138,7 +217,7 @@ static ActorOwn<> get_simple_config_impl(Promise<SimpleConfig> promise, int32 sc
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, const ConfigShared *shared_config, bool is_test,
|
ActorOwn<> get_simple_config_azure(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, bool is_test,
|
||||||
int32 scheduler_id) {
|
int32 scheduler_id) {
|
||||||
string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod")
|
string url = PSTRING() << "https://software-download.microsoft.com/" << (is_test ? "test" : "prod")
|
||||||
<< "v2/config.txt";
|
<< "v2/config.txt";
|
||||||
@ -146,8 +225,8 @@ ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, const ConfigSh
|
|||||||
return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "tcdnb.azureedge.net", prefer_ipv6);
|
return get_simple_config_impl(std::move(promise), scheduler_id, std::move(url), "tcdnb.azureedge.net", prefer_ipv6);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, const ConfigShared *shared_config, bool is_test,
|
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config,
|
||||||
int32 scheduler_id) {
|
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
|
||||||
return ActorOwn<>();
|
return ActorOwn<>();
|
||||||
@ -156,14 +235,19 @@ ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, const Con
|
|||||||
const int timeout = 10;
|
const int timeout = 10;
|
||||||
const int ttl = 3;
|
const int ttl = 3;
|
||||||
const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6");
|
const bool prefer_ipv6 = shared_config == nullptr ? false : shared_config->get_option_boolean("prefer_ipv6");
|
||||||
if (name.empty()) {
|
if (name.empty() || true) {
|
||||||
name = is_test ? "tapv2.stel.com" : "apv2.stel.com";
|
name = is_test ? "tapv3.stel.com" : "apv3.stel.com";
|
||||||
}
|
}
|
||||||
return ActorOwn<>(create_actor_on_scheduler<Wget>(
|
return ActorOwn<>(create_actor_on_scheduler<Wget>(
|
||||||
"Wget", scheduler_id,
|
"Wget", scheduler_id,
|
||||||
PromiseCreator::lambda([promise = std::move(promise)](Result<unique_ptr<HttpQuery>> r_query) mutable {
|
PromiseCreator::lambda([promise = std::move(promise)](Result<unique_ptr<HttpQuery>> r_query) mutable {
|
||||||
promise.set_result([&]() -> Result<SimpleConfig> {
|
promise.set_result([&]() -> Result<SimpleConfigResult> {
|
||||||
TRY_RESULT(http_query, std::move(r_query));
|
TRY_RESULT(http_query, std::move(r_query));
|
||||||
|
LOG(ERROR) << *http_query;
|
||||||
|
|
||||||
|
SimpleConfigResult res;
|
||||||
|
res.r_http_date = HttpDate::parse_http_date(http_query->get_arg("date").str());
|
||||||
|
res.r_config = [&]() -> Result<SimpleConfig> {
|
||||||
TRY_RESULT(json, json_decode(http_query->content_));
|
TRY_RESULT(json, json_decode(http_query->content_));
|
||||||
if (json.type() != JsonValue::Type::Object) {
|
if (json.type() != JsonValue::Type::Object) {
|
||||||
return Status::Error("json error");
|
return Status::Error("json error");
|
||||||
@ -190,6 +274,8 @@ ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, const Con
|
|||||||
data = parts[0] + parts[1];
|
data = parts[0] + parts[1];
|
||||||
}
|
}
|
||||||
return decode_config(data);
|
return decode_config(data);
|
||||||
|
}();
|
||||||
|
return res;
|
||||||
}());
|
}());
|
||||||
}),
|
}),
|
||||||
PSTRING() << "https://www.google.com/resolve?name=" << url_encode(name) << "&type=16",
|
PSTRING() << "https://www.google.com/resolve?name=" << url_encode(name) << "&type=16",
|
||||||
@ -198,11 +284,10 @@ ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, const Con
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorOwn<> get_full_config(DcId dc_id, IPAddress ip_address, mtproto::ProxySecret secret, Promise<FullConfig> promise) {
|
ActorOwn<> get_full_config(DcOption option, Promise<FullConfig> promise) {
|
||||||
class SessionCallback : public Session::Callback {
|
class SessionCallback : public Session::Callback {
|
||||||
public:
|
public:
|
||||||
SessionCallback(ActorShared<> parent, IPAddress address, mtproto::ProxySecret secret)
|
SessionCallback(ActorShared<> parent, DcOption option) : parent_(std::move(parent)), option_(std::move(option)) {
|
||||||
: parent_(std::move(parent)), address_(std::move(address)), secret_(std::move(secret)) {
|
|
||||||
}
|
}
|
||||||
void on_failed() final {
|
void on_failed() final {
|
||||||
}
|
}
|
||||||
@ -211,10 +296,14 @@ ActorOwn<> get_full_config(DcId dc_id, IPAddress ip_address, mtproto::ProxySecre
|
|||||||
void request_raw_connection(unique_ptr<mtproto::AuthData> auth_data,
|
void request_raw_connection(unique_ptr<mtproto::AuthData> auth_data,
|
||||||
Promise<unique_ptr<mtproto::RawConnection>> promise) final {
|
Promise<unique_ptr<mtproto::RawConnection>> promise) final {
|
||||||
request_raw_connection_cnt_++;
|
request_raw_connection_cnt_++;
|
||||||
VLOG(config_recoverer) << "Request full config from " << address_ << ", try = " << request_raw_connection_cnt_;
|
VLOG(config_recoverer) << "Request full config from " << option_.get_ip_address()
|
||||||
|
<< ", try = " << request_raw_connection_cnt_;
|
||||||
if (request_raw_connection_cnt_ <= 2) {
|
if (request_raw_connection_cnt_ <= 2) {
|
||||||
send_closure(G()->connection_creator(), &ConnectionCreator::request_raw_connection_by_ip, address_,
|
send_closure(G()->connection_creator(), &ConnectionCreator::request_raw_connection_by_ip,
|
||||||
mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, 0, secret_}, std::move(promise));
|
option_.get_ip_address(),
|
||||||
|
mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp,
|
||||||
|
narrow_cast<int16>(option_.get_dc_id().get_raw_id()), option_.get_secret()},
|
||||||
|
std::move(promise));
|
||||||
} else {
|
} else {
|
||||||
// Delay all queries except first forever
|
// Delay all queries except first forever
|
||||||
delay_forever_.push_back(std::move(promise));
|
delay_forever_.push_back(std::move(promise));
|
||||||
@ -229,8 +318,7 @@ ActorOwn<> get_full_config(DcId dc_id, IPAddress ip_address, mtproto::ProxySecre
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ActorShared<> parent_;
|
ActorShared<> parent_;
|
||||||
IPAddress address_;
|
DcOption option_;
|
||||||
mtproto::ProxySecret secret_;
|
|
||||||
size_t request_raw_connection_cnt_{0};
|
size_t request_raw_connection_cnt_{0};
|
||||||
std::vector<Promise<unique_ptr<mtproto::RawConnection>>> delay_forever_;
|
std::vector<Promise<unique_ptr<mtproto::RawConnection>>> delay_forever_;
|
||||||
};
|
};
|
||||||
@ -311,17 +399,16 @@ ActorOwn<> get_full_config(DcId dc_id, IPAddress ip_address, mtproto::ProxySecre
|
|||||||
|
|
||||||
class GetConfigActor : public NetQueryCallback {
|
class GetConfigActor : public NetQueryCallback {
|
||||||
public:
|
public:
|
||||||
GetConfigActor(DcId dc_id, IPAddress ip_address, mtproto::ProxySecret secret, Promise<FullConfig> promise)
|
GetConfigActor(DcOption option, Promise<FullConfig> promise)
|
||||||
: dc_id_(dc_id), ip_address_(std::move(ip_address)), secret_(std::move(secret)), promise_(std::move(promise)) {
|
: option_(std::move(option)), promise_(std::move(promise)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start_up() override {
|
void start_up() override {
|
||||||
auto session_callback =
|
auto auth_data = std::make_shared<SimpleAuthData>(option_.get_dc_id());
|
||||||
make_unique<SessionCallback>(actor_shared(this, 1), std::move(ip_address_), std::move(secret_));
|
int32 int_dc_id = option_.get_dc_id().get_raw_id();
|
||||||
|
auto session_callback = make_unique<SessionCallback>(actor_shared(this, 1), std::move(option_));
|
||||||
|
|
||||||
auto auth_data = std::make_shared<SimpleAuthData>(dc_id_);
|
|
||||||
int32 int_dc_id = dc_id_.get_raw_id();
|
|
||||||
if (G()->is_test_dc()) {
|
if (G()->is_test_dc()) {
|
||||||
int_dc_id += 10000;
|
int_dc_id += 10000;
|
||||||
}
|
}
|
||||||
@ -357,15 +444,12 @@ ActorOwn<> get_full_config(DcId dc_id, IPAddress ip_address, mtproto::ProxySecre
|
|||||||
session_.reset();
|
session_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
DcId dc_id_;
|
DcOption option_;
|
||||||
IPAddress ip_address_;
|
|
||||||
ActorOwn<Session> session_;
|
ActorOwn<Session> session_;
|
||||||
mtproto::ProxySecret secret_;
|
|
||||||
Promise<FullConfig> promise_;
|
Promise<FullConfig> promise_;
|
||||||
};
|
};
|
||||||
|
|
||||||
return ActorOwn<>(create_actor<GetConfigActor>("GetConfigActor", dc_id, std::move(ip_address), std::move(secret),
|
return ActorOwn<>(create_actor<GetConfigActor>("GetConfigActor", option, std::move(promise)));
|
||||||
std::move(promise)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConfigRecoverer : public Actor {
|
class ConfigRecoverer : public Actor {
|
||||||
@ -434,9 +518,31 @@ class ConfigRecoverer : public Actor {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_simple_config(Result<SimpleConfig> r_simple_config, bool dummy) {
|
void on_simple_config(Result<SimpleConfigResult> r_simple_config_result, bool dummy) {
|
||||||
simple_config_query_.reset();
|
simple_config_query_.reset();
|
||||||
dc_options_i_ = 0;
|
dc_options_i_ = 0;
|
||||||
|
|
||||||
|
SimpleConfigResult cfg;
|
||||||
|
if (r_simple_config_result.is_error()) {
|
||||||
|
cfg.r_http_date = r_simple_config_result.error().clone();
|
||||||
|
cfg.r_config = r_simple_config_result.move_as_error();
|
||||||
|
} else {
|
||||||
|
cfg = r_simple_config_result.move_as_ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg.r_http_date.is_ok() && (date_option_i_ == 0 || cfg.r_config.is_error())) {
|
||||||
|
G()->update_dns_time_difference(cfg.r_http_date.ok() - Time::now());
|
||||||
|
} else if (cfg.r_config.is_ok()) {
|
||||||
|
G()->update_dns_time_difference(cfg.r_config.ok()->date_ - Time::now());
|
||||||
|
}
|
||||||
|
date_option_i_ = (date_option_i_ + 1) % 2;
|
||||||
|
|
||||||
|
do_on_simple_config(std::move(cfg.r_config));
|
||||||
|
update_dc_options();
|
||||||
|
loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_on_simple_config(Result<SimpleConfig> r_simple_config) {
|
||||||
if (r_simple_config.is_ok()) {
|
if (r_simple_config.is_ok()) {
|
||||||
auto config = r_simple_config.move_as_ok();
|
auto config = r_simple_config.move_as_ok();
|
||||||
VLOG(config_recoverer) << "Receive raw " << to_string(config);
|
VLOG(config_recoverer) << "Receive raw " << to_string(config);
|
||||||
@ -460,7 +566,6 @@ class ConfigRecoverer : public Actor {
|
|||||||
VLOG(config_recoverer) << "Config has expired at " << config->expires_;
|
VLOG(config_recoverer) << "Config has expired at " << config->expires_;
|
||||||
}
|
}
|
||||||
|
|
||||||
G()->update_dns_time_difference(config->date_ - Time::now());
|
|
||||||
simple_config_expires_at_ = get_config_expire_time();
|
simple_config_expires_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++) {
|
||||||
@ -471,8 +576,6 @@ class ConfigRecoverer : public Actor {
|
|||||||
simple_config_ = DcOptions();
|
simple_config_ = DcOptions();
|
||||||
simple_config_expires_at_ = get_failed_config_expire_time();
|
simple_config_expires_at_ = get_failed_config_expire_time();
|
||||||
}
|
}
|
||||||
update_dc_options();
|
|
||||||
loop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_full_config(Result<FullConfig> r_full_config, bool dummy) {
|
void on_full_config(Result<FullConfig> r_full_config, bool dummy) {
|
||||||
@ -526,6 +629,8 @@ class ConfigRecoverer : public Actor {
|
|||||||
double dc_options_at_{0};
|
double dc_options_at_{0};
|
||||||
size_t dc_options_i_;
|
size_t dc_options_i_;
|
||||||
|
|
||||||
|
size_t date_option_i_{0};
|
||||||
|
|
||||||
FullConfig full_config_;
|
FullConfig full_config_;
|
||||||
double full_config_expires_at_{0};
|
double full_config_expires_at_{0};
|
||||||
ActorOwn<> full_config_query_;
|
ActorOwn<> full_config_query_;
|
||||||
@ -593,7 +698,8 @@ class ConfigRecoverer : public Actor {
|
|||||||
if (need_simple_config) {
|
if (need_simple_config) {
|
||||||
ref_cnt_++;
|
ref_cnt_++;
|
||||||
VLOG(config_recoverer) << "ASK SIMPLE CONFIG";
|
VLOG(config_recoverer) << "ASK SIMPLE CONFIG";
|
||||||
auto promise = PromiseCreator::lambda([actor_id = actor_shared(this)](Result<SimpleConfig> r_simple_config) {
|
auto promise =
|
||||||
|
PromiseCreator::lambda([actor_id = actor_shared(this)](Result<SimpleConfigResult> r_simple_config) {
|
||||||
send_closure(actor_id, &ConfigRecoverer::on_simple_config, std::move(r_simple_config), false);
|
send_closure(actor_id, &ConfigRecoverer::on_simple_config, std::move(r_simple_config), false);
|
||||||
});
|
});
|
||||||
auto get_simple_config = [&]() {
|
auto get_simple_config = [&]() {
|
||||||
@ -614,9 +720,8 @@ class ConfigRecoverer : public Actor {
|
|||||||
if (need_full_config) {
|
if (need_full_config) {
|
||||||
ref_cnt_++;
|
ref_cnt_++;
|
||||||
VLOG(config_recoverer) << "ASK FULL CONFIG";
|
VLOG(config_recoverer) << "ASK FULL CONFIG";
|
||||||
full_config_query_ = get_full_config(
|
full_config_query_ =
|
||||||
dc_options_.dc_options[dc_options_i_].get_dc_id(), dc_options_.dc_options[dc_options_i_].get_ip_address(),
|
get_full_config(dc_options_.dc_options[dc_options_i_],
|
||||||
dc_options_.dc_options[dc_options_i_].get_secret(),
|
|
||||||
PromiseCreator::lambda([actor_id = actor_shared(this)](Result<FullConfig> r_full_config) {
|
PromiseCreator::lambda([actor_id = actor_shared(this)](Result<FullConfig> r_full_config) {
|
||||||
send_closure(actor_id, &ConfigRecoverer::on_full_config, std::move(r_full_config), false);
|
send_closure(actor_id, &ConfigRecoverer::on_full_config, std::move(r_full_config), false);
|
||||||
}));
|
}));
|
||||||
|
@ -28,14 +28,34 @@ extern int VERBOSITY_NAME(config_recoverer);
|
|||||||
class ConfigShared;
|
class ConfigShared;
|
||||||
|
|
||||||
using SimpleConfig = tl_object_ptr<telegram_api::help_configSimple>;
|
using SimpleConfig = tl_object_ptr<telegram_api::help_configSimple>;
|
||||||
|
struct SimpleConfigResult {
|
||||||
|
Result<SimpleConfig> r_config;
|
||||||
|
Result<int64> r_http_date;
|
||||||
|
};
|
||||||
|
|
||||||
Result<SimpleConfig> decode_config(Slice input);
|
Result<SimpleConfig> decode_config(Slice input);
|
||||||
|
|
||||||
ActorOwn<> get_simple_config_azure(Promise<SimpleConfig> promise, const ConfigShared *shared_config, bool is_test,
|
ActorOwn<> get_simple_config_azure(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config, bool is_test,
|
||||||
int32 scheduler_id);
|
int32 scheduler_id);
|
||||||
|
|
||||||
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfig> promise, const ConfigShared *shared_config, bool is_test,
|
ActorOwn<> get_simple_config_google_dns(Promise<SimpleConfigResult> promise, const ConfigShared *shared_config,
|
||||||
int32 scheduler_id);
|
bool is_test, int32 scheduler_id);
|
||||||
|
|
||||||
|
class HttpDate {
|
||||||
|
public:
|
||||||
|
static bool is_leap(int year) {
|
||||||
|
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||||
|
}
|
||||||
|
static int32 days_in_month(int year, int month) {
|
||||||
|
static int cnt[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
return cnt[month - 1] + (month == 2 && is_leap(year));
|
||||||
|
}
|
||||||
|
static int64 seconds_in_day() {
|
||||||
|
return 24 * 60 * 60;
|
||||||
|
}
|
||||||
|
static Result<int64> to_unix_time(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second);
|
||||||
|
static Result<int64> parse_http_date(std::string slice);
|
||||||
|
};
|
||||||
|
|
||||||
using FullConfig = tl_object_ptr<telegram_api::config>;
|
using FullConfig = tl_object_ptr<telegram_api::config>;
|
||||||
|
|
||||||
|
@ -753,6 +753,9 @@ void ConnectionCreator::request_raw_connection_by_ip(IPAddress ip_address, mtpro
|
|||||||
};
|
};
|
||||||
auto token = next_token();
|
auto token = next_token();
|
||||||
auto callback = td::make_unique<Callback>(std::move(socket_fd_promise));
|
auto callback = td::make_unique<Callback>(std::move(socket_fd_promise));
|
||||||
|
LOG(INFO) << "Tls in ConfigRecoverer " << ip_address << " " << transport_type.secret.get_domain() << " "
|
||||||
|
<< transport_type.secret.emulate_tls() << " " << transport_type.secret.get_proxy_secret().size()
|
||||||
|
<< transport_type.secret.get_encoded_secret();
|
||||||
children_[token] = {false, create_actor<mtproto::TlsInit>(
|
children_[token] = {false, create_actor<mtproto::TlsInit>(
|
||||||
"TlsInit", std::move(socket_fd), ip_address, transport_type.secret.get_domain(),
|
"TlsInit", std::move(socket_fd), ip_address, transport_type.secret.get_domain(),
|
||||||
transport_type.secret.get_proxy_secret().str(), std::move(callback),
|
transport_type.secret.get_proxy_secret().str(), std::move(callback),
|
||||||
@ -984,7 +987,8 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
|
|||||||
bool was_connected_{false};
|
bool was_connected_{false};
|
||||||
unique_ptr<detail::StatsCallback> stats_callback_;
|
unique_ptr<detail::StatsCallback> stats_callback_;
|
||||||
};
|
};
|
||||||
LOG(INFO) << "Start " << (proxy.use_socks5_proxy() ? "Socks5" : "HTTP") << ": " << extra.debug_str;
|
LOG(INFO) << "Start " << (proxy.use_socks5_proxy() ? "Socks5" : (proxy.use_http_tcp_proxy() ? "HTTP" : "Tls"))
|
||||||
|
<< ": " << extra.debug_str;
|
||||||
auto token = next_token();
|
auto token = next_token();
|
||||||
auto callback = td::make_unique<Callback>(std::move(promise), std::move(stats_callback));
|
auto callback = td::make_unique<Callback>(std::move(promise), std::move(stats_callback));
|
||||||
if (proxy.use_socks5_proxy()) {
|
if (proxy.use_socks5_proxy()) {
|
||||||
|
102
test/mtproto.cpp
102
test/mtproto.cpp
@ -121,105 +121,17 @@ TEST(Mtproto, GetHostByNameActor) {
|
|||||||
sched.finish();
|
sched.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Date {
|
|
||||||
public:
|
|
||||||
static bool is_leap(int year) {
|
|
||||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
|
||||||
}
|
|
||||||
static int32 days_in_month(int year, int month) {
|
|
||||||
int cnt[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
||||||
return cnt[month - 1] + (month == 2 && is_leap(year));
|
|
||||||
}
|
|
||||||
static int64 seconds_in_day() {
|
|
||||||
return 24 * 60 * 60;
|
|
||||||
}
|
|
||||||
static Result<int64> to_unix_time(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second) {
|
|
||||||
int64 res = 0;
|
|
||||||
if (year < 1970 || year > 2037) {
|
|
||||||
return td::Status::Error("invalid year");
|
|
||||||
}
|
|
||||||
if (month < 1 || month > 12) {
|
|
||||||
return td::Status::Error("invalid month");
|
|
||||||
}
|
|
||||||
if (day < 1 || day > days_in_month(year, month)) {
|
|
||||||
return td::Status::Error("invalid day");
|
|
||||||
}
|
|
||||||
if (hour < 0 || hour > 24) { // is hour == 24 possible?
|
|
||||||
return td::Status::Error("invalid hour");
|
|
||||||
}
|
|
||||||
if (minute < 0 || minute > 60) {
|
|
||||||
return td::Status::Error("invalid minute");
|
|
||||||
}
|
|
||||||
if (second < 0 || second > 60) {
|
|
||||||
return td::Status::Error("invalid second");
|
|
||||||
}
|
|
||||||
for (int y = 1970; y < year; y++) {
|
|
||||||
res += (is_leap(y) + 365) * seconds_in_day();
|
|
||||||
}
|
|
||||||
for (int m = 1; m < month; m++) {
|
|
||||||
res += days_in_month(year, m) * seconds_in_day();
|
|
||||||
}
|
|
||||||
res += (day - 1) * seconds_in_day();
|
|
||||||
res += hour * 60 * 60;
|
|
||||||
res += minute * 60;
|
|
||||||
res += second;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(Time, to_unix_time) {
|
TEST(Time, to_unix_time) {
|
||||||
ASSERT_EQ(0, Date::to_unix_time(1970, 1, 1, 0, 0, 0).move_as_ok());
|
ASSERT_EQ(0, HttpDate::to_unix_time(1970, 1, 1, 0, 0, 0).move_as_ok());
|
||||||
ASSERT_EQ(60 * 60 + 60 + 1, Date::to_unix_time(1970, 1, 1, 1, 1, 1).move_as_ok());
|
ASSERT_EQ(60 * 60 + 60 + 1, HttpDate::to_unix_time(1970, 1, 1, 1, 1, 1).move_as_ok());
|
||||||
ASSERT_EQ(24 * 60 * 60, Date::to_unix_time(1970, 1, 2, 0, 0, 0).move_as_ok());
|
ASSERT_EQ(24 * 60 * 60, HttpDate::to_unix_time(1970, 1, 2, 0, 0, 0).move_as_ok());
|
||||||
ASSERT_EQ(31 * 24 * 60 * 60, Date::to_unix_time(1970, 2, 1, 0, 0, 0).move_as_ok());
|
ASSERT_EQ(31 * 24 * 60 * 60, HttpDate::to_unix_time(1970, 2, 1, 0, 0, 0).move_as_ok());
|
||||||
ASSERT_EQ(365 * 24 * 60 * 60, Date::to_unix_time(1971, 1, 1, 0, 0, 0).move_as_ok());
|
ASSERT_EQ(365 * 24 * 60 * 60, HttpDate::to_unix_time(1971, 1, 1, 0, 0, 0).move_as_ok());
|
||||||
ASSERT_EQ(1562780559, Date::to_unix_time(2019, 7, 10, 17, 42, 39).move_as_ok());
|
ASSERT_EQ(1562780559, HttpDate::to_unix_time(2019, 7, 10, 17, 42, 39).move_as_ok());
|
||||||
}
|
|
||||||
|
|
||||||
Result<int64> parse_http_date(std::string slice) {
|
|
||||||
td::Parser p(slice);
|
|
||||||
p.read_till(','); // ignore week day
|
|
||||||
p.skip(',');
|
|
||||||
p.skip_whitespaces();
|
|
||||||
TRY_RESULT(day, to_integer_safe<int32>(p.read_word()));
|
|
||||||
auto month_name = p.read_word();
|
|
||||||
to_lower_inplace(month_name);
|
|
||||||
TRY_RESULT(year, to_integer_safe<int32>(p.read_word()));
|
|
||||||
p.skip_whitespaces();
|
|
||||||
p.skip_nofail('0');
|
|
||||||
TRY_RESULT(hour, to_integer_safe<int32>(p.read_till(':')));
|
|
||||||
p.skip(':');
|
|
||||||
p.skip_nofail('0');
|
|
||||||
TRY_RESULT(minute, to_integer_safe<int32>(p.read_till(':')));
|
|
||||||
p.skip(':');
|
|
||||||
p.skip_nofail('0');
|
|
||||||
TRY_RESULT(second, to_integer_safe<int32>(p.read_word()));
|
|
||||||
auto gmt = p.read_word();
|
|
||||||
TRY_STATUS(std::move(p.status()));
|
|
||||||
if (gmt != "GMT") {
|
|
||||||
return Status::Error("timezone must be GMT");
|
|
||||||
}
|
|
||||||
|
|
||||||
Slice month_names[12] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
|
|
||||||
|
|
||||||
int month = 0;
|
|
||||||
|
|
||||||
for (int m = 1; m <= 12; m++) {
|
|
||||||
if (month_names[m - 1] == month_name) {
|
|
||||||
month = m;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (month == 0) {
|
|
||||||
return Status::Error("Unknown month name");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Date::to_unix_time(year, month, day, hour, minute, second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Time, parse_http_date) {
|
TEST(Time, parse_http_date) {
|
||||||
ASSERT_EQ(784887151, parse_http_date("Tue, 15 Nov 1994 08:12:31 GMT").move_as_ok());
|
ASSERT_EQ(784887151, HttpDate::parse_http_date("Tue, 15 Nov 1994 08:12:31 GMT").move_as_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Mtproto, config) {
|
TEST(Mtproto, config) {
|
||||||
|
Reference in New Issue
Block a user