add new socks5_alert to trouble shoot SOCKS5 proxies

This commit is contained in:
Arvid Norberg 2019-12-22 00:48:05 +01:00 committed by Arvid Norberg
parent b5bf6c3260
commit 0675bd263f
13 changed files with 152 additions and 31 deletions

View File

@ -1,3 +1,5 @@
* add new socks5_alert to trouble shoot SOCKS5 proxies
1.2.3 release
* fix erroneous event=completed tracker announce when checking files

View File

@ -236,6 +236,7 @@ namespace boost
POLY(block_uploaded_alert)
POLY(alerts_dropped_alert)
POLY(session_stats_alert)
POLY(socks5_alert)
#if TORRENT_ABI_VERSION == 1
POLY(anonymous_mode_alert)
@ -1029,6 +1030,13 @@ void bind_alert()
.add_property("dropped_alerts", &get_dropped_alerts)
;
class_<socks5_alert, bases<alert>, noncopyable>(
"socks5_alert", no_init)
.def_readonly("error", &socks5_alert::error)
.def_readonly("op", &socks5_alert::op)
.add_property("ip", make_getter(&socks5_alert::ip, by_value()))
;
}
#ifdef _MSC_VER

View File

@ -83,7 +83,7 @@ namespace libtorrent {
constexpr int user_alert_id = 10000;
// this constant represents "max_alert_index" + 1
constexpr int num_alert_types = 96;
constexpr int num_alert_types = 97;
// internal
enum alert_priority
@ -2947,6 +2947,28 @@ TORRENT_VERSION_NAMESPACE_2
std::bitset<num_alert_types> dropped_alerts;
};
// this alert is posted with SOCKS5 related errors, when a SOCKS5 proxy is
// configured. It's enabled with the error_notification alert category.
struct TORRENT_EXPORT socks5_alert final : alert
{
// internal
explicit socks5_alert(aux::stack_allocator& alloc
, tcp::endpoint const& ep, operation_t operation, error_code const& ec);
TORRENT_DEFINE_ALERT(socks5_alert, 96)
static constexpr alert_category_t static_category = alert::error_notification;
std::string message() const override;
// the error
error_code error;
// the operation that failed
operation_t op;
// the endpoint configured as the proxy
aux::noexcept_movable<tcp::endpoint> ip;
};
TORRENT_VERSION_NAMESPACE_2_END
#undef TORRENT_DEFINE_ALERT_IMPL

View File

@ -39,7 +39,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/asio/io_service.hpp>
#include <vector>
namespace libtorrent { namespace aux {
namespace libtorrent {
class alert_manager;
namespace aux {
struct listen_endpoint_t;
struct proxy_settings;
@ -92,7 +96,7 @@ namespace libtorrent { namespace aux {
tcp::endpoint bind(socket_type& s, address const& remote_address
, error_code& ec) const;
void update_proxy(proxy_settings const& settings);
void update_proxy(proxy_settings const& settings, alert_manager& alerts);
// close all sockets
void close();

View File

@ -139,6 +139,7 @@ struct session_stats_header_alert;
struct dht_sample_infohashes_alert;
struct block_uploaded_alert;
struct alerts_dropped_alert;
struct socks5_alert;
TORRENT_VERSION_NAMESPACE_2_END
// include/libtorrent/announce_entry.hpp
@ -280,6 +281,9 @@ TORRENT_VERSION_NAMESPACE_2_END
// include/libtorrent/file_storage.hpp
struct file_entry;
// include/libtorrent/fingerprint.hpp
struct fingerprint;
// include/libtorrent/lazy_entry.hpp
struct pascal_string;
struct lazy_entry;

View File

@ -166,10 +166,13 @@ namespace libtorrent {
// create or read a symlink
symlink,
// handshake with a peer or server
handshake,
};
// maps an operation id (from peer_error_alert and peer_disconnected_alert)
// to its name. See peer_connection for the constants
// to its name. See operation_t for the constants
TORRENT_EXPORT char const* operation_name(operation_t op);
#if TORRENT_ABI_VERSION == 1

View File

@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent {
class alert_manager;
struct socks5;
using udp_send_flags_t = flags::bitfield_flag<std::uint8_t, struct udp_send_flags_tag>;
@ -95,7 +96,7 @@ namespace libtorrent {
void close();
int local_port() const { return m_bind_port; }
void set_proxy_settings(aux::proxy_settings const& ps);
void set_proxy_settings(aux::proxy_settings const& ps, alert_manager& alerts);
aux::proxy_settings const& get_proxy_settings() { return m_proxy_settings; }
bool is_closed() const { return m_abort; }

View File

@ -895,6 +895,7 @@ namespace {
case o::partfile_write: return -1;
case o::hostname_lookup: return -1;
case o::symlink: return -1;
case o::handshake: return -1;
}
return -1;
}
@ -1560,7 +1561,8 @@ namespace {
"partfile_read",
"partfile_write",
"hostname_lookup",
"symlink"
"symlink",
"handshake"
};
int const idx = static_cast<int>(op);
@ -2582,7 +2584,7 @@ namespace {
"dht_pkt", "dht_get_peers_reply", "dht_direct_response",
"picker_log", "session_error", "dht_live_nodes",
"session_stats_header", "dht_sample_infohashes",
"block_uploaded", "alerts_dropped"
"block_uploaded", "alerts_dropped", "socks5"
}};
TORRENT_ASSERT(alert_type >= 0);
@ -2605,6 +2607,21 @@ namespace {
return ret;
}
socks5_alert::socks5_alert(aux::stack_allocator&
, tcp::endpoint const& ep, operation_t operation, error_code const& ec)
: error(ec)
, op(operation)
, ip(ep)
{}
std::string socks5_alert::message() const
{
char buf[512];
std::snprintf(buf, sizeof(buf), "SOCKS5 error. op: %s ec: %s ep: %s"
, operation_name(op), error.message().c_str(), print_endpoint(ip).c_str());
return buf;
}
// this will no longer be necessary in C++17
constexpr alert_category_t torrent_removed_alert::static_category;
constexpr alert_category_t read_piece_alert::static_category;
@ -2693,6 +2710,7 @@ namespace {
constexpr alert_category_t dht_sample_infohashes_alert::static_category;
constexpr alert_category_t block_uploaded_alert::static_category;
constexpr alert_category_t alerts_dropped_alert::static_category;
constexpr alert_category_t socks5_alert::static_category;
#if TORRENT_ABI_VERSION == 1
constexpr alert_category_t anonymous_mode_alert::static_category;
constexpr alert_category_t mmap_cache_alert::static_category;

View File

@ -1665,7 +1665,7 @@ namespace aux {
// change after the session is up and listening, at no other point
// set_proxy_settings is called with the correct proxy configuration,
// internally, this method handle the SOCKS5's connection logic
ret->udp_sock->sock.set_proxy_settings(proxy());
ret->udp_sock->sock.set_proxy_settings(proxy(), m_alerts);
ADD_OUTSTANDING_ASYNC("session_impl::on_udp_packet");
ret->udp_sock->sock.async_read(aux::make_handler(std::bind(&session_impl::on_udp_packet
@ -2100,7 +2100,7 @@ namespace aux {
// change after the session is up and listening, at no other point
// set_proxy_settings is called with the correct proxy configuration,
// internally, this method handle the SOCKS5's connection logic
udp_sock->sock.set_proxy_settings(proxy());
udp_sock->sock.set_proxy_settings(proxy(), m_alerts);
ADD_OUTSTANDING_ASYNC("session_impl::on_udp_packet");
udp_sock->sock.async_read(aux::make_handler(std::bind(&session_impl::on_udp_packet
@ -5286,8 +5286,8 @@ namespace aux {
void session_impl::update_proxy()
{
for (auto& i : m_listen_sockets)
i->udp_sock->sock.set_proxy_settings(proxy());
m_outgoing_sockets.update_proxy(proxy());
i->udp_sock->sock.set_proxy_settings(proxy(), m_alerts);
m_outgoing_sockets.update_proxy(proxy(), m_alerts);
}
void session_impl::update_ip_notifier()

View File

@ -108,10 +108,10 @@ namespace libtorrent { namespace aux {
return tcp::endpoint();
}
void outgoing_sockets::update_proxy(proxy_settings const& settings)
void outgoing_sockets::update_proxy(proxy_settings const& settings, alert_manager& alerts)
{
for (auto const& i : sockets)
i->sock.set_proxy_settings(settings);
i->sock.set_proxy_settings(settings, alerts);
}
void outgoing_sockets::close()

View File

@ -40,6 +40,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/deadline_timer.hpp"
#include "libtorrent/aux_/numeric_cast.hpp"
#include "libtorrent/broadcast_socket.hpp" // for is_v4
#include "libtorrent/alert_manager.hpp"
#include "libtorrent/socks5_stream.hpp" // for socks_error
#include <cstdlib>
#include <functional>
@ -67,11 +69,12 @@ std::size_t const max_header_size = 255;
// the common case cheaper by not allocating this space unconditionally
struct socks5 : std::enable_shared_from_this<socks5>
{
explicit socks5(io_service& ios)
explicit socks5(io_service& ios, alert_manager& alerts)
: m_socks5_sock(ios)
, m_resolver(ios)
, m_timer(ios)
, m_retry_timer(ios)
, m_alerts(alerts)
, m_abort(false)
, m_active(false)
{}
@ -103,6 +106,7 @@ private:
tcp::resolver m_resolver;
deadline_timer m_timer;
deadline_timer m_retry_timer;
alert_manager& m_alerts;
std::array<char, tmp_buffer_size> m_tmp_buf;
aux::proxy_settings m_proxy_settings;
@ -111,7 +115,7 @@ private:
// 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;
tcp::endpoint m_proxy_addr;
// this is where UDP packets that are to be forwarded
// are sent. The result from UDP ASSOCIATE is stored
@ -472,7 +476,8 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
if (err) m_bind_port = ep.port();
}
void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)
void udp_socket::set_proxy_settings(aux::proxy_settings const& ps
, alert_manager& alerts)
{
TORRENT_ASSERT(is_single_thread());
@ -490,8 +495,7 @@ void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)
|| ps.type == settings_pack::socks5_pw)
{
// connect to socks5 server and open up the UDP tunnel
m_socks5_connection = std::make_shared<socks5>(lt::get_io_service(m_socket));
m_socks5_connection = std::make_shared<socks5>(lt::get_io_service(m_socket), alerts);
m_socks5_connection->start(ps);
}
}
@ -517,10 +521,14 @@ void socks5::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
if (e == boost::asio::error::operation_aborted) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::hostname_lookup, e);
return;
}
m_proxy_addr.address(i->endpoint().address());
m_proxy_addr.port(i->endpoint().port());
m_proxy_addr = i->endpoint();
error_code ec;
m_socks5_sock.open(is_v4(m_proxy_addr) ? tcp::v4() : tcp::v6(), ec);
@ -529,7 +537,7 @@ void socks5::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
m_socks5_sock.set_option(boost::asio::socket_base::keep_alive(true), ec);
ADD_OUTSTANDING_ASYNC("socks5::on_connected");
m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port())
m_socks5_sock.async_connect(m_proxy_addr
, std::bind(&socks5::on_connected, self(), _1));
ADD_OUTSTANDING_ASYNC("socks5::on_connect_timeout");
@ -546,6 +554,9 @@ void socks5::on_connect_timeout(error_code const& e)
if (m_abort) return;
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::connect, errors::timed_out);
error_code ignore;
m_socks5_sock.close(ignore);
}
@ -561,7 +572,12 @@ void socks5::on_connected(error_code const& e)
if (m_abort) return;
// we failed to connect to the proxy
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::connect, e);
return;
}
using namespace libtorrent::detail;
@ -591,7 +607,12 @@ void socks5::handshake1(error_code const& e)
{
COMPLETE_ASYNC("socks5::on_handshake1");
if (m_abort) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake, e);
return;
}
ADD_OUTSTANDING_ASYNC("socks5::on_handshake2");
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 2)
@ -603,7 +624,12 @@ void socks5::handshake2(error_code const& e)
COMPLETE_ASYNC("socks5::on_handshake2");
if (m_abort) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake, e);
return;
}
using namespace libtorrent::detail;
@ -613,6 +639,9 @@ void socks5::handshake2(error_code const& e)
if (version < 5)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake
, socks_error::unsupported_version);
error_code ec;
m_socks5_sock.close(ec);
return;
@ -626,6 +655,9 @@ void socks5::handshake2(error_code const& e)
{
if (m_proxy_settings.username.empty())
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake
, socks_error::username_required);
error_code ec;
m_socks5_sock.close(ec);
return;
@ -648,6 +680,10 @@ void socks5::handshake2(error_code const& e)
}
else
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake
, socks_error::unsupported_authentication_method);
error_code ec;
m_socks5_sock.close(ec);
return;
@ -658,7 +694,12 @@ void socks5::handshake3(error_code const& e)
{
COMPLETE_ASYNC("socks5::on_handshake3");
if (m_abort) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake, e);
return;
}
ADD_OUTSTANDING_ASYNC("socks5::on_handshake4");
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 2)
@ -669,7 +710,12 @@ void socks5::handshake4(error_code const& e)
{
COMPLETE_ASYNC("socks5::on_handshake4");
if (m_abort) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake, e);
return;
}
using namespace libtorrent::detail;
@ -705,7 +751,12 @@ void socks5::connect1(error_code const& e)
{
COMPLETE_ASYNC("socks5::connect1");
if (m_abort) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::connect, e);
return;
}
ADD_OUTSTANDING_ASYNC("socks5::connect2");
boost::asio::async_read(m_socks5_sock, boost::asio::buffer(m_tmp_buf.data(), 10)
@ -717,7 +768,12 @@ void socks5::connect2(error_code const& e)
COMPLETE_ASYNC("socks5::connect2");
if (m_abort) return;
if (e) return;
if (e)
{
if (m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::handshake, e);
return;
}
using namespace libtorrent::detail;
@ -757,6 +813,9 @@ void socks5::hung_up(error_code const& e)
if (e == boost::asio::error::operation_aborted || m_abort) return;
if (e && m_alerts.should_post<socks5_alert>())
m_alerts.emplace_alert<socks5_alert>(m_proxy_addr, operation_t::sock_read, e);
// the socks connection was closed, re-open it in a bit
m_retry_timer.expires_from_now(seconds(5));
m_retry_timer.async_wait(std::bind(&socks5::retry_socks_connect

View File

@ -178,10 +178,11 @@ TORRENT_TEST(alerts_types)
TEST_ALERT_TYPE(dht_sample_infohashes_alert, 93, 0, alert::dht_operation_notification);
TEST_ALERT_TYPE(block_uploaded_alert, 94, 0, PROGRESS_NOTIFICATION alert::upload_notification);
TEST_ALERT_TYPE(alerts_dropped_alert, 95, 3, alert::error_notification);
TEST_ALERT_TYPE(socks5_alert, 96, 0, alert::error_notification);
#undef TEST_ALERT_TYPE
TEST_EQUAL(num_alert_types, 96);
TEST_EQUAL(num_alert_types, 97);
TEST_EQUAL(num_alert_types, count_alert_types);
}

View File

@ -489,7 +489,6 @@ TORRENT_TEST(file_priority_multiple_calls)
settings_pack pack = settings();
lt::session ses(pack);
error_code ec;
auto t = ::generate_torrent(true);
add_torrent_params addp;