merged anonymous mode fix from RC_0_16

This commit is contained in:
Arvid Norberg 2013-06-12 07:57:13 +00:00
parent dd183c2116
commit 6bc908fd49
9 changed files with 295 additions and 56 deletions

View File

@ -22,6 +22,7 @@
* fix uTP edge case where udp socket buffer fills up
* fix nagle implementation in uTP
* fix proxy failure semantics with regards to anonymous mode
* fix round-robin seed-unchoke algorithm
* add bootstrap.sh to generage configure script and run configure
* fix bug in SOCK5 UDP support

View File

@ -186,6 +186,8 @@ namespace libtorrent
void connect2(error_code const& e);
void hung_up(error_code const& e);
void drain_queue();
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);

View File

@ -2406,10 +2406,13 @@ namespace libtorrent
if (settings().force_proxy)
{
// in force_proxy mode we don't talk directly to trackers
// unless there is a proxy
// we only allow trackers if there is a proxy and issue
// a warning if there isn't one
std::string protocol = req.url.substr(0, req.url.find(':'));
int proxy_type = m_ses.m_proxy.type;
// http can run over any proxy, so as long as one is used
// it's OK. If no proxy is configured, skip this tracker
if ((protocol == "http" || protocol == "https")
&& proxy_type == proxy_settings::none)
{
@ -2423,10 +2426,13 @@ namespace libtorrent
continue;
}
// for UDP, only socks5 and i2p proxies will work.
// if we're not using one of those proxues with a UDP
// tracker, skip it
if (protocol == "udp"
|| (proxy_type != proxy_settings::socks5
&& proxy_type != proxy_settings::socks5
&& proxy_type != proxy_settings::socks5_pw
&& proxy_type != proxy_settings::i2p_proxy))
&& proxy_type != proxy_settings::i2p_proxy)
{
ae.next_announce = now + minutes(10);
if (m_ses.m_alerts.should_post<anonymous_mode_alert>())
@ -2575,8 +2581,7 @@ namespace libtorrent
INVARIANT_CHECK;
TORRENT_ASSERT(r.kind == tracker_request::announce_request);
TORRENT_ASSERT(!tracker_ips.empty());
if (external_ip != address())
if (external_ip != address() && !tracker_ips.empty())
m_ses.set_external_address(external_ip, aux::session_impl::source_tracker
, *tracker_ips.begin());

View File

@ -153,8 +153,14 @@ void udp_socket::send_hostname(char const* hostname, int port
}
// this function is only supported when we're using a proxy
TORRENT_ASSERT(m_queue_packets);
if (!m_queue_packets) return;
if (!m_queue_packets)
{
address target = address::from_string(hostname, ec);
if (!ec) send(udp::endpoint(target, port), p, len, ec, 0);
return;
}
if (m_queue.size() > 1000) return;
m_queue.push_back(queued_packet());
queued_packet& qp = m_queue.back();
@ -186,13 +192,11 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len
wrap(ep, p, len, ec);
return;
}
else if (m_force_proxy)
{
return;
}
if (m_queue_packets)
{
if (m_queue.size() > 1000) return;
m_queue.push_back(queued_packet());
queued_packet& qp = m_queue.back();
qp.ep = ep;
@ -202,10 +206,8 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len
return;
}
}
else if (m_force_proxy)
{
return;
}
if (m_force_proxy) return;
#if TORRENT_USE_IPV6
if (ep.address().is_v6() && m_ipv6_sock.is_open())
@ -777,6 +779,9 @@ void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
if (e)
{
call_handler(e, udp::endpoint(), 0, 0);
drain_queue();
return;
}
@ -818,7 +823,10 @@ void udp_socket::on_timeout()
+ m_outstanding_resolve
+ m_outstanding_connect_queue
+ m_outstanding_socks);
m_queue_packets = false;
if (m_abort) return;
CHECK_MAGIC;
TORRENT_ASSERT(is_single_thread());
@ -974,7 +982,11 @@ void udp_socket::handshake1(error_code const& e)
+ m_outstanding_socks);
if (m_abort) return;
CHECK_MAGIC;
if (e) return;
if (e)
{
drain_queue();
return;
}
TORRENT_ASSERT(is_single_thread());
@ -1008,7 +1020,11 @@ void udp_socket::handshake2(error_code const& e)
if (m_abort) return;
CHECK_MAGIC;
if (e) return;
if (e)
{
drain_queue();
return;
}
using namespace libtorrent::detail;
@ -1018,7 +1034,13 @@ void udp_socket::handshake2(error_code const& e)
int version = read_uint8(p);
int method = read_uint8(p);
if (version < 5) return;
if (version < 5)
{
error_code ec;
m_socks5_sock.close(ec);
drain_queue();
return;
}
if (method == 0)
{
@ -1030,6 +1052,7 @@ void udp_socket::handshake2(error_code const& e)
{
error_code ec;
m_socks5_sock.close(ec);
drain_queue();
return;
}
@ -1053,6 +1076,7 @@ void udp_socket::handshake2(error_code const& e)
}
else
{
drain_queue();
error_code ec;
m_socks5_sock.close(ec);
return;
@ -1077,7 +1101,11 @@ void udp_socket::handshake3(error_code const& e)
+ m_outstanding_socks);
if (m_abort) return;
CHECK_MAGIC;
if (e) return;
if (e)
{
drain_queue();
return;
}
TORRENT_ASSERT(is_single_thread());
@ -1110,7 +1138,11 @@ void udp_socket::handshake4(error_code const& e)
+ m_outstanding_socks);
if (m_abort) return;
CHECK_MAGIC;
if (e) return;
if (e)
{
drain_queue();
return;
}
TORRENT_ASSERT(is_single_thread());
@ -1120,8 +1152,11 @@ void udp_socket::handshake4(error_code const& e)
int version = read_uint8(p);
int status = read_uint8(p);
if (version != 1) return;
if (status != 0) return;
if (version != 1 || status != 0)
{
drain_queue();
return;
}
socks_forward_udp(/*l*/);
}
@ -1170,7 +1205,11 @@ void udp_socket::connect1(error_code const& e)
+ m_outstanding_socks);
if (m_abort) return;
CHECK_MAGIC;
if (e) return;
if (e)
{
drain_queue();
return;
}
TORRENT_ASSERT(is_single_thread());
@ -1210,7 +1249,7 @@ void udp_socket::connect2(error_code const& e)
CHECK_MAGIC;
if (e)
{
m_queue.clear();
drain_queue();
return;
}
@ -1226,7 +1265,7 @@ void udp_socket::connect2(error_code const& e)
if (version != 5 || status != 0)
{
m_queue.clear();
drain_queue();
return;
}
@ -1239,29 +1278,12 @@ void udp_socket::connect2(error_code const& e)
{
// in this case we need to read more data from the socket
TORRENT_ASSERT(false && "not implemented yet!");
m_queue.clear();
drain_queue();
return;
}
m_tunnel_packets = true;
m_queue_packets = false;
// forward all packets that were put in the queue
while (!m_queue.empty())
{
queued_packet const& p = m_queue.front();
error_code 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, p.flags);
}
m_queue.pop_front();
}
drain_queue();
#if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("udp_socket::hung_up");
@ -1300,6 +1322,28 @@ void udp_socket::hung_up(error_code const& e)
set_proxy_settings(m_proxy_settings);
}
void udp_socket::drain_queue()
{
m_queue_packets = false;
// forward all packets that were put in the queue
while (!m_queue.empty())
{
queued_packet const& p = m_queue.front();
error_code ec;
if (p.hostname)
{
udp_socket::send_hostname(p.hostname, p.ep.port(), &p.buf[0], p.buf.size(), ec);
free(p.hostname);
}
else if (!m_force_proxy) // block incoming packets that aren't coming via the proxy
{
udp_socket::send(p.ep, &p.buf[0], p.buf.size(), ec, p.flags);
}
m_queue.pop_front();
}
}
rate_limited_udp_socket::rate_limited_udp_socket(io_service& ios
, connection_queue& cc)
: udp_socket(ios, cc)

View File

@ -42,6 +42,7 @@ test-suite libtorrent :
[ run test_file_storage.cpp ]
[ run test_peer_priority.cpp ]
[ run test_file.cpp ]
[ run test_privacy.cpp ]
[ run test_threads.cpp ]
[ run test_rss.cpp ]
[ run test_bandwidth_limiter.cpp ]

View File

@ -55,6 +55,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/asio/ssl/context.hpp>
#endif
#include <boost/detail/atomic_count.hpp>
#define DEBUG_WEB_SERVER 0
#define DLOG if (DEBUG_WEB_SERVER) fprintf
@ -488,8 +490,8 @@ int start_tracker()
return port;
}
int g_udp_tracker_requests = 0;
int g_http_tracker_requests = 0;
boost::detail::atomic_count g_udp_tracker_requests(0);
boost::detail::atomic_count g_http_tracker_requests(0);
void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoint const* from, char* buffer, udp::socket* sock)
{
@ -506,6 +508,9 @@ void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoin
fprintf(stderr, "UDP message too short\n");
return;
}
fprintf(stderr, "UDP message %d bytes\n", int(bytes_transferred));
char* ptr = buffer;
detail::read_uint64(ptr);
boost::uint32_t action = detail::read_uint32(ptr);
@ -517,6 +522,7 @@ void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoin
{
case 0: // connect
fprintf(stderr, "UDP connect\n");
ptr = buffer;
detail::write_uint32(0, ptr); // action = connect
detail::write_uint32(transaction_id, ptr); // transaction_id
@ -526,6 +532,7 @@ void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoin
case 1: // announce
fprintf(stderr, "UDP announce\n");
ptr = buffer;
detail::write_uint32(1, ptr); // action = announce
detail::write_uint32(transaction_id, ptr); // transaction_id
@ -536,7 +543,12 @@ void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoin
// 0 peers
sock->send_to(asio::buffer(buffer, 20), *from, 0, e);
break;
default: // ignore scrapes
case 2:
// ignore scrapes
fprintf(stderr, "UDP scrape\n");
break;
default:
fprintf(stderr, "UDP unknown message: %d\n", action);
break;
}
}
@ -785,13 +797,6 @@ void web_server_thread(int* port, bool ssl, bool chunked)
web_ios = &ios;
fprintf(stderr, "web server initialized on port %d\n", *port);
{
libtorrent::mutex::scoped_lock l(web_lock);
web_initialized.signal(l);
}
char buf[10000];
int len = 0;
int offset = 0;
@ -809,6 +814,14 @@ void web_server_thread(int* port, bool ssl, bool chunked)
proxy_settings p;
instantiate_connection(ios, p, s, ctx);
fprintf(stderr, "web server initialized on port %d%s\n", *port, ssl ? " [SSL]" : "");
{
libtorrent::mutex::scoped_lock l(web_lock);
web_initialized.signal(l);
}
for (;;)
{
if (connection_close)
@ -979,7 +992,7 @@ void web_server_thread(int* port, bool ssl, bool chunked)
connection_close = true;
}
DLOG(stderr, "%s", std::string(buf + offset, p.body_start()).c_str());
DLOG(stderr, "REQ: %s", std::string(buf + offset, p.body_start()).c_str());
if (failed)
{

172
test/test_privacy.cpp Normal file
View File

@ -0,0 +1,172 @@
/*
Copyright (c) 2013, Arvid Norberg
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.
*/
#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"
#include <fstream>
using namespace libtorrent;
char const* proxy_name[] = {
"none",
"socks4",
"socks5",
"socks5_pw",
"http",
"http_pw",
"i2p_proxy"
};
std::vector<std::string> rejected_trackers;
bool alert_predicate(libtorrent::alert* a)
{
anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
if (am == NULL) return false;
if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
rejected_trackers.push_back(am->str);
return false;
}
enum flags_t
{
anonymous_mode = 1,
expect_http_connection = 2,
expect_udp_connection = 4,
expect_http_reject = 8,
expect_udp_reject = 16,
};
void test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
int http_port = start_web_server();
int udp_port = start_tracker();
int prev_udp_announces = g_udp_tracker_requests;
int prev_http_announces = g_http_tracker_requests;
int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;
session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);
session_settings sett;
sett.half_open_limit = 1;
sett.announce_to_all_trackers = true;
sett.announce_to_all_tiers = true;
sett.anonymous_mode = flags & anonymous_mode;
sett.force_proxy = flags & anonymous_mode;
s->set_settings(sett);
proxy_settings ps;
ps.hostname = "non-existing.com";
ps.port = 4444;
ps.type = proxy_type;
s->set_proxy(ps);
error_code ec;
create_directory("tmp1_privacy", ec);
std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
file.close();
char http_tracker_url[200];
snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
t->add_tracker(http_tracker_url, 0);
char udp_tracker_url[200];
snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
t->add_tracker(udp_tracker_url, 1);
add_torrent_params addp;
addp.flags &= ~add_torrent_params::flag_paused;
addp.flags &= ~add_torrent_params::flag_auto_managed;
addp.ti = t;
addp.save_path = "tmp1_privacy";
torrent_handle h = s->add_torrent(addp);
//TODO: also add a peer and a DHT node to make sure we don't contact those as well
rejected_trackers.clear();
for (int i = 0; i < 10; ++i)
{
print_alerts(*s, "s", false, false, false, &alert_predicate);
test_sleep(100);
}
// we should have announced to the tracker by now
TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + bool(flags & expect_udp_connection));
TEST_EQUAL(g_http_tracker_requests, prev_http_announces + bool(flags & expect_http_connection));
if (flags & expect_udp_reject)
TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());
if (flags & expect_http_reject)
TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());
fprintf(stderr, "destructing session\n");
delete s;
fprintf(stderr, "done\n");
}
int test_main()
{
// not using anonymous mode
// UDP fails open if we can't connect to the proxy
// or if the proxy doesn't support UDP
test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection);
test_proxy(proxy_settings::socks4, expect_udp_connection);
test_proxy(proxy_settings::socks5, expect_udp_connection);
test_proxy(proxy_settings::socks5_pw, expect_udp_connection);
test_proxy(proxy_settings::http, expect_udp_connection);
test_proxy(proxy_settings::http_pw, expect_udp_connection);
test_proxy(proxy_settings::i2p_proxy, expect_udp_connection);
// using anonymous mode
// TODO: also expect whether or not to get a anonymous_alert indicating the tracker isn't anonymous
test_proxy(proxy_settings::none, anonymous_mode);
test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
test_proxy(proxy_settings::socks5, anonymous_mode);
test_proxy(proxy_settings::socks5_pw, anonymous_mode);
test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
return 0;
}

View File

@ -46,5 +46,6 @@ int test_main()
// for the asynchronous call to set the alert
// mask completes, before it goes on to destruct
// the session object
return 0;
}

View File

@ -119,7 +119,7 @@ int test_main()
file.close();
// this should fail
snprintf(tracker_url, sizeof(tracker_url), "udp://www.google.com:80/announce");
snprintf(tracker_url, sizeof(tracker_url), "udp://www1.non-existent.com:80/announce");
t->add_tracker(tracker_url, 0);
// and this should fail