2009-01-26 19:15:20 +01:00
|
|
|
/*
|
|
|
|
|
2018-04-09 09:04:33 +02:00
|
|
|
Copyright (c) 2007-2018, Arvid Norberg
|
2009-01-26 19:15:20 +01:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2009-09-16 05:46:36 +02:00
|
|
|
#include "libtorrent/config.hpp"
|
2007-12-09 05:15:24 +01:00
|
|
|
#include "libtorrent/udp_socket.hpp"
|
2009-09-16 05:46:36 +02:00
|
|
|
#include "libtorrent/socket_io.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/settings_pack.hpp"
|
2015-07-12 05:01:27 +02:00
|
|
|
#include "libtorrent/error.hpp"
|
2016-12-05 20:49:45 +01:00
|
|
|
#include "libtorrent/time.hpp"
|
2016-04-23 23:29:25 +02:00
|
|
|
#include "libtorrent/debug.hpp"
|
2016-12-05 20:49:45 +01:00
|
|
|
#include "libtorrent/deadline_timer.hpp"
|
2017-02-08 16:54:55 +01:00
|
|
|
#include "libtorrent/aux_/numeric_cast.hpp"
|
2018-04-01 13:48:17 +02:00
|
|
|
#include "libtorrent/broadcast_socket.hpp" // for is_v4
|
2015-03-12 05:34:54 +01:00
|
|
|
|
2016-07-10 05:17:55 +02:00
|
|
|
#include <cstdlib>
|
2016-08-29 14:31:23 +02:00
|
|
|
#include <functional>
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
2016-02-01 01:40:31 +01:00
|
|
|
#include <boost/asio/ip/v6_only.hpp>
|
2016-04-24 21:26:28 +02:00
|
|
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
namespace libtorrent {
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-05-25 06:31:52 +02:00
|
|
|
using namespace std::placeholders;
|
2008-09-23 01:43:21 +02:00
|
|
|
|
2018-07-24 12:16:43 +02:00
|
|
|
// used to build SOCKS messages in
|
|
|
|
std::size_t const tmp_buffer_size = 270;
|
|
|
|
|
|
|
|
// used for SOCKS5 UDP wrapper header
|
|
|
|
std::size_t const max_header_size = 25;
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// this class hold the state of the SOCKS5 connection to maintain the UDP
|
|
|
|
// ASSOCIATE tunnel. It's instantiated on the heap for two reasons:
|
|
|
|
//
|
|
|
|
// 1. since its asynchronous functions may refer to it after the udp_socket has
|
|
|
|
// been destructed, it needs to be held by a shared_ptr
|
2016-07-28 20:57:26 +02:00
|
|
|
// 2. since using a socks proxy is assumed to be a less common case, it makes
|
2016-04-24 21:26:28 +02:00
|
|
|
// the common case cheaper by not allocating this space unconditionally
|
2016-08-29 14:31:23 +02:00
|
|
|
struct socks5 : std::enable_shared_from_this<socks5>
|
2010-08-03 11:08:37 +02:00
|
|
|
{
|
2016-07-10 20:27:42 +02:00
|
|
|
explicit socks5(io_service& ios)
|
2016-04-24 21:26:28 +02:00
|
|
|
: m_socks5_sock(ios)
|
|
|
|
, m_resolver(ios)
|
|
|
|
, m_timer(ios)
|
2017-05-22 03:02:09 +02:00
|
|
|
, m_retry_timer(ios)
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_abort(false)
|
|
|
|
, m_active(false)
|
2018-07-02 01:11:22 +02:00
|
|
|
{}
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void start(aux::proxy_settings const& ps);
|
|
|
|
void close();
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
bool active() const { return m_active; }
|
|
|
|
udp::endpoint target() const { return m_udp_proxy_addr; }
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
private:
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-08-29 14:31:23 +02:00
|
|
|
std::shared_ptr<socks5> self() { return shared_from_this(); }
|
2013-06-12 09:57:13 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void on_name_lookup(error_code const& e, tcp::resolver::iterator i);
|
2018-01-11 01:35:15 +01:00
|
|
|
void on_connect_timeout(error_code const& e);
|
|
|
|
void on_connected(error_code const& e);
|
2016-04-24 21:26:28 +02:00
|
|
|
void handshake1(error_code const& e);
|
|
|
|
void handshake2(error_code const& e);
|
|
|
|
void handshake3(error_code const& e);
|
|
|
|
void handshake4(error_code const& e);
|
|
|
|
void socks_forward_udp();
|
|
|
|
void connect1(error_code const& e);
|
|
|
|
void connect2(error_code const& e);
|
|
|
|
void hung_up(error_code const& e);
|
2017-05-22 03:02:09 +02:00
|
|
|
void retry_socks_connect(error_code const& e);
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
tcp::socket m_socks5_sock;
|
|
|
|
tcp::resolver m_resolver;
|
|
|
|
deadline_timer m_timer;
|
2017-05-22 03:02:09 +02:00
|
|
|
deadline_timer m_retry_timer;
|
2018-07-24 12:16:43 +02:00
|
|
|
std::array<char, tmp_buffer_size> m_tmp_buf;
|
2013-11-20 02:19:42 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
aux::proxy_settings m_proxy_settings;
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// this is the endpoint the proxy server lives at.
|
|
|
|
// when performing a UDP associate, we get another
|
|
|
|
// endpoint (presumably on the same IP) where we're
|
|
|
|
// supposed to send UDP packets.
|
|
|
|
udp::endpoint m_proxy_addr;
|
2010-02-06 09:14:18 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// this is where UDP packets that are to be forwarded
|
|
|
|
// are sent. The result from UDP ASSOCIATE is stored
|
|
|
|
// in here.
|
|
|
|
udp::endpoint m_udp_proxy_addr;
|
2010-02-06 09:14:18 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// set to true when we've been asked to shut down
|
|
|
|
bool m_abort;
|
2008-12-19 07:20:09 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// set to true once the tunnel is established
|
|
|
|
bool m_active;
|
|
|
|
};
|
2015-08-25 04:18:10 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifdef TORRENT_HAS_DONT_FRAGMENT
|
|
|
|
struct set_dont_frag
|
|
|
|
{
|
|
|
|
set_dont_frag(udp::socket& sock, bool const df)
|
|
|
|
: m_socket(sock)
|
|
|
|
, m_df(df)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!m_df) return;
|
|
|
|
error_code ignore_errors;
|
|
|
|
m_socket.set_option(libtorrent::dont_fragment(true), ignore_errors);
|
|
|
|
TORRENT_ASSERT_VAL(!ignore_errors, ignore_errors.message());
|
2010-02-18 05:37:02 +01:00
|
|
|
}
|
2013-06-12 09:57:13 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
~set_dont_frag()
|
2012-07-01 20:44:46 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!m_df) return;
|
|
|
|
error_code ignore_errors;
|
|
|
|
m_socket.set_option(libtorrent::dont_fragment(false), ignore_errors);
|
|
|
|
TORRENT_ASSERT_VAL(!ignore_errors, ignore_errors.message());
|
2012-07-01 20:44:46 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
private:
|
|
|
|
udp::socket& m_socket;
|
|
|
|
bool const m_df;
|
|
|
|
};
|
2015-08-22 00:28:12 +02:00
|
|
|
#else
|
2016-04-24 21:26:28 +02:00
|
|
|
struct set_dont_frag
|
|
|
|
{ set_dont_frag(udp::socket&, int) {} };
|
2009-04-04 18:59:53 +02:00
|
|
|
#endif
|
2012-07-01 20:44:46 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
udp_socket::udp_socket(io_service& ios)
|
|
|
|
: m_socket(ios)
|
2016-04-30 19:52:06 +02:00
|
|
|
, m_buf(new receive_buffer())
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_bind_port(0)
|
|
|
|
, m_abort(true)
|
2016-04-30 19:52:06 +02:00
|
|
|
{}
|
2011-02-09 09:01:53 +01:00
|
|
|
|
2016-07-22 18:31:42 +02:00
|
|
|
int udp_socket::read(span<packet> pkts, error_code& ec)
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
auto const num = int(pkts.size());
|
2016-04-24 21:26:28 +02:00
|
|
|
int ret = 0;
|
|
|
|
packet p;
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
while (ret < num)
|
2011-02-05 22:19:33 +01:00
|
|
|
{
|
2018-05-29 16:45:15 +02:00
|
|
|
std::size_t const len = m_socket.receive_from(boost::asio::buffer(*m_buf)
|
|
|
|
, p.from, 0, ec);
|
2008-09-23 01:43:21 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (ec == error::would_block
|
|
|
|
|| ec == error::try_again
|
|
|
|
|| ec == error::operation_aborted
|
|
|
|
|| ec == error::bad_descriptor)
|
2015-11-25 22:36:06 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
return ret;
|
2015-11-25 22:36:06 +01:00
|
|
|
}
|
2014-05-11 01:44:57 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (ec == error::interrupted)
|
2014-05-11 01:44:57 +02:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (ec)
|
2015-11-13 20:27:13 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
// SOCKS5 cannot wrap ICMP errors. And even if it could, they certainly
|
|
|
|
// would not arrive as unwrapped (regular) ICMP errors. If we're using
|
|
|
|
// a proxy we must ignore these
|
2018-07-04 14:49:51 +02:00
|
|
|
if (m_proxy_settings.type != settings_pack::none) continue;
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
p.error = ec;
|
2016-07-22 18:31:42 +02:00
|
|
|
p.data = span<char>();
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-29 16:45:15 +02:00
|
|
|
p.data = {m_buf->data(), len};
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
// support packets coming from the SOCKS5 proxy
|
|
|
|
if (m_socks5_connection && m_socks5_connection->active())
|
|
|
|
{
|
|
|
|
// if the source IP doesn't match the proxy's, ignore the packet
|
|
|
|
if (p.from != m_socks5_connection->target()) continue;
|
2018-07-04 14:49:51 +02:00
|
|
|
// if we failed to unwrap, silently ignore the packet
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!unwrap(p.from, p.data)) continue;
|
2015-11-13 20:27:13 +01:00
|
|
|
}
|
2018-07-04 14:49:51 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// if we don't proxy trackers or peers, we may be receiving unwrapped
|
|
|
|
// packets and we must let them through.
|
|
|
|
bool const proxy_only
|
|
|
|
= m_proxy_settings.proxy_peer_connections
|
|
|
|
&& m_proxy_settings.proxy_tracker_connections
|
|
|
|
;
|
|
|
|
|
|
|
|
// if we proxy everything, block all packets that aren't coming from
|
|
|
|
// the proxy
|
|
|
|
if (m_proxy_settings.type != settings_pack::none && proxy_only) continue;
|
|
|
|
}
|
2015-11-13 20:27:13 +01:00
|
|
|
}
|
2012-06-21 17:05:57 +02:00
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
pkts[aux::numeric_cast<std::size_t>(ret)] = p;
|
2016-04-24 21:26:28 +02:00
|
|
|
++ret;
|
2012-06-22 06:21:20 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// we only have a single buffer for now, so we can only return a
|
|
|
|
// single packet. In the future though, we could attempt to drain
|
|
|
|
// the socket here, or maybe even use recvmmsg()
|
|
|
|
break;
|
2012-06-22 06:21:20 +02:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
return ret;
|
2012-06-25 05:31:11 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void udp_socket::send_hostname(char const* hostname, int const port
|
2017-07-26 19:38:40 +02:00
|
|
|
, span<char const> p, error_code& ec, udp_send_flags_t const flags)
|
2012-06-25 05:31:11 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
|
|
|
|
// if the sockets are closed, the udp_socket is closing too
|
|
|
|
if (!is_open())
|
2012-07-01 20:44:46 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
ec = error_code(boost::system::errc::bad_file_descriptor, generic_category());
|
|
|
|
return;
|
2012-07-01 20:44:46 +02:00
|
|
|
}
|
|
|
|
|
2018-07-04 14:49:51 +02:00
|
|
|
bool const use_proxy
|
|
|
|
= ((flags & peer_connection) && m_proxy_settings.proxy_peer_connections)
|
|
|
|
|| ((flags & tracker_connection) && m_proxy_settings.proxy_tracker_connections)
|
|
|
|
|| !(flags & (tracker_connection | peer_connection))
|
|
|
|
;
|
2016-04-24 21:26:28 +02:00
|
|
|
|
2018-07-04 14:49:51 +02:00
|
|
|
if (use_proxy && m_proxy_settings.type != settings_pack::none)
|
2012-06-30 17:30:38 +02:00
|
|
|
{
|
2018-07-04 14:49:51 +02:00
|
|
|
if (m_socks5_connection && m_socks5_connection->active())
|
|
|
|
{
|
|
|
|
// send udp packets through SOCKS5 server
|
|
|
|
wrap(hostname, port, p, ec, flags);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ec = error_code(boost::system::errc::permission_denied, generic_category());
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
return;
|
2012-06-25 05:31:11 +02:00
|
|
|
}
|
2012-06-22 06:21:20 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// the overload that takes a hostname is really only supported when we're
|
|
|
|
// using a proxy
|
2018-07-04 14:49:51 +02:00
|
|
|
address const target = make_address(hostname, ec);
|
2016-11-21 16:08:26 +01:00
|
|
|
if (!ec) send(udp::endpoint(target, std::uint16_t(port)), p, ec, flags);
|
2012-06-22 06:21:20 +02:00
|
|
|
}
|
|
|
|
|
2016-07-22 18:31:42 +02:00
|
|
|
void udp_socket::send(udp::endpoint const& ep, span<char const> p
|
2017-07-26 19:38:40 +02:00
|
|
|
, error_code& ec, udp_send_flags_t const flags)
|
2012-06-21 17:05:57 +02:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// if the sockets are closed, the udp_socket is closing too
|
|
|
|
if (!is_open())
|
2008-03-25 05:46:18 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
ec = error_code(boost::system::errc::bad_file_descriptor, generic_category());
|
2012-06-21 17:05:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-04 14:49:51 +02:00
|
|
|
bool const use_proxy
|
2016-04-24 21:26:28 +02:00
|
|
|
= ((flags & peer_connection) && m_proxy_settings.proxy_peer_connections)
|
|
|
|
|| ((flags & tracker_connection) && m_proxy_settings.proxy_tracker_connections)
|
2017-07-26 19:38:40 +02:00
|
|
|
|| !(flags & (tracker_connection | peer_connection))
|
2016-04-24 21:26:28 +02:00
|
|
|
;
|
2012-06-21 17:05:57 +02:00
|
|
|
|
2018-07-04 14:49:51 +02:00
|
|
|
if (use_proxy && m_proxy_settings.type != settings_pack::none)
|
2016-02-22 02:00:55 +01:00
|
|
|
{
|
2018-07-04 14:49:51 +02:00
|
|
|
if (m_socks5_connection && m_socks5_connection->active())
|
|
|
|
{
|
|
|
|
// send udp packets through SOCKS5 server
|
|
|
|
wrap(ep, p, ec, flags);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ec = error_code(boost::system::errc::permission_denied, generic_category());
|
|
|
|
}
|
2016-02-22 02:00:55 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// set the DF flag for the socket and clear it again in the destructor
|
2017-07-26 19:38:40 +02:00
|
|
|
set_dont_frag df(m_socket, (flags & dont_fragment)
|
2018-04-01 13:48:17 +02:00
|
|
|
&& is_v4(ep));
|
2014-05-11 01:44:57 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socket.send_to(boost::asio::buffer(p.data(), p.size()), ep, 0, ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-07-22 18:31:42 +02:00
|
|
|
void udp_socket::wrap(udp::endpoint const& ep, span<char const> p
|
2017-07-26 19:38:40 +02:00
|
|
|
, error_code& ec, udp_send_flags_t const flags)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
TORRENT_UNUSED(flags);
|
2007-12-09 05:15:24 +01:00
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2018-07-24 12:16:43 +02:00
|
|
|
std::array<char, max_header_size> header;
|
2018-07-02 01:11:22 +02:00
|
|
|
char* h = header.data();
|
2007-12-09 05:15:24 +01:00
|
|
|
|
|
|
|
write_uint16(0, h); // reserved
|
|
|
|
write_uint8(0, h); // fragment
|
2018-04-01 13:48:17 +02:00
|
|
|
write_uint8(is_v4(ep) ? 1 : 4, h); // atyp
|
2010-08-03 11:08:37 +02:00
|
|
|
write_endpoint(ep, h);
|
|
|
|
|
2016-05-01 05:10:47 +02:00
|
|
|
std::array<boost::asio::const_buffer, 2> iovec;
|
2018-07-02 01:11:22 +02:00
|
|
|
iovec[0] = boost::asio::const_buffer(header.data(), aux::numeric_cast<std::size_t>(h - header.data()));
|
2016-04-24 21:26:28 +02:00
|
|
|
iovec[1] = boost::asio::const_buffer(p.data(), p.size());
|
2010-08-03 11:08:37 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// set the DF flag for the socket and clear it again in the destructor
|
2017-07-26 19:38:40 +02:00
|
|
|
set_dont_frag df(m_socket, (flags & dont_fragment)
|
2018-04-01 13:48:17 +02:00
|
|
|
&& is_v4(ep));
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
m_socket.send_to(iovec, m_socks5_connection->target(), 0, ec);
|
2010-08-03 11:08:37 +02:00
|
|
|
}
|
|
|
|
|
2016-07-22 18:31:42 +02:00
|
|
|
void udp_socket::wrap(char const* hostname, int const port, span<char const> p
|
2017-07-26 19:38:40 +02:00
|
|
|
, error_code& ec, udp_send_flags_t const flags)
|
2010-08-03 11:08:37 +02:00
|
|
|
{
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2018-07-24 12:16:43 +02:00
|
|
|
std::array<char, max_header_size> header;
|
2018-07-02 01:11:22 +02:00
|
|
|
char* h = header.data();
|
2010-08-03 11:08:37 +02:00
|
|
|
|
|
|
|
write_uint16(0, h); // reserved
|
|
|
|
write_uint8(0, h); // fragment
|
|
|
|
write_uint8(3, h); // atyp
|
2017-02-08 16:54:55 +01:00
|
|
|
std::size_t const hostlen = std::min(std::strlen(hostname), std::size_t(255));
|
|
|
|
write_uint8(hostlen, h); // hostname len
|
2016-11-21 16:08:26 +01:00
|
|
|
std::memcpy(h, hostname, hostlen);
|
2010-08-03 11:08:37 +02:00
|
|
|
h += hostlen;
|
2017-02-08 16:54:55 +01:00
|
|
|
write_uint16(port, h);
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-05-01 05:10:47 +02:00
|
|
|
std::array<boost::asio::const_buffer, 2> iovec;
|
2018-07-02 01:11:22 +02:00
|
|
|
iovec[0] = boost::asio::const_buffer(header.data(), aux::numeric_cast<std::size_t>(h - header.data()));
|
2016-04-24 21:26:28 +02:00
|
|
|
iovec[1] = boost::asio::const_buffer(p.data(), p.size());
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// set the DF flag for the socket and clear it again in the destructor
|
2017-07-26 19:38:40 +02:00
|
|
|
set_dont_frag df(m_socket, (flags & dont_fragment)
|
2018-04-01 13:48:17 +02:00
|
|
|
&& is_v4(m_socket.local_endpoint(ec)));
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
m_socket.send_to(iovec, m_socks5_connection->target(), 0, ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// unwrap the UDP packet from the SOCKS5 header
|
2016-04-24 21:26:28 +02:00
|
|
|
// buf is an in-out parameter. It will be updated
|
|
|
|
// return false if the packet should be ignored. It's not a valid Socks5 UDP
|
|
|
|
// forwarded packet
|
2016-07-22 18:31:42 +02:00
|
|
|
bool udp_socket::unwrap(udp::endpoint& from, span<char>& buf)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
|
|
|
// the minimum socks5 header size
|
2018-01-11 01:35:15 +01:00
|
|
|
auto const size = aux::numeric_cast<int>(buf.size());
|
2016-04-24 21:26:28 +02:00
|
|
|
if (size <= 10) return false;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
char* p = buf.data();
|
2007-12-09 05:15:24 +01:00
|
|
|
p += 2; // reserved
|
2016-04-24 21:26:28 +02:00
|
|
|
int const frag = read_uint8(p);
|
2007-12-09 05:15:24 +01:00
|
|
|
// fragmentation is not supported
|
2016-04-24 21:26:28 +02:00
|
|
|
if (frag != 0) return false;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
int const atyp = read_uint8(p);
|
2007-12-09 05:15:24 +01:00
|
|
|
if (atyp == 1)
|
|
|
|
{
|
|
|
|
// IPv4
|
2016-04-24 21:26:28 +02:00
|
|
|
from = read_v4_endpoint<udp::endpoint>(p);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
else if (atyp == 4)
|
|
|
|
{
|
|
|
|
// IPv6
|
2016-04-24 21:26:28 +02:00
|
|
|
from = read_v6_endpoint<udp::endpoint>(p);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
int const len = read_uint8(p);
|
|
|
|
if (len > buf.end() - p) return false;
|
2010-08-03 11:08:37 +02:00
|
|
|
std::string hostname(p, p + len);
|
2016-04-24 21:26:28 +02:00
|
|
|
error_code ec;
|
2018-01-04 10:48:22 +01:00
|
|
|
address addr = make_address(hostname, ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
// we only support "hostnames" that are a dotted decimal IP
|
|
|
|
if (ec) return false;
|
2010-08-03 11:08:37 +02:00
|
|
|
p += len;
|
2016-04-24 21:26:28 +02:00
|
|
|
from = udp::endpoint(addr, read_uint16(p));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
buf = {p, aux::numeric_cast<std::size_t>(size - (p - buf.data()))};
|
2016-04-24 21:26:28 +02:00
|
|
|
return true;
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2012-03-01 09:27:22 +01:00
|
|
|
#if !defined BOOST_ASIO_ENABLE_CANCELIO && defined TORRENT_WINDOWS
|
2010-11-29 02:33:05 +01:00
|
|
|
#error BOOST_ASIO_ENABLE_CANCELIO needs to be defined when building libtorrent to enable cancel() in asio on windows
|
|
|
|
#endif
|
|
|
|
|
2007-12-09 05:15:24 +01:00
|
|
|
void udp_socket::close()
|
|
|
|
{
|
2010-09-25 23:39:27 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socket.close(ec);
|
2010-09-25 22:07:27 +02:00
|
|
|
TORRENT_ASSERT_VAL(!ec || ec == error::bad_descriptor, ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_socks5_connection)
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socks5_connection->close();
|
|
|
|
m_socks5_connection.reset();
|
2012-06-21 17:05:57 +02:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
m_abort = true;
|
2010-11-29 02:33:05 +01:00
|
|
|
}
|
|
|
|
|
2016-12-10 20:31:09 +01:00
|
|
|
void udp_socket::open(udp const& protocol, error_code& ec)
|
2008-02-05 07:32:10 +01:00
|
|
|
{
|
2010-09-25 23:39:27 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2016-02-22 02:00:55 +01:00
|
|
|
m_abort = false;
|
2010-02-21 21:15:07 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_socket.is_open()) m_socket.close(ec);
|
2016-02-22 02:00:55 +01:00
|
|
|
ec.clear();
|
2008-02-05 07:32:10 +01:00
|
|
|
|
2016-12-10 20:31:09 +01:00
|
|
|
m_socket.open(protocol, ec);
|
|
|
|
if (ec) return;
|
|
|
|
if (protocol == udp::v6())
|
2008-02-05 07:32:10 +01:00
|
|
|
{
|
2016-01-31 09:06:24 +01:00
|
|
|
error_code err;
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socket.set_option(boost::asio::ip::v6_only(true), err);
|
2016-01-31 09:06:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
// enable Teredo on windows
|
|
|
|
m_socket.set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), err);
|
|
|
|
#endif // TORRENT_WINDOWS
|
2008-02-05 07:32:10 +01:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
// this is best-effort. ignore errors
|
|
|
|
#ifdef TORRENT_WINDOWS
|
2018-05-13 16:52:32 +02:00
|
|
|
error_code err;
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socket.set_option(exclusive_address_use(true), err);
|
2017-05-10 13:53:07 +02:00
|
|
|
#endif
|
2016-12-10 20:31:09 +01:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
|
2016-12-10 20:31:09 +01:00
|
|
|
void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
|
|
|
{
|
|
|
|
if (!m_socket.is_open()) open(ep.protocol(), ec);
|
|
|
|
if (ec) return;
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socket.bind(ep, ec);
|
|
|
|
if (ec) return;
|
2017-12-15 17:18:27 +01:00
|
|
|
m_socket.non_blocking(true, ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
if (ec) return;
|
|
|
|
|
2016-12-19 02:56:59 +01:00
|
|
|
error_code err;
|
2016-12-20 07:16:13 +01:00
|
|
|
m_bind_port = m_socket.local_endpoint(err).port();
|
2016-12-19 02:56:59 +01:00
|
|
|
if (err) m_bind_port = ep.port();
|
2008-02-05 07:32:10 +01:00
|
|
|
}
|
|
|
|
|
2015-08-25 04:18:10 +02:00
|
|
|
void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2010-09-25 23:39:27 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_socks5_connection)
|
|
|
|
{
|
|
|
|
m_socks5_connection->close();
|
|
|
|
m_socks5_connection.reset();
|
|
|
|
}
|
2015-06-02 03:14:52 +02:00
|
|
|
|
2007-12-09 05:15:24 +01:00
|
|
|
m_proxy_settings = ps;
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_abort) return;
|
2010-07-18 04:49:26 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ps.type == settings_pack::socks5
|
|
|
|
|| ps.type == settings_pack::socks5_pw)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
|
|
|
// connect to socks5 server and open up the UDP tunnel
|
2014-12-17 03:44:27 +01:00
|
|
|
|
2016-12-05 20:49:45 +01:00
|
|
|
m_socks5_connection = std::make_shared<socks5>(m_socket.get_io_service());
|
2016-04-24 21:26:28 +02:00
|
|
|
m_socks5_connection->start(ps);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// ===================== SOCKS 5 =========================
|
2016-02-22 02:00:55 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::start(aux::proxy_settings const& ps)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
m_proxy_settings = ps;
|
2012-10-21 05:56:22 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// TODO: use the system resolver_interface here
|
2016-05-01 05:10:47 +02:00
|
|
|
tcp::resolver::query q(ps.hostname, to_string(ps.port).data());
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_name_lookup");
|
2016-05-25 06:31:52 +02:00
|
|
|
m_resolver.async_resolve(q, std::bind(
|
2016-04-24 21:26:28 +02:00
|
|
|
&socks5::on_name_lookup, self(), _1, _2));
|
|
|
|
}
|
2011-04-09 19:59:00 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
|
|
|
|
{
|
|
|
|
COMPLETE_ASYNC("socks5::on_name_lookup");
|
2016-02-22 02:00:55 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_abort) return;
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2015-06-06 07:22:53 +02:00
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
2011-04-09 19:59:00 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (e) return;
|
2011-02-09 09:01:53 +01:00
|
|
|
|
2007-12-09 05:15:24 +01:00
|
|
|
m_proxy_addr.address(i->endpoint().address());
|
|
|
|
m_proxy_addr.port(i->endpoint().port());
|
2012-10-21 05:56:22 +02:00
|
|
|
|
2014-10-03 22:56:57 +02:00
|
|
|
error_code ec;
|
2018-04-01 13:48:17 +02:00
|
|
|
m_socks5_sock.open(is_v4(m_proxy_addr) ? tcp::v4() : tcp::v6(), ec);
|
2014-10-03 22:56:57 +02:00
|
|
|
|
|
|
|
// enable keepalives
|
|
|
|
m_socks5_sock.set_option(boost::asio::socket_base::keep_alive(true), ec);
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_connected");
|
2014-10-03 22:56:57 +02:00
|
|
|
m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port())
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::on_connected, self(), _1));
|
2014-10-03 22:56:57 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_connect_timeout");
|
2014-10-03 22:56:57 +02:00
|
|
|
m_timer.expires_from_now(seconds(10));
|
2016-05-25 06:31:52 +02:00
|
|
|
m_timer.async_wait(std::bind(&socks5::on_connect_timeout
|
2016-04-24 21:26:28 +02:00
|
|
|
, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
void socks5::on_connect_timeout(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::on_connect_timeout");
|
2014-10-03 22:56:57 +02:00
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
2014-10-03 22:56:57 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_abort) return;
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2014-10-03 22:56:57 +02:00
|
|
|
error_code ignore;
|
|
|
|
m_socks5_sock.close(ignore);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::on_connected(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::on_connected");
|
2008-09-23 01:43:21 +02:00
|
|
|
|
2014-10-03 22:56:57 +02:00
|
|
|
m_timer.cancel();
|
2014-06-30 10:41:33 +02:00
|
|
|
|
2015-06-06 07:22:53 +02:00
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
2014-06-30 10:41:33 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_abort) return;
|
2011-05-15 00:25:49 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// we failed to connect to the proxy
|
|
|
|
if (e) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
|
|
|
// send SOCKS5 authentication methods
|
2018-07-02 01:11:22 +02:00
|
|
|
char* p = m_tmp_buf.data();
|
2007-12-09 05:15:24 +01:00
|
|
|
write_uint8(5, p); // SOCKS VERSION 5
|
|
|
|
if (m_proxy_settings.username.empty()
|
2014-07-06 21:18:00 +02:00
|
|
|
|| m_proxy_settings.type == settings_pack::socks5)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
|
|
|
write_uint8(1, p); // 1 authentication method (no auth)
|
|
|
|
write_uint8(0, p); // no authentication
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
write_uint8(2, p); // 2 authentication methods
|
|
|
|
write_uint8(0, p); // no authentication
|
|
|
|
write_uint8(2, p); // username/password
|
|
|
|
}
|
2018-07-02 01:11:22 +02:00
|
|
|
TORRENT_ASSERT_VAL(p - m_tmp_buf.data() < int(m_tmp_buf.size()), (p - m_tmp_buf.data()));
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_handshake1");
|
2018-07-02 01:11:22 +02:00
|
|
|
boost::asio::async_write(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data()
|
|
|
|
, aux::numeric_cast<std::size_t>(p - m_tmp_buf.data()))
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::handshake1, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::handshake1(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::on_handshake1");
|
|
|
|
if (m_abort) return;
|
|
|
|
if (e) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_handshake2");
|
2018-07-02 01:11:22 +02:00
|
|
|
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 2)
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::handshake2, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::handshake2(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::on_handshake2");
|
|
|
|
if (m_abort) return;
|
2011-04-09 19:59:00 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (e) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2018-07-02 01:11:22 +02:00
|
|
|
char* p = m_tmp_buf.data();
|
|
|
|
int const version = read_uint8(p);
|
|
|
|
int const method = read_uint8(p);
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2013-06-12 09:57:13 +02:00
|
|
|
if (version < 5)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
m_socks5_sock.close(ec);
|
|
|
|
return;
|
|
|
|
}
|
2007-12-09 05:15:24 +01:00
|
|
|
|
|
|
|
if (method == 0)
|
|
|
|
{
|
2010-09-25 23:39:27 +02:00
|
|
|
socks_forward_udp(/*l*/);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
else if (method == 2)
|
|
|
|
{
|
|
|
|
if (m_proxy_settings.username.empty())
|
|
|
|
{
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2007-12-30 00:47:51 +01:00
|
|
|
m_socks5_sock.close(ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// start sub-negotiation
|
2018-07-02 01:11:22 +02:00
|
|
|
p = m_tmp_buf.data();
|
2007-12-09 05:15:24 +01:00
|
|
|
write_uint8(1, p);
|
2016-04-17 22:56:07 +02:00
|
|
|
TORRENT_ASSERT(m_proxy_settings.username.size() < 0x100);
|
|
|
|
write_uint8(uint8_t(m_proxy_settings.username.size()), p);
|
2007-12-09 05:15:24 +01:00
|
|
|
write_string(m_proxy_settings.username, p);
|
2016-04-17 22:56:07 +02:00
|
|
|
TORRENT_ASSERT(m_proxy_settings.password.size() < 0x100);
|
|
|
|
write_uint8(uint8_t(m_proxy_settings.password.size()), p);
|
2007-12-09 05:15:24 +01:00
|
|
|
write_string(m_proxy_settings.password, p);
|
2018-07-02 01:11:22 +02:00
|
|
|
TORRENT_ASSERT_VAL(p - m_tmp_buf.data() < int(m_tmp_buf.size()), (p - m_tmp_buf.data()));
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_handshake3");
|
2017-02-08 16:54:55 +01:00
|
|
|
boost::asio::async_write(m_socks5_sock
|
2018-07-02 01:11:22 +02:00
|
|
|
, boost::asio::buffer(m_tmp_buf.data(), aux::numeric_cast<std::size_t>(p - m_tmp_buf.data()))
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::handshake3, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2007-12-30 00:47:51 +01:00
|
|
|
m_socks5_sock.close(ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::handshake3(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::on_handshake3");
|
|
|
|
if (m_abort) return;
|
|
|
|
if (e) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::on_handshake4");
|
2018-07-02 01:11:22 +02:00
|
|
|
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 2)
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::handshake4, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::handshake4(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::on_handshake4");
|
|
|
|
if (m_abort) return;
|
|
|
|
if (e) return;
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2007-12-09 05:15:24 +01:00
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2018-07-02 01:11:22 +02:00
|
|
|
char* p = m_tmp_buf.data();
|
|
|
|
int const version = read_uint8(p);
|
|
|
|
int const status = read_uint8(p);
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (version != 1 || status != 0) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2010-09-25 23:39:27 +02:00
|
|
|
socks_forward_udp(/*l*/);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::socks_forward_udp()
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
|
|
|
// send SOCKS5 UDP command
|
2018-07-02 01:11:22 +02:00
|
|
|
char* p = m_tmp_buf.data();
|
2007-12-09 05:15:24 +01:00
|
|
|
write_uint8(5, p); // SOCKS VERSION 5
|
|
|
|
write_uint8(3, p); // UDP ASSOCIATE command
|
|
|
|
write_uint8(0, p); // reserved
|
2013-05-24 08:28:46 +02:00
|
|
|
write_uint8(1, p); // ATYP = IPv4
|
|
|
|
write_uint32(0, p); // 0.0.0.0
|
|
|
|
write_uint16(0, p); // :0
|
2018-07-02 01:11:22 +02:00
|
|
|
TORRENT_ASSERT_VAL(p - m_tmp_buf.data() < int(m_tmp_buf.size()), (p - m_tmp_buf.data()));
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::connect1");
|
2017-02-08 16:54:55 +01:00
|
|
|
boost::asio::async_write(m_socks5_sock
|
2018-07-02 01:11:22 +02:00
|
|
|
, boost::asio::buffer(m_tmp_buf.data(), aux::numeric_cast<std::size_t>(p - m_tmp_buf.data()))
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::connect1, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::connect1(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::connect1");
|
|
|
|
if (m_abort) return;
|
|
|
|
if (e) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::connect2");
|
2018-07-02 01:11:22 +02:00
|
|
|
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 10)
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::connect2, self(), _1));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::connect2(error_code const& e)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::connect2");
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_abort) return;
|
|
|
|
if (e) return;
|
2008-09-19 19:31:16 +02:00
|
|
|
|
2007-12-09 05:15:24 +01:00
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2018-07-02 01:11:22 +02:00
|
|
|
char* p = m_tmp_buf.data();
|
|
|
|
int const version = read_uint8(p); // VERSION
|
|
|
|
int const status = read_uint8(p); // STATUS
|
2011-02-21 06:24:41 +01:00
|
|
|
++p; // RESERVED
|
2018-07-02 01:11:22 +02:00
|
|
|
int const atyp = read_uint8(p); // address type
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (version != 5 || status != 0) return;
|
2007-12-09 05:15:24 +01:00
|
|
|
|
|
|
|
if (atyp == 1)
|
|
|
|
{
|
2013-05-24 08:28:46 +02:00
|
|
|
m_udp_proxy_addr.address(address_v4(read_uint32(p)));
|
|
|
|
m_udp_proxy_addr.port(read_uint16(p));
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// in this case we need to read more data from the socket
|
2016-04-24 21:26:28 +02:00
|
|
|
// no IPv6 support for UDP socks5
|
2016-05-02 18:36:21 +02:00
|
|
|
TORRENT_ASSERT_FAIL();
|
2011-09-18 01:03:46 +02:00
|
|
|
return;
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
2015-06-02 03:14:52 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// we're done!
|
|
|
|
m_active = true;
|
2010-07-25 03:31:15 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("socks5::hung_up");
|
2018-07-02 01:11:22 +02:00
|
|
|
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 10)
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&socks5::hung_up, self(), _1));
|
2010-07-25 03:31:15 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::hung_up(error_code const& e)
|
2010-07-25 03:31:15 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
COMPLETE_ASYNC("socks5::hung_up");
|
|
|
|
m_active = false;
|
2010-07-25 03:31:15 +02:00
|
|
|
|
2015-06-06 07:22:53 +02:00
|
|
|
if (e == boost::asio::error::operation_aborted || m_abort) return;
|
2010-07-25 03:31:15 +02:00
|
|
|
|
2017-05-20 12:07:24 +02:00
|
|
|
// the socks connection was closed, re-open it in a bit
|
|
|
|
m_retry_timer.expires_from_now(seconds(5));
|
2017-05-22 03:02:09 +02:00
|
|
|
m_retry_timer.async_wait(std::bind(&socks5::retry_socks_connect
|
|
|
|
, self(), _1));
|
2017-05-20 12:07:24 +02:00
|
|
|
}
|
|
|
|
|
2017-05-22 03:02:09 +02:00
|
|
|
void socks5::retry_socks_connect(error_code const& e)
|
2017-05-20 12:07:24 +02:00
|
|
|
{
|
2017-05-22 03:02:09 +02:00
|
|
|
if (e) return;
|
2016-04-24 21:26:28 +02:00
|
|
|
start(m_proxy_settings);
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void socks5::close()
|
2013-06-12 09:57:13 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
m_abort = true;
|
|
|
|
error_code ec;
|
|
|
|
m_socks5_sock.close(ec);
|
|
|
|
m_resolver.cancel();
|
|
|
|
m_timer.cancel();
|
|
|
|
}
|
2013-06-12 09:57:13 +02:00
|
|
|
|
2017-07-26 19:38:40 +02:00
|
|
|
constexpr udp_send_flags_t udp_socket::peer_connection;
|
|
|
|
constexpr udp_send_flags_t udp_socket::tracker_connection;
|
|
|
|
constexpr udp_send_flags_t udp_socket::dont_queue;
|
|
|
|
constexpr udp_send_flags_t udp_socket::dont_fragment;
|
|
|
|
|
2013-06-12 09:57:13 +02:00
|
|
|
}
|