Support specifying multiple proxies
This commit is contained in:
@ -64,8 +64,12 @@ Options:
|
||||
SOCKS-PROXY = "socks://"<HOSTNAME>[":"<PORT>]
|
||||
|
||||
Routes traffic via the proxy chain.
|
||||
The default proxy is directly connection without proxying.
|
||||
The default proxy is a direct connection without proxying.
|
||||
The last PROXY-URI is negotiated automatically for Naive padding.
|
||||
|
||||
If multiple proxies are specified, they must match the number of specified
|
||||
LISTEN-URIs, and each LISTEN-URI is routed to the PROXY matched by position.
|
||||
|
||||
Limitations:
|
||||
* QUIC proxies cannot follow TCP-based proxies in a proxy chain.
|
||||
* The user needs to ensure there is no loop in the proxy chain.
|
||||
|
||||
@ -76,17 +76,13 @@ NaiveConfig::~NaiveConfig() = default;
|
||||
|
||||
bool NaiveConfig::Parse(const base::Value::Dict& value) {
|
||||
if (const base::Value* v = value.Find("listen")) {
|
||||
listen.clear();
|
||||
std::vector<std::string> listen_strs;
|
||||
if (const std::string* str = v->GetIfString()) {
|
||||
if (!listen.emplace_back().Parse(*str)) {
|
||||
return false;
|
||||
}
|
||||
listen_strs.push_back(*str);
|
||||
} else if (const base::Value::List* strs = v->GetIfList()) {
|
||||
for (const auto& str_e : *strs) {
|
||||
if (const std::string* s = str_e.GetIfString()) {
|
||||
if (!listen.emplace_back().Parse(*s)) {
|
||||
return false;
|
||||
}
|
||||
listen_strs.push_back(*s);
|
||||
} else {
|
||||
std::cerr << "Invalid listen element" << std::endl;
|
||||
return false;
|
||||
@ -96,6 +92,14 @@ bool NaiveConfig::Parse(const base::Value::Dict& value) {
|
||||
std::cerr << "Invalid listen" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!listen_strs.empty()) {
|
||||
listen.clear();
|
||||
}
|
||||
for (const std::string& str : listen_strs) {
|
||||
if (!listen.emplace_back().Parse(str)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (const base::Value* v = value.Find("insecure-concurrency")) {
|
||||
@ -126,8 +130,24 @@ bool NaiveConfig::Parse(const base::Value::Dict& value) {
|
||||
}
|
||||
|
||||
if (const base::Value* v = value.Find("proxy")) {
|
||||
std::vector<std::string> proxy_strs;
|
||||
if (const std::string* str = v->GetIfString(); str && !str->empty()) {
|
||||
base::StringTokenizer proxy_uri_list(*str, ",");
|
||||
proxy_strs.push_back(*str);
|
||||
} else if (const base::Value::List* strs = v->GetIfList()) {
|
||||
for (const auto& str_e : *strs) {
|
||||
if (const std::string* s = str_e.GetIfString(); s && !s->empty()) {
|
||||
proxy_strs.push_back(*s);
|
||||
} else {
|
||||
std::cerr << "Invalid proxy element" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Invalid proxy argument" << std::endl;
|
||||
return false;
|
||||
}
|
||||
for (const std::string& str : proxy_strs) {
|
||||
base::StringTokenizer proxy_uri_list(str, ",");
|
||||
std::vector<ProxyServer> proxy_servers;
|
||||
bool seen_tcp = false;
|
||||
while (proxy_uri_list.GetNext()) {
|
||||
@ -187,6 +207,7 @@ bool NaiveConfig::Parse(const base::Value::Dict& value) {
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
ProxyChain proxy_chain;
|
||||
if (std::any_of(proxy_servers.begin(), proxy_servers.end(),
|
||||
[](const ProxyServer& s) { return s.is_quic(); })) {
|
||||
proxy_chain = ProxyChain::ForIpProtection(proxy_servers);
|
||||
@ -198,9 +219,7 @@ bool NaiveConfig::Parse(const base::Value::Dict& value) {
|
||||
std::cerr << "Invalid proxy chain" << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Invalid proxy argument" << std::endl;
|
||||
return false;
|
||||
proxy_chains.push_back(proxy_chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ struct NaiveConfig {
|
||||
HttpRequestHeaders extra_headers;
|
||||
|
||||
// The last server is assumed to be Naive.
|
||||
ProxyChain proxy_chain = ProxyChain::Direct();
|
||||
std::vector<ProxyChain> proxy_chains;
|
||||
std::set<HostPortPair> origins_to_force_quic_on;
|
||||
std::map<url::SchemeHostPort, AuthCredentials> auth_store;
|
||||
|
||||
|
||||
@ -172,7 +172,8 @@ std::unique_ptr<URLRequestContext> BuildCertURLRequestContext(NetLog* net_log) {
|
||||
std::unique_ptr<URLRequestContext> BuildURLRequestContext(
|
||||
const NaiveConfig& config,
|
||||
scoped_refptr<CertNetFetcherURLRequest> cert_net_fetcher,
|
||||
NetLog* net_log) {
|
||||
NetLog* net_log,
|
||||
int proxy_chain_index = 0) {
|
||||
URLRequestContextBuilder builder;
|
||||
|
||||
builder.DisableHttpCache();
|
||||
@ -212,8 +213,13 @@ std::unique_ptr<URLRequestContext> BuildURLRequestContext(
|
||||
ProxyConfig proxy_config;
|
||||
proxy_config.proxy_rules().type =
|
||||
net::ProxyConfig::ProxyRules::Type::PROXY_LIST;
|
||||
proxy_config.proxy_rules().single_proxies.SetSingleProxyChain(
|
||||
config.proxy_chain);
|
||||
if (config.proxy_chains.empty()) {
|
||||
proxy_config.proxy_rules().single_proxies.SetSingleProxyChain(
|
||||
ProxyChain::Direct());
|
||||
} else {
|
||||
proxy_config.proxy_rules().single_proxies.SetSingleProxyChain(
|
||||
config.proxy_chains.at(proxy_chain_index));
|
||||
}
|
||||
LOG(INFO) << "Proxying via "
|
||||
<< proxy_config.proxy_rules().single_proxies.ToDebugString();
|
||||
auto proxy_service =
|
||||
@ -456,14 +462,20 @@ int main(int argc, char* argv[]) {
|
||||
cert_net_fetcher = base::MakeRefCounted<net::CertNetFetcherURLRequest>();
|
||||
cert_net_fetcher->SetURLRequestContext(cert_context.get());
|
||||
#endif
|
||||
auto context =
|
||||
net::BuildURLRequestContext(config, std::move(cert_net_fetcher), net_log);
|
||||
auto* session = context->http_transaction_factory()->GetSession();
|
||||
|
||||
if (config.proxy_chains.size() >= 2 &&
|
||||
config.proxy_chains.size() != config.listen.size()) {
|
||||
std::cerr << "Listen addresses do not match multiple proxy chains"
|
||||
<< std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<net::NaiveProxy>> naive_proxies;
|
||||
std::vector<std::unique_ptr<net::URLRequestContext>> contexts;
|
||||
std::unique_ptr<net::RedirectResolver> resolver;
|
||||
|
||||
for (const net::NaiveListenConfig& listen_config : config.listen) {
|
||||
for (size_t listen_i = 0; listen_i < config.listen.size(); ++listen_i) {
|
||||
const net::NaiveListenConfig& listen_config = config.listen[listen_i];
|
||||
auto listen_socket =
|
||||
std::make_unique<net::TCPServerSocket>(net_log, net::NetLogSource());
|
||||
|
||||
@ -503,6 +515,15 @@ int main(int argc, char* argv[]) {
|
||||
config.resolver_prefix);
|
||||
}
|
||||
|
||||
if (config.proxy_chains.size() >= 2) {
|
||||
contexts.push_back(net::BuildURLRequestContext(
|
||||
config, std::move(cert_net_fetcher), net_log, listen_i));
|
||||
} else if (contexts.empty()) {
|
||||
contexts.push_back(net::BuildURLRequestContext(
|
||||
config, std::move(cert_net_fetcher), net_log));
|
||||
}
|
||||
auto& context = contexts.back();
|
||||
auto* session = context->http_transaction_factory()->GetSession();
|
||||
auto naive_proxy = std::make_unique<net::NaiveProxy>(
|
||||
std::move(listen_socket), listen_config.protocol, listen_config.user,
|
||||
listen_config.pass, config.insecure_concurrency, resolver.get(),
|
||||
|
||||
@ -245,6 +245,16 @@ test_naive('Multiple listens - config file', 'http://127.0.0.1:{PORT2}',
|
||||
config_content='"listen":["socks://:{PORT1}", "http://:{PORT2}"],"log":""',
|
||||
config_file='multiple-listen.json')
|
||||
|
||||
test_naive('Multiple proxies - command line', 'socks5h://127.0.0.1:{PORT1}',
|
||||
'--log --listen=socks://:{PORT1} --listen=socks://:{PORT2} --proxy=http://127.0.0.1:{PORT3} --proxy=http://127.0.0.1:{PORT4}',
|
||||
'--log --listen=http://:{PORT3} --listen=http://:{PORT4} --proxy=socks://127.0.0.1:{PORT5}',
|
||||
'--log --listen=socks://:{PORT5}')
|
||||
|
||||
test_naive('Multiple proxies - command line', 'socks5h://127.0.0.1:{PORT2}',
|
||||
'--log --listen=socks://:{PORT1} --listen=socks://:{PORT2} --proxy=http://127.0.0.1:{PORT3} --proxy=http://127.0.0.1:{PORT4}',
|
||||
'--log --listen=http://:{PORT3} --listen=http://:{PORT4} --proxy=socks://127.0.0.1:{PORT5}',
|
||||
'--log --listen=socks://:{PORT5}')
|
||||
|
||||
test_naive('Trivial - listen scheme only', 'socks5h://127.0.0.1:1080',
|
||||
'--log --listen=socks://')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user