diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index 6df86b00c..49cd84e77 100644 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -150,6 +150,9 @@ namespace libtorrent boost::uint32_t key; int num_want; +#if TORRENT_USE_IPV6 + address_v6 ipv6; +#endif sha1_hash info_hash; peer_id pid; address bind_ip; diff --git a/simulation/test_tracker.cpp b/simulation/test_tracker.cpp index 8166765df..afa8ef6d5 100644 --- a/simulation/test_tracker.cpp +++ b/simulation/test_tracker.cpp @@ -39,6 +39,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/announce_entry.hpp" #include "libtorrent/session.hpp" +#include "libtorrent/create_torrent.hpp" +#include "libtorrent/file_storage.hpp" +#include "libtorrent/torrent_info.hpp" using namespace libtorrent; using namespace sim; @@ -397,7 +400,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2 p.name = "test-torrent"; p.save_path = "."; p.info_hash.assign("abababababababababab"); - int const delay = setup(p); + int const delay = setup(p, *ses); ses->async_add_torrent(p); // run the test 5 seconds in @@ -434,7 +437,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2 template void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "/announce") { - tracker_test([](lt::add_torrent_params& p) { + tracker_test([](lt::add_torrent_params& p, lt::session&) { p.trackers.push_back("http://tracker.com:8080/announce"); return 5; }, @@ -629,7 +632,7 @@ TORRENT_TEST(try_next) bool got_announce = false; tracker_test( - [](lt::add_torrent_params& p) + [](lt::add_torrent_params& p, lt::session&) { // TODO: 3 use tracker_tiers here to put the trackers in different tiers p.trackers.push_back("udp://failing-tracker.com/announce"); @@ -691,6 +694,113 @@ TORRENT_TEST(try_next) TEST_EQUAL(got_announce, true); } +boost::shared_ptr make_torrent(bool priv) +{ + file_storage fs; + fs.add_file("foobar", 13241); + create_torrent ct(fs); + + ct.add_tracker("http://tracker.com:8080/announce"); + + for (int i = 0; i < ct.num_pieces(); ++i) + ct.set_hash(i, sha1_hash(0)); + + ct.set_priv(priv); + + entry e = ct.generate(); + std::vector buf; + bencode(std::back_inserter(buf), e); + error_code ec; + return boost::make_shared(buf.data(), buf.size(), ec); +} + +// make sure we _do_ send our IPv6 address to trackers for private torrents +TORRENT_TEST(tracker_ipv6_argument) +{ + bool got_announce = false; + bool got_ipv6 = false; + tracker_test( + [](lt::add_torrent_params& p, lt::session& ses) + { + settings_pack pack; + pack.set_bool(settings_pack::anonymous_mode, false); + ses.apply_settings(pack); + p.ti = make_torrent(true); + return 60; + }, + [&](std::string method, std::string req + , std::map& headers) + { + got_announce = true; + int pos = req.find("&ipv6="); + TEST_CHECK(pos != std::string::npos); + got_ipv6 = pos != std::string::npos; + return sim::send_response(200, "OK", 11) + "d5:peers0:e"; + } + , [](torrent_handle h) {} + , [](torrent_handle h) {}); + TEST_EQUAL(got_announce, true); + TEST_EQUAL(got_ipv6, true); +} + +// make sure we do _not_ send our IPv6 address to trackers for non-private +// torrents +TORRENT_TEST(tracker_ipv6_argument_non_private) +{ + bool got_announce = false; + bool got_ipv6 = false; + tracker_test( + [](lt::add_torrent_params& p, lt::session& ses) + { + settings_pack pack; + pack.set_bool(settings_pack::anonymous_mode, false); + ses.apply_settings(pack); + p.ti = make_torrent(false); + return 60; + }, + [&](std::string method, std::string req + , std::map& headers) + { + got_announce = true; + int pos = req.find("&ipv6="); + TEST_CHECK(pos == std::string::npos); + got_ipv6 = pos != std::string::npos; + return sim::send_response(200, "OK", 11) + "d5:peers0:e"; + } + , [](torrent_handle h) {} + , [](torrent_handle h) {}); + TEST_EQUAL(got_announce, true); + TEST_EQUAL(got_ipv6, false); +} + +TORRENT_TEST(tracker_ipv6_argument_privacy_mode) +{ + bool got_announce = false; + bool got_ipv6 = false; + tracker_test( + [](lt::add_torrent_params& p, lt::session& ses) + { + settings_pack pack; + pack.set_bool(settings_pack::anonymous_mode, true); + ses.apply_settings(pack); + p.ti = make_torrent(true); + return 60; + }, + [&](std::string method, std::string req + , std::map& headers) + { + got_announce = true; + int pos = req.find("&ipv6="); + TEST_CHECK(pos == std::string::npos); + got_ipv6 = pos != std::string::npos; + return sim::send_response(200, "OK", 11) + "d5:peers0:e"; + } + , [](torrent_handle h) {} + , [](torrent_handle h) {}); + TEST_EQUAL(got_announce, true); + TEST_EQUAL(got_ipv6, false); +} + // TODO: test external IP // TODO: test with different queuing settings // TODO: test when a torrent transitions from downloading to finished and diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 89fd0be7a..4887462e8 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -183,20 +183,22 @@ namespace libtorrent { url += "&ip=" + escape_string(announce_ip.c_str(), announce_ip.size()); } -// TODO: support this somehow -/* else if (settings.get_bool(settings_pack::announce_double_nat) - && is_local(m_ses.listen_address())) - { - // only use the global external listen address here - // if it turned out to be on a local network - // since otherwise the tracker should use our - // source IP to determine our origin - url += "&ip=" + print_address(m_ses.listen_address()); - } -*/ } } +#if TORRENT_USE_IPV6 + if (tracker_req().ipv6 != address_v6() && !i2p) + { + error_code err; + std::string const ip = tracker_req().ipv6.to_string(err); + if (!err) + { + url += "&ipv6="; + url += ip; + } + } +#endif + m_tracker_connection.reset(new http_connection(get_io_service(), m_man.host_resolver() , boost::bind(&http_tracker_connection::on_response, shared_from_this(), _1, _2, _3, _4) , true, settings.get_int(settings_pack::max_http_recv_buffer_size) diff --git a/src/torrent.cpp b/src/torrent.cpp index 610d62629..aca196ab8 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3140,7 +3140,19 @@ namespace libtorrent if (req.downloaded < 0) req.downloaded = 0; req.event = e; - error_code ec; + +#if TORRENT_USE_IPV6 + // since sending our IPv6 address to the tracker may be sensitive. Only + // do that if we're not in anonymous mode and if it's a private torrent + if (!settings().get_bool(settings_pack::anonymous_mode) + && m_torrent_file + && m_torrent_file->priv()) + { + tcp::endpoint ep; + ep = m_ses.get_ipv6_interface(); + if (ep != tcp::endpoint()) req.ipv6 = ep.address().to_v6(); + } +#endif // if we are aborting. we don't want any new peers req.num_want = (req.event == tracker_request::stopped)