merged RC_1_1 into master
This commit is contained in:
commit
308cbfe097
|
@ -82,6 +82,7 @@
|
||||||
* resume data no longer has timestamps of files
|
* resume data no longer has timestamps of files
|
||||||
* require C++11 to build libtorrent
|
* require C++11 to build libtorrent
|
||||||
|
|
||||||
|
* restore support for incoming connections over SOCKS5 (disabled by default)
|
||||||
* use unique peer_ids per connection
|
* use unique peer_ids per connection
|
||||||
* fix iOS build on recent SDK
|
* fix iOS build on recent SDK
|
||||||
* fix tracker connection bind issue for IPv6 trackers
|
* fix tracker connection bind issue for IPv6 trackers
|
||||||
|
|
|
@ -342,6 +342,10 @@ namespace aux {
|
||||||
void async_accept(std::shared_ptr<tcp::acceptor> const& listener, transport ssl);
|
void async_accept(std::shared_ptr<tcp::acceptor> const& listener, transport ssl);
|
||||||
void on_accept_connection(std::shared_ptr<socket_type> const& s
|
void on_accept_connection(std::shared_ptr<socket_type> const& s
|
||||||
, std::weak_ptr<tcp::acceptor> listener, error_code const& e, transport ssl);
|
, std::weak_ptr<tcp::acceptor> listener, error_code const& e, transport ssl);
|
||||||
|
void on_socks_listen(std::shared_ptr<socket_type> const& s
|
||||||
|
, error_code const& e);
|
||||||
|
void on_socks_accept(std::shared_ptr<socket_type> const& s
|
||||||
|
, error_code const& e);
|
||||||
|
|
||||||
void incoming_connection(std::shared_ptr<socket_type> const& s);
|
void incoming_connection(std::shared_ptr<socket_type> const& s);
|
||||||
|
|
||||||
|
@ -742,6 +746,7 @@ namespace aux {
|
||||||
void update_listen_interfaces();
|
void update_listen_interfaces();
|
||||||
void update_privileged_ports();
|
void update_privileged_ports();
|
||||||
void update_auto_sequential();
|
void update_auto_sequential();
|
||||||
|
void update_incoming_socks5();
|
||||||
void update_max_failcount();
|
void update_max_failcount();
|
||||||
void update_resolver_cache_timeout();
|
void update_resolver_cache_timeout();
|
||||||
|
|
||||||
|
@ -952,9 +957,16 @@ namespace aux {
|
||||||
void ssl_handshake(error_code const& ec, std::shared_ptr<socket_type> s);
|
void ssl_handshake(error_code const& ec, std::shared_ptr<socket_type> s);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// when as a socks proxy is used for peers, also
|
||||||
|
// listen for incoming connections on a socks connection
|
||||||
|
std::shared_ptr<socket_type> m_socks_listen_socket;
|
||||||
|
std::uint16_t m_socks_listen_port;
|
||||||
|
|
||||||
// round-robin index into m_outgoing_interfaces
|
// round-robin index into m_outgoing_interfaces
|
||||||
mutable std::uint8_t m_interface_index = 0;
|
mutable std::uint8_t m_interface_index = 0;
|
||||||
|
|
||||||
|
void open_new_incoming_socks_connection();
|
||||||
|
|
||||||
std::shared_ptr<listen_socket_t> setup_listener(
|
std::shared_ptr<listen_socket_t> setup_listener(
|
||||||
listen_endpoint_t const& lep, error_code& ec);
|
listen_endpoint_t const& lep, error_code& ec);
|
||||||
|
|
||||||
|
|
|
@ -727,6 +727,12 @@ namespace libtorrent {
|
||||||
// changes are taken in consideration.
|
// changes are taken in consideration.
|
||||||
enable_ip_notifier,
|
enable_ip_notifier,
|
||||||
|
|
||||||
|
// this enables a SOCKS5 "extension", in which libtorrent attempts to
|
||||||
|
// receive incoming connections over a SOCKS5 proxy. The traditional
|
||||||
|
// interpretation of the RFC and normal SOCKS5 implementations do not
|
||||||
|
// support this.
|
||||||
|
incoming_socks5_connections,
|
||||||
|
|
||||||
max_bool_setting_internal
|
max_bool_setting_internal
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
// commands
|
// commands
|
||||||
enum {
|
enum {
|
||||||
socks5_connect = 1,
|
socks5_connect = 1,
|
||||||
|
socks5_bind = 2,
|
||||||
socks5_udp_associate = 3
|
socks5_udp_associate = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +93,7 @@ public:
|
||||||
: proxy_base(io_service)
|
: proxy_base(io_service)
|
||||||
, m_version(5)
|
, m_version(5)
|
||||||
, m_command(socks5_connect)
|
, m_command(socks5_connect)
|
||||||
|
, m_listen(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void set_version(int v) { m_version = v; }
|
void set_version(int v) { m_version = v; }
|
||||||
|
@ -109,6 +111,38 @@ public:
|
||||||
m_password = password;
|
m_password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
void async_accept(Handler const& handler)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_listen == 1);
|
||||||
|
TORRENT_ASSERT(m_command == socks5_bind);
|
||||||
|
|
||||||
|
// to avoid unnecessary copying of the handler,
|
||||||
|
// store it in a shaed_ptr
|
||||||
|
error_code e;
|
||||||
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
add_outstanding_async("socks5_stream::connect1");
|
||||||
|
#endif
|
||||||
|
connect1(e, std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
void async_listen(tcp::endpoint const& ep, Handler const& handler)
|
||||||
|
{
|
||||||
|
m_command = socks5_bind;
|
||||||
|
|
||||||
|
m_remote_endpoint = ep;
|
||||||
|
|
||||||
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
add_outstanding_async("socks5_stream::name_lookup");
|
||||||
|
#endif
|
||||||
|
tcp::resolver::query q(m_hostname, to_string(m_port).data());
|
||||||
|
using std::placeholders::_1;
|
||||||
|
using std::placeholders::_2;
|
||||||
|
m_resolver.async_resolve(q, std::bind(
|
||||||
|
&socks5_stream::name_lookup, this, _1, _2, handler_type(std::move(handler))));
|
||||||
|
}
|
||||||
|
|
||||||
void set_dst_name(std::string const& host)
|
void set_dst_name(std::string const& host)
|
||||||
{
|
{
|
||||||
// if this assert trips, set_dst_name() is called wth an IP address rather
|
// if this assert trips, set_dst_name() is called wth an IP address rather
|
||||||
|
@ -134,12 +168,25 @@ public:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
endpoint_type local_endpoint() const
|
||||||
|
{
|
||||||
|
return m_local_endpoint;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
endpoint_type local_endpoint(error_code&) const
|
||||||
|
{
|
||||||
|
return m_local_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: 2 add async_connect() that takes a hostname and port as well
|
// TODO: 2 add async_connect() that takes a hostname and port as well
|
||||||
template <class Handler>
|
template <class Handler>
|
||||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||||
{
|
{
|
||||||
// make sure we don't try to connect to INADDR_ANY. binding is fine,
|
// make sure we don't try to connect to INADDR_ANY. binding is fine,
|
||||||
// and using a hostname is fine on SOCKS version 5.
|
// and using a hostname is fine on SOCKS version 5.
|
||||||
|
TORRENT_ASSERT(m_command != socks5_bind);
|
||||||
TORRENT_ASSERT(endpoint.address() != address()
|
TORRENT_ASSERT(endpoint.address() != address()
|
||||||
|| (!m_dst_name.empty() && m_version == 5));
|
|| (!m_dst_name.empty() && m_version == 5));
|
||||||
|
|
||||||
|
@ -165,16 +212,16 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void name_lookup(error_code const& e, tcp::resolver::iterator i
|
void name_lookup(error_code const& e, tcp::resolver::iterator i
|
||||||
, handler_type& h);
|
, handler_type h);
|
||||||
void connected(error_code const& e, handler_type& h);
|
void connected(error_code const& e, handler_type h);
|
||||||
void handshake1(error_code const& e, handler_type& h);
|
void handshake1(error_code const& e, handler_type h);
|
||||||
void handshake2(error_code const& e, handler_type& h);
|
void handshake2(error_code const& e, handler_type h);
|
||||||
void handshake3(error_code const& e, handler_type& h);
|
void handshake3(error_code const& e, handler_type h);
|
||||||
void handshake4(error_code const& e, handler_type& h);
|
void handshake4(error_code const& e, handler_type h);
|
||||||
void socks_connect(handler_type h);
|
void socks_connect(handler_type h);
|
||||||
void connect1(error_code const& e, handler_type& h);
|
void connect1(error_code const& e, handler_type h);
|
||||||
void connect2(error_code const& e, handler_type& h);
|
void connect2(error_code const& e, handler_type h);
|
||||||
void connect3(error_code const& e, handler_type& h);
|
void connect3(error_code const& e, handler_type h);
|
||||||
|
|
||||||
// send and receive buffer
|
// send and receive buffer
|
||||||
std::vector<char> m_buffer;
|
std::vector<char> m_buffer;
|
||||||
|
@ -183,10 +230,19 @@ private:
|
||||||
std::string m_password;
|
std::string m_password;
|
||||||
std::string m_dst_name;
|
std::string m_dst_name;
|
||||||
|
|
||||||
|
// when listening via a socks proxy, this is the IP and port our listen
|
||||||
|
// socket bound to
|
||||||
|
endpoint_type m_local_endpoint;
|
||||||
|
|
||||||
int m_version;
|
int m_version;
|
||||||
|
|
||||||
// the socks command to send for this connection (connect or udp associate)
|
// the socks command to send for this connection (connect, bind,
|
||||||
|
// udp associate)
|
||||||
int m_command;
|
int m_command;
|
||||||
|
|
||||||
|
// set to one when we're waiting for the
|
||||||
|
// second message to accept an incoming connection
|
||||||
|
int m_listen;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,155 @@ void run_test(Setup const& setup
|
||||||
test(sim, *ses, params.ti);
|
test(sim, *ses, params.ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(socks5_tcp_accept)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
bool incoming_connection = false;
|
||||||
|
run_test(
|
||||||
|
[](lt::session& ses)
|
||||||
|
{
|
||||||
|
settings_pack p;
|
||||||
|
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||||
|
ses.apply_settings(p);
|
||||||
|
set_proxy(ses, settings_pack::socks5);
|
||||||
|
},
|
||||||
|
[&](lt::session& ses, lt::alert const* alert) {
|
||||||
|
if (auto* a = lt::alert_cast<lt::incoming_connection_alert>(alert))
|
||||||
|
{
|
||||||
|
TEST_EQUAL(a->socket_type, 2);
|
||||||
|
incoming_connection = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](sim::simulation& sim, lt::session& ses
|
||||||
|
, std::shared_ptr<lt::torrent_info> ti)
|
||||||
|
{
|
||||||
|
// test connecting to the client via its socks5 listen port
|
||||||
|
// TODO: maybe we could use peer_conn here instead
|
||||||
|
fake_peer peer1(sim, "60.0.0.0");
|
||||||
|
fake_peer peer2(sim, "60.0.0.1");
|
||||||
|
|
||||||
|
sim::timer t1(sim, lt::seconds(2), [&](boost::system::error_code const& ec)
|
||||||
|
{
|
||||||
|
peer1.connect_to(tcp::endpoint(addr("50.50.50.50"), 6881), ti->info_hash());
|
||||||
|
});
|
||||||
|
|
||||||
|
sim::timer t2(sim, lt::seconds(3), [&](boost::system::error_code const& ec)
|
||||||
|
{
|
||||||
|
peer2.connect_to(tcp::endpoint(addr("50.50.50.50"), 6881), ti->info_hash());
|
||||||
|
});
|
||||||
|
|
||||||
|
sim.run();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_EQUAL(incoming_connection, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(socks4_tcp_accept)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
bool incoming_connection = false;
|
||||||
|
run_test(
|
||||||
|
[](lt::session& ses)
|
||||||
|
{
|
||||||
|
settings_pack p;
|
||||||
|
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||||
|
ses.apply_settings(p);
|
||||||
|
set_proxy(ses, settings_pack::socks4);
|
||||||
|
},
|
||||||
|
[&](lt::session& ses, lt::alert const* alert) {
|
||||||
|
if (auto* a = lt::alert_cast<lt::incoming_connection_alert>(alert))
|
||||||
|
{
|
||||||
|
TEST_EQUAL(a->socket_type, 2);
|
||||||
|
TEST_EQUAL(a->endpoint.address(), addr("60.0.0.0"))
|
||||||
|
incoming_connection = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](sim::simulation& sim, lt::session& ses
|
||||||
|
, std::shared_ptr<lt::torrent_info> ti)
|
||||||
|
{
|
||||||
|
fake_peer peer1(sim, "60.0.0.0");
|
||||||
|
|
||||||
|
sim::timer t1(sim, lt::seconds(2), [&](boost::system::error_code const& ec)
|
||||||
|
{
|
||||||
|
peer1.connect_to(tcp::endpoint(addr("50.50.50.50"), 6881), ti->info_hash());
|
||||||
|
});
|
||||||
|
|
||||||
|
sim.run();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_EQUAL(incoming_connection, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure a listen_succeeded_alert is issued when successfully listening on
|
||||||
|
// incoming connections via a socks5 proxy
|
||||||
|
TORRENT_TEST(socks4_tcp_listen_alert)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
bool listen_alert = false;
|
||||||
|
run_test(
|
||||||
|
[](lt::session& ses)
|
||||||
|
{
|
||||||
|
settings_pack p;
|
||||||
|
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||||
|
ses.apply_settings(p);
|
||||||
|
set_proxy(ses, settings_pack::socks4);
|
||||||
|
},
|
||||||
|
[&](lt::session& ses, lt::alert const* alert) {
|
||||||
|
if (auto* a = lt::alert_cast<lt::listen_succeeded_alert>(alert))
|
||||||
|
{
|
||||||
|
if (a->socket_type == socket_type_t::socks5)
|
||||||
|
{
|
||||||
|
TEST_EQUAL(a->address, addr("0.0.0.0"));
|
||||||
|
TEST_EQUAL(a->port, 6881);
|
||||||
|
listen_alert = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](sim::simulation& sim, lt::session& ses
|
||||||
|
, std::shared_ptr<lt::torrent_info> ti)
|
||||||
|
{
|
||||||
|
sim.run();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_EQUAL(listen_alert, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(socks5_tcp_listen_alert)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
bool listen_alert = false;
|
||||||
|
run_test(
|
||||||
|
[](lt::session& ses)
|
||||||
|
{
|
||||||
|
settings_pack p;
|
||||||
|
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||||
|
ses.apply_settings(p);
|
||||||
|
set_proxy(ses, settings_pack::socks5);
|
||||||
|
},
|
||||||
|
[&](lt::session& ses, lt::alert const* alert) {
|
||||||
|
if (auto* a = lt::alert_cast<lt::listen_succeeded_alert>(alert))
|
||||||
|
{
|
||||||
|
if (a->socket_type == socket_type_t::socks5)
|
||||||
|
{
|
||||||
|
TEST_EQUAL(a->address, addr("0.0.0.0"));
|
||||||
|
TEST_EQUAL(a->port, 6881);
|
||||||
|
listen_alert = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](sim::simulation& sim, lt::session& ses
|
||||||
|
, std::shared_ptr<lt::torrent_info> ti)
|
||||||
|
{
|
||||||
|
sim.run();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
TEST_EQUAL(listen_alert, true);
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_TEST(socks5_tcp_announce)
|
TORRENT_TEST(socks5_tcp_announce)
|
||||||
{
|
{
|
||||||
using namespace lt;
|
using namespace lt;
|
||||||
|
@ -108,6 +257,9 @@ TORRENT_TEST(socks5_tcp_announce)
|
||||||
run_test(
|
run_test(
|
||||||
[](lt::session& ses)
|
[](lt::session& ses)
|
||||||
{
|
{
|
||||||
|
settings_pack p;
|
||||||
|
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||||
|
ses.apply_settings(p);
|
||||||
set_proxy(ses, settings_pack::socks5);
|
set_proxy(ses, settings_pack::socks5);
|
||||||
|
|
||||||
lt::add_torrent_params params;
|
lt::add_torrent_params params;
|
||||||
|
@ -153,8 +305,7 @@ TORRENT_TEST(socks5_tcp_announce)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// since force_proxy is enabled, don't send the port
|
TEST_EQUAL(alert_port, tracker_port);
|
||||||
TEST_EQUAL(tracker_port, 0);
|
|
||||||
TEST_CHECK(alert_port != -1);
|
TEST_CHECK(alert_port != -1);
|
||||||
TEST_CHECK(tracker_port != -1);
|
TEST_CHECK(tracker_port != -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@ std::string make_ep_string(char const* address, bool const is_v6
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int connect_socks = 2;
|
||||||
|
|
||||||
template <typename Setup, typename HandleAlerts, typename Test>
|
template <typename Setup, typename HandleAlerts, typename Test>
|
||||||
void run_test(
|
void run_test(
|
||||||
Setup const& setup
|
Setup const& setup
|
||||||
|
@ -122,7 +124,8 @@ void run_test(
|
||||||
print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
|
print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
|
||||||
if (auto ta = alert_cast<lt::add_torrent_alert>(a))
|
if (auto ta = alert_cast<lt::add_torrent_alert>(a))
|
||||||
{
|
{
|
||||||
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
|
ta->handle.connect_peer(lt::tcp::endpoint(
|
||||||
|
(flags & connect_socks) ? proxy : peer1, 6881));
|
||||||
}
|
}
|
||||||
on_alert(ses, a);
|
on_alert(ses, a);
|
||||||
});
|
});
|
||||||
|
@ -188,6 +191,29 @@ TORRENT_TEST(socks5_tcp_connect)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(socks5_tcp_accept)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
run_test(
|
||||||
|
[](lt::session& ses0, lt::session& ses1)
|
||||||
|
{
|
||||||
|
// this time, the session accepting the connection is listening on a
|
||||||
|
// socks5 BIND session
|
||||||
|
settings_pack p;
|
||||||
|
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||||
|
ses1.apply_settings(p);
|
||||||
|
set_proxy(ses1, settings_pack::socks5);
|
||||||
|
filter_ips(ses0);
|
||||||
|
},
|
||||||
|
[](lt::session& ses, lt::alert const* alert) {},
|
||||||
|
[](std::shared_ptr<lt::session> ses[2]) {
|
||||||
|
TEST_EQUAL(is_seed(*ses[0]), true);
|
||||||
|
},
|
||||||
|
connect_socks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TORRENT_TEST(encryption_tcp)
|
TORRENT_TEST(encryption_tcp)
|
||||||
{
|
{
|
||||||
using namespace lt;
|
using namespace lt;
|
||||||
|
|
|
@ -419,6 +419,7 @@ namespace aux {
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
, m_i2p_conn(m_io_service)
|
, m_i2p_conn(m_io_service)
|
||||||
#endif
|
#endif
|
||||||
|
, m_socks_listen_port(0)
|
||||||
, m_created(clock_type::now())
|
, m_created(clock_type::now())
|
||||||
, m_last_tick(m_created)
|
, m_last_tick(m_created)
|
||||||
, m_last_second_tick(m_created - milliseconds(900))
|
, m_last_second_tick(m_created - milliseconds(900))
|
||||||
|
@ -908,6 +909,13 @@ namespace aux {
|
||||||
|
|
||||||
m_outgoing_sockets.close();
|
m_outgoing_sockets.close();
|
||||||
|
|
||||||
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||||
|
{
|
||||||
|
m_socks_listen_socket->close(ec);
|
||||||
|
TORRENT_ASSERT(!ec);
|
||||||
|
}
|
||||||
|
m_socks_listen_socket.reset();
|
||||||
|
|
||||||
// we need to give all the sockets an opportunity to actually have their handlers
|
// we need to give all the sockets an opportunity to actually have their handlers
|
||||||
// called and cancelled before we continue the shutdown. This is a bit
|
// called and cancelled before we continue the shutdown. This is a bit
|
||||||
// complicated, if there are no "undead" peers, it's safe to resume the
|
// complicated, if there are no "undead" peers, it's safe to resume the
|
||||||
|
@ -1975,6 +1983,7 @@ namespace {
|
||||||
if (map_ports) remap_ports(remap_natpmp_and_upnp, *s);
|
if (map_ports) remap_ports(remap_natpmp_and_upnp, *s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open_new_incoming_socks_connection();
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
open_new_incoming_i2p_connection();
|
open_new_incoming_i2p_connection();
|
||||||
#endif
|
#endif
|
||||||
|
@ -2168,6 +2177,99 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void session_impl::open_new_incoming_socks_connection()
|
||||||
|
{
|
||||||
|
int const proxy_type = m_settings.get_int(settings_pack::proxy_type);
|
||||||
|
|
||||||
|
if (proxy_type != settings_pack::socks5
|
||||||
|
&& proxy_type != settings_pack::socks5_pw
|
||||||
|
&& proxy_type != settings_pack::socks4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_settings.get_bool(settings_pack::incoming_socks5_connections))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_socks_listen_socket) return;
|
||||||
|
|
||||||
|
m_socks_listen_socket = std::make_shared<socket_type>(m_io_service);
|
||||||
|
bool const ret = instantiate_connection(m_io_service, proxy()
|
||||||
|
, *m_socks_listen_socket, NULL, NULL, false, false);
|
||||||
|
TORRENT_ASSERT_VAL(ret, ret);
|
||||||
|
TORRENT_UNUSED(ret);
|
||||||
|
|
||||||
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
add_outstanding_async("session_impl::on_socks_listen");
|
||||||
|
#endif
|
||||||
|
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
||||||
|
|
||||||
|
m_socks_listen_port = m_listen_interfaces.empty() ? 0
|
||||||
|
: static_cast<std::uint16_t>(m_listen_interfaces[0].port);
|
||||||
|
if (m_socks_listen_port == 0) m_socks_listen_port = static_cast<std::uint16_t>(2000 + random(60000));
|
||||||
|
s.async_listen(tcp::endpoint(address_v4::any(), m_socks_listen_port)
|
||||||
|
, std::bind(&session_impl::on_socks_listen, this
|
||||||
|
, m_socks_listen_socket, _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_impl::on_socks_listen(std::shared_ptr<socket_type> const& sock
|
||||||
|
, error_code const& e)
|
||||||
|
{
|
||||||
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
complete_async("session_impl::on_socks_listen");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TORRENT_ASSERT(sock == m_socks_listen_socket || !m_socks_listen_socket);
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
m_socks_listen_socket.reset();
|
||||||
|
if (e == boost::asio::error::operation_aborted) return;
|
||||||
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
|
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||||
|
, tcp::endpoint(), operation_t::sock_accept, e
|
||||||
|
, socket_type_t::socks5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
tcp::endpoint const ep = sock->local_endpoint(ec);
|
||||||
|
TORRENT_ASSERT(!ec);
|
||||||
|
TORRENT_UNUSED(ec);
|
||||||
|
|
||||||
|
m_socks_listen_port = ep.port();
|
||||||
|
|
||||||
|
if (m_alerts.should_post<listen_succeeded_alert>())
|
||||||
|
m_alerts.emplace_alert<listen_succeeded_alert>(
|
||||||
|
ep, socket_type_t::socks5);
|
||||||
|
|
||||||
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
add_outstanding_async("session_impl::on_socks_accept");
|
||||||
|
#endif
|
||||||
|
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
||||||
|
s.async_accept(std::bind(&session_impl::on_socks_accept, this
|
||||||
|
, m_socks_listen_socket, _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_impl::on_socks_accept(std::shared_ptr<socket_type> const& s
|
||||||
|
, error_code const& e)
|
||||||
|
{
|
||||||
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
complete_async("session_impl::on_socks_accept");
|
||||||
|
#endif
|
||||||
|
TORRENT_ASSERT(s == m_socks_listen_socket || !m_socks_listen_socket);
|
||||||
|
m_socks_listen_socket.reset();
|
||||||
|
if (e == boost::asio::error::operation_aborted) return;
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
|
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||||
|
, tcp::endpoint(), operation_t::sock_accept, e
|
||||||
|
, socket_type_t::socks5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
open_new_incoming_socks_connection();
|
||||||
|
incoming_connection(s);
|
||||||
|
}
|
||||||
|
|
||||||
void session_impl::update_i2p_bridge()
|
void session_impl::update_i2p_bridge()
|
||||||
{
|
{
|
||||||
// we need this socket to be open before we
|
// we need this socket to be open before we
|
||||||
|
@ -5285,6 +5387,22 @@ namespace {
|
||||||
i.second->update_auto_sequential();
|
i.second->update_auto_sequential();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void session_impl::update_incoming_socks5()
|
||||||
|
{
|
||||||
|
if (!m_settings.get_bool(settings_pack::incoming_socks5_connections))
|
||||||
|
{
|
||||||
|
if (m_socks_listen_socket)
|
||||||
|
{
|
||||||
|
m_socks_listen_socket->close();
|
||||||
|
m_socks_listen_socket.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
open_new_incoming_socks_connection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void session_impl::update_max_failcount()
|
void session_impl::update_max_failcount()
|
||||||
{
|
{
|
||||||
for (auto& i : m_torrents)
|
for (auto& i : m_torrents)
|
||||||
|
@ -5299,6 +5417,9 @@ namespace {
|
||||||
|
|
||||||
void session_impl::update_proxy()
|
void session_impl::update_proxy()
|
||||||
{
|
{
|
||||||
|
// in case we just set a socks proxy, we might have to
|
||||||
|
// open the socks incoming connection
|
||||||
|
if (!m_socks_listen_socket) open_new_incoming_socks_connection();
|
||||||
for (auto& i : m_listen_sockets)
|
for (auto& i : m_listen_sockets)
|
||||||
i->udp_sock->sock.set_proxy_settings(proxy());
|
i->udp_sock->sock.set_proxy_settings(proxy());
|
||||||
m_outgoing_sockets.update_proxy(proxy());
|
m_outgoing_sockets.update_proxy(proxy());
|
||||||
|
@ -5382,6 +5503,13 @@ namespace {
|
||||||
|
|
||||||
std::uint16_t session_impl::listen_port(listen_socket_t* sock) const
|
std::uint16_t session_impl::listen_port(listen_socket_t* sock) const
|
||||||
{
|
{
|
||||||
|
// if peer connections are set up to be received over a socks
|
||||||
|
// proxy, and it's the same one as we're using for the tracker
|
||||||
|
// just tell the tracker the socks5 port we're listening on
|
||||||
|
// TODO: socks5 proxies should be treated as a separate interface!
|
||||||
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||||
|
return m_socks_listen_port;
|
||||||
|
|
||||||
// if not, don't tell the tracker anything if we're in force_proxy
|
// if not, don't tell the tracker anything if we're in force_proxy
|
||||||
// mode. We don't want to leak our listen port since it can
|
// mode. We don't want to leak our listen port since it can
|
||||||
// potentially identify us if it is leaked elsewhere
|
// potentially identify us if it is leaked elsewhere
|
||||||
|
@ -5401,6 +5529,13 @@ namespace {
|
||||||
std::uint16_t session_impl::ssl_listen_port(listen_socket_t* sock) const
|
std::uint16_t session_impl::ssl_listen_port(listen_socket_t* sock) const
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
// if peer connections are set up to be received over a socks
|
||||||
|
// proxy, and it's the same one as we're using for the tracker
|
||||||
|
// just tell the tracker the socks5 port we're listening on
|
||||||
|
// TODO: socks5 proxies should be treated as a separate interface!
|
||||||
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||||
|
return m_socks_listen_port;
|
||||||
|
|
||||||
if (sock) return std::uint16_t(sock->tcp_external_port);
|
if (sock) return std::uint16_t(sock->tcp_external_port);
|
||||||
|
|
||||||
// if not, don't tell the tracker anything if we're in force_proxy
|
// if not, don't tell the tracker anything if we're in force_proxy
|
||||||
|
|
|
@ -200,6 +200,7 @@ constexpr int CLOSE_FILE_INTERVAL = 0;
|
||||||
SET(auto_sequential, true, &session_impl::update_auto_sequential),
|
SET(auto_sequential, true, &session_impl::update_auto_sequential),
|
||||||
SET(proxy_tracker_connections, true, nullptr),
|
SET(proxy_tracker_connections, true, nullptr),
|
||||||
SET(enable_ip_notifier, true, &session_impl::update_ip_notifier),
|
SET(enable_ip_notifier, true, &session_impl::update_ip_notifier),
|
||||||
|
SET(incoming_socks5_connections, false, &session_impl::update_incoming_socks5),
|
||||||
}});
|
}});
|
||||||
|
|
||||||
aux::array<int_setting_entry_t, settings_pack::num_int_settings> const int_settings
|
aux::array<int_setting_entry_t, settings_pack::num_int_settings> const int_settings
|
||||||
|
|
|
@ -77,8 +77,58 @@ namespace libtorrent {
|
||||||
return cat;
|
return cat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// parse out the endpoint from a SOCKS response
|
||||||
|
tcp::endpoint parse_endpoint(std::vector<char> const& buffer
|
||||||
|
, int const version)
|
||||||
|
{
|
||||||
|
using namespace libtorrent::detail;
|
||||||
|
char const* p = &buffer[0];
|
||||||
|
p += 2; // version & response code
|
||||||
|
if (version == 5)
|
||||||
|
{
|
||||||
|
++p; // reserved byte
|
||||||
|
int const atyp = read_uint8(p);
|
||||||
|
|
||||||
|
if (atyp == 1)
|
||||||
|
{
|
||||||
|
tcp::endpoint ret;
|
||||||
|
ret.address(read_v4_address(p));
|
||||||
|
ret.port(read_uint16(p));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (atyp == 3)
|
||||||
|
{
|
||||||
|
// we don't support resolving the endpoint address
|
||||||
|
// if we receive a domain name, just set the remote
|
||||||
|
// endpoint to INADDR_ANY
|
||||||
|
return tcp::endpoint();
|
||||||
|
}
|
||||||
|
else if (atyp == 4)
|
||||||
|
{
|
||||||
|
tcp::endpoint ret;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
ret.address(read_v6_address(p));
|
||||||
|
ret.port(read_uint16(p));
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (version == 4)
|
||||||
|
{
|
||||||
|
tcp::endpoint ret;
|
||||||
|
ret.port(read_uint16(p));
|
||||||
|
ret.address(read_v4_address(p));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
TORRENT_ASSERT(false);
|
||||||
|
return tcp::endpoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void socks5_stream::name_lookup(error_code const& e, tcp::resolver::iterator i
|
void socks5_stream::name_lookup(error_code const& e, tcp::resolver::iterator i
|
||||||
, handler_type& h)
|
, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::name_lookup");
|
COMPLETE_ASYNC("socks5_stream::name_lookup");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -97,7 +147,7 @@ namespace libtorrent {
|
||||||
&socks5_stream::connected, this, _1, std::move(h)));
|
&socks5_stream::connected, this, _1, std::move(h)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::connected(error_code const& e, handler_type& h)
|
void socks5_stream::connected(error_code const& e, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::connected");
|
COMPLETE_ASYNC("socks5_stream::connected");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -134,7 +184,7 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::handshake1(error_code const& e, handler_type& h)
|
void socks5_stream::handshake1(error_code const& e, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::handshake1");
|
COMPLETE_ASYNC("socks5_stream::handshake1");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -145,7 +195,7 @@ namespace libtorrent {
|
||||||
, std::bind(&socks5_stream::handshake2, this, _1, std::move(h)));
|
, std::bind(&socks5_stream::handshake2, this, _1, std::move(h)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::handshake2(error_code const& e, handler_type& h)
|
void socks5_stream::handshake2(error_code const& e, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::handshake2");
|
COMPLETE_ASYNC("socks5_stream::handshake2");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -197,7 +247,7 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::handshake3(error_code const& e
|
void socks5_stream::handshake3(error_code const& e
|
||||||
, handler_type& h)
|
, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::handshake3");
|
COMPLETE_ASYNC("socks5_stream::handshake3");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -209,7 +259,7 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::handshake4(error_code const& e
|
void socks5_stream::handshake4(error_code const& e
|
||||||
, handler_type& h)
|
, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::handshake4");
|
COMPLETE_ASYNC("socks5_stream::handshake4");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -248,7 +298,7 @@ namespace libtorrent {
|
||||||
:(m_remote_endpoint.address().is_v4()?4:16)));
|
:(m_remote_endpoint.address().is_v4()?4:16)));
|
||||||
char* p = &m_buffer[0];
|
char* p = &m_buffer[0];
|
||||||
write_uint8(5, p); // SOCKS VERSION 5
|
write_uint8(5, p); // SOCKS VERSION 5
|
||||||
write_uint8(std::uint8_t(m_command), p); // CONNECT command
|
write_uint8(std::uint8_t(m_command), p); // CONNECT/BIND command
|
||||||
write_uint8(0, p); // reserved
|
write_uint8(0, p); // reserved
|
||||||
if (!m_dst_name.empty())
|
if (!m_dst_name.empty())
|
||||||
{
|
{
|
||||||
|
@ -261,7 +311,8 @@ namespace libtorrent {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we either need a hostname or a valid endpoint
|
// we either need a hostname or a valid endpoint
|
||||||
TORRENT_ASSERT(m_remote_endpoint.address() != address());
|
TORRENT_ASSERT(m_command == socks5_bind
|
||||||
|
|| m_remote_endpoint.address() != address());
|
||||||
|
|
||||||
write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
|
write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
|
||||||
write_address(m_remote_endpoint.address(), p);
|
write_address(m_remote_endpoint.address(), p);
|
||||||
|
@ -279,7 +330,7 @@ namespace libtorrent {
|
||||||
m_buffer.resize(m_user.size() + 9);
|
m_buffer.resize(m_user.size() + 9);
|
||||||
char* p = &m_buffer[0];
|
char* p = &m_buffer[0];
|
||||||
write_uint8(4, p); // SOCKS VERSION 4
|
write_uint8(4, p); // SOCKS VERSION 4
|
||||||
write_uint8(std::uint8_t(m_command), p); // CONNECT command
|
write_uint8(std::uint8_t(m_command), p); // CONNECT/BIND command
|
||||||
write_uint16(m_remote_endpoint.port(), p);
|
write_uint16(m_remote_endpoint.port(), p);
|
||||||
write_uint32(m_remote_endpoint.address().to_v4().to_ulong(), p);
|
write_uint32(m_remote_endpoint.address().to_v4().to_ulong(), p);
|
||||||
std::copy(m_user.begin(), m_user.end(), p);
|
std::copy(m_user.begin(), m_user.end(), p);
|
||||||
|
@ -297,7 +348,7 @@ namespace libtorrent {
|
||||||
, std::bind(&socks5_stream::connect1, this, _1, std::move(h)));
|
, std::bind(&socks5_stream::connect1, this, _1, std::move(h)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::connect1(error_code const& e, handler_type& h)
|
void socks5_stream::connect1(error_code const& e, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::connect1");
|
COMPLETE_ASYNC("socks5_stream::connect1");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -312,7 +363,7 @@ namespace libtorrent {
|
||||||
, std::bind(&socks5_stream::connect2, this, _1, std::move(h)));
|
, std::bind(&socks5_stream::connect2, this, _1, std::move(h)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::connect2(error_code const& e, handler_type& h)
|
void socks5_stream::connect2(error_code const& e, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::connect2");
|
COMPLETE_ASYNC("socks5_stream::connect2");
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
@ -352,6 +403,18 @@ namespace libtorrent {
|
||||||
// on address type)
|
// on address type)
|
||||||
if (atyp == 1)
|
if (atyp == 1)
|
||||||
{
|
{
|
||||||
|
if (m_command == socks5_bind)
|
||||||
|
{
|
||||||
|
if (m_listen == 0)
|
||||||
|
{
|
||||||
|
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||||
|
m_listen = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
std::vector<char>().swap(m_buffer);
|
std::vector<char>().swap(m_buffer);
|
||||||
h(e);
|
h(e);
|
||||||
return;
|
return;
|
||||||
|
@ -390,6 +453,18 @@ namespace libtorrent {
|
||||||
// access granted
|
// access granted
|
||||||
if (response == 90)
|
if (response == 90)
|
||||||
{
|
{
|
||||||
|
if (m_command == socks5_bind)
|
||||||
|
{
|
||||||
|
if (m_listen == 0)
|
||||||
|
{
|
||||||
|
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||||
|
m_listen = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
std::vector<char>().swap(m_buffer);
|
std::vector<char>().swap(m_buffer);
|
||||||
h(e);
|
h(e);
|
||||||
return;
|
return;
|
||||||
|
@ -406,13 +481,25 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void socks5_stream::connect3(error_code const& e, handler_type& h)
|
void socks5_stream::connect3(error_code const& e, handler_type h)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("socks5_stream::connect3");
|
COMPLETE_ASYNC("socks5_stream::connect3");
|
||||||
using namespace libtorrent::detail;
|
using namespace libtorrent::detail;
|
||||||
|
|
||||||
if (handle_error(e, h)) return;
|
if (handle_error(e, h)) return;
|
||||||
|
|
||||||
|
if (m_command == socks5_bind)
|
||||||
|
{
|
||||||
|
if (m_listen == 0)
|
||||||
|
{
|
||||||
|
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||||
|
m_listen = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
std::vector<char>().swap(m_buffer);
|
std::vector<char>().swap(m_buffer);
|
||||||
h(e);
|
h(e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue