From 29e6cbbdae88d7286a5454e311531bec1cb263fc Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Wed, 31 Aug 2016 21:49:21 -0700 Subject: [PATCH] fix exit condition when parsing nodes (#1046) fix exit condition when parsing nodes --- include/libtorrent/kademlia/node.hpp | 6 +- include/libtorrent/socket_io.hpp | 12 ++++ src/kademlia/node.cpp | 2 +- src/kademlia/traversal_algorithm.cpp | 3 +- test/test_dht.cpp | 87 ++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 5 deletions(-) diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index 84eb6eacd..dfa69ae93 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -206,9 +206,9 @@ public: dht_observer* observer() const { return m_observer; } - udp protocol() { return m_protocol.protocol; } - char const* protocol_family_name() { return m_protocol.family_name; } - char const* protocol_nodes_key() { return m_protocol.nodes_key; } + udp protocol() const { return m_protocol.protocol; } + char const* protocol_family_name() const { return m_protocol.family_name; } + char const* protocol_nodes_key() const { return m_protocol.nodes_key; } bool native_address(udp::endpoint ep) const { return ep.protocol().family() == m_protocol.protocol.family(); } diff --git a/include/libtorrent/socket_io.hpp b/include/libtorrent/socket_io.hpp index 9eb7db930..484d03399 100644 --- a/include/libtorrent/socket_io.hpp +++ b/include/libtorrent/socket_io.hpp @@ -56,6 +56,18 @@ namespace libtorrent namespace detail { + template + size_t address_size(Proto p) + { + TORRENT_UNUSED(p); +#if TORRENT_USE_IPV6 + if (p == Proto::v6()) + return address_v6::bytes_type().size(); + else +#endif + return address_v4::bytes_type().size(); + } + template void write_address(address const& a, OutIt& out) { diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index 2ea8dfa74..f4bc44c4d 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -621,7 +621,7 @@ struct ping_observer : observer char const* nodes = n.string_ptr(); char const* end = nodes + n.string_length(); - while (end - nodes >= 26) + while (end - nodes >= 20 + detail::address_size(protocol) + 2) { node_id id; std::copy(nodes, nodes + 20, id.begin()); diff --git a/src/kademlia/traversal_algorithm.cpp b/src/kademlia/traversal_algorithm.cpp index dfdc8d80e..79021930f 100644 --- a/src/kademlia/traversal_algorithm.cpp +++ b/src/kademlia/traversal_algorithm.cpp @@ -52,6 +52,7 @@ using namespace std::placeholders; namespace libtorrent { namespace dht { +using detail::address_size; using detail::read_v4_endpoint; #if TORRENT_USE_IPV6 using detail::read_v6_endpoint; @@ -608,7 +609,7 @@ void traversal_observer::reply(msg const& m) char const* nodes = n.string_ptr(); char const* end = nodes + n.string_length(); - while (end - nodes >= 26) + while (end - nodes >= 20 + address_size(protocol) + 2) { node_id id; std::copy(nodes, nodes + 20, id.begin()); diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 0aad7de50..06284dac4 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -1643,6 +1643,93 @@ TORRENT_TEST(bootstrap_v6) } #endif +// test that the node ignores a nodes entry which is too short +void test_short_nodes(address(&rand_addr)()) +{ + dht_test_setup t(udp::endpoint(rand_addr(), 20)); + bdecode_node response; + bool ret; + + dht::key_desc_t const find_node_desc[] = { + { "y", bdecode_node::string_t, 1, 0 }, + { "t", bdecode_node::string_t, 2, 0 }, + { "q", bdecode_node::string_t, 9, 0 }, + { "a", bdecode_node::dict_t, 0, key_desc_t::parse_children }, + { "id", bdecode_node::string_t, 20, 0 }, + { "target", bdecode_node::string_t, 20, key_desc_t::optional }, + { "info_hash", bdecode_node::string_t, 20, key_desc_t::optional | key_desc_t::last_child }, + }; + + bdecode_node find_node_keys[7]; + + // bootstrap + + g_sent_packets.clear(); + + udp::endpoint initial_node(rand_addr(), 1234); + std::vector nodesv; + nodesv.push_back(initial_node); + t.dht_node.bootstrap(nodesv, std::bind(&nop_node)); + + TEST_EQUAL(g_sent_packets.size(), 1); + if (g_sent_packets.empty()) return; + TEST_EQUAL(g_sent_packets.front().first, initial_node); + + lazy_from_entry(g_sent_packets.front().second, response); + ret = verify_message(response, find_node_desc, find_node_keys, t.error_string + , sizeof(t.error_string)); + if (ret) + { + TEST_EQUAL(find_node_keys[0].string_value(), "q"); + TEST_CHECK(find_node_keys[2].string_value() == "find_node" + || find_node_keys[2].string_value() == "get_peers"); + + if (find_node_keys[0].string_value() != "q" + || (find_node_keys[2].string_value() != "find_node" + && find_node_keys[2].string_value() != "get_peers")) return; + } + else + { + std::fprintf(stderr, " invalid find_node request: %s\n", print_entry(response).c_str()); + TEST_ERROR(t.error_string); + return; + } + + udp::endpoint found_node(rand_addr(), 2235); + nodes_t nodes; + nodes.push_back(found_node); + g_sent_packets.clear(); + msg_args args; + // chop one byte off of the nodes string + if (initial_node.address().is_v4()) + { + args.nodes(nodes); + args.a["nodes"] = args.a["nodes"].string().substr(1); + } + else + { + args.nodes6(nodes); + args.a["nodes6"] = args.a["nodes6"].string().substr(1); + } + + send_dht_response(t.dht_node, response, initial_node, args); + + TEST_EQUAL(g_sent_packets.size(), 0); +} + +TORRENT_TEST(short_nodes_v4) +{ + test_short_nodes(rand_v4); +} + +#if TORRENT_USE_IPV6 +TORRENT_TEST(short_nodes_v6) +{ + if (supports_ipv6()) + test_short_nodes(rand_v6); +} +#endif + void test_get_peers(address(&rand_addr)()) { dht_test_setup t(udp::endpoint(rand_addr(), 20));