Add --extra-headers option

This commit is contained in:
klzgrad 2020-05-21 01:47:03 +08:00
parent ce80501ac2
commit f00c94e4d7

View File

@ -15,6 +15,7 @@
#include "base/json/json_file_value_serializer.h" #include "base/json/json_file_value_serializer.h"
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/rand_util.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
@ -35,6 +36,8 @@
#include "net/http/http_auth.h" #include "net/http/http_auth.h"
#include "net/http/http_auth_cache.h" #include "net/http/http_auth_cache.h"
#include "net/http/http_network_session.h" #include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_transaction_factory.h" #include "net/http/http_transaction_factory.h"
#include "net/log/file_net_log_observer.h" #include "net/log/file_net_log_observer.h"
#include "net/log/net_log.h" #include "net/log/net_log.h"
@ -78,6 +81,7 @@ struct CommandLine {
std::string listen; std::string listen;
std::string proxy; std::string proxy;
bool padding; bool padding;
std::string extra_headers;
std::string host_resolver_rules; std::string host_resolver_rules;
std::string resolver_range; std::string resolver_range;
bool no_log; bool no_log;
@ -91,6 +95,7 @@ struct Params {
std::string listen_addr; std::string listen_addr;
int listen_port; int listen_port;
bool use_padding; bool use_padding;
net::HttpRequestHeaders extra_headers;
std::string proxy_url; std::string proxy_url;
std::u16string proxy_user; std::u16string proxy_user;
std::u16string proxy_pass; std::u16string proxy_pass;
@ -114,79 +119,6 @@ std::unique_ptr<base::Value> GetConstants() {
return constants_dict; return constants_dict;
} }
std::unique_ptr<net::URLRequestContext> BuildCertURLRequestContext(
net::NetLog* net_log) {
net::URLRequestContextBuilder builder;
builder.DisableHttpCache();
builder.set_net_log(net_log);
net::ProxyConfig proxy_config;
auto proxy_service =
net::ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
std::make_unique<net::ProxyConfigServiceFixed>(
net::ProxyConfigWithAnnotation(proxy_config, kTrafficAnnotation)),
net_log);
proxy_service->ForceReloadProxyConfig();
builder.set_proxy_resolution_service(std::move(proxy_service));
return builder.Build();
}
// Builds a URLRequestContext assuming there's only a single loop.
std::unique_ptr<net::URLRequestContext> BuildURLRequestContext(
const Params& params,
scoped_refptr<net::CertNetFetcherURLRequest> cert_net_fetcher,
net::NetLog* net_log) {
net::URLRequestContextBuilder builder;
builder.DisableHttpCache();
builder.set_net_log(net_log);
net::ProxyConfig proxy_config;
proxy_config.proxy_rules().ParseFromString(params.proxy_url);
LOG(INFO) << "Proxying via " << params.proxy_url;
auto proxy_service =
net::ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
std::make_unique<net::ProxyConfigServiceFixed>(
net::ProxyConfigWithAnnotation(proxy_config, kTrafficAnnotation)),
net_log);
proxy_service->ForceReloadProxyConfig();
builder.set_proxy_resolution_service(std::move(proxy_service));
if (!params.host_resolver_rules.empty()) {
builder.set_host_mapping_rules(params.host_resolver_rules);
}
builder.SetCertVerifier(
net::CertVerifier::CreateDefault(std::move(cert_net_fetcher)));
auto context = builder.Build();
if (!params.proxy_url.empty() && !params.proxy_user.empty() &&
!params.proxy_pass.empty()) {
auto* session = context->http_transaction_factory()->GetSession();
auto* auth_cache = session->http_auth_cache();
std::string proxy_url = params.proxy_url;
GURL proxy_gurl(proxy_url);
if (proxy_url.compare(0, 7, "quic://") == 0) {
proxy_url.replace(0, 4, "https");
auto* quic = context->quic_context()->params();
quic->supported_versions = {quic::ParsedQuicVersion::RFCv1()};
quic->origins_to_force_quic_on.insert(
net::HostPortPair::FromURL(proxy_gurl));
}
url::SchemeHostPort auth_origin(proxy_gurl);
net::AuthCredentials credentials(params.proxy_user, params.proxy_pass);
auth_cache->Add(auth_origin, net::HttpAuth::AUTH_PROXY,
/*realm=*/std::string(), net::HttpAuth::AUTH_SCHEME_BASIC,
net::NetworkIsolationKey(), /*challenge=*/"Basic",
credentials, /*path=*/"/");
}
return context;
}
void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) { void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) {
if (proc.HasSwitch("h") || proc.HasSwitch("help")) { if (proc.HasSwitch("h") || proc.HasSwitch("help")) {
std::cout << "Usage: naive { OPTIONS | config.json }\n" std::cout << "Usage: naive { OPTIONS | config.json }\n"
@ -200,6 +132,7 @@ void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) {
"--proxy=<proto>://[<user>:<pass>@]<hostname>[:<port>]\n" "--proxy=<proto>://[<user>:<pass>@]<hostname>[:<port>]\n"
" proto: https, quic\n" " proto: https, quic\n"
"--padding Use padding\n" "--padding Use padding\n"
"--extra-headers=... Extra headers split by CRLF\n"
"--host-resolver-rules=... Resolver rules\n" "--host-resolver-rules=... Resolver rules\n"
"--resolver-range=... Redirect resolver range\n" "--resolver-range=... Redirect resolver range\n"
"--log[=<path>] Log to stderr, or file\n" "--log[=<path>] Log to stderr, or file\n"
@ -217,6 +150,7 @@ void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) {
cmdline->listen = proc.GetSwitchValueASCII("listen"); cmdline->listen = proc.GetSwitchValueASCII("listen");
cmdline->proxy = proc.GetSwitchValueASCII("proxy"); cmdline->proxy = proc.GetSwitchValueASCII("proxy");
cmdline->padding = proc.HasSwitch("padding"); cmdline->padding = proc.HasSwitch("padding");
cmdline->extra_headers = proc.GetSwitchValueASCII("extra-headers");
cmdline->host_resolver_rules = cmdline->host_resolver_rules =
proc.GetSwitchValueASCII("host-resolver-rules"); proc.GetSwitchValueASCII("host-resolver-rules");
cmdline->resolver_range = proc.GetSwitchValueASCII("resolver-range"); cmdline->resolver_range = proc.GetSwitchValueASCII("resolver-range");
@ -241,36 +175,41 @@ void GetCommandLineFromConfig(const base::FilePath& config_path,
std::cerr << "Invalid config format" << std::endl; std::cerr << "Invalid config format" << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (value->FindKeyOfType("listen", base::Value::Type::STRING)) { const auto* listen = value->FindStringKey("listen");
cmdline->listen = value->FindKey("listen")->GetString(); if (listen) {
cmdline->listen = *listen;
} }
if (value->FindKeyOfType("proxy", base::Value::Type::STRING)) { const auto* proxy = value->FindStringKey("proxy");
cmdline->proxy = value->FindKey("proxy")->GetString(); if (proxy) {
cmdline->proxy = *proxy;
} }
cmdline->padding = false; cmdline->padding = value->FindBoolKey("padding").value_or(false);
if (value->FindKeyOfType("padding", base::Value::Type::BOOLEAN)) { const auto* extra_headers = value->FindStringKey("extra-headers");
cmdline->padding = value->FindKey("padding")->GetBool(); if (extra_headers) {
cmdline->extra_headers = *extra_headers;
} }
if (value->FindKeyOfType("host-resolver-rules", base::Value::Type::STRING)) { const auto* host_resolver_rules = value->FindStringKey("host-resolver-rules");
cmdline->host_resolver_rules = if (host_resolver_rules) {
value->FindKey("host-resolver-rules")->GetString(); cmdline->host_resolver_rules = *host_resolver_rules;
} }
if (value->FindKeyOfType("resolver-range", base::Value::Type::STRING)) { const auto* resolver_range = value->FindStringKey("resolver-range");
cmdline->resolver_range = value->FindKey("resolver-range")->GetString(); if (resolver_range) {
cmdline->resolver_range = *resolver_range;
} }
cmdline->no_log = true; cmdline->no_log = true;
if (value->FindKeyOfType("log", base::Value::Type::STRING)) { const auto* log = value->FindStringKey("log");
if (log) {
cmdline->no_log = false; cmdline->no_log = false;
cmdline->log = cmdline->log = base::FilePath::FromUTF8Unsafe(*log);
base::FilePath::FromUTF8Unsafe(value->FindKey("log")->GetString());
} }
if (value->FindKeyOfType("log-net-log", base::Value::Type::STRING)) { const auto* log_net_log = value->FindStringKey("log-net-log");
cmdline->log_net_log = base::FilePath::FromUTF8Unsafe( if (log_net_log) {
value->FindKey("log-net-log")->GetString()); cmdline->log_net_log = base::FilePath::FromUTF8Unsafe(*log_net_log);
} }
if (value->FindKeyOfType("ssl-key-log-file", base::Value::Type::STRING)) { const auto* ssl_key_log_file = value->FindStringKey("ssl-key-log-file");
cmdline->ssl_key_log_file = base::FilePath::FromUTF8Unsafe( if (ssl_key_log_file) {
value->FindKey("ssl-key-log-file")->GetString()); cmdline->ssl_key_log_file =
base::FilePath::FromUTF8Unsafe(*ssl_key_log_file);
} }
} }
@ -343,6 +282,8 @@ bool ParseCommandLine(const CommandLine& cmdline, Params* params) {
params->use_padding = cmdline.padding; params->use_padding = cmdline.padding;
params->extra_headers.AddHeadersFromString(cmdline.extra_headers);
params->host_resolver_rules = cmdline.host_resolver_rules; params->host_resolver_rules = cmdline.host_resolver_rules;
if (params->protocol == net::NaiveConnection::kRedir) { if (params->protocol == net::NaiveConnection::kRedir) {
@ -419,7 +360,110 @@ class PrintingLogObserver : public NetLog::ThreadSafeObserver {
<< ": " << event_phase << params_str; << ": " << event_phase << params_str;
} }
}; };
} // namespace
class ProxyInfo;
class ProxyServer;
namespace {
class NaiveProxyDelegate : public ProxyDelegate {
public:
NaiveProxyDelegate(const Params& params) : params_(params) {}
void OnResolveProxy(const GURL& url,
const std::string& method,
const ProxyRetryInfoMap& proxy_retry_info,
ProxyInfo* result) override {}
void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
HttpRequestHeaders* extra_headers) override {
extra_headers->SetHeader("Padding",
std::string(base::RandInt(16, 32), '.'));
extra_headers->MergeFrom(params_.extra_headers);
}
Error OnTunnelHeadersReceived(
const ProxyServer& proxy_server,
const HttpResponseHeaders& response_headers) override {
return OK;
}
private:
const Params& params_;
};
std::unique_ptr<URLRequestContext> BuildCertURLRequestContext(NetLog* net_log) {
URLRequestContextBuilder builder;
builder.DisableHttpCache();
builder.set_net_log(net_log);
ProxyConfig proxy_config;
auto proxy_service =
ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
std::make_unique<ProxyConfigServiceFixed>(
ProxyConfigWithAnnotation(proxy_config, kTrafficAnnotation)),
net_log);
proxy_service->ForceReloadProxyConfig();
builder.set_proxy_resolution_service(std::move(proxy_service));
return builder.Build();
}
// Builds a URLRequestContext assuming there's only a single loop.
std::unique_ptr<URLRequestContext> BuildURLRequestContext(
const Params& params,
scoped_refptr<CertNetFetcherURLRequest> cert_net_fetcher,
NetLog* net_log) {
URLRequestContextBuilder builder;
builder.DisableHttpCache();
builder.set_net_log(net_log);
ProxyConfig proxy_config;
proxy_config.proxy_rules().ParseFromString(params.proxy_url);
LOG(INFO) << "Proxying via " << params.proxy_url;
auto proxy_service =
ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
std::make_unique<ProxyConfigServiceFixed>(
ProxyConfigWithAnnotation(proxy_config, kTrafficAnnotation)),
net_log);
proxy_service->ForceReloadProxyConfig();
builder.set_proxy_resolution_service(std::move(proxy_service));
if (!params.host_resolver_rules.empty()) {
builder.set_host_mapping_rules(params.host_resolver_rules);
}
builder.SetCertVerifier(
CertVerifier::CreateDefault(std::move(cert_net_fetcher)));
builder.set_proxy_delegate(std::make_unique<NaiveProxyDelegate>(params));
auto context = builder.Build();
if (!params.proxy_url.empty() && !params.proxy_user.empty() &&
!params.proxy_pass.empty()) {
auto* session = context->http_transaction_factory()->GetSession();
auto* auth_cache = session->http_auth_cache();
std::string proxy_url = params.proxy_url;
GURL proxy_gurl(proxy_url);
if (proxy_url.compare(0, 7, "quic://") == 0) {
proxy_url.replace(0, 4, "https");
auto* quic = context->quic_context()->params();
quic->supported_versions = {quic::ParsedQuicVersion::RFCv1()};
quic->origins_to_force_quic_on.insert(
net::HostPortPair::FromURL(proxy_gurl));
}
url::SchemeHostPort auth_origin(proxy_gurl);
AuthCredentials credentials(params.proxy_user, params.proxy_pass);
auth_cache->Add(auth_origin, HttpAuth::AUTH_PROXY,
/*realm=*/{}, HttpAuth::AUTH_SCHEME_BASIC, {},
/*challenge=*/"Basic", credentials, /*path=*/"/");
}
return context;
}
} // namespace } // namespace
} // namespace net } // namespace net
@ -490,14 +534,14 @@ int main(int argc, char* argv[]) {
net::NetLogCaptureMode::kDefault); net::NetLogCaptureMode::kDefault);
} }
auto cert_context = BuildCertURLRequestContext(net_log); auto cert_context = net::BuildCertURLRequestContext(net_log);
scoped_refptr<net::CertNetFetcherURLRequest> cert_net_fetcher; scoped_refptr<net::CertNetFetcherURLRequest> cert_net_fetcher;
#if defined(OS_LINUX) || defined(OS_MAC) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_MAC) || defined(OS_ANDROID)
cert_net_fetcher = base::MakeRefCounted<net::CertNetFetcherURLRequest>(); cert_net_fetcher = base::MakeRefCounted<net::CertNetFetcherURLRequest>();
cert_net_fetcher->SetURLRequestContext(cert_context.get()); cert_net_fetcher->SetURLRequestContext(cert_context.get());
#endif #endif
auto context = auto context =
BuildURLRequestContext(params, std::move(cert_net_fetcher), net_log); net::BuildURLRequestContext(params, std::move(cert_net_fetcher), net_log);
auto* session = context->http_transaction_factory()->GetSession(); auto* session = context->http_transaction_factory()->GetSession();
auto listen_socket = auto listen_socket =