improved SOCKS5 support

This commit is contained in:
Arvid Norberg 2010-08-03 09:08:37 +00:00
parent e7561e5274
commit fd5f1bf80b
22 changed files with 434 additions and 79 deletions

View File

@ -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

View File

@ -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
=========

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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();
}

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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;
};
}

View File

@ -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));
}

View File

@ -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(

View File

@ -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

View File

@ -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)

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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