first implementation of DHT security implementation. tie the node ID to the external IP

This commit is contained in:
Arvid Norberg
2010-12-11 09:38:07 +00:00
parent 6769df7508
commit 29ed03f720
15 changed files with 356 additions and 14 deletions

View File

@@ -67,7 +67,8 @@ namespace libtorrent
return ((ip & 0xff000000) == 0x0a000000 // 10.x.x.x
|| (ip & 0xfff00000) == 0xac100000 // 172.16.x.x
|| (ip & 0xffff0000) == 0xc0a80000 // 192.168.x.x
|| (ip & 0xffff0000) == 0xa9fe0000); // 169.254.x.x
|| (ip & 0xffff0000) == 0xa9fe0000 // 169.254.x.x
|| (ip & 0xff000000) == 0x7f000000); // 127.x.x.x
}
bool is_loopback(address const& addr)

View File

@@ -183,9 +183,9 @@ node_impl::node_impl(libtorrent::aux::session_impl& ses
, node_id nid
, void* userdata)
: m_settings(settings)
, m_id(nid == (node_id::min)() ? generate_id() : nid)
, m_id(nid == (node_id::min)() || !verify_id(nid, ses.external_address()) ? generate_id(ses.external_address()) : nid)
, m_table(m_id, 8, settings)
, m_rpc(m_id, m_table, f, userdata)
, m_rpc(m_id, m_table, f, userdata, ses)
, m_last_tracker_tick(time_now())
, m_ses(ses)
, m_send(f)
@@ -702,6 +702,11 @@ void node_impl::incoming_request(msg const& m, entry& e)
entry& reply = e["r"];
m_rpc.add_our_id(reply);
// if this nodes ID doesn't match its IP, tell it what
// its IP is
if (!verify_id(id, m.addr.address()))
reply["ip"] = address_to_bytes(m.addr.address());
if (strcmp(query, "ping") == 0)
{
// we already have 't' and 'id' in the response
@@ -848,6 +853,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
++g_announces;
#endif
}
/*
else if (strcmp(query, "find_torrent") == 0)
{
key_desc_t msg_desc[] = {
@@ -921,6 +927,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
i->second.publish(msg_keys[2]->string_value(), in_tags, num_tags);
}
*/
else
{
// if we don't recognize the message but there's a

View File

@@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/kademlia/node_id.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/broadcast_socket.hpp" // for is_local et.al
namespace libtorrent { namespace dht
{
@@ -94,19 +95,52 @@ int distance_exp(node_id const& n1, node_id const& n2)
}
struct static_ { static_() { std::srand(std::time(0)); } } static__;
node_id generate_id()
void hash_address(address const& ip, sha1_hash& h)
{
if (ip.is_v4())
{
address_v4::bytes_type b = ip.to_v4().to_bytes();
h = hasher((char*)&b[0], b.size()).final();
}
else
{
address_v6::bytes_type b = ip.to_v6().to_bytes();
h = hasher((char*)&b[0], b.size()).final();
}
}
// verifies whether a node-id matches the IP it's used from
// returns true if the node-id is OK coming from this source
// and false otherwise.
bool verify_id(node_id const& nid, address const& source_ip)
{
// no need to verify local IPs, they would be incorrect anyway
if (is_local(source_ip)) return true;
node_id h;
hash_address(source_ip, h);
return memcmp(&nid[0], &h[0], 4) == 0;
}
node_id generate_id(address const& external_ip)
{
node_id h;
char random[20];
#ifdef _MSC_VER
std::generate(random, random + 20, &rand);
#else
std::generate(random, random + 20, &std::rand);
#endif
h = hasher(random, 20).final();
hasher h;
h.update(random, 20);
return h.final();
if (!is_local(external_ip))
{
node_id ph;
hash_address(external_ip, ph);
memcpy(&h[0], &ph[0], 4);
}
return h;
}
} } // namespace libtorrent::dht

View File

@@ -176,7 +176,7 @@ bool routing_table::need_refresh(node_id& target) const
if (time_now() - i->last_active < minutes(15)) return false;
// generate a random node_id within the given bucket
target = generate_id();
target = generate_id(address());
int num_bits = std::distance(m_buckets.begin(), i) + 1;
node_id mask(0);
for (int i = 0; i < num_bits; ++i) mask[i/8] |= 0x80 >> (i&7);

View File

@@ -33,10 +33,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/pch.hpp"
#include "libtorrent/socket.hpp"
// TODO: it would be nice to not have this dependency here
#include "libtorrent/aux_/session_impl.hpp"
#include <boost/bind.hpp>
#include <libtorrent/io.hpp>
#include <libtorrent/invariant_check.hpp>
#include <libtorrent/kademlia/node_id.hpp> // for generate_id
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/logging.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
@@ -150,8 +154,6 @@ void observer::timeout()
m_algorithm->failed(observer_ptr(this));
}
node_id generate_id();
enum { observer_size = max3<
sizeof(find_data_observer)
, sizeof(announce_observer)
@@ -161,7 +163,7 @@ enum { observer_size = max3<
rpc_manager::rpc_manager(node_id const& our_id
, routing_table& table, send_fun const& sf
, void* userdata)
, void* userdata, aux::session_impl& ses)
: m_pool_allocator(observer_size, 10)
, m_next_transaction_id(std::rand() % max_transaction_id)
, m_send(sf)
@@ -172,6 +174,7 @@ rpc_manager::rpc_manager(node_id const& our_id
, m_random_number(generate_id())
, m_allocated_observers(0)
, m_destructing(false)
, m_ses(ses)
{
std::srand(time(0));
@@ -339,6 +342,22 @@ bool rpc_manager::incoming(msg const& m, node_id* id)
return false;
}
lazy_entry const* ext_ip = ret_ent->dict_find_string("ip");
if (ext_ip && ext_ip->string_length() == 4)
{
// this node claims we use the wrong node-ID!
address_v4::bytes_type b;
memcpy(&b[0], ext_ip->string_ptr(), 4);
m_ses.set_external_address(address_v4(b));
}
else if (ext_ip && ext_ip->string_length() == 16)
{
// this node claims we use the wrong node-ID!
address_v6::bytes_type b;
memcpy(&b[0], ext_ip->string_ptr(), 16);
m_ses.set_external_address(address_v6(b));
}
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(rpc) << "[" << o->m_algorithm.get() << "] Reply with transaction id: "
<< tid << " from " << m.addr;

View File

@@ -4353,6 +4353,12 @@ namespace aux {
m_external_address = ip;
if (m_alerts.should_post<external_ip_alert>())
m_alerts.post_alert(external_ip_alert(ip));
// since we have a new external IP now, we need to
// restart the DHT with a new node ID
#ifndef TORRENT_DISABLE_DHT
start_dht(m_dht_state);
#endif
}
void session_impl::free_disk_buffer(char* buf)

View File

@@ -47,6 +47,20 @@ namespace libtorrent
return addr.to_string(ec);
}
std::string address_to_bytes(address const& a)
{
if (a.is_v4())
{
address_v4::bytes_type b = a.to_v4().to_bytes();
return std::string((char*)&b[0], b.size());
}
else
{
address_v6::bytes_type b = a.to_v6().to_bytes();
return std::string((char*)&b[0], b.size());
}
}
std::string print_endpoint(tcp::endpoint const& ep)
{
error_code ec;