diff --git a/ChangeLog b/ChangeLog index 668799fbf..8d3f33f41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -82,6 +82,7 @@ * resume data no longer has timestamps of files * require C++11 to build libtorrent + * restore support for incoming connections over SOCKS5 (disabled by default) * use unique peer_ids per connection * fix iOS build on recent SDK * fix tracker connection bind issue for IPv6 trackers diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index bb9f13d79..efc901a15 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -342,6 +342,10 @@ namespace aux { void async_accept(std::shared_ptr const& listener, transport ssl); void on_accept_connection(std::shared_ptr const& s , std::weak_ptr listener, error_code const& e, transport ssl); + void on_socks_listen(std::shared_ptr const& s + , error_code const& e); + void on_socks_accept(std::shared_ptr const& s + , error_code const& e); void incoming_connection(std::shared_ptr const& s); @@ -742,6 +746,7 @@ namespace aux { void update_listen_interfaces(); void update_privileged_ports(); void update_auto_sequential(); + void update_incoming_socks5(); void update_max_failcount(); void update_resolver_cache_timeout(); @@ -952,9 +957,16 @@ namespace aux { void ssl_handshake(error_code const& ec, std::shared_ptr s); #endif + // when as a socks proxy is used for peers, also + // listen for incoming connections on a socks connection + std::shared_ptr m_socks_listen_socket; + std::uint16_t m_socks_listen_port; + // round-robin index into m_outgoing_interfaces mutable std::uint8_t m_interface_index = 0; + void open_new_incoming_socks_connection(); + std::shared_ptr setup_listener( listen_endpoint_t const& lep, error_code& ec); diff --git a/include/libtorrent/settings_pack.hpp b/include/libtorrent/settings_pack.hpp index 47961a909..5b40ac1eb 100644 --- a/include/libtorrent/settings_pack.hpp +++ b/include/libtorrent/settings_pack.hpp @@ -727,6 +727,12 @@ namespace libtorrent { // changes are taken in consideration. 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 }; diff --git a/include/libtorrent/socks5_stream.hpp b/include/libtorrent/socks5_stream.hpp index 1c078335d..72a014f02 100644 --- a/include/libtorrent/socks5_stream.hpp +++ b/include/libtorrent/socks5_stream.hpp @@ -85,6 +85,7 @@ public: // commands enum { socks5_connect = 1, + socks5_bind = 2, socks5_udp_associate = 3 }; @@ -92,6 +93,7 @@ public: : proxy_base(io_service) , m_version(5) , m_command(socks5_connect) + , m_listen(0) {} void set_version(int v) { m_version = v; } @@ -109,6 +111,38 @@ public: m_password = password; } + template + 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 + 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) { // if this assert trips, set_dst_name() is called wth an IP address rather @@ -134,12 +168,25 @@ public: } #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 template void async_connect(endpoint_type const& endpoint, Handler const& handler) { // make sure we don't try to connect to INADDR_ANY. binding is fine, // and using a hostname is fine on SOCKS version 5. + TORRENT_ASSERT(m_command != socks5_bind); TORRENT_ASSERT(endpoint.address() != address() || (!m_dst_name.empty() && m_version == 5)); @@ -165,16 +212,16 @@ public: private: void name_lookup(error_code const& e, tcp::resolver::iterator i - , handler_type& h); - void connected(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 handshake3(error_code const& e, handler_type& h); - void handshake4(error_code const& e, handler_type& h); + , handler_type h); + void connected(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 handshake3(error_code const& e, handler_type h); + void handshake4(error_code const& e, handler_type h); void socks_connect(handler_type h); - void connect1(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 connect1(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); // send and receive buffer std::vector m_buffer; @@ -183,10 +230,19 @@ private: std::string m_password; 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; - // 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; + + // set to one when we're waiting for the + // second message to accept an incoming connection + int m_listen; }; } diff --git a/simulation/test_socks5.cpp b/simulation/test_socks5.cpp index 22b4d9572..b2d5a8001 100644 --- a/simulation/test_socks5.cpp +++ b/simulation/test_socks5.cpp @@ -100,6 +100,155 @@ void run_test(Setup const& setup 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(alert)) + { + TEST_EQUAL(a->socket_type, 2); + incoming_connection = true; + } + }, + [](sim::simulation& sim, lt::session& ses + , std::shared_ptr 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(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 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(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 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(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 ti) + { + sim.run(); + } + ); + + TEST_EQUAL(listen_alert, true); +} + TORRENT_TEST(socks5_tcp_announce) { using namespace lt; @@ -108,6 +257,9 @@ TORRENT_TEST(socks5_tcp_announce) 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::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(tracker_port, 0); + TEST_EQUAL(alert_port, tracker_port); TEST_CHECK(alert_port != -1); TEST_CHECK(tracker_port != -1); } diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index 0bb5b35cc..3e28b8304 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -63,6 +63,8 @@ std::string make_ep_string(char const* address, bool const is_v6 return ret; } +const int connect_socks = 2; + template void run_test( Setup const& setup @@ -122,7 +124,8 @@ void run_test( print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) { if (auto ta = alert_cast(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); }); @@ -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 ses[2]) { + TEST_EQUAL(is_seed(*ses[0]), true); + }, + connect_socks + ); +} + + TORRENT_TEST(encryption_tcp) { using namespace lt; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 6f9a1c702..017272e13 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -419,6 +419,7 @@ namespace aux { #if TORRENT_USE_I2P , m_i2p_conn(m_io_service) #endif + , m_socks_listen_port(0) , m_created(clock_type::now()) , m_last_tick(m_created) , m_last_second_tick(m_created - milliseconds(900)) @@ -908,6 +909,13 @@ namespace aux { 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 // 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 @@ -1975,6 +1983,7 @@ namespace { if (map_ports) remap_ports(remap_natpmp_and_upnp, *s); } + open_new_incoming_socks_connection(); #if TORRENT_USE_I2P open_new_incoming_i2p_connection(); #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(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(); + + m_socks_listen_port = m_listen_interfaces.empty() ? 0 + : static_cast(m_listen_interfaces[0].port); + if (m_socks_listen_port == 0) m_socks_listen_port = static_cast(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 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()) + m_alerts.emplace_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()) + m_alerts.emplace_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(); + 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 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()) + m_alerts.emplace_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() { // we need this socket to be open before we @@ -5285,6 +5387,22 @@ namespace { 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() { for (auto& i : m_torrents) @@ -5299,6 +5417,9 @@ namespace { 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) i->udp_sock->sock.set_proxy_settings(proxy()); m_outgoing_sockets.update_proxy(proxy()); @@ -5382,6 +5503,13 @@ namespace { 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 // mode. We don't want to leak our listen port since it can // 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 { #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 not, don't tell the tracker anything if we're in force_proxy diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index 533c617ed..2b79c561a 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -200,6 +200,7 @@ constexpr int CLOSE_FILE_INTERVAL = 0; SET(auto_sequential, true, &session_impl::update_auto_sequential), SET(proxy_tracker_connections, true, nullptr), SET(enable_ip_notifier, true, &session_impl::update_ip_notifier), + SET(incoming_socks5_connections, false, &session_impl::update_incoming_socks5), }}); aux::array const int_settings diff --git a/src/socks5_stream.cpp b/src/socks5_stream.cpp index e18c1601c..1aab6b1cd 100644 --- a/src/socks5_stream.cpp +++ b/src/socks5_stream.cpp @@ -77,8 +77,58 @@ namespace libtorrent { return cat; } + namespace + { + // parse out the endpoint from a SOCKS response + tcp::endpoint parse_endpoint(std::vector 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 - , handler_type& h) + , handler_type h) { COMPLETE_ASYNC("socks5_stream::name_lookup"); if (handle_error(e, h)) return; @@ -97,7 +147,7 @@ namespace libtorrent { &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"); 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"); if (handle_error(e, h)) return; @@ -145,7 +195,7 @@ namespace libtorrent { , 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"); if (handle_error(e, h)) return; @@ -197,7 +247,7 @@ namespace libtorrent { } void socks5_stream::handshake3(error_code const& e - , handler_type& h) + , handler_type h) { COMPLETE_ASYNC("socks5_stream::handshake3"); if (handle_error(e, h)) return; @@ -209,7 +259,7 @@ namespace libtorrent { } void socks5_stream::handshake4(error_code const& e - , handler_type& h) + , handler_type h) { COMPLETE_ASYNC("socks5_stream::handshake4"); if (handle_error(e, h)) return; @@ -248,7 +298,7 @@ namespace libtorrent { :(m_remote_endpoint.address().is_v4()?4:16))); char* p = &m_buffer[0]; 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 if (!m_dst_name.empty()) { @@ -261,7 +311,8 @@ namespace libtorrent { else { // 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_address(m_remote_endpoint.address(), p); @@ -279,7 +330,7 @@ namespace libtorrent { m_buffer.resize(m_user.size() + 9); char* p = &m_buffer[0]; 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_uint32(m_remote_endpoint.address().to_v4().to_ulong(), 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))); } - 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"); if (handle_error(e, h)) return; @@ -312,7 +363,7 @@ namespace libtorrent { , 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"); if (handle_error(e, h)) return; @@ -352,6 +403,18 @@ namespace libtorrent { // on address type) 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().swap(m_buffer); h(e); return; @@ -390,6 +453,18 @@ namespace libtorrent { // access granted 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().swap(m_buffer); h(e); 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"); using namespace libtorrent::detail; 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().swap(m_buffer); h(e); }