diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c2145e5e..f66994b5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(RELEASE_MOTTO "Our Lord And Savior" CACHE STRING "Release motto") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +set(BOOTSTRAP_SYSTEM_PATH "" CACHE PATH "Fallback bootstrap path") set(DEFAULT_WITH_BOOTSTRAP ON) if(APPLE) set(DEFAULT_WITH_BOOTSTRAP OFF) diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index d1d0196ef..b4a8cab18 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -235,6 +235,10 @@ add_library(lokinet-amalgum service/tag.cpp ) +if(BOOTSTRAP_SYSTEM_PATH) + message(STATUS "Building with fallback boostrap path \"${BOOTSTRAP_SYSTEM_PATH}\"") + target_compile_definitions(lokinet-amalgum PRIVATE "BOOTSTRAP_FALLBACK=\"${BOOTSTRAP_SYSTEM_PATH}\"") +endif() if(WITH_PEERSTATS_BACKEND) target_compile_definitions(lokinet-amalgum PRIVATE -DLOKINET_PEERSTATS_BACKEND) diff --git a/llarp/bootstrap.cpp b/llarp/bootstrap.cpp index 56731257f..7d221ab66 100644 --- a/llarp/bootstrap.cpp +++ b/llarp/bootstrap.cpp @@ -36,4 +36,35 @@ namespace llarp { return BEncodeWriteList(begin(), end(), buf); } + + void + BootstrapList::AddFromFile(fs::path fpath) + { + bool isListFile = false; + { + std::ifstream inf(fpath.c_str(), std::ios::binary); + if (inf.is_open()) + { + const char ch = inf.get(); + isListFile = ch == 'l'; + } + } + if (isListFile) + { + if (not BDecodeReadFile(fpath, *this)) + { + throw std::runtime_error{fmt::format("failed to read bootstrap list file '{}'", fpath)}; + } + } + else + { + RouterContact rc; + if (not rc.Read(fpath)) + { + throw std::runtime_error{ + fmt::format("failed to decode bootstrap RC, file='{}', rc={}", fpath, rc)}; + } + this->insert(rc); + } + } } // namespace llarp diff --git a/llarp/bootstrap.hpp b/llarp/bootstrap.hpp index e9a62d7e9..ba126c03a 100644 --- a/llarp/bootstrap.hpp +++ b/llarp/bootstrap.hpp @@ -2,6 +2,7 @@ #include "router_contact.hpp" #include +#include "llarp/util/fs.hpp" namespace llarp { @@ -13,6 +14,9 @@ namespace llarp bool BEncode(llarp_buffer_t* buf) const; + void + AddFromFile(fs::path fpath); + void Clear(); }; diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 421deb3f7..b1747dfdc 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -666,32 +666,7 @@ namespace llarp BootstrapList b_list; for (const auto& router : configRouters) { - bool isListFile = false; - { - std::ifstream inf(router.c_str(), std::ios::binary); - if (inf.is_open()) - { - const char ch = inf.get(); - isListFile = ch == 'l'; - } - } - if (isListFile) - { - if (not BDecodeReadFile(router, b_list)) - { - throw std::runtime_error{fmt::format("failed to read bootstrap list file '{}'", router)}; - } - } - else - { - RouterContact rc; - if (not rc.Read(router)) - { - throw std::runtime_error{ - fmt::format("failed to decode bootstrap RC, file='{}', rc={}", router, rc)}; - } - b_list.insert(rc); - } + b_list.AddFromFile(router); } for (const auto& rc : conf.bootstrap.routers) @@ -699,19 +674,52 @@ namespace llarp b_list.emplace(rc); } - for (auto& rc : b_list) + // in case someone has an old bootstrap file and is trying to use a bootstrap + // that no longer exists + for (auto rc_itr = b_list.begin(); rc_itr != b_list.end();) { - if (not rc.Verify(Now())) + if (rc_itr->IsObsoleteBootstrap()) + b_list.erase(rc_itr); + else + rc_itr++; + } + + auto verifyRCs = [&]() { + for (auto& rc : b_list) { - LogWarn("ignoring invalid RC: ", RouterID(rc.pubkey)); - continue; + if (rc.IsObsoleteBootstrap()) + { + LogWarn("ignoring obsolete boostrap RC: ", RouterID(rc.pubkey)); + continue; + } + if (not rc.Verify(Now())) + { + log::warning(logcat, "ignoring invalid RC: {}", RouterID(rc.pubkey)); + continue; + } + bootstrapRCList.emplace(std::move(rc)); } - bootstrapRCList.emplace(std::move(rc)); - } + }; + + verifyRCs(); + +#ifdef BOOTSTRAP_FALLBACK + constexpr std::string_view bootstrap_fallback = BOOTSTRAP_FALLBACK; +#else + constexpr std::string_view bootstrap_fallback{}; +#endif // BOOTSTRAP_FALLBACK if (bootstrapRCList.empty() and not conf.bootstrap.seednode) { - throw std::runtime_error{"we have no bootstrap nodes"}; + if (not bootstrap_fallback.empty()) + { + b_list.clear(); + b_list.AddFromFile(bootstrap_fallback); + + verifyRCs(); + } + if (bootstrapRCList.empty()) // empty after trying fallback, if set + throw std::runtime_error{"we have no bootstrap nodes"}; } if (conf.bootstrap.seednode) @@ -1038,14 +1046,27 @@ namespace llarp connectToNum = strictConnect; } - if (auto dereg = LooksDeregistered(); (dereg or decom) and now >= m_NextDecommissionWarn) + if (now >= m_NextDecommissionWarn) { - // complain about being deregistered constexpr auto DecommissionWarnInterval = 5min; - LogError( - "We are running as a service node but we seem to be ", - dereg ? "deregistered" : "decommissioned"); - m_NextDecommissionWarn = now + DecommissionWarnInterval; + if (auto dereg = LooksDeregistered(); dereg or decom) + { + // complain about being deregistered + LogError( + "We are running as a service node but we seem to be ", + dereg ? "deregistered" : "decommissioned"); + m_NextDecommissionWarn = now + DecommissionWarnInterval; + } + else if (isSvcNode) + { + constexpr int KnownPeerWarningThreshold = 5; + if (nodedb()->NumLoaded() < KnownPeerWarningThreshold) + log::error( + logcat, + "We appear to be an active service node, but have fewer than {} known peers.", + KnownPeerWarningThreshold); + m_NextDecommissionWarn = now + DecommissionWarnInterval; + } } // if we need more sessions to routers and we are not a service node kicked from the network diff --git a/llarp/router_contact.cpp b/llarp/router_contact.cpp index 598aa1753..9004c1c34 100644 --- a/llarp/router_contact.cpp +++ b/llarp/router_contact.cpp @@ -533,6 +533,20 @@ namespace llarp return false; } + static constexpr std::array obsolete_bootstraps = { + "7a16ac0b85290bcf69b2f3b52456d7e989ac8913b4afbb980614e249a3723218"sv}; + + bool + RouterContact::IsObsoleteBootstrap() const + { + for (const auto& k : obsolete_bootstraps) + { + if (pubkey.ToHex() == k) + return true; + } + return false; + } + bool RouterContact::Write(const fs::path& fname) const { diff --git a/llarp/router_contact.hpp b/llarp/router_contact.hpp index bafade89b..340bab597 100644 --- a/llarp/router_contact.hpp +++ b/llarp/router_contact.hpp @@ -205,6 +205,9 @@ namespace llarp bool FromOurNetwork() const; + bool + IsObsoleteBootstrap() const; + private: bool DecodeVersion_0(llarp_buffer_t* buf); diff --git a/llarp/util/types.hpp b/llarp/util/types.hpp index be6a0a286..1944bd905 100644 --- a/llarp/util/types.hpp +++ b/llarp/util/types.hpp @@ -3,6 +3,8 @@ #include #include +#include "oxen/log/format.hpp" + using byte_t = uint8_t; using llarp_proto_version_t = std::uint8_t; @@ -10,6 +12,7 @@ namespace llarp { using Duration_t = std::chrono::milliseconds; using namespace std::literals; + using namespace oxen::log::literals; /// convert to milliseconds uint64_t