From 1d55894befa9da8446baf9f090d4c58a2add3490 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 26 Oct 2013 22:59:55 +0000 Subject: [PATCH] improve obfuscated get_peers --- include/libtorrent/kademlia/find_data.hpp | 6 ++- include/libtorrent/kademlia/routing_table.hpp | 5 +++ src/kademlia/find_data.cpp | 43 ++++++++++++++++--- src/kademlia/routing_table.cpp | 15 +++++++ 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/include/libtorrent/kademlia/find_data.hpp b/include/libtorrent/kademlia/find_data.hpp index b5c170dd5..5c6134914 100644 --- a/include/libtorrent/kademlia/find_data.hpp +++ b/include/libtorrent/kademlia/find_data.hpp @@ -57,7 +57,7 @@ class node_impl; // -------- find data ----------- -//TODO: 3 rename this class to find_peers, since that's what it does +//TODO: 3 rename this class to get_peers, since that's what it does // find_data is an unnecessarily generic name class find_data : public traversal_algorithm { @@ -112,6 +112,10 @@ protected: observer_ptr new_observer(void* ptr, udp::endpoint const& ep, node_id const& id); virtual bool invoke(observer_ptr o); virtual void done(); +private: + // when set to false, we no longer obfuscate + // the target hash, and send regular get_peers + bool m_obfuscated; }; class find_data_observer : public observer diff --git a/include/libtorrent/kademlia/routing_table.hpp b/include/libtorrent/kademlia/routing_table.hpp index 8488ff60b..2e21ba3ea 100644 --- a/include/libtorrent/kademlia/routing_table.hpp +++ b/include/libtorrent/kademlia/routing_table.hpp @@ -146,6 +146,11 @@ public: boost::tuple size() const; size_type num_global_nodes() const; + + // the number of bits down we have full buckets + // i.e. essentially the number of full buckets + // we have + int depth() const; // returns true if there are no working nodes // in the routing table diff --git a/src/kademlia/find_data.cpp b/src/kademlia/find_data.cpp index 22cd87636..7860386f9 100644 --- a/src/kademlia/find_data.cpp +++ b/src/kademlia/find_data.cpp @@ -267,10 +267,11 @@ obfuscated_get_peers::obfuscated_get_peers( , nodes_callback const& ncallback , bool noseeds) : find_data(node, info_hash, dcallback, ncallback, noseeds) + , m_obfuscated(true) { } -char const* obfuscated_get_peers::name() const { return "get_peers [obfuscated]"; } +char const* obfuscated_get_peers::name() const { return !m_obfuscated ? find_data::name() : "get_peers [obfuscated]"; } observer_ptr obfuscated_get_peers::new_observer(void* ptr , udp::endpoint const& ep, node_id const& id) @@ -284,6 +285,34 @@ observer_ptr obfuscated_get_peers::new_observer(void* ptr bool obfuscated_get_peers::invoke(observer_ptr o) { + if (!m_obfuscated) return find_data::invoke(o); + + node_id id = o->id(); + int shared_prefix = 160 - distance_exp(id, m_target); + + // when we get close to the target zone in the DHT + // start using the correct info-hash, in order to + // start receiving peers + if (shared_prefix > m_node.m_table.depth() - 10) + { + m_obfuscated = false; + // clear the queried bits on all successful nodes in + // our node-list for this traversal algorithm, to + // allow the get_peers traversal to regress in case + // nodes further down end up being dead + for (std::vector::iterator i = m_results.begin() + , end(m_results.end()); i != end; ++i) + { + observer* o = i->get(); + // don't re-request from nodes that didn't respond + if (o->flags & observer::flag_failed) continue; + // don't interrupt with queries that are already in-flight + if ((o->flags & observer::flag_alive) == 0) continue; + o->flags &= ~(observer::flag_queried | observer::flag_alive); + } + return find_data::invoke(o); + } + entry e; e["y"] = "q"; e["q"] = "find_node"; @@ -295,9 +324,6 @@ bool obfuscated_get_peers::invoke(observer_ptr o) // bits in the info-hash for the node we're querying to // give a good answer, but not more. - node_id id = o->id(); - int shared_prefix = 160 - distance_exp(id, m_target); - // now, obfuscate the bits past shared_prefix + 5 node_id obfuscated_target = generate_random_id(); obfuscated_target >>= shared_prefix + 3; @@ -309,6 +335,11 @@ bool obfuscated_get_peers::invoke(observer_ptr o) void obfuscated_get_peers::done() { + if (!m_obfuscated) return find_data::done(); + + // oops, we failed to switch over to the non-obfuscated + // mode early enough. do it now + boost::intrusive_ptr ta(new find_data(m_node, m_target , m_data_callback , m_nodes_callback @@ -327,11 +358,11 @@ void obfuscated_get_peers::done() int num_added = 0; for (std::vector::iterator i = m_results.begin() - , end(m_results.end()); i != end && num_added < 10; ++i) + , end(m_results.end()); i != end && num_added < 16; ++i) { observer_ptr o = *i; - // only add nodes whose node ID we knoe and that + // only add nodes whose node ID we know and that // we know are alive if (o->flags & observer::flag_no_id) continue; if ((o->flags & observer::flag_alive) == 0) continue; diff --git a/src/kademlia/routing_table.cpp b/src/kademlia/routing_table.cpp index 53e43b676..f0e62b8da 100644 --- a/src/kademlia/routing_table.cpp +++ b/src/kademlia/routing_table.cpp @@ -126,6 +126,21 @@ size_type routing_table::num_global_nodes() const else return (size_type(2) << deepest_bucket) * deepest_size; } +int routing_table::depth() const +{ + // TODO: 3 cache the depth! + int deepest_bucket = 0; + for (table_t::const_iterator i = m_buckets.begin() + , end(m_buckets.end()); i != end; ++i) + { + if (i->live_nodes.size() < m_bucket_size) + break; + // this bucket is full + ++deepest_bucket; + } + return deepest_bucket; +} + #if (defined TORRENT_DHT_VERBOSE_LOGGING || defined TORRENT_DEBUG) && TORRENT_USE_IOSTREAM void routing_table::print_state(std::ostream& os) const