Add TransparentProxy abstract class.

GitOrigin-RevId: 77ced69b5d87c17a1bbc6d654bb0206a4e32e69d
This commit is contained in:
levlam 2018-07-26 03:28:02 +03:00
parent 236636e129
commit 2ca3c7eeed
7 changed files with 180 additions and 120 deletions

View File

@ -24,6 +24,7 @@
#include "td/net/GetHostByNameActor.h"
#include "td/net/Socks5.h"
#include "td/net/TransparentProxy.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
@ -493,7 +494,7 @@ void ConnectionCreator::ping_proxy_resolved(int32 proxy_id, IPAddress ip_address
});
CHECK(proxy.use_proxy());
if (proxy.use_socks5_proxy()) {
class Callback : public Socks5::Callback {
class Callback : public TransparentProxy::Callback {
public:
explicit Callback(Promise<SocketFd> promise) : promise_(std::move(promise)) {
}
@ -905,7 +906,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
extra.stat);
if (proxy.use_socks5_proxy()) {
class Callback : public Socks5::Callback {
class Callback : public TransparentProxy::Callback {
public:
explicit Callback(Promise<ConnectionData> promise, std::unique_ptr<detail::StatsCallback> stats_callback)
: promise_(std::move(promise)), stats_callback_(std::move(stats_callback)) {

View File

@ -19,6 +19,7 @@ set(TDNET_SOURCE
td/net/Socks5.cpp
td/net/SslFd.cpp
td/net/TcpListener.cpp
td/net/TransparentProxy.cpp
td/net/Wget.cpp
td/net/GetHostByNameActor.h
@ -35,6 +36,7 @@ set(TDNET_SOURCE
td/net/Socks5.h
td/net/SslFd.h
td/net/TcpListener.h
td/net/TransparentProxy.h
td/net/Wget.h
)

View File

@ -13,54 +13,8 @@
namespace td {
static int VERBOSITY_NAME(socks5) = VERBOSITY_NAME(DEBUG);
Socks5::Socks5(SocketFd socket_fd, IPAddress ip_address, string username, string password,
std::unique_ptr<Callback> callback, ActorShared<> parent)
: fd_(std::move(socket_fd))
, ip_address_(std::move(ip_address))
, username_(std::move(username))
, password_(std::move(password))
, callback_(std::move(callback))
, parent_(std::move(parent)) {
}
void Socks5::on_error(Status status) {
CHECK(status.is_error());
VLOG(socks5) << "Receive " << status;
if (callback_) {
callback_->set_result(std::move(status));
callback_.reset();
}
stop();
}
void Socks5::tear_down() {
VLOG(socks5) << "Finish to connect to proxy";
unsubscribe(fd_.get_fd());
fd_.get_fd().set_observer(nullptr);
if (callback_) {
callback_->set_result(std::move(fd_));
callback_.reset();
}
}
void Socks5::hangup() {
on_error(Status::Error("Cancelled"));
}
void Socks5::start_up() {
VLOG(socks5) << "Begin to connect to proxy";
fd_.get_fd().set_observer(this);
subscribe(fd_.get_fd());
set_timeout_in(10);
if (can_write(fd_)) {
loop();
}
}
void Socks5::send_greeting() {
VLOG(socks5) << "Send greeting to proxy";
VLOG(proxy) << "Send greeting to proxy";
CHECK(state_ == State::SendGreeting);
state_ = State::WaitGreetingResponse;
@ -79,7 +33,7 @@ void Socks5::send_greeting() {
Status Socks5::wait_greeting_response() {
auto &buf = fd_.input_buffer();
VLOG(socks5) << "Receive greeting response of size " << buf.size();
VLOG(proxy) << "Receive greeting response of size " << buf.size();
if (buf.size() < 2) {
return Status::OK();
}
@ -101,7 +55,7 @@ Status Socks5::wait_greeting_response() {
}
Status Socks5::send_username_password() {
VLOG(socks5) << "Send username and password";
VLOG(proxy) << "Send username and password";
if (username_.size() >= 128) {
return Status::Error("Username is too long");
}
@ -123,7 +77,7 @@ Status Socks5::send_username_password() {
Status Socks5::wait_password_response() {
auto &buf = fd_.input_buffer();
VLOG(socks5) << "Receive password response of size " << buf.size();
VLOG(proxy) << "Receive password response of size " << buf.size();
if (buf.size() < 2) {
return Status::OK();
}
@ -142,7 +96,7 @@ Status Socks5::wait_password_response() {
}
void Socks5::send_ip_address() {
VLOG(socks5) << "Send IP address";
VLOG(proxy) << "Send IP address";
CHECK(state_ == State::SendIpAddress);
callback_->on_connected();
string request;
@ -170,7 +124,7 @@ void Socks5::send_ip_address() {
Status Socks5::wait_ip_address_response() {
CHECK(state_ == State::WaitIpAddressResponse);
auto it = fd_.input_buffer().clone();
VLOG(socks5) << "Receive IP address response of size " << it.size();
VLOG(proxy) << "Receive IP address response of size " << it.size();
if (it.size() < 4) {
return Status::OK();
}
@ -189,16 +143,19 @@ Status Socks5::wait_ip_address_response() {
return Status::Error("byte must be zero");
}
it.advance(1, c_slice);
size_t total_size = 6;
if (c == '\x01') {
if (it.size() < 4) {
return Status::OK();
}
it.advance(4);
total_size += 4;
} else if (c == '\x04') {
if (it.size() < 16) {
return Status::OK();
}
it.advance(16);
total_size += 16;
} else {
return Status::Error("Invalid response");
}
@ -206,43 +163,30 @@ Status Socks5::wait_ip_address_response() {
return Status::OK();
}
it.advance(2);
fd_.input_buffer().advance(total_size);
stop();
return Status::OK();
}
void Socks5::loop() {
auto status = [&] {
TRY_STATUS(fd_.flush_read());
switch (state_) {
case State::SendGreeting:
send_greeting();
break;
case State::WaitGreetingResponse:
TRY_STATUS(wait_greeting_response());
break;
case State::WaitPasswordResponse:
TRY_STATUS(wait_password_response());
break;
case State::WaitIpAddressResponse:
TRY_STATUS(wait_ip_address_response());
break;
case State::SendIpAddress:
case State::Stop:
UNREACHABLE();
}
TRY_STATUS(fd_.flush_write());
return Status::OK();
}();
if (status.is_error()) {
on_error(std::move(status));
Status Socks5::loop_impl() {
switch (state_) {
case State::SendGreeting:
send_greeting();
break;
case State::WaitGreetingResponse:
TRY_STATUS(wait_greeting_response());
break;
case State::WaitPasswordResponse:
TRY_STATUS(wait_password_response());
break;
case State::WaitIpAddressResponse:
TRY_STATUS(wait_ip_address_response());
break;
case State::SendIpAddress:
case State::Stop:
UNREACHABLE();
}
if (can_close(fd_)) {
on_error(Status::Error("Connection closed"));
}
}
void Socks5::timeout_expired() {
on_error(Status::Error("Timeout expired"));
return Status::OK();
}
} // namespace td

View File

@ -6,45 +6,17 @@
//
#pragma once
#include "td/actor/actor.h"
#include "td/net/TransparentProxy.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/common.h"
#include "td/utils/port/IPAddress.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Status.h"
namespace td {
class Socks5 : public Actor {
class Socks5 : public TransparentProxy {
public:
class Callback {
public:
Callback() = default;
Callback(const Callback &) = delete;
Callback &operator=(const Callback &) = delete;
virtual ~Callback() = default;
virtual void set_result(Result<SocketFd>) = 0;
virtual void on_connected() = 0;
};
Socks5(SocketFd socket_fd, IPAddress ip_address, string username, string password, std::unique_ptr<Callback> callback,
ActorShared<> parent);
using TransparentProxy::TransparentProxy;
private:
BufferedFd<SocketFd> fd_;
IPAddress ip_address_;
string username_;
string password_;
std::unique_ptr<Callback> callback_;
ActorShared<> parent_;
void on_error(Status status);
void tear_down() override;
void start_up() override;
void hangup() override;
enum class State {
SendGreeting,
WaitGreetingResponse,
@ -63,8 +35,7 @@ class Socks5 : public Actor {
void send_ip_address();
Status wait_ip_address_response();
void loop() override;
void timeout_expired() override;
Status loop_impl() override;
};
} // namespace td

View File

@ -0,0 +1,85 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// 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/net/TransparentProxy.h"
#include "td/utils/logging.h"
#include "td/utils/port/Fd.h"
#include "td/utils/Slice.h"
namespace td {
int VERBOSITY_NAME(proxy) = VERBOSITY_NAME(DEBUG);
TransparentProxy::TransparentProxy(SocketFd socket_fd, IPAddress ip_address, string username, string password,
std::unique_ptr<Callback> callback, ActorShared<> parent)
: fd_(std::move(socket_fd))
, ip_address_(std::move(ip_address))
, username_(std::move(username))
, password_(std::move(password))
, callback_(std::move(callback))
, parent_(std::move(parent)) {
}
void TransparentProxy::on_error(Status status) {
CHECK(status.is_error());
VLOG(proxy) << "Receive " << status;
if (callback_) {
callback_->set_result(std::move(status));
callback_.reset();
}
stop();
}
void TransparentProxy::tear_down() {
VLOG(proxy) << "Finish to connect to proxy";
unsubscribe(fd_.get_fd());
fd_.get_fd().set_observer(nullptr);
if (callback_) {
if (!fd_.input_buffer().empty()) {
LOG(ERROR) << "Have " << fd_.input_buffer().size() << " unread bytes";
callback_->set_result(Status::Error("Proxy has sent to much data"));
} else {
callback_->set_result(std::move(fd_));
}
callback_.reset();
}
}
void TransparentProxy::hangup() {
on_error(Status::Error("Cancelled"));
}
void TransparentProxy::start_up() {
VLOG(proxy) << "Begin to connect to proxy";
fd_.get_fd().set_observer(this);
subscribe(fd_.get_fd());
set_timeout_in(10);
if (can_write(fd_)) {
loop();
}
}
void TransparentProxy::loop() {
auto status = [&] {
TRY_STATUS(fd_.flush_read());
TRY_STATUS(loop_impl());
TRY_STATUS(fd_.flush_write());
return Status::OK();
}();
if (status.is_error()) {
on_error(std::move(status));
}
if (can_close(fd_)) {
on_error(Status::Error("Connection closed"));
}
}
void TransparentProxy::timeout_expired() {
on_error(Status::Error("Timeout expired"));
}
} // namespace td

View File

@ -0,0 +1,56 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// 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/actor/actor.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/common.h"
#include "td/utils/port/IPAddress.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Status.h"
namespace td {
extern int VERBOSITY_NAME(proxy);
class TransparentProxy : public Actor {
public:
class Callback {
public:
Callback() = default;
Callback(const Callback &) = delete;
Callback &operator=(const Callback &) = delete;
virtual ~Callback() = default;
virtual void set_result(Result<SocketFd>) = 0;
virtual void on_connected() = 0;
};
TransparentProxy(SocketFd socket_fd, IPAddress ip_address, string username, string password, std::unique_ptr<Callback> callback,
ActorShared<> parent);
protected:
BufferedFd<SocketFd> fd_;
IPAddress ip_address_;
string username_;
string password_;
std::unique_ptr<Callback> callback_;
ActorShared<> parent_;
void on_error(Status status);
void tear_down() override;
void start_up() override;
void hangup() override;
void loop() override;
void timeout_expired() override;
virtual Status loop_impl() = 0;
};
} // namespace td

View File

@ -17,6 +17,7 @@
#include "td/mtproto/RawConnection.h"
#include "td/net/Socks5.h"
#include "td/net/TransparentProxy.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/net/DcId.h"
@ -302,7 +303,7 @@ class Socks5TestActor : public Actor {
send_closure(actor_id, &Socks5TestActor::on_result, std::move(res), false);
});
class Callback : public Socks5::Callback {
class Callback : public TransparentProxy::Callback {
public:
explicit Callback(Promise<SocketFd> promise) : promise_(std::move(promise)) {
}