Add support for HTTP-only HTTP proxies.
GitOrigin-RevId: 7b8e3e7afb0f26c8e8fa97b0ffff5d1ad0267b5c
This commit is contained in:
parent
a547f42886
commit
8de0bcd0a6
@ -2051,8 +2051,8 @@ textParseModeHTML = TextParseMode;
|
|||||||
//@description A SOCKS5 proxy server @username Username for logging in; may be empty @password Password for logging in; may be empty
|
//@description A SOCKS5 proxy server @username Username for logging in; may be empty @password Password for logging in; may be empty
|
||||||
proxyTypeSocks5 username:string password:string = ProxyType;
|
proxyTypeSocks5 username:string password:string = ProxyType;
|
||||||
|
|
||||||
//@description A HTTP transparent proxy server @username Username for logging in; may be empty @password Password for logging in; may be empty
|
//@description A HTTP transparent proxy server @username Username for logging in; may be empty @password Password for logging in; may be empty @http_only Pass true, if the proxy supports only HTTP requests and doesn't support transparent TCP connections via HTTP CONNECT method
|
||||||
proxyTypeHttp username:string password:string = ProxyType;
|
proxyTypeHttp username:string password:string http_only:Bool = ProxyType;
|
||||||
|
|
||||||
//@description An MTProto proxy server @secret The proxy's secret in hexadecimal encoding
|
//@description An MTProto proxy server @secret The proxy's secret in hexadecimal encoding
|
||||||
proxyTypeMtproto secret:string = ProxyType;
|
proxyTypeMtproto secret:string = ProxyType;
|
||||||
|
Binary file not shown.
@ -15,14 +15,18 @@
|
|||||||
#include "td/utils/Status.h"
|
#include "td/utils/Status.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
class Storer;
|
class Storer;
|
||||||
|
|
||||||
namespace mtproto {
|
namespace mtproto {
|
||||||
|
|
||||||
class AuthKeyHandshakeContext {
|
class AuthKeyHandshakeContext {
|
||||||
public:
|
public:
|
||||||
virtual ~AuthKeyHandshakeContext() = default;
|
virtual ~AuthKeyHandshakeContext() = default;
|
||||||
virtual DhCallback *get_dh_callback() = 0;
|
virtual DhCallback *get_dh_callback() = 0;
|
||||||
virtual PublicRsaKeyInterface *get_public_rsa_key_interface() = 0;
|
virtual PublicRsaKeyInterface *get_public_rsa_key_interface() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AuthKeyHandshake {
|
class AuthKeyHandshake {
|
||||||
public:
|
public:
|
||||||
class Callback {
|
class Callback {
|
||||||
@ -100,5 +104,6 @@ class AuthKeyHandshake {
|
|||||||
Status on_server_dh_params(Slice message, Callback *connection, DhCallback *dh_callback) TD_WARN_UNUSED_RESULT;
|
Status on_server_dh_params(Slice message, Callback *connection, DhCallback *dh_callback) TD_WARN_UNUSED_RESULT;
|
||||||
Status on_dh_gen_response(Slice message, Callback *connection) TD_WARN_UNUSED_RESULT;
|
Status on_dh_gen_response(Slice message, Callback *connection) TD_WARN_UNUSED_RESULT;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mtproto
|
} // namespace mtproto
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
|
|
||||||
#include "td/utils/buffer.h"
|
#include "td/utils/buffer.h"
|
||||||
#include "td/utils/logging.h"
|
#include "td/utils/logging.h"
|
||||||
|
#include "td/utils/misc.h"
|
||||||
#include "td/utils/Slice.h"
|
#include "td/utils/Slice.h"
|
||||||
#include "td/utils/Status.h"
|
#include "td/utils/Status.h"
|
||||||
|
|
||||||
// TODO: do I need \r\n as delimiter?
|
// TODO: do I need \r\n as delimiter?
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace mtproto {
|
namespace mtproto {
|
||||||
@ -47,9 +49,23 @@ void Transport::write(BufferWriter &&message, bool quick_ack) {
|
|||||||
* Host: url
|
* Host: url
|
||||||
*/
|
*/
|
||||||
HttpHeaderCreator hc;
|
HttpHeaderCreator hc;
|
||||||
hc.init_post("/api");
|
Slice host;
|
||||||
hc.add_header("Host", "");
|
Slice proxy_authorizarion;
|
||||||
hc.set_keep_alive();
|
std::tie(host, proxy_authorizarion) = split(Slice(secret_), '|');
|
||||||
|
if (host.empty()) {
|
||||||
|
hc.init_post("/api");
|
||||||
|
hc.add_header("Host", "");
|
||||||
|
hc.set_keep_alive();
|
||||||
|
} else {
|
||||||
|
hc.init_post(PSLICE() << "HTTP://" << host << ":80/api");
|
||||||
|
hc.add_header("Host", host);
|
||||||
|
hc.add_header("User-Agent", "curl/7.35.0");
|
||||||
|
hc.add_header("Accept", "*/*");
|
||||||
|
hc.add_header("Proxy-Connection", "keep-alive");
|
||||||
|
if (!proxy_authorizarion.empty()) {
|
||||||
|
hc.add_header("Proxy-Authorization", proxy_authorizarion);
|
||||||
|
}
|
||||||
|
}
|
||||||
hc.set_content_size(message.size());
|
hc.set_content_size(message.size());
|
||||||
auto r_head = hc.finish();
|
auto r_head = hc.finish();
|
||||||
CHECK(r_head.is_ok());
|
CHECK(r_head.is_ok());
|
||||||
@ -71,7 +87,11 @@ bool Transport::can_write() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t Transport::max_prepend_size() const {
|
size_t Transport::max_prepend_size() const {
|
||||||
return MAX_PREPEND_SIZE;
|
if (secret_.empty()) {
|
||||||
|
return 96;
|
||||||
|
} else {
|
||||||
|
return (secret_.size() + 1) / 2 * 4 + 156;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Transport::max_append_size() const {
|
size_t Transport::max_append_size() const {
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
namespace mtproto {
|
namespace mtproto {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
class Transport : public IStreamTransport {
|
class Transport : public IStreamTransport {
|
||||||
public:
|
public:
|
||||||
|
explicit Transport(string secret) : secret_(std::move(secret)) {
|
||||||
|
}
|
||||||
|
|
||||||
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT;
|
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT;
|
||||||
bool support_quick_ack() const override {
|
bool support_quick_ack() const override {
|
||||||
return false;
|
return false;
|
||||||
@ -35,16 +39,15 @@ class Transport : public IStreamTransport {
|
|||||||
size_t max_prepend_size() const override;
|
size_t max_prepend_size() const override;
|
||||||
size_t max_append_size() const override;
|
size_t max_append_size() const override;
|
||||||
TransportType get_type() const override {
|
TransportType get_type() const override {
|
||||||
return {TransportType::Http, 0, ""};
|
return {TransportType::Http, 0, secret_};
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
string secret_;
|
||||||
HttpReader reader_;
|
HttpReader reader_;
|
||||||
HttpQuery http_query_;
|
HttpQuery http_query_;
|
||||||
ChainBufferWriter *output_;
|
ChainBufferWriter *output_;
|
||||||
enum { Write, Read } turn_ = Write;
|
enum { Write, Read } turn_ = Write;
|
||||||
|
|
||||||
enum { MAX_PREPEND_SIZE = 96 };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace http
|
} // namespace http
|
||||||
|
@ -20,7 +20,7 @@ std::unique_ptr<IStreamTransport> create_transport(TransportType type) {
|
|||||||
case TransportType::Tcp:
|
case TransportType::Tcp:
|
||||||
return std::make_unique<tcp::OldTransport>();
|
return std::make_unique<tcp::OldTransport>();
|
||||||
case TransportType::Http:
|
case TransportType::Http:
|
||||||
return std::make_unique<http::Transport>();
|
return std::make_unique<http::Transport>(type.secret);
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
namespace mtproto {
|
namespace mtproto {
|
||||||
namespace tcp {
|
namespace tcp {
|
||||||
|
|
||||||
class ITransport {
|
class ITransport {
|
||||||
// Writes packet into message.
|
// Writes packet into message.
|
||||||
// Returns 0 if everything is ok, and [expected_size] otherwise.
|
// Returns 0 if everything is ok, and [expected_size] otherwise.
|
||||||
|
@ -3232,7 +3232,7 @@ class CliClient final : public Actor {
|
|||||||
send_request(make_tl_object<td_api::enableProxy>(as_proxy_id(args)));
|
send_request(make_tl_object<td_api::enableProxy>(as_proxy_id(args)));
|
||||||
} else if (op == "rproxy") {
|
} else if (op == "rproxy") {
|
||||||
send_request(make_tl_object<td_api::removeProxy>(as_proxy_id(args)));
|
send_request(make_tl_object<td_api::removeProxy>(as_proxy_id(args)));
|
||||||
} else if (op == "aproxy" || op == "aeproxy") {
|
} else if (op == "aproxy" || op == "aeproxy" || op == "aeproxytcp") {
|
||||||
string server;
|
string server;
|
||||||
string port;
|
string port;
|
||||||
string user;
|
string user;
|
||||||
@ -3245,7 +3245,7 @@ class CliClient final : public Actor {
|
|||||||
type = make_tl_object<td_api::proxyTypeMtproto>(user);
|
type = make_tl_object<td_api::proxyTypeMtproto>(user);
|
||||||
} else {
|
} else {
|
||||||
if (port == "80") {
|
if (port == "80") {
|
||||||
type = make_tl_object<td_api::proxyTypeHttp>(user, password);
|
type = make_tl_object<td_api::proxyTypeHttp>(user, password, op != "aeproxytcp");
|
||||||
} else {
|
} else {
|
||||||
type = make_tl_object<td_api::proxyTypeSocks5>(user, password);
|
type = make_tl_object<td_api::proxyTypeSocks5>(user, password);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "td/net/Socks5.h"
|
#include "td/net/Socks5.h"
|
||||||
#include "td/net/TransparentProxy.h"
|
#include "td/net/TransparentProxy.h"
|
||||||
|
|
||||||
|
#include "td/utils/base64.h"
|
||||||
#include "td/utils/format.h"
|
#include "td/utils/format.h"
|
||||||
#include "td/utils/logging.h"
|
#include "td/utils/logging.h"
|
||||||
#include "td/utils/misc.h"
|
#include "td/utils/misc.h"
|
||||||
@ -175,8 +176,11 @@ class ConnectionCreator::ProxyInfo {
|
|||||||
bool use_socks5_proxy() const {
|
bool use_socks5_proxy() const {
|
||||||
return proxy_type() == Proxy::Type::Socks5;
|
return proxy_type() == Proxy::Type::Socks5;
|
||||||
}
|
}
|
||||||
bool use_http_proxy() const {
|
bool use_http_tcp_proxy() const {
|
||||||
return proxy_type() == Proxy::Type::Http;
|
return proxy_type() == Proxy::Type::HttpTcp;
|
||||||
|
}
|
||||||
|
bool use_http_caching_proxy() const {
|
||||||
|
return proxy_type() == Proxy::Type::HttpCaching;
|
||||||
}
|
}
|
||||||
bool use_mtproto_proxy() const {
|
bool use_mtproto_proxy() const {
|
||||||
return proxy_type() == Proxy::Type::Mtproto;
|
return proxy_type() == Proxy::Type::Mtproto;
|
||||||
@ -198,7 +202,7 @@ template <class T>
|
|||||||
void Proxy::parse(T &parser) {
|
void Proxy::parse(T &parser) {
|
||||||
using td::parse;
|
using td::parse;
|
||||||
parse(type_, parser);
|
parse(type_, parser);
|
||||||
if (type_ == Proxy::Type::Socks5 || type_ == Proxy::Type::Http) {
|
if (type_ == Proxy::Type::Socks5 || type_ == Proxy::Type::HttpTcp || type_ == Proxy::Type::HttpCaching) {
|
||||||
parse(server_, parser);
|
parse(server_, parser);
|
||||||
parse(port_, parser);
|
parse(port_, parser);
|
||||||
parse(user_, parser);
|
parse(user_, parser);
|
||||||
@ -216,7 +220,7 @@ template <class T>
|
|||||||
void Proxy::store(T &storer) const {
|
void Proxy::store(T &storer) const {
|
||||||
using td::store;
|
using td::store;
|
||||||
store(type_, storer);
|
store(type_, storer);
|
||||||
if (type_ == Proxy::Type::Socks5 || type_ == Proxy::Type::Http) {
|
if (type_ == Proxy::Type::Socks5 || type_ == Proxy::Type::HttpTcp || type_ == Proxy::Type::HttpCaching) {
|
||||||
store(server_, storer);
|
store(server_, storer);
|
||||||
store(port_, storer);
|
store(port_, storer);
|
||||||
store(user_, storer);
|
store(user_, storer);
|
||||||
@ -234,8 +238,10 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Proxy &proxy) {
|
|||||||
switch (proxy.type()) {
|
switch (proxy.type()) {
|
||||||
case Proxy::Type::Socks5:
|
case Proxy::Type::Socks5:
|
||||||
return string_builder << "ProxySocks5 " << proxy.server() << ":" << proxy.port();
|
return string_builder << "ProxySocks5 " << proxy.server() << ":" << proxy.port();
|
||||||
case Proxy::Type::Http:
|
case Proxy::Type::HttpTcp:
|
||||||
return string_builder << "ProxyHttp " << proxy.server() << ":" << proxy.port();
|
return string_builder << "ProxyHttpTcp " << proxy.server() << ":" << proxy.port();
|
||||||
|
case Proxy::Type::HttpCaching:
|
||||||
|
return string_builder << "ProxyHttpCaching " << proxy.server() << ":" << proxy.port();
|
||||||
case Proxy::Type::Mtproto:
|
case Proxy::Type::Mtproto:
|
||||||
return string_builder << "ProxyMtproto " << proxy.server() << ":" << proxy.port() << "/" << proxy.secret();
|
return string_builder << "ProxyMtproto " << proxy.server() << ":" << proxy.port() << "/" << proxy.secret();
|
||||||
case Proxy::Type::None:
|
case Proxy::Type::None:
|
||||||
@ -306,7 +312,11 @@ void ConnectionCreator::add_proxy(string server, int32 port, bool enable,
|
|||||||
}
|
}
|
||||||
case td_api::proxyTypeHttp::ID: {
|
case td_api::proxyTypeHttp::ID: {
|
||||||
auto type = td_api::move_object_as<td_api::proxyTypeHttp>(proxy_type);
|
auto type = td_api::move_object_as<td_api::proxyTypeHttp>(proxy_type);
|
||||||
new_proxy = Proxy::http(server, port, type->username_, type->password_);
|
if (type->http_only_) {
|
||||||
|
new_proxy = Proxy::http_caching(server, port, type->username_, type->password_);
|
||||||
|
} else {
|
||||||
|
new_proxy = Proxy::http_tcp(server, port, type->username_, type->password_);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case td_api::proxyTypeMtproto::ID: {
|
case td_api::proxyTypeMtproto::ID: {
|
||||||
@ -395,7 +405,8 @@ void ConnectionCreator::get_proxy_link(int32 proxy_id, Promise<string> promise)
|
|||||||
url += "socks";
|
url += "socks";
|
||||||
is_socks = true;
|
is_socks = true;
|
||||||
break;
|
break;
|
||||||
case Proxy::Type::Http:
|
case Proxy::Type::HttpTcp:
|
||||||
|
case Proxy::Type::HttpCaching:
|
||||||
return promise.set_error(Status::Error(400, "HTTP proxy can't have public link"));
|
return promise.set_error(Status::Error(400, "HTTP proxy can't have public link"));
|
||||||
case Proxy::Type::Mtproto:
|
case Proxy::Type::Mtproto:
|
||||||
url += "proxy";
|
url += "proxy";
|
||||||
@ -426,7 +437,7 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise<double> promise) {
|
|||||||
ProxyInfo proxy{nullptr, IPAddress()};
|
ProxyInfo proxy{nullptr, IPAddress()};
|
||||||
auto main_dc_id = G()->net_query_dispatcher().main_dc_id();
|
auto main_dc_id = G()->net_query_dispatcher().main_dc_id();
|
||||||
bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6");
|
bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6");
|
||||||
auto infos = dc_options_set_.find_all_connections(main_dc_id, false, false, prefer_ipv6);
|
auto infos = dc_options_set_.find_all_connections(main_dc_id, false, false, prefer_ipv6, false);
|
||||||
if (infos.empty()) {
|
if (infos.empty()) {
|
||||||
return promise.set_error(Status::Error(400, "Can't find valid DC address"));
|
return promise.set_error(Status::Error(400, "Can't find valid DC address"));
|
||||||
}
|
}
|
||||||
@ -506,7 +517,7 @@ void ConnectionCreator::ping_proxy_resolved(int32 proxy_id, IPAddress ip_address
|
|||||||
std::move(transport_type), std::move(promise));
|
std::move(transport_type), std::move(promise));
|
||||||
});
|
});
|
||||||
CHECK(proxy.use_proxy());
|
CHECK(proxy.use_proxy());
|
||||||
if (proxy.use_socks5_proxy() || proxy.use_http_proxy()) {
|
if (proxy.use_socks5_proxy() || proxy.use_http_tcp_proxy()) {
|
||||||
class Callback : public TransparentProxy::Callback {
|
class Callback : public TransparentProxy::Callback {
|
||||||
public:
|
public:
|
||||||
explicit Callback(Promise<SocketFd> promise) : promise_(std::move(promise)) {
|
explicit Callback(Promise<SocketFd> promise) : promise_(std::move(promise)) {
|
||||||
@ -604,6 +615,7 @@ void ConnectionCreator::on_proxy_changed(bool from_db) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VLOG(connections) << "Drop proxy IP address " << proxy_ip_address_;
|
||||||
resolve_proxy_query_token_ = 0;
|
resolve_proxy_query_token_ = 0;
|
||||||
resolve_proxy_timestamp_ = Timestamp();
|
resolve_proxy_timestamp_ = Timestamp();
|
||||||
proxy_ip_address_ = IPAddress();
|
proxy_ip_address_ = IPAddress();
|
||||||
@ -658,8 +670,11 @@ td_api::object_ptr<td_api::proxy> ConnectionCreator::get_proxy_object(int32 prox
|
|||||||
case Proxy::Type::Socks5:
|
case Proxy::Type::Socks5:
|
||||||
type = make_tl_object<td_api::proxyTypeSocks5>(proxy.user().str(), proxy.password().str());
|
type = make_tl_object<td_api::proxyTypeSocks5>(proxy.user().str(), proxy.password().str());
|
||||||
break;
|
break;
|
||||||
case Proxy::Type::Http:
|
case Proxy::Type::HttpTcp:
|
||||||
type = make_tl_object<td_api::proxyTypeHttp>(proxy.user().str(), proxy.password().str());
|
type = make_tl_object<td_api::proxyTypeHttp>(proxy.user().str(), proxy.password().str(), false);
|
||||||
|
break;
|
||||||
|
case Proxy::Type::HttpCaching:
|
||||||
|
type = make_tl_object<td_api::proxyTypeHttp>(proxy.user().str(), proxy.password().str(), true);
|
||||||
break;
|
break;
|
||||||
case Proxy::Type::Mtproto:
|
case Proxy::Type::Mtproto:
|
||||||
type = make_tl_object<td_api::proxyTypeMtproto>(proxy.secret().str());
|
type = make_tl_object<td_api::proxyTypeMtproto>(proxy.secret().str());
|
||||||
@ -674,13 +689,17 @@ td_api::object_ptr<td_api::proxy> ConnectionCreator::get_proxy_object(int32 prox
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionCreator::on_network(bool network_flag, uint32 network_generation) {
|
void ConnectionCreator::on_network(bool network_flag, uint32 network_generation) {
|
||||||
|
VLOG(connections) << "Receive network flag " << network_flag << " with generation " << network_generation;
|
||||||
network_flag_ = network_flag;
|
network_flag_ = network_flag;
|
||||||
auto old_generation = network_generation_;
|
auto old_generation = network_generation_;
|
||||||
network_generation_ = network_generation;
|
network_generation_ = network_generation;
|
||||||
if (network_flag_) {
|
if (network_flag_) {
|
||||||
resolve_proxy_query_token_ = 0;
|
if (old_generation != network_generation_) {
|
||||||
resolve_proxy_timestamp_ = Timestamp();
|
VLOG(connections) << "Set proxy query token to 0: " << old_generation << " " << network_generation_;
|
||||||
get_proxy_info_timestamp_ = Timestamp();
|
resolve_proxy_query_token_ = 0;
|
||||||
|
resolve_proxy_timestamp_ = Timestamp();
|
||||||
|
get_proxy_info_timestamp_ = Timestamp();
|
||||||
|
}
|
||||||
for (auto &client : clients_) {
|
for (auto &client : clients_) {
|
||||||
client.second.backoff.clear();
|
client.second.backoff.clear();
|
||||||
client.second.flood_control.clear_events();
|
client.second.flood_control.clear_events();
|
||||||
@ -695,6 +714,7 @@ void ConnectionCreator::on_network(bool network_flag, uint32 network_generation)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionCreator::on_online(bool online_flag) {
|
void ConnectionCreator::on_online(bool online_flag) {
|
||||||
|
VLOG(connections) << "Receive online flag " << online_flag;
|
||||||
online_flag_ = online_flag;
|
online_flag_ = online_flag;
|
||||||
if (online_flag_) {
|
if (online_flag_) {
|
||||||
for (auto &client : clients_) {
|
for (auto &client : clients_) {
|
||||||
@ -768,6 +788,16 @@ Result<mtproto::TransportType> ConnectionCreator::get_transport_type(const Proxy
|
|||||||
TRY_RESULT(secret, hex_decode(proxy.proxy().secret()));
|
TRY_RESULT(secret, hex_decode(proxy.proxy().secret()));
|
||||||
return mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, raw_dc_id, std::move(secret)};
|
return mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, raw_dc_id, std::move(secret)};
|
||||||
}
|
}
|
||||||
|
if (proxy.use_http_caching_proxy()) {
|
||||||
|
CHECK(info.option != nullptr);
|
||||||
|
string proxy_authorization;
|
||||||
|
if (!proxy.proxy().user().empty() || !proxy.proxy().password().empty()) {
|
||||||
|
proxy_authorization =
|
||||||
|
"|basic " + td::base64_encode(PSLICE() << proxy.proxy().user() << ':' << proxy.proxy().password());
|
||||||
|
}
|
||||||
|
return mtproto::TransportType{mtproto::TransportType::Http, 0,
|
||||||
|
PSTRING() << info.option->get_ip_address().get_ip_str() << proxy_authorization};
|
||||||
|
}
|
||||||
|
|
||||||
if (info.use_http) {
|
if (info.use_http) {
|
||||||
return mtproto::TransportType{mtproto::TransportType::Http, 0, ""};
|
return mtproto::TransportType{mtproto::TransportType::Http, 0, ""};
|
||||||
@ -781,8 +811,9 @@ Result<SocketFd> ConnectionCreator::find_connection(const ProxyInfo &proxy, DcId
|
|||||||
extra.debug_str = PSTRING() << "Failed to find valid IP for " << dc_id;
|
extra.debug_str = PSTRING() << "Failed to find valid IP for " << dc_id;
|
||||||
bool prefer_ipv6 =
|
bool prefer_ipv6 =
|
||||||
G()->shared_config().get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy.ip_address().is_ipv6());
|
G()->shared_config().get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy.ip_address().is_ipv6());
|
||||||
TRY_RESULT(info, dc_options_set_.find_connection(dc_id, allow_media_only,
|
bool only_http = proxy.use_http_caching_proxy();
|
||||||
proxy.use_proxy() && proxy.use_socks5_proxy(), prefer_ipv6));
|
TRY_RESULT(info, dc_options_set_.find_connection(
|
||||||
|
dc_id, allow_media_only, proxy.use_proxy() && proxy.use_socks5_proxy(), prefer_ipv6, only_http));
|
||||||
extra.stat = info.stat;
|
extra.stat = info.stat;
|
||||||
TRY_RESULT(transport_type, get_transport_type(proxy, info));
|
TRY_RESULT(transport_type, get_transport_type(proxy, info));
|
||||||
extra.transport_type = std::move(transport_type);
|
extra.transport_type = std::move(transport_type);
|
||||||
@ -799,7 +830,7 @@ Result<SocketFd> ConnectionCreator::find_connection(const ProxyInfo &proxy, DcId
|
|||||||
|
|
||||||
extra.check_mode |= info.should_check;
|
extra.check_mode |= info.should_check;
|
||||||
|
|
||||||
if (proxy.use_socks5_proxy() || proxy.use_http_proxy()) {
|
if (proxy.use_proxy()) {
|
||||||
extra.mtproto_ip = info.option->get_ip_address();
|
extra.mtproto_ip = info.option->get_ip_address();
|
||||||
extra.debug_str = PSTRING() << (proxy.use_socks5_proxy() ? "Socks5 " : "HTTP ") << proxy.ip_address() << " --> "
|
extra.debug_str = PSTRING() << (proxy.use_socks5_proxy() ? "Socks5 " : "HTTP ") << proxy.ip_address() << " --> "
|
||||||
<< extra.mtproto_ip << extra.debug_str;
|
<< extra.mtproto_ip << extra.debug_str;
|
||||||
@ -815,14 +846,17 @@ Result<SocketFd> ConnectionCreator::find_connection(const ProxyInfo &proxy, DcId
|
|||||||
void ConnectionCreator::client_loop(ClientInfo &client) {
|
void ConnectionCreator::client_loop(ClientInfo &client) {
|
||||||
CHECK(client.hash != 0);
|
CHECK(client.hash != 0);
|
||||||
if (!network_flag_) {
|
if (!network_flag_) {
|
||||||
|
VLOG(connections) << "Exit client_loop, because there is no network";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (close_flag_) {
|
if (close_flag_) {
|
||||||
|
VLOG(connections) << "Exit client_loop, because of closing";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyInfo proxy{active_proxy_id_ == 0 ? nullptr : &proxies_[active_proxy_id_], proxy_ip_address_};
|
ProxyInfo proxy{active_proxy_id_ == 0 ? nullptr : &proxies_[active_proxy_id_], proxy_ip_address_};
|
||||||
if (proxy.use_proxy() && !proxy.ip_address().is_valid()) {
|
if (proxy.use_proxy() && !proxy.ip_address().is_valid()) {
|
||||||
|
VLOG(connections) << "Exit client_loop, because there is no valid IP address for proxy: " << proxy.ip_address();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,7 +963,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
|
|||||||
client.is_media ? media_net_stats_callback_ : common_net_stats_callback_, actor_id(this), client.hash,
|
client.is_media ? media_net_stats_callback_ : common_net_stats_callback_, actor_id(this), client.hash,
|
||||||
extra.stat);
|
extra.stat);
|
||||||
|
|
||||||
if (proxy.use_socks5_proxy() || proxy.use_http_proxy()) {
|
if (proxy.use_socks5_proxy() || proxy.use_http_tcp_proxy()) {
|
||||||
class Callback : public TransparentProxy::Callback {
|
class Callback : public TransparentProxy::Callback {
|
||||||
public:
|
public:
|
||||||
explicit Callback(Promise<ConnectionData> promise, std::unique_ptr<detail::StatsCallback> stats_callback)
|
explicit Callback(Promise<ConnectionData> promise, std::unique_ptr<detail::StatsCallback> stats_callback)
|
||||||
@ -1267,6 +1301,7 @@ void ConnectionCreator::loop() {
|
|||||||
resolve_proxy_query_token_ = next_token();
|
resolve_proxy_query_token_ = next_token();
|
||||||
const Proxy &proxy = proxies_[active_proxy_id_];
|
const Proxy &proxy = proxies_[active_proxy_id_];
|
||||||
bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6");
|
bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6");
|
||||||
|
VLOG(connections) << "Resolve IP address " << resolve_proxy_query_token_ << " of " << proxy.server();
|
||||||
send_closure(
|
send_closure(
|
||||||
get_host_by_name_actor_, &GetHostByNameActor::run, proxy.server().str(), proxy.port(), prefer_ipv6,
|
get_host_by_name_actor_, &GetHostByNameActor::run, proxy.server().str(), proxy.port(), prefer_ipv6,
|
||||||
PromiseCreator::lambda([actor_id = create_reference(resolve_proxy_query_token_)](Result<IPAddress> result) {
|
PromiseCreator::lambda([actor_id = create_reference(resolve_proxy_query_token_)](Result<IPAddress> result) {
|
||||||
@ -1349,6 +1384,8 @@ void ConnectionCreator::schedule_get_proxy_info(int32 expires) {
|
|||||||
|
|
||||||
void ConnectionCreator::on_proxy_resolved(Result<IPAddress> r_ip_address, bool dummy) {
|
void ConnectionCreator::on_proxy_resolved(Result<IPAddress> r_ip_address, bool dummy) {
|
||||||
if (get_link_token() != resolve_proxy_query_token_) {
|
if (get_link_token() != resolve_proxy_query_token_) {
|
||||||
|
VLOG(connections) << "Ignore unneeded proxy IP address " << get_link_token() << ", expected "
|
||||||
|
<< resolve_proxy_query_token_;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1358,10 +1395,12 @@ void ConnectionCreator::on_proxy_resolved(Result<IPAddress> r_ip_address, bool d
|
|||||||
|
|
||||||
resolve_proxy_query_token_ = 0;
|
resolve_proxy_query_token_ = 0;
|
||||||
if (r_ip_address.is_error()) {
|
if (r_ip_address.is_error()) {
|
||||||
|
VLOG(connections) << "Receive error for resolving proxy IP address: " << r_ip_address.error();
|
||||||
resolve_proxy_timestamp_ = Timestamp::in(1 * 60);
|
resolve_proxy_timestamp_ = Timestamp::in(1 * 60);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
proxy_ip_address_ = r_ip_address.move_as_ok();
|
proxy_ip_address_ = r_ip_address.move_as_ok();
|
||||||
|
VLOG(connections) << "Set proxy IP address to " << proxy_ip_address_;
|
||||||
resolve_proxy_timestamp_ = Timestamp::in(5 * 60);
|
resolve_proxy_timestamp_ = Timestamp::in(5 * 60);
|
||||||
for (auto &client : clients_) {
|
for (auto &client : clients_) {
|
||||||
client_loop(client.second);
|
client_loop(client.second);
|
||||||
|
@ -60,9 +60,19 @@ class Proxy {
|
|||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Proxy http(string server, int32 port, string user, string password) {
|
static Proxy http_tcp(string server, int32 port, string user, string password) {
|
||||||
Proxy proxy;
|
Proxy proxy;
|
||||||
proxy.type_ = Type::Http;
|
proxy.type_ = Type::HttpTcp;
|
||||||
|
proxy.server_ = std::move(server);
|
||||||
|
proxy.port_ = std::move(port);
|
||||||
|
proxy.user_ = std::move(user);
|
||||||
|
proxy.password_ = std::move(password);
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Proxy http_caching(string server, int32 port, string user, string password) {
|
||||||
|
Proxy proxy;
|
||||||
|
proxy.type_ = Type::HttpCaching;
|
||||||
proxy.server_ = std::move(server);
|
proxy.server_ = std::move(server);
|
||||||
proxy.port_ = std::move(port);
|
proxy.port_ = std::move(port);
|
||||||
proxy.user_ = std::move(user);
|
proxy.user_ = std::move(user);
|
||||||
@ -99,7 +109,7 @@ class Proxy {
|
|||||||
return secret_;
|
return secret_;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Type : int32 { None, Socks5, Mtproto, Http };
|
enum class Type : int32 { None, Socks5, Mtproto, HttpTcp, HttpCaching };
|
||||||
Type type() const {
|
Type type() const {
|
||||||
return type_;
|
return type_;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ DcOptions DcOptionsSet::get_dc_options() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vector<DcOptionsSet::ConnectionInfo> DcOptionsSet::find_all_connections(DcId dc_id, bool allow_media_only,
|
vector<DcOptionsSet::ConnectionInfo> DcOptionsSet::find_all_connections(DcId dc_id, bool allow_media_only,
|
||||||
bool use_static, bool prefer_ipv6) {
|
bool use_static, bool prefer_ipv6,
|
||||||
|
bool only_http) {
|
||||||
std::vector<ConnectionInfo> options;
|
std::vector<ConnectionInfo> options;
|
||||||
std::vector<ConnectionInfo> static_options;
|
std::vector<ConnectionInfo> static_options;
|
||||||
|
|
||||||
@ -72,18 +73,22 @@ vector<DcOptionsSet::ConnectionInfo> DcOptionsSet::find_all_connections(DcId dc_
|
|||||||
|
|
||||||
OptionStat *option_stat = get_option_stat(option_info.get());
|
OptionStat *option_stat = get_option_stat(option_info.get());
|
||||||
|
|
||||||
info.use_http = false;
|
if (!only_http) {
|
||||||
info.stat = &option_stat->tcp_stat;
|
info.use_http = false;
|
||||||
if (option.is_static()) {
|
info.stat = &option_stat->tcp_stat;
|
||||||
static_options.push_back(info);
|
if (option.is_static()) {
|
||||||
} else {
|
static_options.push_back(info);
|
||||||
options.push_back(info);
|
} else {
|
||||||
|
options.push_back(info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!option.is_obfuscated_tcp_only() && !option.is_static() && false) { // TODO fix HTTP-mode and enable it
|
if (only_http) {
|
||||||
info.use_http = true;
|
if (!option.is_obfuscated_tcp_only() && !option.is_static()) {
|
||||||
info.stat = &option_stat->http_stat;
|
info.use_http = true;
|
||||||
options.push_back(info);
|
info.stat = &option_stat->http_stat;
|
||||||
|
options.push_back(info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,8 +126,8 @@ vector<DcOptionsSet::ConnectionInfo> DcOptionsSet::find_all_connections(DcId dc_
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<DcOptionsSet::ConnectionInfo> DcOptionsSet::find_connection(DcId dc_id, bool allow_media_only, bool use_static,
|
Result<DcOptionsSet::ConnectionInfo> DcOptionsSet::find_connection(DcId dc_id, bool allow_media_only, bool use_static,
|
||||||
bool prefer_ipv6) {
|
bool prefer_ipv6, bool only_http) {
|
||||||
auto options = find_all_connections(dc_id, allow_media_only, use_static, prefer_ipv6);
|
auto options = find_all_connections(dc_id, allow_media_only, use_static, prefer_ipv6, only_http);
|
||||||
|
|
||||||
if (options.empty()) {
|
if (options.empty()) {
|
||||||
return Status::Error(PSLICE() << "No such connection: " << tag("dc_id", dc_id)
|
return Status::Error(PSLICE() << "No such connection: " << tag("dc_id", dc_id)
|
||||||
|
@ -61,9 +61,11 @@ class DcOptionsSet {
|
|||||||
Stat *stat{nullptr};
|
Stat *stat{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
vector<ConnectionInfo> find_all_connections(DcId dc_id, bool allow_media_only, bool use_static, bool prefer_ipv6);
|
vector<ConnectionInfo> find_all_connections(DcId dc_id, bool allow_media_only, bool use_static, bool prefer_ipv6,
|
||||||
|
bool only_http);
|
||||||
|
|
||||||
Result<ConnectionInfo> find_connection(DcId dc_id, bool allow_media_only, bool use_static, bool prefer_ipv6);
|
Result<ConnectionInfo> find_connection(DcId dc_id, bool allow_media_only, bool use_static, bool prefer_ipv6,
|
||||||
|
bool only_http);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Reference in New Issue
Block a user