first implementation of DHT security implementation. tie the node ID to the external IP
This commit is contained in:
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user