From fe37884bc6c92737e44ff6fa35fd300f4ba36c97 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 19 Aug 2017 16:49:09 +0200 Subject: [PATCH] fix IPv6 tracker support by performing the second announce in more cases --- ChangeLog | 1 + include/libtorrent/tracker_manager.hpp | 6 ++++ simulation/test_tracker.cpp | 47 +++++++++++++++++++++++--- src/torrent.cpp | 10 +++--- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 15e648238..eee04b8a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix IPv6 tracker support by performing the second announce in more cases * fix utf-8 encoding check in torrent parser * fix infinite loop when parsing maliciously crafted torrents * fix invalid read in parse_int in bdecoder diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index 8ec129df5..de4ac6b0a 100644 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -101,6 +101,7 @@ namespace libtorrent , send_stats(true) , private_torrent(false) , triggered_manually(false) + , second_announce(false) #ifdef TORRENT_USE_OPENSSL , ssl_ctx(0) #endif @@ -168,6 +169,11 @@ namespace libtorrent // scrape_tracker() or force_reannounce() bool triggered_manually; + // this is set when announcing to the next address family. There are only + // two address families now, so when this is set, we won't trigger another + // automatic announce + bool second_announce; + #ifdef TORRENT_USE_OPENSSL boost::asio::ssl::context* ssl_ctx; #endif diff --git a/simulation/test_tracker.cpp b/simulation/test_tracker.cpp index 54cdc63e7..260412366 100644 --- a/simulation/test_tracker.cpp +++ b/simulation/test_tracker.cpp @@ -287,9 +287,8 @@ void on_alert_notify(lt::session* ses) }); } -// this test makes sure that a tracker whose host name resolves to both IPv6 and -// IPv4 addresses will be announced to twice, once for each address family -TORRENT_TEST(ipv6_support) +void test_ipv6_support(char const* listen_interfaces + , int const expect_v4, int const expect_v6) { using sim::asio::ip::address_v4; sim_config network_cfg; @@ -335,6 +334,7 @@ TORRENT_TEST(ipv6_support) asio::io_service ios(sim, { address_v4::from_string("10.0.0.3") , address_v6::from_string("ffff::1337") }); lt::settings_pack sett = settings(); + sett.set_str(settings_pack::listen_interfaces, listen_interfaces); std::unique_ptr ses(new lt::session(sett, ios)); ses->set_alert_notify(std::bind(&on_alert_notify, ses.get())); @@ -370,9 +370,46 @@ TORRENT_TEST(ipv6_support) sim.run(); } + TEST_EQUAL(v4_announces, expect_v4); + TEST_EQUAL(v6_announces, expect_v6); +} + +// this test makes sure that a tracker whose host name resolves to both IPv6 and +// IPv4 addresses will be announced to twice, once for each address family +TORRENT_TEST(ipv6_support) +{ // 2 because there's one announce on startup and one when shutting down - TEST_EQUAL(v4_announces, 2); - TEST_EQUAL(v6_announces, 2); + test_ipv6_support("0.0.0.0:6881", 2, 2); +} + +TORRENT_TEST(ipv6_support_bind_v4_v6_any) +{ + test_ipv6_support("0.0.0.0:6881,[::0]:6881", 2, 2); +} + +TORRENT_TEST(ipv6_support_bind_v6_any) +{ + test_ipv6_support("[::0]:6881", 0, 2); +} + +TORRENT_TEST(ipv6_support_bind_v4) +{ + test_ipv6_support("10.0.0.3:6881", 2, 0); +} + +TORRENT_TEST(ipv6_support_bind_v6) +{ + test_ipv6_support("[ffff::1337]:6881", 0, 2); +} + +TORRENT_TEST(ipv6_support_bind_v4_v6) +{ + test_ipv6_support("10.0.0.3:6881,[ffff::1337]:6881", 2, 2); +} + +TORRENT_TEST(ipv6_support_bind_v6_v4) +{ + test_ipv6_support("[ffff::1337]:6881,10.0.0.3:6881", 2, 2); } // this runs a simulation of a torrent with tracker(s), making sure the request diff --git a/src/torrent.cpp b/src/torrent.cpp index 3aacf237a..cdeb09762 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3641,15 +3641,12 @@ namespace { // when talking to the tracker. If there is a matching interface // type in the tracker IP list, make another tracker request // using that interface - // in order to avoid triggering this case over and over, don't - // do it if the bind IP for the tracker request that just completed - // matches one of the listen interfaces, since that means this - // announce was the second one + // in order to avoid triggering this case over and over, check whether + // this announce was itself triggered by this logic (second_announce) if (((!is_any(m_ses.get_ipv6_interface().address()) && tracker_ip.is_v4()) || (!is_any(m_ses.get_ipv4_interface().address()) && tracker_ip.is_v6())) - && r.bind_ip != m_ses.get_ipv4_interface().address() - && r.bind_ip != m_ses.get_ipv6_interface().address()) + && !r.second_announce) { std::list
::const_iterator i = std::find_if(tracker_ips.begin() , tracker_ips.end(), boost::bind(&address::is_v4, _1) != tracker_ip.is_v4()); @@ -3667,6 +3664,7 @@ namespace { tracker_request req = r; req.private_torrent = m_torrent_file->priv(); + req.second_announce = true; // tell the tracker to bind to the opposite protocol type req.bind_ip = tracker_ip.is_v4()