diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b707a0f5..8c3b407d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ if(APPLE) set(LOKINET_APPLE_BUILD 5) endif() -set(RELEASE_MOTTO "Our Lord And Savior" CACHE STRING "Release motto") +set(LOKINET_RELEASE_MOTTO "Anonymous, decentralized, IP-based overlay network" CACHE STRING "Release motto") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") diff --git a/daemon/lokinet-bootstrap.cpp b/daemon/lokinet-bootstrap.cpp index e1ad9cb4d..afdecec72 100644 --- a/daemon/lokinet-bootstrap.cpp +++ b/daemon/lokinet-bootstrap.cpp @@ -86,7 +86,7 @@ main(int argc, char* argv[]) #else cpr::Get( cpr::Url{bootstrap_url}, - cpr::Header{{"User-Agent", std::string{llarp::VERSION_FULL}}}, + cpr::Header{{"User-Agent", std::string{llarp::LOKINET_VERSION_FULL}}}, cpr::Ssl(cpr::ssl::CaPath{X509_get_default_cert_dir()})); #endif if (resp.status_code != 200) diff --git a/daemon/lokinet.cpp b/daemon/lokinet.cpp index b56227f40..67ac4a671 100644 --- a/daemon/lokinet.cpp +++ b/daemon/lokinet.cpp @@ -403,7 +403,7 @@ namespace { if (options.version) { - std::cout << llarp::VERSION_FULL << std::endl; + std::cout << llarp::LOKINET_VERSION_FULL << std::endl; return 0; } @@ -548,7 +548,8 @@ namespace static void run_main_context(std::optional confFile, const llarp::RuntimeOptions opts) { - llarp::LogInfo(fmt::format("starting up {} {}", llarp::VERSION_FULL, llarp::RELEASE_MOTTO)); + llarp::LogInfo(fmt::format( + "starting up {} {}", llarp::LOKINET_VERSION_FULL, llarp::LOKINET_RELEASE_MOTTO)); try { std::shared_ptr conf; diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 06e4ac5b2..9b6635cb9 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -91,7 +91,6 @@ add_dependencies(lokinet-utils genversion) lokinet_add_library(lokinet-time-place ev/ev.cpp ev/libuv.cpp - net/exit_info.cpp # only router_contact net/ip.cpp net/ip_address.cpp net/ip_packet.cpp @@ -99,6 +98,8 @@ lokinet_add_library(lokinet-time-place net/net_int.cpp net/sock_addr.cpp router_contact.cpp + router_contact_local.cpp + router_contact_remote.cpp router_id.cpp router_version.cpp # to be deleted shortly service/address.cpp diff --git a/llarp/bootstrap-fallbacks.cpp.in b/llarp/bootstrap-fallbacks.cpp.in index baeb4be3a..9cc96008f 100644 --- a/llarp/bootstrap-fallbacks.cpp.in +++ b/llarp/bootstrap-fallbacks.cpp.in @@ -9,17 +9,18 @@ namespace llarp load_bootstrap_fallbacks() { std::unordered_map fallbacks; - using init_list = std::initializer_list>; - // clang-format off - for (const auto& [network, bootstrap] : init_list{ + + for (const auto& [network, bootstrap] : std::initializer_list>{ @BOOTSTRAP_FALLBACKS@ }) - // clang-format on { - llarp_buffer_t buf{bootstrap.data(), bootstrap.size()}; + if (network != RouterContact::ACTIVE_NETID) + continue; + auto& bsl = fallbacks[network]; - bsl.BDecode(&buf); + bsl.bt_decode(bootstrap); } + return fallbacks; } } // namespace llarp diff --git a/llarp/bootstrap.cpp b/llarp/bootstrap.cpp index 624757322..474052c30 100644 --- a/llarp/bootstrap.cpp +++ b/llarp/bootstrap.cpp @@ -6,66 +6,65 @@ namespace llarp { - void - BootstrapList::Clear() - { - clear(); - } - bool - BootstrapList::BDecode(llarp_buffer_t* buf) + BootstrapList::bt_decode(std::string_view buf) { - return bencode_read_list( - [&](llarp_buffer_t* b, bool more) -> bool { - if (more) - { - RouterContact rc{}; - if (not rc.BDecode(b)) - { - LogError("invalid rc in bootstrap list: ", llarp::buffer_printer{*b}); - return false; - } - emplace(std::move(rc)); - } - return true; - }, - buf); + try + { + oxenc::bt_list_consumer btlc{buf}; + + while (not btlc.is_finished()) + emplace(btlc.consume_dict_consumer()); + } + catch (...) + { + log::warning(logcat, "Unable to decode bootstrap RemoteRC"); + return false; + } + + return true; } - bool - BootstrapList::BEncode(llarp_buffer_t* buf) const + std::string_view + BootstrapList::bt_encode() const { - return BEncodeWriteList(begin(), end(), buf); + oxenc::bt_list_producer btlp{}; + + for (const auto& it : *this) + btlp.append(it.view()); + + return btlp.view(); } void - BootstrapList::AddFromFile(fs::path fpath) + BootstrapList::read_from_file(const fs::path& fpath) { bool isListFile = false; + + if (std::ifstream inf(fpath.c_str(), std::ios::binary); inf.is_open()) { - std::ifstream inf(fpath.c_str(), std::ios::binary); - if (inf.is_open()) - { - const char ch = inf.get(); - isListFile = ch == 'l'; - } + const char ch = inf.get(); + isListFile = ch == 'l'; } + if (isListFile) { - if (not BDecodeReadFile(fpath, *this)) + auto content = util::file_to_string(fpath); + + if (not bt_decode(content)) { throw std::runtime_error{fmt::format("failed to read bootstrap list file '{}'", fpath)}; } } else { - RouterContact rc; - if (not rc.Read(fpath)) + RemoteRC rc; + if (not rc.read(fpath)) { throw std::runtime_error{ - fmt::format("failed to decode bootstrap RC, file='{}', rc={}", fpath, rc)}; + fmt::format("failed to decode bootstrap RC, file='{}', rc={}", fpath, rc.to_string())}; } - this->insert(rc); + insert(rc); } } } // namespace llarp diff --git a/llarp/bootstrap.hpp b/llarp/bootstrap.hpp index e72e12fcc..11e8286d3 100644 --- a/llarp/bootstrap.hpp +++ b/llarp/bootstrap.hpp @@ -9,19 +9,22 @@ namespace llarp { - struct BootstrapList final : public std::set + struct BootstrapList final : public std::set { bool - BDecode(llarp_buffer_t* buf); + bt_decode(std::string_view buf); - bool - BEncode(llarp_buffer_t* buf) const; + std::string_view + bt_encode() const; void - AddFromFile(fs::path fpath); + read_from_file(const fs::path& fpath); void - Clear(); + clear_list() + { + clear(); + } }; std::unordered_map diff --git a/llarp/bootstrap_fallbacks.cpp b/llarp/bootstrap_fallbacks.cpp index 458444f63..79f6f646f 100644 --- a/llarp/bootstrap_fallbacks.cpp +++ b/llarp/bootstrap_fallbacks.cpp @@ -10,17 +10,19 @@ namespace llarp load_bootstrap_fallbacks() { std::unordered_map fallbacks; - using init_list = std::initializer_list>; - // clang-format off - for (const auto& [network, bootstrap] : init_list{ - // - }) - // clang-format on + + for (const auto& [network, bootstrap] : + std::initializer_list>{ + // + }) { - llarp_buffer_t buf{bootstrap.data(), bootstrap.size()}; + if (network != RouterContact::ACTIVE_NETID) + continue; + auto& bsl = fallbacks[network]; - bsl.BDecode(&buf); + bsl.bt_decode(bootstrap); } + return fallbacks; } } // namespace llarp diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index e28652d9d..c4d3035da 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -58,14 +58,15 @@ namespace llarp conf.defineOption( "router", "netid", - Default{llarp::DEFAULT_NETID}, + Default{llarp::LOKINET_DEFAULT_NETID}, Comment{ - "Network ID; this is '"s + llarp::DEFAULT_NETID + "' for mainnet, 'gamma' for testnet.", + "Network ID; this is '"s + llarp::LOKINET_DEFAULT_NETID + + "' for mainnet, 'gamma' for testnet.", }, [this](std::string arg) { - if (arg.size() > NetID::size()) + if (arg.size() > NETID_SIZE) throw std::invalid_argument{ - fmt::format("netid is too long, max length is {}", NetID::size())}; + fmt::format("netid is too long, max length is {}", NETID_SIZE)}; m_netId = std::move(arg); }); @@ -1321,7 +1322,7 @@ namespace llarp } bool - PeerSelectionConfig::Acceptable(const std::set& rcs) const + PeerSelectionConfig::Acceptable(const std::set& rcs) const { if (m_UniqueHopsNetmaskSize == 0) return true; @@ -1329,7 +1330,7 @@ namespace llarp std::set seenRanges; for (const auto& hop : rcs) { - const auto network_addr = net::In6ToHUInt(hop.addr.in6().sin6_addr) & netmask; + const auto network_addr = net::In6ToHUInt(hop.addr6()->in6().sin6_addr) & netmask; if (auto [it, inserted] = seenRanges.emplace(network_addr, netmask); not inserted) { return false; @@ -1444,7 +1445,7 @@ namespace llarp { try { - ini = util::slurp_file(*fname); + ini = util::file_to_string(*fname); } catch (const std::exception&) { @@ -1529,7 +1530,7 @@ namespace llarp // open a filestream try { - util::dump_file(confFile, confStr); + util::buffer_to_file(confFile, confStr); } catch (const std::exception& e) { diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index f91c131c2..9ee7f2e6b 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -100,7 +100,7 @@ namespace llarp /// return true if this set of router contacts is acceptable against this config bool - Acceptable(const std::set& hops) const; + Acceptable(const std::set& hops) const; }; struct NetworkConfig diff --git a/llarp/config/ini.cpp b/llarp/config/ini.cpp index 66b55dd4c..c74052819 100644 --- a/llarp/config/ini.cpp +++ b/llarp/config/ini.cpp @@ -15,7 +15,7 @@ namespace llarp { try { - m_Data = util::slurp_file(fname); + m_Data = util::file_to_string(fname); } catch (const std::exception& e) { diff --git a/llarp/config/key_manager.cpp b/llarp/config/key_manager.cpp index 3df661847..f5b05c0f8 100644 --- a/llarp/config/key_manager.cpp +++ b/llarp/config/key_manager.cpp @@ -51,8 +51,8 @@ namespace llarp m_encKeyPath = deriveFile(our_enc_key_filename, config.router.m_encryptionKeyFile); m_transportKeyPath = deriveFile(our_transport_key_filename, config.router.m_transportKeyFile); - RouterContact rc; - bool exists = rc.Read(m_rcPath); + RemoteRC rc; + bool exists = rc.read(m_rcPath); if (not exists and not genIfAbsent) { LogError("Could not read RouterContact at path ", m_rcPath); @@ -61,7 +61,7 @@ namespace llarp // we need to back up keys if our self.signed doesn't appear to have a // valid signature - m_needBackup = (isSNode and not rc.VerifySignature()); + m_needBackup = (isSNode and not rc.verify()); // if our RC file can't be verified, assume it is out of date (e.g. uses // older encryption) and needs to be regenerated. before doing so, backup diff --git a/llarp/constants/version.cpp.in b/llarp/constants/version.cpp.in index e07223705..60d3af6ae 100644 --- a/llarp/constants/version.cpp.in +++ b/llarp/constants/version.cpp.in @@ -4,12 +4,11 @@ namespace llarp { // clang-format off - const std::array VERSION{{@lokinet_VERSION_MAJOR@, @lokinet_VERSION_MINOR@, @lokinet_VERSION_PATCH@}}; - const std::array ROUTER_VERSION{{llarp::constants::proto_version, @lokinet_VERSION_MAJOR@, @lokinet_VERSION_MINOR@, @lokinet_VERSION_PATCH@}}; - const char* const VERSION_TAG = "@VERSIONTAG@"; - const char* const VERSION_FULL = "lokinet-@lokinet_VERSION_MAJOR@.@lokinet_VERSION_MINOR@.@lokinet_VERSION_PATCH@-@VERSIONTAG@"; + const std::array LOKINET_VERSION{{@lokinet_VERSION_MAJOR@, @lokinet_VERSION_MINOR@, @lokinet_VERSION_PATCH@}}; + const char* const LOKINET_VERSION_TAG = "@VERSIONTAG@"; + const char* const LOKINET_VERSION_FULL = "lokinet-@lokinet_VERSION_MAJOR@.@lokinet_VERSION_MINOR@.@lokinet_VERSION_PATCH@-@LOKINET_VERSION_TAG@"; - const char* const RELEASE_MOTTO = "@RELEASE_MOTTO@"; - const char* const DEFAULT_NETID = "lokinet"; + const char* const LOKINET_RELEASE_MOTTO = "@RELEASE_MOTTO@"; + const char* const LOKINET_DEFAULT_NETID = "lokinet"; // clang-format on } // namespace llarp diff --git a/llarp/constants/version.hpp b/llarp/constants/version.hpp index 1bfd68d31..f79b842e2 100644 --- a/llarp/constants/version.hpp +++ b/llarp/constants/version.hpp @@ -6,11 +6,10 @@ namespace llarp { // Given a full lokinet version of: lokinet-1.2.3-abc these are: - extern const std::array VERSION; // [1, 2, 3] - extern const std::array ROUTER_VERSION; // [proto, 1, 2, 3] - extern const char* const VERSION_TAG; // "abc" - extern const char* const VERSION_FULL; // "lokinet-1.2.3-abc" + extern const std::array LOKINET_VERSION; + extern const char* const LOKINET_VERSION_TAG; + extern const char* const LOKINET_VERSION_FULL; - extern const char* const RELEASE_MOTTO; - extern const char* const DEFAULT_NETID; + extern const char* const LOKINET_RELEASE_MOTTO; + extern const char* const LOKINET_DEFAULT_NETID; } // namespace llarp diff --git a/llarp/context.cpp b/llarp/context.cpp index be4f61d97..cffea417f 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -19,8 +19,6 @@ namespace llarp { - static auto logcat = llarp::log::Cat("llarp-context"); - bool Context::CallSafe(std::function f) { @@ -59,7 +57,8 @@ namespace llarp throw std::runtime_error("Cannot call Setup() on context without a Config"); if (opts.showBanner) - llarp::LogInfo(fmt::format("{} {}", llarp::VERSION_FULL, llarp::RELEASE_MOTTO)); + llarp::LogInfo( + fmt::format("{} {}", llarp::LOKINET_VERSION_FULL, llarp::LOKINET_RELEASE_MOTTO)); if (!loop) { @@ -162,7 +161,7 @@ namespace llarp #ifndef _WIN32 if (sig == SIGUSR1) { - if (router and not router->IsServiceNode()) + if (router and not router->is_service_node()) { LogInfo("SIGUSR1: resetting network state"); router->Thaw(); diff --git a/llarp/crypto/crypto.cpp b/llarp/crypto/crypto.cpp index f8a61535a..7b6aa046a 100644 --- a/llarp/crypto/crypto.cpp +++ b/llarp/crypto/crypto.cpp @@ -273,6 +273,14 @@ namespace llarp return true; } + bool + crypto::verify(const PubKey& pub, ustring_view data, ustring_view sig) + { + return (pub.size() == 32 && sig.size() == 64) + ? crypto_sign_verify_detached(sig.data(), data.data(), data.size(), pub.data()) != -1 + : false; + } + bool crypto::verify(const PubKey& pub, uint8_t* buf, size_t size, const Signature& sig) { @@ -428,11 +436,6 @@ namespace llarp return true; } - bool - crypto::seed_to_secretkey(llarp::SecretKey& secret, const llarp::IdentitySecret& seed) - { - return crypto_sign_ed25519_seed_keypair(secret.data() + 32, secret.data(), seed.data()) != -1; - } void crypto::randomize(uint8_t* buf, size_t len) { @@ -517,19 +520,19 @@ namespace llarp #endif const byte_t* - seckey_topublic(const SecretKey& sec) + seckey_to_pubkey(const SecretKey& sec) { return sec.data() + 32; } const byte_t* - pq_keypair_to_public(const PQKeyPair& k) + pq_keypair_to_pubkey(const PQKeyPair& k) { return k.data() + PQ_SECRETKEYSIZE; } const byte_t* - pq_keypair_to_secret(const PQKeyPair& k) + pq_keypair_to_seckey(const PQKeyPair& k) { return k.data(); } diff --git a/llarp/crypto/crypto.hpp b/llarp/crypto/crypto.hpp index 370b23e34..dba97aeed 100644 --- a/llarp/crypto/crypto.hpp +++ b/llarp/crypto/crypto.hpp @@ -64,6 +64,8 @@ namespace llarp sign(Signature&, const PrivateKey&, uint8_t* buf, size_t size); /// ed25519 verify bool + verify(const PubKey&, ustring_view, ustring_view); + bool verify(const PubKey&, uint8_t*, size_t, const Signature&); bool verify(ustring_view, ustring_view, ustring_view); bool @@ -87,9 +89,6 @@ namespace llarp uint64_t key_n, const AlignedBuffer<32>* hash = nullptr); - /// seed to secretkey - bool - seed_to_secretkey(llarp::SecretKey&, const llarp::IdentitySecret&); /// randomize buffer void randomize(uint8_t* buf, size_t len); @@ -124,13 +123,13 @@ namespace llarp randint(); const byte_t* - seckey_topublic(const SecretKey& secret); + seckey_to_pubkey(const SecretKey& secret); const byte_t* - pq_keypair_to_public(const PQKeyPair& keypair); + pq_keypair_to_pubkey(const PQKeyPair& keypair); const byte_t* - pq_keypair_to_secret(const PQKeyPair& keypair); + pq_keypair_to_seckey(const PQKeyPair& keypair); /// rng type that uses llarp::randint(), which is cryptographically secure struct CSRNG diff --git a/llarp/crypto/types.cpp b/llarp/crypto/types.cpp index 30d4a3a9a..092698e81 100644 --- a/llarp/crypto/types.cpp +++ b/llarp/crypto/types.cpp @@ -1,5 +1,6 @@ #include "types.hpp" +#include #include #include @@ -32,6 +33,30 @@ namespace llarp return oxenc::to_hex(begin(), end()); } + PubKey::operator RouterID() const + { + return {as_array()}; + } + + PubKey& + PubKey::operator=(const byte_t* ptr) + { + std::copy(ptr, ptr + SIZE, begin()); + return *this; + } + + bool + operator==(const PubKey& lhs, const PubKey& rhs) + { + return lhs.as_array() == rhs.as_array(); + } + + bool + operator==(const PubKey& lhs, const RouterID& rhs) + { + return lhs.as_array() == rhs.as_array(); + } + bool SecretKey::LoadFromFile(const fs::path& fname) { @@ -39,7 +64,7 @@ namespace llarp std::array tmp; try { - sz = util::slurp_file(fname, tmp.data(), tmp.size()); + sz = util::file_to_buffer(fname, tmp.data(), tmp.size()); } catch (const std::exception&) { @@ -93,67 +118,17 @@ namespace llarp bool SecretKey::SaveToFile(const fs::path& fname) const { - std::string tmp(128, 0); - llarp_buffer_t buf(tmp); - if (!bt_encode(&buf)) - return false; + auto bte = bt_encode(); - tmp.resize(buf.cur - buf.base); try { - util::dump_file(fname, tmp); - } - catch (const std::exception&) - { - return false; - } - return true; - } - - bool - IdentitySecret::LoadFromFile(const fs::path& fname) - { - std::array buf; - size_t sz; - try - { - sz = util::slurp_file(fname, buf.data(), buf.size()); + util::buffer_to_file(fname, bte); } catch (const std::exception& e) { - llarp::LogError("failed to load service node seed: ", e.what()); return false; } - if (sz != SIZE) - { - llarp::LogError("service node seed size invalid: ", sz, " != ", SIZE); - return false; - } - std::copy(buf.begin(), buf.end(), begin()); - return true; - } - byte_t* - Signature::Lo() - { - return data(); - } - - const byte_t* - Signature::Lo() const - { - return data(); - } - - byte_t* - Signature::Hi() - { - return data() + 32; - } - - const byte_t* - Signature::Hi() const - { - return data() + 32; + return true; } } // namespace llarp diff --git a/llarp/crypto/types.hpp b/llarp/crypto/types.hpp index e4188c35d..6e723fae5 100644 --- a/llarp/crypto/types.hpp +++ b/llarp/crypto/types.hpp @@ -2,7 +2,6 @@ #include "constants.hpp" -#include #include #include #include @@ -15,7 +14,9 @@ namespace llarp using SharedSecret = AlignedBuffer; using KeyExchangeNonce = AlignedBuffer<32>; - struct PubKey final : public AlignedBuffer + struct RouterID; + + struct PubKey : public AlignedBuffer { PubKey() = default; @@ -37,36 +38,17 @@ namespace llarp static PubKey from_string(const std::string& s); - operator RouterID() const - { - return {as_array()}; - } + operator RouterID() const; PubKey& - operator=(const byte_t* ptr) - { - std::copy(ptr, ptr + SIZE, begin()); - return *this; - } + operator=(const byte_t* ptr); }; - inline bool - operator==(const PubKey& lhs, const PubKey& rhs) - { - return lhs.as_array() == rhs.as_array(); - } + bool + operator==(const PubKey& lhs, const PubKey& rhs); - inline bool - operator==(const PubKey& lhs, const RouterID& rhs) - { - return lhs.as_array() == rhs.as_array(); - } - - inline bool - operator==(const RouterID& lhs, const PubKey& rhs) - { - return lhs.as_array() == rhs.as_array(); - } + bool + operator==(const PubKey& lhs, const RouterID& rhs); struct PrivateKey; @@ -161,58 +143,24 @@ namespace llarp toPublic(PubKey& pubkey) const; }; - /// IdentitySecret is a secret key from a service node secret seed - struct IdentitySecret final : public AlignedBuffer<32> - { - IdentitySecret() : AlignedBuffer<32>() - {} - - /// no copy constructor - explicit IdentitySecret(const IdentitySecret&) = delete; - // no byte data constructor - explicit IdentitySecret(const byte_t*) = delete; - - /// load service node seed from file - bool - LoadFromFile(const fs::path& fname); - - std::string_view - ToString() const - { - return "[IdentitySecret]"; - } - }; - template <> constexpr inline bool IsToStringFormattable = true; template <> constexpr inline bool IsToStringFormattable = true; template <> constexpr inline bool IsToStringFormattable = true; - template <> - constexpr inline bool IsToStringFormattable = true; using ShortHash = AlignedBuffer; using LongHash = AlignedBuffer; struct Signature final : public AlignedBuffer { - byte_t* - Hi(); - - const byte_t* - Hi() const; - - byte_t* - Lo(); - - const byte_t* - Lo() const; + // }; using TunnelNonce = AlignedBuffer; using SymmNonce = AlignedBuffer; - using SymmKey = AlignedBuffer<32>; + using SymmKey = AlignedBuffer<32>; // not used using PQCipherBlock = AlignedBuffer; using PQPubKey = AlignedBuffer; diff --git a/llarp/dht/kademlia.hpp b/llarp/dht/kademlia.hpp index 776d8cb37..6508898b4 100644 --- a/llarp/dht/kademlia.hpp +++ b/llarp/dht/kademlia.hpp @@ -22,7 +22,7 @@ namespace llarp::dht bool operator()(const RouterContact& left, const RouterContact& right) const { - return (left.pubkey ^ us) < (right.pubkey ^ us); + return (left.router_id() ^ us) < (right.router_id() ^ us); } }; } // namespace llarp::dht diff --git a/llarp/dht/node.hpp b/llarp/dht/node.hpp index 0f2deecc2..36ac3e9d5 100644 --- a/llarp/dht/node.hpp +++ b/llarp/dht/node.hpp @@ -19,19 +19,19 @@ namespace llarp::dht ID.Zero(); } - RCNode(const RouterContact& other) : rc(other), ID(other.pubkey) + RCNode(const RouterContact& other) : rc(other), ID(other.router_id()) {} util::StatusObject ExtractStatus() const { - return rc.ExtractStatus(); + return rc.extract_status(); } bool operator<(const RCNode& other) const { - return rc.last_updated < other.rc.last_updated; + return rc.timestamp() < other.rc.timestamp(); } }; diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index c6bdc009b..ecdafff65 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -69,13 +69,13 @@ namespace llarp::exit snode_blacklist.insert(std::move(snode)); } - std::optional> + std::optional> BaseSession::GetHopsForBuild() { if (numHops == 1) { if (auto maybe = router->node_db()->get_rc(exit_router)) - return std::vector{*maybe}; + return std::vector{*maybe}; return std::nullopt; } @@ -292,7 +292,7 @@ namespace llarp::exit throw; } - RouterContact result{std::move(payload)}; + RemoteRC result{std::move(payload)}; r->node_db()->put_rc_if_newer(result); r->connect_to(result); } diff --git a/llarp/exit/session.hpp b/llarp/exit/session.hpp index ac5da8f84..6410bc2be 100644 --- a/llarp/exit/session.hpp +++ b/llarp/exit/session.hpp @@ -72,7 +72,7 @@ namespace llarp bool CheckPathDead(path::Path_ptr p, llarp_time_t dlt); - std::optional> + std::optional> GetHopsForBuild() override; bool diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 3702c3f2a..b9a46b1a8 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -578,29 +578,7 @@ namespace llarp::handlers void ExitEndpoint::SRVRecordsChanged() { - router->modify_rc( - [srvRecords = SRVRecords()](RouterContact rc) -> std::optional { - // check if there are any new srv records - bool shouldUpdate = false; - - for (const auto& rcSrv : rc.srvRecords) - { - if (srvRecords.count(rcSrv) == 0) - shouldUpdate = true; - } - - // no new records so don't modify - if (not shouldUpdate) - return std::nullopt; - - // we got new entries so we clear the whole vector on the rc and recreate it - rc.srvRecords.clear(); - for (auto& record : srvRecords) - rc.srvRecords.emplace_back(record); - // set the verssion to 1 because we have srv records - rc.version = 1; - return rc; - }); + // TODO: Investigate the usage or the term exit RE: service nodes acting as exits } std::optional diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 468e138a7..e530da4e0 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -623,7 +623,7 @@ namespace llarp::handlers throw; } - r->node_db()->put_rc_if_newer(RouterContact{payload}); + r->node_db()->put_rc_if_newer(RemoteRC{payload}); msg.AddTXTReply(payload); } else @@ -658,7 +658,7 @@ namespace llarp::handlers } else if (subdomain == "netid") { - msg.AddTXTReply(fmt::format("netid={};", router()->rc().netID)); + msg.AddTXTReply(fmt::format("netid={};", RouterContact::ACTIVE_NETID)); } else { diff --git a/llarp/link/connection.cpp b/llarp/link/connection.cpp index 01aaa4fc8..dace3d299 100644 --- a/llarp/link/connection.cpp +++ b/llarp/link/connection.cpp @@ -5,7 +5,7 @@ namespace llarp::link Connection::Connection( std::shared_ptr& c, std::shared_ptr& s, - const RouterContact& rc) + const RemoteRC& rc) : conn{c}, control_stream{s}, remote_rc{std::move(rc)} {} diff --git a/llarp/link/connection.hpp b/llarp/link/connection.hpp index fe8b0961a..46aef9328 100644 --- a/llarp/link/connection.hpp +++ b/llarp/link/connection.hpp @@ -11,7 +11,7 @@ namespace llarp::link { std::shared_ptr conn; std::shared_ptr control_stream; - RouterContact remote_rc; + RemoteRC remote_rc; // one side of a connection will be responsible for some things, e.g. heartbeat bool inbound{false}; @@ -20,7 +20,7 @@ namespace llarp::link Connection( std::shared_ptr& c, std::shared_ptr& s, - const RouterContact& rc); + const RemoteRC& rc); }; } // namespace llarp::link diff --git a/llarp/link/contacts.cpp b/llarp/link/contacts.cpp index 82c7b7b44..de184ea52 100644 --- a/llarp/link/contacts.cpp +++ b/llarp/link/contacts.cpp @@ -39,7 +39,7 @@ namespace llarp while (itr != nodes.end()) { - if (itr->second.rc.IsExpired(now)) + if (itr->second.rc.is_expired(now)) itr = nodes.erase(itr); else ++itr; diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index f3f504795..caa004a4e 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -18,9 +18,9 @@ namespace llarp namespace link { std::shared_ptr - Endpoint::get_conn(const RouterContact& rc) const + Endpoint::get_conn(const RemoteRC& rc) const { - if (auto itr = conns.find(rc.pubkey); itr != conns.end()) + if (auto itr = conns.find(rc.router_id()); itr != conns.end()) return itr->second; return nullptr; @@ -83,7 +83,7 @@ namespace llarp } bool - Endpoint::get_random_connection(RouterContact& router) const + Endpoint::get_random_connection(RemoteRC& router) const { if (const auto size = conns.size(); size) { @@ -301,16 +301,16 @@ namespace llarp // This function assumes the RC has already had its signature verified and connection is allowed. void - LinkManager::connect_to(const RouterContact& rc) + LinkManager::connect_to(const RemoteRC& rc) { - if (auto conn = ep.get_conn(rc.pubkey); conn) + if (auto conn = ep.get_conn(rc.router_id()); conn) { // TODO: should implement some connection failed logic, but not the same logic that // would be executed for another failure case return; } - auto& remote_addr = rc.addr; + const auto& remote_addr = rc.addr(); // TODO: confirm remote end is using the expected pubkey (RouterID). // TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation) @@ -451,7 +451,7 @@ namespace llarp } bool - LinkManager::get_random_connected(RouterContact& router) const + LinkManager::get_random_connected(RemoteRC& router) const { return ep.get_random_connection(router); } @@ -487,13 +487,15 @@ namespace llarp do { - auto filter = [exclude](const auto& rc) -> bool { return exclude.count(rc.pubkey) == 0; }; + auto filter = [exclude](const auto& rc) -> bool { + return exclude.count(rc.router_id()) == 0; + }; if (auto maybe_other = node_db->GetRandom(filter)) { - exclude.insert(maybe_other->pubkey); + exclude.insert(maybe_other->router_id()); - if (not rc_lookup->is_session_allowed(maybe_other->pubkey)) + if (not rc_lookup->is_session_allowed(maybe_other->router_id())) continue; connect_to(*maybe_other); @@ -609,18 +611,19 @@ namespace llarp target_rid.FromString(target_key); const auto target_addr = dht::Key_t{reinterpret_cast(target_key.data())}; - const auto& local_rid = _router.rc().pubkey; + const auto& local_rid = _router.rc().router_id(); const auto local_key = dht::Key_t{local_rid}; if (is_exploratory) { std::string neighbors{}; + const auto closest_rcs = _router.node_db()->find_many_closest_to(target_addr, RC_LOOKUP_STORAGE_REDUNDANCY); for (const auto& rc : closest_rcs) { - const auto& rid = rc.pubkey; + const auto& rid = rc.router_id(); if (_router.router_profiling().IsBadForConnect(rid) || target_rid == rid || local_rid == rid) continue; @@ -635,12 +638,12 @@ namespace llarp else { const auto closest_rc = _router.node_db()->find_closest_to(target_addr); - const auto& closest_rid = closest_rc.pubkey; + const auto& closest_rid = closest_rc.router_id(); const auto closest_key = dht::Key_t{closest_rid}; if (target_addr == closest_key) { - if (closest_rc.ExpiresSoon(llarp::time_now_ms())) + if (closest_rc.expires_within_delta(llarp::time_now_ms())) { send_control_message( target_rid, @@ -652,7 +655,7 @@ namespace llarp } else { - m.respond(serialize_response({{"RC", closest_rc.bt_encode()}})); + m.respond(serialize_response({{"RC", closest_rc.view()}})); } } else if (not is_iterative) @@ -718,7 +721,7 @@ namespace llarp if (m) { - _router.node_db()->put_rc_if_newer(RouterContact{payload}); + _router.node_db()->put_rc_if_newer(RemoteRC{payload}); } else { @@ -837,7 +840,7 @@ namespace llarp const auto now = _router.now(); const auto addr = dht::Key_t{reinterpret_cast(derived_signing_key.data())}; - const auto local_key = _router.rc().pubkey; + const auto local_key = _router.rc().router_id(); if (not service::EncryptedIntroSet::verify(introset, derived_signing_key, sig)) { @@ -878,7 +881,7 @@ namespace llarp log::info(link_cat, "Relaying PublishIntroMessage for {}", addr); const auto& peer_rc = closest_rcs[relay_order]; - const auto& peer_key = peer_rc.pubkey; + const auto& peer_key = peer_rc.router_id(); if (peer_key == local_key) { @@ -908,7 +911,7 @@ namespace llarp for (const auto& rc : closest_rcs) { - if (rc.pubkey == local_key) + if (rc.router_id() == local_key) { rc_index = index; break; @@ -1024,7 +1027,7 @@ namespace llarp log::info(link_cat, "Relaying FindIntroMessage for {}", addr); const auto& peer_rc = closest_rcs[relay_order]; - const auto& peer_key = peer_rc.pubkey; + const auto& peer_key = peer_rc.router_id(); send_control_message( peer_key, diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index 96e37de7f..d99e2face 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -52,7 +52,8 @@ namespace llarp // TODO: see which of these is actually useful and delete the other std::shared_ptr - get_conn(const RouterContact&) const; + get_conn(const RemoteRC&) const; + std::shared_ptr get_conn(const RouterID&) const; @@ -66,12 +67,11 @@ namespace llarp num_connected(bool clients_only) const; bool - get_random_connection(RouterContact& router) const; + get_random_connection(RemoteRC& router) const; template bool - establish_connection( - const oxen::quic::Address& remote, const RouterContact& rc, Opt&&... opts); + establish_connection(const oxen::quic::Address& remote, const RemoteRC& rc, Opt&&... opts); void for_each_connection(std::function func); @@ -239,7 +239,7 @@ namespace llarp connect_to(const RouterID& router); void - connect_to(const RouterContact& rc); + connect_to(const RemoteRC& rc); void close_connection(RouterID rid); @@ -257,7 +257,7 @@ namespace llarp get_num_connected_clients() const; bool - get_random_connected(RouterContact& router) const; + get_random_connected(RemoteRC& router) const; void check_persisting_conns(llarp_time_t now); @@ -364,7 +364,7 @@ namespace llarp template bool Endpoint::establish_connection( - const oxen::quic::Address& remote, const RouterContact& rc, Opt&&... opts) + const oxen::quic::Address& remote, const RemoteRC& rc, Opt&&... opts) { try { @@ -372,8 +372,8 @@ namespace llarp endpoint->connect(remote, link_manager.tls_creds, std::forward(opts)...); // emplace immediately for connection open callback to find scid - connid_map.emplace(conn_interface->scid(), rc.pubkey); - auto [itr, b] = conns.emplace(rc.pubkey, nullptr); + connid_map.emplace(conn_interface->scid(), rc.router_id()); + auto [itr, b] = conns.emplace(rc.router_id(), nullptr); auto control_stream = conn_interface->template get_new_stream(); diff --git a/llarp/messages/path.hpp b/llarp/messages/path.hpp index e4885c620..ca10a0f84 100644 --- a/llarp/messages/path.hpp +++ b/llarp/messages/path.hpp @@ -22,7 +22,7 @@ namespace llarp hop.nonce.Randomize(); // do key exchange - if (!crypto::dh_client(hop.shared, hop.rc.pubkey, hop.commkey, hop.nonce)) + if (!crypto::dh_client(hop.shared, hop.rc.router_id(), hop.commkey, hop.nonce)) { auto err = fmt::format("Failed to generate shared key for path build!"); log::warning(path_cat, err); @@ -60,7 +60,7 @@ namespace llarp outer_nonce.Randomize(); // derive (outer) shared key - if (!crypto::dh_client(shared, hop.rc.pubkey, framekey, outer_nonce)) + if (!crypto::dh_client(shared, hop.rc.router_id(), framekey, outer_nonce)) { log::warning(path_cat, "DH client failed during hop info encryption!"); throw std::runtime_error{"DH failed during hop info encryption"}; diff --git a/llarp/messages/relay.cpp b/llarp/messages/relay.cpp index cabc2aa9d..8bfab3a0b 100644 --- a/llarp/messages/relay.cpp +++ b/llarp/messages/relay.cpp @@ -54,7 +54,7 @@ namespace llarp bool RelayUpstreamMessage::handle_message(Router* r) const { - auto path = r->path_context().GetByDownstream(conn->remote_rc.pubkey, pathid); + auto path = r->path_context().GetByDownstream(conn->remote_rc.router_id(), pathid); if (path) { return path->HandleUpstream(llarp_buffer_t(enc), nonce, r); @@ -110,7 +110,7 @@ namespace llarp bool RelayDownstreamMessage::handle_message(Router* r) const { - auto path = r->path_context().GetByUpstream(conn->remote_rc.pubkey, pathid); + auto path = r->path_context().GetByUpstream(conn->remote_rc.router_id(), pathid); if (path) { return path->HandleDownstream(llarp_buffer_t(enc), nonce, r); diff --git a/llarp/net/exit_info.cpp b/llarp/net/exit_info.cpp deleted file mode 100644 index 69d297cca..000000000 --- a/llarp/net/exit_info.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _WIN32 -#include -#endif - -#include "exit_info.hpp" - -#include - -#include - -namespace llarp -{ - bool - ExitInfo::bt_encode(llarp_buffer_t* buf) const - { - SockAddr exitaddr = ipAddress.createSockAddr(); - const auto* exitaddr6 = static_cast(exitaddr); - - SockAddr netmaskaddr = netmask.createSockAddr(); - const auto* netmaskaddr6 = static_cast(netmaskaddr); - - char tmp[128] = {0}; - if (!bencode_start_dict(buf)) - return false; - - if (!inet_ntop(AF_INET6, &exitaddr6->sin6_addr, tmp, sizeof(tmp))) - return false; - if (!BEncodeWriteDictString("a", std::string(tmp), buf)) - return false; - - if (!inet_ntop(AF_INET6, &netmaskaddr6->sin6_addr, tmp, sizeof(tmp))) - return false; - if (!BEncodeWriteDictString("b", std::string(tmp), buf)) - return false; - - if (!BEncodeWriteDictEntry("k", pubkey, buf)) - return false; - - if (!BEncodeWriteDictInt("v", version, buf)) - return false; - - return bencode_end(buf); - } - - static bool - bdecode_ip_string(llarp_buffer_t* buf, in6_addr& ip) - { - char tmp[128] = {0}; - llarp_buffer_t strbuf; - if (!bencode_read_string(buf, &strbuf)) - return false; - - if (strbuf.sz >= sizeof(tmp)) - return false; - - memcpy(tmp, strbuf.base, strbuf.sz); - tmp[strbuf.sz] = 0; - return inet_pton(AF_INET6, tmp, &ip.s6_addr[0]) == 1; - } - - bool - ExitInfo::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf) - { - bool read = false; - if (!BEncodeMaybeReadDictEntry("k", pubkey, read, k, buf)) - return false; - if (!BEncodeMaybeReadDictInt("v", version, read, k, buf)) - return false; - if (k.startswith("a")) - { - in6_addr tmp; - if (not bdecode_ip_string(buf, tmp)) - return false; - - SockAddr addr(tmp); - ipAddress = IpAddress(addr); - return true; - } - if (k.startswith("b")) - { - in6_addr tmp; - if (not bdecode_ip_string(buf, tmp)) - return false; - SockAddr addr(tmp); - netmask = IpAddress(addr); - return true; - } - return read; - } - - std::string - ExitInfo::ToString() const - { - /* - // TODO: derive these from ipAdress - throw std::runtime_error("FIXME: need in6_addr and netmask from IpAddress"); - in6_addr address; - in6_addr netmask; - - Printer printer(stream, level, spaces); - - std::ostringstream ss; - char tmp[128] = {0}; - - if (inet_ntop(AF_INET6, (void*)&address, tmp, sizeof(tmp))) - ss << tmp; - else - return stream; - ss << std::string("/"); -#if defined(ANDROID) - snprintf(tmp, sizeof(tmp), "%zu", llarp::bits::count_array_bits(netmask.s6_addr)); - ss << tmp; -#else - ss << std::to_string(llarp::bits::count_array_bits(netmask.s6_addr)); -#endif - printer.printValue(ss.str()); - */ - return fmt::format("[Exit {}]", ipAddress.ToString()); - } - -} // namespace llarp diff --git a/llarp/net/exit_info.hpp b/llarp/net/exit_info.hpp deleted file mode 100644 index 5c1c92736..000000000 --- a/llarp/net/exit_info.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "ip_address.hpp" - -#include -#include - -#include - -/** - * exit_info.h - * - * utilities for handling exits on the llarp network - */ - -/// Exit info model -namespace llarp -{ - /// deprecated don't use me , this is only for backwards compat - struct ExitInfo - { - IpAddress ipAddress; - IpAddress netmask; - PubKey pubkey; - uint64_t version = llarp::constants::proto_version; - - ExitInfo() = default; - - ExitInfo(const PubKey& pk, const IpAddress& address) : ipAddress(address), pubkey(pk) - {} - - bool - bt_encode(llarp_buffer_t* buf) const; - - bool - BDecode(llarp_buffer_t* buf) - { - return bencode_decode_dict(*this, buf); - } - - bool - decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf); - - std::string - ToString() const; - }; - - template <> - constexpr inline bool IsToStringFormattable = true; - -} // namespace llarp diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index cc6d2a28b..a5955003d 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -14,9 +14,7 @@ static const std::string RC_FILE_EXT = ".signed"; namespace llarp { - static auto logcat = log::Cat("nodedb"); - - NodeDB::Entry::Entry(RouterContact value) : rc(std::move(value)), insertedAt(llarp::time_now_ms()) + NodeDB::Entry::Entry(RemoteRC value) : rc(std::move(value)), insertedAt(llarp::time_now_ms()) {} static void @@ -72,14 +70,16 @@ namespace llarp router.loop()->call([this]() { m_NextFlushAt += FlushInterval; // make copy of all rcs - std::vector copy; + std::vector copy; + for (const auto& item : entries) copy.push_back(item.second.rc); + // flush them to disk in one big job // TODO: split this up? idk maybe some day... disk([this, data = std::move(copy)]() { for (const auto& rc : data) - rc.Write(get_path_by_pubkey(rc.pubkey)); + rc.write(get_path_by_pubkey(rc.router_id())); }); }); } @@ -121,22 +121,16 @@ namespace llarp if (not(fs::is_regular_file(f) and f.extension() == RC_FILE_EXT)) return true; - RouterContact rc{}; + RemoteRC rc{}; - if (not rc.Read(f)) + if (not rc.read(f)) { // try loading it, purge it if it is junk purge.emplace(f); return true; } - if (not rc.FromOurNetwork()) - { - // skip entries that are not from our network - return true; - } - - if (rc.IsExpired(time_now_ms())) + if (rc.is_expired(time_now_ms())) { // rc expired dont load it and purge it later purge.emplace(f); @@ -145,8 +139,8 @@ namespace llarp // validate signature and purge entries with invalid signatures // load ones with valid signatures - if (rc.VerifySignature()) - entries.emplace(rc.pubkey, rc); + if (rc.verify()) + entries.emplace(rc.router_id(), rc); else purge.emplace(f); @@ -172,7 +166,7 @@ namespace llarp router.loop()->call([this]() { for (const auto& item : entries) - item.second.rc.Write(get_path_by_pubkey(item.first)); + item.second.rc.write(get_path_by_pubkey(item.first)); }); } @@ -183,10 +177,10 @@ namespace llarp [this, pk]() -> bool { return entries.find(pk) != entries.end(); }); } - std::optional + std::optional NodeDB::get_rc(RouterID pk) const { - return router.loop()->call_get([this, pk]() -> std::optional { + return router.loop()->call_get([this, pk]() -> std::optional { const auto itr = entries.find(pk); if (itr == entries.end()) @@ -213,9 +207,9 @@ namespace llarp auto itr = entries.begin(); while (itr != entries.end()) { - if (itr->second.insertedAt < cutoff and keep.count(itr->second.rc.pubkey) == 0) + if (itr->second.insertedAt < cutoff and keep.count(itr->second.rc.router_id()) == 0) { - removed.insert(itr->second.rc.pubkey); + removed.insert(itr->second.rc.router_id()); itr = entries.erase(itr); } else @@ -227,11 +221,12 @@ namespace llarp } void - NodeDB::put_rc(RouterContact rc) + NodeDB::put_rc(RemoteRC rc) { router.loop()->call([this, rc]() { - entries.erase(rc.pubkey); - entries.emplace(rc.pubkey, rc); + const auto& rid = rc.router_id(); + entries.erase(rid); + entries.emplace(rid, rc); }); } @@ -242,17 +237,17 @@ namespace llarp } void - NodeDB::put_rc_if_newer(RouterContact rc) + NodeDB::put_rc_if_newer(RemoteRC rc) { router.loop()->call([this, rc]() { - auto itr = entries.find(rc.pubkey); - if (itr == entries.end() or itr->second.rc.OtherIsNewer(rc)) + auto itr = entries.find(rc.router_id()); + if (itr == entries.end() or itr->second.rc.other_is_newer(rc)) { // delete if existing if (itr != entries.end()) entries.erase(itr); // add new entry - entries.emplace(rc.pubkey, rc); + entries.emplace(rc.router_id(), rc); } }); } @@ -275,32 +270,31 @@ namespace llarp }); } - llarp::RouterContact + RemoteRC NodeDB::find_closest_to(llarp::dht::Key_t location) const { - return router.loop()->call_get([this, location]() { - llarp::RouterContact rc; + return router.loop()->call_get([this, location]() -> RemoteRC { + RemoteRC rc; const llarp::dht::XorMetric compare(location); + VisitAll([&rc, compare](const auto& otherRC) { - if (rc.pubkey.IsZero()) + const auto& rid = rc.router_id(); + + if (rid.IsZero() || compare(dht::Key_t{otherRC.router_id()}, dht::Key_t{rid})) { rc = otherRC; return; } - if (compare( - llarp::dht::Key_t{otherRC.pubkey.as_array()}, - llarp::dht::Key_t{rc.pubkey.as_array()})) - rc = otherRC; }); return rc; }); } - std::vector + std::vector NodeDB::find_many_closest_to(llarp::dht::Key_t location, uint32_t numRouters) const { - return router.loop()->call_get([this, location, numRouters]() { - std::vector all; + return router.loop()->call_get([this, location, numRouters]() -> std::vector { + std::vector all; all.reserve(entries.size()); for (auto& entry : entries) @@ -314,7 +308,7 @@ namespace llarp return compare(*a, *b); }); - std::vector closest; + std::vector closest; closest.reserve(numRouters); for (auto it = all.begin(); it != it_mid; ++it) closest.push_back(**it); diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 7717b5ff5..7552fc6fd 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -26,9 +26,9 @@ namespace llarp { struct Entry { - const RouterContact rc; + const RemoteRC rc; llarp_time_t insertedAt; - explicit Entry(RouterContact rc); + explicit Entry(RemoteRC rc); }; using NodeMap = std::unordered_map; @@ -73,11 +73,11 @@ namespace llarp Tick(llarp_time_t now); /// find the absolute closets router to a dht location - RouterContact + RemoteRC find_closest_to(dht::Key_t location) const; /// find many routers closest to dht key - std::vector + std::vector find_many_closest_to(dht::Key_t location, uint32_t numRouters) const; /// return true if we have an rc by its ident pubkey @@ -85,14 +85,14 @@ namespace llarp has_router(RouterID pk) const; /// maybe get an rc by its ident pubkey - std::optional + std::optional get_rc(RouterID pk) const; template - std::optional + std::optional GetRandom(Filter visit) const { - return router.loop()->call_get([visit]() -> std::optional { + return router.loop()->call_get([visit]() -> std::optional { std::vector entries; for (const auto& entry : entries) entries.push_back(entry); @@ -150,7 +150,7 @@ namespace llarp { if (visit(itr->second.rc)) { - removed.insert(itr->second.rc.pubkey); + removed.insert(itr->second.rc.router_id()); itr = entries.erase(itr); } else @@ -167,10 +167,10 @@ namespace llarp /// put this rc into the cache if it is not there or newer than the one there already void - put_rc_if_newer(RouterContact rc); + put_rc_if_newer(RemoteRC rc); /// unconditional put of rc into cache void - put_rc(RouterContact rc); + put_rc(RemoteRC rc); }; } // namespace llarp diff --git a/llarp/path/path.cpp b/llarp/path/path.cpp index 75be48791..3fb7ad8fa 100644 --- a/llarp/path/path.cpp +++ b/llarp/path/path.cpp @@ -10,7 +10,7 @@ namespace llarp::path { Path::Path( Router* rtr, - const std::vector& h, + const std::vector& h, std::weak_ptr pathset, PathRole startingRoles, std::string shortName) @@ -40,7 +40,7 @@ namespace llarp::path hops[idx].txID = hops[idx + 1].rxID; } // initialize parts of the introduction - intro.router = hops[hsz - 1].rc.pubkey; + intro.router = hops[hsz - 1].rc.router_id(); intro.path_id = hops[hsz - 1].txID; if (auto parent = m_PathSet.lock()) EnterState(ePathBuilding, parent->Now()); @@ -152,13 +152,13 @@ namespace llarp::path RouterID Path::Endpoint() const { - return hops[hops.size() - 1].rc.pubkey; + return hops[hops.size() - 1].rc.router_id(); } PubKey Path::EndpointPubKey() const { - return hops[hops.size() - 1].rc.pubkey; + return hops[hops.size() - 1].rc.router_id(); } PathID_t @@ -184,13 +184,13 @@ namespace llarp::path bool Path::is_endpoint(const RouterID& r, const PathID_t& id) const { - return hops[hops.size() - 1].rc.pubkey == r && hops[hops.size() - 1].txID == id; + return hops[hops.size() - 1].rc.router_id() == r && hops[hops.size() - 1].txID == id; } RouterID Path::upstream() const { - return hops[0].rc.pubkey; + return hops[0].rc.router_id(); } const std::string& @@ -208,7 +208,7 @@ namespace llarp::path { if (!hops.empty()) hops_str += " -> "; - hops_str += RouterID(hop.rc.pubkey).ToString(); + hops_str += hop.rc.router_id().ToView(); } return hops_str; } @@ -262,9 +262,9 @@ namespace llarp::path PathHopConfig::ExtractStatus() const { util::StatusObject obj{ - {"ip", rc.addr.to_string()}, + {"ip", rc.addr().to_string()}, {"lifetime", to_json(lifetime)}, - {"router", rc.pubkey.ToHex()}, + {"router", rc.router_id().ToHex()}, {"txid", txID.ToHex()}, {"rxid", rxID.ToHex()}}; return obj; @@ -330,11 +330,13 @@ namespace llarp::path { if (auto parent = m_PathSet.lock()) { - std::vector newHops; + std::vector new_hops; + for (const auto& hop : hops) - newHops.emplace_back(hop.rc); + new_hops.emplace_back(hop.rc); + LogInfo(name(), " rebuilding on ", ShortName()); - parent->Build(newHops); + parent->Build(new_hops); } } diff --git a/llarp/path/path.hpp b/llarp/path/path.hpp index 4af30f54f..e427997ef 100644 --- a/llarp/path/path.hpp +++ b/llarp/path/path.hpp @@ -69,7 +69,7 @@ namespace llarp Path( Router* rtr, - const std::vector& routers, + const std::vector& routers, std::weak_ptr parent, PathRole startingRoles, std::string shortName); diff --git a/llarp/path/path_types.hpp b/llarp/path/path_types.hpp index 374660e55..47401033e 100644 --- a/llarp/path/path_types.hpp +++ b/llarp/path/path_types.hpp @@ -26,7 +26,7 @@ namespace llarp /// path id PathID_t txID, rxID; // router contact of router - RouterContact rc; + RemoteRC rc; // temp public encryption key SecretKey commkey; /// shared secret at this hop diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index 7b78ead31..2f831bf06 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -83,7 +83,7 @@ namespace llarp hop.nonce.Randomize(); // do key exchange - if (!crypto::dh_client(hop.shared, hop.rc.pubkey, hop.commkey, hop.nonce)) + if (!crypto::dh_client(hop.shared, hop.rc.router_id(), hop.commkey, hop.nonce)) { auto err = fmt::format("{} failed to generate shared key for path build!", Name()); log::error(path_cat, err); @@ -121,7 +121,7 @@ namespace llarp outer_nonce.Randomize(); // derive (outer) shared key - if (!crypto::dh_client(shared, hop.rc.pubkey, framekey, outer_nonce)) + if (!crypto::dh_client(shared, hop.rc.router_id(), framekey, outer_nonce)) { log::error(path_cat, "DH client failed during hop info encryption!"); throw std::runtime_error{"DH failed during hop info encryption"}; @@ -211,23 +211,25 @@ namespace llarp return obj; } - std::optional + std::optional Builder::SelectFirstHop(const std::set& exclude) const { - std::optional found = std::nullopt; + std::optional found = std::nullopt; router->for_each_connection([&](link::Connection& conn) { const auto& rc = conn.remote_rc; + const auto& rid = rc.router_id(); + #ifndef TESTNET - if (router->IsBootstrapNode(rc.pubkey)) + if (router->IsBootstrapNode(rid)) return; #endif - if (exclude.count(rc.pubkey)) + if (exclude.count(rid)) return; - if (BuildCooldownHit(rc.pubkey)) + if (BuildCooldownHit(rid)) return; - if (router->router_profiling().IsBadForPath(rc.pubkey)) + if (router->router_profiling().IsBadForPath(rid)) return; found = rc; @@ -235,15 +237,15 @@ namespace llarp return found; } - std::optional> + std::optional> Builder::GetHopsForBuild() { auto filter = [r = router](const auto& rc) -> bool { - return not r->router_profiling().IsBadForPath(rc.pubkey, 1); + return not r->router_profiling().IsBadForPath(rc.router_id(), 1); }; if (const auto maybe = router->node_db()->GetRandom(filter)) { - return GetHopsAlignedToForBuild(maybe->pubkey); + return GetHopsAlignedToForBuild(maybe->router_id()); } return std::nullopt; } @@ -308,12 +310,12 @@ namespace llarp return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4; } - std::optional> + std::optional> Builder::GetHopsAlignedToForBuild(RouterID endpoint, const std::set& exclude) { const auto pathConfig = router->config()->paths; - std::vector hops; + std::vector hops; { const auto maybe = SelectFirstHop(exclude); if (not maybe.has_value()) @@ -324,7 +326,7 @@ namespace llarp hops.emplace_back(*maybe); }; - RouterContact endpointRC; + RemoteRC endpointRC; if (const auto maybe = router->node_db()->get_rc(endpoint)) { endpointRC = *maybe; @@ -341,19 +343,21 @@ namespace llarp else { auto filter = - [&hops, r = router, endpointRC, pathConfig, exclude](const auto& rc) -> bool { - if (exclude.count(rc.pubkey)) + [&hops, r = router, endpointRC, pathConfig, exclude](const RemoteRC& rc) -> bool { + const auto& rid = rc.router_id(); + + if (exclude.count(rid)) return false; - std::set hopsSet; + std::set hopsSet; hopsSet.insert(endpointRC); hopsSet.insert(hops.begin(), hops.end()); - if (r->router_profiling().IsBadForPath(rc.pubkey, 1)) + if (r->router_profiling().IsBadForPath(rid, 1)) return false; for (const auto& hop : hopsSet) { - if (hop.pubkey == rc.pubkey) + if (hop.router_id() == rid) return false; } @@ -362,7 +366,7 @@ namespace llarp if (not pathConfig.Acceptable(hopsSet)) return false; #endif - return rc.pubkey != endpointRC.pubkey; + return rc.router_id() != endpointRC.router_id(); }; if (const auto maybe = router->node_db()->GetRandom(filter)) @@ -393,7 +397,7 @@ namespace llarp } void - Builder::Build(std::vector hops, PathRole roles) + Builder::Build(std::vector hops, PathRole roles) { if (IsStopped()) { @@ -402,7 +406,7 @@ namespace llarp } lastBuild = llarp::time_now_ms(); - const RouterID edge{hops[0].pubkey}; + const auto& edge = hops[0].router_id(); if (not router->pathbuild_limiter().Attempt(edge)) { @@ -429,7 +433,8 @@ namespace llarp { bool lastHop = (i == (n_hops - 1)); - const auto& nextHop = lastHop ? path_hops[i].rc.pubkey : path_hops[i + 1].rc.pubkey; + const auto& nextHop = + lastHop ? path_hops[i].rc.router_id() : path_hops[i + 1].rc.router_id(); PathBuildMessage::setup_hop_keys(path_hops[i], nextHop); auto frame_str = PathBuildMessage::serialize(path_hops[i]); @@ -533,7 +538,7 @@ namespace llarp DoPathBuildBackoff(); for (const auto& hop : p->hops) { - const RouterID target{hop.rc.pubkey}; + 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); diff --git a/llarp/path/pathbuilder.hpp b/llarp/path/pathbuilder.hpp index 480f7df6d..35fbdb1dc 100644 --- a/llarp/path/pathbuilder.hpp +++ b/llarp/path/pathbuilder.hpp @@ -115,17 +115,17 @@ namespace llarp::path bool BuildOneAlignedTo(const RouterID endpoint) override; - std::optional> + std::optional> GetHopsAlignedToForBuild(RouterID endpoint, const std::set& exclude = {}); void - Build(std::vector hops, PathRole roles = ePathRoleAny) override; + Build(std::vector hops, PathRole roles = ePathRoleAny) override; /// pick a first hop - std::optional + std::optional SelectFirstHop(const std::set& exclude = {}) const; - std::optional> + std::optional> GetHopsForBuild() override; void diff --git a/llarp/path/pathset.hpp b/llarp/path/pathset.hpp index 914c97da1..c228823ac 100644 --- a/llarp/path/pathset.hpp +++ b/llarp/path/pathset.hpp @@ -122,7 +122,7 @@ namespace llarp /// manual build on these hops virtual void - Build(std::vector hops, PathRole roles = ePathRoleAny) = 0; + Build(std::vector hops, PathRole roles = ePathRoleAny) = 0; /// tick owned paths virtual void @@ -252,7 +252,7 @@ namespace llarp virtual void send_packet_to_remote(std::string buf) = 0; - virtual std::optional> + virtual std::optional> GetHopsForBuild() = 0; void diff --git a/llarp/profiling.cpp b/llarp/profiling.cpp index 3ae00f387..ee0428c1e 100644 --- a/llarp/profiling.cpp +++ b/llarp/profiling.cpp @@ -10,8 +10,6 @@ using oxenc::bt_dict_producer; namespace llarp { - static auto logcat = log::Cat("profiling"); - RouterProfile::RouterProfile(bt_dict_consumer dict) { BDecode(std::move(dict)); @@ -204,7 +202,7 @@ namespace llarp first = false; else { - auto& profile = m_Profiles[hop.rc.pubkey]; + auto& profile = m_Profiles[hop.rc.router_id()]; profile.pathFailCount += 1; profile.lastUpdated = llarp::time_now_ms(); } @@ -217,7 +215,7 @@ namespace llarp util::Lock lock{m_ProfilesMutex}; for (const auto& hop : p->hops) { - auto& profile = m_Profiles[hop.rc.pubkey]; + auto& profile = m_Profiles[hop.rc.router_id()]; profile.pathTimeoutCount += 1; profile.lastUpdated = llarp::time_now_ms(); } @@ -230,7 +228,7 @@ namespace llarp const auto sz = p->hops.size(); for (const auto& hop : p->hops) { - auto& profile = m_Profiles[hop.rc.pubkey]; + auto& profile = m_Profiles[hop.rc.router_id()]; // redeem previous fails by halfing the fail count and setting timeout to zero profile.pathFailCount /= 2; profile.pathTimeoutCount = 0; @@ -262,7 +260,7 @@ namespace llarp try { - util::dump_file(fpath, buf); + util::buffer_to_file(fpath, buf); } catch (const std::exception& e) { @@ -299,7 +297,7 @@ namespace llarp { try { - std::string data = util::slurp_file(fname); + std::string data = util::file_to_string(fname); util::Lock lock{m_ProfilesMutex}; BDecode(bt_dict_consumer{data}); } diff --git a/llarp/router/rc_gossiper.cpp b/llarp/router/rc_gossiper.cpp index 429a4b697..a5da35bd3 100644 --- a/llarp/router/rc_gossiper.cpp +++ b/llarp/router/rc_gossiper.cpp @@ -28,9 +28,9 @@ namespace llarp } bool - RCGossiper::IsOurRC(const RouterContact& rc) const + RCGossiper::IsOurRC(const LocalRC& rc) const { - return rc.pubkey == rid; + return rc.router_id() == rid; } void @@ -64,14 +64,14 @@ namespace llarp } bool - RCGossiper::GossipRC(const RouterContact& rc) + RCGossiper::GossipRC(const LocalRC& rc) { // only distribute public routers - if (not rc.IsPublicRouter()) + if (not rc.is_public_router()) return false; if (link_manager == nullptr) return false; - const RouterID pubkey(rc.pubkey); + const RouterID pubkey(rc.router_id()); // filter check if (filter.Contains(pubkey)) return false; diff --git a/llarp/router/rc_gossiper.hpp b/llarp/router/rc_gossiper.hpp index 3678f0632..a0c72fc80 100644 --- a/llarp/router/rc_gossiper.hpp +++ b/llarp/router/rc_gossiper.hpp @@ -12,7 +12,7 @@ namespace llarp /// The maximum number of peers we will flood a gossiped RC to when propagating an RC constexpr size_t MaxGossipPeers = 20; struct LinkManager; - struct RouterContact; + struct LocalRC; struct RCGossiper { @@ -23,7 +23,7 @@ namespace llarp ~RCGossiper() = default; bool - GossipRC(const RouterContact& rc); + GossipRC(const LocalRC& rc); void Decay(Time_t now); @@ -32,7 +32,7 @@ namespace llarp ShouldGossipOurRC(Time_t now) const; bool - IsOurRC(const RouterContact& rc) const; + IsOurRC(const LocalRC& rc) const; void Init(LinkManager*, const RouterID&, Router*); diff --git a/llarp/router/rc_lookup_handler.cpp b/llarp/router/rc_lookup_handler.cpp index 8cb96b10d..b284b9562 100644 --- a/llarp/router/rc_lookup_handler.cpp +++ b/llarp/router/rc_lookup_handler.cpp @@ -66,7 +66,7 @@ namespace llarp void RCLookupHandler::get_rc(const RouterID& rid, RCRequestCallback callback, bool forceLookup) { - RouterContact remoteRC; + RemoteRC remoteRC; if (not forceLookup) { @@ -101,7 +101,7 @@ namespace llarp throw; } - RouterContact result{std::move(payload)}; + RemoteRC result{std::move(payload)}; if (callback) callback(result.router_id(), result, true); @@ -202,24 +202,24 @@ namespace llarp } bool - RCLookupHandler::check_rc(const RouterContact& rc) const + RCLookupHandler::check_rc(const RemoteRC& rc) const { - if (not is_session_allowed(rc.pubkey)) + if (not is_session_allowed(rc.router_id())) { - contacts->delete_rc_node_async(dht::Key_t{rc.pubkey}); + contacts->delete_rc_node_async(dht::Key_t{rc.router_id()}); return false; } - if (not rc.Verify(llarp::time_now_ms())) + if (not rc.verify()) { - LogWarn("RC for ", RouterID(rc.pubkey), " is invalid"); + log::info(link_cat, "Invalid RC (rid: {})", rc.router_id()); return false; } // update nodedb if required - if (rc.IsPublicRouter()) + if (rc.is_public_router()) { - LogDebug("Adding or updating RC for ", RouterID(rc.pubkey), " to nodedb and dht."); + 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); } @@ -248,29 +248,6 @@ namespace llarp }); } - bool - RCLookupHandler::check_renegotiate_valid(RouterContact newrc, RouterContact oldrc) - { - // mismatch of identity ? - if (newrc.pubkey != oldrc.pubkey) - return false; - - if (!is_session_allowed(newrc.pubkey)) - return false; - - auto func = [this, newrc] { check_rc(newrc); }; - work_func(func); - - // update dht if required - if (contacts->rc_nodes()->HasNode(dht::Key_t{newrc.pubkey})) - { - contacts->rc_nodes()->PutNode(newrc); - } - - // TODO: check for other places that need updating the RC - return true; - } - void RCLookupHandler::periodic_update(llarp_time_t now) { @@ -278,15 +255,15 @@ namespace llarp std::unordered_set routersToLookUp; node_db->VisitInsertedBefore( - [&](const RouterContact& rc) { routersToLookUp.insert(rc.pubkey); }, - now - RouterContact::UpdateInterval); + [&](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::StaleInsertionAge); + node_db->remove_stale_rcs(boostrap_rid_list, now - RouterContact::STALE); } void @@ -301,7 +278,8 @@ namespace llarp { for (const auto& rc : bootstrap_rc_list) { - log::info(link_cat, "Doing explore via bootstrap node: {}", RouterID(rc.pubkey)); + 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}); @@ -336,7 +314,7 @@ namespace llarp return; } // service nodes gossip, not explore - if (contacts->router()->IsServiceNode()) + if (contacts->router()->is_service_node()) return; // explore via every connected peer @@ -367,7 +345,7 @@ namespace llarp LinkManager* linkManager, service::Context* hiddenServiceContext, const std::unordered_set& strictConnectPubkeys, - const std::set& bootstrapRCList, + const std::set& bootstrapRCList, bool isServiceNode_arg) { contacts = c; @@ -383,7 +361,7 @@ namespace llarp for (const auto& rc : bootstrap_rc_list) { - boostrap_rid_list.insert(rc.pubkey); + boostrap_rid_list.insert(rc.router_id()); } } @@ -392,7 +370,7 @@ namespace llarp { for (const auto& rc : bootstrap_rc_list) { - if (rc.pubkey == remote) + if (rc.router_id() == remote) { return true; } diff --git a/llarp/router/rc_lookup_handler.hpp b/llarp/router/rc_lookup_handler.hpp index 7802a2597..f7b3f01f4 100644 --- a/llarp/router/rc_lookup_handler.hpp +++ b/llarp/router/rc_lookup_handler.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -24,7 +25,6 @@ namespace llarp struct Contacts; struct LinkManager; - struct RouterContact; enum class RCRequestResult { @@ -35,7 +35,7 @@ namespace llarp }; using RCRequestCallback = - std::function, bool success)>; + std::function, bool success)>; struct RCLookupHandler { @@ -80,14 +80,11 @@ namespace llarp is_registered(const RouterID& remote) const; bool - check_rc(const RouterContact& rc) const; + check_rc(const RemoteRC& rc) const; bool get_random_whitelist_router(RouterID& router) const; - bool - check_renegotiate_valid(RouterContact newrc, RouterContact oldrc); - void periodic_update(llarp_time_t now); @@ -106,7 +103,7 @@ namespace llarp LinkManager* linkManager, service::Context* hiddenServiceContext, const std::unordered_set& strictConnectPubkeys, - const std::set& bootstrapRCList, + const std::set& bootstrapRCList, bool isServiceNode_arg); std::unordered_set @@ -128,7 +125,7 @@ namespace llarp /// service nodes) std::unordered_set strict_connect_pubkeys; - std::set bootstrap_rc_list; + 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 diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index 76c948d1c..782fd7d18 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -6,8 +6,6 @@ namespace llarp { - static auto logcat = log::Cat("route-poker"); - void RoutePoker::add_route(oxen::quic::Address ip) { @@ -119,7 +117,7 @@ namespace llarp bool RoutePoker::is_enabled() const { - if (router.IsServiceNode()) + if (router.is_service_node()) return false; if (const auto& conf = router.config()) return conf->network.m_EnableRoutePoker; @@ -221,7 +219,7 @@ namespace llarp // explicit route pokes for first hops router.for_each_connection( - [this](link::Connection conn) { add_route(conn.remote_rc.addr); }); + [this](link::Connection conn) { add_route(conn.remote_rc.addr()); }); add_route(router.link_manager().local()); // add default route @@ -240,7 +238,7 @@ namespace llarp { // unpoke routes for first hops router.for_each_connection( - [this](link::Connection conn) { delete_route(conn.remote_rc.addr); }); + [this](link::Connection conn) { delete_route(conn.remote_rc.addr()); }); if (is_enabled() and is_up) { vpn::AbstractRouteManager& route = router.vpn_platform()->RouteManager(); diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 1aa99d9a1..3c6e44414 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -36,8 +36,6 @@ static constexpr std::chrono::milliseconds ROUTER_TICK_INTERVAL = 250ms; namespace llarp { - static auto logcat = log::Cat("router"); - Router::Router(EventLoop_ptr loop, std::shared_ptr vpnPlatform) : _route_poker{std::make_shared(*this)} , _lmq{std::make_shared()} @@ -178,7 +176,7 @@ namespace llarp util::StatusObject stats{ {"running", true}, - {"version", llarp::VERSION_FULL}, + {"version", llarp::LOKINET_VERSION_FULL}, {"uptime", to_json(Uptime())}, {"numPathsBuilt", pathsCount}, {"numPeersConnected", peers}, @@ -201,7 +199,7 @@ namespace llarp void Router::Freeze() { - if (IsServiceNode()) + if (is_service_node()) return; for_each_connection( @@ -211,13 +209,14 @@ namespace llarp void Router::Thaw() { - if (IsServiceNode()) + if (is_service_node()) return; std::unordered_set peer_pubkeys; - for_each_connection( - [&peer_pubkeys](link::Connection& conn) { peer_pubkeys.emplace(conn.remote_rc.pubkey); }); + for_each_connection([&peer_pubkeys](link::Connection& conn) { + peer_pubkeys.emplace(conn.remote_rc.router_id()); + }); loop()->call([this, &peer_pubkeys]() { for (auto& pk : peer_pubkeys) @@ -232,10 +231,10 @@ namespace llarp } void - Router::GossipRCIfNeeded(const RouterContact rc) + Router::GossipRCIfNeeded(const LocalRC rc) { /// if we are not a service node forget about gossip - if (not IsServiceNode()) + if (not is_service_node()) return; /// wait for random uptime if (std::chrono::milliseconds{Uptime()} < _randomStartDelay) @@ -246,14 +245,14 @@ namespace llarp bool Router::GetRandomGoodRouter(RouterID& router) { - if (IsServiceNode()) + if (is_service_node()) { return _rc_lookup_handler.get_random_whitelist_router(router); } if (auto maybe = node_db()->GetRandom([](const auto&) -> bool { return true; })) { - router = maybe->pubkey; + router = maybe->router_id(); return true; } return false; @@ -272,7 +271,7 @@ namespace llarp } void - Router::connect_to(const RouterContact& rc) + Router::connect_to(const RemoteRC& rc) { _link_manager.connect_to(rc); } @@ -315,7 +314,7 @@ namespace llarp { _encryption = _key_manager->encryptionKey; - if (IsServiceNode()) + if (is_service_node()) { #if defined(ANDROID) || defined(IOS) LogError("running a service node on mobile device is not possible."); @@ -397,9 +396,9 @@ namespace llarp log::debug(logcat, "Configuring router"); - is_service_node = conf.router.m_isRelay; + _is_service_node = conf.router.m_isRelay; - if (is_service_node) + if (_is_service_node) { rpc_addr = oxenmq::address(conf.lokid.lokidRPCAddr); _rpc_client = std::make_shared(_lmq, weak_from_this()); @@ -418,9 +417,9 @@ namespace llarp _node_db = std::move(nodedb); log::debug( - logcat, is_service_node ? "Running as a relay (service node)" : "Running as a client"); + logcat, _is_service_node ? "Running as a relay (service node)" : "Running as a client"); - if (is_service_node) + if (_is_service_node) { _rpc_client->ConnectAsync(rpc_addr); } @@ -439,34 +438,10 @@ namespace llarp return true; } - /// called in disk worker thread - void - Router::HandleSaveRC() const - { - std::string fname = our_rc_file.string(); - router_contact.Write(fname.c_str()); - } - - bool - Router::SaveRC() - { - LogDebug("verify RC signature"); - if (!router_contact.Verify(now())) - { - Dump(rc()); - LogError("RC is invalid, not saving"); - return false; - } - if (is_service_node) - _node_db->put_rc(router_contact); - queue_disk_io([&]() { HandleSaveRC(); }); - return true; - } - bool - Router::IsServiceNode() const + Router::is_service_node() const { - return is_service_node; + return _is_service_node; } bool @@ -508,7 +483,7 @@ namespace llarp bool Router::have_snode_whitelist() const { - return IsServiceNode() and _rc_lookup_handler.has_received_whitelist(); + return is_service_node() and _rc_lookup_handler.has_received_whitelist(); } bool @@ -564,18 +539,20 @@ namespace llarp return _link_manager.get_num_connected_clients(); } + void + Router::save_rc() + { + _node_db->put_rc(router_contact.view()); + queue_disk_io([&]() { router_contact.write(our_rc_file); }); + } + bool Router::update_rc() { - SecretKey nextOnionKey; - RouterContact nextRC = router_contact; - if (!nextRC.Sign(identity())) - return false; - if (!nextRC.Verify(time_now_ms(), false)) - return false; - router_contact = std::move(nextRC); - if (IsServiceNode()) - return SaveRC(); + router_contact.resign(); + if (is_service_node()) + save_rc(); + return true; } @@ -585,20 +562,17 @@ namespace llarp // Set netid before anything else log::debug(logcat, "Network ID set to {}", conf.router.m_netId); if (!conf.router.m_netId.empty() - && strcmp(conf.router.m_netId.c_str(), llarp::DEFAULT_NETID) != 0) + && strcmp(conf.router.m_netId.c_str(), llarp::LOKINET_DEFAULT_NETID) != 0) { const auto& netid = conf.router.m_netId; llarp::LogWarn( "!!!! you have manually set netid to be '", netid, "' which does not equal '", - llarp::DEFAULT_NETID, + llarp::LOKINET_DEFAULT_NETID, "' you will run as a different network, good luck " "and don't forget: something something MUH traffic " "shape correlation !!!!"); - NetID::DefaultValue() = NetID(reinterpret_cast(netid.c_str())); - // reset netid in our rc - router_contact.netID = llarp::NetID(); } // Router config @@ -628,16 +602,17 @@ namespace llarp else log::debug(logcat, "No explicit public address given; will auto-detect during link setup"); - RouterContact::BlockBogons = conf.router.m_blockBogons; + RouterContact::BLOCK_BOGONS = conf.router.m_blockBogons; auto& networkConfig = conf.network; - /// build a set of strictConnectPubkeys ( + /// build a set of strictConnectPubkeys std::unordered_set strictConnectPubkeys; + if (not networkConfig.m_strictConnect.empty()) { const auto& val = networkConfig.m_strictConnect; - if (IsServiceNode()) + if (is_service_node()) throw std::runtime_error("cannot use strict-connect option as service node"); if (val.size() < 2) throw std::runtime_error( @@ -666,7 +641,7 @@ namespace llarp for (const auto& router : configRouters) { log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile); - bootstrap_rc_list.AddFromFile(router); + bootstrap_rc_list.read_from_file(router); } for (const auto& rc : conf.bootstrap.routers) @@ -674,37 +649,10 @@ namespace llarp bootstrap_rc_list.emplace(rc); } - // in case someone has an old bootstrap file and is trying to use a bootstrap - // that no longer exists - auto clearBadRCs = [this]() { - for (auto it = bootstrap_rc_list.begin(); it != bootstrap_rc_list.end();) - { - if (it->IsObsoleteBootstrap()) - log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID{it->pubkey}); - else if (not it->Verify(now())) - log::warning(logcat, "ignoring invalid bootstrap RC: {}", RouterID{it->pubkey}); - else - { - ++it; - continue; - } - // we are in one of the above error cases that we warned about: - it = bootstrap_rc_list.erase(it); - } - }; - - clearBadRCs(); - if (bootstrap_rc_list.empty() and not conf.bootstrap.seednode) { auto fallbacks = llarp::load_bootstrap_fallbacks(); - if (auto itr = fallbacks.find(router_contact.netID.ToString()); itr != fallbacks.end()) - { - bootstrap_rc_list = itr->second; - log::debug( - logcat, "loaded {} default fallback bootstrap routers", bootstrap_rc_list.size()); - clearBadRCs(); - } + if (bootstrap_rc_list.empty() and not conf.bootstrap.seednode) { // empty after trying fallback, if set @@ -717,6 +665,24 @@ namespace llarp } } + // 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();) + { + if (it->is_obsolete_bootstrap()) + log::warning(logcat, "ignoring obsolete boostrap RC: {}", it->router_id()); + else if (not it->verify()) + log::warning(logcat, "ignoring invalid bootstrap RC: {}", it->router_id()); + else + { + ++it; + continue; + } + + // we are in one of the above error cases that we warned about: + it = bootstrap_rc_list.erase(it); + } + if (conf.bootstrap.seednode) LogInfo("we are a seed node"); else @@ -733,10 +699,10 @@ namespace llarp &_hidden_service_context, strictConnectPubkeys, bootstrap_rc_list, - is_service_node); + _is_service_node); // FIXME: kludge for now, will be part of larger cleanup effort. - if (is_service_node) + if (_is_service_node) InitInboundLinks(); else InitOutboundLinks(); @@ -765,7 +731,7 @@ namespace llarp } // API config - if (not IsServiceNode()) + if (not is_service_node()) { hidden_service_context().AddEndpoint(conf); } @@ -773,19 +739,13 @@ namespace llarp return true; } - bool - Router::CheckRenegotiateValid(RouterContact newrc, RouterContact oldrc) - { - return _rc_lookup_handler.check_renegotiate_valid(newrc, oldrc); - } - bool Router::IsBootstrapNode(const RouterID r) const { return std::count_if( bootstrap_rc_list.begin(), bootstrap_rc_list.end(), - [r](const RouterContact& rc) -> bool { return rc.pubkey == r; }) + [r](const RemoteRC& rc) -> bool { return rc.router_id() == r; }) > 0; } @@ -800,17 +760,24 @@ namespace llarp Router::report_stats() { const auto now = llarp::time_now_ms(); - LogInfo(node_db()->num_loaded(), " RCs loaded"); - LogInfo(bootstrap_rc_list.size(), " bootstrap peers"); - LogInfo(NumberOfConnectedRouters(), " router connections"); - if (IsServiceNode()) + log::info( + logcat, + "{} RCs loaded with {} bootstrap peers and {} router connections!", + node_db()->num_loaded(), + bootstrap_rc_list.size(), + NumberOfConnectedRouters()); + + if (is_service_node()) { - LogInfo(NumberOfConnectedClients(), " client connections"); - LogInfo(ToString(router_contact.Age(now)), " since we last updated our RC"); - LogInfo(ToString(router_contact.TimeUntilExpires(now)), " until our RC expires"); + log::info( + logcat, + "Local service node has {} client connections since last RC update ({} to expiry)", + NumberOfConnectedClients(), + router_contact.age(now), + router_contact.time_to_expiry(now)); } if (_last_stats_report > 0s) - LogInfo(ToString(now - _last_stats_report), " last reported stats"); + log::info(logcat, "Last reported stats time {}", now - _last_stats_report); _last_stats_report = now; } @@ -819,8 +786,8 @@ namespace llarp { std::string status; auto out = std::back_inserter(status); - fmt::format_to(out, "v{}", fmt::join(llarp::VERSION, ".")); - if (IsServiceNode()) + fmt::format_to(out, "v{}", fmt::join(llarp::LOKINET_VERSION, ".")); + if (is_service_node()) { fmt::format_to( out, @@ -896,12 +863,13 @@ namespace llarp _rc_lookup_handler.periodic_update(now); const bool has_whitelist = _rc_lookup_handler.has_received_whitelist(); - const bool is_snode = IsServiceNode(); + const bool is_snode = is_service_node(); const bool is_decommed = appears_decommed(); bool should_gossip = appears_funded(); if (is_snode - and (router_contact.ExpiresSoon(now, std::chrono::milliseconds(randint() % 10000)) or (now - router_contact.last_updated) > rc_regen_interval)) + and (router_contact.expires_within_delta(now, std::chrono::milliseconds(randint() % 10000)) + or (now - router_contact.timestamp().time_since_epoch()) > rc_regen_interval)) { LogInfo("regenerating RC"); if (update_rc()) @@ -921,24 +889,24 @@ namespace llarp GossipRCIfNeeded(router_contact); } // remove RCs for nodes that are no longer allowed by network policy - node_db()->RemoveIf([&](const RouterContact& rc) -> bool { + node_db()->RemoveIf([&](const RemoteRC& rc) -> bool { // don't purge bootstrap nodes from nodedb - if (IsBootstrapNode(rc.pubkey)) + if (IsBootstrapNode(rc.router_id())) { - log::trace(logcat, "Not removing {}: is bootstrap node", rc.pubkey); + log::trace(logcat, "Not removing {}: is bootstrap node", rc.router_id()); return false; } // if for some reason we stored an RC that isn't a valid router // purge this entry - if (not rc.IsPublicRouter()) + if (not rc.is_public_router()) { - log::debug(logcat, "Removing {}: not a valid router", rc.pubkey); + log::debug(logcat, "Removing {}: not a valid router", rc.router_id()); return true; } /// clear out a fully expired RC - if (rc.IsExpired(now)) + if (rc.is_expired(now)) { - log::debug(logcat, "Removing {}: RC is expired", rc.pubkey); + log::debug(logcat, "Removing {}: RC is expired", rc.router_id()); return true; } // clients have no notion of a whilelist @@ -946,23 +914,23 @@ namespace llarp // routers that are not whitelisted for first hops if (not is_snode) { - log::trace(logcat, "Not removing {}: we are a client and it looks fine", rc.pubkey); + log::trace(logcat, "Not removing {}: we are a client and it looks fine", rc.router_id()); return false; } // if we don't have the whitelist yet don't remove the entry if (not has_whitelist) { - log::debug(logcat, "Skipping check on {}: don't have whitelist yet", rc.pubkey); + log::debug(logcat, "Skipping check on {}: don't have whitelist yet", rc.router_id()); return false; } // if we have no whitelist enabled or we have // 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.pubkey)) + if (has_whitelist and not _rc_lookup_handler.is_session_allowed(rc.router_id())) { - log::debug(logcat, "Removing {}: not a valid router", rc.pubkey); + log::debug(logcat, "Removing {}: not a valid router", rc.router_id()); return true; } return false; @@ -971,10 +939,10 @@ namespace llarp if (not is_snode or not has_whitelist) { // find all deregistered relays - std::unordered_set close_peers; + std::unordered_set close_peers; for_each_connection([this, &close_peers](link::Connection& conn) { - const auto& pk = conn.remote_rc.pubkey; + const auto& pk = conn.remote_rc.router_id(); if (conn.remote_is_relay and not _rc_lookup_handler.is_session_allowed(pk)) close_peers.insert(pk); @@ -982,7 +950,7 @@ namespace llarp // mark peers as de-registered for (auto& peer : close_peers) - _link_manager.deregister_peer(std::move(peer)); + _link_manager.deregister_peer(peer); } _link_manager.check_persisting_conns(now); @@ -1051,7 +1019,7 @@ namespace llarp std::set peer_keys; for_each_connection( - [&peer_keys](link::Connection& conn) { peer_keys.emplace(conn.remote_rc.pubkey); }); + [&peer_keys](link::Connection& conn) { peer_keys.emplace(conn.remote_rc.router_id()); }); _contacts->rc_nodes()->RemoveIf( [&peer_keys](const dht::Key_t& k) -> bool { return peer_keys.count(k) == 0; }); @@ -1062,32 +1030,12 @@ namespace llarp _last_tick = llarp::time_now_ms(); } - void - Router::modify_rc(std::function(RouterContact)> modify) - { - if (auto maybe = modify(rc())) - { - router_contact = *maybe; - update_rc(); - _rcGossiper.GossipRC(rc()); - } - } - bool - Router::GetRandomConnectedRouter(RouterContact& result) const + Router::GetRandomConnectedRouter(RemoteRC& result) const { return _link_manager.get_random_connected(result); } - void - Router::HandleDHTLookupForExplore(RouterID /*remote*/, const std::vector& results) - { - for (const auto& rc : results) - { - _rc_lookup_handler.check_rc(rc); - } - } - void Router::set_router_whitelist( const std::vector& whitelist, @@ -1112,80 +1060,48 @@ namespace llarp if (is_running || is_stopping) return false; - // set public signing key - router_contact.pubkey = seckey_topublic(identity()); - // set router version if service node - if (IsServiceNode()) - { - router_contact.routerVersion = RouterVersion(llarp::VERSION, llarp::constants::proto_version); - } + router_contact = LocalRC::make(identity(), public_ip()); - if (IsServiceNode() and not router_contact.IsPublicRouter()) + if (is_service_node() and not router_contact.is_public_router()) { - LogError("we are configured as relay but have no reachable addresses"); - return false; - } - - // set public encryption key - router_contact.enckey = seckey_topublic(encryption()); - - LogInfo("Signing rc..."); - if (!router_contact.Sign(identity())) - { - LogError("failed to sign rc"); - return false; - } - - if (IsServiceNode()) - { - if (!SaveRC()) + if (not router_contact.is_public_router()) { - LogError("failed to save RC"); + log::error(logcat, "Router is configured as relay but has no reachable addresses!"); return false; } - } - if (IsServiceNode()) - { - // initialize as service node - if (!InitServiceNode()) + save_rc(); + + if (not init_service_node()) { - LogError("Failed to initialize service node"); + log::error(logcat, "Router failed to initialize service node!"); return false; } + + log::info(logcat, "Router initialized as service node!"); const RouterID us = pubkey(); - LogInfo("initalized service node: ", us); - // init gossiper here _rcGossiper.Init(&_link_manager, us, this); // relays do not use profiling router_profiling().Disable(); } else { - // we are a client - // regenerate keys and resign rc before everything else + // we are a client, regenerate keys and resign rc before everything else crypto::identity_keygen(_identity); crypto::encryption_keygen(_encryption); - router_contact.pubkey = seckey_topublic(identity()); - router_contact.enckey = seckey_topublic(encryption()); - if (!router_contact.Sign(identity())) - { - LogError("failed to regenerate keys and sign RC"); - return false; - } + router_contact.set_router_id(seckey_to_pubkey(identity())); // resigns RC } - LogInfo("starting hidden service context..."); + log::info(logcat, "Starting hidden service context..."); + if (!hidden_service_context().StartAll()) { - LogError("Failed to start hidden service context"); + log::error(logcat, "Failed to start hidden service context!"); return false; } - { - LogInfo("Loading nodedb from disk..."); - _node_db->load_from_disk(); - } + log::info(logcat, "Loading NodeDB from disk..."); + _node_db->load_from_disk(); _contacts = std::make_shared(llarp::dht::Key_t(pubkey()), *this); @@ -1193,16 +1109,17 @@ namespace llarp { node_db()->put_rc(rc); _contacts->rc_nodes()->PutNode(rc); - LogInfo("added bootstrap node ", RouterID{rc.pubkey}); + log::info(logcat, "Added bootstrap node (rid: {})", rc.router_id()); } - LogInfo("have ", _node_db->num_loaded(), " routers"); + log::info(logcat, "Router populated NodeDB with {} routers", _node_db->num_loaded()); _loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); }); _route_poker->start(); is_running.store(true); _started_at = now(); - if (IsServiceNode()) + + if (is_service_node()) { // do service node testing if we are in service node whitelist mode _loop->call_every(consensus::REACHABILITY_TESTING_TIMER_INTERVAL, weak_from_this(), [this] { @@ -1223,13 +1140,16 @@ namespace llarp { if (not SessionToRouterAllowed(router)) { - LogDebug( - router, - " is no longer a registered service node so we remove it from the testing list"); + log::debug( + logcat, + "{} is no longer a registered service node; dropping from test list", + router); router_testing.remove_node_from_failing(router); continue; } - LogDebug("Establishing session to ", router, " for SN testing"); + + log::debug(logcat, "Establishing session to {} for service node testing", router); + // try to make a session to this random router // this will do a dht lookup if needed _link_manager.connect_to(router); @@ -1406,7 +1326,7 @@ namespace llarp } bool - Router::InitServiceNode() + Router::init_service_node() { LogInfo("accepting transit traffic"); paths.AllowTransit(); @@ -1430,7 +1350,7 @@ namespace llarp bool Router::HasClientExit() const { - if (IsServiceNode()) + if (is_service_node()) return false; const auto& ep = hidden_service_context().GetDefault(); return ep and ep->HasExit(); diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 6354b37c6..9a2973477 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -85,7 +85,7 @@ namespace llarp // use file based logging? bool use_file_logging = false; // our router contact - RouterContact router_contact; + LocalRC router_contact; std::shared_ptr _lmq; path::BuildLimiter _pathbuild_limiter; std::shared_ptr loop_wakeup; @@ -94,7 +94,7 @@ namespace llarp std::atomic is_running; int _outbound_udp_socket = -1; - bool is_service_node = false; + bool _is_service_node = false; std::optional _ourAddress; oxen::quic::Address _local_addr; @@ -147,6 +147,9 @@ namespace llarp void report_stats(); + void + save_rc(); + bool update_rc(); @@ -167,7 +170,7 @@ namespace llarp connect_to(const RouterID& rid); void - connect_to(const RouterContact& rc); + connect_to(const RemoteRC& rc); Contacts* contacts() const @@ -274,7 +277,7 @@ namespace llarp return paths; } - const RouterContact& + const LocalRC& rc() const { return router_contact; @@ -295,9 +298,6 @@ namespace llarp return _rc_lookup_handler.whitelist(); } - void - modify_rc(std::function(RouterContact)> modify); - void set_router_whitelist( const std::vector& whitelist, @@ -381,7 +381,7 @@ namespace llarp status_line(); void - GossipRCIfNeeded(const RouterContact rc); + GossipRCIfNeeded(const LocalRC rc); void InitInboundLinks(); @@ -395,14 +395,14 @@ namespace llarp /// initialize us as a service node /// return true on success bool - InitServiceNode(); + init_service_node(); bool IsRunning() const; /// return true if we are running in service node mode bool - IsServiceNode() const; + is_service_node() const; std::optional OxendErrorState() const; @@ -452,12 +452,6 @@ namespace llarp bool PathToRouterAllowed(const RouterID& router) const; - void - HandleSaveRC() const; - - bool - SaveRC(); - /// return true if we are a client with an exit configured bool HasClientExit() const; @@ -465,7 +459,7 @@ namespace llarp const byte_t* pubkey() const { - return seckey_topublic(_identity); + return seckey_to_pubkey(_identity); } /// send to remote router or queue for sending @@ -489,13 +483,6 @@ namespace llarp bool IsBootstrapNode(RouterID) const; - /// check if newRc matches oldRC and update local rc for this remote contact - /// if valid - /// returns true on valid and updated - /// returns false otherwise - bool - CheckRenegotiateValid(RouterContact newRc, RouterContact oldRC); - /// call internal router ticker void Tick(); @@ -525,10 +512,7 @@ namespace llarp NumberOfConnectedClients() const; bool - GetRandomConnectedRouter(RouterContact& result) const; - - void - HandleDHTLookupForExplore(RouterID remote, const std::vector& results); + GetRandomConnectedRouter(RemoteRC& result) const; bool HasSessionTo(const RouterID& remote) const; diff --git a/llarp/router_contact.cpp b/llarp/router_contact.cpp index d57866222..68b8fcd90 100644 --- a/llarp/router_contact.cpp +++ b/llarp/router_contact.cpp @@ -12,407 +12,273 @@ namespace llarp { - static auto logcat = log::Cat("RC"); - NetID& - NetID::DefaultValue() - { - static NetID defaultID(reinterpret_cast(llarp::DEFAULT_NETID)); - return defaultID; - } - - bool RouterContact::BlockBogons = true; - - /// 1 day rc lifespan - constexpr auto rc_lifetime = 24h; - /// an RC inserted long enough ago (4 hrs) is considered stale and is removed - constexpr auto rc_stale_age = 4h; - /// window of time in which a router wil try to update their RC before it is marked stale - constexpr auto rc_update_window = 5min; - /// update RCs shortly before they are about to expire - constexpr auto rc_update_interval = rc_stale_age - rc_update_window; - - llarp_time_t RouterContact::Lifetime = rc_lifetime; - llarp_time_t RouterContact::StaleInsertionAge = rc_stale_age; - llarp_time_t RouterContact::UpdateInterval = rc_update_interval; - - /// how many rc lifetime intervals should we wait until purging an rc - constexpr auto expiration_lifetime_generations = 10; - /// the max age of an rc before we want to expire it - constexpr auto rc_expire_age = rc_lifetime * expiration_lifetime_generations; + // RouterContact::RouterContact(std::string buf) + // { + // try + // { + // oxenc::bt_list_consumer btlc{buf}; + + // // signature.from_string(btlc.consume_string()); + // signed_bt_dict = btlc.consume_string(); + + // // TODO: parse bt dict + // } + // catch (...) + // { + // log::warning(llarp_cat, "Error: RouterContact failed to populate bt encoded contents!"); + // } + // } + + // std::string + // RouterContact::bt_encode() const + // { + // oxenc::bt_dict_producer btdp; + // bt_encode(btdp); + // return std::move(btdp).str(); + // } - NetID::NetID(const byte_t* val) + void + RouterContact::bt_load(oxenc::bt_dict_consumer& data) { - const size_t len = strnlen(reinterpret_cast(val), size()); - std::copy(val, val + len, begin()); - } + 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)}; - NetID::NetID() : NetID(DefaultValue().data()) - {} + auto ipv4_port = data.require("4"); - bool - NetID::operator==(const NetID& other) const - { - return ToString() == other.ToString(); - } + if (ipv4_port.size() != 6) + throw std::runtime_error{ + "Invalid RC address: expected 6-byte IPv4 IP/port, got {}"_format(ipv4_port.size())}; - std::string - NetID::ToString() const - { - return {begin(), std::find(begin(), end(), '\0')}; - } - - bool - NetID::BDecode(llarp_buffer_t* buf) - { - Zero(); - llarp_buffer_t strbuf; - if (!bencode_read_string(buf, &strbuf)) - return false; + sockaddr_in s4; + s4.sin_family = AF_INET; - if (strbuf.sz > size()) - return false; + std::memcpy(&s4.sin_addr.s_addr, ipv4_port.data(), 4); + std::memcpy(&s4.sin_port, ipv4_port.data() + 4, 2); - std::copy(strbuf.base, strbuf.base + strbuf.sz, begin()); - return true; - } + _addr = oxen::quic::Address{&s4}; - bool - NetID::BEncode(llarp_buffer_t* buf) const - { - auto term = std::find(begin(), end(), '\0'); - return bencode_write_bytestring(buf, data(), std::distance(begin(), term)); - } + if (!_addr.is_public()) + throw std::runtime_error{"Invalid RC: IPv4 address is not a publicly routable IP"}; - RouterContact::RouterContact(std::string buf) - { - try + if (auto ipv6_port = data.maybe("6")) { - oxenc::bt_list_consumer btlc{buf}; + if (ipv6_port->size() != 18) + throw std::runtime_error{ + "Invalid RC address: expected 18-byte IPv6 IP/port, got {}"_format(ipv6_port->size())}; - signature.from_string(btlc.consume_string()); - signed_bt_dict = btlc.consume_string(); + sockaddr_in6 s6{}; + s6.sin6_family = AF_INET6; - // TODO: parse bt dict - } - catch (...) - { - log::warning(llarp_cat, "Error: RouterContact failed to populate bt encoded contents!"); - } - } + std::memcpy(&s6.sin6_addr.s6_addr, ipv6_port->data(), 16); + std::memcpy(&s6.sin6_port, ipv6_port->data() + 16, 2); - std::string - RouterContact::bt_encode() const - { - oxenc::bt_list_producer btlp; - - try - { - btlp.append(signature.ToView()); - btlp.append(signed_bt_dict); + _addr6.emplace(&s6); + if (!_addr6->is_public()) + throw std::runtime_error{"Invalid RC: IPv6 address is not a publicly routable IP"}; } - catch (...) + else { - log::warning(llarp_cat, "Error: RouterContact failed to bt encode contents!"); + _addr6.reset(); } - return std::move(btlp).str(); - } - - void - RouterContact::bt_encode_subdict(oxenc::bt_list_producer& btlp) const - { - btlp.append(signature.ToView()); - btlp.append(signed_bt_dict); - } - - std::string - RouterContact::ToTXTRecord() const - { - std::string result; - auto out = std::back_inserter(result); - fmt::format_to(out, "addr={}; pk={}", addr.to_string(), pubkey); - fmt::format_to(out, "updated={}; onion_pk={}; ", last_updated.count(), enckey.ToHex()); - if (routerVersion.has_value()) - fmt::format_to(out, "router_version={}; ", *routerVersion); - return result; - } - - bool - RouterContact::FromOurNetwork() const - { - return netID == NetID::DefaultValue(); - } + 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( + ACTIVE_NETID, netid)}; - std::string - RouterContact::bencode_signed_section() const - { - oxenc::bt_dict_producer btdp; + auto pk = data.require("p"); - btdp.append("a", addr.to_string()); - btdp.append("i", netID.ToView()); - btdp.append("k", pubkey.bt_encode()); - btdp.append("p", enckey.ToView()); - btdp.append("r", routerVersion->ToString()); + if (pk.size() != RouterID::SIZE) + throw std::runtime_error{"Invalid RC: router id has invalid size {}"_format(pk.size())}; - if (not srvRecords.empty()) - { - auto sublist = btdp.append_list("s"); + std::memcpy(_router_id.data(), pk.data(), RouterID::SIZE); - for (auto& s : srvRecords) - sublist.append(s.bt_encode()); - } + _timestamp = rc_time{std::chrono::seconds{data.require("t")}}; - btdp.append("u", last_updated.count()); + auto ver = data.require("v"); - return std::move(btdp).str(); - } + if (ver.size() != 3) + throw std::runtime_error{ + "Invalid RC router version: received {} bytes (!= 3)"_format(ver.size())}; - void - RouterContact::Clear() - { - signature.Zero(); - enckey.Zero(); - pubkey.Zero(); - routerVersion = std::optional{}; - last_updated = 0s; - srvRecords.clear(); - version = llarp::constants::proto_version; - } - - util::StatusObject - RouterContact::ExtractStatus() const - { - util::StatusObject obj{ - {"lastUpdated", last_updated.count()}, - {"publicRouter", IsPublicRouter()}, - {"identity", pubkey.ToString()}, - {"address", addr.to_string()}}; - - if (routerVersion) - { - obj["routerVersion"] = routerVersion->ToString(); - } - std::vector srv; - for (const auto& record : srvRecords) - { - srv.emplace_back(record.ExtractStatus()); - } - obj["srvRecords"] = srv; - return obj; + for (int i = 0; i < 3; i++) + _router_version[i] = ver[i]; } bool - RouterContact::BDecode(llarp_buffer_t* buf) + RouterContact::write(const fs::path& fname) const { - Clear(); - - if (*buf->cur == 'd') // old format - { - return DecodeVersion_0(buf); - } - else if (*buf->cur != 'l') // if not dict, should be new format and start with list - { - return false; - } + auto bte = view(); try { - std::string_view buf_view(reinterpret_cast(buf->cur), buf->size_left()); - oxenc::bt_list_consumer btlist(buf_view); - - uint64_t outer_version = btlist.consume_integer(); - - if (outer_version == 1) - { - bool decode_result = DecodeVersion_1(btlist); - - // advance the llarp_buffer_t since lokimq serialization is unaware of it. - // FIXME: this is broken (current_buffer got dropped), but the whole thing is getting - // replaced. - // buf->cur += btlist. - // current_buffer().data() - buf_view.data() + 1; - - return decode_result; - } - else - { - log::warning(logcat, "Received RouterContact with unkown version ({})", outer_version); - return false; - } + util::buffer_to_file(fname, bte.data(), bte.size()); } catch (const std::exception& e) { - log::debug(logcat, "RouterContact::BDecode failed: {}", e.what()); + log::error(logcat, "Failed to write RC to {}: {}", fname, e.what()); + return false; } - - return false; + return true; } - bool - RouterContact::DecodeVersion_0(llarp_buffer_t* buf) + util::StatusObject + RouterContact::extract_status() const { - return bencode_decode_dict(*this, buf); + util::StatusObject obj{ + {"lastUpdated", _timestamp.time_since_epoch().count()}, + {"publicRouter", is_public_router()}, + {"identity", _router_id.ToString()}, + {"address", _addr.to_string()}}; + + // if (routerVersion) + // { + // obj["routerVersion"] = routerVersion->ToString(); + // } + // std::vector srv; + // for (const auto& record : srvRecords) + // { + // srv.emplace_back(record.ExtractStatus()); + // } + // obj["srvRecords"] = srv; + + return obj; } bool - RouterContact::DecodeVersion_1(oxenc::bt_list_consumer& btlist) + RouterContact::BDecode(llarp_buffer_t* buf) { - auto signature_string = btlist.consume_string_view(); - signed_bt_dict = btlist.consume_dict_data(); + // TODO: unfuck all of this - if (not btlist.is_finished()) - { - log::debug(logcat, "RouterContact serialized list too long for specified version."); - return false; - } + (void)buf; - llarp_buffer_t sigbuf(signature_string.data(), signature_string.size()); - if (not signature.FromBytestring(&sigbuf)) - { - log::debug(logcat, "RouterContact serialized signature had invalid length."); - return false; - } + // clear(); + + // if (*buf->cur == 'd') // old format + // { + // return DecodeVersion_0(buf); + // } + // else if (*buf->cur != 'l') // if not dict, should be new format and start with list + // { + // return false; + // } + + // try + // { + // std::string_view buf_view(reinterpret_cast(buf->cur), buf->size_left()); + // oxenc::bt_list_consumer btlist(buf_view); + + // uint64_t outer_version = btlist.consume_integer(); + + // if (outer_version == 1) + // { + // bool decode_result = DecodeVersion_1(btlist); + + // // advance the llarp_buffer_t since lokimq serialization is unaware of it. + // // FIXME: this is broken (current_buffer got dropped), but the whole thing is getting + // // replaced. + // // buf->cur += btlist. + // // current_buffer().data() - buf_view.data() + 1; + + // return decode_result; + // } + // else + // { + // log::warning(logcat, "Received RouterContact with unkown version ({})", outer_version); + // return false; + // } + // } + // catch (const std::exception& e) + // { + // log::debug(logcat, "RouterContact::BDecode failed: {}", e.what()); + // } - llarp_buffer_t data_dict_buf(signed_bt_dict.data(), signed_bt_dict.size()); - return bencode_decode_dict(*this, &data_dict_buf); + return false; } bool RouterContact::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) { bool read = false; + (void)key; // TOFIX: fuck everything about llarp_buffer_t + // if (!BEncodeMaybeReadDictEntry("a", addr, read, key, buf)) // return false; - if (!BEncodeMaybeReadDictEntry("i", netID, read, key, buf)) - return false; + // if (!BEncodeMaybeReadDictEntry("i", netID, read, key, buf)) + // return false; - if (!BEncodeMaybeReadDictEntry("k", pubkey, read, key, buf)) - return false; + // if (!BEncodeMaybeReadDictEntry("k", _router_id, read, key, buf)) + // return false; - if (key.startswith("r")) - { - RouterVersion r; - if (not r.BDecode(buf)) - return false; - routerVersion = r; - return true; - } + // if (key.startswith("r")) + // { + // RouterVersion r; + // if (not r.BDecode(buf)) + // return false; + // routerVersion = r; + // return true; + // } - if (not BEncodeMaybeReadDictList("s", srvRecords, read, key, buf)) - return false; + // if (not BEncodeMaybeReadDictList("s", srvRecords, read, key, buf)) + // return false; - if (!BEncodeMaybeReadDictEntry("p", enckey, read, key, buf)) - return false; + // if (!BEncodeMaybeReadDictEntry("p", enckey, read, key, buf)) + // return false; - if (!BEncodeMaybeReadDictInt("u", last_updated, read, key, buf)) - return false; + // if (!BEncodeMaybeReadDictInt("u", _timestamp, read, key, buf)) + // return false; - if (!BEncodeMaybeReadDictInt("v", version, read, key, buf)) - return false; + // if (!BEncodeMaybeReadDictInt("v", version, read, key, buf)) + // return false; - if (key.startswith("x") and serializeExit) - { - return bencode_discard(buf); - } + // if (key.startswith("x") and serializeExit) + // { + // return bencode_discard(buf); + // } - if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf)) - return false; + // if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf)) + // return false; return read or bencode_discard(buf); } bool - RouterContact::IsPublicRouter() const + RouterContact::is_public_router() const { - if (not routerVersion) + if (_router_version.empty()) return false; - return addr.is_addressable(); + return _addr.is_addressable(); } bool - RouterContact::IsExpired(llarp_time_t now) const + RouterContact::is_expired(llarp_time_t now) const { - return Age(now) >= rc_expire_age; + return age(now) >= _timestamp.time_since_epoch() + LIFETIME; } llarp_time_t - RouterContact::TimeUntilExpires(llarp_time_t now) const + RouterContact::time_to_expiry(llarp_time_t now) const { - const auto expiresAt = last_updated + Lifetime; - return now < expiresAt ? expiresAt - now : 0s; + const auto expiry = _timestamp.time_since_epoch() + LIFETIME; + return now < expiry ? expiry - now : 0s; } llarp_time_t - RouterContact::Age(llarp_time_t now) const - { - return now > last_updated ? now - last_updated : 0s; - } - - bool - RouterContact::ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const - { - return TimeUntilExpires(now) <= dlt; - } - - bool - RouterContact::Sign(const SecretKey& secretkey) + RouterContact::age(llarp_time_t now) const { - pubkey = llarp::seckey_topublic(secretkey); - signature.Zero(); - last_updated = time_now_ms(); - - signed_bt_dict = bencode_signed_section(); - - return crypto::sign( - signature, - secretkey, - reinterpret_cast(signed_bt_dict.data()), - signed_bt_dict.size()); - } - - bool - RouterContact::Verify(llarp_time_t now, bool allowExpired) const - { - if (netID != NetID::DefaultValue()) - { - log::error( - logcat, "netid mismatch: '{}' (theirs) != '{}' (ours)", netID, NetID::DefaultValue()); - return false; - } - - if (IsExpired(now) and not allowExpired) - return false; - - // TODO: make net* overridable - const auto* net = net::Platform::Default_ptr(); - - if (net->IsBogon(addr.in4()) && BlockBogons) - { - log::error(logcat, "invalid address info: {}", addr); - return false; - } - - if (!VerifySignature()) - { - log::error(logcat, "invalid signature: {}", *this); - return false; - } - return true; + auto delta = now - _timestamp.time_since_epoch(); + return delta > 0s ? delta : 0s; } bool - RouterContact::VerifySignature() const + RouterContact::expires_within_delta(llarp_time_t now, llarp_time_t dlt) const { - RouterContact copy; - copy = *this; - copy.signature.Zero(); - - auto bte = copy.bt_encode(); - return crypto::verify(pubkey, reinterpret_cast(bte.data()), bte.size(), signature); + return time_to_expiry(now) <= dlt; } static constexpr std::array obsolete_bootstraps = { @@ -421,66 +287,13 @@ namespace llarp }; bool - RouterContact::IsObsoleteBootstrap() const + RouterContact::is_obsolete_bootstrap() const { for (const auto& k : obsolete_bootstraps) { - if (pubkey.ToHex() == k) + if (_router_id.ToHex() == k) return true; } return false; } - - bool - RouterContact::Write(const fs::path& fname) const - { - std::array tmp; - llarp_buffer_t buf(tmp); - - auto bte = bt_encode(); - buf.write(bte.begin(), bte.end()); - - try - { - util::dump_file(fname, tmp.data(), buf.cur - buf.base); - } - catch (const std::exception& e) - { - log::error(logcat, "Failed to write RC to {}: {}", fname, e.what()); - return false; - } - return true; - } - - bool - RouterContact::Read(const fs::path& fname) - { - std::array tmp; - llarp_buffer_t buf(tmp); - try - { - util::slurp_file(fname, tmp.data(), tmp.size()); - } - catch (const std::exception& e) - { - log::error(logcat, "Failed to read RC from {}: {}", fname, e.what()); - return false; - } - return BDecode(&buf); - } - - std::string - RouterContact::ToString() const - { - return fmt::format( - "[RC k={} updated={} netid={} v={} ai={{{}}} e={} z={}]", - pubkey, - last_updated.count(), - netID, - version, - fmt::format("{}", addr), - enckey, - signature); - } - } // namespace llarp diff --git a/llarp/router_contact.hpp b/llarp/router_contact.hpp index 7e8e1fdce..f863bbd67 100644 --- a/llarp/router_contact.hpp +++ b/llarp/router_contact.hpp @@ -1,11 +1,11 @@ #pragma once +#include "router_id.hpp" #include "router_version.hpp" #include #include #include -#include #include #include #include @@ -17,128 +17,148 @@ #include #include -#define MAX_RC_SIZE (1024) - -namespace oxenc -{ - class bt_list_consumer; -} // namespace oxenc - namespace llarp { - /// NetID - struct NetID final : public AlignedBuffer<8> + static auto logcat = log::Cat("RC"); + + using rc_time = std::chrono::time_point; + + static inline constexpr size_t NETID_SIZE{8}; + + /// On the wire we encode the data as a dict containing: + /// "" -- the RC format version, which must be == RouterContact::Version for us to attempt to + /// parse the reset of the fields. (Future versions might have backwards-compat support + /// for lower versions). + /// "4" -- 6 byte packed IPv4 address & port: 4 bytes of IPv4 address followed by 2 bytes of + /// port, both encoded in network (i.e. big-endian) order. + /// "6" -- optional 18 byte IPv6 address & port: 16 byte raw IPv6 address followed by 2 bytes + /// of port in network order. + /// "i" -- optional network ID string of up to 8 bytes; this is omitted for the default network + /// ID ("lokinet") but included for others (such as "gamma" for testnet). + /// "p" -- 32-byte router pubkey + /// "t" -- timestamp when this RC record was created (which also implicitly determines when it + /// goes stale and when it expires). + /// "v" -- lokinet version of the router; this is a three-byte packed value of + /// MAJOR, MINOR, PATCH, e.g. \x00\x0a\x03 for 0.10.3. + /// "~" -- signature of all of the previous serialized data, signed by "p" + + /// RouterContact + struct RouterContact { - static NetID& - DefaultValue(); + static constexpr uint8_t RC_VERSION = 0; - NetID(); + /// Unit tests disable this to allow private IP ranges in RCs, which normally get rejected. + static inline bool BLOCK_BOGONS = true; - explicit NetID(const byte_t* val); + static inline std::string ACTIVE_NETID{LOKINET_DEFAULT_NETID}; - NetID(const NetID& other) = default; - NetID& - operator=(const NetID& other) = default; + static inline constexpr size_t MAX_RC_SIZE = 1024; - bool - operator==(const NetID& other) const; + /// Timespans for RCs: - bool - operator!=(const NetID& other) const - { - return !(*this == other); - } + /// How long (relative to its timestamp) before an RC becomes stale. Stale records are used + /// (e.g. for path building) only if there are no non-stale records available, such as might be + /// the case when a client has been turned off for a while. + static constexpr auto STALE = 12h; - std::string - ToString() const; + /// How long before an RC becomes invalid (and thus deleted). + static constexpr auto LIFETIME = 30 * 24h; - bool - BDecode(llarp_buffer_t* buf); + /// How long before a relay updates and re-publish its RC to the network. (Relays can + /// re-publish more frequently than this if needed; this is meant to apply only if there are no + /// changes i.e. just to push out a new confirmation of the details). + static constexpr auto REPUBLISH = STALE / 2 - 5min; - bool - BEncode(llarp_buffer_t* buf) const; - }; + ustring_view + view() const + { + return _payload; + } - /// RouterContact - struct RouterContact - { - /// for unit tests - static bool BlockBogons; + /// Getters for private attributes + const oxen::quic::Address& + addr() const + { + return _addr; + } - static llarp_time_t Lifetime; - static llarp_time_t UpdateInterval; - static llarp_time_t StaleInsertionAge; + const std::optional& + addr6() const + { + return _addr6; + } - RouterContact() + const RouterID& + router_id() const { - Clear(); + return _router_id; } - RouterContact(std::string buf); + const rc_time& + timestamp() const + { + return _timestamp; + } + protected: // advertised addresses - oxen::quic::Address addr; - // network identifier - NetID netID; - // public encryption public key - llarp::PubKey enckey; + oxen::quic::Address _addr; // refactor all 15 uses to use addr() method + std::optional _addr6; // optional ipv6 // public signing public key - llarp::PubKey pubkey; - // signature - llarp::Signature signature; + RouterID _router_id; // refactor all 103 uses to use router_id() method - llarp_time_t last_updated = 0s; - uint64_t version = llarp::constants::proto_version; - std::optional routerVersion; - /// should we serialize the exit info? - const static bool serializeExit = true; + rc_time _timestamp{}; + + // Lokinet version at the time the RC was produced + std::array _router_version; - std::string signed_bt_dict; + // In both Remote and Local RC's, the entire bt-encoded payload given at construction is + // emplaced here. + // + // In a RemoteRC, this value will be held for the lifetime of the object + // s.t. it can be returned upon calls to ::bt_encode. + // In a LocalRC, this value will be supplanted any time a mutator is invoked, requiring + // the re-signing of the payload. + ustring _payload; - std::vector srvRecords; + public: + /// should we serialize the exit info? + const static bool serializeExit = true; util::StatusObject - ExtractStatus() const; + extract_status() const; - RouterID - router_id() const + nlohmann::json + to_json() const { - return pubkey; + return extract_status(); } - nlohmann::json - ToJson() const + virtual std::string + to_string() const { - return ExtractStatus(); + return fmt::format( + "[RC k={} updated={} v={} addr={}]", + _router_id.ToView(), + _timestamp.time_since_epoch().count(), + RC_VERSION, + _addr.to_string()); } - std::string - ToString() const; - - std::string - bt_encode() const; - - void - bt_encode_subdict(oxenc::bt_list_producer& btlp) const; - - std::string - bencode_signed_section() const; - - std::string - ToTXTRecord() const; + bool + write(const fs::path& fname) const; bool operator==(const RouterContact& other) const { - return addr == other.addr && enckey == other.enckey && pubkey == other.pubkey - && signature == other.signature && last_updated == other.last_updated - && netID == other.netID; + return _router_id == other._router_id and _addr == other._addr and _addr6 == other._addr6 + and _timestamp == other._timestamp and _router_version == other._router_version; } bool operator<(const RouterContact& other) const { - return pubkey < other.pubkey; + return _router_id < other._router_id; } bool @@ -147,14 +167,9 @@ namespace llarp return !(*this == other); } - void - Clear(); - - bool - IsExit() const - { - return false; - } + virtual void + clear() + {} bool BDecode(llarp_buffer_t* buf); @@ -163,66 +178,182 @@ namespace llarp decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf); bool - IsPublicRouter() const; - - bool - Verify(llarp_time_t now, bool allowExpired = true) const; - - bool - Sign(const llarp::SecretKey& secret); + is_public_router() const; /// does this RC expire soon? default delta is 1 minute bool - ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 1min) const; + expires_within_delta(llarp_time_t now, llarp_time_t dlt = 1min) const; /// returns true if this RC is expired and should be removed bool - IsExpired(llarp_time_t now) const; + is_expired(llarp_time_t now) const; /// returns time in ms until we expire or 0 if we have expired llarp_time_t - TimeUntilExpires(llarp_time_t now) const; + time_to_expiry(llarp_time_t now) const; /// get the age of this RC in ms llarp_time_t - Age(llarp_time_t now) const; + age(llarp_time_t now) const; bool - OtherIsNewer(const RouterContact& other) const + other_is_newer(const RouterContact& other) const { - return last_updated < other.last_updated; + return _timestamp < other._timestamp; } bool - Read(const fs::path& fname); + is_obsolete_bootstrap() const; - bool - Write(const fs::path& fname) const; + void + bt_load(oxenc::bt_dict_consumer& data); + }; - bool - VerifySignature() const; + /// Extension of RouterContact used to store a local "RC," and inserts a RouterContact by + /// re-parsing and sending it out. This sub-class contains a pubkey and all the other attributes + /// required for signing and serialization + /// + /// Note: this class may be entirely superfluous, so it is used here as a placeholder until its + /// marginal utility is determined. It may end up as a free-floating method that reads in + /// parameters and outputs a bt-serialized string + struct LocalRC final : public RouterContact + { + static LocalRC + make(const SecretKey secret, oxen::quic::Address local); - /// return true if the netid in this rc is for the network id we are using - bool - FromOurNetwork() const; + private: + ustring _signature; + SecretKey _secret_key; + + void + bt_sign(oxenc::bt_dict_producer& btdp); + + void + bt_encode(oxenc::bt_dict_producer& btdp); + + LocalRC(const SecretKey secret, oxen::quic::Address local); + + public: + LocalRC() = default; + explicit LocalRC(std::string payload, const SecretKey sk); + ~LocalRC() = default; + + void + resign(); + + void + clear() override + { + _addr = {}; + _addr6.reset(); + _router_id.Zero(); + _timestamp = {}; + _router_version.fill(0); + _signature.clear(); + } bool - IsObsoleteBootstrap() const; + operator==(const LocalRC& other) const + { + return _router_id == other._router_id and _addr == other._addr and _addr6 == other._addr6 + and _timestamp == other._timestamp and _router_version == other._router_version + and _signature == other._signature; + } + + /// Mutators for the private member attributes. Calling on the mutators + /// will clear the current signature and re-sign the RC + void + set_addr(oxen::quic::Address new_addr) + { + _addr = std::move(new_addr); + resign(); + } + + void + set_addr6(oxen::quic::Address new_addr) + { + _addr6 = std::move(new_addr); + resign(); + } + + void + set_router_id(RouterID rid) + { + _router_id = std::move(rid); + resign(); + } + + void + set_timestamp(llarp_time_t ts) + { + set_timestamp(rc_time{std::chrono::duration_cast(ts)}); + } + + void + set_timestamp(rc_time ts) + { + _timestamp = ts; + } + /// Sets RC timestamp to current system clock time + void + set_systime_timestamp() + { + set_timestamp( + std::chrono::time_point_cast(std::chrono::system_clock::now())); + } + }; + + /// Extension of RouterContact used in a "read-only" fashion. Parses the incoming RC to query + /// the data in the constructor, eliminating the need for a ::verify method/ + struct RemoteRC final : public RouterContact + { private: + void + bt_verify(oxenc::bt_dict_consumer& data, bool reject_expired = false) const; + + public: + RemoteRC() = default; + RemoteRC(std::string_view data) : RemoteRC{oxenc::bt_dict_consumer{data}} + {} + RemoteRC(ustring_view data) : RemoteRC{oxenc::bt_dict_consumer{data}} + { + _payload = data; + } + explicit RemoteRC(oxenc::bt_dict_consumer btdc); + ~RemoteRC() = default; + + std::string_view + view() const + { + return {reinterpret_cast(_payload.data()), _payload.size()}; + } + bool - DecodeVersion_0(llarp_buffer_t* buf); + verify() const; bool - DecodeVersion_1(oxenc::bt_list_consumer& btlist); + read(const fs::path& fname); + + void + clear() override + { + _addr = {}; + _addr6.reset(); + _router_id.Zero(); + _timestamp = {}; + _router_version.fill(0); + } }; - template <> - constexpr inline bool IsToStringFormattable = true; template <> constexpr inline bool IsToStringFormattable = true; + template <> + constexpr inline bool IsToStringFormattable = true; + template <> + constexpr inline bool IsToStringFormattable = true; - using RouterLookupHandler = std::function&)>; + using RouterLookupHandler = std::function&)>; } // namespace llarp namespace std @@ -233,7 +364,7 @@ namespace std size_t operator()(const llarp::RouterContact& r) const { - return std::hash{}(r.pubkey); + return std::hash{}(r.router_id()); } }; } // namespace std diff --git a/llarp/router_contact_local.cpp b/llarp/router_contact_local.cpp new file mode 100644 index 000000000..9b82551cc --- /dev/null +++ b/llarp/router_contact_local.cpp @@ -0,0 +1,138 @@ +#include "constants/version.hpp" +#include "crypto/crypto.hpp" +#include "net/net.hpp" +#include "router_contact.hpp" +#include "util/bencode.hpp" +#include "util/buffer.hpp" +#include "util/file.hpp" +#include "util/time.hpp" + +#include + +namespace llarp +{ + LocalRC + LocalRC::make(const SecretKey secret, oxen::quic::Address local) + { + return *new LocalRC{secret, local}; + } + + LocalRC::LocalRC(const SecretKey secret, oxen::quic::Address local) + : _secret_key{std::move(secret)} + { + _router_id = llarp::seckey_to_pubkey(_secret_key); + _addr = std::move(local); + _addr6.emplace(&_addr.in6()); + resign(); + } + + LocalRC::LocalRC(std::string payload, const SecretKey sk) : _secret_key{std::move(sk)} + { + _router_id = llarp::seckey_to_pubkey(_secret_key); + + try + { + oxenc::bt_dict_consumer btdc{payload}; + bt_load(btdc); + + btdc.require_signature("~", [this](ustring_view msg, ustring_view sig) { + if (sig.size() != 64) + throw std::runtime_error{"Invalid signature: not 64 bytes"}; + + if (is_expired(time_now_ms())) + throw std::runtime_error{"Unable to verify expired RemoteRC!"}; + + // TODO: revisit if this is needed; detail from previous implementation + const auto* net = net::Platform::Default_ptr(); + + if (net->IsBogon(addr().in4()) and BLOCK_BOGONS) + { + auto err = "Unable to verify expired RemoteRC!"; + log::info(logcat, err); + throw std::runtime_error{err}; + } + + if (not crypto::verify(router_id(), msg, sig)) + throw std::runtime_error{"Failed to verify RemoteRC"}; + }); + } + catch (const std::exception& e) + { + log::warning(logcat, "Failed to parse LocalRC: {}", e.what()); + throw; + } + } + + void + LocalRC::bt_sign(oxenc::bt_dict_producer& btdp) + { + _signature.clear(); + + btdp.append_signature("~", [this](ustring_view to_sign) { + std::array sig; + + if (!crypto::sign(const_cast(sig.data()), _secret_key, to_sign)) + throw std::runtime_error{"Failed to sign RC"}; + + _signature = {sig.data(), sig.size()}; + return sig; + }); + + _payload = btdp.view(); + } + + void + LocalRC::bt_encode(oxenc::bt_dict_producer& btdp) + { + btdp.append("", RC_VERSION); + + std::array buf; + + { + if (not _addr.is_ipv4()) + throw std::runtime_error{"Unable to encode RC: addr is not IPv4"}; + + auto in4 = _addr.in4(); + + std::memcpy(buf.data(), &in4.sin_addr.s_addr, 4); + std::memcpy(buf.data() + 4, &in4.sin_port, 2); + + btdp.append("4", ustring_view{buf.data(), 6}); + } + + if (_addr6) + { + if (not _addr.is_ipv6()) + throw std::runtime_error{"Unable to encode RC: addr6 is set but is not IPv6"}; + + auto in6 = _addr.in6(); + + std::memcpy(buf.data(), &in6.sin6_addr.s6_addr, 16); + std::memcpy(buf.data() + 16, &in6.sin6_port, 2); + + btdp.append("6", ustring_view{buf.data(), 18}); + } + + if (ACTIVE_NETID != llarp::LOKINET_DEFAULT_NETID) + btdp.append("i", ACTIVE_NETID); + + btdp.append("p", _router_id.ToView()); + + btdp.append("t", _timestamp.time_since_epoch().count()); + + static_assert(llarp::LOKINET_VERSION.size() == 3); + btdp.append( + "v", std::string_view{reinterpret_cast(llarp::LOKINET_VERSION.data()), 3}); + + bt_sign(btdp); + } + + void + LocalRC::resign() + { + set_systime_timestamp(); + oxenc::bt_dict_producer btdp; + bt_encode(btdp); + bt_sign(btdp); + } +} // namespace llarp diff --git a/llarp/router_contact_remote.cpp b/llarp/router_contact_remote.cpp new file mode 100644 index 000000000..8cb127d4c --- /dev/null +++ b/llarp/router_contact_remote.cpp @@ -0,0 +1,106 @@ +#include "constants/version.hpp" +#include "crypto/crypto.hpp" +#include "net/net.hpp" +#include "router_contact.hpp" +#include "util/bencode.hpp" +#include "util/buffer.hpp" +#include "util/file.hpp" +#include "util/time.hpp" + +#include + +namespace llarp +{ + RemoteRC::RemoteRC(oxenc::bt_dict_consumer btdc) + { + try + { + bt_load(btdc); + + btdc.require_signature("~", [this](ustring_view msg, ustring_view sig) { + if (sig.size() != 64) + throw std::runtime_error{"Invalid signature: not 64 bytes"}; + + if (is_expired(time_now_ms())) + throw std::runtime_error{"Unable to verify expired RemoteRC!"}; + + // TODO: revisit if this is needed; detail from previous implementation + const auto* net = net::Platform::Default_ptr(); + + if (net->IsBogon(addr().in4()) and BLOCK_BOGONS) + { + auto err = "Unable to verify expired RemoteRC!"; + log::info(logcat, err); + throw std::runtime_error{err}; + } + + if (not crypto::verify(router_id(), msg, sig)) + throw std::runtime_error{"Failed to verify RemoteRC"}; + }); + } + catch (const std::exception& e) + { + log::warning(logcat, "Failed to parse RemoteRC: {}", e.what()); + throw; + } + } + + void + RemoteRC::bt_verify(oxenc::bt_dict_consumer& data, bool reject_expired) const + { + data.require_signature("~", [this, reject_expired](ustring_view msg, ustring_view sig) { + if (sig.size() != 64) + throw std::runtime_error{"Invalid signature: not 64 bytes"}; + + if (is_expired(time_now_ms()) and reject_expired) + throw std::runtime_error{"Unable to verify expired RemoteRC!"}; + + // TODO: revisit if this is needed; detail from previous implementation + const auto* net = net::Platform::Default_ptr(); + + if (net->IsBogon(addr().in4()) and BLOCK_BOGONS) + { + auto err = "Unable to verify expired RemoteRC!"; + log::info(logcat, err); + throw std::runtime_error{err}; + } + + if (not crypto::verify(router_id(), msg, sig)) + throw std::runtime_error{"Failed to verify RemoteRC"}; + }); + } + + bool + RemoteRC::read(const fs::path& fname) + { + ustring buf; + buf.reserve(MAX_RC_SIZE); + + try + { + util::file_to_buffer(fname, buf.data(), MAX_RC_SIZE); + } + catch (const std::exception& e) + { + log::error(logcat, "Failed to read RC from {}: {}", fname, e.what()); + return false; + } + + oxenc::bt_dict_consumer btdc{buf}; + bt_load(btdc); + bt_verify(btdc); + + _payload = buf; + + return true; + } + + bool + RemoteRC::verify() const + { + oxenc::bt_dict_consumer btdc{_payload}; + bt_verify(btdc); + return true; + } + +} // namespace llarp diff --git a/llarp/router_id.hpp b/llarp/router_id.hpp index 273460f91..8a82f924d 100644 --- a/llarp/router_id.hpp +++ b/llarp/router_id.hpp @@ -3,9 +3,11 @@ #include "util/aligned.hpp" #include "util/status.hpp" +#include + namespace llarp { - struct RouterID : public AlignedBuffer<32> + struct RouterID : public PubKey { static constexpr size_t SIZE = 32; @@ -13,10 +15,10 @@ namespace llarp RouterID() = default; - RouterID(const byte_t* buf) : AlignedBuffer(buf) + RouterID(const byte_t* buf) : PubKey(buf) {} - RouterID(const Data& data) : AlignedBuffer(data) + RouterID(const Data& data) : PubKey(data) {} util::StatusObject diff --git a/llarp/rpc/lokid_rpc_client.cpp b/llarp/rpc/lokid_rpc_client.cpp index dfbcb253f..aa4e3f3ad 100644 --- a/llarp/rpc/lokid_rpc_client.cpp +++ b/llarp/rpc/lokid_rpc_client.cpp @@ -51,7 +51,7 @@ namespace llarp::rpc { if (auto router = m_Router.lock()) { - if (not router->IsServiceNode()) + if (not router->is_service_node()) { throw std::runtime_error("we cannot talk to lokid while not a service node"); } @@ -181,7 +181,7 @@ namespace llarp::rpc nlohmann::json payload = { {"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())}, - {"version", {VERSION[0], VERSION[1], VERSION[2]}}}; + {"version", {LOKINET_VERSION[0], LOKINET_VERSION[1], LOKINET_VERSION[2]}}}; if (auto err = r->OxendErrorState()) payload["error"] = *err; diff --git a/llarp/rpc/rpc_server.cpp b/llarp/rpc/rpc_server.cpp index 9e7581e50..598dd36f1 100644 --- a/llarp/rpc/rpc_server.cpp +++ b/llarp/rpc/rpc_server.cpp @@ -74,7 +74,7 @@ namespace llarp::rpc std::shared_ptr GetEndpointByName(Router& r, std::string name) { - if (r.IsServiceNode()) + if (r.is_service_node()) { return r.exitContext().GetExitEndpoint(name); } @@ -154,7 +154,7 @@ namespace llarp::rpc RPCServer::invoke(Version& version) { util::StatusObject result{ - {"version", llarp::VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}}; + {"version", llarp::LOKINET_VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}}; SetJSONResponse(result, version.response); } @@ -309,7 +309,7 @@ namespace llarp::rpc void RPCServer::invoke(LookupSnode& lookupsnode) { - if (not m_Router.IsServiceNode()) + if (not m_Router.is_service_node()) { SetJSONError("Not supported", lookupsnode.response); return; diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 3b1a4dc44..725f498e1 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -206,97 +206,57 @@ namespace llarp::service std::string service, std::function)> resultHandler) { - // handles when we aligned to a loki address - auto handleGotPathToService = [resultHandler, service, this](auto addr) { - // we can probably get this info before we have a path to them but we do this after we - // have a path so when we send the response back they can send shit to them immediately - const auto& container = _state->remote_sessions; - if (auto itr = container.find(addr); itr != container.end()) - { - // parse the stuff we need from this guy - resultHandler(itr->second->GetCurrentIntroSet().GetMatchingSRVRecords(service)); - return; - } - resultHandler({}); - }; - - // handles when we resolved a .snode - auto handleResolvedSNodeName = [resultHandler, nodedb = router()->node_db()](auto router_id) { - std::vector result{}; - if (auto maybe_rc = nodedb->get_rc(router_id)) - { - result = maybe_rc->srvRecords; - } - resultHandler(std::move(result)); - }; - - // handles when we got a path to a remote thing - auto handleGotPathTo = [handleGotPathToService, handleResolvedSNodeName, resultHandler]( - auto maybe_tag, auto address) { - if (not maybe_tag) - { - resultHandler({}); - return; - } - - if (auto* addr = std::get_if
(&address)) - { - // .loki case - handleGotPathToService(*addr); - } - else if (auto* router_id = std::get_if(&address)) - { - // .snode case - handleResolvedSNodeName(*router_id); - } - else - { - // fallback case - // XXX: never should happen but we'll handle it anyways - resultHandler({}); - } - }; - - // handles when we know a long address of a remote resource - auto handleGotAddress = [resultHandler, handleGotPathTo, this](AddressVariant_t address) { - // we will attempt a build to whatever we looked up - const auto result = EnsurePathTo( - address, - [address, handleGotPathTo](auto maybe_tag) { handleGotPathTo(maybe_tag, address); }, - PathAlignmentTimeout()); - - // on path build start fail short circuit - if (not result) - resultHandler({}); - }; - - // look up this name async and start the entire chain of events - lookup_name(name, [handleGotAddress, resultHandler](oxen::quic::message m) mutable { - if (m) - { - std::string name; - try - { - oxenc::bt_dict_consumer btdc{m.body()}; - name = btdc.require("NAME"); - } - catch (...) - { - log::warning(link_cat, "Failed to parse find name response!"); - throw; - } + // A lookup goes through a chain of events: + // - see if the name is ONS, and if so resolve it to a ADDR.loki + // - once we've resolved to ADDR.loki then initiate a path to it + // - once we have a path, consult the remote's introset to pull out the SRV records + // If we fail along the way (e.g. it's a .snode, we can't build a path, or whatever else) then + // we invoke the resultHandler with an empty vector. + lookup_name( + name, [this, resultHandler, service = std::move(service)](oxen::quic::message m) mutable { + if (!m) + return resultHandler({}); - if (auto saddr = service::Address(); saddr.FromString(name)) - handleGotAddress(saddr); + std::string name; + try + { + oxenc::bt_dict_consumer btdc{m.body()}; + name = btdc.require("NAME"); + } + catch (...) + { + log::warning(link_cat, "Failed to parse find name response!"); + throw; + } - if (auto rid = RouterID(); rid.FromString(name)) - handleGotAddress(rid); - } - else - { - resultHandler({}); - } - }); + auto saddr = service::Address(); + if (!saddr.FromString(name)) + return resultHandler({}); // Not a regular ADDR.loki so doesn't support SRV + + // initiate path build + const auto build_started = EnsurePathTo( + saddr, + [this, address = std::move(saddr), resultHandler, service = std::move(service)]( + auto maybe_tag) { + if (not maybe_tag) + return resultHandler({}); + + // we can probably get this info before we have a path to them but we do this after + // we have a path so when we send the DNS response back they can talk to them + // immediately + const auto& container = _state->remote_sessions; + if (auto itr = container.find(address); itr != container.end()) + // parse the stuff we need from this guy + resultHandler(itr->second->GetCurrentIntroSet().GetMatchingSRVRecords(service)); + else + resultHandler({}); + }, + PathAlignmentTimeout()); + + // on path build start fail short circuit + if (not build_started) + resultHandler({}); + }); } bool @@ -754,22 +714,22 @@ namespace llarp::service return now >= next_pub; } - std::optional> + std::optional> Endpoint::GetHopsForBuild() { std::unordered_set exclude; ForEachPath([&exclude](auto path) { exclude.insert(path->Endpoint()); }); const auto maybe = - router()->node_db()->GetRandom([exclude, r = router()](const auto& rc) -> bool { - return exclude.count(rc.pubkey) == 0 - and not r->router_profiling().IsBadForPath(rc.pubkey); + router()->node_db()->GetRandom([exclude, r = router()](const RemoteRC& rc) -> bool { + const auto& rid = rc.router_id(); + return exclude.count(rid) == 0 and not r->router_profiling().IsBadForPath(rid); }); if (not maybe.has_value()) return std::nullopt; - return GetHopsForBuildWithEndpoint(maybe->pubkey); + return GetHopsForBuildWithEndpoint(maybe->router_id()); } - std::optional> + std::optional> Endpoint::GetHopsForBuildWithEndpoint(RouterID endpoint) { return path::Builder::GetHopsAlignedToForBuild(endpoint, SnodeBlacklist()); diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 63bedc6d7..faa8b3f47 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -409,10 +409,10 @@ namespace llarp bool HasExit() const; - std::optional> + std::optional> GetHopsForBuild() override; - std::optional> + std::optional> GetHopsForBuildWithEndpoint(RouterID endpoint); void diff --git a/llarp/service/identity.cpp b/llarp/service/identity.cpp index 3452146b5..892faa90b 100644 --- a/llarp/service/identity.cpp +++ b/llarp/service/identity.cpp @@ -4,16 +4,32 @@ namespace llarp::service { - bool - Identity::BEncode(llarp_buffer_t* buf) const + std::string + Identity::bt_encode() const { - if (!bencode_start_dict(buf)) - return false; - if (!BEncodeWriteDictEntry("s", signkey, buf)) - return false; - if (!BEncodeWriteDictInt("v", version, buf)) - return false; - return bencode_end(buf); + oxenc::bt_dict_producer btdp; + + btdp.append("s", signkey.ToView()); + btdp.append("v", version); + + return std::move(btdp).str(); + } + + void + Identity::bt_decode(std::string buf) + { + try + { + oxenc::bt_dict_consumer btdc{buf}; + + signkey.from_string(btdc.require("s")); + version = btdc.require("v"); + } + catch (...) + { + log::warning(logcat, "Identity failed to parse bt-encoded contents!"); + throw; + } } bool @@ -44,7 +60,7 @@ namespace llarp::service { crypto::identity_keygen(signkey); crypto::encryption_keygen(enckey); - pub.Update(seckey_topublic(signkey), seckey_topublic(enckey)); + pub.Update(seckey_to_pubkey(signkey), seckey_to_pubkey(enckey)); crypto::pqe_keygen(pq); if (not crypto::derive_subkey_private(derivedSignKey, signkey, 1)) { @@ -74,7 +90,7 @@ namespace llarp::service // make sure we are empty Clear(); - std::array tmp; + std::string buf; // this can throw bool exists = fs::exists(fname); @@ -88,16 +104,15 @@ namespace llarp::service // check for file if (!exists) { - llarp_buffer_t buf{tmp}; // regen and encode RegenerateKeys(); - if (!BEncode(&buf)) - throw std::length_error("failed to encode new identity"); - const auto sz = buf.cur - buf.base; + + buf = bt_encode(); + // write try { - util::dump_file(fname, tmp.data(), sz); + util::buffer_to_file(fname, buf.data(), buf.size()); } catch (const std::exception& e) { @@ -114,18 +129,15 @@ namespace llarp::service // read file try { - util::slurp_file(fname, tmp.data(), tmp.size()); + util::file_to_buffer(fname, buf.data(), buf.size()); } catch (const std::length_error&) { throw std::length_error{"service identity too big"}; } + // (don't catch io error exceptions) - { - llarp_buffer_t buf{tmp}; - if (!bencode_decode_dict(*this, &buf)) - throw std::length_error{"could not decode service identity"}; - } + bt_decode(buf); // ensure that the encryption key is set if (enckey.IsZero()) @@ -139,7 +151,7 @@ namespace llarp::service if (!vanity.IsZero()) van = vanity; // update pubkeys - pub.Update(seckey_topublic(signkey), seckey_topublic(enckey), van); + pub.Update(seckey_to_pubkey(signkey), seckey_to_pubkey(enckey), van); if (not crypto::derive_subkey_private(derivedSignKey, signkey, 1)) { throw std::runtime_error("failed to derive subkey"); @@ -163,7 +175,7 @@ namespace llarp::service // set service info i.address_keys = pub; // set public encryption key - i.sntru_pubkey = pq_keypair_to_public(pq); + i.sntru_pubkey = pq_keypair_to_pubkey(pq); auto bte = i.bt_encode(); diff --git a/llarp/service/identity.hpp b/llarp/service/identity.hpp index 70b1919f3..3a8a34749 100644 --- a/llarp/service/identity.hpp +++ b/llarp/service/identity.hpp @@ -31,8 +31,10 @@ namespace llarp::service void RegenerateKeys(); - bool - BEncode(llarp_buffer_t* buf) const; + std::string + bt_encode() const; + + void bt_decode(std::string); /// @param needBackup determines whether existing keys will be cycled void diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 115394f57..c67c99551 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -350,7 +350,7 @@ namespace llarp::service return false; } - std::optional> + std::optional> OutboundContext::GetHopsForBuild() { if (next_intro.router.IsZero()) diff --git a/llarp/service/outbound_context.hpp b/llarp/service/outbound_context.hpp index d0381b0c7..8504efcd7 100644 --- a/llarp/service/outbound_context.hpp +++ b/llarp/service/outbound_context.hpp @@ -152,7 +152,7 @@ namespace llarp::service void HandlePathBuildFailedAt(path::Path_ptr path, RouterID hop) override; - std::optional> + std::optional> GetHopsForBuild() override; std::string diff --git a/llarp/service/protocol.cpp b/llarp/service/protocol.cpp index bcc2960ef..6848e4698 100644 --- a/llarp/service/protocol.cpp +++ b/llarp/service/protocol.cpp @@ -256,7 +256,7 @@ namespace llarp::service // copy ProtocolFrameMessage frame(self->frame); if (!crypto::pqe_decrypt( - self->frame.cipher, K, pq_keypair_to_secret(self->m_LocalIdentity.pq))) + self->frame.cipher, K, pq_keypair_to_seckey(self->m_LocalIdentity.pq))) { LogError("pqke failed C=", self->frame.cipher); self->msg.reset(); diff --git a/llarp/service/protocol.hpp b/llarp/service/protocol.hpp index d3d656e2a..67e8ef91f 100644 --- a/llarp/service/protocol.hpp +++ b/llarp/service/protocol.hpp @@ -130,12 +130,6 @@ namespace llarp std::string bt_encode() const; - bool - BDecode(llarp_buffer_t* buf) - { - return bencode_decode_dict(*this, buf); - } - void clear() { diff --git a/llarp/service/router_lookup_job.cpp b/llarp/service/router_lookup_job.cpp index 3c988a73b..c08a139f2 100644 --- a/llarp/service/router_lookup_job.cpp +++ b/llarp/service/router_lookup_job.cpp @@ -4,13 +4,10 @@ #include -namespace llarp +namespace llarp::service { - namespace service - { - RouterLookupJob::RouterLookupJob(Endpoint* p, RouterLookupHandler h) - : handler(std::move(h)), txid(p->GenTXID()), started(p->Now()) - {} + RouterLookupJob::RouterLookupJob(Endpoint* p, RouterLookupHandler h) + : handler(std::move(h)), txid(p->GenTXID()), started(p->Now()) + {} - } // namespace service -} // namespace llarp +} // namespace llarp::service diff --git a/llarp/service/router_lookup_job.hpp b/llarp/service/router_lookup_job.hpp index 58228107b..d9dce7246 100644 --- a/llarp/service/router_lookup_job.hpp +++ b/llarp/service/router_lookup_job.hpp @@ -2,34 +2,31 @@ #include -namespace llarp +namespace llarp::service { - namespace service - { - struct Endpoint; + struct Endpoint; - struct RouterLookupJob - { - RouterLookupJob(Endpoint* p, RouterLookupHandler h); + struct RouterLookupJob + { + RouterLookupJob(Endpoint* p, RouterLookupHandler h); - RouterLookupHandler handler; - uint64_t txid; - llarp_time_t started; + RouterLookupHandler handler; + uint64_t txid; + llarp_time_t started; - bool - IsExpired(llarp_time_t now) const - { - if (now < started) - return false; - return now - started > 30s; - } + bool + IsExpired(llarp_time_t now) const + { + if (now < started) + return false; + return now - started > 30s; + } - void - InformResult(std::vector result) - { - if (handler) - handler(result); - } - }; - } // namespace service -} // namespace llarp + void + InformResult(std::vector result) + { + if (handler) + handler(result); + } + }; +} // namespace llarp::service diff --git a/llarp/util/bencode.hpp b/llarp/util/bencode.hpp index aae0fe3b1..16f08b9a8 100644 --- a/llarp/util/bencode.hpp +++ b/llarp/util/bencode.hpp @@ -17,16 +17,17 @@ namespace llarp { static auto ben_cat = log::Cat("stupid.bencode"); + template + T + decode_key(oxenc::bt_dict_consumer& btdp, const char* key) + { + return btdp.require(key); + } + template bool BEncodeReadList(List_t& result, llarp_buffer_t* buf); - inline bool - BEncodeWriteDictMsgType(llarp_buffer_t* buf, const char* k, const char* t) - { - return bencode_write_bytestring(buf, k, 1) && bencode_write_bytestring(buf, t, 1); - } - template bool BEncodeWriteDictString(const char* k, const Obj_t& str, llarp_buffer_t* buf) @@ -320,23 +321,6 @@ namespace llarp buffer); } - /// write an iterable container as a list - template - bool - BEncodeWriteSet(const Set_t& set, llarp_buffer_t* buffer) - { - if (not bencode_start_list(buffer)) - return false; - - for (const auto& item : set) - { - if (not item.bt_encode(buffer)) - return false; - } - - return bencode_end(buffer); - } - template bool BEncodeWriteDictList(const char* k, List_t& list, llarp_buffer_t* buf) @@ -365,7 +349,7 @@ namespace llarp std::string content; try { - content = util::slurp_file(fpath); + content = util::file_to_string(fpath); } catch (const std::exception&) { @@ -389,7 +373,7 @@ namespace llarp tmp.resize(buf.cur - buf.base); try { - util::dump_file(fpath, tmp); + util::buffer_to_file(fpath, tmp); } catch (const std::exception& e) { diff --git a/llarp/util/file.cpp b/llarp/util/file.cpp index ff929d016..9b482852a 100644 --- a/llarp/util/file.cpp +++ b/llarp/util/file.cpp @@ -19,7 +19,7 @@ namespace llarp::util { static std::streampos - slurp_file_open(const fs::path& filename, fs::ifstream& in) + file_reader_impl(const fs::path& filename, fs::ifstream& in) { in.exceptions(std::ifstream::failbit | std::ifstream::badbit); in.open(filename, std::ios::binary | std::ios::in); @@ -30,21 +30,21 @@ namespace llarp::util } std::string - slurp_file(const fs::path& filename) + file_to_string(const fs::path& filename) { fs::ifstream in; std::string contents; - auto size = slurp_file_open(filename, in); + auto size = file_reader_impl(filename, in); contents.resize(size); in.read(contents.data(), size); return contents; } size_t - slurp_file(const fs::path& filename, char* buffer, size_t buffer_size) + file_to_buffer(const fs::path& filename, char* buffer, size_t buffer_size) { fs::ifstream in; - auto size = slurp_file_open(filename, in); + auto size = file_reader_impl(filename, in); if (static_cast(size) > buffer_size) throw std::length_error{"file is too large for buffer"}; in.read(buffer, size); @@ -52,7 +52,7 @@ namespace llarp::util } void - dump_file(const fs::path& filename, std::string_view contents) + buffer_to_file(const fs::path& filename, std::string_view contents) { fs::ofstream out; out.exceptions(std::ifstream::failbit | std::ifstream::badbit); diff --git a/llarp/util/file.hpp b/llarp/util/file.hpp index a66b1555f..39c140673 100644 --- a/llarp/util/file.hpp +++ b/llarp/util/file.hpp @@ -14,34 +14,34 @@ namespace llarp::util { /// Reads a binary file from disk into a string. Throws on error. std::string - slurp_file(const fs::path& filename); + file_to_string(const fs::path& filename); /// Reads a binary file from disk directly into a buffer. Throws a std::length_error if the /// file is bigger than the buffer. Returns the bytes copied on success. size_t - slurp_file(const fs::path& filename, char* buffer, size_t buffer_size); + file_to_buffer(const fs::path& filename, char* buffer, size_t buffer_size); /// Same, but for some non-char but single-byte char type (e.g. byte_t, std::byte, unsigned char). template < typename Char, std::enable_if_t, int> = 1> inline size_t - slurp_file(const fs::path& filename, Char* buffer, size_t buffer_size) + file_to_buffer(const fs::path& filename, Char* buffer, size_t buffer_size) { - return slurp_file(filename, reinterpret_cast(buffer), buffer_size); + return file_to_buffer(filename, reinterpret_cast(buffer), buffer_size); } /// Dumps binary string contents to disk. The file is overwritten if it already exists. Throws /// on error. void - dump_file(const fs::path& filename, std::string_view contents); + buffer_to_file(const fs::path& filename, std::string_view contents); /// Same as above, but works via char-like buffer template = 0> inline void - dump_file(const fs::path& filename, const Char* buffer, size_t buffer_size) + buffer_to_file(const fs::path& filename, const Char* buffer, size_t buffer_size) { - return dump_file( + return buffer_to_file( filename, std::string_view{reinterpret_cast(buffer), buffer_size}); }