void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags) { TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer)); void* ptr = m_node.m_rpc.allocate_observer(); if (ptr == 0) { #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "[" << this << "] failed to allocate memory for observer. aborting!"; #endif done(); return; } observer_ptr o = new_observer(ptr, addr, id); if (id.is_all_zeros()) { o->set_id(generate_random_id()); o->flags |= observer::flag_no_id; } o->flags |= flags; TORRENT_ASSERT(libtorrent::dht::is_sorted(m_results.begin(), m_results.end() , boost::bind( compare_ref , boost::bind(&observer::id, _1) , boost::bind(&observer::id, _2) , m_target) )); std::vector<observer_ptr>::iterator i = std::lower_bound( m_results.begin() , m_results.end() , o , boost::bind( compare_ref , boost::bind(&observer::id, _1) , boost::bind(&observer::id, _2) , m_target ) ); if (i == m_results.end() || (*i)->id() != id) { if (m_node.settings().restrict_search_ips && !(flags & observer::flag_initial)) { // don't allow multiple entries from IPs very close to each other std::vector<observer_ptr>::iterator j = std::find_if( m_results.begin(), m_results.end(), boost::bind(&compare_ip_cidr, _1, o)); if (j != m_results.end()) { // we already have a node in this search with an IP very // close to this one. We know that it's not the same, because // it claims a different node-ID. Ignore this to avoid attacks #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "[" << this << "] IGNORING result " << "id: " << o->id() << " address: " << o->target_addr() << " existing node: " << (*j)->id() << " " << (*j)->target_addr() << " distance: " << distance_exp(m_target, o->id()) << " type: " << name() ; #endif return; } } TORRENT_ASSERT((o->flags & observer::flag_no_id) || std::find_if(m_results.begin(), m_results.end() , boost::bind(&observer::id, _1) == id) == m_results.end()); #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "[" << this << "] ADD id: " << id << " address: " << addr << " distance: " << distance_exp(m_target, id) << " invoke-count: " << m_invoke_count << " type: " << name() ; #endif i = m_results.insert(i, o); TORRENT_ASSERT(libtorrent::dht::is_sorted(m_results.begin(), m_results.end() , boost::bind( compare_ref , boost::bind(&observer::id, _1) , boost::bind(&observer::id, _2) , m_target) )); } if (m_results.size() > 100) { #if TORRENT_USE_ASSERTS for (int i = 100; i < int(m_results.size()); ++i) m_results[i]->m_was_abandoned = true; #endif m_results.resize(100); } }
std::string to_string(const node_id& what) { std::ostringstream oss; oss << what.process_id() << "@" << to_string(what.host_id()); return oss.str(); }
void traversal_algorithm::add_entry(node_id const& id , udp::endpoint const& addr, unsigned char const flags) { TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer)); auto o = new_observer(addr, id); if (!o) { #ifndef TORRENT_DISABLE_LOGGING if (get_node().observer() != nullptr) { get_node().observer()->log(dht_logger::traversal, "[%p] failed to allocate memory or observer. aborting!" , static_cast<void*>(this)); } #endif done(); return; } if (id.is_all_zeros()) { o->set_id(generate_random_id()); o->flags |= observer::flag_no_id; } o->flags |= flags; TORRENT_ASSERT(libtorrent::dht::is_sorted(m_results.begin(), m_results.end() , [this](observer_ptr const& lhs, observer_ptr const& rhs) { return compare_ref(lhs->id(), rhs->id(), m_target); })); auto iter = std::lower_bound(m_results.begin(), m_results.end(), o , [this](observer_ptr const& lhs, observer_ptr const& rhs) { return compare_ref(lhs->id(), rhs->id(), m_target); }); if (iter == m_results.end() || (*iter)->id() != id) { if (m_node.settings().restrict_search_ips && !(flags & observer::flag_initial)) { #if TORRENT_USE_IPV6 if (o->target_addr().is_v6()) { address_v6::bytes_type addr_bytes = o->target_addr().to_v6().to_bytes(); address_v6::bytes_type::const_iterator prefix_it = addr_bytes.begin(); std::uint64_t const prefix6 = detail::read_uint64(prefix_it); if (m_peer6_prefixes.insert(prefix6).second) goto add_result; } else #endif { // mask the lower octet std::uint32_t const prefix4 = o->target_addr().to_v4().to_ulong() & 0xffffff00; if (m_peer4_prefixes.insert(prefix4).second) goto add_result; } // we already have a node in this search with an IP very // close to this one. We know that it's not the same, because // it claims a different node-ID. Ignore this to avoid attacks #ifndef TORRENT_DISABLE_LOGGING dht_observer* logger = get_node().observer(); if (logger != nullptr && logger->should_log(dht_logger::traversal)) { char hex_id[41]; aux::to_hex(o->id(), hex_id); logger->log(dht_logger::traversal , "[%p] traversal DUPLICATE node. id: %s addr: %s type: %s" , static_cast<void*>(this), hex_id, print_address(o->target_addr()).c_str(), name()); } #endif return; } add_result: TORRENT_ASSERT((o->flags & observer::flag_no_id) || std::none_of(m_results.begin(), m_results.end() , [&id](observer_ptr const& ob) { return ob->id() == id; })); #ifndef TORRENT_DISABLE_LOGGING dht_observer* logger = get_node().observer(); if (logger != nullptr && logger->should_log(dht_logger::traversal)) { char hex_id[41]; aux::to_hex(id, hex_id); logger->log(dht_logger::traversal , "[%p] ADD id: %s addr: %s distance: %d invoke-count: %d type: %s" , static_cast<void*>(this), hex_id, print_endpoint(addr).c_str() , distance_exp(m_target, id), m_invoke_count, name()); } #endif iter = m_results.insert(iter, o); TORRENT_ASSERT(libtorrent::dht::is_sorted(m_results.begin(), m_results.end() , [this](observer_ptr const& lhs, observer_ptr const& rhs) { return compare_ref(lhs->id(), rhs->id(), m_target); })); } if (m_results.size() > 100) { for (int i = 100; i < int(m_results.size()); ++i) { if ((m_results[i]->flags & (observer::flag_queried | observer::flag_failed | observer::flag_alive)) == observer::flag_queried) { // set the done flag on any outstanding queries to prevent them from // calling finished() or failed() m_results[i]->flags |= observer::flag_done; TORRENT_ASSERT(m_invoke_count > 0); --m_invoke_count; } #if TORRENT_USE_ASSERTS m_results[i]->m_was_abandoned = true; #endif } m_results.resize(100); } }
node_id::node_id(const node_id& other) : super(), m_process_id(other.process_id()), m_host_id(other.host_id()) { }
inline bool operator<(const node_id& lhs, const node_id& rhs) { return lhs.compare(rhs) < 0; }