1 /*
2
3 Copyright (c) 2008, Arvid Norberg
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30
31 */
32
33 #include "test.hpp"
34
35 #ifndef TORRENT_DISABLE_DHT
36
37 #include "libtorrent/config.hpp"
38 #include "libtorrent/session.hpp"
39 #include "libtorrent/kademlia/msg.hpp" // for verify_message
40 #include "libtorrent/kademlia/node.hpp"
41 #include "libtorrent/bencode.hpp"
42 #include "libtorrent/bdecode.hpp"
43 #include "libtorrent/socket_io.hpp" // for hash_address
44 #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6
45 #include "libtorrent/performance_counters.hpp" // for counters
46 #include "libtorrent/random.hpp"
47 #include "libtorrent/kademlia/ed25519.hpp"
48 #include "libtorrent/hex.hpp" // to_hex, from_hex
49 #include "libtorrent/bloom_filter.hpp"
50 #include "libtorrent/hasher.hpp"
51 #include "libtorrent/aux_/time.hpp"
52 #include "libtorrent/aux_/listen_socket_handle.hpp"
53 #include "libtorrent/aux_/session_impl.hpp"
54
55 #include "libtorrent/kademlia/node_id.hpp"
56 #include "libtorrent/kademlia/routing_table.hpp"
57 #include "libtorrent/kademlia/item.hpp"
58 #include "libtorrent/kademlia/dht_observer.hpp"
59 #include "libtorrent/kademlia/dht_tracker.hpp"
60
61 #include <numeric>
62 #include <cstdarg>
63 #include <tuple>
64 #include <iostream>
65 #include <cstdio> // for vsnprintf
66
67 #include "setup_transfer.hpp"
68
69 using namespace lt;
70 using namespace lt::dht;
71 using namespace std::placeholders;
72
73 namespace {
74
get_test_keypair(public_key & pk,secret_key & sk)75 void get_test_keypair(public_key& pk, secret_key& sk)
76 {
77 aux::from_hex({"77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548", 64}
78 , pk.bytes.data());
79 aux::from_hex({"e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74d"
80 "b7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d", 128}
81 , sk.bytes.data());
82 }
83
prev_seq(sequence_number s)84 sequence_number prev_seq(sequence_number s)
85 {
86 return sequence_number(s.value - 1);
87 }
88
next_seq(sequence_number s)89 sequence_number next_seq(sequence_number s)
90 {
91 return sequence_number(s.value + 1);
92 }
93
add_and_replace(node_id & dst,node_id const & add)94 void add_and_replace(node_id& dst, node_id const& add)
95 {
96 bool carry = false;
97 for (int k = 19; k >= 0; --k)
98 {
99 int sum = dst[k] + add[k] + (carry ? 1 : 0);
100 dst[k] = sum & 255;
101 carry = sum > 255;
102 }
103 }
104
node_push_back(std::vector<node_entry> * nv,node_entry const & n)105 void node_push_back(std::vector<node_entry>* nv, node_entry const& n)
106 {
107 nv->push_back(n);
108 }
109
nop_node()110 void nop_node() {}
111
112 // TODO: 3 make the mock_socket hold a reference to the list of where to record
113 // packets instead of having a global variable
114 std::list<std::pair<udp::endpoint, entry>> g_sent_packets;
115
116 struct mock_socket final : socket_manager
117 {
has_quota__anona87d109f0111::mock_socket118 bool has_quota() override { return true; }
send_packet__anona87d109f0111::mock_socket119 bool send_packet(aux::listen_socket_handle const&, entry& msg, udp::endpoint const& ep) override
120 {
121 // TODO: 3 ideally the mock_socket would contain this queue of packets, to
122 // make tests independent
123 g_sent_packets.push_back(std::make_pair(ep, msg));
124 return true;
125 }
126 };
127
dummy_listen_socket(udp::endpoint src)128 std::shared_ptr<aux::listen_socket_t> dummy_listen_socket(udp::endpoint src)
129 {
130 auto ret = std::make_shared<aux::listen_socket_t>();
131 ret->local_endpoint = tcp::endpoint(src.address(), src.port());
132 ret->external_address.cast_vote(src.address()
133 , aux::session_interface::source_dht, rand_v4());
134 return ret;
135 }
136
dummy_listen_socket4()137 std::shared_ptr<aux::listen_socket_t> dummy_listen_socket4()
138 {
139 auto ret = std::make_shared<aux::listen_socket_t>();
140 ret->local_endpoint = tcp::endpoint(addr4("192.168.4.1"), 6881);
141 ret->external_address.cast_vote(addr4("236.0.0.1")
142 , aux::session_interface::source_dht, rand_v4());
143 return ret;
144 }
145
dummy_listen_socket6()146 std::shared_ptr<aux::listen_socket_t> dummy_listen_socket6()
147 {
148 auto ret = std::make_shared<aux::listen_socket_t>();
149 ret->local_endpoint = tcp::endpoint(addr6("2002::1"), 6881);
150 ret->external_address.cast_vote(addr6("2002::1")
151 , aux::session_interface::source_dht, rand_v6());
152 return ret;
153 }
154
get_foreign_node_stub(node_id const &,std::string const &)155 node* get_foreign_node_stub(node_id const&, std::string const&)
156 {
157 return nullptr;
158 }
159
generate_next()160 sha1_hash generate_next()
161 {
162 sha1_hash ret;
163 aux::random_bytes(ret);
164 return ret;
165 }
166
167 std::list<std::pair<udp::endpoint, entry>>::iterator
find_packet(udp::endpoint ep)168 find_packet(udp::endpoint ep)
169 {
170 return std::find_if(g_sent_packets.begin(), g_sent_packets.end()
171 , [&ep] (std::pair<udp::endpoint, entry> const& p)
172 { return p.first == ep; });
173 }
174
node_from_entry(entry const & e,bdecode_node & l)175 void node_from_entry(entry const& e, bdecode_node& l)
176 {
177 error_code ec;
178 static char inbuf[1500];
179 int len = bencode(inbuf, e);
180 int ret = bdecode(inbuf, inbuf + len, l, ec);
181 TEST_CHECK(ret == 0);
182 }
183
write_peers(std::set<tcp::endpoint> const & peers)184 entry write_peers(std::set<tcp::endpoint> const& peers)
185 {
186 entry r;
187 entry::list_type& pe = r.list();
188 for (auto const& p : peers)
189 {
190 std::string endpoint(18, '\0');
191 std::string::iterator out = endpoint.begin();
192 lt::detail::write_endpoint(p, out);
193 endpoint.resize(std::size_t(out - endpoint.begin()));
194 pe.push_back(entry(endpoint));
195 }
196 return r;
197 }
198
199 struct msg_args
200 {
info_hash__anona87d109f0111::msg_args201 msg_args& info_hash(char const* i)
202 { if (i) a["info_hash"] = std::string(i, 20); return *this; }
203
name__anona87d109f0111::msg_args204 msg_args& name(char const* n)
205 { if (n) a["n"] = n; return *this; }
206
token__anona87d109f0111::msg_args207 msg_args& token(std::string t)
208 { a["token"] = t; return *this; }
209
port__anona87d109f0111::msg_args210 msg_args& port(int p)
211 { a["port"] = p; return *this; }
212
target__anona87d109f0111::msg_args213 msg_args& target(sha1_hash const& t)
214 { a["target"] = t.to_string(); return *this; }
215
value__anona87d109f0111::msg_args216 msg_args& value(entry const& v)
217 { a["v"] = v; return *this; }
218
scrape__anona87d109f0111::msg_args219 msg_args& scrape(bool s)
220 { a["scrape"] = s ? 1 : 0; return *this; }
221
seed__anona87d109f0111::msg_args222 msg_args& seed(bool s)
223 { a["seed"] = s ? 1 : 0; return *this; }
224
key__anona87d109f0111::msg_args225 msg_args& key(public_key const& k)
226 { a["k"] = k.bytes; return *this; }
227
sig__anona87d109f0111::msg_args228 msg_args& sig(signature const& s)
229 { a["sig"] = s.bytes; return *this; }
230
seq__anona87d109f0111::msg_args231 msg_args& seq(sequence_number s)
232 { a["seq"] = s.value; return *this; }
233
cas__anona87d109f0111::msg_args234 msg_args& cas(sequence_number c)
235 { a["cas"] = c.value; return *this; }
236
nid__anona87d109f0111::msg_args237 msg_args& nid(sha1_hash const& n)
238 { a["id"] = n.to_string(); return *this; }
239
salt__anona87d109f0111::msg_args240 msg_args& salt(span<char const> s)
241 { if (!s.empty()) a["salt"] = s; return *this; }
242
want__anona87d109f0111::msg_args243 msg_args& want(std::string w)
244 { a["want"].list().push_back(w); return *this; }
245
nodes__anona87d109f0111::msg_args246 msg_args& nodes(std::vector<node_entry> const& n)
247 { if (!n.empty()) a["nodes"] = dht::write_nodes_entry(n); return *this; }
248
nodes6__anona87d109f0111::msg_args249 msg_args& nodes6(std::vector<node_entry> const& n)
250 { if (!n.empty()) a["nodes6"] = dht::write_nodes_entry(n); return *this; }
251
peers__anona87d109f0111::msg_args252 msg_args& peers(std::set<tcp::endpoint> const& p)
253 { if (!p.empty()) a.dict()["values"] = write_peers(p); return *this; }
254
interval__anona87d109f0111::msg_args255 msg_args& interval(time_duration interval)
256 { a["interval"] = total_seconds(interval); return *this; }
257
num__anona87d109f0111::msg_args258 msg_args& num(int num)
259 { a["num"] = num; return *this; }
260
samples__anona87d109f0111::msg_args261 msg_args& samples(std::vector<sha1_hash> const& samples)
262 {
263 a["samples"] = span<char const>(
264 reinterpret_cast<char const*>(samples.data()), int(samples.size()) * 20);
265 return *this;
266 }
267
268 entry a;
269 };
270
send_dht_request(node & node,char const * msg,udp::endpoint const & ep,bdecode_node * reply,msg_args const & args=msg_args (),char const * t="10",bool has_response=true)271 void send_dht_request(node& node, char const* msg, udp::endpoint const& ep
272 , bdecode_node* reply, msg_args const& args = msg_args()
273 , char const* t = "10", bool has_response = true)
274 {
275 // we're about to clear out the backing buffer
276 // for this bdecode_node, so we better clear it now
277 reply->clear();
278 entry e;
279 e["q"] = msg;
280 e["t"] = t;
281 e["y"] = "q";
282 e["a"] = args.a;
283 e["a"].dict().insert(std::make_pair("id", generate_next().to_string()));
284 char msg_buf[1500];
285 int size = bencode(msg_buf, e);
286
287 bdecode_node decoded;
288 error_code ec;
289 bdecode(msg_buf, msg_buf + size, decoded, ec);
290 if (ec) std::printf("bdecode failed: %s\n", ec.message().c_str());
291
292 dht::msg m(decoded, ep);
293 node.incoming(node.m_sock, m);
294
295 // If the request is supposed to get a response, by now the node should have
296 // invoked the send function and put the response in g_sent_packets
297 auto const i = find_packet(ep);
298 if (has_response)
299 {
300 if (i == g_sent_packets.end())
301 {
302 TEST_ERROR("not response from DHT node");
303 return;
304 }
305
306 node_from_entry(i->second, *reply);
307 g_sent_packets.erase(i);
308
309 return;
310 }
311
312 // this request suppose won't be responsed.
313 if (i != g_sent_packets.end())
314 {
315 TEST_ERROR("shouldn't have response from DHT node");
316 return;
317 }
318 }
319
send_dht_response(node & node,bdecode_node const & request,udp::endpoint const & ep,msg_args const & args=msg_args ())320 void send_dht_response(node& node, bdecode_node const& request, udp::endpoint const& ep
321 , msg_args const& args = msg_args())
322 {
323 entry e;
324 e["y"] = "r";
325 e["t"] = request.dict_find_string_value("t").to_string();
326 // e["ip"] = endpoint_to_bytes(ep);
327 e["r"] = args.a;
328 e["r"].dict().insert(std::make_pair("id", generate_next().to_string()));
329 char msg_buf[1500];
330 int const size = bencode(msg_buf, e);
331
332 bdecode_node decoded;
333 error_code ec;
334 bdecode(msg_buf, msg_buf + size, decoded, ec);
335 if (ec) std::printf("bdecode failed: %s\n", ec.message().c_str());
336
337 dht::msg m(decoded, ep);
338 node.incoming(node.m_sock, m);
339 }
340
341 struct announce_item
342 {
announce_item__anona87d109f0111::announce_item343 announce_item(sha1_hash nxt, int const num)
344 : next(nxt)
345 , num_peers(num)
346 {
347 num_peers = (rand() % 5) + 2;
348 ent["next"] = next.to_string();
349 ent["A"] = "a";
350 ent["B"] = "b";
351 ent["num_peers"] = num_peers;
352
353 char buf[512];
354 char* ptr = buf;
355 int len = bencode(ptr, ent);
356 target = hasher(buf, len).final();
357 }
358 sha1_hash next;
359 int num_peers;
360 entry ent;
361 sha1_hash target;
362 };
363
announce_immutable_items(node & node,udp::endpoint const * eps,announce_item const * items,int num_items)364 void announce_immutable_items(node& node, udp::endpoint const* eps
365 , announce_item const* items, int num_items)
366 {
367 std::string token;
368 for (int i = 0; i < 1000; ++i)
369 {
370 for (int j = 0; j < num_items; ++j)
371 {
372 if ((i % items[j].num_peers) == 0) continue;
373 bdecode_node response;
374 send_dht_request(node, "get", eps[i], &response
375 , msg_args().target(items[j].target));
376
377 key_desc_t const desc[] =
378 {
379 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
380 { "id", bdecode_node::string_t, 20, 0},
381 { "token", bdecode_node::string_t, 0, 0},
382 { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child},
383 { "y", bdecode_node::string_t, 1, 0},
384 };
385
386 bdecode_node parsed[5];
387 char error_string[200];
388
389 // std::printf("msg: %s\n", print_entry(response).c_str());
390 int ret = verify_message(response, desc, parsed, error_string);
391 if (ret)
392 {
393 TEST_EQUAL(parsed[4].string_value(), "r");
394 token = parsed[2].string_value().to_string();
395 // std::printf("got token: %s\n", token.c_str());
396 }
397 else
398 {
399 std::printf("msg: %s\n", print_entry(response).c_str());
400 std::printf(" invalid get response: %s\n", error_string);
401 TEST_ERROR(error_string);
402 }
403
404 if (parsed[3])
405 {
406 address_v4::bytes_type b;
407 memcpy(&b[0], parsed[3].string_ptr(), b.size());
408 address_v4 addr(b);
409 TEST_EQUAL(addr, eps[i].address());
410 }
411
412 send_dht_request(node, "put", eps[i], &response
413 , msg_args()
414 .token(token)
415 .target(items[j].target)
416 .value(items[j].ent));
417
418 key_desc_t const desc2[] =
419 {
420 { "y", bdecode_node::string_t, 1, 0 }
421 };
422
423 bdecode_node parsed2[1];
424 ret = verify_message(response, desc2, parsed2, error_string);
425 if (ret)
426 {
427 if (parsed2[0].string_value() != "r")
428 std::printf("msg: %s\n", print_entry(response).c_str());
429
430 TEST_EQUAL(parsed2[0].string_value(), "r");
431 }
432 else
433 {
434 std::printf("msg: %s\n", print_entry(response).c_str());
435 std::printf(" invalid put response: %s\n", error_string);
436 TEST_ERROR(error_string);
437 }
438 }
439 }
440
441 std::set<int> items_num;
442 for (int j = 0; j < num_items; ++j)
443 {
444 bdecode_node response;
445 send_dht_request(node, "get", eps[j], &response
446 , msg_args().target(items[j].target));
447
448 key_desc_t const desc[] =
449 {
450 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
451 { "v", bdecode_node::dict_t, 0, 0},
452 { "id", bdecode_node::string_t, 20, key_desc_t::last_child},
453 { "y", bdecode_node::string_t, 1, 0},
454 };
455
456 bdecode_node parsed[4];
457 char error_string[200];
458
459 int ret = verify_message(response, desc, parsed, error_string);
460 if (ret)
461 {
462 items_num.insert(items_num.begin(), j);
463 }
464 }
465
466 // TODO: check to make sure the "best" items are stored
467 TEST_EQUAL(items_num.size(), 4);
468 }
469
sum_distance_exp(int s,node_entry const & e,node_id const & ref)470 int sum_distance_exp(int s, node_entry const& e, node_id const& ref)
471 {
472 return s + distance_exp(e.id, ref);
473 }
474
475 std::vector<tcp::endpoint> g_got_peers;
476
get_peers_cb(std::vector<tcp::endpoint> const & peers)477 void get_peers_cb(std::vector<tcp::endpoint> const& peers)
478 {
479 g_got_peers.insert(g_got_peers.end(), peers.begin(), peers.end());
480 }
481
482 std::vector<dht::item> g_got_items;
483 dht::item g_put_item;
484 int g_put_count;
485
get_mutable_item_cb(dht::item const & i,bool a)486 void get_mutable_item_cb(dht::item const& i, bool a)
487 {
488 if (!a) return;
489 if (!i.empty())
490 g_got_items.push_back(i);
491 }
492
put_mutable_item_data_cb(dht::item & i)493 void put_mutable_item_data_cb(dht::item& i)
494 {
495 if (!i.empty())
496 g_got_items.push_back(i);
497
498 TEST_CHECK(!g_put_item.empty());
499 i = g_put_item;
500 g_put_count++;
501 }
502
put_mutable_item_cb(dht::item const &,int num,int expect)503 void put_mutable_item_cb(dht::item const&, int num, int expect)
504 {
505 TEST_EQUAL(num, expect);
506 }
507
get_immutable_item_cb(dht::item const & i)508 void get_immutable_item_cb(dht::item const& i)
509 {
510 if (!i.empty())
511 g_got_items.push_back(i);
512 }
513
put_immutable_item_cb(int num,int expect)514 void put_immutable_item_cb(int num, int expect)
515 {
516 TEST_EQUAL(num, expect);
517 }
518
519 struct obs : dht::dht_observer
520 {
set_external_address__anona87d109f0111::obs521 void set_external_address(aux::listen_socket_handle const& s, address const& addr
522 , address const& /*source*/) override
523 {
524 s.get()->external_address.cast_vote(addr
525 , aux::session_interface::source_dht, rand_v4());
526 }
527
get_listen_port__anona87d109f0111::obs528 int get_listen_port(aux::transport, aux::listen_socket_handle const& s) override
529 { return s.get()->udp_external_port(); }
530
get_peers__anona87d109f0111::obs531 void get_peers(sha1_hash const&) override {}
outgoing_get_peers__anona87d109f0111::obs532 void outgoing_get_peers(sha1_hash const& /*target*/
533 , sha1_hash const& /*sent_target*/, udp::endpoint const&) override {}
announce__anona87d109f0111::obs534 void announce(sha1_hash const&, address const&, int) override {}
535 #ifndef TORRENT_DISABLE_LOGGING
should_log__anona87d109f0111::obs536 bool should_log(module_t) const override { return true; }
log__anona87d109f0111::obs537 void log(dht_logger::module_t, char const* fmt, ...) override
538 {
539 va_list v;
540 va_start(v, fmt);
541 char buf[1024];
542 #ifdef __clang__
543 #pragma clang diagnostic push
544 #pragma clang diagnostic ignored "-Wformat-nonliteral"
545 #endif
546 std::vsnprintf(buf, sizeof(buf), fmt, v);
547 #ifdef __clang__
548 #pragma clang diagnostic pop
549 #endif
550 va_end(v);
551 std::printf("%s\n", buf);
552 m_log.emplace_back(buf);
553 }
log_packet__anona87d109f0111::obs554 void log_packet(message_direction_t, span<char const>
555 , udp::endpoint const&) override {}
556 #endif
on_dht_request__anona87d109f0111::obs557 bool on_dht_request(string_view
558 , dht::msg const&, entry&) override { return false; }
559
560 virtual ~obs() = default;
561
562 #ifndef TORRENT_DISABLE_LOGGING
563 std::vector<std::string> m_log;
564 #endif
565 };
566
test_settings()567 dht::settings test_settings()
568 {
569 dht::settings sett;
570 sett.max_torrents = 4;
571 sett.max_dht_items = 4;
572 sett.enforce_node_id = false;
573 return sett;
574 }
575
576 struct dht_test_setup
577 {
dht_test_setup__anona87d109f0111::dht_test_setup578 explicit dht_test_setup(udp::endpoint src)
579 : sett(test_settings())
580 , ls(dummy_listen_socket(src))
581 , dht_storage(dht_default_storage_constructor(sett))
582 , source(src)
583 , dht_node(ls, &s, sett
584 , node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage)
585 {
586 dht_storage->update_node_ids({node_id::min()});
587 }
588
589 dht::settings sett;
590 mock_socket s;
591 std::shared_ptr<aux::listen_socket_t> ls;
592 obs observer;
593 counters cnt;
594 std::unique_ptr<dht_storage_interface> dht_storage;
595 udp::endpoint source;
596 dht::node dht_node;
597 char error_string[200];
598 };
599
600 dht::key_desc_t const err_desc[] = {
601 {"y", bdecode_node::string_t, 1, 0},
602 {"e", bdecode_node::list_t, 2, 0}
603 };
604
605 dht::key_desc_t const peer1_desc[] = {
606 {"y", bdecode_node::string_t, 1, 0},
607 {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
608 {"token", bdecode_node::string_t, 0, 0},
609 {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
610 };
611
612 dht::key_desc_t const get_item_desc[] = {
613 {"y", bdecode_node::string_t, 1, 0},
614 {"t", bdecode_node::string_t, 2, 0},
615 {"q", bdecode_node::string_t, 3, 0},
616 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
617 {"id", bdecode_node::string_t, 20, 0},
618 {"target", bdecode_node::string_t, 20, key_desc_t::last_child},
619 };
620
621 dht::key_desc_t const put_mutable_item_desc[] = {
622 {"y", bdecode_node::string_t, 1, 0},
623 {"t", bdecode_node::string_t, 2, 0},
624 {"q", bdecode_node::string_t, 3, 0},
625 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
626 {"id", bdecode_node::string_t, 20, 0},
627 {"cas", bdecode_node::string_t, 20, key_desc_t::optional},
628 {"k", bdecode_node::string_t, public_key::len, 0},
629 {"seq", bdecode_node::int_t, 0, 0},
630 {"sig", bdecode_node::string_t, signature::len, 0},
631 {"token", bdecode_node::string_t, 2, 0},
632 {"v", bdecode_node::none_t, 0, key_desc_t::last_child},
633 };
634
635 dht::key_desc_t const sample_infohashes_desc[] = {
636 {"y", bdecode_node::string_t, 1, 0},
637 {"t", bdecode_node::string_t, 2, 0},
638 {"q", bdecode_node::string_t, 17, 0},
639 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
640 {"id", bdecode_node::string_t, 20, 0},
641 {"target", bdecode_node::string_t, 20, key_desc_t::last_child},
642 };
643
print_state(std::ostream & os,routing_table const & table)644 void print_state(std::ostream& os, routing_table const& table)
645 {
646 #define BUFFER_CURSOR_POS &buf[std::size_t(cursor)], buf.size() - std::size_t(cursor)
647 std::vector<char> buf(2048);
648 int cursor = 0;
649
650 cursor += std::snprintf(BUFFER_CURSOR_POS
651 , "kademlia routing table state\n"
652 "bucket_size: %d\n"
653 "global node count: %" PRId64 "\n"
654 "node_id: %s\n\n"
655 "number of nodes per bucket:\n"
656 , table.bucket_size()
657 , table.num_global_nodes()
658 , aux::to_hex(table.id()).c_str());
659 if (cursor > int(buf.size()) - 500) buf.resize(buf.size() * 3 / 2);
660
661 int idx = 0;
662
663 for (auto i = table.buckets().begin(), end(table.buckets().end());
664 i != end; ++i, ++idx)
665 {
666 cursor += std::snprintf(BUFFER_CURSOR_POS
667 , "%2d: ", idx);
668 for (int k = 0; k < int(i->live_nodes.size()); ++k)
669 cursor += std::snprintf(BUFFER_CURSOR_POS, "#");
670 for (int k = 0; k < int(i->replacements.size()); ++k)
671 cursor += std::snprintf(BUFFER_CURSOR_POS, "-");
672 cursor += std::snprintf(BUFFER_CURSOR_POS, "\n");
673
674 if (cursor > int(buf.size()) - 500) buf.resize(buf.size() * 3 / 2);
675 }
676
677 time_point now = aux::time_now();
678
679 cursor += std::snprintf(BUFFER_CURSOR_POS
680 , "\nnodes:");
681
682 int bucket_index = 0;
683 for (auto i = table.buckets().begin(), end(table.buckets().end());
684 i != end; ++i, ++bucket_index)
685 {
686 cursor += std::snprintf(BUFFER_CURSOR_POS
687 , "\n=== BUCKET == %d == %d|%d ==== \n"
688 , bucket_index, int(i->live_nodes.size())
689 , int(i->replacements.size()));
690 if (cursor > int(buf.size()) - 500) buf.resize(buf.size() * 3 / 2);
691
692 bucket_t nodes = i->live_nodes;
693
694 std::sort(nodes.begin(), nodes.end()
695 , [](node_entry const& lhs, node_entry const& rhs)
696 { return lhs.id < rhs.id; }
697 );
698
699 for (auto j = nodes.begin(); j != nodes.end(); ++j)
700 {
701 int const bucket_size_limit = table.bucket_limit(bucket_index);
702 TORRENT_ASSERT_VAL(bucket_size_limit <= 256, bucket_size_limit);
703 TORRENT_ASSERT_VAL(bucket_size_limit > 0, bucket_size_limit);
704
705 bool const last_bucket = bucket_index + 1 == int(table.buckets().size());
706 int const prefix = classify_prefix(bucket_index, last_bucket
707 , bucket_size_limit, j->id);
708
709 cursor += std::snprintf(BUFFER_CURSOR_POS
710 , " prefix: %2x id: %s", prefix, aux::to_hex(j->id).c_str());
711
712 if (j->rtt == 0xffff)
713 {
714 cursor += std::snprintf(BUFFER_CURSOR_POS
715 , " rtt: ");
716 }
717 else
718 {
719 cursor += std::snprintf(BUFFER_CURSOR_POS
720 , " rtt: %4d", j->rtt);
721 }
722
723 cursor += std::snprintf(BUFFER_CURSOR_POS
724 , " fail: %3d ping: %d dist: %3d"
725 , j->fail_count()
726 , j->pinged()
727 , distance_exp(table.id(), j->id));
728
729 if (j->last_queried == min_time())
730 {
731 cursor += std::snprintf(BUFFER_CURSOR_POS
732 , " query: ");
733 }
734 else
735 {
736 cursor += std::snprintf(BUFFER_CURSOR_POS
737 , " query: %3d", int(total_seconds(now - j->last_queried)));
738 }
739
740 cursor += std::snprintf(BUFFER_CURSOR_POS
741 , " ip: %s\n", print_endpoint(j->ep()).c_str());
742 if (cursor > int(buf.size()) - 500) buf.resize(buf.size() * 3 / 2);
743 }
744 }
745
746 cursor += std::snprintf(BUFFER_CURSOR_POS
747 , "\nnode spread per bucket:\n");
748 bucket_index = 0;
749 for (auto i = table.buckets().begin(), end(table.buckets().end());
750 i != end; ++i, ++bucket_index)
751 {
752 int const bucket_size_limit = table.bucket_limit(bucket_index);
753 TORRENT_ASSERT_VAL(bucket_size_limit <= 256, bucket_size_limit);
754 TORRENT_ASSERT_VAL(bucket_size_limit > 0, bucket_size_limit);
755 std::array<bool, 256> sub_buckets;
756 sub_buckets.fill(false);
757
758 // the last bucket is special, since it hasn't been split yet, it
759 // includes that top bit as well
760 bool const last_bucket = bucket_index + 1 == int(table.buckets().size());
761
762 for (auto const& e : i->live_nodes)
763 {
764 std::size_t const prefix = static_cast<std::size_t>(
765 classify_prefix(bucket_index, last_bucket, bucket_size_limit, e.id));
766 sub_buckets[prefix] = true;
767 }
768
769 cursor += std::snprintf(BUFFER_CURSOR_POS, "%2d: [", bucket_index);
770
771 for (int j = 0; j < bucket_size_limit; ++j)
772 {
773 cursor += std::snprintf(BUFFER_CURSOR_POS
774 , (sub_buckets[static_cast<std::size_t>(j)] ? "X" : " "));
775 }
776 cursor += std::snprintf(BUFFER_CURSOR_POS
777 , "]\n");
778 if (cursor > int(buf.size()) - 500) buf.resize(buf.size() * 3 / 2);
779 }
780 buf[std::size_t(cursor)] = '\0';
781 os << &buf[0];
782 #undef BUFFER_CURSOR_POS
783 }
784
785 } // anonymous namespace
786
TORRENT_TEST(ping)787 TORRENT_TEST(ping)
788 {
789 dht_test_setup t(udp::endpoint(rand_v4(), 20));
790 bdecode_node response;
791
792 send_dht_request(t.dht_node, "ping", t.source, &response);
793
794 dht::key_desc_t const pong_desc[] = {
795 {"y", bdecode_node::string_t, 1, 0},
796 {"t", bdecode_node::string_t, 2, 0},
797 {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
798 {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
799 };
800
801 bdecode_node pong_keys[4];
802
803 std::printf("msg: %s\n", print_entry(response).c_str());
804 bool ret = dht::verify_message(response, pong_desc, pong_keys, t.error_string);
805 TEST_CHECK(ret);
806 if (ret)
807 {
808 TEST_CHECK(pong_keys[0].string_value() == "r");
809 TEST_CHECK(pong_keys[1].string_value() == "10");
810 }
811 else
812 {
813 std::printf(" invalid ping response: %s\n", t.error_string);
814 }
815 }
816
TORRENT_TEST(invalid_message)817 TORRENT_TEST(invalid_message)
818 {
819 dht_test_setup t(udp::endpoint(rand_v4(), 20));
820 bdecode_node response;
821 bdecode_node err_keys[2];
822
823 send_dht_request(t.dht_node, "find_node", t.source, &response);
824
825 std::printf("msg: %s\n", print_entry(response).c_str());
826 bool ret = dht::verify_message(response, err_desc, err_keys, t.error_string);
827 TEST_CHECK(ret);
828 if (ret)
829 {
830 TEST_CHECK(err_keys[0].string_value() == "e");
831 if (err_keys[1].list_at(0).type() == bdecode_node::int_t
832 && err_keys[1].list_at(1).type() == bdecode_node::string_t)
833 {
834 TEST_CHECK(err_keys[1].list_at(1).string_value() == "missing 'target' key");
835 }
836 else
837 {
838 TEST_ERROR("invalid error response");
839 }
840 }
841 else
842 {
843 std::printf(" invalid error response: %s\n", t.error_string);
844 }
845 }
846
TORRENT_TEST(node_id_testng)847 TORRENT_TEST(node_id_testng)
848 {
849 node_id rnd = generate_secret_id();
850 TEST_CHECK(verify_secret_id(rnd));
851
852 rnd[19] ^= 0x55;
853 TEST_CHECK(!verify_secret_id(rnd));
854
855 rnd = generate_random_id();
856 make_id_secret(rnd);
857 TEST_CHECK(verify_secret_id(rnd));
858 }
859
TORRENT_TEST(get_peers_announce)860 TORRENT_TEST(get_peers_announce)
861 {
862 dht_test_setup t(udp::endpoint(rand_v4(), 20));
863 bdecode_node response;
864
865 send_dht_request(t.dht_node, "get_peers", t.source, &response
866 , msg_args().info_hash("01010101010101010101"));
867
868 bdecode_node peer1_keys[4];
869
870 std::string token;
871 std::printf("msg: %s\n", print_entry(response).c_str());
872 bool ret = dht::verify_message(response, peer1_desc, peer1_keys, t.error_string);
873 TEST_CHECK(ret);
874 if (ret)
875 {
876 TEST_CHECK(peer1_keys[0].string_value() == "r");
877 token = peer1_keys[2].string_value().to_string();
878 // std::printf("got token: %s\n", token.c_str());
879 }
880 else
881 {
882 std::printf("msg: %s\n", print_entry(response).c_str());
883 std::printf(" invalid get_peers response: %s\n", t.error_string);
884 }
885
886 send_dht_request(t.dht_node, "announce_peer", t.source, &response
887 , msg_args()
888 .info_hash("01010101010101010101")
889 .name("test")
890 .token(token)
891 .port(8080));
892
893 dht::key_desc_t const ann_desc[] = {
894 {"y", bdecode_node::string_t, 1, 0},
895 {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
896 {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
897 };
898
899 bdecode_node ann_keys[3];
900
901 std::printf("msg: %s\n", print_entry(response).c_str());
902 ret = dht::verify_message(response, ann_desc, ann_keys, t.error_string);
903 TEST_CHECK(ret);
904 if (ret)
905 {
906 TEST_CHECK(ann_keys[0].string_value() == "r");
907 }
908 else
909 {
910 std::printf(" invalid announce response:\n");
911 TEST_ERROR(t.error_string);
912 }
913 }
914
915 namespace {
916
test_scrape(address (& rand_addr)())917 void test_scrape(address(&rand_addr)())
918 {
919 dht_test_setup t(udp::endpoint(rand_addr(), 20));
920 bdecode_node response;
921
922 init_rand_address();
923
924 // announce from 100 random IPs and make sure scrape works
925 // 50 downloaders and 50 seeds
926 for (int i = 0; i < 100; ++i)
927 {
928 t.source = udp::endpoint(rand_addr(), 6000);
929 send_dht_request(t.dht_node, "get_peers", t.source, &response
930 , msg_args().info_hash("01010101010101010101"));
931
932 bdecode_node peer1_keys[4];
933 bool ret = dht::verify_message(response, peer1_desc, peer1_keys, t.error_string);
934
935 std::string token;
936 if (ret)
937 {
938 TEST_CHECK(peer1_keys[0].string_value() == "r");
939 token = peer1_keys[2].string_value().to_string();
940 }
941 else
942 {
943 std::printf("msg: %s\n", print_entry(response).c_str());
944 std::printf(" invalid get_peers response: %s\n", t.error_string);
945 }
946 response.clear();
947 send_dht_request(t.dht_node, "announce_peer", t.source, &response
948 , msg_args()
949 .info_hash("01010101010101010101")
950 .name("test")
951 .token(token)
952 .port(8080)
953 .seed(i >= 50));
954
955 response.clear();
956 }
957
958 // ====== get_peers ======
959
960 send_dht_request(t.dht_node, "get_peers", t.source, &response
961 , msg_args().info_hash("01010101010101010101").scrape(true));
962
963 dht::key_desc_t const peer2_desc[] = {
964 {"y", bdecode_node::string_t, 1, 0},
965 {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
966 {"BFpe", bdecode_node::string_t, 256, 0},
967 {"BFsd", bdecode_node::string_t, 256, 0},
968 {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
969 };
970
971 bdecode_node peer2_keys[5];
972
973 std::printf("msg: %s\n", print_entry(response).c_str());
974 bool ret = dht::verify_message(response, peer2_desc, peer2_keys, t.error_string);
975 TEST_CHECK(ret);
976 if (ret)
977 {
978 TEST_CHECK(peer2_keys[0].string_value() == "r");
979 TEST_EQUAL(peer2_keys[1].dict_find_string_value("n"), "test");
980
981 bloom_filter<256> downloaders;
982 bloom_filter<256> seeds;
983 downloaders.from_string(peer2_keys[2].string_ptr());
984 seeds.from_string(peer2_keys[3].string_ptr());
985
986 std::printf("seeds: %f\n", double(seeds.size()));
987 std::printf("downloaders: %f\n", double(downloaders.size()));
988
989 TEST_CHECK(std::abs(seeds.size() - 50.f) <= 3.f);
990 TEST_CHECK(std::abs(downloaders.size() - 50.f) <= 3.f);
991 }
992 else
993 {
994 std::printf("invalid get_peers response:\n");
995 TEST_ERROR(t.error_string);
996 }
997 }
998
999 } // anonymous namespace
1000
TORRENT_TEST(scrape_v4)1001 TORRENT_TEST(scrape_v4)
1002 {
1003 test_scrape(rand_v4);
1004 }
1005
TORRENT_TEST(scrape_v6)1006 TORRENT_TEST(scrape_v6)
1007 {
1008 if (supports_ipv6())
1009 test_scrape(rand_v6);
1010 }
1011
1012 namespace {
1013
test_id_enforcement(address (& rand_addr)())1014 void test_id_enforcement(address(&rand_addr)())
1015 {
1016 dht_test_setup t(udp::endpoint(rand_addr(), 20));
1017 bdecode_node response;
1018
1019 // enable node_id enforcement
1020 t.sett.enforce_node_id = true;
1021
1022 node_id nid;
1023 if (is_v4(t.source))
1024 {
1025 // this is one of the test vectors from:
1026 // http://libtorrent.org/dht_sec.html
1027 t.source = udp::endpoint(addr("124.31.75.21"), 1);
1028 nid = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee401");
1029 }
1030 else
1031 {
1032 t.source = udp::endpoint(addr("2001:b829:2123:be84:e16c:d6ae:5290:49f1"), 1);
1033 nid = to_hash("0a8ad123be84e16cd6ae529049f1f1bbe9ebb304");
1034 }
1035
1036 // verify that we reject invalid node IDs
1037 // this is now an invalid node-id for 'source'
1038 nid[0] = 0x18;
1039 // the test nodes don't get pinged so they will only get as far
1040 // as the replacement bucket
1041 int nodes_num = std::get<1>(t.dht_node.size());
1042 send_dht_request(t.dht_node, "find_node", t.source, &response
1043 , msg_args()
1044 .target(sha1_hash("0101010101010101010101010101010101010101"))
1045 .nid(nid));
1046
1047 bdecode_node err_keys[2];
1048 bool ret = dht::verify_message(response, err_desc, err_keys, t.error_string);
1049 TEST_CHECK(ret);
1050 if (ret)
1051 {
1052 TEST_CHECK(err_keys[0].string_value() == "e");
1053 if (err_keys[1].list_at(0).type() == bdecode_node::int_t
1054 && err_keys[1].list_at(1).type() == bdecode_node::string_t)
1055 {
1056 TEST_CHECK(err_keys[1].list_at(1).string_value() == "invalid node ID");
1057 }
1058 else
1059 {
1060 std::printf("msg: %s\n", print_entry(response).c_str());
1061 TEST_ERROR("invalid error response");
1062 }
1063 }
1064 else
1065 {
1066 std::printf("msg: %s\n", print_entry(response).c_str());
1067 std::printf(" invalid error response: %s\n", t.error_string);
1068 }
1069
1070 // a node with invalid node-id shouldn't be added to routing table.
1071 TEST_EQUAL(std::get<1>(t.dht_node.size()), nodes_num);
1072
1073 // now the node-id is valid.
1074 if (is_v4(t.source))
1075 nid[0] = 0x5f;
1076 else
1077 nid[0] = 0x0a;
1078 send_dht_request(t.dht_node, "find_node", t.source, &response
1079 , msg_args()
1080 .target(sha1_hash("0101010101010101010101010101010101010101"))
1081 .nid(nid));
1082
1083 dht::key_desc_t const nodes_desc[] = {
1084 {"y", bdecode_node::string_t, 1, 0},
1085 {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
1086 {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
1087 };
1088
1089 bdecode_node nodes_keys[3];
1090
1091 std::printf("msg: %s\n", print_entry(response).c_str());
1092 ret = dht::verify_message(response, nodes_desc, nodes_keys, t.error_string);
1093 TEST_CHECK(ret);
1094 if (ret)
1095 {
1096 TEST_CHECK(nodes_keys[0].string_value() == "r");
1097 }
1098 else
1099 {
1100 std::printf("msg: %s\n", print_entry(response).c_str());
1101 std::printf(" invalid error response: %s\n", t.error_string);
1102 }
1103 // node with valid node-id should be added to routing table.
1104 TEST_EQUAL(std::get<1>(t.dht_node.size()), nodes_num + 1);
1105 }
1106
1107 } // anonymous namespace
1108
TORRENT_TEST(id_enforcement_v4)1109 TORRENT_TEST(id_enforcement_v4)
1110 {
1111 test_id_enforcement(rand_v4);
1112 }
1113
TORRENT_TEST(id_enforcement_v6)1114 TORRENT_TEST(id_enforcement_v6)
1115 {
1116 if (supports_ipv6())
1117 test_id_enforcement(rand_v6);
1118 }
1119
TORRENT_TEST(bloom_filter)1120 TORRENT_TEST(bloom_filter)
1121 {
1122 bloom_filter<256> test;
1123 for (int i = 0; i < 256; ++i)
1124 {
1125 char adr[50];
1126 std::snprintf(adr, sizeof(adr), "192.0.2.%d", i);
1127 address a = addr(adr);
1128 sha1_hash const iphash = hash_address(a);
1129 test.set(iphash);
1130 }
1131
1132 if (supports_ipv6())
1133 {
1134 for (int i = 0; i < 0x3E8; ++i)
1135 {
1136 char adr[50];
1137 std::snprintf(adr, sizeof(adr), "2001:db8::%x", i);
1138 address a = addr(adr);
1139 sha1_hash const iphash = hash_address(a);
1140 test.set(iphash);
1141 }
1142 }
1143
1144 // these are test vectors from BEP 33
1145 // http://www.bittorrent.org/beps/bep_0033.html
1146 std::printf("test.size: %f\n", double(test.size()));
1147 std::string const bf_str = test.to_string();
1148 std::printf("%s\n", aux::to_hex(bf_str).c_str());
1149 if (supports_ipv6())
1150 {
1151 TEST_CHECK(std::abs(double(test.size()) - 1224.93) < 0.001);
1152 TEST_CHECK(aux::to_hex(bf_str) ==
1153 "f6c3f5eaa07ffd91bde89f777f26fb2b"
1154 "ff37bdb8fb2bbaa2fd3ddde7bacfff75"
1155 "ee7ccbaefe5eedb1fbfaff67f6abff5e"
1156 "43ddbca3fd9b9ffdf4ffd3e9dff12d1b"
1157 "df59db53dbe9fa5b7ff3b8fdfcde1afb"
1158 "8bedd7be2f3ee71ebbbfe93bcdeefe14"
1159 "8246c2bc5dbff7e7efdcf24fd8dc7adf"
1160 "fd8fffdfddfff7a4bbeedf5cb95ce81f"
1161 "c7fcff1ff4ffffdfe5f7fdcbb7fd79b3"
1162 "fa1fc77bfe07fff905b7b7ffc7fefeff"
1163 "e0b8370bb0cd3f5b7f2bd93feb4386cf"
1164 "dd6f7fd5bfaf2e9ebffffeecd67adbf7"
1165 "c67f17efd5d75eba6ffeba7fff47a91e"
1166 "b1bfbb53e8abfb5762abe8ff237279bf"
1167 "efbfeef5ffc5febfdfe5adffadfee1fb"
1168 "737ffffbfd9f6aeffeee76b6fd8f72ef");
1169 }
1170 else
1171 {
1172 TEST_CHECK(std::abs(double(test.size()) - 257.854) < 0.001);
1173 TEST_CHECK(aux::to_hex(bf_str) ==
1174 "24c0004020043000102012743e004800"
1175 "37110820422110008000c0e302854835"
1176 "a05401a4045021302a306c0600018810"
1177 "02d8a0a3a8001901b40a800900310008"
1178 "d2108110c2496a0028700010d804188b"
1179 "01415200082004088026411104a80404"
1180 "8002002000080680828c400080cc4002"
1181 "0c042c0494447280928041402104080d"
1182 "4240040414a41f0205654800b0811830"
1183 "d2020042b002c5800004a71d0204804a"
1184 "0028120a004c10017801490b83400404"
1185 "4106005421000c86900a002050020351"
1186 "0060144e900100924a1018141a028012"
1187 "913f0041802250042280481200002004"
1188 "430804210101c08111c1080100108000"
1189 "2038008211004266848606b035001048");
1190 }
1191 }
1192
1193 namespace {
1194 announce_item const items[] =
1195 {
1196 { generate_next(), 1 },
1197 { generate_next(), 2 },
1198 { generate_next(), 3 },
1199 { generate_next(), 4 },
1200 { generate_next(), 5 },
1201 { generate_next(), 6 },
1202 { generate_next(), 7 },
1203 { generate_next(), 8 }
1204 };
1205
build_nodes()1206 lt::aux::array<node_entry, 8> build_nodes()
1207 {
1208 return lt::aux::array<node_entry, 8>(
1209 std::array<node_entry, 8> {
1210 { { items[0].target, udp::endpoint(addr4("1.1.1.1"), 1231), 10, true}
1211 , { items[1].target, udp::endpoint(addr4("2.2.2.2"), 1232), 10, true}
1212 , { items[2].target, udp::endpoint(addr4("3.3.3.3"), 1233), 10, true}
1213 , { items[3].target, udp::endpoint(addr4("4.4.4.4"), 1234), 10, true}
1214 , { items[4].target, udp::endpoint(addr4("5.5.5.5"), 1235), 10, true}
1215 , { items[5].target, udp::endpoint(addr4("6.6.6.6"), 1236), 10, true}
1216 , { items[6].target, udp::endpoint(addr4("7.7.7.7"), 1237), 10, true}
1217 , { items[7].target, udp::endpoint(addr4("8.8.8.8"), 1238), 10, true} }
1218 });
1219 }
1220
build_nodes(sha1_hash target)1221 lt::aux::array<node_entry, 9> build_nodes(sha1_hash target)
1222 {
1223 return lt::aux::array<node_entry, 9>(
1224 std::array<node_entry, 9> {
1225 { { target, udp::endpoint(addr4("1.1.1.1"), 1231), 10, true}
1226 , { target, udp::endpoint(addr4("2.2.2.2"), 1232), 10, true}
1227 , { target, udp::endpoint(addr4("3.3.3.3"), 1233), 10, true}
1228 , { target, udp::endpoint(addr4("4.4.4.4"), 1234), 10, true}
1229 , { target, udp::endpoint(addr4("5.5.5.5"), 1235), 10, true}
1230 , { target, udp::endpoint(addr4("6.6.6.6"), 1236), 10, true}
1231 , { target, udp::endpoint(addr4("7.7.7.7"), 1237), 10, true}
1232 , { target, udp::endpoint(addr4("8.8.8.8"), 1238), 10, true}
1233 , { target, udp::endpoint(addr4("9.9.9.9"), 1239), 10, true} }
1234 });
1235 }
1236
1237 span<char const> const empty_salt;
1238
1239 // TODO: 3 split this up into smaller tests
test_put(address (& rand_addr)())1240 void test_put(address(&rand_addr)())
1241 {
1242 dht_test_setup t(udp::endpoint(rand_addr(), 20));
1243
1244 bdecode_node response;
1245 bool ret;
1246
1247 // ====== put ======
1248
1249 init_rand_address();
1250 udp::endpoint eps[1000];
1251 for (int i = 0; i < 1000; ++i)
1252 eps[i] = udp::endpoint(rand_addr(), (rand() % 16534) + 1);
1253
1254 announce_immutable_items(t.dht_node, eps, items, sizeof(items)/sizeof(items[0]));
1255
1256 key_desc_t const desc2[] =
1257 {
1258 { "y", bdecode_node::string_t, 1, 0 }
1259 };
1260
1261 bdecode_node desc2_keys[1];
1262
1263 key_desc_t const desc_error[] =
1264 {
1265 { "e", bdecode_node::list_t, 2, 0 },
1266 { "y", bdecode_node::string_t, 1, 0},
1267 };
1268
1269 bdecode_node desc_error_keys[2];
1270
1271 // ==== get / put mutable items ===
1272
1273 span<char const> itemv;
1274
1275 signature sig;
1276 char buffer[1200];
1277 sequence_number seq(4);
1278 public_key pk;
1279 secret_key sk;
1280 get_test_keypair(pk, sk);
1281
1282 // TODO: 4 pass in the actual salt as a parameter
1283 for (int with_salt = 0; with_salt < 2; ++with_salt)
1284 {
1285 seq = sequence_number(4);
1286 std::printf("\nTEST GET/PUT%s \ngenerating ed25519 keys\n\n"
1287 , with_salt ? " with-salt" : " no-salt");
1288 std::array<char, 32> seed = ed25519_create_seed();
1289
1290 std::tie(pk, sk) = ed25519_create_keypair(seed);
1291 std::printf("pub: %s priv: %s\n"
1292 , aux::to_hex(pk.bytes).c_str()
1293 , aux::to_hex(sk.bytes).c_str());
1294
1295 std::string salt;
1296 if (with_salt) salt = "foobar";
1297
1298 hasher h(pk.bytes);
1299 if (with_salt) h.update(salt);
1300 sha1_hash target_id = h.final();
1301
1302 std::printf("target_id: %s\n"
1303 , aux::to_hex(target_id).c_str());
1304
1305 send_dht_request(t.dht_node, "get", t.source, &response
1306 , msg_args().target(target_id));
1307
1308 key_desc_t const desc[] =
1309 {
1310 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
1311 { "id", bdecode_node::string_t, 20, 0},
1312 { "token", bdecode_node::string_t, 0, 0},
1313 { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child},
1314 { "y", bdecode_node::string_t, 1, 0},
1315 };
1316
1317 bdecode_node desc_keys[5];
1318
1319 ret = verify_message(response, desc, desc_keys, t.error_string);
1320 std::string token;
1321 if (ret)
1322 {
1323 TEST_EQUAL(desc_keys[4].string_value(), "r");
1324 token = desc_keys[2].string_value().to_string();
1325 std::printf("get response: %s\n"
1326 , print_entry(response).c_str());
1327 std::printf("got token: %s\n", aux::to_hex(token).c_str());
1328 }
1329 else
1330 {
1331 std::printf("msg: %s\n", print_entry(response).c_str());
1332 std::printf(" invalid get response: %s\n%s\n"
1333 , t.error_string, print_entry(response).c_str());
1334 TEST_ERROR(t.error_string);
1335 }
1336
1337 itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
1338 sig = sign_mutable_item(itemv, salt, seq, pk, sk);
1339 TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), true);
1340
1341 send_dht_request(t.dht_node, "put", t.source, &response
1342 , msg_args()
1343 .token(token)
1344 .value(items[0].ent)
1345 .key(pk)
1346 .sig(sig)
1347 .seq(seq)
1348 .salt(salt));
1349
1350 ret = verify_message(response, desc2, desc2_keys, t.error_string);
1351 if (ret)
1352 {
1353 std::printf("put response: %s\n"
1354 , print_entry(response).c_str());
1355 TEST_EQUAL(desc2_keys[0].string_value(), "r");
1356 }
1357 else
1358 {
1359 std::printf(" invalid put response: %s\n%s\n"
1360 , t.error_string, print_entry(response).c_str());
1361 TEST_ERROR(t.error_string);
1362 }
1363
1364 send_dht_request(t.dht_node, "get", t.source, &response
1365 , msg_args().target(target_id));
1366
1367 std::printf("target_id: %s\n"
1368 , aux::to_hex(target_id).c_str());
1369
1370 key_desc_t const desc3[] =
1371 {
1372 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
1373 { "id", bdecode_node::string_t, 20, 0},
1374 { "v", bdecode_node::none_t, 0, 0},
1375 { "seq", bdecode_node::int_t, 0, 0},
1376 { "sig", bdecode_node::string_t, 0, 0},
1377 { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child},
1378 { "y", bdecode_node::string_t, 1, 0},
1379 };
1380
1381 bdecode_node desc3_keys[7];
1382
1383 ret = verify_message(response, desc3, desc3_keys, t.error_string);
1384 if (ret == 0)
1385 {
1386 std::printf("msg: %s\n", print_entry(response).c_str());
1387 std::printf(" invalid get response: %s\n%s\n"
1388 , t.error_string, print_entry(response).c_str());
1389 TEST_ERROR(t.error_string);
1390 }
1391 else
1392 {
1393 std::printf("get response: %s\n"
1394 , print_entry(response).c_str());
1395 char value[1020];
1396 char* ptr = value;
1397 int const value_len = bencode(ptr, items[0].ent);
1398 TEST_EQUAL(value_len, int(desc3_keys[2].data_section().size()));
1399 TEST_CHECK(std::memcmp(desc3_keys[2].data_section().data(), value, std::size_t(value_len)) == 0);
1400
1401 TEST_EQUAL(int(seq.value), desc3_keys[3].int_value());
1402 }
1403
1404 // also test that invalid signatures fail!
1405
1406 itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
1407 sig = sign_mutable_item(itemv, salt, seq, pk, sk);
1408 TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), 1);
1409 // break the signature
1410 sig.bytes[2] ^= 0xaa;
1411
1412 std::printf("PUT broken signature\n");
1413
1414 TEST_CHECK(verify_mutable_item(itemv, salt, seq, pk, sig) != 1);
1415
1416 send_dht_request(t.dht_node, "put", t.source, &response
1417 , msg_args()
1418 .token(token)
1419 .value(items[0].ent)
1420 .key(pk)
1421 .sig(sig)
1422 .seq(seq)
1423 .salt(salt));
1424
1425 ret = verify_message(response, desc_error, desc_error_keys, t.error_string);
1426 if (ret)
1427 {
1428 std::printf("put response: %s\n", print_entry(response).c_str());
1429 TEST_EQUAL(desc_error_keys[1].string_value(), "e");
1430 // 206 is the code for invalid signature
1431 TEST_EQUAL(desc_error_keys[0].list_int_value_at(0), 206);
1432 }
1433 else
1434 {
1435 std::printf(" invalid put response: %s\n%s\n"
1436 , t.error_string, print_entry(response).c_str());
1437 TEST_ERROR(t.error_string);
1438 }
1439
1440 // === test conditional get ===
1441
1442 send_dht_request(t.dht_node, "get", t.source, &response
1443 , msg_args().target(target_id).seq(prev_seq(seq)));
1444
1445 {
1446 bdecode_node const r = response.dict_find_dict("r");
1447 TEST_CHECK(r.dict_find("v"));
1448 TEST_CHECK(r.dict_find("k"));
1449 TEST_CHECK(r.dict_find("sig"));
1450 }
1451
1452 send_dht_request(t.dht_node, "get", t.source, &response
1453 , msg_args().target(target_id).seq(seq));
1454
1455 {
1456 bdecode_node r = response.dict_find_dict("r");
1457 TEST_CHECK(!r.dict_find("v"));
1458 TEST_CHECK(!r.dict_find("k"));
1459 TEST_CHECK(!r.dict_find("sig"));
1460 }
1461
1462 // === test CAS put ===
1463
1464 // this is the sequence number we expect to be there
1465 sequence_number cas = seq;
1466
1467 // increment sequence number
1468 seq = next_seq(seq);
1469 // put item 1
1470 itemv = span<char const>(buffer, bencode(buffer, items[1].ent));
1471 sig = sign_mutable_item(itemv, salt, seq, pk, sk);
1472 TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), 1);
1473
1474 TEST_CHECK(item_target_id(salt, pk) == target_id);
1475
1476 std::printf("PUT CAS 1\n");
1477
1478 send_dht_request(t.dht_node, "put", t.source, &response
1479 , msg_args()
1480 .token(token)
1481 .value(items[1].ent)
1482 .key(pk)
1483 .sig(sig)
1484 .seq(seq)
1485 .cas(cas)
1486 .salt(salt));
1487
1488 ret = verify_message(response, desc2, desc2_keys, t.error_string);
1489 if (ret)
1490 {
1491 std::printf("put response: %s\n"
1492 , print_entry(response).c_str());
1493 TEST_EQUAL(desc2_keys[0].string_value(), "r");
1494 }
1495 else
1496 {
1497 std::printf(" invalid put response: %s\n%s\n"
1498 , t.error_string, print_entry(response).c_str());
1499 TEST_ERROR(t.error_string);
1500 }
1501
1502 std::printf("PUT CAS 2\n");
1503
1504 // put the same message again. This should fail because the
1505 // CAS hash is outdated, it's not the hash of the value that's
1506 // stored anymore
1507 send_dht_request(t.dht_node, "put", t.source, &response
1508 , msg_args()
1509 .token(token)
1510 .value(items[1].ent)
1511 .key(pk)
1512 .sig(sig)
1513 .seq(seq)
1514 .cas(cas)
1515 .salt(salt));
1516
1517 ret = verify_message(response, desc_error, desc_error_keys, t.error_string);
1518 if (ret)
1519 {
1520 std::printf("put response: %s\n"
1521 , print_entry(response).c_str());
1522 TEST_EQUAL(desc_error_keys[1].string_value(), "e");
1523 // 301 is the error code for CAS hash mismatch
1524 TEST_EQUAL(desc_error_keys[0].list_int_value_at(0), 301);
1525 }
1526 else
1527 {
1528 std::printf(" invalid put response: %s\n%s\nExpected failure 301 (CAS hash mismatch)\n"
1529 , t.error_string, print_entry(response).c_str());
1530 TEST_ERROR(t.error_string);
1531 }
1532 }
1533 }
1534
1535 } // anonymous namespace
1536
TORRENT_TEST(put_v4)1537 TORRENT_TEST(put_v4)
1538 {
1539 test_put(rand_v4);
1540 }
1541
TORRENT_TEST(put_v6)1542 TORRENT_TEST(put_v6)
1543 {
1544 if (supports_ipv6())
1545 test_put(rand_v6);
1546 }
1547
1548 namespace {
1549
test_routing_table(address (& rand_addr)())1550 void test_routing_table(address(&rand_addr)())
1551 {
1552 init_rand_address();
1553
1554 dht_test_setup t(udp::endpoint(rand_addr(), 20));
1555 bdecode_node response;
1556
1557 // test kademlia routing table
1558 dht::settings s;
1559 s.extended_routing_table = false;
1560 // s.restrict_routing_ips = false;
1561 node_id const nid = to_hash("3123456789abcdef01232456789abcdef0123456");
1562 const int bucket_size = 8;
1563 dht::routing_table table(nid, t.source.protocol(), bucket_size, s, &t.observer);
1564 TEST_EQUAL(std::get<0>(table.size()), 0);
1565
1566 address node_addr;
1567 address node_near_addr;
1568 if (is_v6(t.source))
1569 {
1570 node_addr = addr6("2001:1111:1111:1111:1111:1111:1111:1111");
1571 node_near_addr = addr6("2001:1111:1111:1111:eeee:eeee:eeee:eeee");
1572 }
1573 else
1574 {
1575 node_addr = addr4("4.4.4.4");
1576 node_near_addr = addr4("4.4.4.5");
1577 }
1578
1579 // test a node with the same IP:port changing ID
1580 node_id const tmp = generate_id_impl(node_addr, 1);
1581 table.node_seen(tmp, udp::endpoint(node_addr, 4), 10);
1582
1583 std::vector<node_entry> nodes;
1584 table.find_node(nid, nodes, 0, 10);
1585 TEST_EQUAL(table.bucket_size(0), 1);
1586 TEST_EQUAL(std::get<0>(table.size()), 1);
1587 TEST_EQUAL(nodes.size(), 1);
1588 if (!nodes.empty())
1589 {
1590 TEST_EQUAL(nodes[0].id, tmp);
1591 TEST_EQUAL(nodes[0].addr(), node_addr);
1592 TEST_EQUAL(nodes[0].port(), 4);
1593 TEST_EQUAL(nodes[0].timeout_count, 0);
1594 }
1595
1596 // set timeout_count to 1
1597 table.node_failed(tmp, udp::endpoint(node_addr, 4));
1598
1599 nodes.clear();
1600 table.for_each_node(std::bind(node_push_back, &nodes, _1), nullptr);
1601 TEST_EQUAL(nodes.size(), 1);
1602 if (!nodes.empty())
1603 {
1604 TEST_EQUAL(nodes[0].id, tmp);
1605 TEST_EQUAL(nodes[0].addr(), node_addr);
1606 TEST_EQUAL(nodes[0].port(), 4);
1607 TEST_EQUAL(nodes[0].timeout_count, 1);
1608 }
1609
1610 // add the exact same node again, it should set the timeout_count to 0
1611 table.node_seen(tmp, udp::endpoint(node_addr, 4), 10);
1612 nodes.clear();
1613 table.for_each_node(std::bind(node_push_back, &nodes, _1), nullptr);
1614 TEST_EQUAL(nodes.size(), 1);
1615 if (!nodes.empty())
1616 {
1617 TEST_EQUAL(nodes[0].id, tmp);
1618 TEST_EQUAL(nodes[0].addr(), node_addr);
1619 TEST_EQUAL(nodes[0].port(), 4);
1620 TEST_EQUAL(nodes[0].timeout_count, 0);
1621 }
1622
1623 // test adding the same node ID again with a different IP (should be ignored)
1624 table.node_seen(tmp, udp::endpoint(node_addr, 5), 10);
1625 table.find_node(nid, nodes, 0, 10);
1626 TEST_EQUAL(table.bucket_size(0), 1);
1627 if (!nodes.empty())
1628 {
1629 TEST_EQUAL(nodes[0].id, tmp);
1630 TEST_EQUAL(nodes[0].addr(), node_addr);
1631 TEST_EQUAL(nodes[0].port(), 4);
1632 }
1633
1634 // test adding a node that ends up in the same bucket with an IP
1635 // very close to the current one (should be ignored)
1636 // if restrict_routing_ips == true
1637 table.node_seen(tmp, udp::endpoint(node_near_addr, 5), 10);
1638 table.find_node(nid, nodes, 0, 10);
1639 TEST_EQUAL(table.bucket_size(0), 1);
1640 if (!nodes.empty())
1641 {
1642 TEST_EQUAL(nodes[0].id, tmp);
1643 TEST_EQUAL(nodes[0].addr(), node_addr);
1644 TEST_EQUAL(nodes[0].port(), 4);
1645 }
1646
1647 // test adding the same IP:port again with a new node ID (should remove the node)
1648 {
1649 auto const id = generate_id_impl(node_addr, 2);
1650 table.node_seen(id, udp::endpoint(node_addr, 4), 10);
1651 table.find_node(id, nodes, 0, 10);
1652 }
1653 TEST_EQUAL(table.bucket_size(0), 0);
1654 TEST_EQUAL(nodes.size(), 0);
1655
1656 s.restrict_routing_ips = false;
1657
1658 {
1659 auto const ep = rand_udp_ep(rand_addr);
1660 auto const id = generate_id_impl(ep.address(), 2);
1661 table.node_seen(id, ep, 10);
1662 }
1663
1664 nodes.clear();
1665 for (int i = 0; i < 10000; ++i)
1666 {
1667 auto const ep = rand_udp_ep(rand_addr);
1668 auto const id = generate_id_impl(ep.address(), 6);
1669 table.node_seen(id, ep, 20 + (id[19] & 0xff));
1670 }
1671 std::printf("active buckets: %d\n", table.num_active_buckets());
1672 TEST_CHECK(table.num_active_buckets() == 11
1673 || table.num_active_buckets() == 12);
1674 TEST_CHECK(std::get<0>(table.size()) >= bucket_size * 10);
1675 //TODO: 2 test num_global_nodes
1676 //TODO: 2 test need_refresh
1677
1678 print_state(std::cout, table);
1679
1680 table.for_each_node(std::bind(node_push_back, &nodes, _1), nullptr);
1681
1682 std::printf("nodes: %d\n", int(nodes.size()));
1683
1684 std::vector<node_entry> temp;
1685
1686 {
1687 node_id const id = generate_random_id();
1688 table.find_node(id, temp, 0, int(nodes.size()) * 2);
1689 std::printf("returned-all: %d\n", int(temp.size()));
1690 TEST_EQUAL(temp.size(), nodes.size());
1691 }
1692
1693 // This makes sure enough of the nodes returned are actually
1694 // part of the closest nodes
1695 std::set<node_id> duplicates;
1696
1697 const int reps = 50;
1698
1699 for (int r = 0; r < reps; ++r)
1700 {
1701 node_id const id = generate_random_id();
1702 table.find_node(id, temp, 0, bucket_size * 2);
1703 TEST_EQUAL(int(temp.size()), std::min(bucket_size * 2, int(nodes.size())));
1704
1705 std::sort(nodes.begin(), nodes.end(), std::bind(&compare_ref
1706 , std::bind(&node_entry::id, _1)
1707 , std::bind(&node_entry::id, _2), id));
1708
1709 int expected = std::accumulate(nodes.begin(), nodes.begin() + int(temp.size())
1710 , 0, std::bind(&sum_distance_exp, _1, _2, id));
1711 int sum_hits = std::accumulate(temp.begin(), temp.end()
1712 , 0, std::bind(&sum_distance_exp, _1, _2, id));
1713 TEST_EQUAL(bucket_size * 2, int(temp.size()));
1714 TEST_EQUAL(expected, sum_hits);
1715
1716 duplicates.clear();
1717 // This makes sure enough of the nodes returned are actually
1718 // part of the closest nodes
1719 for (std::vector<node_entry>::iterator i = temp.begin()
1720 , end(temp.end()); i != end; ++i)
1721 {
1722 TEST_CHECK(duplicates.count(i->id) == 0);
1723 duplicates.insert(i->id);
1724 }
1725 }
1726
1727 char const* ips[] = {
1728 "124.31.75.21",
1729 "21.75.31.124",
1730 "65.23.51.170",
1731 "84.124.73.14",
1732 "43.213.53.83",
1733 };
1734
1735 int rs[] = { 1,86,22,65,90 };
1736
1737 std::uint8_t prefixes[][3] =
1738 {
1739 { 0x5f, 0xbf, 0xbf },
1740 { 0x5a, 0x3c, 0xe9 },
1741 { 0xa5, 0xd4, 0x32 },
1742 { 0x1b, 0x03, 0x21 },
1743 { 0xe5, 0x6f, 0x6c }
1744 };
1745
1746 for (int i = 0; i < 5; ++i)
1747 {
1748 address const a = addr4(ips[i]);
1749 node_id const new_id = generate_id_impl(a, std::uint32_t(rs[i]));
1750 TEST_CHECK(new_id[0] == prefixes[i][0]);
1751 TEST_CHECK(new_id[1] == prefixes[i][1]);
1752 TEST_CHECK((new_id[2] & 0xf8) == (prefixes[i][2] & 0xf8));
1753
1754 TEST_CHECK(new_id[19] == rs[i]);
1755 std::printf("IP address: %s r: %d node ID: %s\n", ips[i]
1756 , rs[i], aux::to_hex(new_id).c_str());
1757 }
1758 }
1759
1760 } // anonymous namespace
1761
TORRENT_TEST(routing_table_v4)1762 TORRENT_TEST(routing_table_v4)
1763 {
1764 test_routing_table(rand_v4);
1765 }
1766
TORRENT_TEST(routing_table_v6)1767 TORRENT_TEST(routing_table_v6)
1768 {
1769 if (supports_ipv6())
1770 test_routing_table(rand_v6);
1771 }
1772
1773 namespace {
1774
test_bootstrap(address (& rand_addr)())1775 void test_bootstrap(address(&rand_addr)())
1776 {
1777 dht_test_setup t(udp::endpoint(rand_addr(), 20));
1778 bdecode_node response;
1779 bool ret;
1780
1781 dht::key_desc_t const find_node_desc[] = {
1782 {"y", bdecode_node::string_t, 1, 0},
1783 {"t", bdecode_node::string_t, 2, 0},
1784 {"q", bdecode_node::string_t, 9, 0},
1785 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
1786 {"id", bdecode_node::string_t, 20, 0},
1787 {"target", bdecode_node::string_t, 20, key_desc_t::optional},
1788 {"info_hash", bdecode_node::string_t, 20, key_desc_t::optional | key_desc_t::last_child},
1789 };
1790
1791 bdecode_node find_node_keys[7];
1792
1793 // bootstrap
1794
1795 g_sent_packets.clear();
1796
1797 udp::endpoint initial_node(rand_addr(), 1234);
1798 std::vector<udp::endpoint> nodesv;
1799 nodesv.push_back(initial_node);
1800 t.dht_node.bootstrap(nodesv, std::bind(&nop_node));
1801
1802 TEST_EQUAL(g_sent_packets.size(), 1);
1803 if (g_sent_packets.empty()) return;
1804 TEST_EQUAL(g_sent_packets.front().first, initial_node);
1805
1806 node_from_entry(g_sent_packets.front().second, response);
1807 ret = verify_message(response, find_node_desc, find_node_keys, t.error_string);
1808 if (ret)
1809 {
1810 TEST_EQUAL(find_node_keys[0].string_value(), "q");
1811 TEST_CHECK(find_node_keys[2].string_value() == "find_node"
1812 || find_node_keys[2].string_value() == "get_peers");
1813
1814 if (find_node_keys[0].string_value() != "q"
1815 || (find_node_keys[2].string_value() != "find_node"
1816 && find_node_keys[2].string_value() != "get_peers")) return;
1817 }
1818 else
1819 {
1820 std::printf(" invalid find_node request: %s\n", print_entry(response).c_str());
1821 TEST_ERROR(t.error_string);
1822 return;
1823 }
1824
1825 udp::endpoint found_node(rand_addr(), 2235);
1826 std::vector<node_entry> nodes;
1827 nodes.push_back(node_entry{found_node});
1828 g_sent_packets.clear();
1829 if (is_v4(initial_node))
1830 send_dht_response(t.dht_node, response, initial_node, msg_args().nodes(nodes));
1831 else
1832 send_dht_response(t.dht_node, response, initial_node, msg_args().nodes6(nodes));
1833
1834 TEST_EQUAL(g_sent_packets.size(), 1);
1835 if (g_sent_packets.empty()) return;
1836 TEST_EQUAL(g_sent_packets.front().first, found_node);
1837
1838 node_from_entry(g_sent_packets.front().second, response);
1839 ret = verify_message(response, find_node_desc, find_node_keys, t.error_string);
1840 if (ret)
1841 {
1842 TEST_EQUAL(find_node_keys[0].string_value(), "q");
1843 TEST_CHECK(find_node_keys[2].string_value() == "find_node"
1844 || find_node_keys[2].string_value() == "get_peers");
1845 if (find_node_keys[0].string_value() != "q"
1846 || (find_node_keys[2].string_value() != "find_node"
1847 && find_node_keys[2].string_value() != "get_peers")) return;
1848 }
1849 else
1850 {
1851 std::printf(" invalid find_node request: %s\n", print_entry(response).c_str());
1852 TEST_ERROR(t.error_string);
1853 return;
1854 }
1855
1856 g_sent_packets.clear();
1857 send_dht_response(t.dht_node, response, found_node);
1858
1859 TEST_CHECK(g_sent_packets.empty());
1860 TEST_EQUAL(t.dht_node.num_global_nodes(), 3);
1861 }
1862
1863 } // anonymous namespace
1864
TORRENT_TEST(bootstrap_v4)1865 TORRENT_TEST(bootstrap_v4)
1866 {
1867 test_bootstrap(rand_v4);
1868 }
1869
TORRENT_TEST(bootstrap_v6)1870 TORRENT_TEST(bootstrap_v6)
1871 {
1872 if (supports_ipv6())
1873 test_bootstrap(rand_v6);
1874 }
1875
1876 namespace {
1877
test_bootstrap_want(address (& rand_addr)())1878 void test_bootstrap_want(address(&rand_addr)())
1879 {
1880 dht_test_setup t(udp::endpoint(rand_addr(), 20));
1881 bdecode_node response;
1882 bool ret;
1883
1884 dht::key_desc_t const find_node_desc[] = {
1885 {"y", bdecode_node::string_t, 1, 0},
1886 {"t", bdecode_node::string_t, 2, 0},
1887 {"q", bdecode_node::string_t, 9, 0},
1888 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
1889 {"id", bdecode_node::string_t, 20, 0},
1890 {"target", bdecode_node::string_t, 20, key_desc_t::optional},
1891 {"info_hash", bdecode_node::string_t, 20, key_desc_t::optional},
1892 {"want", bdecode_node::list_t, 0, key_desc_t::last_child},
1893 };
1894
1895 bdecode_node find_node_keys[8];
1896
1897 g_sent_packets.clear();
1898
1899 std::vector<udp::endpoint> nodesv;
1900 if (is_v4(t.source))
1901 nodesv.push_back(rand_udp_ep(rand_v6));
1902 else
1903 nodesv.push_back(rand_udp_ep(rand_v4));
1904
1905 t.dht_node.bootstrap(nodesv, std::bind(&nop_node));
1906
1907 TEST_EQUAL(g_sent_packets.size(), 1);
1908 TEST_EQUAL(g_sent_packets.front().first, nodesv[0]);
1909
1910 node_from_entry(g_sent_packets.front().second, response);
1911 ret = verify_message(response, find_node_desc, find_node_keys, t.error_string);
1912 if (ret)
1913 {
1914 TEST_EQUAL(find_node_keys[0].string_value(), "q");
1915 TEST_CHECK(find_node_keys[2].string_value() == "find_node"
1916 || find_node_keys[2].string_value() == "get_peers");
1917
1918 TEST_EQUAL(find_node_keys[7].list_size(), 1);
1919 if (is_v4(t.source))
1920 {
1921 TEST_EQUAL(find_node_keys[7].list_string_value_at(0), "n4");
1922 }
1923 else
1924 {
1925 TEST_EQUAL(find_node_keys[7].list_string_value_at(0), "n6");
1926 }
1927 }
1928 else
1929 {
1930 std::printf(" invalid find_node request: %s\n", print_entry(response).c_str());
1931 TEST_ERROR(t.error_string);
1932 }
1933 }
1934
1935 } // anonymous namespace
1936
TORRENT_TEST(bootstrap_want_v4)1937 TORRENT_TEST(bootstrap_want_v4)
1938 {
1939 test_bootstrap_want(rand_v4);
1940 }
1941
TORRENT_TEST(bootstrap_want_v6)1942 TORRENT_TEST(bootstrap_want_v6)
1943 {
1944 test_bootstrap_want(rand_v6);
1945 }
1946
1947 namespace {
1948
1949 // test that the node ignores a nodes entry which is too short
test_short_nodes(address (& rand_addr)())1950 void test_short_nodes(address(&rand_addr)())
1951 {
1952 dht_test_setup t(udp::endpoint(rand_addr(), 20));
1953 bdecode_node response;
1954 bool ret;
1955
1956 dht::key_desc_t const find_node_desc[] = {
1957 { "y", bdecode_node::string_t, 1, 0 },
1958 { "t", bdecode_node::string_t, 2, 0 },
1959 { "q", bdecode_node::string_t, 9, 0 },
1960 { "a", bdecode_node::dict_t, 0, key_desc_t::parse_children },
1961 { "id", bdecode_node::string_t, 20, 0 },
1962 { "target", bdecode_node::string_t, 20, key_desc_t::optional },
1963 { "info_hash", bdecode_node::string_t, 20, key_desc_t::optional | key_desc_t::last_child },
1964 };
1965
1966 bdecode_node find_node_keys[7];
1967
1968 // bootstrap
1969
1970 g_sent_packets.clear();
1971
1972 udp::endpoint initial_node(rand_addr(), 1234);
1973 std::vector<udp::endpoint> nodesv;
1974 nodesv.push_back(initial_node);
1975 t.dht_node.bootstrap(nodesv, std::bind(&nop_node));
1976
1977 TEST_EQUAL(g_sent_packets.size(), 1);
1978 if (g_sent_packets.empty()) return;
1979 TEST_EQUAL(g_sent_packets.front().first, initial_node);
1980
1981 node_from_entry(g_sent_packets.front().second, response);
1982 ret = verify_message(response, find_node_desc, find_node_keys, t.error_string);
1983 if (ret)
1984 {
1985 TEST_EQUAL(find_node_keys[0].string_value(), "q");
1986 TEST_CHECK(find_node_keys[2].string_value() == "find_node"
1987 || find_node_keys[2].string_value() == "get_peers");
1988
1989 if (find_node_keys[0].string_value() != "q"
1990 || (find_node_keys[2].string_value() != "find_node"
1991 && find_node_keys[2].string_value() != "get_peers")) return;
1992 }
1993 else
1994 {
1995 std::printf(" invalid find_node request: %s\n", print_entry(response).c_str());
1996 TEST_ERROR(t.error_string);
1997 return;
1998 }
1999
2000 udp::endpoint found_node(rand_addr(), 2235);
2001 std::vector<node_entry> nodes;
2002 nodes.push_back(node_entry{found_node});
2003 g_sent_packets.clear();
2004 msg_args args;
2005 // chop one byte off of the nodes string
2006 if (is_v4(initial_node))
2007 {
2008 args.nodes(nodes);
2009 args.a["nodes"] = args.a["nodes"].string().substr(1);
2010 }
2011 else
2012 {
2013 args.nodes6(nodes);
2014 args.a["nodes6"] = args.a["nodes6"].string().substr(1);
2015 }
2016
2017 send_dht_response(t.dht_node, response, initial_node, args);
2018
2019 TEST_EQUAL(g_sent_packets.size(), 0);
2020 }
2021
2022 } // anonymous namespace
2023
TORRENT_TEST(short_nodes_v4)2024 TORRENT_TEST(short_nodes_v4)
2025 {
2026 test_short_nodes(rand_v4);
2027 }
2028
TORRENT_TEST(short_nodes_v6)2029 TORRENT_TEST(short_nodes_v6)
2030 {
2031 if (supports_ipv6())
2032 test_short_nodes(rand_v6);
2033 }
2034
2035 namespace {
2036
test_get_peers(address (& rand_addr)())2037 void test_get_peers(address(&rand_addr)())
2038 {
2039 dht_test_setup t(udp::endpoint(rand_addr(), 20));
2040 bdecode_node response;
2041 bool ret;
2042
2043 dht::key_desc_t const get_peers_desc[] = {
2044 {"y", bdecode_node::string_t, 1, 0},
2045 {"t", bdecode_node::string_t, 2, 0},
2046 {"q", bdecode_node::string_t, 9, 0},
2047 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
2048 {"id", bdecode_node::string_t, 20, 0},
2049 {"info_hash", bdecode_node::string_t, 20, key_desc_t::last_child},
2050 };
2051
2052 bdecode_node get_peers_keys[6];
2053
2054 // get_peers
2055
2056 g_sent_packets.clear();
2057
2058 dht::node_id const target = to_hash("1234876923549721020394873245098347598635");
2059
2060 udp::endpoint const initial_node(rand_addr(), 1234);
2061 dht::node_id const initial_node_id = to_hash("1111111111222222222233333333334444444444");
2062 t.dht_node.m_table.add_node(node_entry{initial_node_id, initial_node, 10, true});
2063
2064 t.dht_node.announce(target, 1234, {}, get_peers_cb);
2065
2066 TEST_EQUAL(g_sent_packets.size(), 1);
2067 if (g_sent_packets.empty()) return;
2068 TEST_EQUAL(g_sent_packets.front().first, initial_node);
2069
2070 node_from_entry(g_sent_packets.front().second, response);
2071 ret = verify_message(response, get_peers_desc, get_peers_keys, t.error_string);
2072 if (ret)
2073 {
2074 TEST_EQUAL(get_peers_keys[0].string_value(), "q");
2075 TEST_EQUAL(get_peers_keys[2].string_value(), "get_peers");
2076 TEST_EQUAL(get_peers_keys[5].string_value(), target.to_string());
2077 if (get_peers_keys[0].string_value() != "q"
2078 || get_peers_keys[2].string_value() != "get_peers")
2079 return;
2080 }
2081 else
2082 {
2083 std::printf(" invalid get_peers request: %s\n", print_entry(response).c_str());
2084 TEST_ERROR(t.error_string);
2085 return;
2086 }
2087
2088 std::set<tcp::endpoint> peers[2];
2089 peers[0].insert(tcp::endpoint(rand_addr(), 4111));
2090 peers[0].insert(tcp::endpoint(rand_addr(), 4112));
2091 peers[0].insert(tcp::endpoint(rand_addr(), 4113));
2092
2093 udp::endpoint next_node(rand_addr(), 2235);
2094 std::vector<node_entry> nodes;
2095 nodes.push_back(node_entry{next_node});
2096
2097 g_sent_packets.clear();
2098 if (is_v4(initial_node))
2099 {
2100 send_dht_response(t.dht_node, response, initial_node
2101 , msg_args().nodes(nodes).token("10").port(1234).peers(peers[0]));
2102 }
2103 else
2104 {
2105 send_dht_response(t.dht_node, response, initial_node
2106 , msg_args().nodes6(nodes).token("10").port(1234).peers(peers[0]));
2107 }
2108
2109 TEST_EQUAL(g_sent_packets.size(), 1);
2110 if (g_sent_packets.empty()) return;
2111 TEST_EQUAL(g_sent_packets.front().first, next_node);
2112
2113 node_from_entry(g_sent_packets.front().second, response);
2114 ret = verify_message(response, get_peers_desc, get_peers_keys, t.error_string);
2115 if (ret)
2116 {
2117 TEST_EQUAL(get_peers_keys[0].string_value(), "q");
2118 TEST_EQUAL(get_peers_keys[2].string_value(), "get_peers");
2119 TEST_EQUAL(get_peers_keys[5].string_value(), target.to_string());
2120 if (get_peers_keys[0].string_value() != "q"
2121 || get_peers_keys[2].string_value() != "get_peers")
2122 return;
2123 }
2124 else
2125 {
2126 std::printf(" invalid get_peers request: %s\n", print_entry(response).c_str());
2127 TEST_ERROR(t.error_string);
2128 return;
2129 }
2130
2131 peers[1].insert(tcp::endpoint(rand_addr(), 4114));
2132 peers[1].insert(tcp::endpoint(rand_addr(), 4115));
2133 peers[1].insert(tcp::endpoint(rand_addr(), 4116));
2134
2135 g_sent_packets.clear();
2136 send_dht_response(t.dht_node, response, next_node
2137 , msg_args().token("11").port(1234).peers(peers[1]));
2138
2139 for (auto const& p : g_sent_packets)
2140 {
2141 // std::printf(" %s:%d: %s\n", i->first.address().to_string(ec).c_str()
2142 // , i->first.port(), i->second.to_string().c_str());
2143 TEST_EQUAL(p.second["q"].string(), "announce_peer");
2144 }
2145
2146 g_sent_packets.clear();
2147
2148 for (int i = 0; i < 2; ++i)
2149 {
2150 for (auto const& peer : peers[i])
2151 {
2152 TEST_CHECK(std::find(g_got_peers.begin(), g_got_peers.end(), peer) != g_got_peers.end());
2153 }
2154 }
2155 g_got_peers.clear();
2156 }
2157
2158 } // anonymous namespace
2159
TORRENT_TEST(get_peers_v4)2160 TORRENT_TEST(get_peers_v4)
2161 {
2162 test_get_peers(rand_v4);
2163 }
2164
TORRENT_TEST(get_peers_v6)2165 TORRENT_TEST(get_peers_v6)
2166 {
2167 if (supports_ipv6())
2168 test_get_peers(rand_v6);
2169 }
2170
2171 namespace {
2172
2173 // TODO: 4 pass in th actual salt as the argument
test_mutable_get(address (& rand_addr)(),bool const with_salt)2174 void test_mutable_get(address(&rand_addr)(), bool const with_salt)
2175 {
2176 dht_test_setup t(udp::endpoint(rand_addr(), 20));
2177
2178 public_key pk;
2179 secret_key sk;
2180 get_test_keypair(pk, sk);
2181
2182 char buffer[1200];
2183 sequence_number seq(4);
2184 span<char const> itemv;
2185 bdecode_node response;
2186
2187 std::string salt;
2188 if (with_salt) salt = "foobar";
2189
2190 // mutable get
2191
2192 g_sent_packets.clear();
2193
2194 udp::endpoint const initial_node(rand_addr(), 1234);
2195 dht::node_id const initial_node_id = to_hash("1111111111222222222233333333334444444444");
2196 t.dht_node.m_table.add_node(node_entry{initial_node_id, initial_node, 10, true});
2197
2198 g_put_item.assign(items[0].ent, salt, seq, pk, sk);
2199 t.dht_node.put_item(pk, std::string()
2200 , std::bind(&put_mutable_item_cb, _1, _2, 0)
2201 , put_mutable_item_data_cb);
2202
2203 TEST_EQUAL(g_sent_packets.size(), 1);
2204
2205 // mutable_get
2206
2207 g_sent_packets.clear();
2208
2209 t.dht_node.get_item(pk, salt, get_mutable_item_cb);
2210
2211 TEST_EQUAL(g_sent_packets.size(), 1);
2212 if (g_sent_packets.empty()) return;
2213 TEST_EQUAL(g_sent_packets.front().first, initial_node);
2214
2215 node_from_entry(g_sent_packets.front().second, response);
2216 bdecode_node get_item_keys[6];
2217 bool const ret = verify_message(response, get_item_desc, get_item_keys, t.error_string);
2218 if (ret)
2219 {
2220 TEST_EQUAL(get_item_keys[0].string_value(), "q");
2221 TEST_EQUAL(get_item_keys[2].string_value(), "get");
2222 if (get_item_keys[0].string_value() != "q"
2223 || get_item_keys[2].string_value() != "get")
2224 return;
2225 }
2226 else
2227 {
2228 std::printf(" invalid get request: %s\n", print_entry(response).c_str());
2229 TEST_ERROR(t.error_string);
2230 return;
2231 }
2232
2233 g_sent_packets.clear();
2234
2235 signature sig;
2236 itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
2237 sig = sign_mutable_item(itemv, salt, seq, pk, sk);
2238 send_dht_response(t.dht_node, response, initial_node
2239 , msg_args()
2240 .token("10")
2241 .port(1234)
2242 .value(items[0].ent)
2243 .key(pk)
2244 .sig(sig)
2245 .salt(salt)
2246 .seq(seq));
2247
2248 TEST_CHECK(g_sent_packets.empty());
2249 TEST_EQUAL(g_got_items.size(), 1);
2250 if (g_got_items.empty()) return;
2251
2252 TEST_EQUAL(g_got_items.front().value(), items[0].ent);
2253 TEST_CHECK(g_got_items.front().pk() == pk);
2254 TEST_CHECK(g_got_items.front().sig() == sig);
2255 TEST_CHECK(g_got_items.front().seq() == seq);
2256 g_got_items.clear();
2257 }
2258
2259 } // anonymous namespace
2260
TORRENT_TEST(mutable_get_v4)2261 TORRENT_TEST(mutable_get_v4)
2262 {
2263 test_mutable_get(rand_v4, false);
2264 }
2265
TORRENT_TEST(mutable_get_salt_v4)2266 TORRENT_TEST(mutable_get_salt_v4)
2267 {
2268 test_mutable_get(rand_v4, true);
2269 }
2270
TORRENT_TEST(mutable_get_v6)2271 TORRENT_TEST(mutable_get_v6)
2272 {
2273 if (supports_ipv6())
2274 test_mutable_get(rand_v6, false);
2275 }
2276
TORRENT_TEST(mutable_get_salt_v6)2277 TORRENT_TEST(mutable_get_salt_v6)
2278 {
2279 if (supports_ipv6())
2280 test_mutable_get(rand_v6, true);
2281 }
2282
TORRENT_TEST(immutable_get)2283 TORRENT_TEST(immutable_get)
2284 {
2285 dht_test_setup t(udp::endpoint(rand_v4(), 20));
2286 bdecode_node response;
2287
2288 // immutable get
2289
2290 g_sent_packets.clear();
2291
2292 udp::endpoint initial_node(addr4("4.4.4.4"), 1234);
2293 dht::node_id const initial_node_id = to_hash("1111111111222222222233333333334444444444");
2294 t.dht_node.m_table.add_node(node_entry{initial_node_id, initial_node, 10, true});
2295
2296 t.dht_node.get_item(items[0].target, get_immutable_item_cb);
2297
2298 TEST_EQUAL(g_sent_packets.size(), 1);
2299 if (g_sent_packets.empty()) return;
2300 TEST_EQUAL(g_sent_packets.front().first, initial_node);
2301
2302 node_from_entry(g_sent_packets.front().second, response);
2303 bdecode_node get_item_keys[6];
2304 bool const ret = verify_message(response, get_item_desc, get_item_keys, t.error_string);
2305 if (ret)
2306 {
2307 TEST_EQUAL(get_item_keys[0].string_value(), "q");
2308 TEST_EQUAL(get_item_keys[2].string_value(), "get");
2309 TEST_EQUAL(get_item_keys[5].string_value(), items[0].target.to_string());
2310 if (get_item_keys[0].string_value() != "q" || get_item_keys[2].string_value() != "get") return;
2311 }
2312 else
2313 {
2314 std::printf(" invalid get request: %s\n", print_entry(response).c_str());
2315 TEST_ERROR(t.error_string);
2316 return;
2317 }
2318
2319 g_sent_packets.clear();
2320 send_dht_response(t.dht_node, response, initial_node
2321 , msg_args().token("10").port(1234).value(items[0].ent));
2322
2323 TEST_CHECK(g_sent_packets.empty());
2324 TEST_EQUAL(g_got_items.size(), 1);
2325 if (g_got_items.empty()) return;
2326
2327 TEST_EQUAL(g_got_items.front().value(), items[0].ent);
2328 g_got_items.clear();
2329 }
2330
TORRENT_TEST(immutable_put)2331 TORRENT_TEST(immutable_put)
2332 {
2333 bdecode_node response;
2334 span<char const> itemv;
2335 char buffer[1200];
2336
2337 dht::key_desc_t const put_immutable_item_desc[] = {
2338 {"y", bdecode_node::string_t, 1, 0},
2339 {"t", bdecode_node::string_t, 2, 0},
2340 {"q", bdecode_node::string_t, 3, 0},
2341 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
2342 {"id", bdecode_node::string_t, 20, 0},
2343 {"token", bdecode_node::string_t, 2, 0},
2344 {"v", bdecode_node::none_t, 0, key_desc_t::last_child},
2345 };
2346
2347 bdecode_node put_immutable_item_keys[7];
2348
2349 // immutable put
2350 g_sent_packets.clear();
2351 for (int loop = 0; loop < 9; loop++)
2352 {
2353 dht_test_setup t(udp::endpoint(rand_v4(), 20));
2354
2355 // set the branching factor to k to make this a little easier
2356 t.sett.search_branching = 8;
2357
2358 lt::aux::array<node_entry, 8> const nodes = build_nodes();
2359
2360 for (node_entry const& n : nodes)
2361 t.dht_node.m_table.add_node(n);
2362
2363 entry put_data;
2364 put_data = "Hello world";
2365 std::string flat_data;
2366 bencode(std::back_inserter(flat_data), put_data);
2367 sha1_hash target = item_target_id(flat_data);
2368
2369 t.dht_node.put_item(target, put_data, std::bind(&put_immutable_item_cb, _1, loop));
2370
2371 TEST_EQUAL(g_sent_packets.size(), 8);
2372 if (g_sent_packets.size() != 8) break;
2373
2374 int idx = -1;
2375 for (auto& node : nodes)
2376 {
2377 ++idx;
2378 auto const packet = find_packet(node.ep());
2379 TEST_CHECK(packet != g_sent_packets.end());
2380 if (packet == g_sent_packets.end()) continue;
2381
2382 node_from_entry(packet->second, response);
2383 bdecode_node get_item_keys[6];
2384 bool const ret = verify_message(response, get_item_desc, get_item_keys, t.error_string);
2385 if (!ret)
2386 {
2387 std::printf(" invalid get request: %s\n", print_entry(response).c_str());
2388 TEST_ERROR(t.error_string);
2389 continue;
2390 }
2391 char tok[11];
2392 std::snprintf(tok, sizeof(tok), "%02d", idx);
2393
2394 msg_args args;
2395 args.token(tok).port(1234).nid(node.id).nodes({node});
2396 send_dht_response(t.dht_node, response, node.ep(), args);
2397 g_sent_packets.erase(packet);
2398 }
2399
2400 TEST_EQUAL(g_sent_packets.size(), 8);
2401 if (g_sent_packets.size() != 8) break;
2402
2403 itemv = span<char const>(buffer, bencode(buffer, put_data));
2404
2405 idx = -1;
2406 for (auto& node : nodes)
2407 {
2408 ++idx;
2409 auto const packet = find_packet(node.ep());
2410 TEST_CHECK(packet != g_sent_packets.end());
2411 if (packet == g_sent_packets.end()) continue;
2412
2413 node_from_entry(packet->second, response);
2414 bool const ret = verify_message(response, put_immutable_item_desc, put_immutable_item_keys
2415 , t.error_string);
2416 if (ret)
2417 {
2418 TEST_EQUAL(put_immutable_item_keys[0].string_value(), "q");
2419 TEST_EQUAL(put_immutable_item_keys[2].string_value(), "put");
2420 span<const char> const v = put_immutable_item_keys[6].data_section();
2421 TEST_EQUAL(v, span<char const>(flat_data));
2422 char tok[11];
2423 std::snprintf(tok, sizeof(tok), "%02d", idx);
2424 TEST_EQUAL(put_immutable_item_keys[5].string_value(), tok);
2425 if (put_immutable_item_keys[0].string_value() != "q"
2426 || put_immutable_item_keys[2].string_value() != "put") continue;
2427
2428 if (idx < loop) send_dht_response(t.dht_node, response, node.ep());
2429 }
2430 else
2431 {
2432 std::printf(" invalid immutable put request: %s\n", print_entry(response).c_str());
2433 TEST_ERROR(t.error_string);
2434 continue;
2435 }
2436 }
2437 g_sent_packets.clear();
2438 g_put_item.clear();
2439 g_put_count = 0;
2440 }
2441 }
2442
TORRENT_TEST(mutable_put)2443 TORRENT_TEST(mutable_put)
2444 {
2445 bdecode_node response;
2446 span<char const> itemv;
2447 char buffer[1200];
2448 bdecode_node put_mutable_item_keys[11];
2449 public_key pk;
2450 secret_key sk;
2451 get_test_keypair(pk, sk);
2452
2453 sequence_number seq(4);
2454
2455 // mutable put
2456 g_sent_packets.clear();
2457 for (int loop = 0; loop < 9; loop++)
2458 {
2459 dht_test_setup t(udp::endpoint(rand_v4(), 20));
2460
2461 // set the branching factor to k to make this a little easier
2462 t.sett.search_branching = 8;
2463
2464 enum { num_test_nodes = 8 };
2465 lt::aux::array<node_entry, num_test_nodes> const nodes = build_nodes();
2466
2467 for (auto const& n : nodes)
2468 t.dht_node.m_table.add_node(n);
2469
2470 g_put_item.assign(items[0].ent, empty_salt, seq, pk, sk);
2471 signature const sig = g_put_item.sig();
2472 t.dht_node.put_item(pk, std::string()
2473 , std::bind(&put_mutable_item_cb, _1, _2, loop)
2474 , put_mutable_item_data_cb);
2475
2476 TEST_EQUAL(g_sent_packets.size(), 8);
2477 if (g_sent_packets.size() != 8) break;
2478
2479 int idx = -1;
2480 for (auto& node : nodes)
2481 {
2482 ++idx;
2483 auto const packet = find_packet(node.ep());
2484 TEST_CHECK(packet != g_sent_packets.end());
2485 if (packet == g_sent_packets.end()) continue;
2486
2487 node_from_entry(packet->second, response);
2488 bdecode_node get_item_keys[6];
2489 bool const ret = verify_message(response, get_item_desc, get_item_keys, t.error_string);
2490 if (!ret)
2491 {
2492 std::printf(" invalid get request: %s\n", print_entry(response).c_str());
2493 TEST_ERROR(t.error_string);
2494 continue;
2495 }
2496 char tok[11];
2497 std::snprintf(tok, sizeof(tok), "%02d", idx);
2498
2499 msg_args args;
2500 args.token(tok).port(1234).nid(node.id).nodes({node});
2501 send_dht_response(t.dht_node, response, node.ep(), args);
2502 g_sent_packets.erase(packet);
2503 }
2504
2505 TEST_EQUAL(g_sent_packets.size(), 8);
2506 if (g_sent_packets.size() != 8) break;
2507
2508 itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
2509
2510 idx = -1;
2511 for (auto& node : nodes)
2512 {
2513 ++idx;
2514 auto const packet = find_packet(node.ep());
2515 TEST_CHECK(packet != g_sent_packets.end());
2516 if (packet == g_sent_packets.end()) continue;
2517
2518 node_from_entry(packet->second, response);
2519 bool const ret = verify_message(response, put_mutable_item_desc, put_mutable_item_keys
2520 , t.error_string);
2521 if (ret)
2522 {
2523 TEST_EQUAL(put_mutable_item_keys[0].string_value(), "q");
2524 TEST_EQUAL(put_mutable_item_keys[2].string_value(), "put");
2525 TEST_EQUAL(put_mutable_item_keys[6].string_value()
2526 , std::string(pk.bytes.data(), public_key::len));
2527 TEST_EQUAL(put_mutable_item_keys[7].int_value(), int(seq.value));
2528 TEST_EQUAL(put_mutable_item_keys[8].string_value()
2529 , std::string(sig.bytes.data(), signature::len));
2530 span<const char> const v = put_mutable_item_keys[10].data_section();
2531 TEST_CHECK(v == itemv);
2532 char tok[11];
2533 std::snprintf(tok, sizeof(tok), "%02d", idx);
2534 TEST_EQUAL(put_mutable_item_keys[9].string_value(), tok);
2535 if (put_mutable_item_keys[0].string_value() != "q"
2536 || put_mutable_item_keys[2].string_value() != "put") continue;
2537
2538 if (idx < loop) send_dht_response(t.dht_node, response, node.ep());
2539 }
2540 else
2541 {
2542 std::printf(" invalid put request: %s\n", print_entry(response).c_str());
2543 TEST_ERROR(t.error_string);
2544 continue;
2545 }
2546 }
2547 g_sent_packets.clear();
2548 g_put_item.clear();
2549 g_put_count = 0;
2550 }
2551 }
2552
TORRENT_TEST(traversal_done)2553 TORRENT_TEST(traversal_done)
2554 {
2555 dht_test_setup t(udp::endpoint(rand_v4(), 20));
2556
2557 // set the branching factor to k to make this a little easier
2558 t.sett.search_branching = 8;
2559
2560 public_key pk;
2561 secret_key sk;
2562 get_test_keypair(pk, sk);
2563
2564 sequence_number seq(4);
2565 bdecode_node response;
2566
2567 // verify that done() is only invoked once
2568 // See PR 252
2569 g_sent_packets.clear();
2570
2571 sha1_hash const target = hasher(pk.bytes).final();
2572 constexpr int num_test_nodes = 9; // we need K + 1 nodes to create the failing sequence
2573
2574 lt::aux::array<node_entry, num_test_nodes> nodes = build_nodes(target);
2575
2576 // invert the ith most significant byte so that the test nodes are
2577 // progressively closer to the target item
2578 for (int i = 0; i < num_test_nodes; ++i)
2579 nodes[i].id[i] = static_cast<std::uint8_t>(~nodes[i].id[i]);
2580
2581 // add the first k nodes to the subject's routing table
2582 for (int i = 0; i < 8; ++i)
2583 t.dht_node.m_table.add_node(nodes[i]);
2584
2585 // kick off a mutable put request
2586 g_put_item.assign(items[0].ent, empty_salt, seq, pk, sk);
2587 t.dht_node.put_item(pk, std::string()
2588 , std::bind(&put_mutable_item_cb, _1, _2, 0)
2589 , put_mutable_item_data_cb);
2590 TEST_EQUAL(g_sent_packets.size(), 8);
2591 if (g_sent_packets.size() != 8) return;
2592
2593 // first send responses for the k closest nodes
2594 for (int i = 1;; ++i)
2595 {
2596 // once the k closest nodes have responded, send the final response
2597 // from the farthest node, this shouldn't trigger a second call to
2598 // get_item_cb
2599 if (i == num_test_nodes) i = 0;
2600
2601 auto const packet = find_packet(nodes[i].ep());
2602 TEST_CHECK(packet != g_sent_packets.end());
2603 if (packet == g_sent_packets.end()) continue;
2604
2605 node_from_entry(packet->second, response);
2606 bdecode_node get_item_keys[6];
2607 bool const ret = verify_message(response, get_item_desc, get_item_keys, t.error_string);
2608 if (!ret)
2609 {
2610 std::printf(" invalid get request: %s\n", print_entry(response).c_str());
2611 TEST_ERROR(t.error_string);
2612 continue;
2613 }
2614 char tok[11];
2615 std::snprintf(tok, sizeof(tok), "%02d", i);
2616
2617 msg_args args;
2618 args.token(tok).port(1234).nid(nodes[i].id);
2619
2620 // add the address of the closest node to the first response
2621 if (i == 1)
2622 args.nodes({nodes[8]});
2623
2624 send_dht_response(t.dht_node, response, nodes[i].ep(), args);
2625 g_sent_packets.erase(packet);
2626
2627 // once we've sent the response from the farthest node, we're done
2628 if (i == 0) break;
2629 }
2630
2631 TEST_EQUAL(g_put_count, 1);
2632 // k nodes should now have outstanding put requests
2633 TEST_EQUAL(g_sent_packets.size(), 8);
2634
2635 g_sent_packets.clear();
2636 g_put_item.clear();
2637 g_put_count = 0;
2638 }
2639
TORRENT_TEST(dht_dual_stack)2640 TORRENT_TEST(dht_dual_stack)
2641 {
2642 // TODO: 3 use dht_test_setup class to simplify the node setup
2643 dht::settings sett = test_settings();
2644 mock_socket s;
2645 auto sock4 = dummy_listen_socket4();
2646 auto sock6 = dummy_listen_socket6();
2647 obs observer;
2648 counters cnt;
2649 node* node4p = nullptr, *node6p = nullptr;
2650 auto get_foreign_node = [&](node_id const&, std::string const& family)
2651 {
2652 if (family == "n4") return node4p;
2653 if (family == "n6") return node6p;
2654 TEST_CHECK(false);
2655 return static_cast<node*>(nullptr);
2656 };
2657 std::unique_ptr<dht_storage_interface> dht_storage(dht_default_storage_constructor(sett));
2658 dht_storage->update_node_ids({node_id(nullptr)});
2659 dht::node node4(sock4, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node, *dht_storage);
2660 dht::node node6(sock6, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node, *dht_storage);
2661 node4p = &node4;
2662 node6p = &node6;
2663
2664 // DHT should be running on port 48199 now
2665 bdecode_node response;
2666 char error_string[200];
2667 bool ret;
2668
2669 node_id id = to_hash("3123456789abcdef01232456789abcdef0123456");
2670 node4.m_table.node_seen(id, udp::endpoint(addr("4.4.4.4"), 4440), 10);
2671 node6.m_table.node_seen(id, udp::endpoint(addr("4::4"), 4441), 10);
2672
2673 // v4 node requesting v6 nodes
2674
2675 udp::endpoint source(addr("10.0.0.1"), 20);
2676
2677 send_dht_request(node4, "find_node", source, &response
2678 , msg_args()
2679 .target(sha1_hash("0101010101010101010101010101010101010101"))
2680 .want("n6"));
2681
2682 dht::key_desc_t const nodes6_desc[] = {
2683 { "y", bdecode_node::string_t, 1, 0 },
2684 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
2685 { "id", bdecode_node::string_t, 20, 0 },
2686 { "nodes6", bdecode_node::string_t, 38, key_desc_t::last_child }
2687 };
2688
2689 bdecode_node nodes6_keys[4];
2690
2691 ret = verify_message(response, nodes6_desc, nodes6_keys, error_string);
2692
2693 if (ret)
2694 {
2695 char const* nodes_ptr = nodes6_keys[3].string_ptr();
2696 TEST_CHECK(memcmp(nodes_ptr, id.data(), id.size()) == 0);
2697 nodes_ptr += id.size();
2698 udp::endpoint rep = detail::read_v6_endpoint<udp::endpoint>(nodes_ptr);
2699 TEST_EQUAL(rep, udp::endpoint(addr("4::4"), 4441));
2700 }
2701 else
2702 {
2703 std::printf("find_node response: %s\n", print_entry(response).c_str());
2704 TEST_ERROR(error_string);
2705 }
2706
2707 // v6 node requesting v4 nodes
2708
2709 source.address(addr("10::1"));
2710
2711 send_dht_request(node6, "get_peers", source, &response
2712 , msg_args().info_hash("0101010101010101010101010101010101010101").want("n4"));
2713
2714 dht::key_desc_t const nodes_desc[] = {
2715 { "y", bdecode_node::string_t, 1, 0 },
2716 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
2717 { "id", bdecode_node::string_t, 20, 0 },
2718 { "nodes", bdecode_node::string_t, 26, key_desc_t::last_child }
2719 };
2720
2721 bdecode_node nodes_keys[4];
2722
2723 ret = verify_message(response, nodes_desc, nodes_keys, error_string);
2724
2725 if (ret)
2726 {
2727 char const* nodes_ptr = nodes_keys[3].string_ptr();
2728 TEST_CHECK(memcmp(nodes_ptr, id.data(), id.size()) == 0);
2729 nodes_ptr += id.size();
2730 udp::endpoint rep = detail::read_v4_endpoint<udp::endpoint>(nodes_ptr);
2731 TEST_EQUAL(rep, udp::endpoint(addr("4.4.4.4"), 4440));
2732 }
2733 else
2734 {
2735 std::printf("find_node response: %s\n", print_entry(response).c_str());
2736 TEST_ERROR(error_string);
2737 }
2738
2739 // v6 node requesting both v4 and v6 nodes
2740
2741 send_dht_request(node6, "find_node", source, &response
2742 , msg_args().target(sha1_hash("0101010101010101010101010101010101010101"))
2743 .want("n4")
2744 .want("n6"));
2745
2746 dht::key_desc_t const nodes46_desc[] = {
2747 { "y", bdecode_node::string_t, 1, 0 },
2748 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
2749 { "id", bdecode_node::string_t, 20, 0 },
2750 { "nodes", bdecode_node::string_t, 26, 0 },
2751 { "nodes6", bdecode_node::string_t, 38, key_desc_t::last_child }
2752 };
2753
2754 bdecode_node nodes46_keys[5];
2755
2756 ret = verify_message(response, nodes46_desc, nodes46_keys, error_string);
2757
2758 if (ret)
2759 {
2760 char const* nodes_ptr = nodes46_keys[3].string_ptr();
2761 TEST_CHECK(memcmp(nodes_ptr, id.data(), id.size()) == 0);
2762 nodes_ptr += id.size();
2763 udp::endpoint rep = detail::read_v4_endpoint<udp::endpoint>(nodes_ptr);
2764 TEST_EQUAL(rep, udp::endpoint(addr("4.4.4.4"), 4440));
2765
2766 nodes_ptr = nodes46_keys[4].string_ptr();
2767 TEST_CHECK(memcmp(nodes_ptr, id.data(), id.size()) == 0);
2768 nodes_ptr += id.size();
2769 rep = detail::read_v6_endpoint<udp::endpoint>(nodes_ptr);
2770 TEST_EQUAL(rep, udp::endpoint(addr("4::4"), 4441));
2771 }
2772 else
2773 {
2774 std::printf("find_node response: %s\n", print_entry(response).c_str());
2775 TEST_ERROR(error_string);
2776 }
2777 }
2778
TORRENT_TEST(multi_home)2779 TORRENT_TEST(multi_home)
2780 {
2781 // send a request with a different listen socket and make sure the node ignores it
2782 dht_test_setup t(udp::endpoint(rand_v4(), 20));
2783 bdecode_node response;
2784
2785 entry e;
2786 e["q"] = "ping";
2787 e["t"] = "10";
2788 e["y"] = "q";
2789 e["a"].dict().insert(std::make_pair("id", generate_next().to_string()));
2790 char msg_buf[1500];
2791 int size = bencode(msg_buf, e);
2792
2793 bdecode_node decoded;
2794 error_code ec;
2795 bdecode(msg_buf, msg_buf + size, decoded, ec);
2796 if (ec) std::printf("bdecode failed: %s\n", ec.message().c_str());
2797
2798 dht::msg m(decoded, t.source);
2799 t.dht_node.incoming(dummy_listen_socket(udp::endpoint(rand_v4(), 21)), m);
2800 TEST_CHECK(g_sent_packets.empty());
2801 g_sent_packets.clear();
2802 }
2803
TORRENT_TEST(signing_test1)2804 TORRENT_TEST(signing_test1)
2805 {
2806 // test vector 1
2807
2808 // test content
2809 span<char const> test_content("12:Hello World!", 15);
2810 // test salt
2811 span<char const> test_salt("foobar", 6);
2812
2813 public_key pk;
2814 secret_key sk;
2815 get_test_keypair(pk, sk);
2816
2817 signature sig;
2818 sig = sign_mutable_item(test_content, empty_salt, sequence_number(1), pk, sk);
2819
2820 TEST_EQUAL(aux::to_hex(sig.bytes)
2821 , "305ac8aeb6c9c151fa120f120ea2cfb923564e11552d06a5d856091e5e853cff"
2822 "1260d3f39e4999684aa92eb73ffd136e6f4f3ecbfda0ce53a1608ecd7ae21f01");
2823
2824 sha1_hash const target_id = item_target_id(empty_salt, pk);
2825 TEST_EQUAL(aux::to_hex(target_id), "4a533d47ec9c7d95b1ad75f576cffc641853b750");
2826 }
2827
TORRENT_TEST(signing_test2)2828 TORRENT_TEST(signing_test2)
2829 {
2830 public_key pk;
2831 secret_key sk;
2832 get_test_keypair(pk, sk);
2833
2834 // test content
2835 span<char const> test_content("12:Hello World!", 15);
2836
2837 signature sig;
2838 // test salt
2839 span<char const> test_salt("foobar", 6);
2840
2841 // test vector 2 (the keypair is the same as test 1)
2842 sig = sign_mutable_item(test_content, test_salt, sequence_number(1), pk, sk);
2843
2844 TEST_EQUAL(aux::to_hex(sig.bytes)
2845 , "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17d"
2846 "df9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08");
2847
2848 sha1_hash target_id = item_target_id(test_salt, pk);
2849 TEST_EQUAL(aux::to_hex(target_id), "411eba73b6f087ca51a3795d9c8c938d365e32c1");
2850 }
2851
TORRENT_TEST(signing_test3)2852 TORRENT_TEST(signing_test3)
2853 {
2854 // test vector 3
2855
2856 // test content
2857 span<char const> test_content("12:Hello World!", 15);
2858
2859 sha1_hash target_id = item_target_id(test_content);
2860 TEST_EQUAL(aux::to_hex(target_id), "e5f96f6f38320f0f33959cb4d3d656452117aadb");
2861 }
2862
2863 // TODO: 2 split this up into smaller test cases
TORRENT_TEST(verify_message)2864 TORRENT_TEST(verify_message)
2865 {
2866 char error_string[200];
2867
2868 // test verify_message
2869 static const key_desc_t msg_desc[] = {
2870 {"A", bdecode_node::string_t, 4, 0},
2871 {"B", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children},
2872 {"B1", bdecode_node::string_t, 0, 0},
2873 {"B2", bdecode_node::string_t, 0, key_desc_t::last_child},
2874 {"C", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children},
2875 {"C1", bdecode_node::string_t, 0, 0},
2876 {"C2", bdecode_node::string_t, 0, key_desc_t::last_child},
2877 };
2878
2879 bdecode_node msg_keys[7];
2880
2881 bdecode_node ent;
2882
2883 error_code ec;
2884 char const test_msg[] = "d1:A4:test1:Bd2:B15:test22:B25:test3ee";
2885 bdecode(test_msg, test_msg + sizeof(test_msg)-1, ent, ec);
2886 std::printf("%s\n", print_entry(ent).c_str());
2887
2888 bool ret = verify_message(ent, msg_desc, msg_keys, error_string);
2889 TEST_CHECK(ret);
2890 TEST_CHECK(msg_keys[0]);
2891 if (msg_keys[0]) TEST_EQUAL(msg_keys[0].string_value(), "test");
2892 TEST_CHECK(msg_keys[1]);
2893 TEST_CHECK(msg_keys[2]);
2894 if (msg_keys[2]) TEST_EQUAL(msg_keys[2].string_value(), "test2");
2895 TEST_CHECK(msg_keys[3]);
2896 if (msg_keys[3]) TEST_EQUAL(msg_keys[3].string_value(), "test3");
2897 TEST_CHECK(!msg_keys[4]);
2898 TEST_CHECK(!msg_keys[5]);
2899 TEST_CHECK(!msg_keys[6]);
2900
2901 char const test_msg2[] = "d1:A4:test1:Cd2:C15:test22:C25:test3ee";
2902 bdecode(test_msg2, test_msg2 + sizeof(test_msg2)-1, ent, ec);
2903 std::printf("%s\n", print_entry(ent).c_str());
2904
2905 ret = verify_message(ent, msg_desc, msg_keys, error_string);
2906 TEST_CHECK(ret);
2907 TEST_CHECK(msg_keys[0]);
2908 if (msg_keys[0]) TEST_EQUAL(msg_keys[0].string_value(), "test");
2909 TEST_CHECK(!msg_keys[1]);
2910 TEST_CHECK(!msg_keys[2]);
2911 TEST_CHECK(!msg_keys[3]);
2912 TEST_CHECK(msg_keys[4]);
2913 TEST_CHECK(msg_keys[5]);
2914 if (msg_keys[5]) TEST_EQUAL(msg_keys[5].string_value(), "test2");
2915 TEST_CHECK(msg_keys[6]);
2916 if (msg_keys[6]) TEST_EQUAL(msg_keys[6].string_value(), "test3");
2917
2918
2919 char const test_msg3[] = "d1:Cd2:C15:test22:C25:test3ee";
2920 bdecode(test_msg3, test_msg3 + sizeof(test_msg3)-1, ent, ec);
2921 std::printf("%s\n", print_entry(ent).c_str());
2922
2923 ret = verify_message(ent, msg_desc, msg_keys, error_string);
2924 TEST_CHECK(!ret);
2925 std::printf("%s\n", error_string);
2926 TEST_EQUAL(error_string, std::string("missing 'A' key"));
2927
2928 char const test_msg4[] = "d1:A6:foobare";
2929 bdecode(test_msg4, test_msg4 + sizeof(test_msg4)-1, ent, ec);
2930 std::printf("%s\n", print_entry(ent).c_str());
2931
2932 ret = verify_message(ent, msg_desc, msg_keys, error_string);
2933 TEST_CHECK(!ret);
2934 std::printf("%s\n", error_string);
2935 TEST_EQUAL(error_string, std::string("invalid value for 'A'"));
2936
2937 char const test_msg5[] = "d1:A4:test1:Cd2:C15:test2ee";
2938 bdecode(test_msg5, test_msg5 + sizeof(test_msg5)-1, ent, ec);
2939 std::printf("%s\n", print_entry(ent).c_str());
2940
2941 ret = verify_message(ent, msg_desc, msg_keys, error_string);
2942 TEST_CHECK(!ret);
2943 std::printf("%s\n", error_string);
2944 TEST_EQUAL(error_string, std::string("missing 'C2' key"));
2945
2946 // test empty strings [ { "":1 }, "" ]
2947 char const test_msg6[] = "ld0:i1ee0:e";
2948 bdecode(test_msg6, test_msg6 + sizeof(test_msg6)-1, ent, ec);
2949 std::printf("%s\n", print_entry(ent).c_str());
2950 TEST_CHECK(ent.type() == bdecode_node::list_t);
2951 if (ent.type() == bdecode_node::list_t)
2952 {
2953 TEST_CHECK(ent.list_size() == 2);
2954 if (ent.list_size() == 2)
2955 {
2956 TEST_CHECK(ent.list_at(0).dict_find_int_value("") == 1);
2957 TEST_CHECK(ent.list_at(1).string_value() == "");
2958 }
2959 }
2960 }
2961
TORRENT_TEST(routing_table_uniform)2962 TORRENT_TEST(routing_table_uniform)
2963 {
2964 // test routing table
2965 dht::settings sett = test_settings();
2966 obs observer;
2967
2968 sett.extended_routing_table = false;
2969 // it's difficult to generate valid nodes with specific node IDs, so just
2970 // turn off that check
2971 sett.prefer_verified_node_ids = false;
2972 node_id id = to_hash("1234876923549721020394873245098347598635");
2973 node_id diff = to_hash("15764f7459456a9453f8719b09547c11d5f34061");
2974
2975 routing_table tbl(id, udp::v4(), 8, sett, &observer);
2976
2977 // insert 256 nodes evenly distributed across the ID space.
2978 // we expect to fill the top 5 buckets
2979 for (int i = 255; i >= 0; --i)
2980 {
2981 // test a node with the same IP:port changing ID
2982 add_and_replace(id, diff);
2983 // in order to make this node-load a bit more realistic, start from
2984 // distant nodes and work our way in closer to the node id
2985 // the routing table will reject nodes that are too imbalanced (if all
2986 // nodes are very close to our ID and none are far away, it's
2987 // suspicious).
2988 id[0] ^= i;
2989 tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
2990
2991 // restore the first byte of the node ID
2992 id[0] ^= i;
2993 }
2994 std::printf("num_active_buckets: %d\n", tbl.num_active_buckets());
2995 // number of nodes per tree level (when adding 256 evenly distributed
2996 // nodes):
2997 // 0: 128
2998 // 1: 64
2999 // 2: 32
3000 // 3: 16
3001 // 4: 8
3002 // i.e. no more than 5 levels
3003 TEST_EQUAL(tbl.num_active_buckets(), 6);
3004
3005 print_state(std::cout, tbl);
3006 }
3007
TORRENT_TEST(routing_table_balance)3008 TORRENT_TEST(routing_table_balance)
3009 {
3010 dht::settings sett = test_settings();
3011 obs observer;
3012
3013 sett.extended_routing_table = false;
3014 sett.prefer_verified_node_ids = false;
3015 node_id id = to_hash("1234876923549721020394873245098347598635");
3016
3017 routing_table tbl(id, udp::v4(), 8, sett, &observer);
3018
3019 // insert nodes in the routing table that will force it to split
3020 // and make sure we don't end up with a table completely out of balance
3021 for (int i = 0; i < 32; ++i)
3022 {
3023 id[0] = (i << 3) & 0xff;
3024 tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
3025 }
3026 std::printf("num_active_buckets: %d\n", tbl.num_active_buckets());
3027 TEST_EQUAL(tbl.num_active_buckets(), 2);
3028
3029 print_state(std::cout, tbl);
3030 }
3031
TORRENT_TEST(routing_table_extended)3032 TORRENT_TEST(routing_table_extended)
3033 {
3034 dht::settings sett = test_settings();
3035 obs observer;
3036 sett.extended_routing_table = true;
3037 sett.prefer_verified_node_ids = false;
3038 node_id id = to_hash("1234876923549721020394873245098347598635");
3039 node_id diff = to_hash("15764f7459456a9453f8719b09547c11d5f34061");
3040
3041 // we can't add the nodes in straight 0,1,2,3 order. That way the routing
3042 // table would get unbalanced and intermediate nodes would be dropped
3043 std::vector<std::uint8_t> node_id_prefix;
3044 node_id_prefix.reserve(256);
3045 for (int i = 0; i < 256; ++i) node_id_prefix.push_back(i & 0xff);
3046 aux::random_shuffle(node_id_prefix);
3047
3048 routing_table tbl(id, udp::v4(), 8, sett, &observer);
3049 for (std::size_t i = 0; i < 256; ++i)
3050 {
3051 add_and_replace(id, diff);
3052 id[0] = node_id_prefix[i];
3053 tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
3054 }
3055 TEST_EQUAL(tbl.num_active_buckets(), 6);
3056
3057 print_state(std::cout, tbl);
3058 }
3059
3060 namespace {
inserter(std::set<node_id> * nodes,node_entry const & ne)3061 void inserter(std::set<node_id>* nodes, node_entry const& ne)
3062 {
3063 nodes->insert(nodes->begin(), ne.id);
3064 }
3065 } // anonymous namespace
3066
TORRENT_TEST(routing_table_set_id)3067 TORRENT_TEST(routing_table_set_id)
3068 {
3069 dht::settings sett = test_settings();
3070 sett.enforce_node_id = false;
3071 sett.extended_routing_table = false;
3072 sett.prefer_verified_node_ids = false;
3073 obs observer;
3074 node_id id = to_hash("0000000000000000000000000000000000000000");
3075
3076 // we can't add the nodes in straight 0,1,2,3 order. That way the routing
3077 // table would get unbalanced and intermediate nodes would be dropped
3078 std::vector<std::uint8_t> node_id_prefix;
3079 node_id_prefix.reserve(256);
3080 for (int i = 0; i < 256; ++i) node_id_prefix.push_back(i & 0xff);
3081 aux::random_shuffle(node_id_prefix);
3082 routing_table tbl(id, udp::v4(), 8, sett, &observer);
3083 for (std::size_t i = 0; i < 256; ++i)
3084 {
3085 id[0] = node_id_prefix[i];
3086 tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
3087 }
3088 TEST_EQUAL(tbl.num_active_buckets(), 6);
3089
3090 std::set<node_id> original_nodes;
3091 tbl.for_each_node(std::bind(&inserter, &original_nodes, _1));
3092
3093 print_state(std::cout, tbl);
3094
3095 id = to_hash("ffffffffffffffffffffffffffffffffffffffff");
3096
3097 tbl.update_node_id(id);
3098
3099 TEST_CHECK(tbl.num_active_buckets() <= 4);
3100 std::set<node_id> remaining_nodes;
3101 tbl.for_each_node(std::bind(&inserter, &remaining_nodes, _1));
3102
3103 std::set<node_id> intersection;
3104 std::set_intersection(remaining_nodes.begin(), remaining_nodes.end()
3105 , original_nodes.begin(), original_nodes.end()
3106 , std::inserter(intersection, intersection.begin()));
3107
3108 // all remaining nodes also exist in the original nodes
3109 TEST_EQUAL(intersection.size(), remaining_nodes.size());
3110
3111 print_state(std::cout, tbl);
3112 }
3113
TORRENT_TEST(routing_table_for_each)3114 TORRENT_TEST(routing_table_for_each)
3115 {
3116 dht::settings sett = test_settings();
3117 obs observer;
3118
3119 sett.extended_routing_table = false;
3120 sett.prefer_verified_node_ids = false;
3121 node_id id = to_hash("1234876923549721020394873245098347598635");
3122
3123 routing_table tbl(id, udp::v4(), 2, sett, &observer);
3124
3125 for (int i = 0; i < 32; ++i)
3126 {
3127 id[0] = (i << 3) & 0xff;
3128 tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
3129 }
3130
3131 int nodes;
3132 int replacements;
3133 std::tie(nodes, replacements, std::ignore) = tbl.size();
3134
3135 std::printf("num_active_buckets: %d\n", tbl.num_active_buckets());
3136 std::printf("live nodes: %d\n", nodes);
3137 std::printf("replacements: %d\n", replacements);
3138
3139 TEST_EQUAL(tbl.num_active_buckets(), 2);
3140 TEST_EQUAL(nodes, 4);
3141 TEST_EQUAL(replacements, 4);
3142
3143 print_state(std::cout, tbl);
3144
3145 std::vector<node_entry> v;
3146 tbl.for_each_node([&](node_entry const& e) { v.push_back(e); }, nullptr);
3147 TEST_EQUAL(v.size(), 4);
3148 v.clear();
3149 tbl.for_each_node(nullptr, [&](node_entry const& e) { v.push_back(e); });
3150 TEST_EQUAL(v.size(), 4);
3151 v.clear();
3152 tbl.for_each_node([&](node_entry const& e) { v.push_back(e); });
3153 TEST_EQUAL(v.size(), 8);
3154 }
3155
TORRENT_TEST(node_set_id)3156 TORRENT_TEST(node_set_id)
3157 {
3158 dht_test_setup t(udp::endpoint(rand_v4(), 20));
3159 node_id old_nid = t.dht_node.nid();
3160 // put in a few votes to make sure the address really changes
3161 for (int i = 0; i < 25; ++i)
3162 t.observer.set_external_address(aux::listen_socket_handle(t.ls), addr4("237.0.0.1"), rand_v4());
3163 t.dht_node.update_node_id();
3164 TEST_CHECK(old_nid != t.dht_node.nid());
3165 // now that we've changed the node's id, make sure the id sent in outgoing messages
3166 // reflects the change
3167
3168 bdecode_node response;
3169 send_dht_request(t.dht_node, "ping", t.source, &response);
3170
3171 dht::key_desc_t const pong_desc[] = {
3172 { "y", bdecode_node::string_t, 1, 0 },
3173 { "t", bdecode_node::string_t, 2, 0 },
3174 { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
3175 { "id", bdecode_node::string_t, 20, key_desc_t::last_child },
3176 };
3177 bdecode_node pong_keys[4];
3178 bool ret = dht::verify_message(response, pong_desc, pong_keys, t.error_string);
3179 TEST_CHECK(ret);
3180 if (!ret) return;
3181
3182 TEST_EQUAL(node_id(pong_keys[3].string_ptr()), t.dht_node.nid());
3183 }
3184
TORRENT_TEST(read_only_node)3185 TORRENT_TEST(read_only_node)
3186 {
3187 // TODO: 3 use dht_test_setup class to simplify the node setup
3188 dht::settings sett = test_settings();
3189 sett.read_only = true;
3190 mock_socket s;
3191 auto ls = dummy_listen_socket4();
3192 obs observer;
3193 counters cnt;
3194
3195 std::unique_ptr<dht_storage_interface> dht_storage(dht_default_storage_constructor(sett));
3196 dht_storage->update_node_ids({node_id(nullptr)});
3197 dht::node node(ls, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage);
3198 udp::endpoint source(addr("10.0.0.1"), 20);
3199 bdecode_node response;
3200 msg_args args;
3201
3202 // for incoming requests, read_only node won't response.
3203 send_dht_request(node, "ping", source, &response, args, "10", false);
3204 TEST_EQUAL(response.type(), bdecode_node::none_t);
3205
3206 args.target(sha1_hash("01010101010101010101"));
3207 send_dht_request(node, "get", source, &response, args, "10", false);
3208 TEST_EQUAL(response.type(), bdecode_node::none_t);
3209
3210 // also, the sender shouldn't be added to routing table.
3211 TEST_EQUAL(std::get<0>(node.size()), 0);
3212
3213 // for outgoing requests, read_only node will add 'ro' key (value == 1)
3214 // in top-level of request.
3215 bdecode_node parsed[7];
3216 char error_string[200];
3217 udp::endpoint initial_node(addr("4.4.4.4"), 1234);
3218 dht::node_id const initial_node_id = to_hash("1111111111222222222233333333334444444444");
3219 node.m_table.add_node(node_entry{initial_node_id, initial_node, 10, true});
3220 bdecode_node request;
3221 sha1_hash target = generate_next();
3222
3223 node.get_item(target, get_immutable_item_cb);
3224 TEST_EQUAL(g_sent_packets.size(), 1);
3225 TEST_EQUAL(g_sent_packets.front().first, initial_node);
3226
3227 dht::key_desc_t const get_item_desc_ro[] = {
3228 {"y", bdecode_node::string_t, 1, 0},
3229 {"t", bdecode_node::string_t, 2, 0},
3230 {"q", bdecode_node::string_t, 3, 0},
3231 {"ro", bdecode_node::int_t, 4, key_desc_t::optional},
3232 {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
3233 {"id", bdecode_node::string_t, 20, 0},
3234 {"target", bdecode_node::string_t, 20, key_desc_t::last_child},
3235 };
3236
3237 node_from_entry(g_sent_packets.front().second, request);
3238 bool ret = verify_message(request, get_item_desc_ro, parsed, error_string);
3239
3240 TEST_CHECK(ret);
3241 TEST_EQUAL(parsed[3].int_value(), 1);
3242
3243 // should have one node now, which is 4.4.4.4:1234
3244 TEST_EQUAL(std::get<0>(node.size()), 1);
3245 // and no replacement nodes
3246 TEST_EQUAL(std::get<1>(node.size()), 0);
3247
3248 // now, disable read_only, try again.
3249 g_sent_packets.clear();
3250 sett.read_only = false;
3251
3252 send_dht_request(node, "get", source, &response);
3253 // sender should be added to repacement bucket
3254 TEST_EQUAL(std::get<1>(node.size()), 1);
3255
3256 g_sent_packets.clear();
3257 #if 0
3258 // TODO: this won't work because the second node isn't pinged so it wont
3259 // be added to the routing table
3260 target = generate_next();
3261 node.get_item(target, get_immutable_item_cb);
3262
3263 // since we have 2 nodes, we should have two packets.
3264 TEST_EQUAL(g_sent_packets.size(), 2);
3265
3266 // both of them shouldn't have a 'ro' key.
3267 node_from_entry(g_sent_packets.front().second, request);
3268 ret = verify_message(request, get_item_desc_ro, parsed, error_string);
3269
3270 TEST_CHECK(ret);
3271 TEST_CHECK(!parsed[3]);
3272
3273 node_from_entry(g_sent_packets.back().second, request);
3274 ret = verify_message(request, get_item_desc_ro, parsed, error_string);
3275
3276 TEST_CHECK(ret);
3277 TEST_CHECK(!parsed[3]);
3278 #endif
3279 }
3280
3281 #ifndef TORRENT_DISABLE_LOGGING
3282 // these tests rely on logging being enabled
3283
TORRENT_TEST(invalid_error_msg)3284 TORRENT_TEST(invalid_error_msg)
3285 {
3286 // TODO: 3 use dht_test_setup class to simplify the node setup
3287 dht::settings sett = test_settings();
3288 mock_socket s;
3289 auto ls = dummy_listen_socket4();
3290 obs observer;
3291 counters cnt;
3292
3293 std::unique_ptr<dht_storage_interface> dht_storage(dht_default_storage_constructor(sett));
3294 dht_storage->update_node_ids({node_id(nullptr)});
3295 dht::node node(ls, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage);
3296 udp::endpoint source(addr("10.0.0.1"), 20);
3297
3298 entry e;
3299 e["y"] = "e";
3300 e["e"].string() = "Malformed Error";
3301 char msg_buf[1500];
3302 int size = bencode(msg_buf, e);
3303
3304 bdecode_node decoded;
3305 error_code ec;
3306 bdecode(msg_buf, msg_buf + size, decoded, ec);
3307 if (ec) std::printf("bdecode failed: %s\n", ec.message().c_str());
3308
3309 dht::msg m(decoded, source);
3310 node.incoming(node.m_sock, m);
3311
3312 bool found = false;
3313 for (auto const& log : observer.m_log)
3314 {
3315 if (log.find("INCOMING ERROR") != std::string::npos
3316 && log.find("(malformed)") != std::string::npos)
3317 found = true;
3318
3319 std::printf("%s\n", log.c_str());
3320 }
3321
3322 TEST_EQUAL(found, true);
3323 }
3324
3325 struct test_algo : dht::traversal_algorithm
3326 {
test_algotest_algo3327 test_algo(node& dht_node, node_id const& target)
3328 : traversal_algorithm(dht_node, target)
3329 {}
3330
donetest_algo3331 void done() { this->dht::traversal_algorithm::done(); }
3332
resultstest_algo3333 std::vector<observer_ptr> const& results() const { return m_results; }
3334
3335 using traversal_algorithm::num_sorted_results;
3336 };
3337
TORRENT_TEST(unsorted_traversal_results)3338 TORRENT_TEST(unsorted_traversal_results)
3339 {
3340 init_rand_address();
3341
3342 // make sure the handling of an unsorted tail of nodes is correct in the
3343 // traversal algorithm. Initial nodes (that we bootstrap from) remain
3344 // unsorted, since we don't know their node IDs
3345
3346 dht_test_setup t(udp::endpoint(rand_v4(), 20));
3347
3348 node_id const our_id = t.dht_node.nid();
3349 auto algo = std::make_shared<test_algo>(t.dht_node, our_id);
3350
3351 std::vector<udp::endpoint> eps;
3352 for (int i = 0; i < 10; ++i)
3353 {
3354 eps.push_back(rand_udp_ep(rand_v4));
3355 algo->add_entry(node_id(), eps.back(), observer::flag_initial);
3356 }
3357
3358 // we should have 10 unsorted nodes now
3359 TEST_CHECK(algo->num_sorted_results() == 0);
3360 auto results = algo->results();
3361 TEST_CHECK(results.size() == eps.size());
3362 for (std::size_t i = 0; i < eps.size(); ++i)
3363 TEST_CHECK(eps[i] == results[i]->target_ep());
3364
3365 // setting the node ID, regardless of what we set it to, should cause this
3366 // observer to become sorted. i.e. be moved to the beginning of the result
3367 // list.
3368 results[5]->set_id(node_id("abababababababababab"));
3369
3370 TEST_CHECK(algo->num_sorted_results() == 1);
3371 results = algo->results();
3372 TEST_CHECK(results.size() == eps.size());
3373 TEST_CHECK(eps[5] == results[0]->target_ep());
3374 algo->done();
3375 }
3376
TORRENT_TEST(rpc_invalid_error_msg)3377 TORRENT_TEST(rpc_invalid_error_msg)
3378 {
3379 // TODO: 3 use dht_test_setup class to simplify the node setup
3380 dht::settings sett = test_settings();
3381 mock_socket s;
3382 auto ls = dummy_listen_socket4();
3383 obs observer;
3384 counters cnt;
3385
3386 dht::routing_table table(node_id(), udp::v4(), 8, sett, &observer);
3387 dht::rpc_manager rpc(node_id(), sett, table, ls, &s, &observer);
3388 std::unique_ptr<dht_storage_interface> dht_storage(dht_default_storage_constructor(sett));
3389 dht_storage->update_node_ids({node_id(nullptr)});
3390 dht::node node(ls, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage);
3391
3392 udp::endpoint source(addr("10.0.0.1"), 20);
3393
3394 // we need this to create an entry for this transaction ID, otherwise the
3395 // incoming message will just be dropped
3396 entry req;
3397 req["y"] = "q";
3398 req["q"] = "bogus_query";
3399 req["t"] = "\0\0\0\0";
3400
3401 g_sent_packets.clear();
3402 auto algo = std::make_shared<dht::traversal_algorithm>(node, node_id());
3403
3404 auto o = rpc.allocate_observer<null_observer>(std::move(algo), source, node_id());
3405 #if TORRENT_USE_ASSERTS
3406 o->m_in_constructor = false;
3407 #endif
3408 rpc.invoke(req, source, o);
3409
3410 // here's the incoming (malformed) error message
3411 entry err;
3412 err["y"] = "e";
3413 err["e"].string() = "Malformed Error";
3414 err["t"] = g_sent_packets.begin()->second["t"].string();
3415 char msg_buf[1500];
3416 int size = bencode(msg_buf, err);
3417
3418 bdecode_node decoded;
3419 error_code ec;
3420 bdecode(msg_buf, msg_buf + size, decoded, ec);
3421 if (ec) std::printf("bdecode failed: %s\n", ec.message().c_str());
3422
3423 dht::msg m(decoded, source);
3424 node_id nid;
3425 rpc.incoming(m, &nid);
3426
3427 bool found = false;
3428 for (auto const& log : observer.m_log)
3429 {
3430 if (log.find("reply with") != std::string::npos
3431 && log.find("(malformed)") != std::string::npos
3432 && log.find("error") != std::string::npos)
3433 found = true;
3434
3435 std::printf("%s\n", log.c_str());
3436 }
3437
3438 TEST_EQUAL(found, true);
3439 }
3440 #endif
3441
3442 // test bucket distribution
TORRENT_TEST(node_id_bucket_distribution)3443 TORRENT_TEST(node_id_bucket_distribution)
3444 {
3445 init_rand_address();
3446
3447 int nodes_per_bucket[160] = {0};
3448 dht::node_id reference_id = generate_id(rand_v4());
3449 int const num_samples = 100000;
3450 for (int i = 0; i < num_samples; ++i)
3451 {
3452 dht::node_id nid = generate_id(rand_v4());
3453 int const bucket = 159 - distance_exp(reference_id, nid);
3454 ++nodes_per_bucket[bucket];
3455 }
3456
3457 for (int i = 0; i < 25; ++i)
3458 {
3459 std::printf("%3d ", nodes_per_bucket[i]);
3460 }
3461 std::printf("\n");
3462
3463 int expected = num_samples / 2;
3464 for (int i = 0; i < 25; ++i)
3465 {
3466 TEST_CHECK(std::abs(nodes_per_bucket[i] - expected) < num_samples / 20);
3467 expected /= 2;
3468 }
3469 }
3470
TORRENT_TEST(node_id_min_distance_exp)3471 TORRENT_TEST(node_id_min_distance_exp)
3472 {
3473 node_id const n1 = to_hash("0000000000000000000000000000000000000002");
3474 node_id const n2 = to_hash("0000000000000000000000000000000000000004");
3475 node_id const n3 = to_hash("0000000000000000000000000000000000000008");
3476
3477 std::vector<node_id> ids;
3478
3479 ids.push_back(n1);
3480
3481 TEST_EQUAL(min_distance_exp(sha1_hash::min(), ids), 1);
3482
3483 ids.push_back(n1);
3484 ids.push_back(n2);
3485
3486 TEST_EQUAL(min_distance_exp(sha1_hash::min(), ids), 1);
3487
3488 ids.push_back(n1);
3489 ids.push_back(n2);
3490 ids.push_back(n3);
3491
3492 TEST_EQUAL(min_distance_exp(sha1_hash::min(), ids), 1);
3493
3494 ids.clear();
3495 ids.push_back(n3);
3496 ids.push_back(n2);
3497 ids.push_back(n2);
3498
3499 TEST_EQUAL(min_distance_exp(sha1_hash::min(), ids), 2);
3500 }
3501
TORRENT_TEST(dht_verify_node_address)3502 TORRENT_TEST(dht_verify_node_address)
3503 {
3504 obs observer;
3505 // initial setup taken from dht test above
3506 dht::settings s;
3507 s.extended_routing_table = false;
3508 node_id id = to_hash("3123456789abcdef01232456789abcdef0123456");
3509 const int bucket_size = 8;
3510 dht::routing_table table(id, udp::v4(), bucket_size, s, &observer);
3511 std::vector<node_entry> nodes;
3512 TEST_EQUAL(std::get<0>(table.size()), 0);
3513
3514 node_id tmp = id;
3515 node_id diff = to_hash("15764f7459456a9453f8719b09547c11d5f34061");
3516
3517 add_and_replace(tmp, diff);
3518 table.node_seen(tmp, udp::endpoint(addr("4.4.4.4"), 4), 10);
3519 table.find_node(id, nodes, 0, 10);
3520 TEST_EQUAL(std::get<0>(table.size()), 1);
3521 TEST_EQUAL(nodes.size(), 1);
3522
3523 // incorrect data, wrong IP
3524 table.node_seen(tmp
3525 , udp::endpoint(addr("4.4.4.6"), 4), 10);
3526 table.find_node(id, nodes, 0, 10);
3527
3528 TEST_EQUAL(std::get<0>(table.size()), 1);
3529 TEST_EQUAL(nodes.size(), 1);
3530
3531 // incorrect data, wrong id, should cause node to be removed
3532 table.node_seen(to_hash("0123456789abcdef01232456789abcdef0123456")
3533 , udp::endpoint(addr("4.4.4.4"), 4), 10);
3534 table.find_node(id, nodes, 0, 10);
3535
3536 TEST_EQUAL(std::get<0>(table.size()), 0);
3537 TEST_EQUAL(nodes.size(), 0);
3538 }
3539
TORRENT_TEST(generate_prefix_mask)3540 TORRENT_TEST(generate_prefix_mask)
3541 {
3542 std::vector<std::pair<int, char const*>> const test = {
3543 { 0, "0000000000000000000000000000000000000000" },
3544 { 1, "8000000000000000000000000000000000000000" },
3545 { 2, "c000000000000000000000000000000000000000" },
3546 { 11, "ffe0000000000000000000000000000000000000" },
3547 { 17, "ffff800000000000000000000000000000000000" },
3548 { 37, "fffffffff8000000000000000000000000000000" },
3549 { 160, "ffffffffffffffffffffffffffffffffffffffff" },
3550 };
3551
3552 for (auto const& i : test)
3553 {
3554 TEST_EQUAL(generate_prefix_mask(i.first), to_hash(i.second));
3555 }
3556 }
3557
TORRENT_TEST(distance_exp)3558 TORRENT_TEST(distance_exp)
3559 {
3560 // distance_exp
3561
3562
3563 using tst = std::tuple<char const*, char const*, int>;
3564
3565 std::vector<std::tuple<char const*, char const*, int>> const distance_tests = {
3566 tst{ "ffffffffffffffffffffffffffffffffffffffff"
3567 , "0000000000000000000000000000000000000000", 159 },
3568
3569 tst{ "ffffffffffffffffffffffffffffffffffffffff"
3570 , "7fffffffffffffffffffffffffffffffffffffff", 159 },
3571
3572 tst{ "ffffffffffffffffffffffffffffffffffffffff"
3573 , "ffffffffffffffffffffffffffffffffffffffff", 0 },
3574
3575 tst{ "ffffffffffffffffffffffffffffffffffffffff"
3576 , "fffffffffffffffffffffffffffffffffffffffe", 0 },
3577
3578 tst{ "8000000000000000000000000000000000000000"
3579 , "fffffffffffffffffffffffffffffffffffffffe", 158 },
3580
3581 tst{ "c000000000000000000000000000000000000000"
3582 , "fffffffffffffffffffffffffffffffffffffffe", 157 },
3583
3584 tst{ "e000000000000000000000000000000000000000"
3585 , "fffffffffffffffffffffffffffffffffffffffe", 156 },
3586
3587 tst{ "f000000000000000000000000000000000000000"
3588 , "fffffffffffffffffffffffffffffffffffffffe", 155 },
3589
3590 tst{ "f8f2340985723049587230495872304958703294"
3591 , "f743589043r890f023980f90e203980d090c3840", 155 },
3592
3593 tst{ "ffff740985723049587230495872304958703294"
3594 , "ffff889043r890f023980f90e203980d090c3840", 159 - 16 },
3595 };
3596
3597 for (auto const& t : distance_tests)
3598 {
3599 std::printf("%s %s: %d\n"
3600 , std::get<0>(t), std::get<1>(t), std::get<2>(t));
3601
3602 TEST_EQUAL(distance_exp(to_hash(std::get<0>(t))
3603 , to_hash(std::get<1>(t))), std::get<2>(t));
3604 }
3605 }
3606
TORRENT_TEST(compare_ip_cidr)3607 TORRENT_TEST(compare_ip_cidr)
3608 {
3609 using tst = std::tuple<char const*, char const*, bool>;
3610 std::vector<tst> const v4tests = {
3611 tst{"10.255.255.0", "10.255.255.255", true},
3612 tst{"11.0.0.0", "10.255.255.255", false},
3613 tst{"0.0.0.0", "128.255.255.255", false},
3614 tst{"0.0.0.0", "127.255.255.255", false},
3615 tst{"255.255.255.0", "255.255.255.255", true},
3616 tst{"255.254.255.0", "255.255.255.255", false},
3617 tst{"0.0.0.0", "0.0.0.0", true},
3618 tst{"255.255.255.255", "255.255.255.255", true},
3619 };
3620
3621 for (auto const& t : v4tests)
3622 {
3623 std::printf("%s %s\n", std::get<0>(t), std::get<1>(t));
3624 TEST_EQUAL(compare_ip_cidr(
3625 addr4(std::get<0>(t)), addr4(std::get<1>(t))), std::get<2>(t));
3626 }
3627
3628 std::vector<tst> const v6tests = {
3629 tst{"::1", "::ffff:ffff:ffff:ffff", true},
3630 tst{"::2:0000:0000:0000:0000", "::1:ffff:ffff:ffff:ffff", false},
3631 tst{"::ff:0000:0000:0000:0000", "::ffff:ffff:ffff:ffff", false},
3632 tst{"::caca:0000:0000:0000:0000", "::ffff:ffff:ffff:ffff:ffff", false},
3633 tst{"::a:0000:0000:0000:0000", "::b:ffff:ffff:ffff:ffff", false},
3634 tst{"::7f:0000:0000:0000:0000", "::ffff:ffff:ffff:ffff", false},
3635 tst{"7f::", "ff::", false},
3636 tst{"ff::", "ff::", true},
3637 tst{"::", "::", true},
3638 tst{"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", true},
3639 };
3640
3641 for (auto const& t : v6tests)
3642 {
3643 TEST_EQUAL(compare_ip_cidr(
3644 addr6(std::get<0>(t)), addr6(std::get<1>(t))), std::get<2>(t));
3645 }
3646 }
3647
TORRENT_TEST(dht_state)3648 TORRENT_TEST(dht_state)
3649 {
3650 dht_state s;
3651
3652 s.nids.emplace_back(address::from_string("1.1.1.1"), to_hash("0000000000000000000000000000000000000001"));
3653 s.nodes.push_back(uep("1.1.1.1", 1));
3654 s.nodes.push_back(uep("2.2.2.2", 2));
3655 // remove these for now because they will only get used if the host system has IPv6 support
3656 // hopefully in the future we can rely on the test system supporting IPv6
3657 //s.nids.emplace_back(address::from_string("1::1"), to_hash("0000000000000000000000000000000000000002"));
3658 //s.nodes6.push_back(uep("1::1", 3));
3659 //s.nodes6.push_back(uep("2::2", 4));
3660
3661 entry const e = save_dht_state(s);
3662
3663 std::vector<char> tmp;
3664 bencode(std::back_inserter(tmp), e);
3665
3666 bdecode_node n;
3667 error_code ec;
3668 int r = bdecode(&tmp[0], &tmp[0] + tmp.size(), n, ec);
3669 TEST_CHECK(!r);
3670
3671 dht_state const s1 = read_dht_state(n);
3672 TEST_CHECK(s1.nids == s.nids);
3673 TEST_CHECK(s1.nodes == s.nodes);
3674
3675 // empty
3676 bdecode_node n1;
3677 dht_state const s2 = read_dht_state(n1);
3678 TEST_CHECK(s2.nids.empty());
3679 TEST_CHECK(s2.nodes.empty());
3680 }
3681
TORRENT_TEST(sample_infohashes)3682 TORRENT_TEST(sample_infohashes)
3683 {
3684 init_rand_address();
3685
3686 dht_test_setup t(rand_udp_ep());
3687 bdecode_node response;
3688
3689 g_sent_packets.clear();
3690
3691 udp::endpoint initial_node = rand_udp_ep();
3692 t.dht_node.m_table.add_node(node_entry{initial_node});
3693
3694 // nodes
3695 sha1_hash const h1 = rand_hash();
3696 sha1_hash const h2 = rand_hash();
3697 udp::endpoint const ep1 = rand_udp_ep(rand_v4);
3698 udp::endpoint const ep2 = rand_udp_ep(rand_v4);
3699
3700 t.dht_node.sample_infohashes(initial_node, items[0].target,
3701 [h1, ep1, h2, ep2](time_duration interval, int num
3702 , std::vector<sha1_hash> samples
3703 , std::vector<std::pair<sha1_hash, udp::endpoint>> const& nodes)
3704 {
3705 TEST_EQUAL(total_seconds(interval), 10);
3706 TEST_EQUAL(num, 2);
3707 TEST_EQUAL(samples.size(), 1);
3708 TEST_EQUAL(samples[0], to_hash("1000000000000000000000000000000000000001"));
3709 TEST_EQUAL(nodes.size(), 2);
3710 TEST_EQUAL(nodes[0].first, h1);
3711 TEST_EQUAL(nodes[0].second, ep1);
3712 TEST_EQUAL(nodes[1].first, h2);
3713 TEST_EQUAL(nodes[1].second, ep2);
3714 });
3715
3716 TEST_EQUAL(g_sent_packets.size(), 1);
3717 if (g_sent_packets.empty()) return;
3718 TEST_EQUAL(g_sent_packets.front().first, initial_node);
3719
3720 node_from_entry(g_sent_packets.front().second, response);
3721 bdecode_node sample_infohashes_keys[6];
3722 bool const ret = verify_message(response
3723 , sample_infohashes_desc, sample_infohashes_keys, t.error_string);
3724 if (ret)
3725 {
3726 TEST_EQUAL(sample_infohashes_keys[0].string_value(), "q");
3727 TEST_EQUAL(sample_infohashes_keys[2].string_value(), "sample_infohashes");
3728 TEST_EQUAL(sample_infohashes_keys[5].string_value(), items[0].target.to_string());
3729 }
3730 else
3731 {
3732 std::printf(" invalid sample_infohashes request: %s\n", print_entry(response).c_str());
3733 TEST_ERROR(t.error_string);
3734 return;
3735 }
3736
3737 std::vector<node_entry> nodes;
3738 nodes.emplace_back(h1, ep1);
3739 nodes.emplace_back(h2, ep2);
3740
3741 g_sent_packets.clear();
3742 send_dht_response(t.dht_node, response, initial_node
3743 , msg_args()
3744 .interval(seconds(10))
3745 .num(2)
3746 .samples({to_hash("1000000000000000000000000000000000000001")})
3747 .nodes(nodes));
3748
3749 TEST_CHECK(g_sent_packets.empty());
3750 }
3751
3752 namespace {
fake_node(bool verified,int rtt=0)3753 node_entry fake_node(bool verified, int rtt = 0)
3754 {
3755 node_entry e(rand_udp_ep());
3756 e.verified = verified;
3757 e.rtt = static_cast<std::uint16_t>(rtt);
3758 return e;
3759 }
3760 }
3761
TORRENT_TEST(node_entry_comparison)3762 TORRENT_TEST(node_entry_comparison)
3763 {
3764 // being verified or not always trumps RTT in sort order
3765 TEST_CHECK(fake_node(true, 10) < fake_node(false, 5));
3766 TEST_CHECK(fake_node(true, 5) < fake_node(false, 10));
3767 TEST_CHECK(!(fake_node(false, 10) < fake_node(true, 5)));
3768 TEST_CHECK(!(fake_node(false, 5) < fake_node(true, 10)));
3769
3770 // if both are verified, lower RTT is better
3771 TEST_CHECK(fake_node(true, 5) < fake_node(true, 10));
3772 TEST_CHECK(!(fake_node(true, 10) < fake_node(true, 5)));
3773
3774 // if neither are verified, lower RTT is better
3775 TEST_CHECK(fake_node(false, 5) < fake_node(false, 10));
3776 TEST_CHECK(!(fake_node(false, 10) < fake_node(false, 5)));
3777 }
3778
TORRENT_TEST(mostly_verified_nodes)3779 TORRENT_TEST(mostly_verified_nodes)
3780 {
3781 // an empty bucket is OK
3782 TEST_CHECK(mostly_verified_nodes({}));
3783 TEST_CHECK(mostly_verified_nodes({fake_node(true)}));
3784 TEST_CHECK(mostly_verified_nodes({fake_node(true), fake_node(false)}));
3785 TEST_CHECK(mostly_verified_nodes({fake_node(true), fake_node(true), fake_node(false)}));
3786 TEST_CHECK(mostly_verified_nodes({fake_node(true), fake_node(true), fake_node(true), fake_node(false)}));
3787
3788 // a large bucket with only half of the nodes verified, does not count as
3789 // "mostly"
3790 TEST_CHECK(!mostly_verified_nodes({fake_node(true), fake_node(false)
3791 , fake_node(true), fake_node(false)
3792 , fake_node(true), fake_node(false)
3793 , fake_node(true), fake_node(false)
3794 , fake_node(true), fake_node(false)
3795 , fake_node(true), fake_node(false)}));
3796
3797 // 1 of 3 is not "mostly"
3798 TEST_CHECK(!mostly_verified_nodes({fake_node(false), fake_node(true), fake_node(false)}));
3799
3800 TEST_CHECK(!mostly_verified_nodes({fake_node(false)}));
3801 TEST_CHECK(!mostly_verified_nodes({fake_node(false), fake_node(false)}));
3802 TEST_CHECK(!mostly_verified_nodes({fake_node(false), fake_node(false), fake_node(false)}));
3803 }
3804
TORRENT_TEST(classify_prefix)3805 TORRENT_TEST(classify_prefix)
3806 {
3807 // the last bucket in the routing table
3808 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("0cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 0);
3809 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 1);
3810 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("4cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 2);
3811 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("6cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 3);
3812 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 4);
3813 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("acdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 5);
3814 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("ccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 6);
3815 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("ecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 7);
3816 TEST_EQUAL(int(classify_prefix(0, true, 8, to_hash("fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 7);
3817
3818 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("c0cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 0);
3819 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("c2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 1);
3820 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("c4cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 2);
3821 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("c6cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 3);
3822 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("c8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 4);
3823 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("cacdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 5);
3824 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("cccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 6);
3825 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("cecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3826 TEST_EQUAL(int(classify_prefix(4, true, 8, to_hash("cfcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3827
3828 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dc0cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 0);
3829 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dc2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 1);
3830 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dc4cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 2);
3831 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dc6cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 3);
3832 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dc8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 4);
3833 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dcacdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 5);
3834 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dcccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 6);
3835 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dcecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 7);
3836 TEST_EQUAL(int(classify_prefix(8, true, 8, to_hash("dcfcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc"))), 7);
3837
3838 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdc0cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 0);
3839 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdc2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 1);
3840 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdc4cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 2);
3841 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdc6cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 3);
3842 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdc8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 4);
3843 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdcacdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 5);
3844 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdcccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 6);
3845 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdcecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3846 TEST_EQUAL(int(classify_prefix(12, true, 8, to_hash("cdcfcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3847
3848 // not the last bucket in the routing table
3849 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdc0cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 0);
3850 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdc2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 1);
3851 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdc4cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 2);
3852 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdc6cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 3);
3853 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdc8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 4);
3854 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdcacdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 5);
3855 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdcccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 6);
3856 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdcecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3857 TEST_EQUAL(int(classify_prefix(11, false, 8, to_hash("cdcfcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3858
3859 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdc8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 0);
3860 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdc9cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 1);
3861 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdcacdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 2);
3862 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdcbcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 3);
3863 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdcccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 4);
3864 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 5);
3865 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdcecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 6);
3866 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdcfcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3867 TEST_EQUAL(int(classify_prefix(12, false, 8, to_hash("cdc7cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3868
3869 // larger bucket
3870 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc0cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 0);
3871 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc1cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 1);
3872 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 2);
3873 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc3cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 3);
3874 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc4cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 4);
3875 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc5cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 5);
3876 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc6cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 6);
3877 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc7cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 7);
3878 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc8cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 8);
3879 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdc9cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 9);
3880 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdcacdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 10);
3881 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdcbcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 11);
3882 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdcccdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 12);
3883 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 13);
3884 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdcecdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 14);
3885 TEST_EQUAL(int(classify_prefix(12, true, 16, to_hash("cdcfcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"))), 15);
3886 }
3887
3888 namespace {
n(ip_set * ips,char const * nid,bool verified=true,int rtt=0,int failed=0)3889 node_entry n(ip_set* ips, char const* nid, bool verified = true, int rtt = 0, int failed = 0)
3890 {
3891 node_entry e(rand_udp_ep());
3892 if (ips) ips->insert(e.addr());
3893 e.verified = verified;
3894 e.rtt = static_cast<std::uint16_t>(rtt);
3895 e.id = to_hash(nid);
3896 if (failed != 0) e.timeout_count = static_cast<std::uint8_t>(failed);
3897 return e;
3898 }
3899 }
3900
3901 #ifndef TORRENT_DISABLE_LOGGING
3902 #define LOGGER , nullptr
3903 #else
3904 #define LOGGER
3905 #endif
TORRENT_TEST(replace_node_impl)3906 TORRENT_TEST(replace_node_impl)
3907 {
3908 // replace specific prefix "slot"
3909 {
3910 ip_set p;
3911 dht::bucket_t b = {
3912 n(&p, "1fffffffffffffffffffffffffffffffffffffff", true, 50),
3913 n(&p, "3fffffffffffffffffffffffffffffffffffffff", true, 50),
3914 n(&p, "5fffffffffffffffffffffffffffffffffffffff", true, 50),
3915 n(&p, "7fffffffffffffffffffffffffffffffffffffff", true, 50),
3916 n(&p, "9fffffffffffffffffffffffffffffffffffffff", true, 50), // <== replaced
3917 n(&p, "bfffffffffffffffffffffffffffffffffffffff", true, 50),
3918 n(&p, "dfffffffffffffffffffffffffffffffffffffff", true, 50),
3919 n(&p, "ffffffffffffffffffffffffffffffffffffffff", true, 50),
3920 };
3921 TEST_EQUAL(p.size(), 8);
3922 TEST_CHECK(
3923 replace_node_impl(n(nullptr, "9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd")
3924 , b, p, 0, 8, true LOGGER) == routing_table::node_added);
3925 TEST_CHECK(b[4].id == to_hash("9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"));
3926 TEST_EQUAL(p.size(), 8);
3927 }
3928
3929 // only try to replace specific prefix "slot", and if we fail (RTT is
3930 // higher), don't replace anything else
3931 {
3932 ip_set p;
3933 dht::bucket_t b = {
3934 n(&p, "1fffffffffffffffffffffffffffffffffffffff", true, 500),
3935 n(&p, "3fffffffffffffffffffffffffffffffffffffff", true, 500),
3936 n(&p, "5fffffffffffffffffffffffffffffffffffffff", true, 500),
3937 n(&p, "7fffffffffffffffffffffffffffffffffffffff", true, 500),
3938 n(&p, "9fffffffffffffffffffffffffffffffffffffff", true, 50),
3939 n(&p, "bfffffffffffffffffffffffffffffffffffffff", true, 500),
3940 n(&p, "dfffffffffffffffffffffffffffffffffffffff", true, 500),
3941 n(&p, "ffffffffffffffffffffffffffffffffffffffff", true, 500),
3942 };
3943 TEST_EQUAL(p.size(), 8);
3944 TEST_CHECK(
3945 replace_node_impl(n(nullptr, "9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", true, 100)
3946 , b, p, 0, 8, true LOGGER) != routing_table::node_added);
3947 TEST_CHECK(b[4].id == to_hash("9fffffffffffffffffffffffffffffffffffffff"));
3948 TEST_EQUAL(p.size(), 8);
3949 }
3950
3951 // if there are multiple candidates to replace, pick the one with the highest
3952 // RTT. We're picking the prefix slots with duplicates
3953 {
3954 ip_set p;
3955 dht::bucket_t b = {
3956 n(&p, "1fffffffffffffffffffffffffffffffffffffff", true, 50),
3957 n(&p, "3fffffffffffffffffffffffffffffffffffffff", true, 50),
3958 n(&p, "5fffffffffffffffffffffffffffffffffffffff", true, 50),
3959 n(&p, "7fffffffffffffffffffffffffffffffffffffff", true, 50),
3960 n(&p, "bfffffffffffffffffffffffffffffffffffffff", true, 50),
3961 n(&p, "bfffffffffffffffffffffffffffffffffffffff", true, 51), // <== replaced
3962 n(&p, "dfffffffffffffffffffffffffffffffffffffff", true, 50),
3963 n(&p, "ffffffffffffffffffffffffffffffffffffffff", true, 50),
3964 };
3965 TEST_EQUAL(p.size(), 8);
3966 TEST_CHECK(
3967 replace_node_impl(n(nullptr, "9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", true, 50)
3968 , b, p, 0, 8, true LOGGER) == routing_table::node_added);
3969 TEST_CHECK(b[5].id == to_hash("9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"));
3970 TEST_EQUAL(p.size(), 8);
3971 }
3972
3973 // if there is a node with fail count > 0, replaec that, regardless of
3974 // anything else
3975 {
3976 ip_set p;
3977 dht::bucket_t b = {
3978 n(&p, "1fffffffffffffffffffffffffffffffffffffff", true, 50),
3979 n(&p, "3fffffffffffffffffffffffffffffffffffffff", true, 50),
3980 n(&p, "5fffffffffffffffffffffffffffffffffffffff", true, 50),
3981 n(&p, "7fffffffffffffffffffffffffffffffffffffff", true, 50),
3982 n(&p, "9fffffffffffffffffffffffffffffffffffffff", true, 50),
3983 n(&p, "bfffffffffffffffffffffffffffffffffffffff", true, 50),
3984 n(&p, "dfffffffffffffffffffffffffffffffffffffff", true, 50),
3985 n(&p, "ffffffffffffffffffffffffffffffffffffffff", true, 50, 1), // <== replaced
3986 };
3987 TEST_EQUAL(p.size(), 8);
3988 TEST_CHECK(
3989 replace_node_impl(n(nullptr, "9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", true, 50)
3990 , b, p, 0, 8, true LOGGER) == routing_table::node_added);
3991 TEST_CHECK(b[7].id == to_hash("9fcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"));
3992 TEST_EQUAL(p.size(), 8);
3993 }
3994 }
3995
TORRENT_TEST(all_in_same_bucket)3996 TORRENT_TEST(all_in_same_bucket)
3997 {
3998 TEST_CHECK(all_in_same_bucket({}, to_hash("8000000000000000000000000000000000000000"), 0) == true);
3999 TEST_CHECK(all_in_same_bucket({}, to_hash("8000000000000000000000000000000000000001"), 1) == true);
4000 TEST_CHECK(all_in_same_bucket({}, to_hash("8000000000000000000000000000000000000002"), 2) == true);
4001 TEST_CHECK(all_in_same_bucket({}, to_hash("8000000000000000000000000000000000000003"), 3) == true);
4002 {
4003 dht::bucket_t b = {
4004 n(nullptr, "0000000000000000000000000000000000000000"),
4005 };
4006 TEST_CHECK(all_in_same_bucket(b, to_hash("8000000000000000000000000000000000000000"), 0) == false);
4007 }
4008
4009 {
4010 dht::bucket_t b = {
4011 n(nullptr, "8000000000000000000000000000000000000000"),
4012 n(nullptr, "f000000000000000000000000000000000000000"),
4013 };
4014 TEST_CHECK(all_in_same_bucket(b, to_hash("8000000000000000000000000000000000000000"), 0) == true);
4015 }
4016 {
4017 dht::bucket_t b = {
4018 n(nullptr, "8000000000000000000000000000000000000000"),
4019 n(nullptr, "0000000000000000000000000000000000000000"),
4020 };
4021 TEST_CHECK(all_in_same_bucket(b, to_hash("8000000000000000000000000000000000000000"), 0) == false);
4022 }
4023 {
4024 dht::bucket_t b = {
4025 n(nullptr, "0800000000000000000000000000000000000000"),
4026 n(nullptr, "0000000000000000000000000000000000000000"),
4027 };
4028 TEST_CHECK(all_in_same_bucket(b, to_hash("0800000000000000000000000000000000000000"), 4) == false);
4029 }
4030 {
4031 dht::bucket_t b = {
4032 n(nullptr, "0800000000000000000000000000000000000000"),
4033 n(nullptr, "0800000000000000000000000000000000000000"),
4034 };
4035
4036 TEST_CHECK(all_in_same_bucket(b, to_hash("0800000000000000000000000000000000000000"), 4) == true);
4037 }
4038 {
4039 dht::bucket_t b = {
4040 n(nullptr, "0007000000000000000000000000000000000000"),
4041 n(nullptr, "0004000000000000000000000000000000000000"),
4042 };
4043
4044 TEST_CHECK(all_in_same_bucket(b, to_hash("0005000000000000000000000000000000000000"), 13) == true);
4045 }
4046 }
4047
4048 namespace {
test_rate_limit(dht::settings & sett,std::function<void (lt::dht::socket_manager &)> f)4049 void test_rate_limit(dht::settings& sett, std::function<void(lt::dht::socket_manager&)> f)
4050 {
4051 io_service ios;
4052 obs observer;
4053 counters cnt;
4054 auto dht_storage = dht_default_storage_constructor(sett);
4055 dht_state s;
4056
4057 lt::dht::dht_tracker::send_fun_t send;
4058
4059 dht_tracker dht(&observer, ios, send, sett, cnt, *dht_storage, std::move(s));
4060 f(dht);
4061 }
4062 }
4063
TORRENT_TEST(rate_limit_int_max)4064 TORRENT_TEST(rate_limit_int_max)
4065 {
4066 dht::settings sett;
4067 sett.upload_rate_limit = std::numeric_limits<int>::max();
4068
4069 test_rate_limit(sett, [](lt::dht::socket_manager& sm) {
4070 TEST_CHECK(sm.has_quota());
4071 std::this_thread::sleep_for(milliseconds(10));
4072
4073 // *any* increment to the quote above INT_MAX may overflow. Ensure it
4074 // doesn't
4075 TEST_CHECK(sm.has_quota());
4076 });
4077 }
4078
TORRENT_TEST(rate_limit_large_delta)4079 TORRENT_TEST(rate_limit_large_delta)
4080 {
4081 dht::settings sett;
4082 sett.upload_rate_limit = std::numeric_limits<int>::max() / 2;
4083
4084 test_rate_limit(sett, [](lt::dht::socket_manager& sm) {
4085 TEST_CHECK(sm.has_quota());
4086 std::this_thread::sleep_for(milliseconds(2500));
4087
4088 // even though we have headroom in the limit itself, this long delay
4089 // would increment the quota past INT_MAX
4090 TEST_CHECK(sm.has_quota());
4091 });
4092 }
4093
TORRENT_TEST(rate_limit_accrue_limit)4094 TORRENT_TEST(rate_limit_accrue_limit)
4095 {
4096 dht::settings sett;
4097 sett.upload_rate_limit = std::numeric_limits<int>::max() / 5;
4098
4099 test_rate_limit(sett, [](lt::dht::socket_manager& sm) {
4100 TEST_CHECK(sm.has_quota());
4101 for (int i = 0; i < 10; ++i)
4102 {
4103 std::this_thread::sleep_for(milliseconds(500));
4104 TEST_CHECK(sm.has_quota());
4105 }
4106 });
4107 }
4108
4109
4110 // TODO: test obfuscated_get_peers
4111
4112 #else
TORRENT_TEST(dht)4113 TORRENT_TEST(dht)
4114 {
4115 // dummy dht test
4116 TEST_CHECK(true);
4117 }
4118
4119 #endif
4120