示例#1
0
void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	if (id.is_all_zeros())
		TORRENT_LOG(traversal) << time_now_string() << "[" << this << ":" << name()
			<< "] WARNING: node returned a list which included a node with id 0";
#endif
	add_entry(id, addr, 0);
}
void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	if (id.is_all_zeros())
	{
		TORRENT_LOG(traversal) << time_now_string() << "[" << this << "] WARNING node returned a list which included a node with id 0";
	}
#endif

	// let the routing table know this node may exist
	m_node.m_table.heard_about(id, addr);

	add_entry(id, addr, 0);
}
void traversal_algorithm::traverse(node_id const& id, udp::endpoint const& addr)
{
#ifndef TORRENT_DISABLE_LOGGING
	dht_observer* logger = get_node().observer();
	if (logger != nullptr && logger->should_log(dht_logger::traversal) && id.is_all_zeros())
	{
		logger->log(dht_logger::traversal
			, "[%p] WARNING node returned a list which included a node with id 0"
			, static_cast<void*>(this));
	}
#endif

	// let the routing table know this node may exist
	m_node.m_table.heard_about(id, addr);

	add_entry(id, addr, 0);
}
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);
	}
}
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);
	}
}