improved SOCKS5 support
This commit is contained in:
parent
e7561e5274
commit
fd5f1bf80b
|
@ -1,3 +1,4 @@
|
|||
* improved SOCKS5 support by proxying hostname lookups
|
||||
* improved support for multi-homed clients
|
||||
* added feature to not count downloaded bytes from web seeds in stats
|
||||
* added alert for incoming local service discovery messages
|
||||
|
|
|
@ -4679,6 +4679,7 @@ direct certain traffic to a proxy.
|
|||
};
|
||||
|
||||
proxy_type type;
|
||||
bool proxy_hostnames;
|
||||
};
|
||||
|
||||
``hostname`` is the name or IP of the proxy server. ``port`` is the
|
||||
|
@ -4715,6 +4716,10 @@ options are available:
|
|||
.. _`RFC 1929`: http://www.faqs.org/rfcs/rfc1929.html
|
||||
.. _CONNECT: draft-luotonen-web-proxy-tunneling-01.txt
|
||||
|
||||
``proxy_hostnames`` defaults to true. It means that hostnames should be
|
||||
attempted to be resolved through the proxy instead of using the local DNS
|
||||
service. This is only supported by SOCKS5 and HTTP.
|
||||
|
||||
ip_filter
|
||||
=========
|
||||
|
||||
|
|
|
@ -717,6 +717,9 @@ namespace libtorrent
|
|||
void on_receive_udp(error_code const& e
|
||||
, udp::endpoint const& ep, char const* buf, int len);
|
||||
|
||||
void on_receive_udp_hostname(error_code const& e
|
||||
, char const* hostname, char const* buf, int len);
|
||||
|
||||
// this announce timer is used
|
||||
// by the DHT.
|
||||
deadline_timer m_dht_announce_timer;
|
||||
|
|
|
@ -160,6 +160,8 @@ private:
|
|||
|
||||
std::vector<char> m_recvbuffer;
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
// TODO: for proxies to work correctly over SSL, the
|
||||
// ssl_stream needs to be wrapped inside the socket_type
|
||||
variant_stream<socket_type, ssl_stream<socket_type> > m_sock;
|
||||
#else
|
||||
socket_type m_sock;
|
||||
|
|
|
@ -57,6 +57,23 @@ public:
|
|||
m_password = password;
|
||||
}
|
||||
|
||||
void set_dst_name(std::string const& host)
|
||||
{
|
||||
m_dst_name = host;
|
||||
}
|
||||
|
||||
void close(error_code& ec)
|
||||
{
|
||||
m_dst_name.clear();
|
||||
proxy_base::close(ec);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_dst_name.clear();
|
||||
proxy_base::close();
|
||||
}
|
||||
|
||||
typedef boost::function<void(error_code const&)> handler_type;
|
||||
|
||||
template <class Handler>
|
||||
|
@ -92,6 +109,7 @@ private:
|
|||
// proxy authentication
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
std::string m_dst_name;
|
||||
|
||||
// this is true if the connection is HTTP based and
|
||||
// want to talk directly to the proxy
|
||||
|
|
|
@ -122,25 +122,35 @@ public:
|
|||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
void bind(endpoint_type const& endpoint)
|
||||
{
|
||||
m_sock.bind(endpoint);
|
||||
// m_sock.bind(endpoint);
|
||||
}
|
||||
#endif
|
||||
|
||||
void bind(endpoint_type const& endpoint, error_code& ec)
|
||||
{
|
||||
m_sock.bind(endpoint, ec);
|
||||
// the reason why we ignore binds here is because we don't
|
||||
// (necessarily) yet know what address family the proxy
|
||||
// will resolve to, and binding to the wrong one would
|
||||
// break our connection attempt later. The caller here
|
||||
// doesn't necessarily know that we're proxying, so this
|
||||
// bind address is based on the final endpoint, not the
|
||||
// proxy.
|
||||
// TODO: it would be nice to remember the bind port and bind once we know where the proxy is
|
||||
// m_sock.bind(endpoint, ec);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
void open(protocol_type const& p)
|
||||
{
|
||||
m_sock.open(p);
|
||||
// m_sock.open(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
void open(protocol_type const& p, error_code& ec)
|
||||
{
|
||||
m_sock.open(p, ec);
|
||||
// we need to ignore this for the same reason as stated
|
||||
// for ignoring bind()
|
||||
// m_sock.open(p, ec);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
@ -154,6 +164,7 @@ public:
|
|||
|
||||
void close(error_code& ec)
|
||||
{
|
||||
m_remote_endpoint = endpoint_type();
|
||||
m_sock.close(ec);
|
||||
m_resolver.cancel();
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ namespace libtorrent
|
|||
|
||||
struct TORRENT_EXPORT proxy_settings
|
||||
{
|
||||
proxy_settings() : port(0), type(none) {}
|
||||
proxy_settings() : port(0), type(none)
|
||||
, proxy_hostnames(true) {}
|
||||
|
||||
std::string hostname;
|
||||
int port;
|
||||
|
@ -78,7 +79,10 @@ namespace libtorrent
|
|||
};
|
||||
|
||||
proxy_type type;
|
||||
|
||||
|
||||
// when set to true, hostname are resolved
|
||||
// through the proxy (if supported)
|
||||
bool proxy_hostnames;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT session_settings
|
||||
|
@ -105,7 +109,7 @@ namespace libtorrent
|
|||
, allow_multiple_connections_per_ip(false)
|
||||
, max_failcount(3)
|
||||
, min_reconnect_time(60)
|
||||
, peer_connect_timeout(7)
|
||||
, peer_connect_timeout(15)
|
||||
, ignore_limits_on_local_network(true)
|
||||
, connection_speed(10)
|
||||
, send_redundant_have(false)
|
||||
|
|
|
@ -96,6 +96,27 @@ public:
|
|||
m_password = password;
|
||||
}
|
||||
|
||||
void set_dst_name(std::string const& host)
|
||||
{
|
||||
m_dst_name = host;
|
||||
if (m_dst_name.size() > 255)
|
||||
m_dst_name.resize(255);
|
||||
}
|
||||
|
||||
void close(error_code& ec)
|
||||
{
|
||||
m_hostname.clear();
|
||||
m_dst_name.clear();
|
||||
proxy_base::close(ec);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_hostname.clear();
|
||||
m_dst_name.clear();
|
||||
proxy_base::close();
|
||||
}
|
||||
|
||||
typedef boost::function<void(error_code const&)> handler_type;
|
||||
|
||||
//#error fix error messages to use custom error_code category
|
||||
|
@ -112,7 +133,7 @@ public:
|
|||
// 3.1 send SOCKS5 authentication method message
|
||||
// 3.2 read SOCKS5 authentication response
|
||||
// 3.3 send username+password
|
||||
// 4 send SOCKS command message
|
||||
// 4. send SOCKS command message
|
||||
|
||||
// to avoid unnecessary copying of the handler,
|
||||
// store it in a shaed_ptr
|
||||
|
@ -142,6 +163,7 @@ private:
|
|||
// proxy authentication
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
std::string m_dst_name;
|
||||
int m_version;
|
||||
int m_command;
|
||||
// set to one when we're waiting for the
|
||||
|
|
|
@ -211,6 +211,8 @@ namespace libtorrent
|
|||
void received_bytes(int bytes);
|
||||
virtual bool on_receive(error_code const& ec, udp::endpoint const& ep
|
||||
, char const* buf, int size) { return false; }
|
||||
virtual bool on_receive_hostname(error_code const& ec, char const* hostname
|
||||
, char const* buf, int size) { return false; }
|
||||
|
||||
protected:
|
||||
boost::weak_ptr<request_callback> m_requester;
|
||||
|
@ -246,6 +248,10 @@ namespace libtorrent
|
|||
void received_bytes(int bytes);
|
||||
|
||||
bool incoming_udp(error_code const& e, udp::endpoint const& ep, char const* buf, int size);
|
||||
|
||||
// this is only used for SOCKS packets, since
|
||||
// they may be addressed to hostname
|
||||
bool incoming_udp(error_code const& e, char const* hostname, char const* buf, int size);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -53,8 +53,10 @@ namespace libtorrent
|
|||
public:
|
||||
typedef boost::function<void(error_code const& ec
|
||||
, udp::endpoint const&, char const* buf, int size)> callback_t;
|
||||
typedef boost::function<void(error_code const& ec
|
||||
, char const*, char const* buf, int size)> callback2_t;
|
||||
|
||||
udp_socket(io_service& ios, callback_t const& c, connection_queue& cc);
|
||||
udp_socket(io_service& ios, callback_t const& c, callback2_t const& c2, connection_queue& cc);
|
||||
~udp_socket();
|
||||
|
||||
bool is_open() const
|
||||
|
@ -67,6 +69,9 @@ namespace libtorrent
|
|||
}
|
||||
io_service& get_io_service() { return m_ipv4_sock.get_io_service(); }
|
||||
|
||||
// this is only valid when using a socks5 proxy
|
||||
void send_hostname(char const* hostname, int port, char const* p, int len, error_code& ec);
|
||||
|
||||
void send(udp::endpoint const& ep, char const* p, int len, error_code& ec);
|
||||
void bind(udp::endpoint const& ep, error_code& ec);
|
||||
void bind(int port);
|
||||
|
@ -89,13 +94,19 @@ namespace libtorrent
|
|||
struct queued_packet
|
||||
{
|
||||
udp::endpoint ep;
|
||||
char* hostname;
|
||||
buffer buf;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// callback for regular incoming packets
|
||||
callback_t m_callback;
|
||||
|
||||
// callback for proxied incoming packets with a domain
|
||||
// name as source
|
||||
callback2_t m_callback2;
|
||||
|
||||
void on_read(udp::socket* sock, error_code const& e, std::size_t bytes_transferred);
|
||||
void on_name_lookup(error_code const& e, tcp::resolver::iterator i);
|
||||
void on_timeout();
|
||||
|
@ -111,6 +122,7 @@ namespace libtorrent
|
|||
void hung_up(error_code const& e);
|
||||
|
||||
void wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec);
|
||||
void wrap(char const* hostname, int port, char const* p, int len, error_code& ec);
|
||||
void unwrap(error_code const& e, char const* buf, int size);
|
||||
|
||||
mutable mutex m_mutex;
|
||||
|
@ -133,7 +145,7 @@ namespace libtorrent
|
|||
proxy_settings m_proxy_settings;
|
||||
connection_queue& m_cc;
|
||||
tcp::resolver m_resolver;
|
||||
char m_tmp_buf[100];
|
||||
char m_tmp_buf[270];
|
||||
bool m_queue_packets;
|
||||
bool m_tunnel_packets;
|
||||
bool m_abort;
|
||||
|
@ -151,7 +163,7 @@ namespace libtorrent
|
|||
|
||||
struct rate_limited_udp_socket : public udp_socket
|
||||
{
|
||||
rate_limited_udp_socket(io_service& ios, callback_t const& c, connection_queue& cc);
|
||||
rate_limited_udp_socket(io_service& ios, callback_t const& c, callback2_t const& c2, connection_queue& cc);
|
||||
void set_rate_limit(int limit) { m_rate_limit = limit; }
|
||||
bool can_send() const { return int(m_queue.size()) >= m_queue_size_limit; }
|
||||
bool send(udp::endpoint const& ep, char const* p, int len, error_code& ec, int flags = 0);
|
||||
|
|
|
@ -93,9 +93,12 @@ namespace libtorrent
|
|||
|
||||
void name_lookup(error_code const& error, tcp::resolver::iterator i);
|
||||
void timeout(error_code const& error);
|
||||
void start_announce();
|
||||
|
||||
bool on_receive(error_code const& e, udp::endpoint const& ep
|
||||
, char const* buf, int size);
|
||||
bool on_receive_hostname(error_code const& e, char const* hostname
|
||||
, char const* buf, int size);
|
||||
bool on_connect_response(char const* buf, int size);
|
||||
bool on_announce_response(char const* buf, int size);
|
||||
bool on_scrape_response(char const* buf, int size);
|
||||
|
@ -108,9 +111,8 @@ namespace libtorrent
|
|||
|
||||
tracker_manager& m_man;
|
||||
|
||||
// udp::resolver m_name_lookup;
|
||||
// udp_socket m_socket;
|
||||
bool m_abort;
|
||||
std::string m_hostname;
|
||||
udp::endpoint m_target;
|
||||
std::list<tcp::endpoint> m_endpoints;
|
||||
|
||||
|
@ -128,6 +130,8 @@ namespace libtorrent
|
|||
static mutex m_cache_mutex;
|
||||
|
||||
action_t m_state;
|
||||
|
||||
proxy_settings m_proxy;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -296,6 +296,16 @@ void http_connection::start(std::string const& hostname, std::string const& port
|
|||
}
|
||||
else
|
||||
#endif
|
||||
if (ps && ps->proxy_hostnames
|
||||
&& (ps->type == proxy_settings::socks5
|
||||
|| ps->type == proxy_settings::socks5_pw))
|
||||
{
|
||||
m_hostname = hostname;
|
||||
m_port = port;
|
||||
m_endpoints.push_back(tcp::endpoint(address(), atoi(port.c_str())));
|
||||
queue_connect();
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp::resolver::query query(hostname, port);
|
||||
m_resolver.async_resolve(query, boost::bind(&http_connection::on_resolve
|
||||
|
@ -452,6 +462,23 @@ void http_connection::queue_connect()
|
|||
void http_connection::connect(int ticket, tcp::endpoint target_address)
|
||||
{
|
||||
m_connection_ticket = ticket;
|
||||
if (m_proxy.proxy_hostnames
|
||||
&& (m_proxy.type == proxy_settings::socks5
|
||||
|| m_proxy.type == proxy_settings::socks5_pw))
|
||||
{
|
||||
// we're using a socks proxy and we're resolving
|
||||
// hostnames through it
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
if (!m_ssl)
|
||||
{
|
||||
TORRENT_ASSERT(m_sock.get<socket_type>()->get<socks5_stream>());
|
||||
m_sock.get<socket_type>()->get<socks5_stream>()->set_dst_name(m_hostname);
|
||||
}
|
||||
#else
|
||||
TORRENT_ASSERT(m_sock.get<socks5_stream>());
|
||||
m_sock.get<socks5_stream>()->set_dst_name(m_hostname);
|
||||
#endif
|
||||
}
|
||||
m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
|
||||
, shared_from_this(), _1));
|
||||
}
|
||||
|
|
|
@ -75,8 +75,16 @@ namespace libtorrent
|
|||
|
||||
// send CONNECT
|
||||
std::back_insert_iterator<std::vector<char> > p(m_buffer);
|
||||
write_string("CONNECT " + print_endpoint(m_remote_endpoint)
|
||||
+ " HTTP/1.0\r\n", p);
|
||||
std::string endpoint;
|
||||
if (!m_hostname.empty())
|
||||
{
|
||||
endpoint = m_hostname + ':' + to_string(m_remote_endpoint.port()).elems;
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = print_endpoint(m_remote_endpoint);
|
||||
}
|
||||
write_string("CONNECT " + endpoint + " HTTP/1.0\r\n", p);
|
||||
if (!m_user.empty())
|
||||
{
|
||||
write_string("Proxy-Authorization: Basic " + base64encode(
|
||||
|
|
|
@ -3174,9 +3174,11 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(m_connecting);
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
error_code ec;
|
||||
(*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << m_remote.address().to_string(ec)
|
||||
(*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << print_endpoint(m_remote)
|
||||
<< "\n";
|
||||
#endif
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << print_endpoint(m_remote) << "\n";
|
||||
#endif
|
||||
disconnect(errors::timed_out, 1);
|
||||
}
|
||||
|
@ -4786,8 +4788,7 @@ namespace libtorrent
|
|||
|
||||
error_code ec;
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " CONNECTING: " << m_remote.address().to_string(ec)
|
||||
<< ":" << m_remote.port() << "\n";
|
||||
(*m_ses.m_logger) << time_now_string() << " ON_CONNECT: " << print_endpoint(m_remote) << "\n";
|
||||
#endif
|
||||
|
||||
m_connection_ticket = ticket;
|
||||
|
@ -4802,6 +4803,9 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " OPEN " << (m_remote.address().is_v4()?"IPv4":"IPv6") << "\n";
|
||||
#endif
|
||||
m_socket->open(m_remote.protocol(), ec);
|
||||
if (ec)
|
||||
{
|
||||
|
@ -4809,27 +4813,23 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
// set the socket to non-blocking, so that we can
|
||||
// read the entire buffer on each read event we get
|
||||
tcp::socket::non_blocking_io ioc(true);
|
||||
m_socket->io_control(ioc, ec);
|
||||
if (ec)
|
||||
{
|
||||
disconnect(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
tcp::endpoint bind_interface = t->get_interface();
|
||||
|
||||
std::pair<int, int> const& out_ports = m_ses.settings().outgoing_ports;
|
||||
if (out_ports.first > 0 && out_ports.second >= out_ports.first)
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " SET REUSE ADDRESS\n";
|
||||
#endif
|
||||
m_socket->set_option(socket_acceptor::reuse_address(true), ec);
|
||||
if (ec)
|
||||
{
|
||||
disconnect(ec);
|
||||
return;
|
||||
}
|
||||
// ignore errors because the underlying socket may not
|
||||
// be opened yet. This happens when we're routing through
|
||||
// a proxy. In that case, we don't yet know the address of
|
||||
// the proxy server, and more importantly, we don't know
|
||||
// the address family of its address. This means we can't
|
||||
// open the socket yet. The socks abstraction layer defers
|
||||
// opening it.
|
||||
ec.clear();
|
||||
bind_interface.port(m_ses.next_port());
|
||||
}
|
||||
|
||||
|
@ -4845,12 +4845,21 @@ namespace libtorrent
|
|||
bind_interface.address(address_v4::any());
|
||||
}
|
||||
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " BIND: " << print_endpoint(bind_interface) << "\n";
|
||||
#endif
|
||||
m_socket->bind(bind_interface, ec);
|
||||
if (ec)
|
||||
{
|
||||
disconnect(ec);
|
||||
return;
|
||||
}
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " ASYNC_CONNECT: " << print_endpoint(m_remote) << "\n";
|
||||
#endif
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " ASYNC_CONNECT: " << print_endpoint(m_remote) << "\n";
|
||||
#endif
|
||||
m_socket->async_connect(m_remote
|
||||
, boost::bind(&peer_connection::on_connection_complete, self(), _1));
|
||||
m_connect = time_now();
|
||||
|
@ -4882,7 +4891,11 @@ namespace libtorrent
|
|||
if (e)
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " CONNECTION FAILED: " << m_remote.address().to_string(ec)
|
||||
(*m_ses.m_logger) << time_now_string() << " CONNECTION FAILED: " << print_endpoint(m_remote)
|
||||
<< ": " << e.message() << "\n";
|
||||
#endif
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " CONNECTION FAILED: " << print_endpoint(m_remote)
|
||||
<< ": " << e.message() << "\n";
|
||||
#endif
|
||||
disconnect(e, 1);
|
||||
|
@ -4898,10 +4911,23 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(m_socket);
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " COMPLETED: " << m_remote.address().to_string(ec)
|
||||
(*m_ses.m_logger) << time_now_string() << " COMPLETED: " << print_endpoint(m_remote)
|
||||
<< " rtt = " << m_rtt << "\n";
|
||||
#endif
|
||||
|
||||
// set the socket to non-blocking, so that we can
|
||||
// read the entire buffer on each read event we get
|
||||
tcp::socket::non_blocking_io ioc(true);
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_logger) << time_now_string() << " SET NON-BLOCKING\n";
|
||||
#endif
|
||||
m_socket->io_control(ioc, ec);
|
||||
if (ec)
|
||||
{
|
||||
disconnect(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_remote == m_socket->local_endpoint(ec))
|
||||
{
|
||||
// if the remote endpoint is the same as the local endpoint, we're connected
|
||||
|
|
|
@ -511,7 +511,9 @@ namespace aux {
|
|||
, m_dht_announce_timer(m_io_service)
|
||||
#endif
|
||||
, m_external_udp_port(0)
|
||||
, m_udp_socket(m_io_service, boost::bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
|
||||
, m_udp_socket(m_io_service
|
||||
, boost::bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
|
||||
, boost::bind(&session_impl::on_receive_udp_hostname, this, _1, _2, _3, _4)
|
||||
, m_half_open)
|
||||
, m_timer(m_io_service)
|
||||
, m_lsd_announce_timer(m_io_service)
|
||||
|
@ -1640,6 +1642,17 @@ namespace aux {
|
|||
}
|
||||
}
|
||||
|
||||
void session_impl::on_receive_udp_hostname(error_code const& e
|
||||
, char const* hostname, char const* buf, int len)
|
||||
{
|
||||
// it's probably a udp tracker response
|
||||
if (m_tracker_manager.incoming_udp(e, hostname, buf, len))
|
||||
{
|
||||
m_stat.received_tracker_bytes(len + 28);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener)
|
||||
|
|
|
@ -79,6 +79,9 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
m_sock.open(i->endpoint().protocol());
|
||||
// TOOD: we could bind the socket here, since we know what the
|
||||
// target endpoint is of the proxy
|
||||
m_sock.async_connect(i->endpoint(), boost::bind(
|
||||
&socks5_stream::connected, this, _1, h));
|
||||
}
|
||||
|
@ -259,14 +262,27 @@ namespace libtorrent
|
|||
if (m_version == 5)
|
||||
{
|
||||
// send SOCKS5 connect command
|
||||
m_buffer.resize(6 + (m_remote_endpoint.address().is_v4()?4:16));
|
||||
m_buffer.resize(6 + (!m_dst_name.empty()
|
||||
?m_dst_name.size() + 1
|
||||
:(m_remote_endpoint.address().is_v4()?4:16)));
|
||||
char* p = &m_buffer[0];
|
||||
write_uint8(5, p); // SOCKS VERSION 5
|
||||
write_uint8(m_command, p); // CONNECT/BIND command
|
||||
write_uint8(0, p); // reserved
|
||||
write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
|
||||
write_endpoint(m_remote_endpoint, p);
|
||||
TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size()));
|
||||
if (!m_dst_name.empty())
|
||||
{
|
||||
write_uint8(3, p); // address type
|
||||
TORRENT_ASSERT(m_dst_name.size() <= 255);
|
||||
write_uint8(m_dst_name.size(), p);
|
||||
std::copy(m_dst_name.begin(), m_dst_name.end(), p);
|
||||
p += m_dst_name.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
|
||||
write_address(m_remote_endpoint.address(), p);
|
||||
}
|
||||
write_uint16(m_remote_endpoint.port(), p);
|
||||
}
|
||||
else if (m_version == 4)
|
||||
{
|
||||
|
|
|
@ -1729,7 +1729,7 @@ namespace libtorrent
|
|||
, tracker_ips.end(), boost::bind(&address::is_v4, _1) != tracker_ip.is_v4());
|
||||
if (i != tracker_ips.end())
|
||||
{
|
||||
// the tracker did resolve to a different type if address, so announce
|
||||
// the tracker did resolve to a different type of address, so announce
|
||||
// to that as well
|
||||
|
||||
// tell the tracker to bind to the opposite protocol type
|
||||
|
@ -3333,6 +3333,18 @@ namespace libtorrent
|
|||
// TODO: we have already resolved this URL, just connect
|
||||
}
|
||||
|
||||
if (m_ses.m_port_filter.access(port) & port_filter::blocked)
|
||||
{
|
||||
if (m_ses.m_alerts.should_post<url_seed_alert>())
|
||||
{
|
||||
m_ses.m_alerts.post_alert(
|
||||
url_seed_alert(get_handle(), web->url, errors::port_blocked));
|
||||
}
|
||||
// never try it again
|
||||
m_web_seeds.erase(web);
|
||||
return;
|
||||
}
|
||||
|
||||
web->resolving = true;
|
||||
proxy_settings const& ps = m_ses.web_seed_proxy();
|
||||
if (ps.type == proxy_settings::http
|
||||
|
@ -3343,20 +3355,14 @@ namespace libtorrent
|
|||
m_ses.m_host_resolver.async_resolve(q,
|
||||
boost::bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, web));
|
||||
}
|
||||
else if (ps.proxy_hostnames
|
||||
&& (ps.type == proxy_settings::socks5
|
||||
|| ps.type == proxy_settings::socks5_pw))
|
||||
{
|
||||
connect_web_seed(web, tcp::endpoint(address(), port));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_ses.m_port_filter.access(port) & port_filter::blocked)
|
||||
{
|
||||
if (m_ses.m_alerts.should_post<url_seed_alert>())
|
||||
{
|
||||
m_ses.m_alerts.post_alert(
|
||||
url_seed_alert(get_handle(), web->url, errors::port_blocked));
|
||||
}
|
||||
// never try it again
|
||||
m_web_seeds.erase(web);
|
||||
return;
|
||||
}
|
||||
|
||||
tcp::resolver::query q(hostname, to_string(port).elems);
|
||||
m_ses.m_host_resolver.async_resolve(q,
|
||||
boost::bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, web
|
||||
|
@ -3456,7 +3462,11 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
tcp::endpoint a(host->endpoint());
|
||||
connect_web_seed(web, a);
|
||||
}
|
||||
|
||||
void torrent::connect_web_seed(std::list<web_seed_entry>::iterator web, tcp::endpoint const& a)
|
||||
{
|
||||
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
|
||||
{
|
||||
if (m_ses.m_alerts.should_post<peer_blocked_alert>())
|
||||
|
@ -3476,14 +3486,31 @@ namespace libtorrent
|
|||
(void)ret;
|
||||
TORRENT_ASSERT(ret);
|
||||
|
||||
if (m_ses.web_seed_proxy().type == proxy_settings::http
|
||||
|| m_ses.web_seed_proxy().type == proxy_settings::http_pw)
|
||||
proxy_settings const& ps = m_ses.web_seed_proxy();
|
||||
if (ps.type == proxy_settings::http
|
||||
|| ps.type == proxy_settings::http_pw)
|
||||
{
|
||||
// the web seed connection will talk immediately to
|
||||
// the proxy, without requiring CONNECT support
|
||||
s->get<http_stream>()->set_no_connect(true);
|
||||
}
|
||||
|
||||
if (ps.proxy_hostnames
|
||||
&& (ps.type == proxy_settings::socks5
|
||||
|| ps.type == proxy_settings::socks5_pw))
|
||||
{
|
||||
// we're using a socks proxy and we're resolving
|
||||
// hostnames through it
|
||||
TORRENT_ASSERT(s->get<socks5_stream>());
|
||||
|
||||
using boost::tuples::ignore;
|
||||
std::string hostname;
|
||||
error_code ec;
|
||||
boost::tie(ignore, ignore, hostname, ignore, ignore)
|
||||
= parse_url_components(web->url, ec);
|
||||
s->get<socks5_stream>()->set_dst_name(hostname);
|
||||
}
|
||||
|
||||
boost::intrusive_ptr<peer_connection> c;
|
||||
if (web->type == web_seed_entry::url_seed)
|
||||
{
|
||||
|
|
|
@ -266,6 +266,20 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
bool tracker_manager::incoming_udp(error_code const& e
|
||||
, char const* hostname, char const* buf, int size)
|
||||
{
|
||||
for (tracker_connections_t::iterator i = m_connections.begin();
|
||||
i != m_connections.end();)
|
||||
{
|
||||
boost::intrusive_ptr<tracker_connection> p = *i;
|
||||
++i;
|
||||
// on_receive() may remove the tracker connection from the list
|
||||
if (p->on_receive_hostname(e, hostname, buf, size)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void tracker_manager::abort_all_requests(bool all)
|
||||
{
|
||||
// removes all connections from m_connections
|
||||
|
|
|
@ -47,9 +47,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace libtorrent;
|
||||
|
||||
udp_socket::udp_socket(asio::io_service& ios, udp_socket::callback_t const& c
|
||||
udp_socket::udp_socket(asio::io_service& ios
|
||||
, udp_socket::callback_t const& c
|
||||
, udp_socket::callback2_t const& c2
|
||||
, connection_queue& cc)
|
||||
: m_callback(c)
|
||||
, m_callback2(c2)
|
||||
, m_ipv4_sock(ios)
|
||||
#if TORRENT_USE_IPV6
|
||||
, m_ipv6_sock(ios)
|
||||
|
@ -93,6 +96,33 @@ udp_socket::~udp_socket()
|
|||
#define CHECK_MAGIC do {} while (false)
|
||||
#endif
|
||||
|
||||
void udp_socket::send_hostname(char const* hostname, int port
|
||||
, char const* p, int len, error_code& ec)
|
||||
{
|
||||
CHECK_MAGIC;
|
||||
|
||||
TORRENT_ASSERT(is_open());
|
||||
|
||||
// if the sockets are closed, the udp_socket is closing too
|
||||
if (!is_open()) return;
|
||||
|
||||
if (m_tunnel_packets)
|
||||
{
|
||||
// send udp packets through SOCKS5 server
|
||||
wrap(hostname, port, p, len, ec);
|
||||
return;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(m_queue_packets);
|
||||
if (!m_queue_packets) return;
|
||||
|
||||
m_queue.push_back(queued_packet());
|
||||
queued_packet& qp = m_queue.back();
|
||||
qp.ep.port(port);
|
||||
qp.hostname = strdup(hostname);
|
||||
qp.buf.insert(qp.buf.begin(), p, p + len);
|
||||
}
|
||||
|
||||
void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_code& ec)
|
||||
{
|
||||
CHECK_MAGIC;
|
||||
|
@ -114,6 +144,7 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_cod
|
|||
m_queue.push_back(queued_packet());
|
||||
queued_packet& qp = m_queue.back();
|
||||
qp.ep = ep;
|
||||
qp.hostname = 0;
|
||||
qp.buf.insert(qp.buf.begin(), p, p + len);
|
||||
return;
|
||||
}
|
||||
|
@ -288,8 +319,38 @@ void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, error_cod
|
|||
write_uint16(0, h); // reserved
|
||||
write_uint8(0, h); // fragment
|
||||
write_uint8(ep.address().is_v4()?1:4, h); // atyp
|
||||
write_address(ep.address(), h);
|
||||
write_uint16(ep.port(), h);
|
||||
write_endpoint(ep, h);
|
||||
|
||||
boost::array<asio::const_buffer, 2> iovec;
|
||||
iovec[0] = asio::const_buffer(header, h - header);
|
||||
iovec[1] = asio::const_buffer(p, len);
|
||||
|
||||
#if TORRENT_USE_IPV6
|
||||
if (m_proxy_addr.address().is_v4() && m_ipv4_sock.is_open())
|
||||
#endif
|
||||
m_ipv4_sock.send_to(iovec, m_proxy_addr, 0, ec);
|
||||
#if TORRENT_USE_IPV6
|
||||
else
|
||||
m_ipv6_sock.send_to(iovec, m_proxy_addr, 0, ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
void udp_socket::wrap(char const* hostname, int port, char const* p, int len, error_code& ec)
|
||||
{
|
||||
CHECK_MAGIC;
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
char header[270];
|
||||
char* h = header;
|
||||
|
||||
write_uint16(0, h); // reserved
|
||||
write_uint8(0, h); // fragment
|
||||
write_uint8(3, h); // atyp
|
||||
int hostlen = (std::min)(strlen(hostname), size_t(255));
|
||||
write_uint8(hostlen, h); // hostname len
|
||||
memcpy(h, hostname, hostlen);
|
||||
h += hostlen;
|
||||
write_uint16(port, h);
|
||||
|
||||
boost::array<asio::const_buffer, 2> iovec;
|
||||
iovec[0] = asio::const_buffer(header, h - header);
|
||||
|
@ -337,7 +398,11 @@ void udp_socket::unwrap(error_code const& e, char const* buf, int size)
|
|||
#endif
|
||||
else
|
||||
{
|
||||
// domain name not supported
|
||||
int len = read_uint8(p);
|
||||
if (len > (buf + size) - p) return;
|
||||
std::string hostname(p, p + len);
|
||||
p += len;
|
||||
m_callback2(e, hostname.c_str(), p, size - (p - buf));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -646,9 +711,20 @@ void udp_socket::socks_forward_udp(mutex::scoped_lock& l)
|
|||
write_uint8(5, p); // SOCKS VERSION 5
|
||||
write_uint8(3, p); // UDP ASSOCIATE command
|
||||
write_uint8(0, p); // reserved
|
||||
write_uint8(1, p); // ATYP IPv4
|
||||
write_uint32(0, p); // IP any
|
||||
write_uint16(m_bind_port, p);
|
||||
error_code ec;
|
||||
tcp::endpoint local = m_socks5_sock.local_endpoint(ec);
|
||||
write_uint8(local.address().is_v4() ? 1 : 4, p); // ATYP IPv4
|
||||
detail::write_address(local.address(), p);
|
||||
int port = 0;
|
||||
#if TORRENT_USE_IPV6
|
||||
if (local.address().is_v4())
|
||||
#endif
|
||||
port = m_ipv4_sock.local_endpoint(ec).port();
|
||||
#if TORRENT_USE_IPV6
|
||||
else
|
||||
port = m_ipv6_sock.local_endpoint(ec).port();
|
||||
#endif
|
||||
detail::write_uint16(port , p);
|
||||
|
||||
asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
|
||||
, boost::bind(&udp_socket::connect1, this, _1));
|
||||
|
@ -702,7 +778,15 @@ void udp_socket::connect2(error_code const& e)
|
|||
{
|
||||
queued_packet const& p = m_queue.front();
|
||||
error_code ec;
|
||||
udp_socket::send(p.ep, &p.buf[0], p.buf.size(), ec);
|
||||
if (p.hostname)
|
||||
{
|
||||
udp_socket::send_hostname(p.hostname, p.ep.port(), &p.buf[0], p.buf.size(), ec);
|
||||
free(p.hostname);
|
||||
}
|
||||
else
|
||||
{
|
||||
udp_socket::send(p.ep, &p.buf[0], p.buf.size(), ec);
|
||||
}
|
||||
m_queue.pop_front();
|
||||
}
|
||||
|
||||
|
@ -724,8 +808,10 @@ void udp_socket::hung_up(error_code const& e)
|
|||
}
|
||||
|
||||
rate_limited_udp_socket::rate_limited_udp_socket(io_service& ios
|
||||
, callback_t const& c, connection_queue& cc)
|
||||
: udp_socket(ios, c, cc)
|
||||
, callback_t const& c
|
||||
, callback2_t const& c2
|
||||
, connection_queue& cc)
|
||||
: udp_socket(ios, c, c2, cc)
|
||||
, m_timer(ios)
|
||||
, m_queue_size_limit(200)
|
||||
, m_rate_limit(4000)
|
||||
|
|
|
@ -75,6 +75,7 @@ namespace libtorrent
|
|||
, m_ses(ses)
|
||||
, m_attempts(0)
|
||||
, m_state(action_error)
|
||||
, m_proxy(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -98,18 +99,30 @@ namespace libtorrent
|
|||
|
||||
session_settings const& settings = m_ses.settings();
|
||||
|
||||
tcp::resolver::query q(hostname, to_string(port).elems);
|
||||
m_ses.m_host_resolver.async_resolve(q
|
||||
, boost::bind(
|
||||
&udp_tracker_connection::name_lookup, self(), _1, _2));
|
||||
if (m_proxy.proxy_hostnames
|
||||
&& (m_proxy.type == proxy_settings::socks5
|
||||
|| m_proxy.type == proxy_settings::socks5_pw))
|
||||
{
|
||||
m_hostname = hostname;
|
||||
m_target.port(port);
|
||||
start_announce();
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp::resolver::query q(hostname, to_string(port).elems);
|
||||
m_ses.m_host_resolver.async_resolve(q
|
||||
, boost::bind(
|
||||
&udp_tracker_connection::name_lookup, self(), _1, _2));
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||
boost::shared_ptr<request_callback> cb = requester();
|
||||
if (cb) cb->debug_log(("*** UDP_TRACKER [ initiating name lookup: " + hostname + " ]").c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
set_timeout(tracker_req().event == tracker_request::stopped
|
||||
? settings.stop_tracker_timeout
|
||||
: settings.tracker_completion_timeout
|
||||
, settings.tracker_receive_timeout);
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||
boost::shared_ptr<request_callback> cb = requester();
|
||||
if (cb) cb->debug_log(("*** UDP_TRACKER [ initiating name lookup: " + hostname + " ]").c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void udp_tracker_connection::name_lookup(error_code const& error
|
||||
|
@ -197,6 +210,11 @@ namespace libtorrent
|
|||
|
||||
if (cb) cb->m_tracker_address = tcp::endpoint(m_target.address(), m_target.port());
|
||||
|
||||
start_announce();
|
||||
}
|
||||
|
||||
void udp_tracker_connection::start_announce()
|
||||
{
|
||||
mutex::scoped_lock l(m_cache_mutex);
|
||||
std::map<address, connection_cache_entry>::iterator cc
|
||||
= m_connection_cache.find(m_target.address());
|
||||
|
@ -238,6 +256,16 @@ namespace libtorrent
|
|||
tracker_connection::close();
|
||||
}
|
||||
|
||||
bool udp_tracker_connection::on_receive_hostname(error_code const& e
|
||||
, char const* hostname, char const* buf, int size)
|
||||
{
|
||||
// just ignore the hostname this came from, pretend that
|
||||
// it's from the same endpoint we sent it to (i.e. the same
|
||||
// port). We have so many other ways of confirming this packet
|
||||
// comes from the tracker anyway, so it's not a big deal
|
||||
return on_receive(e, m_target, buf, size);
|
||||
}
|
||||
|
||||
bool udp_tracker_connection::on_receive(error_code const& e
|
||||
, udp::endpoint const& ep, char const* buf, int size)
|
||||
{
|
||||
|
@ -367,7 +395,14 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(ptr - buf == sizeof(buf));
|
||||
|
||||
error_code ec;
|
||||
m_ses.m_udp_socket.send(m_target, buf, 16, ec);
|
||||
if (!m_hostname.empty())
|
||||
{
|
||||
m_ses.m_udp_socket.send_hostname(m_hostname.c_str(), m_target.port(), buf, 16, ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ses.m_udp_socket.send(m_target, buf, 16, ec);
|
||||
}
|
||||
m_state = action_connect;
|
||||
sent_bytes(16 + 28); // assuming UDP/IP header
|
||||
++m_attempts;
|
||||
|
@ -403,7 +438,14 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(out - buf == sizeof(buf));
|
||||
|
||||
error_code ec;
|
||||
m_ses.m_udp_socket.send(m_target, buf, sizeof(buf), ec);
|
||||
if (!m_hostname.empty())
|
||||
{
|
||||
m_ses.m_udp_socket.send_hostname(m_hostname.c_str(), m_target.port(), buf, sizeof(buf), ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ses.m_udp_socket.send(m_target, buf, sizeof(buf), ec);
|
||||
}
|
||||
m_state = action_scrape;
|
||||
sent_bytes(sizeof(buf) + 28); // assuming UDP/IP header
|
||||
++m_attempts;
|
||||
|
@ -590,7 +632,14 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
error_code ec;
|
||||
m_ses.m_udp_socket.send(m_target, buf, sizeof(buf), ec);
|
||||
if (!m_hostname.empty())
|
||||
{
|
||||
m_ses.m_udp_socket.send_hostname(m_hostname.c_str(), m_target.port(), buf, sizeof(buf), ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ses.m_udp_socket.send(m_target, buf, sizeof(buf), ec);
|
||||
}
|
||||
m_state = action_announce;
|
||||
sent_bytes(sizeof(buf) + 28); // assuming UDP/IP header
|
||||
++m_attempts;
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace libtorrent
|
|||
// according to the settings.
|
||||
set_timeout(ses.settings().urlseed_timeout);
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << "*** web_peer_connection\n";
|
||||
(*m_logger) << "*** web_peer_connection " << url << "\n";
|
||||
#endif
|
||||
|
||||
std::string protocol;
|
||||
|
|
|
@ -71,7 +71,8 @@ void http_connect_handler(http_connection& c)
|
|||
error_code ec;
|
||||
std::cerr << "connected to: " << print_endpoint(c.socket().remote_endpoint(ec))
|
||||
<< std::endl;
|
||||
TEST_CHECK(c.socket().remote_endpoint(ec).address() == address::from_string("127.0.0.1", ec));
|
||||
// this is not necessarily true when using a proxy and proxying hostnames
|
||||
// TEST_CHECK(c.socket().remote_endpoint(ec).address() == address::from_string("127.0.0.1", ec));
|
||||
}
|
||||
|
||||
void http_handler(error_code const& ec, http_parser const& parser
|
||||
|
|
Loading…
Reference in New Issue