From ad9d0b19c1303447102541a43aaa4822dc1acc89 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 14 Nov 2023 21:53:19 -0500 Subject: [PATCH] remove rc_lookup_handler, relocating useful parts RC "lookup" is being replaced with "gimme all recently updated RCs". As such, doing a lookup on a specific RC is going away, as is network exploration, so a lot of what RCLookupHandler was doing will no longer be relevant. Functionality from it which was kept has moved to NodeDB, as it makes sense for that functionality to live where the RCs live. --- llarp/CMakeLists.txt | 1 - llarp/handlers/exit.cpp | 16 +- llarp/handlers/tun.cpp | 12 +- llarp/link/link_manager.cpp | 78 ++++--- llarp/link/link_manager.hpp | 11 +- llarp/nodedb.cpp | 77 ++++++- llarp/nodedb.hpp | 78 +++++++ llarp/path/pathbuilder.cpp | 25 -- llarp/router/rc_lookup_handler.cpp | 357 ----------------------------- llarp/router/rc_lookup_handler.hpp | 143 ------------ llarp/router/router.cpp | 72 +++--- llarp/router/router.hpp | 20 +- 12 files changed, 247 insertions(+), 643 deletions(-) delete mode 100644 llarp/router/rc_lookup_handler.cpp delete mode 100644 llarp/router/rc_lookup_handler.hpp diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 8d1dd9e35..e7e06d0fe 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -109,7 +109,6 @@ lokinet_add_library(lokinet-time-place # lokinet-platform holds all platform specific code lokinet_add_library(lokinet-platform net/interface_info.cpp - router/rc_lookup_handler.cpp vpn/packet_router.cpp vpn/platform.cpp ) diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 64f07d001..ffab0a37c 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -2,8 +2,8 @@ #include #include +#include #include -#include #include #include @@ -243,9 +243,8 @@ namespace llarp::handlers { if (msg.questions[0].IsName("random.snode")) { - RouterID random; - if (GetRouter()->GetRandomGoodRouter(random)) - msg.AddCNAMEReply(random.ToString(), 1); + if (auto random = GetRouter()->GetRandomGoodRouter()) + msg.AddCNAMEReply(random->ToString(), 1); else msg.AddNXReply(); } @@ -263,11 +262,10 @@ namespace llarp::handlers const bool isV4 = msg.questions[0].qtype == dns::qTypeA; if (msg.questions[0].IsName("random.snode")) { - RouterID random; - if (GetRouter()->GetRandomGoodRouter(random)) + if (auto random = GetRouter()->GetRandomGoodRouter()) { - msg.AddCNAMEReply(random.ToString(), 1); - auto ip = ObtainServiceNodeIP(random); + msg.AddCNAMEReply(random->ToString(), 1); + auto ip = ObtainServiceNodeIP(*random); msg.AddINReply(ip, false); } else @@ -333,7 +331,7 @@ namespace llarp::handlers void ExitEndpoint::ObtainSNodeSession(const RouterID& rid, exit::SessionReadyFunc obtain_cb) { - if (not router->rc_lookup_handler().is_session_allowed(rid)) + if (not router->node_db()->is_connection_allowed(rid)) { obtain_cb(nullptr); return; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index ad288017b..fec8b8187 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -705,10 +705,9 @@ namespace llarp::handlers { if (is_random_snode(msg)) { - RouterID random; - if (router()->GetRandomGoodRouter(random)) + if (auto random = router()->GetRandomGoodRouter()) { - msg.AddCNAMEReply(random.ToString(), 1); + msg.AddCNAMEReply(random->ToString(), 1); } else msg.AddNXReply(); @@ -755,11 +754,10 @@ namespace llarp::handlers // on MacOS this is a typeA query else if (is_random_snode(msg)) { - RouterID random; - if (router()->GetRandomGoodRouter(random)) + if (auto random = router()->GetRandomGoodRouter()) { - msg.AddCNAMEReply(random.ToString(), 1); - return ReplyToSNodeDNSWhenReady(random, std::make_shared(msg), isV6); + msg.AddCNAMEReply(random->ToString(), 1); + return ReplyToSNodeDNSWhenReady(*random, std::make_shared(msg), isV6); } msg.AddNXReply(); diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 6c6a10c48..175f85ee3 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -243,21 +242,17 @@ namespace llarp return true; } - _router.loop()->call([this, remote, endpoint, body, f = std::move(func)]() { - auto pending = PendingControlMessage(body, endpoint, f); + _router.loop()->call([this, + remote, + endpoint = std::move(endpoint), + body = std::move(body), + f = std::move(func)]() { + auto pending = PendingControlMessage(std::move(body), std::move(endpoint), f); auto [itr, b] = pending_conn_msg_queue.emplace(remote, MessageQueue()); itr->second.push_back(std::move(pending)); - rc_lookup->get_rc(remote, [this]([[maybe_unused]] auto rid, auto rc, auto success) { - if (success) - { - _router.node_db()->put_rc_if_newer(*rc); - connect_to(*rc); - } - else - log::warning(quic_cat, "Do something intelligent here for error handling"); - }); + connect_to(remote); }); return false; @@ -275,21 +270,13 @@ namespace llarp return true; } - _router.loop()->call([&]() { + _router.loop()->call([this, body = std::move(body), remote]() { auto pending = PendingDataMessage(body); auto [itr, b] = pending_conn_msg_queue.emplace(remote, MessageQueue()); itr->second.push_back(std::move(pending)); - rc_lookup->get_rc(remote, [this]([[maybe_unused]] auto rid, auto rc, auto success) { - if (success) - { - _router.node_db()->put_rc_if_newer(*rc); - connect_to(*rc); - } - else - log::warning(quic_cat, "Do something intelligent here for error handling"); - }); + connect_to(remote); }); return false; @@ -304,15 +291,13 @@ namespace llarp void LinkManager::connect_to(const RouterID& rid) { - rc_lookup->get_rc(rid, [this]([[maybe_unused]] auto rid, auto rc, auto success) { - if (success) - { - _router.node_db()->put_rc_if_newer(*rc); - connect_to(*rc); - } - else - log::warning(quic_cat, "Do something intelligent here for error handling"); - }); + auto rc = node_db->get_rc(rid); + if (rc) + { + connect_to(*rc); + } + else + log::warning(quic_cat, "Do something intelligent here for error handling"); } // This function assumes the RC has already had its signature verified and connection is allowed. @@ -400,6 +385,27 @@ namespace llarp }); } + void + LinkManager::gossip_rc(const RemoteRC& rc) + { + for (auto& [rid, conn] : ep.conns) + send_control_message(rid, "gossip_rc", std::string{rc.view()}, nullptr); + } + + void + LinkManager::handle_gossip_rc(oxen::quic::message m) + { + try + { + RemoteRC rc{m.body()}; + } + catch (const std::exception& e) + { + log::info(link_cat, "Recieved invalid RC, dropping on the floor."); + return; + } + } + bool LinkManager::have_connection_to(const RouterID& remote, bool client_only) const { @@ -486,10 +492,9 @@ namespace llarp } void - LinkManager::init(RCLookupHandler* rcLookup) + LinkManager::init() { is_stopping = false; - rc_lookup = rcLookup; node_db = _router.node_db(); } @@ -509,7 +514,7 @@ namespace llarp { exclude.insert(maybe_other->router_id()); - if (not rc_lookup->is_session_allowed(maybe_other->router_id())) + if (not node_db->is_connection_allowed(maybe_other->router_id())) continue; connect_to(*maybe_other); @@ -630,8 +635,9 @@ namespace llarp { std::string neighbors{}; - const auto closest_rcs = - _router.node_db()->find_many_closest_to(target_addr, RC_LOOKUP_STORAGE_REDUNDANCY); + // TODO: constant replaced with 4 (what the constant it referred to was) for compilation, + // pending removal + const auto closest_rcs = _router.node_db()->find_many_closest_to(target_addr, 4); for (const auto& rc : closest_rcs) { diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index 1f05c8c3b..4efda035a 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -27,6 +26,7 @@ namespace namespace llarp { struct LinkManager; + struct NodeDB; namespace link { @@ -176,7 +176,6 @@ namespace llarp util::DecayingHashSet clients{path::DEFAULT_LIFETIME}; - RCLookupHandler* rc_lookup; std::shared_ptr node_db; oxen::quic::Address addr; @@ -221,6 +220,12 @@ namespace llarp return addr; } + void + gossip_rc(const RemoteRC& rc); + + void + handle_gossip_rc(oxen::quic::message m); + bool have_connection_to(const RouterID& remote, bool client_only = false) const; @@ -261,7 +266,7 @@ namespace llarp extract_status() const; void - init(RCLookupHandler* rcLookup); + init(); void for_each_connection(std::function func); diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index a5955003d..7207a2b0d 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -99,6 +99,73 @@ namespace llarp return m_Root / skiplistDir / fname; } + void + NodeDB::set_bootstrap_routers(const std::set& rcs) + { + bootstraps.clear(); // this function really shouldn't be called more than once, but... + for (const auto& rc : rcs) + bootstraps.emplace(rc.router_id(), rc); + } + + void + NodeDB::set_router_whitelist( + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist) + { + if (whitelist.empty()) + return; + + registered_routers.clear(); + registered_routers.insert(whitelist.begin(), whitelist.end()); + registered_routers.insert(greylist.begin(), greylist.end()); + registered_routers.insert(greenlist.begin(), greenlist.end()); + + router_whitelist.clear(); + router_whitelist.insert(whitelist.begin(), whitelist.end()); + router_greylist.clear(); + router_greylist.insert(greylist.begin(), greylist.end()); + router_greenlist.clear(); + router_greenlist.insert(greenlist.begin(), greenlist.end()); + + log::info( + logcat, "lokinet service node list now has ", router_whitelist.size(), " active routers"); + } + + std::optional + NodeDB::get_random_whitelist_router() const + { + const auto sz = router_whitelist.size(); + if (sz == 0) + return std::nullopt; + auto itr = router_whitelist.begin(); + if (sz > 1) + std::advance(itr, randint() % sz); + return *itr; + } + + bool + NodeDB::is_connection_allowed(const RouterID& remote) const + { + if (pinned_edges.size() && pinned_edges.count(remote) == 0 && !bootstraps.count(remote)) + { + return false; + } + + if (not router.is_service_node()) + return true; + + return router_whitelist.count(remote) or router_greylist.count(remote); + } + + bool + NodeDB::is_first_hop_allowed(const RouterID& remote) const + { + if (pinned_edges.size() && pinned_edges.count(remote) == 0) + return false; + return true; + } + void NodeDB::load_from_disk() { @@ -180,14 +247,12 @@ namespace llarp std::optional NodeDB::get_rc(RouterID pk) const { - return router.loop()->call_get([this, pk]() -> std::optional { - const auto itr = entries.find(pk); + const auto itr = entries.find(pk); - if (itr == entries.end()) - return std::nullopt; + if (itr == entries.end()) + return std::nullopt; - return itr->second.rc; - }); + return itr->second.rc; } void diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 7552fc6fd..7d7c088eb 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -49,7 +49,85 @@ namespace llarp fs::path get_path_by_pubkey(RouterID pk) const; + std::unordered_map bootstraps; + + // whitelist = active routers + std::unordered_set router_whitelist; + // greylist = fully funded, but decommissioned routers + std::unordered_set router_greylist; + // greenlist = registered but not fully-staked routers + std::unordered_set router_greenlist; + + // all registered relays (snodes) + std::unordered_set registered_routers; + + // only ever use to specific edges as path first-hops + std::unordered_set pinned_edges; + public: + void + set_bootstrap_routers(const std::set& rcs); + + const std::unordered_set& + whitelist() const + { + return router_whitelist; + } + + const std::unordered_set& + greylist() const + { + return router_greylist; + } + + const std::unordered_set& + get_registered_routers() const + { + return registered_routers; + } + + void + set_router_whitelist( + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist); + + std::optional + get_random_whitelist_router() const; + + // client: + // if pinned edges were specified, connections are allowed only to those and + // to the configured bootstrap nodes. otherwise, always allow. + // + // relay: + // outgoing connections are allowed only to other registered, funded relays + // (whitelist and greylist, respectively). + bool + is_connection_allowed(const RouterID& remote) const; + + // client: + // same as is_connection_allowed + // + // server: + // we only build new paths through registered, not decommissioned relays + // (i.e. whitelist) + bool + is_path_allowed(const RouterID& remote) const + { + return router_whitelist.count(remote); + } + + // if pinned edges were specified, the remote must be in that set, else any remote + // is allowed as first hop. + bool + is_first_hop_allowed(const RouterID& remote) const; + + const std::unordered_set& + get_pinned_edges() const + { + return pinned_edges; + } + explicit NodeDB( fs::path rootdir, std::function)> diskCaller, Router* r); diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index 2f51e5fae..49b080cd0 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -575,30 +574,6 @@ namespace llarp router->router_profiling().MarkPathTimeout(p.get()); PathSet::HandlePathBuildTimeout(p); DoPathBuildBackoff(); - for (const auto& hop : p->hops) - { - const auto& target = hop.rc.router_id(); - // look up router and see if it's still on the network - log::info(path_cat, "Looking up RouterID {} due to path build timeout", target); - - router->rc_lookup_handler().get_rc( - target, - [this](auto rid, auto rc, auto success) { - if (success && rc) - { - log::info(path_cat, "Refreshed RouterContact for {}", rid); - router->node_db()->put_rc_if_newer(*rc); - } - else - { - // remove all connections to this router as it's probably not registered anymore - log::warning(path_cat, "Removing router {} due to path build timeout", rid); - router->link_manager().deregister_peer(rid); - router->node_db()->remove_router(rid); - } - }, - true); - } } void diff --git a/llarp/router/rc_lookup_handler.cpp b/llarp/router/rc_lookup_handler.cpp deleted file mode 100644 index c2df0c833..000000000 --- a/llarp/router/rc_lookup_handler.cpp +++ /dev/null @@ -1,357 +0,0 @@ -#include "rc_lookup_handler.hpp" - -#include "router.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace llarp -{ - void - RCLookupHandler::add_valid_router(const RouterID& rid) - { - router->loop()->call([this, rid]() { router_whitelist.insert(rid); }); - } - - void - RCLookupHandler::remove_valid_router(const RouterID& rid) - { - router->loop()->call([this, rid]() { router_whitelist.erase(rid); }); - } - - static void - loadColourList(std::unordered_set& beigelist, const std::vector& new_beige) - { - beigelist.clear(); - beigelist.insert(new_beige.begin(), new_beige.end()); - } - - void - RCLookupHandler::set_router_whitelist( - const std::vector& whitelist, - const std::vector& greylist, - const std::vector& greenlist) - { - if (whitelist.empty()) - return; - - router->loop()->call([this, whitelist, greylist, greenlist]() { - loadColourList(router_whitelist, whitelist); - loadColourList(router_greylist, greylist); - loadColourList(router_greenlist, greenlist); - LogInfo("lokinet service node list now has ", router_whitelist.size(), " active routers"); - }); - } - - bool - RCLookupHandler::has_received_whitelist() const - { - return router->loop()->call_get([this]() { return not router_whitelist.empty(); }); - } - - std::unordered_set - RCLookupHandler::whitelist() const - { - return router->loop()->call_get([this]() { return router_whitelist; }); - } - - void - RCLookupHandler::get_rc(const RouterID& rid, RCRequestCallback callback, bool forceLookup) - { - (void)rid; - (void)callback; - (void)forceLookup; - /* RC refactor pending, this will likely go away entirely - * - * - RemoteRC remoteRC; - - if (not forceLookup) - { - if (const auto maybe = node_db->get_rc(rid); maybe.has_value()) - { - remoteRC = *maybe; - - if (callback) - { - callback(rid, remoteRC, true); - } - - return; - } - } - - auto lookup_cb = [this, callback, rid](RemoteRC rc, bool success) mutable { - auto& r = link_manager->router(); - - if (not success) - { - if (callback) - callback(rid, std::nullopt, false); - return; - } - - r.node_db()->put_rc_if_newer(rc); - if (callback) - callback(rc.router_id(), rc, true); - }; - - // TODO: RC fetching and gossiping in general is being refactored, and the old method - // of look it up over a path or directly but using the same method but called - // differently is going away. It's a mess. The below will do a lookup via a path, - // relays will need a different implementation TBD. - if (!isServiceNode) - hidden_service_context->GetDefault()->lookup_router(rid, std::move(lookup_cb)); - */ - } - - bool - RCLookupHandler::is_grey_listed(const RouterID& remote) const - { - if (strict_connect_pubkeys.size() && strict_connect_pubkeys.count(remote) == 0 - && !is_remote_in_bootstrap(remote)) - { - return false; - } - - if (not isServiceNode) - return false; - - return router->loop()->call_get([this, remote]() { return router_greylist.count(remote); }); - } - - bool - RCLookupHandler::is_green_listed(const RouterID& remote) const - { - return router->loop()->call_get([this, remote]() { return router_greenlist.count(remote); }); - } - - bool - RCLookupHandler::is_registered(const RouterID& rid) const - { - return router->loop()->call_get([this, rid]() { - return router_whitelist.count(rid) || router_greylist.count(rid) - || router_greenlist.count(rid); - }); - } - - bool - RCLookupHandler::is_path_allowed(const RouterID& rid) const - { - return router->loop()->call_get([this, rid]() { - if (strict_connect_pubkeys.size() && strict_connect_pubkeys.count(rid) == 0 - && !is_remote_in_bootstrap(rid)) - { - return false; - } - - if (not isServiceNode) - return true; - - return router_whitelist.count(rid) != 0; - }); - } - - bool - RCLookupHandler::is_session_allowed(const RouterID& rid) const - { - return router->loop()->call_get([this, rid]() { - if (strict_connect_pubkeys.size() && strict_connect_pubkeys.count(rid) == 0 - && !is_remote_in_bootstrap(rid)) - { - return false; - } - - if (not isServiceNode) - return true; - - return router_whitelist.count(rid) or router_greylist.count(rid); - }); - } - - bool - RCLookupHandler::check_rc(const RemoteRC& rc) const - { - if (not is_session_allowed(rc.router_id())) - { - contacts->delete_rc_node_async(dht::Key_t{rc.router_id()}); - return false; - } - - if (not rc.verify()) - { - log::info(link_cat, "Invalid RC (rid: {})", rc.router_id()); - return false; - } - - // update nodedb if required - if (rc.is_public_router()) - { - log::info(link_cat, "Adding or updating RC (rid: {}) to nodeDB and DHT", rc.router_id()); - node_db->put_rc_if_newer(rc); - contacts->put_rc_node_async(rc); - } - - return true; - } - - size_t - RCLookupHandler::num_strict_connect_routers() const - { - return strict_connect_pubkeys.size(); - } - - bool - RCLookupHandler::get_random_whitelist_router(RouterID& rid) const - { - return router->loop()->call_get([this, rid]() mutable { - const auto sz = router_whitelist.size(); - auto itr = router_whitelist.begin(); - if (sz == 0) - return false; - if (sz > 1) - std::advance(itr, randint() % sz); - rid = *itr; - return true; - }); - } - - void - RCLookupHandler::periodic_update(llarp_time_t now) - { - // try looking up stale routers - std::unordered_set routersToLookUp; - - node_db->VisitInsertedBefore( - [&](const RouterContact& rc) { routersToLookUp.insert(rc.router_id()); }, - now - RouterContact::REPUBLISH); - - for (const auto& router : routersToLookUp) - { - get_rc(router, nullptr, true); - } - - node_db->remove_stale_rcs(boostrap_rid_list, now - RouterContact::STALE); - } - - void - RCLookupHandler::explore_network() - { - const size_t known = node_db->num_loaded(); - if (bootstrap_rc_list.empty() && known == 0) - { - LogError("we have no bootstrap nodes specified"); - } - else if (known <= bootstrap_rc_list.size()) - { - for (const auto& rc : bootstrap_rc_list) - { - const auto& rid = rc.router_id(); - log::info(link_cat, "Doing explore via bootstrap node: {}", rid); - - // TODO: replace this concept - // dht->ExploreNetworkVia(dht::Key_t{rc.pubkey}); - } - } - - if (isServiceNode) - { - static constexpr size_t LookupPerTick = 5; - - std::vector lookup_routers = router->loop()->call_get([this]() { - std::vector lookups; - lookups.reserve(LookupPerTick); - - for (const auto& r : router_whitelist) - { - if (not node_db->has_router(r)) - lookups.emplace_back(r); - } - - return lookups; - }); - - if (lookup_routers.size() > LookupPerTick) - { - std::shuffle(lookup_routers.begin(), lookup_routers.end(), llarp::csrng); - lookup_routers.resize(LookupPerTick); - } - - for (const auto& r : lookup_routers) - get_rc(r, nullptr, true); - return; - } - // service nodes gossip, not explore - if (contacts->router()->is_service_node()) - return; - - // explore via every connected peer - /* - * TODO: DHT explore via libquic - * - _linkManager->ForEachPeer([&](ILinkSession* s) { - if (!s->IsEstablished()) - return; - const RouterContact rc = s->GetRemoteRC(); - if (rc.IsPublicRouter() && (_bootstrapRCList.find(rc) == _bootstrapRCList.end())) - { - LogDebug("Doing explore via public node: ", RouterID(rc.pubkey)); - _dht->impl->ExploreNetworkVia(dht::Key_t{rc.pubkey}); - } - }); - * - * - */ - } - - void - RCLookupHandler::init( - std::shared_ptr c, - std::shared_ptr nodedb, - EventLoop_ptr l, - std::function)> dowork, - LinkManager* linkManager, - service::Context* hiddenServiceContext, - const std::unordered_set& strictConnectPubkeys, - const std::set& bootstrapRCList, - bool isServiceNode_arg) - { - contacts = c; - node_db = std::move(nodedb); - loop = std::move(l); - work_func = std::move(dowork); - hidden_service_context = hiddenServiceContext; - strict_connect_pubkeys = strictConnectPubkeys; - bootstrap_rc_list = bootstrapRCList; - link_manager = linkManager; - router = &link_manager->router(); - isServiceNode = isServiceNode_arg; - - for (const auto& rc : bootstrap_rc_list) - { - boostrap_rid_list.insert(rc.router_id()); - } - } - - bool - RCLookupHandler::is_remote_in_bootstrap(const RouterID& remote) const - { - for (const auto& rc : bootstrap_rc_list) - { - if (rc.router_id() == remote) - { - return true; - } - } - return false; - } - -} // namespace llarp diff --git a/llarp/router/rc_lookup_handler.hpp b/llarp/router/rc_lookup_handler.hpp deleted file mode 100644 index f7b3f01f4..000000000 --- a/llarp/router/rc_lookup_handler.hpp +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include - -struct llarp_dht_context; - -namespace llarp -{ - class NodeDB; - struct Router; - class EventLoop; - - namespace service - { - struct Context; - } // namespace service - - struct Contacts; - struct LinkManager; - - enum class RCRequestResult - { - Success, - InvalidRouter, - RouterNotFound, - BadRC - }; - - using RCRequestCallback = - std::function, bool success)>; - - struct RCLookupHandler - { - public: - ~RCLookupHandler() = default; - - void - add_valid_router(const RouterID& router); - - void - remove_valid_router(const RouterID& router); - - void - set_router_whitelist( - const std::vector& whitelist, - const std::vector& greylist, - const std::vector& greenlist); - - bool - has_received_whitelist() const; - - void - get_rc(const RouterID& router, RCRequestCallback callback, bool forceLookup = false); - - bool - is_path_allowed(const RouterID& remote) const; - - bool - is_session_allowed(const RouterID& remote) const; - - bool - is_grey_listed(const RouterID& remote) const; - - // "greenlist" = new routers (i.e. "green") that aren't fully funded yet - bool - is_green_listed(const RouterID& remote) const; - - // registered just means that there is at least an operator stake, but doesn't require the node - // be fully funded, active, or not decommed. (In other words: it is any of the white, grey, or - // green list). - bool - is_registered(const RouterID& remote) const; - - bool - check_rc(const RemoteRC& rc) const; - - bool - get_random_whitelist_router(RouterID& router) const; - - void - periodic_update(llarp_time_t now); - - void - explore_network(); - - size_t - num_strict_connect_routers() const; - - void - init( - std::shared_ptr contacts, - std::shared_ptr nodedb, - std::shared_ptr loop, - std::function)> dowork, - LinkManager* linkManager, - service::Context* hiddenServiceContext, - const std::unordered_set& strictConnectPubkeys, - const std::set& bootstrapRCList, - bool isServiceNode_arg); - - std::unordered_set - whitelist() const; - - private: - bool - is_remote_in_bootstrap(const RouterID& remote) const; - - std::shared_ptr contacts = nullptr; - std::shared_ptr node_db; - std::shared_ptr loop; - std::function)> work_func = nullptr; - service::Context* hidden_service_context = nullptr; - LinkManager* link_manager = nullptr; - Router* router; - - /// explicit whitelist of routers we will connect to directly (not for - /// service nodes) - std::unordered_set strict_connect_pubkeys; - - std::set bootstrap_rc_list; - std::unordered_set boostrap_rid_list; - - // Now that all calls are made through the event loop, any access to these - // booleans is not guarded by a mutex - std::atomic isServiceNode = false; - - // whitelist = active routers - std::unordered_set router_whitelist; - // greylist = fully funded, but decommissioned routers - std::unordered_set router_greylist; - // greenlist = registered but not fully-staked routers - std::unordered_set router_greenlist; - }; - -} // namespace llarp diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 6c4f51eac..56c1787cc 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -239,20 +239,19 @@ namespace llarp _rcGossiper.GossipRC(rc); } - bool - Router::GetRandomGoodRouter(RouterID& router) + std::optional + Router::GetRandomGoodRouter() { if (is_service_node()) { - return _rc_lookup_handler.get_random_whitelist_router(router); + return node_db()->get_random_whitelist_router(); } if (auto maybe = node_db()->GetRandom([](const auto&) -> bool { return true; })) { - router = maybe->router_id(); - return true; + return maybe->router_id(); } - return false; + return std::nullopt; } void @@ -479,25 +478,25 @@ namespace llarp bool Router::have_snode_whitelist() const { - return is_service_node() and _rc_lookup_handler.has_received_whitelist(); + return whitelist_received; } bool Router::appears_decommed() const { - return have_snode_whitelist() and _rc_lookup_handler.is_grey_listed(pubkey()); + return have_snode_whitelist() and node_db()->greylist().count(pubkey()); } bool Router::appears_funded() const { - return have_snode_whitelist() and _rc_lookup_handler.is_session_allowed(pubkey()); + return have_snode_whitelist() and node_db()->is_connection_allowed(pubkey()); } bool Router::appears_registered() const { - return have_snode_whitelist() and _rc_lookup_handler.is_registered(pubkey()); + return have_snode_whitelist() and node_db()->get_registered_routers().count(pubkey()); } bool @@ -509,7 +508,7 @@ namespace llarp bool Router::SessionToRouterAllowed(const RouterID& router) const { - return _rc_lookup_handler.is_session_allowed(router); + return node_db()->is_connection_allowed(router); } bool @@ -520,7 +519,7 @@ namespace llarp // we are decom'd don't allow any paths outbound at all return false; } - return _rc_lookup_handler.is_path_allowed(router); + return node_db()->is_path_allowed(router); } size_t @@ -679,23 +678,15 @@ namespace llarp it = bootstrap_rc_list.erase(it); } + node_db()->set_bootstrap_routers(bootstrap_rc_list); + if (conf.bootstrap.seednode) LogInfo("we are a seed node"); else LogInfo("Loaded ", bootstrap_rc_list.size(), " bootstrap routers"); // Init components after relevant config settings loaded - _link_manager.init(&_rc_lookup_handler); - _rc_lookup_handler.init( - _contacts, - _node_db, - _loop, - [this](std::function work) { queue_work(std::move(work)); }, - &_link_manager, - &_hidden_service_context, - strictConnectPubkeys, - bootstrap_rc_list, - _is_service_node); + _link_manager.init(); // FIXME: kludge for now, will be part of larger cleanup effort. if (_is_service_node) @@ -856,9 +847,6 @@ namespace llarp _rcGossiper.Decay(now); - _rc_lookup_handler.periodic_update(now); - - const bool has_whitelist = _rc_lookup_handler.has_received_whitelist(); const bool is_snode = is_service_node(); const bool is_decommed = appears_decommed(); bool should_gossip = appears_funded(); @@ -915,7 +903,7 @@ namespace llarp } // if we don't have the whitelist yet don't remove the entry - if (not has_whitelist) + if (not whitelist_received) { log::debug(logcat, "Skipping check on {}: don't have whitelist yet", rc.router_id()); return false; @@ -924,7 +912,7 @@ namespace llarp // the whitelist enabled and we got the whitelist // check against the whitelist and remove if it's not // in the whitelist OR if there is no whitelist don't remove - if (has_whitelist and not _rc_lookup_handler.is_session_allowed(rc.router_id())) + if (not node_db()->is_connection_allowed(rc.router_id())) { log::debug(logcat, "Removing {}: not a valid router", rc.router_id()); return true; @@ -932,7 +920,9 @@ namespace llarp return false; }); - if (not is_snode or not has_whitelist) + /* TODO: this behavior seems incorrect, but fixing it will require discussion + * + if (not is_snode or not whitelist_received) { // find all deregistered relays std::unordered_set close_peers; @@ -948,23 +938,18 @@ namespace llarp for (auto& peer : close_peers) _link_manager.deregister_peer(peer); } + */ _link_manager.check_persisting_conns(now); size_t connected = NumberOfConnectedRouters(); - const int interval = is_snode ? 5 : 2; - const auto timepoint_now = std::chrono::steady_clock::now(); - if (timepoint_now >= _next_explore_at and not is_decommed) - { - _rc_lookup_handler.explore_network(); - _next_explore_at = timepoint_now + std::chrono::seconds(interval); - } size_t connectToNum = _link_manager.min_connected_routers; - const auto strictConnect = _rc_lookup_handler.num_strict_connect_routers(); - if (strictConnect > 0 && connectToNum > strictConnect) + const auto& pinned_edges = _node_db->get_pinned_edges(); + const auto pinned_count = pinned_edges.size(); + if (pinned_count > 0 && connectToNum > pinned_count) { - connectToNum = strictConnect; + connectToNum = pinned_count; } if (is_snode and now >= _next_decomm_warning) @@ -1032,13 +1017,20 @@ namespace llarp return _link_manager.get_random_connected(result); } + std::unordered_set + Router::router_whitelist() const + { + return _node_db->whitelist(); + } + void Router::set_router_whitelist( const std::vector& whitelist, const std::vector& greylist, const std::vector& unfundedlist) { - _rc_lookup_handler.set_router_whitelist(whitelist, greylist, unfundedlist); + node_db()->set_router_whitelist(whitelist, greylist, unfundedlist); + whitelist_received = true; } bool diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 9a2973477..92b412acd 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -1,7 +1,6 @@ #pragma once #include "rc_gossiper.hpp" -#include "rc_lookup_handler.hpp" #include "route_poker.hpp" #include @@ -59,8 +58,6 @@ namespace llarp static constexpr size_t INTROSET_STORAGE_REDUNDANCY = (INTROSET_RELAY_REDUNDANCY * INTROSET_REQS_PER_RELAY); - static constexpr size_t RC_LOOKUP_STORAGE_REDUNDANCY{4}; - struct Contacts; struct Router : std::enable_shared_from_this @@ -122,12 +119,12 @@ namespace llarp const llarp_time_t _randomStartDelay; std::shared_ptr _rpc_client; + bool whitelist_received{false}; oxenmq::address rpc_addr; Profiling _router_profiling; fs::path _profile_file; LinkManager _link_manager{*this}; - RCLookupHandler _rc_lookup_handler; RCGossiper _rcGossiper; /// how often do we resign our RC? milliseconds. @@ -211,12 +208,6 @@ namespace llarp return _link_manager; } - RCLookupHandler& - rc_lookup_handler() - { - return _rc_lookup_handler; - } - inline int outbound_udp_socket() const { @@ -293,10 +284,7 @@ namespace llarp ExtractSummaryStatus() const; std::unordered_set - router_whitelist() const - { - return _rc_lookup_handler.whitelist(); - } + router_whitelist() const; void set_router_whitelist( @@ -389,8 +377,8 @@ namespace llarp void InitOutboundLinks(); - bool - GetRandomGoodRouter(RouterID& r); + std::optional + GetRandomGoodRouter(); /// initialize us as a service node /// return true on success