Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option to send host header in HTTP proxy CONNECT command #7710

Open
wants to merge 1 commit into
base: RC_2_0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

2.0.11 not released

* add option to send host header in HTTP proxy CONNECT command
* don't hint FADV_RANDOM on posix systems. May improve seeding performance
* allow boost connect while checking resume data if no_verify_files flag is set
* fix BEP-40 peer priority for IPv6
Expand Down
4 changes: 4 additions & 0 deletions include/libtorrent/aux_/proxy_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ namespace aux {

// if true, tracker connections are subject to the proxy settings
bool proxy_tracker_connections = true;

// when proxying non plain HTTP over an HTTP proxy (SSL or peer
// connections), also tell the proxy which hostname we're connecting to
bool send_host_in_connect = false;
};

}}
Expand Down
14 changes: 9 additions & 5 deletions include/libtorrent/http_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,21 @@ class http_stream : public proxy_base
m_password = password;
}

void set_dst_name(std::string const& host)
void set_host(std::string const& host)
{
m_dst_name = host;
m_host = host;
}

void close(error_code& ec)
{
m_dst_name.clear();
m_host.clear();
proxy_base::close(ec);
}

#ifndef BOOST_NO_EXCEPTIONS
void close()
{
m_dst_name.clear();
m_host.clear();
proxy_base::close();
}
#endif
Expand Down Expand Up @@ -129,6 +129,10 @@ class http_stream : public proxy_base
std::back_insert_iterator<std::vector<char>> p(m_buffer);
std::string const endpoint = print_endpoint(m_remote_endpoint);
write_string("CONNECT " + endpoint + " HTTP/1.0\r\n", p);
if (!m_host.empty())
{
write_string("Host: " + m_host + "\r\n", p);
}
if (!m_user.empty())
{
write_string("Proxy-Authorization: Basic " + base64encode(
Expand Down Expand Up @@ -218,7 +222,7 @@ class http_stream : public proxy_base
// proxy authentication
std::string m_user;
std::string m_password;
std::string m_dst_name;
std::string m_host;

// this is true if the connection is HTTP based and
// want to talk directly to the proxy
Expand Down
8 changes: 8 additions & 0 deletions include/libtorrent/settings_pack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,14 @@ namespace aux {
// protocol may not be valid from the proxy's point of view.
socks5_udp_send_local_ep,

// When using HTTP proxy (in proxy_type), libtorrent will connect
// to peers and trackers using the `CONNECT` proxy command. In this
// command it's possible to reveal the hostname of the server we're
// connecting to. When this option is true, the hostname will be
// sent. This feature can be useful if the proxy is used to
// man-in-the-middle connections.
proxy_send_host_in_connect,

max_bool_setting_internal
};

Expand Down
30 changes: 25 additions & 5 deletions simulation/test_http_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ void run_suite(lt::aux::proxy_settings ps)
// the try-next test in his case would test the socks proxy itself, whether
// it has robust retry behavior (which the simple test proxy that comes with
// libsimulator doesn't).
if (ps.proxy_hostnames == false)
if (ps.type != settings_pack::socks5 && ps.proxy_hostnames == false)
{
// this hostname will resolve to multiple IPs, all but one that we cannot
// connect to and the second one where we'll get the test file response. Make
Expand Down Expand Up @@ -600,9 +600,7 @@ TORRENT_TEST(http_connection_http_error)
test_proxy_failure(settings_pack::http);
}

// Requests a proxied SSL connection. This test just ensures that the correct CONNECT request
// is sent to the proxy server.
TORRENT_TEST(http_connection_ssl_proxy)
void test_connection_ssl_proxy(bool const with_hostname)
{
using sim::asio::ip::address_v4;
sim_config network_cfg;
Expand All @@ -615,15 +613,24 @@ TORRENT_TEST(http_connection_ssl_proxy)
sim::http_server http_proxy(proxy_ios, 4445);

lt::aux::proxy_settings ps = make_proxy_settings(settings_pack::http);
ps.send_host_in_connect = with_hostname;

int client_counter = 0;
int proxy_counter = 0;

http_proxy.register_handler("10.0.0.2:8080"
, [&proxy_counter](std::string method, std::string req, std::map<std::string, std::string>&)
, [&proxy_counter, with_hostname](std::string method, std::string req, std::map<std::string, std::string>& headers)
{
proxy_counter++;
TEST_EQUAL(method, "CONNECT");
if (with_hostname)
{
TEST_EQUAL(headers["host"], "10.0.0.2");
}
else
{
TEST_CHECK(headers.empty());
}
return sim::send_response(403, "Not supported", 1337);
});

Expand Down Expand Up @@ -656,6 +663,19 @@ TORRENT_TEST(http_connection_ssl_proxy)
TEST_EQUAL(proxy_counter, 1);
}

// Requests a proxied SSL connection. This test just ensures that the correct CONNECT request
// is sent to the proxy server.
TORRENT_TEST(http_connection_ssl_proxy_no_hostname)
{
test_connection_ssl_proxy(false);
}

TORRENT_TEST(http_connection_ssl_proxy_hostname)
{
test_connection_ssl_proxy(true);
}


// TODO: test http proxy with password
// TODO: test socks5 with password
// TODO: test SSL
Expand Down
6 changes: 6 additions & 0 deletions src/http_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,12 @@ void http_connection::connect()
}
}

if (m_proxy.send_host_in_connect
&& boost::get<http_stream>(&*m_sock))
{
boost::get<http_stream>(*m_sock).set_host(m_hostname);
}

TORRENT_ASSERT(m_next_ep < int(m_endpoints.size()));
if (m_next_ep >= int(m_endpoints.size())) return;

Expand Down
2 changes: 2 additions & 0 deletions src/proxy_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ void init(proxy_settings& p, Settings const& sett)
settings_pack::proxy_peer_connections);
p.proxy_tracker_connections = sett.get_bool(
settings_pack::proxy_tracker_connections);
p.send_host_in_connect = sett.get_bool(
settings_pack::proxy_send_host_in_connect);
}

}
Expand Down
1 change: 1 addition & 0 deletions src/settings_pack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ constexpr int DISK_WRITE_MODE = settings_pack::enable_os_cache;
SET(allow_idna, false, nullptr),
SET(enable_set_file_valid_data, false, nullptr),
SET(socks5_udp_send_local_ep, false, nullptr),
SET(proxy_send_host_in_connect, false, nullptr),
}});

CONSTEXPR_SETTINGS
Expand Down
19 changes: 17 additions & 2 deletions src/torrent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6658,11 +6658,11 @@ namespace {
aux::socket_type s = instantiate_connection(m_ses.get_context()
, m_ses.proxy(), userdata, nullptr, true, false);

if (boost::get<http_stream>(&s))
if (auto* inner = boost::get<http_stream>(&s))
{
// the web seed connection will talk immediately to
// the proxy, without requiring CONNECT support
boost::get<http_stream>(s).set_no_connect(true);
inner->set_no_connect(true);
}

std::string hostname;
Expand Down Expand Up @@ -6723,6 +6723,21 @@ namespace {
bool const proxy_hostnames = settings().get_bool(settings_pack::proxy_hostnames)
&& !is_ip;

if (!is_ip
&& settings().get_bool(settings_pack::proxy_send_host_in_connect))
{
if (auto* inner1 = boost::get<http_stream>(&s))
{
inner1->set_host(hostname);
}
#if TORRENT_USE_SSL
else if (auto* inner2 = boost::get<ssl_stream<http_stream>>(&s))
{
inner2->next_layer().set_host(hostname);
}
#endif
}

if (proxy_hostnames
&& (boost::get<socks5_stream>(&s)
#if TORRENT_USE_SSL
Expand Down
Loading