mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
Redirect DNS for redir://
Run a fake stub DNS resolver at the same port with redir://.
This commit is contained in:
parent
92ee6dee7d
commit
7011614753
@ -2363,6 +2363,8 @@ if (!is_ios && !is_android) {
|
|||||||
"tools/naive/naive_proxy_bin.cc",
|
"tools/naive/naive_proxy_bin.cc",
|
||||||
"tools/naive/http_proxy_socket.cc",
|
"tools/naive/http_proxy_socket.cc",
|
||||||
"tools/naive/http_proxy_socket.h",
|
"tools/naive/http_proxy_socket.h",
|
||||||
|
"tools/naive/redirect_resolver.h",
|
||||||
|
"tools/naive/redirect_resolver.cc",
|
||||||
"tools/naive/socks5_server_socket.cc",
|
"tools/naive/socks5_server_socket.cc",
|
||||||
"tools/naive/socks5_server_socket.h",
|
"tools/naive/socks5_server_socket.h",
|
||||||
]
|
]
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#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/http_proxy_socket.h"
|
||||||
|
#include "net/tools/naive/redirect_resolver.h"
|
||||||
#include "net/tools/naive/socks5_server_socket.h"
|
#include "net/tools/naive/socks5_server_socket.h"
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
@ -52,6 +53,7 @@ NaiveConnection::NaiveConnection(
|
|||||||
const ProxyInfo& proxy_info,
|
const ProxyInfo& proxy_info,
|
||||||
const SSLConfig& server_ssl_config,
|
const SSLConfig& server_ssl_config,
|
||||||
const SSLConfig& proxy_ssl_config,
|
const SSLConfig& proxy_ssl_config,
|
||||||
|
RedirectResolver* resolver,
|
||||||
HttpNetworkSession* session,
|
HttpNetworkSession* session,
|
||||||
const NetLogWithSource& net_log,
|
const NetLogWithSource& net_log,
|
||||||
std::unique_ptr<StreamSocket> accepted_socket,
|
std::unique_ptr<StreamSocket> accepted_socket,
|
||||||
@ -62,6 +64,7 @@ NaiveConnection::NaiveConnection(
|
|||||||
proxy_info_(proxy_info),
|
proxy_info_(proxy_info),
|
||||||
server_ssl_config_(server_ssl_config),
|
server_ssl_config_(server_ssl_config),
|
||||||
proxy_ssl_config_(proxy_ssl_config),
|
proxy_ssl_config_(proxy_ssl_config),
|
||||||
|
resolver_(resolver),
|
||||||
session_(session),
|
session_(session),
|
||||||
net_log_(net_log),
|
net_log_(net_log),
|
||||||
next_state_(STATE_NONE),
|
next_state_(STATE_NONE),
|
||||||
@ -208,7 +211,17 @@ int NaiveConnection::DoConnectServer() {
|
|||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
IPEndPoint ipe;
|
IPEndPoint ipe;
|
||||||
if (ipe.FromSockAddr(dst.addr, dst.addr_len)) {
|
if (ipe.FromSockAddr(dst.addr, dst.addr_len)) {
|
||||||
|
const auto& addr = ipe.address();
|
||||||
|
auto name = resolver_->FindNameByAddress(addr);
|
||||||
|
if (!name.empty()) {
|
||||||
|
origin = HostPortPair(name, ipe.port());
|
||||||
|
} else if (!resolver_->IsInResolvedRange(addr)) {
|
||||||
origin = HostPortPair::FromIPEndPoint(ipe);
|
origin = HostPortPair::FromIPEndPoint(ipe);
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Connection " << id_ << " to unresolved name for "
|
||||||
|
<< addr.ToString();
|
||||||
|
return ERR_ADDRESS_INVALID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -27,6 +27,7 @@ class ProxyInfo;
|
|||||||
class StreamSocket;
|
class StreamSocket;
|
||||||
struct NetworkTrafficAnnotationTag;
|
struct NetworkTrafficAnnotationTag;
|
||||||
struct SSLConfig;
|
struct SSLConfig;
|
||||||
|
class RedirectResolver;
|
||||||
|
|
||||||
class NaiveConnection {
|
class NaiveConnection {
|
||||||
public:
|
public:
|
||||||
@ -52,6 +53,7 @@ class NaiveConnection {
|
|||||||
const ProxyInfo& proxy_info,
|
const ProxyInfo& proxy_info,
|
||||||
const SSLConfig& server_ssl_config,
|
const SSLConfig& server_ssl_config,
|
||||||
const SSLConfig& proxy_ssl_config,
|
const SSLConfig& proxy_ssl_config,
|
||||||
|
RedirectResolver* resolver,
|
||||||
HttpNetworkSession* session,
|
HttpNetworkSession* session,
|
||||||
const NetLogWithSource& net_log,
|
const NetLogWithSource& net_log,
|
||||||
std::unique_ptr<StreamSocket> accepted_socket,
|
std::unique_ptr<StreamSocket> accepted_socket,
|
||||||
@ -103,6 +105,7 @@ class NaiveConnection {
|
|||||||
const ProxyInfo& proxy_info_;
|
const ProxyInfo& proxy_info_;
|
||||||
const SSLConfig& server_ssl_config_;
|
const SSLConfig& server_ssl_config_;
|
||||||
const SSLConfig& proxy_ssl_config_;
|
const SSLConfig& proxy_ssl_config_;
|
||||||
|
RedirectResolver* resolver_;
|
||||||
HttpNetworkSession* session_;
|
HttpNetworkSession* session_;
|
||||||
const NetLogWithSource& net_log_;
|
const NetLogWithSource& net_log_;
|
||||||
|
|
||||||
|
@ -27,11 +27,13 @@ namespace net {
|
|||||||
NaiveProxy::NaiveProxy(std::unique_ptr<ServerSocket> listen_socket,
|
NaiveProxy::NaiveProxy(std::unique_ptr<ServerSocket> listen_socket,
|
||||||
NaiveConnection::Protocol protocol,
|
NaiveConnection::Protocol protocol,
|
||||||
bool use_padding,
|
bool use_padding,
|
||||||
|
RedirectResolver* resolver,
|
||||||
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_padding_(use_padding),
|
use_padding_(use_padding),
|
||||||
|
resolver_(resolver),
|
||||||
session_(session),
|
session_(session),
|
||||||
net_log_(
|
net_log_(
|
||||||
NetLogWithSource::Make(session->net_log(), NetLogSourceType::NONE)),
|
NetLogWithSource::Make(session->net_log(), NetLogSourceType::NONE)),
|
||||||
@ -107,7 +109,7 @@ void NaiveProxy::DoConnect() {
|
|||||||
}
|
}
|
||||||
auto connection_ptr = std::make_unique<NaiveConnection>(
|
auto connection_ptr = std::make_unique<NaiveConnection>(
|
||||||
++last_id_, protocol_, pad_direction, proxy_info_, server_ssl_config_,
|
++last_id_, protocol_, pad_direction, proxy_info_, server_ssl_config_,
|
||||||
proxy_ssl_config_, session_, net_log_, std::move(socket),
|
proxy_ssl_config_, resolver_, session_, net_log_, std::move(socket),
|
||||||
traffic_annotation_);
|
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);
|
||||||
|
@ -25,12 +25,14 @@ class NaiveConnection;
|
|||||||
class ServerSocket;
|
class ServerSocket;
|
||||||
class StreamSocket;
|
class StreamSocket;
|
||||||
struct NetworkTrafficAnnotationTag;
|
struct NetworkTrafficAnnotationTag;
|
||||||
|
class RedirectResolver;
|
||||||
|
|
||||||
class NaiveProxy {
|
class NaiveProxy {
|
||||||
public:
|
public:
|
||||||
NaiveProxy(std::unique_ptr<ServerSocket> server_socket,
|
NaiveProxy(std::unique_ptr<ServerSocket> server_socket,
|
||||||
NaiveConnection::Protocol protocol,
|
NaiveConnection::Protocol protocol,
|
||||||
bool use_padding,
|
bool use_padding,
|
||||||
|
RedirectResolver* resolver,
|
||||||
HttpNetworkSession* session,
|
HttpNetworkSession* session,
|
||||||
const NetworkTrafficAnnotationTag& traffic_annotation);
|
const NetworkTrafficAnnotationTag& traffic_annotation);
|
||||||
~NaiveProxy();
|
~NaiveProxy();
|
||||||
@ -58,6 +60,7 @@ class NaiveProxy {
|
|||||||
ProxyInfo proxy_info_;
|
ProxyInfo proxy_info_;
|
||||||
SSLConfig server_ssl_config_;
|
SSLConfig server_ssl_config_;
|
||||||
SSLConfig proxy_ssl_config_;
|
SSLConfig proxy_ssl_config_;
|
||||||
|
RedirectResolver* resolver_;
|
||||||
HttpNetworkSession* session_;
|
HttpNetworkSession* session_;
|
||||||
NetLogWithSource net_log_;
|
NetLogWithSource net_log_;
|
||||||
|
|
||||||
|
@ -47,8 +47,10 @@
|
|||||||
#include "net/socket/client_socket_pool_manager.h"
|
#include "net/socket/client_socket_pool_manager.h"
|
||||||
#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/socket/udp_server_socket.h"
|
||||||
#include "net/ssl/ssl_key_logger_impl.h"
|
#include "net/ssl/ssl_key_logger_impl.h"
|
||||||
#include "net/tools/naive/naive_proxy.h"
|
#include "net/tools/naive/naive_proxy.h"
|
||||||
|
#include "net/tools/naive/redirect_resolver.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"
|
||||||
@ -74,6 +76,7 @@ struct CommandLine {
|
|||||||
std::string proxy;
|
std::string proxy;
|
||||||
bool padding;
|
bool padding;
|
||||||
std::string host_resolver_rules;
|
std::string host_resolver_rules;
|
||||||
|
std::string resolver_range;
|
||||||
bool no_log;
|
bool no_log;
|
||||||
base::FilePath log;
|
base::FilePath log;
|
||||||
base::FilePath log_net_log;
|
base::FilePath log_net_log;
|
||||||
@ -89,6 +92,8 @@ struct Params {
|
|||||||
std::string proxy_user;
|
std::string proxy_user;
|
||||||
std::string proxy_pass;
|
std::string proxy_pass;
|
||||||
std::string host_resolver_rules;
|
std::string host_resolver_rules;
|
||||||
|
net::IPAddress resolver_range;
|
||||||
|
size_t resolver_prefix;
|
||||||
logging::LoggingSettings log_settings;
|
logging::LoggingSettings log_settings;
|
||||||
base::FilePath log_path;
|
base::FilePath log_path;
|
||||||
base::FilePath net_log_path;
|
base::FilePath net_log_path;
|
||||||
@ -176,6 +181,7 @@ void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) {
|
|||||||
" proto: https, quic\n"
|
" proto: https, quic\n"
|
||||||
"--padding Use padding\n"
|
"--padding Use padding\n"
|
||||||
"--host-resolver-rules=... Resolver rules\n"
|
"--host-resolver-rules=... Resolver rules\n"
|
||||||
|
"--resolver-range=... Redirect resolver range\n"
|
||||||
"--log[=<path>] Log to stderr, or file\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"
|
||||||
@ -193,6 +199,7 @@ void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) {
|
|||||||
cmdline->padding = proc.HasSwitch("padding");
|
cmdline->padding = proc.HasSwitch("padding");
|
||||||
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->no_log = !proc.HasSwitch("log");
|
cmdline->no_log = !proc.HasSwitch("log");
|
||||||
cmdline->log = proc.GetSwitchValuePath("log");
|
cmdline->log = proc.GetSwitchValuePath("log");
|
||||||
cmdline->log_net_log = proc.GetSwitchValuePath("log-net-log");
|
cmdline->log_net_log = proc.GetSwitchValuePath("log-net-log");
|
||||||
@ -228,6 +235,9 @@ void GetCommandLineFromConfig(const base::FilePath& config_path,
|
|||||||
cmdline->host_resolver_rules =
|
cmdline->host_resolver_rules =
|
||||||
value->FindKey("host-resolver-rules")->GetString();
|
value->FindKey("host-resolver-rules")->GetString();
|
||||||
}
|
}
|
||||||
|
if (value->FindKeyOfType("resolver-range", base::Value::Type::STRING)) {
|
||||||
|
cmdline->resolver_range = value->FindKey("resolver-range")->GetString();
|
||||||
|
}
|
||||||
cmdline->no_log = true;
|
cmdline->no_log = true;
|
||||||
if (value->FindKeyOfType("log", base::Value::Type::STRING)) {
|
if (value->FindKeyOfType("log", base::Value::Type::STRING)) {
|
||||||
cmdline->no_log = false;
|
cmdline->no_log = false;
|
||||||
@ -267,8 +277,13 @@ bool ParseCommandLine(const CommandLine& cmdline, Params* params) {
|
|||||||
params->protocol = net::NaiveConnection::kHttp;
|
params->protocol = net::NaiveConnection::kHttp;
|
||||||
params->listen_port = 8080;
|
params->listen_port = 8080;
|
||||||
} else if (url.scheme() == "redir") {
|
} else if (url.scheme() == "redir") {
|
||||||
|
#if defined(OS_LINUX)
|
||||||
params->protocol = net::NaiveConnection::kRedir;
|
params->protocol = net::NaiveConnection::kRedir;
|
||||||
params->listen_port = 1080;
|
params->listen_port = 1080;
|
||||||
|
#else
|
||||||
|
std::cerr << "Redir protocol only supports Linux." << std::endl;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Invalid scheme in --listen" << std::endl;
|
std::cerr << "Invalid scheme in --listen" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -311,6 +326,22 @@ bool ParseCommandLine(const CommandLine& cmdline, Params* params) {
|
|||||||
|
|
||||||
params->host_resolver_rules = cmdline.host_resolver_rules;
|
params->host_resolver_rules = cmdline.host_resolver_rules;
|
||||||
|
|
||||||
|
if (params->protocol == net::NaiveConnection::kRedir) {
|
||||||
|
std::string range = "100.64.0.0/10";
|
||||||
|
if (!cmdline.resolver_range.empty())
|
||||||
|
range = cmdline.resolver_range;
|
||||||
|
|
||||||
|
if (!net::ParseCIDRBlock(range, ¶ms->resolver_range,
|
||||||
|
¶ms->resolver_prefix)) {
|
||||||
|
std::cerr << "Invalid resolver range" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (params->resolver_range.IsIPv6()) {
|
||||||
|
std::cerr << "IPv6 resolver range not supported" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!cmdline.no_log) {
|
if (!cmdline.no_log) {
|
||||||
if (!params->log_path.empty()) {
|
if (!params->log_path.empty()) {
|
||||||
params->log_settings.logging_dest = logging::LOG_TO_FILE;
|
params->log_settings.logging_dest = logging::LOG_TO_FILE;
|
||||||
@ -459,8 +490,32 @@ int main(int argc, char* argv[]) {
|
|||||||
LOG(INFO) << "Listening on " << params.listen_addr << ":"
|
LOG(INFO) << "Listening on " << params.listen_addr << ":"
|
||||||
<< params.listen_port;
|
<< params.listen_port;
|
||||||
|
|
||||||
|
std::unique_ptr<net::RedirectResolver> resolver;
|
||||||
|
if (params.protocol == net::NaiveConnection::kRedir) {
|
||||||
|
auto resolver_socket =
|
||||||
|
std::make_unique<net::UDPServerSocket>(net_log, net::NetLogSource());
|
||||||
|
resolver_socket->AllowAddressReuse();
|
||||||
|
net::IPAddress listen_addr;
|
||||||
|
if (!listen_addr.AssignFromIPLiteral(params.listen_addr)) {
|
||||||
|
LOG(ERROR) << "Failed to open resolver: " << net::ERR_ADDRESS_INVALID;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = resolver_socket->Listen(
|
||||||
|
net::IPEndPoint(listen_addr, params.listen_port));
|
||||||
|
if (result != net::OK) {
|
||||||
|
LOG(ERROR) << "Failed to open resolver: " << result;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver = std::make_unique<net::RedirectResolver>(
|
||||||
|
std::move(resolver_socket), params.resolver_range,
|
||||||
|
params.resolver_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
net::NaiveProxy naive_proxy(std::move(listen_socket), params.protocol,
|
net::NaiveProxy naive_proxy(std::move(listen_socket), params.protocol,
|
||||||
params.use_padding, session, kTrafficAnnotation);
|
params.use_padding, resolver.get(), session,
|
||||||
|
kTrafficAnnotation);
|
||||||
|
|
||||||
base::RunLoop().Run();
|
base::RunLoop().Run();
|
||||||
|
|
||||||
|
241
src/net/tools/naive/redirect_resolver.cc
Normal file
241
src/net/tools/naive/redirect_resolver.cc
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
// Copyright 2019 klzgrad <kizdiv@gmail.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "net/tools/naive/redirect_resolver.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/optional.h"
|
||||||
|
#include "base/threading/thread_task_runner_handle.h"
|
||||||
|
#include "net/base/io_buffer.h"
|
||||||
|
#include "net/base/net_errors.h"
|
||||||
|
#include "net/dns/dns_query.h"
|
||||||
|
#include "net/dns/dns_response.h"
|
||||||
|
#include "net/dns/dns_util.h"
|
||||||
|
#include "net/socket/datagram_server_socket.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int kUdpReadBufferSize = 1024;
|
||||||
|
constexpr int kResolutionTtl = 60;
|
||||||
|
constexpr int kResolutionRecycleTime = 60 * 5;
|
||||||
|
|
||||||
|
std::string PackedIPv4ToString(uint32_t addr) {
|
||||||
|
return net::IPAddress(addr >> 24, addr >> 16, addr >> 8, addr).ToString();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace net {
|
||||||
|
|
||||||
|
Resolution::Resolution() = default;
|
||||||
|
|
||||||
|
Resolution::~Resolution() = default;
|
||||||
|
|
||||||
|
RedirectResolver::RedirectResolver(std::unique_ptr<DatagramServerSocket> socket,
|
||||||
|
const IPAddress& range,
|
||||||
|
size_t prefix)
|
||||||
|
: socket_(std::move(socket)),
|
||||||
|
range_(range),
|
||||||
|
prefix_(prefix),
|
||||||
|
offset_(0),
|
||||||
|
buffer_(base::MakeRefCounted<IOBufferWithSize>(kUdpReadBufferSize)) {
|
||||||
|
DCHECK(socket_);
|
||||||
|
// Start accepting connections in next run loop in case when delegate is not
|
||||||
|
// ready to get callbacks.
|
||||||
|
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||||
|
FROM_HERE, base::BindOnce(&RedirectResolver::DoRead,
|
||||||
|
weak_ptr_factory_.GetWeakPtr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectResolver::~RedirectResolver() = default;
|
||||||
|
|
||||||
|
void RedirectResolver::DoRead() {
|
||||||
|
for (;;) {
|
||||||
|
int rv = socket_->RecvFrom(
|
||||||
|
buffer_.get(), kUdpReadBufferSize, &recv_address_,
|
||||||
|
base::BindOnce(&RedirectResolver::OnRecv, base::Unretained(this)));
|
||||||
|
if (rv == ERR_IO_PENDING)
|
||||||
|
return;
|
||||||
|
rv = HandleReadResult(rv);
|
||||||
|
if (rv == ERR_IO_PENDING)
|
||||||
|
return;
|
||||||
|
if (rv < 0) {
|
||||||
|
LOG(INFO) << "DoRead: ignoring error " << rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RedirectResolver::OnRecv(int result) {
|
||||||
|
int rv;
|
||||||
|
rv = HandleReadResult(result);
|
||||||
|
if (rv == ERR_IO_PENDING)
|
||||||
|
return;
|
||||||
|
if (rv < 0) {
|
||||||
|
LOG(INFO) << "OnRecv: ignoring error " << result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RedirectResolver::OnSend(int result) {
|
||||||
|
if (result < 0) {
|
||||||
|
LOG(INFO) << "OnSend: ignoring error " << result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RedirectResolver::HandleReadResult(int result) {
|
||||||
|
if (result < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
DnsQuery query(buffer_.get());
|
||||||
|
if (!query.Parse(result)) {
|
||||||
|
LOG(INFO) << "Malformed DNS query from " << recv_address_.ToString();
|
||||||
|
return ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size;
|
||||||
|
if (query.qtype() == dns_protocol::kTypeA) {
|
||||||
|
Resolution res;
|
||||||
|
|
||||||
|
auto name = DNSDomainToString(query.qname());
|
||||||
|
|
||||||
|
auto by_name_lookup = resolution_by_name_.emplace(name, resolutions_.end());
|
||||||
|
auto by_name = by_name_lookup.first;
|
||||||
|
bool has_name = !by_name_lookup.second;
|
||||||
|
if (has_name) {
|
||||||
|
auto res_it = by_name->second;
|
||||||
|
auto by_addr = res_it->by_addr;
|
||||||
|
uint32_t addr = res_it->addr;
|
||||||
|
|
||||||
|
resolutions_.erase(res_it);
|
||||||
|
resolutions_.emplace_back();
|
||||||
|
res_it = std::prev(resolutions_.end());
|
||||||
|
|
||||||
|
by_name->second = res_it;
|
||||||
|
by_addr->second = res_it;
|
||||||
|
res_it->addr = addr;
|
||||||
|
res_it->name = name;
|
||||||
|
res_it->time = base::TimeTicks::Now();
|
||||||
|
res_it->by_name = by_name;
|
||||||
|
res_it->by_addr = by_addr;
|
||||||
|
} else {
|
||||||
|
uint32_t addr = (range_.bytes()[0] << 24) | (range_.bytes()[1] << 16) |
|
||||||
|
(range_.bytes()[2] << 8) | range_.bytes()[3];
|
||||||
|
uint32_t subnet = ~0U >> prefix_;
|
||||||
|
addr &= ~subnet;
|
||||||
|
addr += offset_;
|
||||||
|
offset_ = (offset_ + 1) & subnet;
|
||||||
|
|
||||||
|
auto by_addr_lookup =
|
||||||
|
resolution_by_addr_.emplace(addr, resolutions_.end());
|
||||||
|
auto by_addr = by_addr_lookup.first;
|
||||||
|
bool has_addr = !by_addr_lookup.second;
|
||||||
|
if (has_addr) {
|
||||||
|
// Too few available addresses. Overwrites old one.
|
||||||
|
auto res_it = by_addr->second;
|
||||||
|
|
||||||
|
LOG(INFO) << "Overwrite " << res_it->name << " "
|
||||||
|
<< PackedIPv4ToString(res_it->addr) << " with " << name << " "
|
||||||
|
<< PackedIPv4ToString(addr);
|
||||||
|
resolution_by_name_.erase(res_it->by_name);
|
||||||
|
resolutions_.erase(res_it);
|
||||||
|
resolutions_.emplace_back();
|
||||||
|
res_it = std::prev(resolutions_.end());
|
||||||
|
|
||||||
|
by_name->second = res_it;
|
||||||
|
by_addr->second = res_it;
|
||||||
|
res_it->addr = addr;
|
||||||
|
res_it->name = name;
|
||||||
|
res_it->time = base::TimeTicks::Now();
|
||||||
|
res_it->by_name = by_name;
|
||||||
|
res_it->by_addr = by_addr;
|
||||||
|
} else {
|
||||||
|
LOG(INFO) << "Add " << name << " " << PackedIPv4ToString(addr);
|
||||||
|
resolutions_.emplace_back();
|
||||||
|
auto res_it = std::prev(resolutions_.end());
|
||||||
|
|
||||||
|
by_name->second = res_it;
|
||||||
|
by_addr->second = res_it;
|
||||||
|
res_it->addr = addr;
|
||||||
|
res_it->name = name;
|
||||||
|
res_it->time = base::TimeTicks::Now();
|
||||||
|
res_it->by_name = by_name;
|
||||||
|
res_it->by_addr = by_addr;
|
||||||
|
|
||||||
|
// Collects garbage.
|
||||||
|
auto now = base::TimeTicks::Now();
|
||||||
|
for (auto it = resolutions_.begin();
|
||||||
|
it != resolutions_.end() &&
|
||||||
|
(now - it->time).InSeconds() > kResolutionRecycleTime;) {
|
||||||
|
auto next = std::next(it);
|
||||||
|
LOG(INFO) << "Drop " << it->name << " "
|
||||||
|
<< PackedIPv4ToString(it->addr);
|
||||||
|
resolution_by_name_.erase(it->by_name);
|
||||||
|
resolution_by_addr_.erase(it->by_addr);
|
||||||
|
resolutions_.erase(it);
|
||||||
|
it = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DnsResourceRecord record;
|
||||||
|
record.name = name;
|
||||||
|
record.type = dns_protocol::kTypeA;
|
||||||
|
record.klass = dns_protocol::kClassIN;
|
||||||
|
record.ttl = kResolutionTtl;
|
||||||
|
uint32_t addr = by_name->second->addr;
|
||||||
|
record.SetOwnedRdata(IPAddressToPackedString(
|
||||||
|
IPAddress(addr >> 24, addr >> 16, addr >> 8, addr)));
|
||||||
|
base::Optional<DnsQuery> query_opt(base::in_place, query.id(),
|
||||||
|
query.qname(), query.qtype());
|
||||||
|
DnsResponse response(query.id(), /*is_authoritative=*/false,
|
||||||
|
/*answers=*/{std::move(record)},
|
||||||
|
/*authority_records=*/{}, /*additional_records=*/{},
|
||||||
|
query_opt);
|
||||||
|
size = response.io_buffer_size();
|
||||||
|
if (size > buffer_->size() || !response.io_buffer()) {
|
||||||
|
return ERR_NO_BUFFER_SPACE;
|
||||||
|
}
|
||||||
|
std::memcpy(buffer_->data(), response.io_buffer()->data(), size);
|
||||||
|
} else {
|
||||||
|
base::Optional<DnsQuery> query_opt(base::in_place, query.id(),
|
||||||
|
query.qname(), query.qtype());
|
||||||
|
DnsResponse response(query.id(), /*is_authoritative=*/false, /*answers=*/{},
|
||||||
|
/*authority_records=*/{}, /*additional_records=*/{},
|
||||||
|
query_opt, dns_protocol::kRcodeSERVFAIL);
|
||||||
|
size = response.io_buffer_size();
|
||||||
|
if (size > buffer_->size() || !response.io_buffer()) {
|
||||||
|
return ERR_NO_BUFFER_SPACE;
|
||||||
|
}
|
||||||
|
std::memcpy(buffer_->data(), response.io_buffer()->data(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket_->SendTo(
|
||||||
|
buffer_.get(), size, recv_address_,
|
||||||
|
base::BindOnce(&RedirectResolver::OnSend, base::Unretained(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RedirectResolver::IsInResolvedRange(const IPAddress& address) const {
|
||||||
|
if (!address.IsIPv4())
|
||||||
|
return false;
|
||||||
|
return IPAddressMatchesPrefix(address, range_, prefix_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RedirectResolver::FindNameByAddress(
|
||||||
|
const IPAddress& address) const {
|
||||||
|
if (!address.IsIPv4())
|
||||||
|
return {};
|
||||||
|
uint32_t addr = (address.bytes()[0] << 24) | (address.bytes()[1] << 16) |
|
||||||
|
(address.bytes()[2] << 8) | address.bytes()[3];
|
||||||
|
auto by_addr = resolution_by_addr_.find(addr);
|
||||||
|
if (by_addr == resolution_by_addr_.end())
|
||||||
|
return {};
|
||||||
|
return by_addr->second->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace net
|
70
src/net/tools/naive/redirect_resolver.h
Normal file
70
src/net/tools/naive/redirect_resolver.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2019 klzgrad <kizdiv@gmail.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef NET_TOOLS_NAIVE_REDIRECT_RESOLVER_H_
|
||||||
|
#define NET_TOOLS_NAIVE_REDIRECT_RESOLVER_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/macros.h"
|
||||||
|
#include "base/memory/ref_counted.h"
|
||||||
|
#include "base/memory/weak_ptr.h"
|
||||||
|
#include "base/time/time.h"
|
||||||
|
#include "net/base/ip_address.h"
|
||||||
|
#include "net/base/ip_endpoint.h"
|
||||||
|
|
||||||
|
namespace net {
|
||||||
|
|
||||||
|
class DatagramServerSocket;
|
||||||
|
class IOBufferWithSize;
|
||||||
|
|
||||||
|
struct Resolution {
|
||||||
|
Resolution();
|
||||||
|
~Resolution();
|
||||||
|
|
||||||
|
uint32_t addr;
|
||||||
|
std::string name;
|
||||||
|
base::TimeTicks time;
|
||||||
|
std::map<std::string, std::list<Resolution>::iterator>::iterator by_name;
|
||||||
|
std::map<uint32_t, std::list<Resolution>::iterator>::iterator by_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RedirectResolver {
|
||||||
|
public:
|
||||||
|
RedirectResolver(std::unique_ptr<DatagramServerSocket> socket,
|
||||||
|
const IPAddress& range,
|
||||||
|
size_t prefix);
|
||||||
|
~RedirectResolver();
|
||||||
|
|
||||||
|
bool IsInResolvedRange(const IPAddress& address) const;
|
||||||
|
std::string FindNameByAddress(const IPAddress& address) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DoRead();
|
||||||
|
void OnRecv(int result);
|
||||||
|
void OnSend(int result);
|
||||||
|
int HandleReadResult(int result);
|
||||||
|
|
||||||
|
std::unique_ptr<DatagramServerSocket> socket_;
|
||||||
|
IPAddress range_;
|
||||||
|
size_t prefix_;
|
||||||
|
uint32_t offset_;
|
||||||
|
scoped_refptr<IOBufferWithSize> buffer_;
|
||||||
|
IPEndPoint recv_address_;
|
||||||
|
|
||||||
|
std::map<std::string, std::list<Resolution>::iterator> resolution_by_name_;
|
||||||
|
std::map<uint32_t, std::list<Resolution>::iterator> resolution_by_addr_;
|
||||||
|
std::list<Resolution> resolutions_;
|
||||||
|
|
||||||
|
base::WeakPtrFactory<RedirectResolver> weak_ptr_factory_{this};
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RedirectResolver);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace net
|
||||||
|
#endif // NET_TOOLS_NAIVE_REDIRECT_RESOLVER_H_
|
Loading…
Reference in New Issue
Block a user