Add QUIC client

This commit is contained in:
klzgrad 2018-12-12 23:22:18 -05:00
parent 9d2e9cd9ff
commit 5c8e8a9b96
5 changed files with 182 additions and 181 deletions

View File

@ -12,20 +12,19 @@
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/rand_util.h" #include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/base/privacy_mode.h" #include "net/base/privacy_mode.h"
#include "net/http/http_network_session.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_info.h" #include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_list.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
#include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_manager.h" #include "net/socket/client_socket_pool_manager.h"
#include "net/socket/stream_socket.h" #include "net/socket/stream_socket.h"
#include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session.h"
#include "net/tools/naive/http_proxy_socket.h"
#include "net/tools/naive/socks5_server_socket.h"
namespace net { namespace net {
@ -38,14 +37,24 @@ constexpr int kMaxPaddingSize = 255;
NaiveConnection::NaiveConnection( NaiveConnection::NaiveConnection(
unsigned int id, unsigned int id,
Protocol protocol,
Direction pad_direction, Direction pad_direction,
const ProxyInfo& proxy_info,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpNetworkSession* session,
const NetLogWithSource& net_log,
std::unique_ptr<StreamSocket> accepted_socket, std::unique_ptr<StreamSocket> accepted_socket,
Delegate* delegate,
const NetworkTrafficAnnotationTag& traffic_annotation) const NetworkTrafficAnnotationTag& traffic_annotation)
: id_(id), : id_(id),
protocol_(protocol),
pad_direction_(pad_direction), pad_direction_(pad_direction),
proxy_info_(proxy_info),
server_ssl_config_(server_ssl_config),
proxy_ssl_config_(proxy_ssl_config),
session_(session),
net_log_(net_log),
next_state_(STATE_NONE), next_state_(STATE_NONE),
delegate_(delegate),
client_socket_(std::move(accepted_socket)), client_socket_(std::move(accepted_socket)),
server_socket_handle_(std::make_unique<ClientSocketHandle>()), server_socket_handle_(std::make_unique<ClientSocketHandle>()),
sockets_{client_socket_.get(), nullptr}, sockets_{client_socket_.get(), nullptr},
@ -167,10 +176,30 @@ int NaiveConnection::DoConnectClientComplete(int result) {
} }
int NaiveConnection::DoConnectServer() { int NaiveConnection::DoConnectServer() {
DCHECK(delegate_);
next_state_ = STATE_CONNECT_SERVER_COMPLETE; next_state_ = STATE_CONNECT_SERVER_COMPLETE;
return delegate_->OnConnectServer(id_, client_socket_.get(), HostPortPair origin;
if (protocol_ == kSocks5) {
const auto* socket =
static_cast<const Socks5ServerSocket*>(client_socket_.get());
origin = socket->request_endpoint();
} else if (protocol_ == kHttp) {
const auto* socket =
static_cast<const HttpProxySocket*>(client_socket_.get());
origin = socket->request_endpoint();
}
if (origin.IsEmpty()) {
LOG(ERROR) << "Connection " << id_ << " to invalid origin";
return ERR_ADDRESS_INVALID;
}
LOG(INFO) << "Connection " << id_ << " to " << origin.ToString();
// Ignores socket limit set by socket pool for this type of socket.
return InitSocketHandleForRawConnect2(
origin, session_, LOAD_IGNORE_LIMITS, MAXIMUM_PRIORITY, proxy_info_,
server_ssl_config_, proxy_ssl_config_, PRIVACY_MODE_DISABLED, net_log_,
server_socket_handle_.get(), io_callback_); server_socket_handle_.get(), io_callback_);
} }

View File

@ -20,14 +20,23 @@ namespace net {
class ClientSocketHandle; class ClientSocketHandle;
class DrainableIOBuffer; class DrainableIOBuffer;
class HttpNetworkSession;
class IOBuffer; class IOBuffer;
class NetLogWithSource;
class ProxyInfo;
class StreamSocket; class StreamSocket;
struct NetworkTrafficAnnotationTag; struct NetworkTrafficAnnotationTag;
struct SSLConfig;
class NaiveConnection { class NaiveConnection {
public: public:
using TimeFunc = base::TimeTicks (*)(); using TimeFunc = base::TimeTicks (*)();
enum Protocol {
kSocks5,
kHttp,
};
// From this direction. // From this direction.
enum Direction { enum Direction {
kClient = 0, kClient = 0,
@ -36,24 +45,15 @@ class NaiveConnection {
kNone = 2, kNone = 2,
}; };
class Delegate {
public:
Delegate() {}
virtual ~Delegate() {}
virtual int OnConnectServer(unsigned int connection_id,
const StreamSocket* accepted_socket,
ClientSocketHandle* server_socket,
CompletionRepeatingCallback callback) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
NaiveConnection(unsigned int id, NaiveConnection(unsigned int id,
Protocol protocol,
Direction pad_direction, Direction pad_direction,
const ProxyInfo& proxy_info,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpNetworkSession* session,
const NetLogWithSource& net_log,
std::unique_ptr<StreamSocket> accepted_socket, std::unique_ptr<StreamSocket> accepted_socket,
Delegate* delegate,
const NetworkTrafficAnnotationTag& traffic_annotation); const NetworkTrafficAnnotationTag& traffic_annotation);
~NaiveConnection(); ~NaiveConnection();
@ -97,7 +97,13 @@ class NaiveConnection {
void OnPushComplete(Direction from, Direction to, int result); void OnPushComplete(Direction from, Direction to, int result);
unsigned int id_; unsigned int id_;
Protocol protocol_;
Direction pad_direction_; Direction pad_direction_;
const ProxyInfo& proxy_info_;
const SSLConfig& server_ssl_config_;
const SSLConfig& proxy_ssl_config_;
HttpNetworkSession* session_;
const NetLogWithSource& net_log_;
CompletionRepeatingCallback io_callback_; CompletionRepeatingCallback io_callback_;
CompletionOnceCallback connect_callback_; CompletionOnceCallback connect_callback_;
@ -105,8 +111,6 @@ class NaiveConnection {
State next_state_; State next_state_;
Delegate* delegate_;
std::unique_ptr<StreamSocket> client_socket_; std::unique_ptr<StreamSocket> client_socket_;
std::unique_ptr<ClientSocketHandle> server_socket_handle_; std::unique_ptr<ClientSocketHandle> server_socket_handle_;

View File

@ -16,7 +16,6 @@
#include "net/http/http_network_session.h" #include "net/http/http_network_session.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h" #include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/proxy_resolution/proxy_config.h" #include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_list.h" #include "net/proxy_resolution/proxy_list.h"
#include "net/socket/client_socket_pool_manager.h" #include "net/socket/client_socket_pool_manager.h"
#include "net/socket/server_socket.h" #include "net/socket/server_socket.h"
@ -27,18 +26,32 @@
namespace net { namespace net {
NaiveProxy::NaiveProxy(std::unique_ptr<ServerSocket> listen_socket, NaiveProxy::NaiveProxy(std::unique_ptr<ServerSocket> listen_socket,
Protocol protocol, NaiveConnection::Protocol protocol,
bool use_proxy, bool use_padding,
HttpNetworkSession* session, HttpNetworkSession* session,
const NetworkTrafficAnnotationTag& traffic_annotation) const NetworkTrafficAnnotationTag& traffic_annotation)
: listen_socket_(std::move(listen_socket)), : listen_socket_(std::move(listen_socket)),
protocol_(protocol), protocol_(protocol),
use_proxy_(use_proxy), use_padding_(use_padding),
session_(session), session_(session),
net_log_( net_log_(
NetLogWithSource::Make(session->net_log(), NetLogSourceType::NONE)), NetLogWithSource::Make(session->net_log(), NetLogSourceType::NONE)),
last_id_(0), last_id_(0),
traffic_annotation_(traffic_annotation) { traffic_annotation_(traffic_annotation) {
const auto& proxy_config = static_cast<ConfiguredProxyResolutionService*>(
session_->proxy_resolution_service())
->config();
DCHECK(proxy_config);
const ProxyList& proxy_list =
proxy_config.value().value().proxy_rules().single_proxies;
DCHECK(!proxy_list.IsEmpty());
proxy_info_.UseProxyList(proxy_list);
proxy_info_.set_traffic_annotation(
net::MutableNetworkTrafficAnnotationTag(traffic_annotation_));
session_->GetSSLConfig(&server_ssl_config_, &proxy_ssl_config_);
proxy_ssl_config_.disable_cert_verification_network_fetches = true;
DCHECK(listen_socket_); DCHECK(listen_socket_);
// Start accepting connections in next run loop in case when delegate is not // Start accepting connections in next run loop in case when delegate is not
// ready to get callbacks. // ready to get callbacks.
@ -78,19 +91,24 @@ void NaiveProxy::HandleAcceptResult(int result) {
void NaiveProxy::DoConnect() { void NaiveProxy::DoConnect() {
std::unique_ptr<StreamSocket> socket; std::unique_ptr<StreamSocket> socket;
NaiveConnection::Direction pad_direction; NaiveConnection::Direction pad_direction;
if (protocol_ == kSocks5) { if (protocol_ == NaiveConnection::kSocks5) {
socket = std::make_unique<Socks5ServerSocket>(std::move(accepted_socket_), socket = std::make_unique<Socks5ServerSocket>(std::move(accepted_socket_),
traffic_annotation_); traffic_annotation_);
pad_direction = NaiveConnection::kClient; pad_direction = NaiveConnection::kClient;
} else if (protocol_ == kHttp) { } else if (protocol_ == NaiveConnection::kHttp) {
socket = std::make_unique<HttpProxySocket>(std::move(accepted_socket_), socket = std::make_unique<HttpProxySocket>(std::move(accepted_socket_),
traffic_annotation_); traffic_annotation_);
pad_direction = NaiveConnection::kServer; pad_direction = NaiveConnection::kServer;
} else { } else {
return; return;
} }
if (!use_padding_) {
pad_direction = NaiveConnection::kNone;
}
auto connection_ptr = std::make_unique<NaiveConnection>( auto connection_ptr = std::make_unique<NaiveConnection>(
++last_id_, pad_direction, std::move(socket), this, traffic_annotation_); ++last_id_, protocol_, pad_direction, proxy_info_, server_ssl_config_,
proxy_ssl_config_, session_, net_log_, std::move(socket),
traffic_annotation_);
auto* connection = connection_ptr.get(); auto* connection = connection_ptr.get();
connection_by_id_[connection->id()] = std::move(connection_ptr); connection_by_id_[connection->id()] = std::move(connection_ptr);
int result = connection->Connect( int result = connection->Connect(
@ -101,61 +119,8 @@ void NaiveProxy::DoConnect() {
HandleConnectResult(connection, result); HandleConnectResult(connection, result);
} }
int NaiveProxy::OnConnectServer(unsigned int connection_id, void NaiveProxy::OnConnectComplete(unsigned int connection_id, int result) {
const StreamSocket* client_socket, auto* connection = FindConnection(connection_id);
ClientSocketHandle* server_socket,
CompletionRepeatingCallback callback) {
// Ignores socket limit set by socket pool for this type of socket.
constexpr int request_load_flags = LOAD_IGNORE_LIMITS;
constexpr RequestPriority request_priority = MAXIMUM_PRIORITY;
ProxyInfo proxy_info;
SSLConfig server_ssl_config;
SSLConfig proxy_ssl_config;
if (use_proxy_) {
const auto& proxy_config = static_cast<ConfiguredProxyResolutionService*>(
session_->proxy_resolution_service())
->config();
DCHECK(proxy_config);
const ProxyList& proxy_list =
proxy_config.value().value().proxy_rules().single_proxies;
if (proxy_list.IsEmpty())
return ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
proxy_info.UseProxyList(proxy_list);
proxy_info.set_traffic_annotation(
net::MutableNetworkTrafficAnnotationTag(traffic_annotation_));
session_->GetSSLConfig(&server_ssl_config, &proxy_ssl_config);
proxy_ssl_config.disable_cert_verification_network_fetches = true;
} else {
proxy_info.UseDirect();
}
HostPortPair request_endpoint;
if (protocol_ == kSocks5) {
const auto* socket = static_cast<const Socks5ServerSocket*>(client_socket);
request_endpoint = socket->request_endpoint();
} else if (protocol_ == kHttp) {
const auto* socket = static_cast<const HttpProxySocket*>(client_socket);
request_endpoint = socket->request_endpoint();
}
if (request_endpoint.IsEmpty()) {
LOG(ERROR) << "Connection " << connection_id << " to invalid origin";
return ERR_ADDRESS_INVALID;
}
LOG(INFO) << "Connection " << connection_id << " to "
<< request_endpoint.ToString();
return InitSocketHandleForRawConnect2(
request_endpoint, session_, request_load_flags, request_priority,
proxy_info, server_ssl_config, proxy_ssl_config, PRIVACY_MODE_DISABLED,
net_log_, server_socket, callback);
}
void NaiveProxy::OnConnectComplete(int connection_id, int result) {
NaiveConnection* connection = FindConnection(connection_id);
if (!connection) if (!connection)
return; return;
HandleConnectResult(connection, result); HandleConnectResult(connection, result);
@ -178,8 +143,8 @@ void NaiveProxy::DoRun(NaiveConnection* connection) {
HandleRunResult(connection, result); HandleRunResult(connection, result);
} }
void NaiveProxy::OnRunComplete(int connection_id, int result) { void NaiveProxy::OnRunComplete(unsigned int connection_id, int result) {
NaiveConnection* connection = FindConnection(connection_id); auto* connection = FindConnection(connection_id);
if (!connection) if (!connection)
return; return;
HandleRunResult(connection, result); HandleRunResult(connection, result);
@ -189,7 +154,7 @@ void NaiveProxy::HandleRunResult(NaiveConnection* connection, int result) {
Close(connection->id(), result); Close(connection->id(), result);
} }
void NaiveProxy::Close(int connection_id, int reason) { void NaiveProxy::Close(unsigned int connection_id, int reason) {
auto it = connection_by_id_.find(connection_id); auto it = connection_by_id_.find(connection_id);
if (it == connection_by_id_.end()) if (it == connection_by_id_.end())
return; return;
@ -206,19 +171,11 @@ void NaiveProxy::Close(int connection_id, int reason) {
connection_by_id_.erase(it); connection_by_id_.erase(it);
} }
NaiveConnection* NaiveProxy::FindConnection(int connection_id) { NaiveConnection* NaiveProxy::FindConnection(unsigned int connection_id) {
auto it = connection_by_id_.find(connection_id); auto it = connection_by_id_.find(connection_id);
if (it == connection_by_id_.end()) if (it == connection_by_id_.end())
return nullptr; return nullptr;
return it->second.get(); return it->second.get();
} }
// This is called after any delegate callbacks are called to check if Close()
// has been called during callback processing. Using the pointer of connection,
// |connection| is safe here because Close() deletes the connection in next run
// loop.
bool NaiveProxy::HasClosedConnection(NaiveConnection* connection) {
return FindConnection(connection->id()) != connection;
}
} // namespace net } // namespace net

View File

@ -13,6 +13,8 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "net/base/completion_repeating_callback.h" #include "net/base/completion_repeating_callback.h"
#include "net/log/net_log_with_source.h" #include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/ssl/ssl_config.h"
#include "net/tools/naive/naive_connection.h" #include "net/tools/naive/naive_connection.h"
namespace net { namespace net {
@ -24,24 +26,14 @@ class ServerSocket;
class StreamSocket; class StreamSocket;
struct NetworkTrafficAnnotationTag; struct NetworkTrafficAnnotationTag;
class NaiveProxy : public NaiveConnection::Delegate { class NaiveProxy {
public: public:
enum Protocol {
kSocks5,
kHttp,
};
NaiveProxy(std::unique_ptr<ServerSocket> server_socket, NaiveProxy(std::unique_ptr<ServerSocket> server_socket,
Protocol protocol, NaiveConnection::Protocol protocol,
bool use_proxy, bool use_padding,
HttpNetworkSession* session, HttpNetworkSession* session,
const NetworkTrafficAnnotationTag& traffic_annotation); const NetworkTrafficAnnotationTag& traffic_annotation);
~NaiveProxy() override; ~NaiveProxy();
int OnConnectServer(unsigned int connection_id,
const StreamSocket* accepted_socket,
ClientSocketHandle* server_socket,
CompletionRepeatingCallback callback) override;
private: private:
void DoAcceptLoop(); void DoAcceptLoop();
@ -49,21 +41,23 @@ class NaiveProxy : public NaiveConnection::Delegate {
void HandleAcceptResult(int result); void HandleAcceptResult(int result);
void DoConnect(); void DoConnect();
void OnConnectComplete(int connection_id, int result); void OnConnectComplete(unsigned int connection_id, int result);
void HandleConnectResult(NaiveConnection* connection, int result); void HandleConnectResult(NaiveConnection* connection, int result);
void DoRun(NaiveConnection* connection); void DoRun(NaiveConnection* connection);
void OnRunComplete(int connection_id, int result); void OnRunComplete(unsigned int connection_id, int result);
void HandleRunResult(NaiveConnection* connection, int result); void HandleRunResult(NaiveConnection* connection, int result);
void Close(int connection_id, int reason); void Close(unsigned int connection_id, int reason);
NaiveConnection* FindConnection(int connection_id); NaiveConnection* FindConnection(unsigned int connection_id);
bool HasClosedConnection(NaiveConnection* connection);
std::unique_ptr<ServerSocket> listen_socket_; std::unique_ptr<ServerSocket> listen_socket_;
Protocol protocol_; NaiveConnection::Protocol protocol_;
bool use_proxy_; bool use_padding_;
ProxyInfo proxy_info_;
SSLConfig server_ssl_config_;
SSLConfig proxy_ssl_config_;
HttpNetworkSession* session_; HttpNetworkSession* session_;
NetLogWithSource net_log_; NetLogWithSource net_log_;

View File

@ -4,6 +4,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <string> #include <string>
@ -47,12 +48,14 @@
#include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket.h"
#include "net/socket/tcp_server_socket.h" #include "net/socket/tcp_server_socket.h"
#include "net/ssl/ssl_key_logger_impl.h" #include "net/ssl/ssl_key_logger_impl.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/tools/naive/naive_proxy.h" #include "net/tools/naive/naive_proxy.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_context_builder.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/scheme_host_port.h" #include "url/scheme_host_port.h"
#include "url/url_util.h"
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h" #include "base/mac/scoped_nsautorelease_pool.h"
@ -68,15 +71,16 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("naive", ""); net::DefineNetworkTrafficAnnotation("naive", "");
struct Params { struct Params {
net::NaiveConnection::Protocol protocol;
std::string listen_addr; std::string listen_addr;
int listen_port; int listen_port;
net::NaiveProxy::Protocol protocol; bool use_padding;
bool use_proxy;
std::string proxy_url; std::string proxy_url;
std::u16string proxy_user; std::u16string proxy_user;
std::u16string proxy_pass; std::u16string proxy_pass;
std::string host_resolver_rules; std::string host_resolver_rules;
logging::LoggingSettings log_settings; logging::LoggingSettings log_settings;
base::FilePath log_path;
base::FilePath net_log_path; base::FilePath net_log_path;
base::FilePath ssl_key_path; base::FilePath ssl_key_path;
}; };
@ -103,9 +107,7 @@ std::unique_ptr<net::URLRequestContext> BuildURLRequestContext(
builder.set_net_log(net_log); builder.set_net_log(net_log);
net::ProxyConfig proxy_config; net::ProxyConfig proxy_config;
if (params.use_proxy) {
proxy_config.proxy_rules().ParseFromString(params.proxy_url); proxy_config.proxy_rules().ParseFromString(params.proxy_url);
}
auto proxy_service = auto proxy_service =
net::ConfiguredProxyResolutionService::CreateWithoutProxyResolver( net::ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
std::make_unique<net::ProxyConfigServiceFixed>( std::make_unique<net::ProxyConfigServiceFixed>(
@ -120,11 +122,20 @@ std::unique_ptr<net::URLRequestContext> BuildURLRequestContext(
auto context = builder.Build(); auto context = builder.Build();
if (params.use_proxy) { if (!params.proxy_url.empty() && !params.proxy_user.empty() &&
net::HttpNetworkSession* session = !params.proxy_pass.empty()) {
context->http_transaction_factory()->GetSession(); auto* session = context->http_transaction_factory()->GetSession();
net::HttpAuthCache* auth_cache = session->http_auth_cache(); auto* auth_cache = session->http_auth_cache();
GURL auth_origin(params.proxy_url); std::string proxy_url = params.proxy_url;
if (proxy_url.compare(0, 7, "quic://") == 0) {
proxy_url.replace(0, 4, "https");
auto* quic = context->quic_context()->params();
const auto& versions = quic::SupportedVersions();
quic->supported_versions.assign(versions.begin(), versions.end());
quic->origins_to_force_quic_on.insert(
net::HostPortPair::FromURL(GURL(proxy_url)));
}
GURL auth_origin(proxy_url);
net::AuthCredentials credentials(params.proxy_user, params.proxy_pass); net::AuthCredentials credentials(params.proxy_user, params.proxy_pass);
auth_cache->Add(auth_origin, net::HttpAuth::AUTH_PROXY, auth_cache->Add(auth_origin, net::HttpAuth::AUTH_PROXY,
/*realm=*/std::string(), net::HttpAuth::AUTH_SCHEME_BASIC, /*realm=*/std::string(), net::HttpAuth::AUTH_SCHEME_BASIC,
@ -139,92 +150,98 @@ bool ParseCommandLineFlags(Params* params) {
const base::CommandLine& line = *base::CommandLine::ForCurrentProcess(); const base::CommandLine& line = *base::CommandLine::ForCurrentProcess();
if (line.HasSwitch("h") || line.HasSwitch("help")) { if (line.HasSwitch("h") || line.HasSwitch("help")) {
LOG(INFO) << "Usage: naive [options]\n" std::cout << "Usage: naive [options]\n"
"\n" "\n"
"Options:\n" "Options:\n"
"-h, --help Show this message\n" "-h, --help Show this message\n"
"--version Print version\n" "--version Print version\n"
"--addr=<address> Address to listen on (0.0.0.0)\n" "--listen=<proto>://[addr][:port]\n"
"--port=<port> Port to listen on (1080)\n" " proto: socks, http\n"
"--proto=[socks|http] Protocol to accept (socks)\n" "--proxy=<proto>://[<user>:<pass>@]<hostname>[:<port>]\n"
"--proxy=https://<user>:<pass>@<hostname>[:<port>]\n" " proto: https, quic\n"
" Proxy specification.\n" "--padding Use padding\n"
"--log Log to stderr, otherwise no log\n" "--log[=<path>] Log to stderr, or file\n"
"--log-net-log=<path> Save NetLog\n" "--log-net-log=<path> Save NetLog\n"
"--ssl-key-log-file=<path> Save SSL keys for Wireshark\n"; "--ssl-key-log-file=<path> Save SSL keys for Wireshark\n"
<< std::endl;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
return false; return false;
} }
if (line.HasSwitch("version")) { if (line.HasSwitch("version")) {
LOG(INFO) << "Version: " << version_info::GetVersionNumber(); std::cout << "Version: " << version_info::GetVersionNumber() << std::endl;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
return false; return false;
} }
params->protocol = net::NaiveConnection::kSocks5;
params->listen_addr = "0.0.0.0"; params->listen_addr = "0.0.0.0";
if (line.HasSwitch("addr")) { params->listen_port = 1080;
params->listen_addr = line.GetSwitchValueASCII("addr"); url::AddStandardScheme("socks", url::SCHEME_WITH_HOST_AND_PORT);
} if (line.HasSwitch("listen")) {
if (params->listen_addr.empty()) { GURL url(line.GetSwitchValueASCII("listen"));
LOG(ERROR) << "Invalid --addr"; if (url.scheme() == "socks") {
params->protocol = net::NaiveConnection::kSocks5;
params->listen_port = 1080;
} else if (url.scheme() == "http") {
params->protocol = net::NaiveConnection::kHttp;
params->listen_port = 8080;
} else {
LOG(ERROR) << "Invalid scheme in --listen";
return false; return false;
} }
if (!url.host().empty()) {
params->listen_port = 1080; params->listen_addr = url.host();
if (line.HasSwitch("port")) { }
if (!base::StringToInt(line.GetSwitchValueASCII("port"), if (!url.port().empty()) {
&params->listen_port)) { if (!base::StringToInt(url.port(), &params->listen_port)) {
LOG(ERROR) << "Invalid --port"; LOG(ERROR) << "Invalid port in --listen";
return false; return false;
} }
if (params->listen_port <= 0 || if (params->listen_port <= 0 ||
params->listen_port > std::numeric_limits<uint16_t>::max()) { params->listen_port > std::numeric_limits<uint16_t>::max()) {
LOG(ERROR) << "Invalid --port"; LOG(ERROR) << "Invalid port in --listen";
return false; return false;
} }
} }
params->protocol = net::NaiveProxy::kSocks5;
if (line.HasSwitch("proto")) {
const auto& proto = line.GetSwitchValueASCII("proto");
if (proto == "socks") {
params->protocol = net::NaiveProxy::kSocks5;
} else if (proto == "http") {
params->protocol = net::NaiveProxy::kHttp;
} else {
LOG(ERROR) << "Invalid --proto";
return false;
}
} }
params->use_proxy = false; url::AddStandardScheme("quic",
url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION);
params->proxy_url = "direct://";
GURL url(line.GetSwitchValueASCII("proxy")); GURL url(line.GetSwitchValueASCII("proxy"));
if (line.HasSwitch("proxy")) { if (line.HasSwitch("proxy")) {
params->use_proxy = true;
if (!url.is_valid()) { if (!url.is_valid()) {
LOG(ERROR) << "Invalid proxy URL"; LOG(ERROR) << "Invalid proxy URL";
return false; return false;
} }
if (url.scheme() != "https") { if (url.scheme() != "https" && url.scheme() != "quic") {
LOG(ERROR) << "Must be HTTPS proxy"; LOG(ERROR) << "Must be HTTPS or QUIC proxy";
return false;
}
if (url.username().empty() || url.password().empty()) {
LOG(ERROR) << "Missing user or pass";
return false; return false;
} }
params->proxy_url = url::SchemeHostPort(url).Serialize(); params->proxy_url = url::SchemeHostPort(url).Serialize();
net::GetIdentityFromURL(url, &params->proxy_user, &params->proxy_pass); net::GetIdentityFromURL(url, &params->proxy_user, &params->proxy_pass);
} }
params->use_padding = false;
if (line.HasSwitch("padding")) {
params->use_padding = true;
}
if (line.HasSwitch("host-resolver-rules")) { if (line.HasSwitch("host-resolver-rules")) {
params->host_resolver_rules = params->host_resolver_rules =
line.GetSwitchValueASCII("host-resolver-rules"); line.GetSwitchValueASCII("host-resolver-rules");
} }
if (line.HasSwitch("log")) { if (line.HasSwitch("log")) {
params->log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; params->log_settings.logging_dest = logging::LOG_DEFAULT;
params->log_path = line.GetSwitchValuePath("log");
if (!params->log_path.empty()) {
params->log_settings.logging_dest = logging::LOG_TO_FILE;
} else if (params->log_settings.logging_dest == logging::LOG_TO_FILE) {
params->log_path = base::FilePath::FromUTF8Unsafe("naive.log");
}
params->log_settings.log_file_path = params->log_path.value().c_str();
} else { } else {
params->log_settings.logging_dest = logging::LOG_NONE; params->log_settings.logging_dest = logging::LOG_NONE;
} }
@ -340,6 +357,7 @@ int main(int argc, char* argv[]) {
} }
auto context = BuildURLRequestContext(params, net_log); auto context = BuildURLRequestContext(params, net_log);
auto* session = context->http_transaction_factory()->GetSession();
auto listen_socket = auto listen_socket =
std::make_unique<net::TCPServerSocket>(net_log, net::NetLogSource()); std::make_unique<net::TCPServerSocket>(net_log, net::NetLogSource());
@ -351,9 +369,8 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
net::NaiveProxy naive_proxy( net::NaiveProxy naive_proxy(std::move(listen_socket), params.protocol,
std::move(listen_socket), params.protocol, params.use_proxy, params.use_padding, session, kTrafficAnnotation);
context->http_transaction_factory()->GetSession(), kTrafficAnnotation);
base::RunLoop().Run(); base::RunLoop().Run();