diff --git a/docs/dht_sec.rst b/docs/dht_sec.rst index c93f894aa..221d11cab 100644 --- a/docs/dht_sec.rst +++ b/docs/dht_sec.rst @@ -137,15 +137,21 @@ bootstrapping ------------- In order to set ones initial node ID, the external IP needs to be known. This -is not a trivial problem. With this extension, *all* DHT requests whose node -ID does not match its IP address MUST be serviced and MUST also include one -extra result value (inside the ``r`` dictionary) called ``ip``. The IP field -contains the raw (big endian) byte representation of the external IP address. -This is the same byte sequence used to verify the node ID. +is not a trivial problem. With this extension, *all* DHT responses SHOULD include +a *top-level* field called ``ip``, containing a compact binary representation of +the requestor's IP and port. That is big endian IP followed by 2 bytes of big endian +port. + +The IP portion is the same byte sequence used to verify the node ID. + +It is important that the ``ip`` field is in the top level dictionary. Nodes that +enforce the node-ID will respond with an error message ("y": "e", "e": { ... }), +whereas a node that supports this extension but without enforcing it will respond +with a normal reply ("y": "r", "r": { ... }). A DHT node which receives an ``ip`` result in a request SHOULD consider restarting its DHT node with a new node ID, taking this IP into account. Since a single node -can not be trusted, there should be some mechanism of determining whether or +can not be trusted, there should be some mechanism to determine whether or not the node has a correct understanding of its external IP or not. This could be done by voting, or only restart the DHT once at least a certain number of nodes, from separate searches, tells you your node ID is incorrect. diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index a8add2f91..aacc62f87 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -68,6 +68,7 @@ TORRENT_DECLARE_LOG(node); #endif struct traversal_algorithm; +struct dht_observer; struct key_desc_t { @@ -295,6 +296,8 @@ public: rpc_manager m_rpc; private: + dht_observer* m_observer; + table_t m_map; dht_immutable_table_t m_immutable_table; dht_mutable_table_t m_mutable_table; diff --git a/include/libtorrent/kademlia/rpc_manager.hpp b/include/libtorrent/kademlia/rpc_manager.hpp index 0ffc99213..0d769221c 100644 --- a/include/libtorrent/kademlia/rpc_manager.hpp +++ b/include/libtorrent/kademlia/rpc_manager.hpp @@ -66,16 +66,13 @@ struct null_observer : public observer }; class routing_table; -struct dht_observer; class TORRENT_EXTRA_EXPORT rpc_manager { public: - typedef boost::function3 external_ip_fun; rpc_manager(node_id const& our_id - , routing_table& table, udp_socket_interface* sock - , dht_observer* observer); + , routing_table& table, udp_socket_interface* sock); ~rpc_manager(); void unreachable(udp::endpoint const& ep); @@ -118,7 +115,6 @@ private: node_id m_random_number; int m_allocated_observers; bool m_destructing; - dht_observer* m_observer; }; } } // namespace libtorrent::dht diff --git a/include/libtorrent/socket_io.hpp b/include/libtorrent/socket_io.hpp index 201c628cb..4c65c3a5c 100644 --- a/include/libtorrent/socket_io.hpp +++ b/include/libtorrent/socket_io.hpp @@ -47,6 +47,7 @@ namespace libtorrent TORRENT_EXTRA_EXPORT std::string print_endpoint(tcp::endpoint const& ep); TORRENT_EXTRA_EXPORT std::string print_endpoint(udp::endpoint const& ep); TORRENT_EXTRA_EXPORT std::string address_to_bytes(address const& a); + TORRENT_EXPORT std::string endpoint_to_bytes(udp::endpoint const& ep); TORRENT_EXTRA_EXPORT void hash_address(address const& ip, sha1_hash& h); namespace detail diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index d959b3c9d..5668d582e 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/kademlia/rpc_manager.hpp" #include "libtorrent/kademlia/routing_table.hpp" #include "libtorrent/kademlia/node.hpp" +#include #include "libtorrent/kademlia/refresh.hpp" #include "libtorrent/kademlia/find_data.hpp" @@ -100,7 +101,8 @@ node_impl::node_impl(alert_dispatcher* alert_disp : m_settings(settings) , m_id(nid == (node_id::min)() || !verify_id(nid, external_address) ? generate_id(external_address) : nid) , m_table(m_id, 8, settings) - , m_rpc(m_id, m_table, sock, observer) + , m_rpc(m_id, m_table, sock) + , m_observer(observer) , m_last_tracker_tick(time_now()) , m_post_alert(alert_disp) , m_sock(sock) @@ -221,6 +223,28 @@ void node_impl::incoming(msg const& m) char y = *(y_ent->string_ptr()); + lazy_entry const* ext_ip = m.message.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); + if (m_observer) + m_observer->set_external_address(address_v4(b) + , m.addr.address()); + } +#if TORRENT_USE_IPV6 + 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); + if (m_observer) + m_observer->set_external_address(address_v6(b) + , m.addr.address()); + } +#endif + switch (y) { case 'r': @@ -657,6 +681,17 @@ void node_impl::incoming_request(msg const& m, entry& e) return; } + e["ip"] = endpoint_to_bytes(m.addr); +/* + // if this nodes ID doesn't match its IP, tell it what + // its IP is with an error + // don't enforce this yet + if (!verify_id(id, m.addr.address())) + { + incoming_error(e, "invalid node ID"); + return; + } +*/ char const* query = top_level[0]->string_cstr(); lazy_entry const* arg_ent = top_level[1]; @@ -668,11 +703,6 @@ 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()); - // mirror back the other node's external port reply["p"] = m.addr.port(); diff --git a/src/kademlia/rpc_manager.cpp b/src/kademlia/rpc_manager.cpp index 9a6b156f7..52dbc0cf6 100644 --- a/src/kademlia/rpc_manager.cpp +++ b/src/kademlia/rpc_manager.cpp @@ -46,7 +46,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #include #include // time() @@ -159,8 +158,7 @@ enum { observer_size = max3< }; rpc_manager::rpc_manager(node_id const& our_id - , routing_table& table, udp_socket_interface* sock - , dht_observer* observer) + , routing_table& table, udp_socket_interface* sock) : m_pool_allocator(observer_size, 10) , m_sock(sock) , m_our_id(our_id) @@ -169,7 +167,6 @@ rpc_manager::rpc_manager(node_id const& our_id , m_random_number(generate_random_id()) , m_allocated_observers(0) , m_destructing(false) - , m_observer(observer) { std::srand(time(0)); @@ -340,28 +337,6 @@ 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); - if (m_observer) - m_observer->set_external_address(address_v4(b) - , m.addr.address()); - } -#if TORRENT_USE_IPV6 - 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); - if (m_observer) - m_observer->set_external_address(address_v6(b) - , m.addr.address()); - } -#endif - #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(rpc) << "[" << o->m_algorithm.get() << "] Reply with transaction id: " << tid << " from " << m.addr; diff --git a/src/socket_io.cpp b/src/socket_io.cpp index 3700ecca3..9f289e105 100644 --- a/src/socket_io.cpp +++ b/src/socket_io.cpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/socket_io.hpp" #include "libtorrent/address.hpp" +#include "libtorrent/io.hpp" // for write_uint16 #include "libtorrent/hasher.hpp" // for hasher namespace libtorrent @@ -50,18 +51,18 @@ namespace libtorrent std::string address_to_bytes(address const& a) { -#if TORRENT_USE_IPV6 - if (a.is_v6()) - { - address_v6::bytes_type b = a.to_v6().to_bytes(); - return std::string((char*)&b[0], b.size()); - } - else -#endif - { - address_v4::bytes_type b = a.to_v4().to_bytes(); - return std::string((char*)&b[0], b.size()); - } + std::string ret; + std::back_insert_iterator out(ret); + detail::write_address(a, out); + return ret; + } + + std::string endpoint_to_bytes(udp::endpoint const& ep) + { + std::string ret; + std::back_insert_iterator out(ret); + detail::write_endpoint(ep, out); + return ret; } std::string print_endpoint(tcp::endpoint const& ep) diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 65451c9ee..ea84fe64b 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bloom_filter.hpp" #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/ip_voter.hpp" +#include "libtorrent/socket_io.hpp" #include #include #include @@ -402,6 +403,14 @@ int test_main() test1.resize(100, true); TEST_CHECK(test1.all_set() == true); + + // test address_to_bytes + TEST_EQUAL(address_to_bytes(address_v4::from_string("10.11.12.13")), "\x0a\x0b\x0c\x0d"); + TEST_EQUAL(address_to_bytes(address_v4::from_string("16.5.127.1")), "\x10\x05\x7f\x01"); + + // test endpoint_to_bytes + TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("10.11.12.13"), 8080)), "\x0a\x0b\x0c\x0d\x1f\x90"); + TEST_EQUAL(endpoint_to_bytes(udp::endpoint(address_v4::from_string("16.5.127.1"), 12345)), "\x10\x05\x7f\x01\x30\x39"); return 0; }