From 1e1f4dd40b8a32f59da6945b427e76edf1834d5e Mon Sep 17 00:00:00 2001 From: dr7ana Date: Tue, 12 Dec 2023 07:45:38 -0800 Subject: [PATCH] come on already work already --- llarp/bootstrap.cpp | 4 +-- llarp/bootstrap.hpp | 6 ++-- llarp/link/link_manager.cpp | 53 +++++++++++++++++------------- llarp/link/link_manager.hpp | 12 ++----- llarp/nodedb.cpp | 40 ++++++++++++++++------- llarp/nodedb.hpp | 36 +++++++++++++++++---- llarp/router/router.cpp | 46 +++++++++++--------------- llarp/router_contact.cpp | 57 +++++++++++++++++---------------- llarp/router_contact_remote.cpp | 1 - 9 files changed, 142 insertions(+), 113 deletions(-) diff --git a/llarp/bootstrap.cpp b/llarp/bootstrap.cpp index 3100eada6..b5f35c605 100644 --- a/llarp/bootstrap.cpp +++ b/llarp/bootstrap.cpp @@ -26,7 +26,7 @@ namespace llarp } bool - BootstrapList::contains(const RouterID& rid) + BootstrapList::contains(const RouterID& rid) const { for (const auto& it : *this) { @@ -38,7 +38,7 @@ namespace llarp } bool - BootstrapList::contains(const RemoteRC& rc) + BootstrapList::contains(const RemoteRC& rc) const { return count(rc); } diff --git a/llarp/bootstrap.hpp b/llarp/bootstrap.hpp index 472406861..b2cad4205 100644 --- a/llarp/bootstrap.hpp +++ b/llarp/bootstrap.hpp @@ -12,7 +12,7 @@ namespace llarp { struct BootstrapList final : public std::set { - std::set::iterator _curr; + std::set::iterator _curr = begin(); const RemoteRC& current() @@ -30,7 +30,7 @@ namespace llarp read_from_file(const fs::path& fpath); bool - contains(const RouterID& rid); + contains(const RouterID& rid) const; // returns a reference to the next index and a boolean that equals true if // this is the front of the set @@ -46,7 +46,7 @@ namespace llarp } bool - contains(const RemoteRC& rc); + contains(const RemoteRC& rc) const; void randomize() diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index f1dff5b44..71137e381 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -178,12 +178,13 @@ namespace llarp bool result = false; RouterID other{key.data()}; - if (auto itr = rids_pending_verification.find(other); itr != rids_pending_verification.end()) - { - verified_rids[other] = itr->second; - rids_pending_verification.erase(itr); - result = true; - } + // if (auto itr = rids_pending_verification.find(other); itr != + // rids_pending_verification.end()) + // { + // verified_rids[other] = itr->second; + // rids_pending_verification.erase(itr); + // result = true; + // } if (_router.node_db()->has_rc(other)) result = true; @@ -254,7 +255,8 @@ namespace llarp if (func) { func = [this, f = std::move(func)](oxen::quic::message m) mutable { - _router.loop()->call([func = std::move(f), msg = std::move(m)]() mutable { func(std::move(msg)); }); + _router.loop()->call( + [func = std::move(f), msg = std::move(m)]() mutable { func(std::move(msg)); }); }; } @@ -358,12 +360,12 @@ namespace llarp const auto& remote_addr = rc.addr(); const auto& rid = rc.router_id(); - rids_pending_verification[rid] = rc; + // rids_pending_verification[rid] = rc; // TODO: confirm remote end is using the expected pubkey (RouterID). // TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation) if (auto rv = ep.establish_connection( - oxen::quic::RemoteAddress{rc.router_id().ToView(), remote_addr}, + oxen::quic::RemoteAddress{rid.ToView(), remote_addr}, rc, std::move(on_open), std::move(on_close)); @@ -391,6 +393,7 @@ namespace llarp logcat, "BTRequestStream closed unexpectedly (ec:{}); closing connection...", error_code); s.conn.close_connection(error_code); }); + register_commands(control_stream); itr->second = std::make_shared(ci.shared_from_this(), control_stream, rc); log::critical(logcat, "Successfully configured inbound connection fom {}; storing RC...", rid); @@ -460,9 +463,10 @@ namespace llarp { const auto& rid = c_itr->second; - if (auto maybe = rids_pending_verification.find(rid); - maybe != rids_pending_verification.end()) - rids_pending_verification.erase(maybe); + // if (auto maybe = rids_pending_verification.find(rid); + // maybe != rids_pending_verification.end()) + // rids_pending_verification.erase(maybe); + // in case this didn't clear earlier, do it now if (auto p_itr = pending_conn_msg_queue.find(rid); p_itr != pending_conn_msg_queue.end()) pending_conn_msg_queue.erase(p_itr); @@ -665,14 +669,14 @@ namespace llarp return; } - node_db->put_rc(remote); + auto is_seed = _router.is_bootstrap_seed(); - auto& bootstraps = node_db->bootstrap_list(); - auto count = bootstraps.size(); + auto& src = is_seed ? node_db->bootstrap_seeds() : node_db->get_known_rcs(); + auto count = src.size(); if (count == 0) { - log::error(logcat, "No bootstraps locally to send!"); + log::error(logcat, "No {} locally to send!", is_seed ? "bootstrap seeds" : "known RCs"); m.respond(messages::ERROR_RESPONSE, true); return; } @@ -685,18 +689,21 @@ namespace llarp { auto sublist = btdp.append_list("rcs"); - while (i < quantity) + for (const auto& rc : src) { - auto& next_rc = bootstraps.next(); + if (not rc.is_expired(now)) + sublist.append_encoded(rc.view()); - if (next_rc.is_expired(now)) - continue; - - sublist.append_encoded(next_rc.view()); - ++i; + if (++i >= quantity) + break; } } + if (is_seed) + node_db->bootstrap_seeds().insert(remote); + else + node_db->put_rc(remote); + m.respond(std::move(btdp).str()); } diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index b97a6c7a9..e8b9c9431 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -181,7 +181,7 @@ namespace llarp // when establishing a connection, the rid of the remote is placed here to be cross- // checked by the tls verification callback std::map rids_pending_verification; - // in the interim of verifying an inbound connection and the creation of its link::Connection + // in the interim of verifying an outbound connection and the creation of its link::Connection // object, we store the rid and rc here std::map verified_rids; @@ -354,18 +354,9 @@ namespace llarp {"find_name"sv, &LinkManager::handle_find_name}, {"publish_intro"sv, &LinkManager::handle_publish_intro}, {"find_intro"sv, &LinkManager::handle_find_intro}}; - /* - {"path_confirm", &LinkManager::handle_path_confirm}, - {"path_latency", &LinkManager::handle_path_latency}, - {"update_exit", &LinkManager::handle_update_exit}, - {"obtain_exit", &LinkManager::handle_obtain_exit}, - {"close_exit", &LinkManager::handle_close_exit}, - {"convo_intro", &LinkManager::handle_convo_intro}}; - */ // these requests are direct, i.e. not over a path; // the rest are relay->relay - // TODO: new RC fetch endpoint (which will be both client->relay and relay->relay) std::unordered_map< std::string_view, void (LinkManager::*)(std::string_view body, std::function respond)> @@ -431,6 +422,7 @@ namespace llarp s.conn.close_connection(error_code); }); + link_manager.register_commands(control_stream); itr->second = std::make_shared(conn_interface, control_stream, rc); return true; diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index b67069e47..674af63d3 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -192,15 +192,10 @@ namespace llarp } void - NodeDB::set_bootstrap_routers(std::unique_ptr from_router) + NodeDB::set_bootstrap_routers(BootstrapList from_router) { - // TODO: if this needs to be called more than once (ex: drastic failures), then - // change this assert to a bootstraps.clear() call - if (_bootstraps) - assert(_bootstraps->empty()); - - _bootstraps = std::move(from_router); - _bootstraps->randomize(); + _bootstraps.merge(from_router); + _bootstraps.randomize(); } bool @@ -610,6 +605,8 @@ namespace llarp if (_router.is_service_node()) { _needs_rebootstrap = false; + _needs_initial_fetch = false; + _using_bootstrap_fallback = false; fail_sources.clear(); fetch_failures = 0; return; @@ -627,6 +624,7 @@ namespace llarp _router.last_rid_fetch = llarp::time_point_now(); fetch_counters.clear(); _needs_rebootstrap = false; + _using_bootstrap_fallback = false; if (initial) { @@ -638,6 +636,7 @@ namespace llarp void NodeDB::fallback_to_bootstrap() { + log::critical(logcat, "{} called", __PRETTY_FUNCTION__); auto at_max_failures = bootstrap_attempts >= MAX_BOOTSTRAP_FETCH_ATTEMPTS; // base case: we have failed to query all bootstraps, or we received a sample of @@ -660,7 +659,7 @@ namespace llarp return; } - auto rc = _bootstraps->next(); + auto rc = (_using_bootstrap_fallback) ? _bootstraps.next() : _bootstraps.current(); fetch_source = rc.router_id(); } @@ -669,8 +668,10 @@ namespace llarp _needs_rebootstrap = false; ++bootstrap_attempts; + log::critical(logcat, "Dispatching BootstrapRC fetch request to {}", _bootstraps.current().view()); + _router.link_manager().fetch_bootstrap_rcs( - _bootstraps->current(), + _bootstraps.current(), BootstrapFetchMessage::serialize(_router.router_contact, BOOTSTRAP_SOURCE_COUNT), [this](oxen::quic::message m) mutable { if (not m) @@ -723,7 +724,7 @@ namespace llarp if (rids.size() == BOOTSTRAP_SOURCE_COUNT) { - known_rids.swap(rids); + known_rids.merge(rids); fetch_initial(); } else @@ -745,6 +746,7 @@ namespace llarp NodeDB::bootstrap_cooldown() { _needs_rebootstrap = true; + _using_bootstrap_fallback = false; _router.next_bootstrap_attempt = llarp::time_point_now() + BOOTSTRAP_COOLDOWN; } @@ -792,7 +794,7 @@ namespace llarp NodeDB::is_connection_allowed(const RouterID& remote) const { if (_pinned_edges.size() && _pinned_edges.count(remote) == 0 - && not _bootstraps->contains(remote)) + && not _bootstraps.contains(remote)) return false; if (not _router.is_service_node()) @@ -810,6 +812,20 @@ namespace llarp return true; } + void + NodeDB::store_bootstraps() + { + if (_bootstraps.empty()) + return; + + for (const auto& rc : _bootstraps) + { + put_rc(rc); + } + + log::critical(logcat, "NodeDB populated with {} routers", num_rcs()); + } + void NodeDB::load_from_disk() { diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index eb595fec9..db1b98ef5 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -121,6 +121,9 @@ namespace llarp the unknown_rids container - rc_lookup: holds all the same rc's as known_rcs, but can be used to look them up by their rid + - bootstrap_seeds: if we are the seed node, we insert the rc's of bootstrap fetch requests + senders into this container to "introduce" them to each other + - _bootstraps: the standard container for bootstrap RemoteRCs */ std::set known_rids; std::set> unconfirmed_rids; @@ -130,6 +133,9 @@ namespace llarp std::map rc_lookup; + std::set _bootstrap_seeds; + BootstrapList _bootstraps{}; + /** RouterID lists // TODO: get rid of all these, replace with better decom/not staked sets - white: active routers - gray: fully funded, but decommissioned routers @@ -178,8 +184,6 @@ namespace llarp fs::path get_path_by_pubkey(RouterID pk) const; - std::unique_ptr _bootstraps{}; - public: explicit NodeDB( fs::path rootdir, std::function)> diskCaller, Router* r); @@ -214,6 +218,9 @@ namespace llarp return _needs_rebootstrap; } + void + ingest_bootstrap_seed(); + bool ingest_fetched_rcs(std::set rcs, rc_time timestamp); @@ -299,32 +306,47 @@ namespace llarp return _pinned_edges; } + void + store_bootstraps(); + size_t num_bootstraps() const { - return _bootstraps ? _bootstraps->size() : 0; + return _bootstraps.size(); } bool has_bootstraps() const { - return _bootstraps ? _bootstraps->empty() : false; + return _bootstraps.empty(); } const BootstrapList& bootstrap_list() const { - return *_bootstraps; + return _bootstraps; } BootstrapList& bootstrap_list() { - return *_bootstraps; + return _bootstraps; + } + + const std::set& + bootstrap_seeds() const + { + return _bootstrap_seeds; + } + + std::set& + bootstrap_seeds() + { + return _bootstrap_seeds; } void - set_bootstrap_routers(std::unique_ptr from_router); + set_bootstrap_routers(BootstrapList from_router); const std::set& whitelist() const diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index a700aaf9c..426e8397a 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -631,17 +631,18 @@ namespace llarp configRouters.push_back(defaultBootstrapFile); } - auto _bootstrap_rc_list = std::make_unique(); + BootstrapList _bootstrap_rc_list; auto clear_bad_rcs = [&]() mutable { + log::critical(logcat, "Clearing bad RCs..."); // in case someone has an old bootstrap file and is trying to use a bootstrap // that no longer exists - for (auto it = _bootstrap_rc_list->begin(); it != _bootstrap_rc_list->end();) + for (auto it = _bootstrap_rc_list.begin(); it != _bootstrap_rc_list.end();) { if (it->is_obsolete_bootstrap()) - log::warning(logcat, "ignoring obsolete bootstrap RC: {}", it->router_id()); + log::critical(logcat, "ignoring obsolete bootstrap RC: {}", it->router_id()); else if (not it->verify()) - log::warning(logcat, "ignoring invalid bootstrap RC: {}", it->router_id()); + log::critical(logcat, "ignoring invalid bootstrap RC: {}", it->router_id()); else { ++it; @@ -649,29 +650,27 @@ namespace llarp } // we are in one of the above error cases that we warned about: - it = _bootstrap_rc_list->erase(it); + it = _bootstrap_rc_list.erase(it); } }; for (const auto& router : configRouters) { log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile); - _bootstrap_rc_list->read_from_file(router); + _bootstrap_rc_list.read_from_file(router); } for (const auto& rc : conf.bootstrap.routers) { - _bootstrap_rc_list->emplace(rc); + _bootstrap_rc_list.emplace(rc); } - clear_bad_rcs(); - _bootstrap_seed = conf.bootstrap.seednode; if (_bootstrap_seed) log::critical(logcat, "We are a bootstrap seed node!"); - if (_bootstrap_rc_list->empty() and not _bootstrap_seed) + if (_bootstrap_rc_list.empty() and not _bootstrap_seed) { log::warning(logcat, "Warning: bootstrap list is empty and we are not a seed node"); @@ -679,10 +678,10 @@ namespace llarp if (auto itr = fallbacks.find(RouterContact::ACTIVE_NETID); itr != fallbacks.end()) { - _bootstrap_rc_list->merge(itr->second); + _bootstrap_rc_list.merge(itr->second); } - if (_bootstrap_rc_list->empty()) + if (_bootstrap_rc_list.empty()) { // empty after trying fallback, if set log::error( @@ -694,12 +693,12 @@ namespace llarp throw std::runtime_error("No bootstrap nodes available."); } - log::info( - logcat, "Loaded {} default fallback bootstrap routers!", _bootstrap_rc_list->size()); - clear_bad_rcs(); + log::critical( + logcat, "Loaded {} default fallback bootstrap routers!", _bootstrap_rc_list.size()); } - log::critical(logcat, "We have {} bootstrap routers!", _bootstrap_rc_list->size()); + clear_bad_rcs(); + log::critical(logcat, "We have {} bootstrap routers!", _bootstrap_rc_list.size()); node_db()->set_bootstrap_routers(std::move(_bootstrap_rc_list)); @@ -1140,21 +1139,11 @@ namespace llarp log::info(logcat, "Loading NodeDB from disk..."); _node_db->load_from_disk(); + _node_db->store_bootstraps(); log::info(logcat, "Creating Introset Contacts..."); _contacts = std::make_unique(*this); - if (_node_db->has_bootstraps()) - { - for (const auto& rc : _node_db->bootstrap_list()) - { - node_db()->put_rc(rc); - log::info(logcat, "Added bootstrap node (rid: {})", rc.router_id()); - } - - log::info(logcat, "Router populated NodeDB with {} routers", _node_db->num_rcs()); - } - _loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); }); _route_poker->start(); @@ -1163,7 +1152,7 @@ namespace llarp _started_at = now(); - if (is_service_node()) + if (is_service_node() and not _testing_disabled) { // do service node testing if we are in service node whitelist mode _loop->call_every(consensus::REACHABILITY_TESTING_TIMER_INTERVAL, weak_from_this(), [this] { @@ -1225,6 +1214,7 @@ namespace llarp } }); } + llarp::sys::service_manager->ready(); return is_running; } diff --git a/llarp/router_contact.cpp b/llarp/router_contact.cpp index dbb57d2da..b660c7990 100644 --- a/llarp/router_contact.cpp +++ b/llarp/router_contact.cpp @@ -17,45 +17,55 @@ namespace llarp if (int rc_ver = data.require(""); rc_ver != RC_VERSION) throw std::runtime_error{"Invalid RC: do not know how to parse v{} RCs"_format(rc_ver)}; - auto ipv4_port = data.require("4"); + auto addr_key = data.key(); + bool addr_set = false; - if (ipv4_port.size() != 6) - throw std::runtime_error{ - "Invalid RC address: expected 6-byte IPv4 IP/port, got {}"_format(ipv4_port.size())}; - - sockaddr_in s4; - s4.sin_family = AF_INET; + if (addr_key == "4") + { + auto ipv4_port = data.consume(); - std::memcpy(&s4.sin_addr.s_addr, ipv4_port.data(), 4); - std::memcpy(&s4.sin_port, ipv4_port.data() + 4, 2); + if (ipv4_port.size() != 6) + throw std::runtime_error{ + "Invalid RC address: expected 6-byte IPv4 IP/port, got {}"_format(ipv4_port.size())}; - _addr = oxen::quic::Address{&s4}; + sockaddr_in s4; + s4.sin_family = AF_INET; - if (!_addr.is_public()) - throw std::runtime_error{"Invalid RC: IPv4 address is not a publicly routable IP"}; + std::memcpy(&s4.sin_addr.s_addr, ipv4_port.data(), 4); + std::memcpy(&s4.sin_port, ipv4_port.data() + 4, 2); - if (auto ipv6_port = data.maybe("6")) + _addr = oxen::quic::Address{&s4}; + // advance in case ipv4 and ipv6 are included + addr_key = data.key(); + addr_set = true; + } + if (addr_key == "6") { - if (ipv6_port->size() != 18) + auto ipv6_port = data.consume(); + + if (ipv6_port.size() != 18) throw std::runtime_error{ - "Invalid RC address: expected 18-byte IPv6 IP/port, got {}"_format(ipv6_port->size())}; + "Invalid RC address: expected 18-byte IPv6 IP/port, got {}"_format(ipv6_port.size())}; sockaddr_in6 s6{}; s6.sin6_family = AF_INET6; - std::memcpy(&s6.sin6_addr.s6_addr, ipv6_port->data(), 16); - std::memcpy(&s6.sin6_port, ipv6_port->data() + 16, 2); + std::memcpy(&s6.sin6_addr.s6_addr, ipv6_port.data(), 16); + std::memcpy(&s6.sin6_port, ipv6_port.data() + 16, 2); _addr6.emplace(&s6); + if (!_addr6->is_public()) throw std::runtime_error{"Invalid RC: IPv6 address is not a publicly routable IP"}; } else - { _addr6.reset(); - } + + if (not addr_set) + throw std::runtime_error{"Invalid RC: could not discern ipv4 vs ipv6 in payload"}; auto netid = data.maybe("i").value_or(llarp::LOKINET_DEFAULT_NETID); + if (netid != ACTIVE_NETID) throw std::runtime_error{ "Invalid RC netid: expected {}, got {}; this is an RC for a different network!"_format( @@ -67,14 +77,7 @@ namespace llarp "Invalid RC pubkey: expected 32 bytes, got {}"_format(pubkey.size())}; std::memcpy(_router_id.data(), pubkey.data(), 32); - // auto pk = data.require("p"); - - // if (pk.size() != RouterID::SIZE) - // throw std::runtime_error{"Invalid RC: router id has invalid size {}"_format(pk.size())}; - - // std::memcpy(_router_id.data(), pk.data(), RouterID::SIZE); - - _timestamp = rc_time{std::chrono::seconds{data.require("t")}}; + _timestamp = rc_time{std::chrono::seconds{data.require("t")}}; auto ver = data.require("v"); diff --git a/llarp/router_contact_remote.cpp b/llarp/router_contact_remote.cpp index 857d2f4a6..ef405662b 100644 --- a/llarp/router_contact_remote.cpp +++ b/llarp/router_contact_remote.cpp @@ -16,7 +16,6 @@ namespace llarp try { bt_load(btdc); - bt_verify(btdc, /*reject_expired=*/true); } catch (const std::exception& e)