From 41be942ae7eeb6457813a60178559c8372eabb7c Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 9 Apr 2009 01:04:49 +0000 Subject: [PATCH] experimental support for incoming connections over socks (untested) --- include/libtorrent/aux_/session_impl.hpp | 19 +++++- include/libtorrent/socks5_stream.hpp | 6 ++ src/session_impl.cpp | 54 +++++++++++++++- src/socks5_stream.cpp | 81 +++++++++++++++++++++--- 4 files changed, 146 insertions(+), 14 deletions(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 8eb72c58d..d2dff894a 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -153,8 +153,12 @@ namespace libtorrent tcp::endpoint get_ipv6_interface() const; void async_accept(boost::shared_ptr const& listener); - void on_incoming_connection(boost::shared_ptr const& s + void on_accept_connection(boost::shared_ptr const& s , boost::weak_ptr listener, error_code const& e); + void on_socks_accept(boost::shared_ptr const& s + , error_code const& e); + + void incoming_connection(boost::shared_ptr const& s); // must be locked to access the data // in this struct @@ -254,7 +258,12 @@ namespace libtorrent void announce_lsd(sha1_hash const& ih); void set_peer_proxy(proxy_settings const& s) - { m_peer_proxy = s; } + { + m_peer_proxy = s; + // 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(); + } void set_web_seed_proxy(proxy_settings const& s) { m_web_seed_proxy = s; } void set_tracker_proxy(proxy_settings const& s) @@ -442,6 +451,12 @@ namespace libtorrent // we might need more than one listen socket std::list m_listen_sockets; + // when as a socks proxy is used for peers, also + // listen for incoming connections on a socks connection + boost::shared_ptr m_socks_listen_socket; + + void open_new_incoming_socks_connection(); + listen_socket_t setup_listener(tcp::endpoint ep, int retries, bool v6_only = false); // the settings for the client diff --git a/include/libtorrent/socks5_stream.hpp b/include/libtorrent/socks5_stream.hpp index 9819fd763..c796e9e9f 100644 --- a/include/libtorrent/socks5_stream.hpp +++ b/include/libtorrent/socks5_stream.hpp @@ -74,10 +74,13 @@ public: : proxy_base(io_service) , m_version(5) , m_command(1) + , m_listen(0) {} void set_version(int v) { m_version = v; } + void set_command(int c) { m_command = c; } + void set_username(std::string const& user , std::string const& password) { @@ -134,6 +137,9 @@ private: std::string m_password; int m_version; 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/src/session_impl.cpp b/src/session_impl.cpp index f8d0cd008..1efe34bd2 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -77,6 +77,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/upnp.hpp" #include "libtorrent/natpmp.hpp" #include "libtorrent/lsd.hpp" +#include "libtorrent/instantiate_connection.hpp" #ifndef TORRENT_WINDOWS #include @@ -766,8 +767,14 @@ namespace aux { } } + open_new_incoming_socks_connection(); + + // figure out which IPv6 address we're listening on + // or at least one of them. This is used to announce + // to the tracker m_ipv6_interface = tcp::endpoint(); +#if TORRENT_USE_IPV6 for (std::list::const_iterator i = m_listen_sockets.begin() , end(m_listen_sockets.end()); i != end; ++i) { @@ -798,6 +805,7 @@ namespace aux { break; } } +#endif // TORRENT_USE_IPV6 if (!m_listen_sockets.empty()) { @@ -825,6 +833,25 @@ namespace aux { #endif } + void session_impl::open_new_incoming_socks_connection() + { + if (m_peer_proxy.type != proxy_settings::socks5 + && m_peer_proxy.type != proxy_settings::socks5_pw + && m_peer_proxy.type != proxy_settings::socks4) + return; + + if (m_socks_listen_socket) return; + + bool ret = instantiate_connection(m_io_service, m_peer_proxy + , *m_socks_listen_socket); + TORRENT_ASSERT(ret); + + socks5_stream& s = *m_socks_listen_socket->get(); + s.set_command(2); // 2 means BIND (as opposed to CONNECT) + s.async_connect(tcp::endpoint(address_v4::any(), m_listen_interface.port()) + , boost::bind(&session_impl::on_socks_accept, this, m_socks_listen_socket, _1)); + } + #ifndef TORRENT_DISABLE_DHT void session_impl::on_receive_udp(error_code const& e @@ -856,11 +883,11 @@ namespace aux { shared_ptr c(new socket_type(m_io_service)); c->instantiate(m_io_service); listener->async_accept(*c->get() - , bind(&session_impl::on_incoming_connection, this, c + , bind(&session_impl::on_accept_connection, this, c , boost::weak_ptr(listener), _1)); } - void session_impl::on_incoming_connection(shared_ptr const& s + void session_impl::on_accept_connection(shared_ptr const& s , weak_ptr listen_socket, error_code const& e) { boost::shared_ptr listener = listen_socket.lock(); @@ -904,6 +931,12 @@ namespace aux { } async_accept(listener); + incoming_connection(s); + } + + void session_impl::incoming_connection(boost::shared_ptr const& s) + { + error_code ec; // we got a connection request! tcp::endpoint endp = s->remote_endpoint(ec); @@ -988,6 +1021,23 @@ namespace aux { c->start(); } } + + void session_impl::on_socks_accept(boost::shared_ptr const& s + , error_code const& e) + { + m_socks_listen_socket.reset(); + if (e == asio::error::operation_aborted) return; + if (e) + { + if (m_alerts.should_post()) + m_alerts.post_alert(listen_failed_alert(tcp::endpoint( + address_v4::any(), m_listen_interface.port()), e)); + return; + } + open_new_incoming_socks_connection(); + incoming_connection(s); + } + void session_impl::close_connection(peer_connection const* p , char const* message) { diff --git a/src/socks5_stream.cpp b/src/socks5_stream.cpp index 361c944ca..5784a837e 100644 --- a/src/socks5_stream.cpp +++ b/src/socks5_stream.cpp @@ -356,18 +356,34 @@ namespace libtorrent // we ignore the proxy IP it was bound to if (atyp == 1) { - std::vector().swap(m_buffer); - (*h)(e); + if (m_command == 2) + { + if (m_listen == 0) + { + m_listen = 1; + connect1(e, h); + return; + } + m_remote_endpoint.address(read_v4_address(p)); + m_remote_endpoint.port(read_uint16(p)); + std::vector().swap(m_buffer); + (*h)(e); + } + else + { + std::vector().swap(m_buffer); + (*h)(e); + } return; } - int skip_bytes = 0; + int extra_bytes = 0; if (atyp == 4) { - skip_bytes = 12; + extra_bytes = 12; } else if (atyp == 3) { - skip_bytes = read_uint8(p) - 3; + extra_bytes = read_uint8(p) - 3; } else { @@ -376,10 +392,11 @@ namespace libtorrent close(ec); return; } - m_buffer.resize(skip_bytes); + m_buffer.resize(m_buffer.size() + extra_bytes); - async_read(m_sock, asio::buffer(m_buffer) - , boost::bind(&socks5_stream::connect3, this, _1, h)); + TORRENT_ASSERT(extra_bytes > 0); + async_read(m_sock, asio::buffer(&m_buffer[m_buffer.size() - extra_bytes], extra_bytes) + , boost::bind(&socks5_stream::connect3, this, _1, h)); } else if (m_version == 4) { @@ -394,8 +411,24 @@ namespace libtorrent // access granted if (response == 90) { - std::vector().swap(m_buffer); - (*h)(e); + if (m_command == 2) + { + if (m_listen == 0) + { + m_listen = 1; + connect1(e, h); + return; + } + m_remote_endpoint.address(read_v4_address(p)); + m_remote_endpoint.port(read_uint16(p)); + std::vector().swap(m_buffer); + (*h)(e); + } + else + { + std::vector().swap(m_buffer); + (*h)(e); + } return; } @@ -414,6 +447,8 @@ namespace libtorrent void socks5_stream::connect3(error_code const& e, boost::shared_ptr h) { + using namespace libtorrent::detail; + if (e) { (*h)(e); @@ -422,6 +457,32 @@ namespace libtorrent return; } + if (m_command == 2) + { + if (m_listen == 0) + { + m_listen = 1; + connect1(e, h); + return; + } + + char* p = &m_buffer[0]; + p += 2; // version and response code + int atyp = read_uint8(p); + TORRENT_ASSERT(atyp == 3 || atyp == 4); + if (atyp == 4) + { + // we don't support resolving the endpoint address + // if we receive a domain name, just set the remote + // endpoint to INADDR_ANY + m_remote_endpoint = tcp::endpoint(); + } + else if (atyp == 3) + { + m_remote_endpoint.address(read_v4_address(p)); + m_remote_endpoint.port(read_uint16(p)); + } + } std::vector().swap(m_buffer); (*h)(e); }