From 36792d4337bf2296ba38e4e62b17255e41930ce5 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 13 Oct 2022 14:19:25 -0300 Subject: [PATCH 01/25] Fix multi-field < ordering Lots and lots of places in the code had broken < operators because they are returning something like: foo < other.foo or bar < other.bar; but this breaks both the strict weak ordering requirements that are required for the "Compare" requirement for things like std::map/set/priority_queue. For example: a = {.foo=1, .bar=3} b = {.foo=3, .bar=1} does not have an ordering over a and b (both `a < b` and `b < a` are satisfied at the same time). This needs to be instead something like: foo < other.foo or (foo == other.foo and bar < other.bar) but that's a bit clunkier, and it is easier to use std::tie for tuple's built-in < comparison which does the right thing: std::tie(foo, bar) < std::tie(other.foo, other.bar) (Initially I noticed this in SockAddr/sockaddr_in6, but upon further investigation this extends to the major of multi-field `operator<`'s.) This fixes it by using std::tie (or something similar) everywhere we are doing multi-field inequalities. --- llarp/dns/srv_data.hpp | 14 +++-- llarp/iwp/linklayer.cpp | 2 +- llarp/iwp/linklayer.hpp | 2 +- llarp/iwp/message_buffer.hpp | 5 +- llarp/link/server.cpp | 2 +- llarp/link/server.hpp | 8 ++- llarp/net/address_info.cpp | 2 +- llarp/net/ip_range.hpp | 4 +- llarp/net/net.hpp | 116 +++++++++++++++++++---------------- llarp/net/sock_addr.cpp | 6 +- llarp/net/traffic_policy.hpp | 6 +- llarp/net/uint128.hpp | 8 +-- llarp/router_version.hpp | 2 +- llarp/service/intro.hpp | 4 +- llarp/vpn/platform.hpp | 2 +- 15 files changed, 98 insertions(+), 85 deletions(-) diff --git a/llarp/dns/srv_data.hpp b/llarp/dns/srv_data.hpp index f61606322..58281ab8d 100644 --- a/llarp/dns/srv_data.hpp +++ b/llarp/dns/srv_data.hpp @@ -10,7 +10,7 @@ namespace llarp::dns { - typedef std::tuple SRVTuple; + using SRVTuple = std::tuple; struct SRVData { @@ -38,19 +38,23 @@ namespace llarp::dns SRVTuple toTuple() const; + auto + toTupleRef() const + { + return std::tie(service_proto, priority, weight, port, target); + } + /// so we can put SRVData in a std::set bool operator<(const SRVData& other) const { - return service_proto < other.service_proto or priority < other.priority - or weight < other.weight or port < other.port or target < other.target; + return toTupleRef() < other.toTupleRef(); } bool operator==(const SRVData& other) const { - return service_proto == other.service_proto and priority == other.priority - and weight == other.weight and port == other.port and target == other.target; + return toTupleRef() == other.toTupleRef(); } bool diff --git a/llarp/iwp/linklayer.cpp b/llarp/iwp/linklayer.cpp index 03e2259eb..6fb807058 100644 --- a/llarp/iwp/linklayer.cpp +++ b/llarp/iwp/linklayer.cpp @@ -26,7 +26,7 @@ namespace llarp::iwp , m_Inbound{allowInbound} {} - const char* + std::string_view LinkLayer::Name() const { return "iwp"; diff --git a/llarp/iwp/linklayer.hpp b/llarp/iwp/linklayer.hpp index 6d58b046c..82504edc7 100644 --- a/llarp/iwp/linklayer.hpp +++ b/llarp/iwp/linklayer.hpp @@ -35,7 +35,7 @@ namespace llarp::iwp std::shared_ptr NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override; - const char* + std::string_view Name() const override; uint16_t diff --git a/llarp/iwp/message_buffer.hpp b/llarp/iwp/message_buffer.hpp index 3ea352064..f0dae604c 100644 --- a/llarp/iwp/message_buffer.hpp +++ b/llarp/iwp/message_buffer.hpp @@ -53,11 +53,12 @@ namespace llarp uint16_t m_ResendPriority; bool - operator<(const OutboundMessage& msg) const + operator<(const OutboundMessage& other) const { // yes, the first order is reversed as higher means more important // second part is for queue order - return msg.m_ResendPriority < m_ResendPriority or m_MsgID < msg.m_MsgID; + int prioA = -m_ResendPriority, prioB = -other.m_ResendPriority; + return std::tie(prioA, m_MsgID) < std::tie(prioB, other.m_MsgID); } ILinkSession::Packet_t diff --git a/llarp/link/server.cpp b/llarp/link/server.cpp index 58924e4ad..72eaa7ff9 100644 --- a/llarp/link/server.cpp +++ b/llarp/link/server.cpp @@ -249,7 +249,7 @@ namespace llarp bool ILinkLayer::PickAddress(const RouterContact& rc, llarp::AddressInfo& picked) const { - std::string OurDialect = Name(); + auto OurDialect = Name(); for (const auto& addr : rc.addrs) { if (addr.dialect == OurDialect) diff --git a/llarp/link/server.hpp b/llarp/link/server.hpp index 0e7c86c89..f9aca894b 100644 --- a/llarp/link/server.hpp +++ b/llarp/link/server.hpp @@ -135,7 +135,7 @@ namespace llarp virtual void Stop(); - virtual const char* + virtual std::string_view Name() const = 0; util::StatusObject @@ -179,7 +179,7 @@ namespace llarp bool IsCompatable(const llarp::RouterContact& other) const { - const std::string us = Name(); + const auto us = Name(); for (const auto& ai : other.addrs) if (ai.dialect == us) return true; @@ -207,7 +207,9 @@ namespace llarp bool operator<(const ILinkLayer& other) const { - return Rank() < other.Rank() || Name() < other.Name() || m_ourAddr < other.m_ourAddr; + auto rankA = Rank(), rankB = other.Rank(); + auto nameA = Name(), nameB = other.Name(); + return std::tie(rankA, nameA, m_ourAddr) < std::tie(rankB, nameB, other.m_ourAddr); } /// called by link session to remove a pending session who is timed out diff --git a/llarp/net/address_info.cpp b/llarp/net/address_info.cpp index fd5424632..f39b1d4c9 100644 --- a/llarp/net/address_info.cpp +++ b/llarp/net/address_info.cpp @@ -23,7 +23,7 @@ namespace llarp bool operator<(const AddressInfo& lhs, const AddressInfo& rhs) { - return lhs.rank < rhs.rank || lhs.ip < rhs.ip || lhs.port < rhs.port; + return std::tie(lhs.rank, lhs.ip, lhs.port) < std::tie(rhs.rank, rhs.ip, rhs.port); } std::variant diff --git a/llarp/net/ip_range.hpp b/llarp/net/ip_range.hpp index 9772793aa..a4e9b0be3 100644 --- a/llarp/net/ip_range.hpp +++ b/llarp/net/ip_range.hpp @@ -117,8 +117,8 @@ namespace llarp bool operator<(const IPRange& other) const { - return (this->addr & this->netmask_bits) < (other.addr & other.netmask_bits) - || this->netmask_bits < other.netmask_bits; + auto maskedA = addr & netmask_bits, maskedB = other.addr & other.netmask_bits; + return std::tie(maskedA, netmask_bits) < std::tie(maskedB, other.netmask_bits); } bool diff --git a/llarp/net/net.hpp b/llarp/net/net.hpp index e54a7ee8e..b3a7af8e4 100644 --- a/llarp/net/net.hpp +++ b/llarp/net/net.hpp @@ -34,62 +34,16 @@ namespace llarp { - inline bool - operator==(const in_addr& a, const in_addr& b) + inline int + cmp(const in_addr& a, const in_addr& b) { - return memcmp(&a, &b, sizeof(in_addr)) == 0; + return memcmp(&a, &b, sizeof(in_addr)); } - inline bool - operator==(const in6_addr& a, const in6_addr& b) + inline int + cmp(const in6_addr& a, const in6_addr& b) { - return memcmp(&a, &b, sizeof(in6_addr)) == 0; - } - - inline bool - operator==(const sockaddr_in& a, const sockaddr_in& b) - { - return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr; - } - - inline bool - operator==(const sockaddr_in6& a, const sockaddr_in6& b) - { - return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr; - } - - inline bool - operator==(const sockaddr& a, const sockaddr& b) - { - if (a.sa_family != b.sa_family) - return false; - switch (a.sa_family) - { - case AF_INET: - return reinterpret_cast(a) == reinterpret_cast(b); - case AF_INET6: - return reinterpret_cast(a) == reinterpret_cast(b); - default: - return false; - } - } - - inline bool - operator<(const in_addr& a, const in_addr& b) - { - return memcmp(&a, &b, sizeof(in_addr)) < 0; - } - - inline bool - operator<(const in6_addr& a, const in6_addr& b) - { - return memcmp(&a, &b, sizeof(in6_addr)) < 0; - } - - inline bool - operator<(const sockaddr_in6& a, const sockaddr_in6& b) - { - return a.sin6_addr < b.sin6_addr or a.sin6_port < b.sin6_port; + return memcmp(&a, &b, sizeof(in6_addr)); } namespace net @@ -261,3 +215,61 @@ namespace llarp } // namespace net } // namespace llarp + +inline bool +operator==(const in_addr& a, const in_addr& b) +{ + return llarp::cmp(a, b) == 0; +} + +inline bool +operator==(const in6_addr& a, const in6_addr& b) +{ + return llarp::cmp(a, b) == 0; +} + +inline bool +operator==(const sockaddr_in& a, const sockaddr_in& b) +{ + return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr; +} + +inline bool +operator==(const sockaddr_in6& a, const sockaddr_in6& b) +{ + return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr; +} + +inline bool +operator==(const sockaddr& a, const sockaddr& b) +{ + if (a.sa_family != b.sa_family) + return false; + switch (a.sa_family) + { + case AF_INET: + return reinterpret_cast(a) == reinterpret_cast(b); + case AF_INET6: + return reinterpret_cast(a) == reinterpret_cast(b); + default: + return false; + } +} + +inline bool +operator<(const in_addr& a, const in_addr& b) +{ + return llarp::cmp(a, b) < 0; +} + +inline bool +operator<(const in6_addr& a, const in6_addr& b) +{ + return llarp::cmp(a, b) < 0; +} + +inline bool +operator<(const sockaddr_in6& a, const sockaddr_in6& b) +{ + return std::tie(a.sin6_addr, a.sin6_port) < std::tie(b.sin6_addr, b.sin6_port); +} diff --git a/llarp/net/sock_addr.cpp b/llarp/net/sock_addr.cpp index f42feb928..8fdf457f1 100644 --- a/llarp/net/sock_addr.cpp +++ b/llarp/net/sock_addr.cpp @@ -206,15 +206,13 @@ namespace llarp bool SockAddr::operator<(const SockAddr& other) const { - return (m_addr.sin6_addr < other.m_addr.sin6_addr) - or (m_addr.sin6_port < other.m_addr.sin6_port); + return m_addr < other.m_addr; } bool SockAddr::operator==(const SockAddr& other) const { - return m_addr.sin6_addr == other.m_addr.sin6_addr - and m_addr.sin6_port == other.m_addr.sin6_port; + return m_addr == other.m_addr; } huint128_t diff --git a/llarp/net/traffic_policy.hpp b/llarp/net/traffic_policy.hpp index 1368d05d4..a34456535 100644 --- a/llarp/net/traffic_policy.hpp +++ b/llarp/net/traffic_policy.hpp @@ -33,11 +33,7 @@ namespace llarp::net bool operator<(const ProtocolInfo& other) const { - if (port and other.port) - { - return protocol < other.protocol or *port < *other.port; - } - return protocol < other.protocol; + return std::tie(protocol, port) < std::tie(other.protocol, other.port); } ProtocolInfo() = default; diff --git a/llarp/net/uint128.hpp b/llarp/net/uint128.hpp index 4bc39f53c..dde7c83af 100644 --- a/llarp/net/uint128.hpp +++ b/llarp/net/uint128.hpp @@ -141,25 +141,25 @@ namespace llarp constexpr bool operator<(const uint128_t& b) const { - return upper < b.upper || (upper == b.upper && lower < b.lower); + return std::tie(upper, lower) < std::tie(b.upper, b.lower); } constexpr bool operator<=(const uint128_t& b) const { - return upper < b.upper || (upper == b.upper && lower <= b.lower); + return std::tie(upper, lower) <= std::tie(b.upper, b.lower); } constexpr bool operator>(const uint128_t& b) const { - return upper > b.upper || (upper == b.upper && lower > b.lower); + return std::tie(upper, lower) > std::tie(b.upper, b.lower); } constexpr bool operator>=(const uint128_t& b) const { - return upper > b.upper || (upper == b.upper && lower >= b.lower); + return std::tie(upper, lower) >= std::tie(b.upper, b.lower); } constexpr uint128_t& diff --git a/llarp/router_version.hpp b/llarp/router_version.hpp index 30429483b..a03cc02fc 100644 --- a/llarp/router_version.hpp +++ b/llarp/router_version.hpp @@ -41,7 +41,7 @@ namespace llarp bool operator<(const RouterVersion& other) const { - return m_ProtoVersion < other.m_ProtoVersion || m_Version < other.m_Version; + return std::tie(m_ProtoVersion, m_Version) < std::tie(other.m_ProtoVersion, other.m_Version); } bool diff --git a/llarp/service/intro.hpp b/llarp/service/intro.hpp index c1c431eb0..bb659a4d4 100644 --- a/llarp/service/intro.hpp +++ b/llarp/service/intro.hpp @@ -55,8 +55,8 @@ namespace llarp bool operator<(const Introduction& other) const { - return expiresAt < other.expiresAt || pathID < other.pathID || router < other.router - || version < other.version || latency < other.latency; + return std::tie(expiresAt, pathID, router, version, latency) + < std::tie(other.expiresAt, other.pathID, other.router, other.version, other.latency); } bool diff --git a/llarp/vpn/platform.hpp b/llarp/vpn/platform.hpp index 6d0b18063..ebba6dee8 100644 --- a/llarp/vpn/platform.hpp +++ b/llarp/vpn/platform.hpp @@ -25,7 +25,7 @@ namespace llarp::vpn bool operator<(const InterfaceAddress& other) const { - return range < other.range or fam < other.fam; + return std::tie(range, fam) < std::tie(other.range, other.fam); } }; From 0e576ff59e06fa12afbbb37b0ce4225a830d9841 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 14 Oct 2022 18:02:53 -0300 Subject: [PATCH 02/25] Clean up oxend service node list handling This aligns service node updating logic a bit closer to what happens in storage server, and should make it a bit more resilient, hopefully tracking down the (off-Github) reported issue where lokinet sometimes doesn't see itself as active. - Initiate a service node list update in the 30s timer lokinet ping timer (in case we miss a block notify for some reason); although this is expensive, the next point mitigates it: - Retrieve the block hash with the SN state update, and feed it back into the next get_service_nodes call (as "poll_block_hash") so that oxend just sends back a mostly-empty response when the block hasn't changed, allowing both oxend and lokinet to skip nearly all of the work of a service node list update when the block hasn't changed since the last poll. (This was already partially implemenated--we were already looking for "unchanged"--but without a block hash to get from and pass back to oxend we'd never actually get an "unchanged" result). - Tighten up the service node list handling by moving the "unchanged" handling into the get_service_nodes response handler: this way the HandleNewServiceNodeList function is only handling the list but not the logic as to whether there actually is a new list or not. --- llarp/rpc/lokid_rpc_client.cpp | 133 +++++++++++++++++++-------------- llarp/rpc/lokid_rpc_client.hpp | 7 +- 2 files changed, 83 insertions(+), 57 deletions(-) diff --git a/llarp/rpc/lokid_rpc_client.cpp b/llarp/rpc/lokid_rpc_client.cpp index 7048188fd..78b3e47ff 100644 --- a/llarp/rpc/lokid_rpc_client.cpp +++ b/llarp/rpc/lokid_rpc_client.cpp @@ -112,35 +112,57 @@ namespace llarp void LokidRpcClient::UpdateServiceNodeList() { - nlohmann::json request, fields; - fields["pubkey_ed25519"] = true; - fields["service_node_pubkey"] = true; - fields["funded"] = true; - fields["active"] = true; - request["fields"] = fields; - m_UpdatingList = true; + if (m_UpdatingList.exchange(true)) + return; // update already in progress + + nlohmann::json request{ + {"fields", + { + {"pubkey_ed25519", true}, + {"service_node_pubkey", true}, + {"funded", true}, + {"active", true}, + {"block_hash", true}, + }}, + }; + if (!m_LastUpdateHash.empty()) + request["fields"]["poll_block_hash"] = m_LastUpdateHash; + Request( "rpc.get_service_nodes", [self = shared_from_this()](bool success, std::vector data) { - self->m_UpdatingList = false; if (not success) - { LogWarn("failed to update service node list"); - return; - } - if (data.size() < 2) + else if (data.size() < 2) + LogWarn("oxend gave empty reply for service node list"); + else { - LogWarn("lokid gave empty reply for service node list"); - return; - } - try - { - self->HandleGotServiceNodeList(std::move(data[1])); - } - catch (std::exception& ex) - { - LogError("failed to process service node list: ", ex.what()); + try + { + auto json = nlohmann::json::parse(std::move(data[1])); + if (json.at("status") != "OK") + throw std::runtime_error{"get_service_nodes did not return 'OK' status"}; + if (auto it = json.find("unchanged"); + it != json.end() and it->is_boolean() and it->get()) + LogDebug("service node list unchanged"); + else + { + self->HandleNewServiceNodeList(json.at("service_node_states")); + if (auto it = json.find("block_hash"); it != json.end() and it->is_string()) + self->m_LastUpdateHash = it->get(); + else + self->m_LastUpdateHash.clear(); + } + } + catch (const std::exception& ex) + { + LogError("failed to process service node list: ", ex.what()); + } } + + // set down here so that the 1) we don't start updating until we're completely finished + // with the previous update; and 2) so that m_UpdatingList also guards m_LastUpdateHash + self->m_UpdatingList = false; }, request.dump()); } @@ -180,52 +202,51 @@ namespace llarp } LogDebug("subscribed to new blocks: ", data[0]); }); + // Trigger an update on a regular timer as well in case we missed a block notify for some + // reason (e.g. oxend restarts and loses the subscription); we poll using the last known + // hash so that the poll is very cheap (basically empty) if the block hasn't advanced. + self->UpdateServiceNodeList(); }; + // Fire one ping off right away to get things going. + makePingRequest(); m_lokiMQ->add_timer(makePingRequest, PingInterval); - // initial fetch of service node list - UpdateServiceNodeList(); } void - LokidRpcClient::HandleGotServiceNodeList(std::string data) + LokidRpcClient::HandleNewServiceNodeList(const nlohmann::json& j) { - auto j = nlohmann::json::parse(std::move(data)); - if (const auto itr = j.find("unchanged"); itr != j.end() and itr->get()) - { - LogDebug("service node list unchanged"); - return; - } std::unordered_map keymap; std::vector activeNodeList, nonActiveNodeList; - if (const auto itr = j.find("service_node_states"); itr != j.end() and itr->is_array()) + if (not j.is_array()) + throw std::runtime_error{ + "Invalid service node list: expected array of service node states"}; + + for (auto& snode : j) { - for (auto& snode : *itr) - { - // Skip unstaked snodes: - if (const auto funded_itr = snode.find("funded"); funded_itr == snode.end() - or not funded_itr->is_boolean() or not funded_itr->get()) - continue; + // Skip unstaked snodes: + if (const auto funded_itr = snode.find("funded"); funded_itr == snode.end() + or not funded_itr->is_boolean() or not funded_itr->get()) + continue; - const auto ed_itr = snode.find("pubkey_ed25519"); - if (ed_itr == snode.end() or not ed_itr->is_string()) - continue; - const auto svc_itr = snode.find("service_node_pubkey"); - if (svc_itr == snode.end() or not svc_itr->is_string()) - continue; - const auto active_itr = snode.find("active"); - if (active_itr == snode.end() or not active_itr->is_boolean()) - continue; - const bool active = active_itr->get(); + const auto ed_itr = snode.find("pubkey_ed25519"); + if (ed_itr == snode.end() or not ed_itr->is_string()) + continue; + const auto svc_itr = snode.find("service_node_pubkey"); + if (svc_itr == snode.end() or not svc_itr->is_string()) + continue; + const auto active_itr = snode.find("active"); + if (active_itr == snode.end() or not active_itr->is_boolean()) + continue; + const bool active = active_itr->get(); - RouterID rid; - PubKey pk; - if (not rid.FromHex(ed_itr->get()) - or not pk.FromHex(svc_itr->get())) - continue; + RouterID rid; + PubKey pk; + if (not rid.FromHex(ed_itr->get()) + or not pk.FromHex(svc_itr->get())) + continue; - keymap[rid] = pk; - (active ? activeNodeList : nonActiveNodeList).push_back(std::move(rid)); - } + keymap[rid] = pk; + (active ? activeNodeList : nonActiveNodeList).push_back(std::move(rid)); } if (activeNodeList.empty()) diff --git a/llarp/rpc/lokid_rpc_client.hpp b/llarp/rpc/lokid_rpc_client.hpp index b2614bd10..bfc267480 100644 --- a/llarp/rpc/lokid_rpc_client.hpp +++ b/llarp/rpc/lokid_rpc_client.hpp @@ -55,6 +55,8 @@ namespace llarp void Command(std::string_view cmd); + /// triggers a service node list refresh from oxend; thread-safe and will do nothing if an + /// update is already in progress. void UpdateServiceNodeList(); @@ -72,8 +74,10 @@ namespace llarp m_lokiMQ->request(*m_Connection, std::move(cmd), std::move(func)); } + // Handles a service node list update; takes the "service_node_states" object of an oxend + // "get_service_nodes" rpc request. void - HandleGotServiceNodeList(std::string json); + HandleNewServiceNodeList(const nlohmann::json& json); // Handles request from lokid for peer stats on a specific peer void @@ -88,6 +92,7 @@ namespace llarp std::weak_ptr m_Router; std::atomic m_UpdatingList; + std::string m_LastUpdateHash; std::unordered_map m_KeyMap; From bd869b3b079c8c58b910274eb54c869eeaa7d001 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 14 Oct 2022 20:37:19 -0300 Subject: [PATCH 03/25] Log demotion Demote a couple spammy messages to trace level. --- llarp/dht/context.cpp | 2 +- llarp/router/router.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llarp/dht/context.cpp b/llarp/dht/context.cpp index d2b0e7129..06c67953d 100644 --- a/llarp/dht/context.cpp +++ b/llarp/dht/context.cpp @@ -441,7 +441,7 @@ namespace llarp Context::CleanupTX() { auto now = Now(); - llarp::LogDebug("DHT tick"); + llarp::LogTrace("DHT tick"); pendingRouterLookups().Expire(now); _pendingIntrosetLookups.Expire(now); diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 975c6074b..0349e1179 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -973,7 +973,7 @@ namespace llarp // don't purge bootstrap nodes from nodedb if (IsBootstrapNode(rc.pubkey)) { - log::debug(logcat, "Not removing {}: is bootstrap node", rc.pubkey); + log::trace(logcat, "Not removing {}: is bootstrap node", rc.pubkey); return false; } // if for some reason we stored an RC that isn't a valid router From c5e787b8cb16510d7472870395724778a5b118bd Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 14 Oct 2022 20:55:21 -0300 Subject: [PATCH 04/25] Oxend error ping + unfunded tracking Currently (from a recent PR) we aren't pinging oxend if not active, but that behaviour ended up being quite wrong because lokinet needs to ping even when decommissioned or deregistered (when decommissioned we need the ping to get commissioned again, and if not registered we need the ping to get past the "lokinet isn't pinging" nag screen to prepare a registration). This considerably revises the pinging behaviour: - We ping oxend *unless* there is a specific error with our connections (i.e. we *should* be establishing peer connections but don't have any) - If we do have such an error, we send a new oxend "error" ping to report the error to oxend and get oxend to hold off on sending uptime proofs. Along the way this also changes how we handle the current node state: instead of just tracking deregistered/decommissioned, we now track three states: - LooksRegistered -- which means the SN is known to the network (but not necessarily active or fully staked) - LooksFunded -- which means it is known *and* is fully funded, but not necessarily active - LooksDecommissioned -- which means it is known, funded, and not currently active (which implies decommissioned). The funded (or more precisely, unfunded) state is now tracked in rc_lookup_handler in a "greenlist" -- i.e. new SNs that are so new (i.e. "green") that they aren't even fully staked or active yet. --- llarp/router/abstractrouter.hpp | 18 ++++---- llarp/router/i_rc_lookup_handler.hpp | 10 ++++- llarp/router/rc_lookup_handler.cpp | 40 ++++++++++++------ llarp/router/rc_lookup_handler.hpp | 21 +++++++++- llarp/router/router.cpp | 49 +++++++++++++--------- llarp/router/router.hpp | 28 ++++++++----- llarp/rpc/lokid_rpc_client.cpp | 62 +++++++++++++++------------- 7 files changed, 147 insertions(+), 81 deletions(-) diff --git a/llarp/router/abstractrouter.hpp b/llarp/router/abstractrouter.hpp index 022e6767a..7f6a368a7 100644 --- a/llarp/router/abstractrouter.hpp +++ b/llarp/router/abstractrouter.hpp @@ -199,14 +199,12 @@ namespace llarp virtual bool IsServiceNode() const = 0; - virtual bool - IsActiveServiceNode() const = 0; - - /// If we are running as a service node and appear active, i.e. registered and not - /// decommissioned, we should *not* ping core if we know of too few peers, to indicate to core - /// we are not in a good state. - virtual bool - ShouldPingOxen() const = 0; + /// Called to determine if we're in a bad state (which gets reported to our oxend) that should + /// prevent uptime proofs from going out to the network (so that the error state gets noticed). + /// Currently this means we require a decent number of peers whenever we are fully staked + /// (active or decommed). + virtual std::optional + OxendErrorState() const = 0; virtual bool StartRpcServer() = 0; @@ -315,7 +313,9 @@ namespace llarp /// set router's service node whitelist virtual void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) = 0; + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& unfundedlist) = 0; virtual std::unordered_set GetRouterWhitelist() const = 0; diff --git a/llarp/router/i_rc_lookup_handler.hpp b/llarp/router/i_rc_lookup_handler.hpp index ffc5a3a4b..4efee04c6 100644 --- a/llarp/router/i_rc_lookup_handler.hpp +++ b/llarp/router/i_rc_lookup_handler.hpp @@ -34,7 +34,9 @@ namespace llarp virtual void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) = 0; + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist) = 0; virtual void GetRC(const RouterID& router, RCRequestCallback callback, bool forceLookup = false) = 0; @@ -48,6 +50,12 @@ namespace llarp virtual bool IsGreylisted(const RouterID& remote) const = 0; + virtual bool + IsGreenlisted(const RouterID& remote) const = 0; + + virtual bool + IsRegistered(const RouterID& remote) const = 0; + virtual bool CheckRC(const RouterContact& rc) const = 0; diff --git a/llarp/router/rc_lookup_handler.cpp b/llarp/router/rc_lookup_handler.cpp index 48150090f..dc0285972 100644 --- a/llarp/router/rc_lookup_handler.cpp +++ b/llarp/router/rc_lookup_handler.cpp @@ -32,26 +32,28 @@ namespace llarp whitelistRouters.erase(router); } + static void + loadColourList(std::unordered_set& beigelist, const std::vector& new_beige) + { + beigelist.clear(); + beigelist.insert(new_beige.begin(), new_beige.end()); + } + void RCLookupHandler::SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist) { if (whitelist.empty()) return; util::Lock l(_mutex); - whitelistRouters.clear(); - greylistRouters.clear(); - for (auto& router : whitelist) - { - whitelistRouters.emplace(router); - } - for (auto& router : greylist) - { - greylistRouters.emplace(router); - } + loadColourList(whitelistRouters, whitelist); + loadColourList(greylistRouters, greylist); + loadColourList(greenlistRouters, greenlist); - LogInfo("lokinet service node list now has ", whitelistRouters.size(), " routers"); + LogInfo("lokinet service node list now has ", whitelistRouters.size(), " active routers"); } bool @@ -140,6 +142,20 @@ namespace llarp return greylistRouters.count(remote); } + bool + RCLookupHandler::IsGreenlisted(const RouterID& remote) const + { + util::Lock lock{_mutex}; + return greenlistRouters.count(remote); + } + + bool + RCLookupHandler::IsRegistered(const RouterID& remote) const + { + util::Lock lock{_mutex}; + return whitelistRouters.count(remote) || greylistRouters.count(remote) || greenlistRouters.count(remote); + } + bool RCLookupHandler::PathIsAllowed(const RouterID& remote) const { diff --git a/llarp/router/rc_lookup_handler.hpp b/llarp/router/rc_lookup_handler.hpp index 8beee74b7..184b8d102 100644 --- a/llarp/router/rc_lookup_handler.hpp +++ b/llarp/router/rc_lookup_handler.hpp @@ -42,8 +42,11 @@ namespace llarp void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) override - EXCLUDES(_mutex); + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist + + ) override EXCLUDES(_mutex); bool HaveReceivedWhitelist() const override; @@ -61,6 +64,16 @@ namespace llarp bool IsGreylisted(const RouterID& remote) const override EXCLUDES(_mutex); + // "greenlist" = new routers (i.e. "green") that aren't fully funded yet + bool + IsGreenlisted(const RouterID& remote) const override EXCLUDES(_mutex); + + // registered just means that there is at least an operator stake, but doesn't require the node + // be fully funded, active, or not decommed. (In other words: it is any of the white, grey, or + // green list). + bool + IsRegistered(const RouterID& remote) const override EXCLUDES(_mutex); + bool CheckRC(const RouterContact& rc) const override; @@ -134,8 +147,12 @@ namespace llarp bool useWhitelist = false; bool isServiceNode = false; + // whitelist = active routers std::unordered_set whitelistRouters GUARDED_BY(_mutex); + // greylist = fully funded, but decommissioned routers std::unordered_set greylistRouters GUARDED_BY(_mutex); + // greenlist = registered but not fully-staked routers + std::unordered_set greenlistRouters GUARDED_BY(_mutex); using TimePoint = std::chrono::steady_clock::time_point; std::unordered_map _routerLookupTimes; diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 0349e1179..b272e36e8 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -471,16 +471,14 @@ namespace llarp return nodedb()->NumLoaded() < KnownPeerWarningThreshold; } - bool - Router::IsActiveServiceNode() const + std::optional + Router::OxendErrorState() const { - return IsServiceNode() and not(LooksDeregistered() or LooksDecommissioned()); - } - - bool - Router::ShouldPingOxen() const - { - return IsActiveServiceNode() and not TooFewPeers(); + // If we're in the white or gray list then we *should* be establishing connections to other + // routers, so if we have almost no peers then something is almost certainly wrong. + if (LooksFunded() and TooFewPeers()) + return "too few peer connections; lokinet is not adequately connected to the network"; + return std::nullopt; } void @@ -508,10 +506,17 @@ namespace llarp } bool - Router::LooksDeregistered() const + Router::LooksFunded() const { return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist() - and not _rcLookupHandler.SessionIsAllowed(pubkey()); + and _rcLookupHandler.SessionIsAllowed(pubkey()); + } + + bool + Router::LooksRegistered() const + { + return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist() + and _rcLookupHandler.IsRegistered(pubkey()); } bool @@ -1061,12 +1066,16 @@ namespace llarp if (now >= m_NextDecommissionWarn) { constexpr auto DecommissionWarnInterval = 5min; - if (auto dereg = LooksDeregistered(); dereg or decom) + if (auto registered = LooksRegistered(), funded = LooksFunded(); + not(registered and funded and not decom)) { - // complain about being deregistered - LogError( - "We are running as a service node but we seem to be ", - dereg ? "deregistered" : "decommissioned"); + // complain about being deregistered/decommed/unfunded + log::error( + logcat, + "We are running as a service node but we seem to be {}", + not registered ? "deregistered" + : decom ? "decommissioned" + : "not fully staked"); m_NextDecommissionWarn = now + DecommissionWarnInterval; } else if (isSvcNode and TooFewPeers()) @@ -1081,7 +1090,7 @@ namespace llarp // if we need more sessions to routers and we are not a service node kicked from the network // we shall connect out to others - if (connected < connectToNum and not LooksDeregistered()) + if (connected < connectToNum and LooksFunded()) { size_t dlt = connectToNum - connected; LogDebug("connecting to ", dlt, " random routers to keep alive"); @@ -1233,9 +1242,11 @@ namespace llarp void Router::SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& unfundedlist) { - _rcLookupHandler.SetRouterWhitelist(whitelist, greylist); + _rcLookupHandler.SetRouterWhitelist(whitelist, greylist, unfundedlist); } bool diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 8eb751410..53b24e4aa 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -143,7 +143,9 @@ namespace llarp void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) override; + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& unfunded) override; std::unordered_set GetRouterWhitelist() const override @@ -203,9 +205,16 @@ namespace llarp bool LooksDecommissioned() const; - /// return true if we look like we are a deregistered service node + /// return true if we look like we are a registered, fully-staked service node (either active or + /// decommissioned). This condition determines when we are allowed to (and attempt to) connect + /// to other peers when running as a service node. bool - LooksDeregistered() const; + LooksFunded() const; + + /// return true if we a registered service node; not that this only requires a partial stake, + /// and does not imply that this service node is *active* or fully funded. + bool + LooksRegistered() const; /// return true if we look like we are allowed and able to test other routers bool @@ -378,12 +387,8 @@ namespace llarp bool IsServiceNode() const override; - /// return true if service node *and* not deregistered or decommissioned - bool - IsActiveServiceNode() const override; - - bool - ShouldPingOxen() const override; + std::optional + OxendErrorState() const override; void Close(); @@ -556,8 +561,11 @@ namespace llarp bool m_isServiceNode = false; + // Delay warning about being decommed/dereged until we've had enough time to sync up with oxend + static constexpr auto DECOMM_WARNING_STARTUP_DELAY = 15s; + llarp_time_t m_LastStatsReport = 0s; - llarp_time_t m_NextDecommissionWarn = 0s; + llarp_time_t m_NextDecommissionWarn = time_now_ms() + DECOMM_WARNING_STARTUP_DELAY; std::shared_ptr m_keyManager; std::shared_ptr m_peerDb; diff --git a/llarp/rpc/lokid_rpc_client.cpp b/llarp/rpc/lokid_rpc_client.cpp index 78b3e47ff..a40c33383 100644 --- a/llarp/rpc/lokid_rpc_client.cpp +++ b/llarp/rpc/lokid_rpc_client.cpp @@ -174,25 +174,27 @@ namespace llarp auto makePingRequest = [self = shared_from_this()]() { // send a ping PubKey pk{}; - bool should_ping = false; - if (auto r = self->m_Router.lock()) - { - pk = r->pubkey(); - should_ping = r->ShouldPingOxen(); - } - if (should_ping) - { - nlohmann::json payload = { - {"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())}, - {"version", {VERSION[0], VERSION[1], VERSION[2]}}}; - self->Request( - "admin.lokinet_ping", - [](bool success, std::vector data) { - (void)data; - LogDebug("Received response for ping. Successful: ", success); - }, - payload.dump()); - } + auto r = self->m_Router.lock(); + if (not r) + return; // router has gone away, maybe shutting down? + + pk = r->pubkey(); + + nlohmann::json payload = { + {"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())}, + {"version", {VERSION[0], VERSION[1], VERSION[2]}}}; + + if (auto err = r->OxendErrorState()) + payload["error"] = *err; + + self->Request( + "admin.lokinet_ping", + [](bool success, std::vector data) { + (void)data; + LogDebug("Received response for ping. Successful: ", success); + }, + payload.dump()); + // subscribe to block updates self->Request("sub.block", [](bool success, std::vector data) { if (data.empty() or not success) @@ -216,18 +218,13 @@ namespace llarp LokidRpcClient::HandleNewServiceNodeList(const nlohmann::json& j) { std::unordered_map keymap; - std::vector activeNodeList, nonActiveNodeList; + std::vector activeNodeList, decommNodeList, unfundedNodeList; if (not j.is_array()) throw std::runtime_error{ "Invalid service node list: expected array of service node states"}; for (auto& snode : j) { - // Skip unstaked snodes: - if (const auto funded_itr = snode.find("funded"); funded_itr == snode.end() - or not funded_itr->is_boolean() or not funded_itr->get()) - continue; - const auto ed_itr = snode.find("pubkey_ed25519"); if (ed_itr == snode.end() or not ed_itr->is_string()) continue; @@ -238,6 +235,10 @@ namespace llarp if (active_itr == snode.end() or not active_itr->is_boolean()) continue; const bool active = active_itr->get(); + const auto funded_itr = snode.find("funded"); + if (funded_itr == snode.end() or not funded_itr->is_boolean()) + continue; + const bool funded = funded_itr->get(); RouterID rid; PubKey pk; @@ -246,7 +247,10 @@ namespace llarp continue; keymap[rid] = pk; - (active ? activeNodeList : nonActiveNodeList).push_back(std::move(rid)); + (active ? activeNodeList + : funded ? decommNodeList + : unfundedNodeList) + .push_back(std::move(rid)); } if (activeNodeList.empty()) @@ -254,17 +258,19 @@ namespace llarp LogWarn("got empty service node list, ignoring."); return; } + // inform router about the new list if (auto router = m_Router.lock()) { auto& loop = router->loop(); loop->call([this, active = std::move(activeNodeList), - inactive = std::move(nonActiveNodeList), + decomm = std::move(decommNodeList), + unfunded = std::move(unfundedNodeList), keymap = std::move(keymap), router = std::move(router)]() mutable { m_KeyMap = std::move(keymap); - router->SetRouterWhitelist(active, inactive); + router->SetRouterWhitelist(active, decomm, unfunded); }); } else From e143bd13cd0c6fe014b48df950fa06353be52f1a Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 14 Oct 2022 22:29:58 -0300 Subject: [PATCH 05/25] zlib version bump --- cmake/StaticBuild.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 62277eaa3..cb0a1ce15 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -55,11 +55,11 @@ set(LIBUV_SOURCE libuv-v${LIBUV_VERSION}.tar.gz) set(LIBUV_HASH SHA512=b4f8944e2c79e3a6a31ded6cccbe4c0eeada50db6bc8a448d7015642795012a4b80ffeef7ca455bb093c59a8950d0e1430566c3c2fa87b73f82699098162d834 CACHE STRING "libuv source hash") -set(ZLIB_VERSION 1.2.12 CACHE STRING "zlib version") +set(ZLIB_VERSION 1.2.13 CACHE STRING "zlib version") set(ZLIB_MIRROR ${LOCAL_MIRROR} https://zlib.net CACHE STRING "zlib mirror(s)") -set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.gz) -set(ZLIB_HASH SHA256=91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9 +set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.xz) +set(ZLIB_HASH SHA256=d14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98 CACHE STRING "zlib source hash") set(CURL_VERSION 7.83.1 CACHE STRING "curl version") From 6813dd659c14ad47e7adab502794a620d438c0ce Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 16 Oct 2022 14:53:23 -0400 Subject: [PATCH 06/25] lint --- llarp/router/rc_lookup_handler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llarp/router/rc_lookup_handler.cpp b/llarp/router/rc_lookup_handler.cpp index dc0285972..ca9169e65 100644 --- a/llarp/router/rc_lookup_handler.cpp +++ b/llarp/router/rc_lookup_handler.cpp @@ -153,7 +153,8 @@ namespace llarp RCLookupHandler::IsRegistered(const RouterID& remote) const { util::Lock lock{_mutex}; - return whitelistRouters.count(remote) || greylistRouters.count(remote) || greenlistRouters.count(remote); + return whitelistRouters.count(remote) || greylistRouters.count(remote) + || greenlistRouters.count(remote); } bool From 306d54e285ecbb6606c17536d0a7d90ad26c4a05 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 17 Oct 2022 08:33:50 -0400 Subject: [PATCH 07/25] when running as a client squelch warnings about snode status and make sure we connect out --- llarp/router/router.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index b272e36e8..9c1f1c1e6 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -1063,7 +1063,7 @@ namespace llarp connectToNum = strictConnect; } - if (now >= m_NextDecommissionWarn) + if (isSvcNode and now >= m_NextDecommissionWarn) { constexpr auto DecommissionWarnInterval = 5min; if (auto registered = LooksRegistered(), funded = LooksFunded(); @@ -1078,7 +1078,7 @@ namespace llarp : "not fully staked"); m_NextDecommissionWarn = now + DecommissionWarnInterval; } - else if (isSvcNode and TooFewPeers()) + else if (TooFewPeers()) { log::error( logcat, @@ -1088,9 +1088,9 @@ namespace llarp } } - // if we need more sessions to routers and we are not a service node kicked from the network + // if we need more sessions to routers and we are not a service node kicked from the network or we are a client // we shall connect out to others - if (connected < connectToNum and LooksFunded()) + if (connected < connectToNum and (LooksFunded() or not isSvcNode)) { size_t dlt = connectToNum - connected; LogDebug("connecting to ", dlt, " random routers to keep alive"); From 082756c64cc2ae81d0dbdcefa072c931d8e1c1d1 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 17 Oct 2022 09:10:34 -0400 Subject: [PATCH 08/25] cancel pending queries on down. after calling Down() any pending queries will not be properly canceled and results in a crash when we destruct the queries on our side. --- llarp/dns/server.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index aa9e83da7..44dbd8bda 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -89,7 +89,6 @@ namespace llarp::dns class Query : public QueryJob_Base { - std::weak_ptr parent; std::shared_ptr src; SockAddr resolverAddr; SockAddr askerAddr; @@ -102,11 +101,13 @@ namespace llarp::dns SockAddr toaddr, SockAddr fromaddr) : QueryJob_Base{std::move(query)} - , parent{parent_} , src{std::move(pktsrc)} , resolverAddr{std::move(toaddr)} , askerAddr{std::move(fromaddr)} + , parent{parent_} {} + std::weak_ptr parent; + int id{}; virtual void SendReply(llarp::OwnedBuffer replyBuf) const override; @@ -126,6 +127,8 @@ namespace llarp::dns #endif std::optional m_LocalAddr; + std::set m_Pending; + struct ub_result_deleter { @@ -166,7 +169,9 @@ namespace llarp::dns hdr.id = query->Underlying().hdr_id; buf.cur = buf.base; hdr.Encode(&buf); - + // remove pending query + if(auto ptr = query->parent.lock()) + ptr->call([id=query->id, ptr]() { ptr->m_Pending.erase(id); }); // send reply query->SendReply(std::move(pkt)); } @@ -407,6 +412,13 @@ namespace llarp::dns #endif if (m_ctx) { + // cancel pending queries + // make copy as ub_cancel modifies m_Pending + const auto pending = m_Pending; + for(auto id : pending) + ::ub_cancel(m_ctx, id); + m_Pending.clear(); + ::ub_ctx_delete(m_ctx); m_ctx = nullptr; } @@ -486,7 +498,7 @@ namespace llarp::dns q.qclass, tmp.get(), &Resolver::Callback, - nullptr)) + &tmp->id)) { log::warning( logcat, "failed to send upstream query with libunbound: {}", ub_strerror(err)); @@ -494,6 +506,7 @@ namespace llarp::dns } else { + m_Pending.insert(tmp->id); // Leak the bare pointer we gave to unbound; we'll recapture it in Callback (void)tmp.release(); } From e5b7ea5f2d020674bb9e0aa77316196c2b9d3c4e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 17 Oct 2022 09:38:19 -0400 Subject: [PATCH 09/25] dont do queries while down --- llarp/dns/server.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index 44dbd8bda..dbf108469 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -490,6 +490,12 @@ namespace llarp::dns return true; } } + if(not m_ctx) + { + // we are down + tmp->Cancel(); + return true; + } const auto& q = query.questions[0]; if (auto err = ub_resolve_async( m_ctx, From 011bd2e84fb591eb1c737403d4f0192a62258aea Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 17 Oct 2022 19:05:30 -0400 Subject: [PATCH 10/25] format --- llarp/dns/server.cpp | 9 ++++----- llarp/router/router.cpp | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index dbf108469..49e4fef14 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -129,7 +129,6 @@ namespace llarp::dns std::optional m_LocalAddr; std::set m_Pending; - struct ub_result_deleter { void @@ -170,8 +169,8 @@ namespace llarp::dns buf.cur = buf.base; hdr.Encode(&buf); // remove pending query - if(auto ptr = query->parent.lock()) - ptr->call([id=query->id, ptr]() { ptr->m_Pending.erase(id); }); + if (auto ptr = query->parent.lock()) + ptr->call([id = query->id, ptr]() { ptr->m_Pending.erase(id); }); // send reply query->SendReply(std::move(pkt)); } @@ -415,7 +414,7 @@ namespace llarp::dns // cancel pending queries // make copy as ub_cancel modifies m_Pending const auto pending = m_Pending; - for(auto id : pending) + for (auto id : pending) ::ub_cancel(m_ctx, id); m_Pending.clear(); @@ -490,7 +489,7 @@ namespace llarp::dns return true; } } - if(not m_ctx) + if (not m_ctx) { // we are down tmp->Cancel(); diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 9c1f1c1e6..00d357eb7 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -1088,8 +1088,8 @@ namespace llarp } } - // if we need more sessions to routers and we are not a service node kicked from the network or we are a client - // we shall connect out to others + // if we need more sessions to routers and we are not a service node kicked from the network or + // we are a client we shall connect out to others if (connected < connectToNum and (LooksFunded() or not isSvcNode)) { size_t dlt = connectToNum - connected; From c3a515da49cf025ac82e67e54cd2664413d91e68 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 18 Oct 2022 12:05:13 -0300 Subject: [PATCH 11/25] Config setting documentation edits Rewords/reformats the documentation of various configuration options. --- llarp/config/config.cpp | 106 +++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index d0f9f567e..9f8f41397 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -459,9 +459,8 @@ namespace llarp "owned-range", MultiValue, Comment{ - "When in exit mode announce we allow a private range in our introset" - "exmaple:", - "owned-range=10.0.0.0/24", + "When in exit mode announce we allow a private range in our introset. For example:", + " owned-range=10.0.0.0/24", }, [this](std::string arg) { IPRange range; @@ -475,12 +474,17 @@ namespace llarp "traffic-whitelist", MultiValue, Comment{ - "List of ip traffic whitelist, anything not specified will be dropped by us." - "examples:", - "tcp for all tcp traffic regardless of port", - "0x69 for all packets using ip protocol 0x69" - "udp/53 for udp port 53", - "tcp/smtp for smtp port", + "Adds an IP traffic type whitelist; can be specified multiple times. If any are", + "specified then only matched traffic will be allowed and all other traffic will be", + "dropped. Examples:", + " traffic-whitelist=tcp", + "would allow all TCP/IP packets (regardless of port);", + " traffic-whitelist=0x69", + "would allow IP traffic with IP protocol 0x69;", + " traffic-whitelist=udp/53", + "would allow UDP port 53; and", + " traffic-whitelist=tcp/smtp", + "would allow TCP traffic on the standard smtp port (21).", }, [this](std::string arg) { if (not m_TrafficPolicy) @@ -497,9 +501,12 @@ namespace llarp MultiValue, Comment{ "Specify a `.loki` address and an optional ip range to use as an exit broker.", - "Example:", - "exit-node=whatever.loki # maps all exit traffic to whatever.loki", - "exit-node=stuff.loki:100.0.0.0/24 # maps 100.0.0.0/24 to stuff.loki", + "Examples:", + " exit-node=whatever.loki", + "would map all exit traffic through whatever.loki; and", + " exit-node=stuff.loki:100.0.0.0/24", + "would map the IP range 100.0.0.0/24 through stuff.loki.", + "This option can be specified multiple times (to map different IP ranges).", }, [this](std::string arg) { if (arg.empty()) @@ -580,10 +587,10 @@ namespace llarp Default{true}, Comment{ "Enable / disable automatic route configuration.", - "When this is enabled and an exit is used Lokinet will automatically configure " - "operating system routes to route traffic through the exit node.", - "This is enabled by default, but can be disabled to perform advanced exit routing " - "configuration manually."}, + "When this is enabled and an exit is used Lokinet will automatically configure the", + "operating system routes to route public internet traffic through the exit node.", + "This is enabled by default, but can be disabled if advanced/manual exit routing", + "configuration is desired."}, AssignmentAcceptor(m_EnableRoutePoker)); conf.defineOption( @@ -593,8 +600,8 @@ namespace llarp Default{true}, Comment{ "Enable / disable route configuration blackholes.", - "When enabled lokinet will drop ip4 and ip6 not included in exit config.", - "Enabled by default."}, + "When enabled lokinet will drop IPv4 and IPv6 traffic (when in exit mode) that is not", + "handled in the exit configuration. Enabled by default."}, AssignmentAcceptor(m_BlackholeRoutes)); conf.defineOption( @@ -602,7 +609,7 @@ namespace llarp "ifname", Comment{ "Interface name for lokinet traffic. If unset lokinet will look for a free name", - "lokinetN, starting at 0 (e.g. lokinet0, lokinet1, ...).", + "matching 'lokinetN', starting at N=0 (e.g. lokinet0, lokinet1, ...).", }, AssignmentAcceptor(m_ifname)); @@ -626,10 +633,10 @@ namespace llarp "ip6-range", ClientOnly, Comment{ - "For all ipv6 exit traffic you will use this as the base address bitwised or'd with " + "For all IPv6 exit traffic you will use this as the base address bitwised or'd with ", "the v4 address in use.", "To disable ipv6 set this to an empty value.", - "!!! WARNING !!! Disabling ipv6 tunneling when you have ipv6 routes WILL lead to " + "!!! WARNING !!! Disabling ipv6 tunneling when you have ipv6 routes WILL lead to ", "de-anonymization as lokinet will no longer carry your ipv6 traffic.", }, IP6RangeDefault, @@ -720,9 +727,13 @@ namespace llarp ClientOnly, MultiValue, Comment{ - "Specify SRV Records for services hosted on the SNApp", - "for more info see https://docs.loki.network/Lokinet/Guides/HostingSNApps/", - "srv=_service._protocol priority weight port target.loki", + "Specify SRV Records for services hosted on the SNApp for protocols that use SRV", + "records for service discovery. Each line specifies a single SRV record as:", + " srv=_service._protocol priority weight port target.loki", + "and can be specified multiple times as needed.", + "For more info see", + "https://docs.oxen.io/products-built-on-oxen/lokinet/snapps/hosting-snapps", + "and general description of DNS SRV record configuration.", }, [this](std::string arg) { llarp::dns::SRVData newSRV; @@ -737,8 +748,8 @@ namespace llarp "path-alignment-timeout", ClientOnly, Comment{ - "time in seconds how long to wait for a path to align to pivot routers", - "if not provided a sensible default will be used", + "How long to wait (in seconds) for a path to align to a pivot router when establishing", + "a path through the network to a remote .loki address.", }, [this](int val) { if (val <= 0) @@ -753,9 +764,10 @@ namespace llarp ClientOnly, Default{fs::path{params.defaultDataDir / "addrmap.dat"}}, Comment{ - "persist mapped ephemeral addresses to a file", - "on restart the mappings will be loaded so that ip addresses will not be mapped to a " - "different address", + "If given this specifies a file in which to record mapped local tunnel addresses so", + "the same local address will be used for the same lokinet address on reboot. If this", + "is not specified then the local IP of remote lokinet targets will not persist across", + "restarts of lokinet.", }, [this](fs::path arg) { if (arg.empty()) @@ -879,7 +891,7 @@ namespace llarp "on systems which use resolveconf)", }); - // forwad the rest to libunbound + // forward the rest to libunbound conf.addUndeclaredHandler("dns", [this](auto, std::string_view key, std::string_view val) { m_ExtraOpts.emplace(key, val); }); @@ -1150,7 +1162,7 @@ namespace llarp RelayOnly, Default{true}, Comment{ - "Whether or not we should talk to lokid. Must be enabled for staked routers.", + "Whether or not we should talk to oxend. Must be enabled for staked routers.", }, AssignmentAcceptor(whitelistRouters)); @@ -1159,8 +1171,8 @@ namespace llarp return; throw std::invalid_argument( "the [lokid]:jsonrpc option is no longer supported; please use the [lokid]:rpc config " - "option instead with lokid's lmq-local-control address -- typically a value such as " - "rpc=ipc:///var/lib/loki/lokid.sock or rpc=ipc:///home/snode/.loki/lokid.sock"); + "option instead with oxend's lmq-local-control address -- typically a value such as " + "rpc=ipc:///var/lib/oxen/oxend.sock or rpc=ipc:///home/snode/.oxen/oxend.sock"); }); conf.defineOption( @@ -1168,12 +1180,12 @@ namespace llarp "rpc", RelayOnly, Comment{ - "lokimq control address for for communicating with lokid. Depends on lokid's", + "oxenmq control address for for communicating with oxend. Depends on oxend's", "lmq-local-control configuration option. By default this value should be", - "ipc://LOKID-DATA-DIRECTORY/lokid.sock, such as:", - " rpc=ipc:///var/lib/loki/lokid.sock", - " rpc=ipc:///home/USER/.loki/lokid.sock", - "but can use (non-default) TCP if lokid is configured that way:", + "ipc://OXEND-DATA-DIRECTORY/oxend.sock, such as:", + " rpc=ipc:///var/lib/oxen/oxend.sock", + " rpc=ipc:///home/USER/.oxen/oxend.sock", + "but can use (non-default) TCP if oxend is configured that way:", " rpc=tcp://127.0.0.1:5678", }, [this](std::string arg) { lokidRPCAddr = oxenmq::address(arg); }); @@ -1202,7 +1214,7 @@ namespace llarp "add-node", MultiValue, Comment{ - "Specify a bootstrap file containing a signed RouterContact of a service node", + "Specify a bootstrap file containing a list of signed RouterContacts of service nodes", "which can act as a bootstrap. Can be specified multiple times.", }, [this](std::string arg) { @@ -1292,9 +1304,9 @@ namespace llarp m_UniqueHopsNetmaskSize = arg; }, Comment{ - "Netmask for router path selection; each router must be from a distinct IP subnet " + "Netmask for router path selection; each router must be from a distinct IPv4 subnet", "of the given size.", - "E.g. 16 ensures that all routers are using distinct /16 IP addresses."}); + "E.g. 16 ensures that all routers are using IPs from distinct /16 IP ranges."}); #ifdef WITH_GEOIP conf.defineOption( @@ -1306,9 +1318,11 @@ namespace llarp m_ExcludeCountries.emplace(lowercase_ascii_string(std::move(arg))); }, Comment{ - "exclude a country given its 2 letter country code from being used in path builds", - "e.g. exclude-country=DE", - "can be listed multiple times to exclude multiple countries"}); + "Exclude a country given its 2 letter country code from being used in path builds.", + "For example:", + " exclude-country=DE", + "would avoid building paths through routers with IPs in Germany.", + "This option can be specified multiple times to exclude multiple countries"}); #endif } @@ -1616,11 +1630,11 @@ namespace llarp initializeConfig(def, *params); generateCommonConfigComments(def); - // lokid + // oxend def.addSectionComments( "lokid", { - "Settings for communicating with lokid", + "Settings for communicating with oxend", }); return def.generateINIConfig(true); From 0c0ba29baede254c3b292d928860bb48f92285a6 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 19 Oct 2022 22:29:09 -0400 Subject: [PATCH 12/25] use first gateway, not last... --- llarp/router/route_poker.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index 8b38b133a..3fdc0e4bb 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -147,13 +147,16 @@ namespace llarp auto& route = platform->RouteManager(); - // find current gateways + // get current gateways, assume sorted by lowest metric first auto gateways = route.GetGatewaysNotOnInterface(*vpn); std::optional next_gw; for (auto& gateway : gateways) { if (auto* gw_ptr = std::get_if(&gateway)) + { next_gw = *gw_ptr; + break; + } } // update current gateway and apply state changes as needed From 0ed3d51aa2f879dced9fb5b3c6f3ae1f940d741d Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 20 Oct 2022 11:56:47 -0300 Subject: [PATCH 13/25] Update static deps to latest stable versions --- cmake/StaticBuild.cmake | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index cb0a1ce15..bfb346712 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -11,25 +11,25 @@ set(OPENSSL_SOURCE openssl-${OPENSSL_VERSION}.tar.gz) set(OPENSSL_HASH SHA256=aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a CACHE STRING "openssl source hash") -set(EXPAT_VERSION 2.4.8 CACHE STRING "expat version") +set(EXPAT_VERSION 2.4.9 CACHE STRING "expat version") string(REPLACE "." "_" EXPAT_TAG "R_${EXPAT_VERSION}") set(EXPAT_MIRROR ${LOCAL_MIRROR} https://github.com/libexpat/libexpat/releases/download/${EXPAT_TAG} CACHE STRING "expat download mirror(s)") set(EXPAT_SOURCE expat-${EXPAT_VERSION}.tar.xz) -set(EXPAT_HASH SHA256=f79b8f904b749e3e0d20afeadecf8249c55b2e32d4ebb089ae378df479dcaf25 +set(EXPAT_HASH SHA512=8508379b4915d84d50f3638678a90792179c98247d1cb5e6e6387d117af4dc148ac7031c1debea8b96e7b710ef436cf0dd5da91f3d22b8186a00cfafe1201169 CACHE STRING "expat source hash") -set(UNBOUND_VERSION 1.16.2 CACHE STRING "unbound version") +set(UNBOUND_VERSION 1.17.0 CACHE STRING "unbound version") set(UNBOUND_MIRROR ${LOCAL_MIRROR} https://nlnetlabs.nl/downloads/unbound CACHE STRING "unbound download mirror(s)") set(UNBOUND_SOURCE unbound-${UNBOUND_VERSION}.tar.gz) -set(UNBOUND_HASH SHA512=0ea65ea63265be677441bd2a28df12098ec5e86c3372240c2874f9bd13752b8b818da81ae6076cf02cbeba3d36e397698a4c2b50570be1a6a8e47f57a0251572 +set(UNBOUND_HASH SHA512=f6b9f279330fb19b5feca09524959940aad8c4e064528aa82b369c726d77e9e8e5ca23f366f6e9edcf2c061b96f482ed7a2c26ac70fc15ae5762b3d7e36a5284 CACHE STRING "unbound source hash") -set(SQLITE3_VERSION 3380500 CACHE STRING "sqlite3 version") +set(SQLITE3_VERSION 3390400 CACHE STRING "sqlite3 version") set(SQLITE3_MIRROR ${LOCAL_MIRROR} https://www.sqlite.org/2022 CACHE STRING "sqlite3 download mirror(s)") set(SQLITE3_SOURCE sqlite-autoconf-${SQLITE3_VERSION}.tar.gz) -set(SQLITE3_HASH SHA3_256=ab649fea76f49a6ec7f907f001d87b8bd76dec0679c783e3992284c5a882a98c +set(SQLITE3_HASH SHA3_256=431328e30d12c551da9ba7ef2122b269076058512014afa799caaf62ca567090 CACHE STRING "sqlite3 source hash") set(SODIUM_VERSION 1.0.18 CACHE STRING "libsodium version") @@ -48,11 +48,11 @@ set(ZMQ_SOURCE zeromq-${ZMQ_VERSION}.tar.gz) set(ZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e CACHE STRING "libzmq source hash") -set(LIBUV_VERSION 1.44.1 CACHE STRING "libuv version") +set(LIBUV_VERSION 1.44.2 CACHE STRING "libuv version") set(LIBUV_MIRROR ${LOCAL_MIRROR} https://dist.libuv.org/dist/v${LIBUV_VERSION} CACHE STRING "libuv mirror(s)") set(LIBUV_SOURCE libuv-v${LIBUV_VERSION}.tar.gz) -set(LIBUV_HASH SHA512=b4f8944e2c79e3a6a31ded6cccbe4c0eeada50db6bc8a448d7015642795012a4b80ffeef7ca455bb093c59a8950d0e1430566c3c2fa87b73f82699098162d834 +set(LIBUV_HASH SHA512=91197ff9303112567bbb915bbb88058050e2ad1c048815a3b57c054635d5dc7df458b956089d785475290132236cb0edcfae830f5d749de29a9a3213eeaf0b20 CACHE STRING "libuv source hash") set(ZLIB_VERSION 1.2.13 CACHE STRING "zlib version") @@ -62,11 +62,11 @@ set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.xz) set(ZLIB_HASH SHA256=d14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98 CACHE STRING "zlib source hash") -set(CURL_VERSION 7.83.1 CACHE STRING "curl version") +set(CURL_VERSION 7.85.0 CACHE STRING "curl version") set(CURL_MIRROR ${LOCAL_MIRROR} https://curl.haxx.se/download https://curl.askapache.com CACHE STRING "curl mirror(s)") set(CURL_SOURCE curl-${CURL_VERSION}.tar.xz) -set(CURL_HASH SHA256=2cb9c2356e7263a1272fd1435ef7cdebf2cd21400ec287b068396deb705c22c4 +set(CURL_HASH SHA512=b57cc31649a4f47cc4b482f56a85c86c8e8aaeaf01bc1b51b065fdb9145a9092bc52535e52a85a66432eb163605b2edbf5bc5c33ea6e40e50f26a69ad1365cbd CACHE STRING "curl source hash") include(ExternalProject) From 081dfd3328db1bc93439b3001c889a6829297fca Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 20 Oct 2022 12:04:46 -0300 Subject: [PATCH 14/25] Update submodules to latest version: cpr: 1.9.2 cxxopts: 3.0.0 ghc-filesystem: 1.5.12 nlohmann-json: 3.11.2 pybind11: 2.10.0 sqlite_orm: 1.7.1 Plus other updates need to make these work: - cpr needs a cprver.h configured with the version (cmake code copied from oxen-core). --- external/CMakeLists.txt | 15 +++++++++++++++ external/cpr | 2 +- external/cxxopts | 2 +- external/ghc-filesystem | 2 +- external/nlohmann | 2 +- external/pybind11 | 2 +- external/sqlite_orm | 2 +- 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 0e43855c0..d235c1ec2 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -124,4 +124,19 @@ if(WITH_BOOTSTRAP) target_include_directories(cpr PUBLIC cpr/include) target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) add_library(cpr::cpr ALIAS cpr) + + file(READ cpr/CMakeLists.txt cpr_cmake_head LIMIT 1000) + if(cpr_cmake_head MATCHES "project\\(cpr VERSION ([0-9]+)\.([0-9]+)\.([0-9]+) LANGUAGES CXX\\)") + set(cpr_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(cpr_VERSION_MINOR ${CMAKE_MATCH_2}) + set(cpr_VERSION_PATCH ${CMAKE_MATCH_3}) + set(cpr_VERSION "${cpr_VERSION_MAJOR}.${cpr_VERSION_MINOR}.${cpr_VERSION_PATCH}") + set(cpr_VERSION_NUM "(${cpr_VERSION_MAJOR} * 0x10000 + ${cpr_VERSION_MINOR} * 0x100 + ${cpr_VERSION_PATCH})") + + configure_file(cpr/cmake/cprver.h.in "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated_includes/cpr/cprver.h") + target_include_directories(cpr PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated_includes") + else() + message(FATAL_ERROR "Could not identify cpr submodule version!") + endif() + endif() diff --git a/external/cpr b/external/cpr index aac5058a1..f88fd7737 160000 --- a/external/cpr +++ b/external/cpr @@ -1 +1 @@ -Subproject commit aac5058a15e9ad5ad393973dc6fe44d7614a7f55 +Subproject commit f88fd7737de3e640c61703eb57a0fa0ce00c60cd diff --git a/external/cxxopts b/external/cxxopts index 6fa46a748..c74846a89 160000 --- a/external/cxxopts +++ b/external/cxxopts @@ -1 +1 @@ -Subproject commit 6fa46a748838d5544ff8e9ab058906ba2c4bc0f3 +Subproject commit c74846a891b3cc3bfa992d588b1295f528d43039 diff --git a/external/ghc-filesystem b/external/ghc-filesystem index 2a8b380f8..cd6805e94 160000 --- a/external/ghc-filesystem +++ b/external/ghc-filesystem @@ -1 +1 @@ -Subproject commit 2a8b380f8d4e77b389c42a194ab9c70d8e3a0f1e +Subproject commit cd6805e94dd5d6346be1b75a54cdc27787319dd2 diff --git a/external/nlohmann b/external/nlohmann index db78ac1d7..bc889afb4 160000 --- a/external/nlohmann +++ b/external/nlohmann @@ -1 +1 @@ -Subproject commit db78ac1d7716f56fc9f1b030b715f872f93964e4 +Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d diff --git a/external/pybind11 b/external/pybind11 index 8de7772cc..aa304c9c7 160000 --- a/external/pybind11 +++ b/external/pybind11 @@ -1 +1 @@ -Subproject commit 8de7772cc72daca8e947b79b83fea46214931604 +Subproject commit aa304c9c7d725ffb9d10af08a3b34cb372307020 diff --git a/external/sqlite_orm b/external/sqlite_orm index 4c6a46bd4..fdcc1da46 160000 --- a/external/sqlite_orm +++ b/external/sqlite_orm @@ -1 +1 @@ -Subproject commit 4c6a46bd4dcfba14a650e0fafb86331526878587 +Subproject commit fdcc1da46fbd90feb886c0588462a62d29eb5a06 From 0e09539b619427f21e1c0327d232ff7f975a288b Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 20 Oct 2022 12:12:02 -0300 Subject: [PATCH 15/25] CI fixes - cd .. after the build, before running extra_cmds, because the scripts we invoke expect to be in the root, not in the build dir (and it's dirtier for the build function to not undo the `cd build` that it runs). - fix unclosed parenthesis in mac static lib checker --- .drone.jsonnet | 16 +++++++++------- contrib/ci/drone-check-static-libs.sh | 2 +- contrib/ci/drone-static-upload.sh | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 203746cca..8985bf981 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -83,8 +83,9 @@ local debian_pipeline(name, cmake_extra + ci_dep_mirror(local_mirror), 'VERBOSE=1 make -j' + jobs, + 'cd ..', ] - + (if tests then ['../contrib/ci/drone-gdb.sh ./test/testAll --use-colour yes'] else []) + + (if tests then ['./contrib/ci/drone-gdb.sh ./build/test/testAll --use-colour yes'] else []) + extra_cmds, }, ], @@ -295,6 +296,7 @@ local mac_builder(name, // disk image. Most likely the GUI is required because if you lose sight of how pretty the // surface of macOS is you might see how ugly the insides are. 'ninja -j' + jobs + ' assemble_gui', + 'cd ..', ] + extra_cmds, }, ], @@ -394,8 +396,8 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = { '-DCMAKE_C_FLAGS="-march=x86-64 -mtune=haswell" ' + '-DNATIVE_BUILD=OFF -DWITH_SYSTEMD=OFF -DWITH_BOOTSTRAP=OFF -DBUILD_LIBLOKINET=OFF', extra_cmds=[ - '../contrib/ci/drone-check-static-libs.sh', - '../contrib/ci/drone-static-upload.sh', + './contrib/ci/drone-check-static-libs.sh', + './contrib/ci/drone-static-upload.sh', ]), // Static armhf build (gets uploaded) debian_pipeline('Static (buster armhf)', @@ -406,8 +408,8 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = { '-DCMAKE_CXX_FLAGS="-march=armv7-a+fp -Wno-psabi" -DCMAKE_C_FLAGS="-march=armv7-a+fp" ' + '-DNATIVE_BUILD=OFF -DWITH_SYSTEMD=OFF -DWITH_BOOTSTRAP=OFF', extra_cmds=[ - '../contrib/ci/drone-check-static-libs.sh', - 'UPLOAD_OS=linux-armhf ../contrib/ci/drone-static-upload.sh', + './contrib/ci/drone-check-static-libs.sh', + 'UPLOAD_OS=linux-armhf ./contrib/ci/drone-static-upload.sh', ], jobs=4), @@ -425,8 +427,8 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = { // Macos builds: mac_builder('macOS (Release)', extra_cmds=[ - '../contrib/ci/drone-check-static-libs.sh', - '../contrib/ci/drone-static-upload.sh', + './contrib/ci/drone-check-static-libs.sh', + './contrib/ci/drone-static-upload.sh', ]), mac_builder('macOS (Debug)', build_type='Debug'), ] diff --git a/contrib/ci/drone-check-static-libs.sh b/contrib/ci/drone-check-static-libs.sh index 0d919c7ca..b4d8b0b2a 100755 --- a/contrib/ci/drone-check-static-libs.sh +++ b/contrib/ci/drone-check-static-libs.sh @@ -8,7 +8,7 @@ set -o errexit bad= if [ "$DRONE_STAGE_OS" == "darwin" ]; then if otool -L llarp/apple/org.lokinet.network-extension.systemextension/Contents/MacOS/org.lokinet.network-extension | \ - grep -Ev '^llarp/apple:|^\t(/usr/lib/lib(System\.|c\+\+|objc)|/System/Library/Frameworks/(CoreFoundation|NetworkExtension|Foundation|Network)\.framework'; then + grep -Ev '^llarp/apple:|^\t(/usr/lib/lib(System\.|c\+\+|objc))|/System/Library/Frameworks/(CoreFoundation|NetworkExtension|Foundation|Network)\.framework'; then bad=1 fi elif [ "$DRONE_STAGE_OS" == "linux" ]; then diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh index 460d001c2..3f66c4545 100755 --- a/contrib/ci/drone-static-upload.sh +++ b/contrib/ci/drone-static-upload.sh @@ -55,8 +55,8 @@ elif [ -e build-mac ]; then mv build-mac/Lokinet*/ "$base" tar cJvf "$archive" "$base" else - cp -av daemon/lokinet daemon/lokinet-vpn "$base" - cp -av ../contrib/bootstrap/mainnet.signed "$base/bootstrap.signed" + cp -av build/daemon/lokinet{,-vpn} "$base" + cp -av contrib/bootstrap/mainnet.signed "$base/bootstrap.signed" # tar dat shiz up yo archive="$base.tar.xz" tar cJvf "$archive" "$base" From f2454285fe29ab70147adc2136306fbe25b49d3e Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 20 Oct 2022 13:38:36 -0300 Subject: [PATCH 16/25] Set _WIN32_WINNT in static deps Set -D_WIN32_WINNT for static deps; unbound, in particular, needs this as the latest version appears to rely on something only provided in non-ancient windows to build properly. This required moving _winver into the toolchain file so that it is available earlier in cmake code (StaticBuild is included long before win32.cmake), but also this seems a more appropriate place for it. --- cmake/StaticBuild.cmake | 5 +++++ cmake/win32.cmake | 3 --- contrib/cross/mingw_core.cmake | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index bfb346712..d0b9f7b29 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -167,6 +167,11 @@ if(APPLE) set(deps_CXXFLAGS "${deps_CXXFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() +if(_winver) + set(deps_CFLAGS "${deps_CFLAGS} -D_WIN32_WINNT=${_winver}") + set(deps_CXXFLAGS "${deps_CXXFLAGS} -D_WIN32_WINNT=${_winver}") +endif() + if("${CMAKE_GENERATOR}" STREQUAL "Unix Makefiles") set(_make $(MAKE)) diff --git a/cmake/win32.cmake b/cmake/win32.cmake index ae3bdb6d2..a8f977c28 100644 --- a/cmake/win32.cmake +++ b/cmake/win32.cmake @@ -13,9 +13,6 @@ option(WITH_WINDOWS_32 "build 32 bit windows" OFF) # GNU ld sees fit to merge *all* the .ident sections in object files # to .r[o]data section one after the other! add_compile_options(-fno-ident -Wa,-mbig-obj) -# the minimum windows version, set to 6 rn because supporting older windows is hell -set(_winver 0x0600) -add_definitions(-D_WIN32_WINNT=${_winver}) if(EMBEDDED_CFG) link_libatomic() diff --git a/contrib/cross/mingw_core.cmake b/contrib/cross/mingw_core.cmake index a42673eda..8086ab7f3 100644 --- a/contrib/cross/mingw_core.cmake +++ b/contrib/cross/mingw_core.cmake @@ -1,4 +1,8 @@ -set(CMAKE_SYSTEM_VERSION 5.0) +set(CMAKE_SYSTEM_VERSION 6.0) + +# the minimum windows version, set to 6 rn because supporting older windows is hell +set(_winver 0x0600) +add_definitions(-D_WIN32_WINNT=${_winver}) # target environment on the build host system # second one is for non-root installs From f01b075d3e677ca46b64454a5b30edd4ad60f034 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 20 Oct 2022 12:50:13 -0300 Subject: [PATCH 17/25] Rename darwin -> macos in uploaded build file --- contrib/ci/drone-static-upload.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh index 3f66c4545..2f2f7f2ef 100755 --- a/contrib/ci/drone-static-upload.sh +++ b/contrib/ci/drone-static-upload.sh @@ -19,9 +19,15 @@ set -o xtrace # Don't start tracing until *after* we write the ssh key chmod 600 ssh_key -os="${UPLOAD_OS:-$DRONE_STAGE_OS-$DRONE_STAGE_ARCH}" -if [ -n "$WINDOWS_BUILD_NAME" ]; then - os="windows-$WINDOWS_BUILD_NAME" +os="$UPLOAD_OS" +if [ -z "$os" ]; then + if [ "$DRONE_STAGE_OS" == "darwin" ]; then + os="macos-$DRONE_STAGE_ARCH" + elif [ -n "$WINDOWS_BUILD_NAME" ]; then + os="windows-$WINDOWS_BUILD_NAME" + else + os="$DRONE_STAGE_OS-$DRONE_STAGE_ARCH" + fi fi if [ -n "$DRONE_TAG" ]; then From d011f8fb4a14b1f724fc1f15b532c5f97512babf Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 20 Oct 2022 19:23:14 -0300 Subject: [PATCH 18/25] Bump clang-format to 14 --- .drone.jsonnet | 2 +- contrib/ci/drone-format-verify.sh | 5 ++++- contrib/format-version.sh | 19 +++++++++++++++++++ contrib/format.sh | 24 ++++-------------------- daemon/lokinet.cpp | 5 ++--- llarp/apple/route_manager.hpp | 6 ++++-- llarp/dns/message.cpp | 6 ++++-- llarp/handlers/exit.cpp | 3 ++- llarp/handlers/null.hpp | 7 ++++--- llarp/iwp/session.cpp | 6 ++++-- llarp/link/session.hpp | 3 ++- llarp/net/posix.cpp | 3 ++- llarp/path/path_context.cpp | 3 ++- llarp/path/pathbuilder.cpp | 3 ++- llarp/path/pathset.cpp | 3 ++- llarp/path/pathset.hpp | 9 ++++++--- llarp/peerstats/peer_db.cpp | 6 ++++-- llarp/service/endpoint.cpp | 6 ++++-- llarp/service/lookup.hpp | 6 ++++-- llarp/win32/windivert.cpp | 3 ++- pybind/llarp/handlers/pyhandler.hpp | 7 ++++--- 21 files changed, 82 insertions(+), 53 deletions(-) create mode 100644 contrib/format-version.sh diff --git a/.drone.jsonnet b/.drone.jsonnet index 203746cca..e2890382a 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -336,7 +336,7 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = { 'echo "Building on ${DRONE_STAGE_MACHINE}"', apt_get_quiet + ' update', apt_get_quiet + ' install -y eatmydata', - 'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y git clang-format-11 jsonnet', + 'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y git clang-format-14 jsonnet', './contrib/ci/drone-format-verify.sh', ], }], diff --git a/contrib/ci/drone-format-verify.sh b/contrib/ci/drone-format-verify.sh index 387340018..197b2e2a9 100755 --- a/contrib/ci/drone-format-verify.sh +++ b/contrib/ci/drone-format-verify.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash test "x$IGNORE" != "x" && exit 0 + +. $(dirname $0)/../format-version.sh + repo=$(readlink -e $(dirname $0)/../../) -clang-format-11 -i $(find $repo/jni $repo/daemon $repo/llarp $repo/include $repo/pybind | grep -E '\.[hc](pp)?$') +$CLANG_FORMAT -i $(find $repo/jni $repo/daemon $repo/llarp $repo/include $repo/pybind | grep -E '\.[hc](pp)?$') jsonnetfmt -i $repo/.drone.jsonnet git --no-pager diff --exit-code --color || (echo -ne '\n\n\e[31;1mLint check failed; please run ./contrib/format.sh\e[0m\n\n' ; exit 1) diff --git a/contrib/format-version.sh b/contrib/format-version.sh new file mode 100644 index 000000000..d8fe6e855 --- /dev/null +++ b/contrib/format-version.sh @@ -0,0 +1,19 @@ + +CLANG_FORMAT_DESIRED_VERSION=14 + +CLANG_FORMAT=$(command -v clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) +if [ $? -ne 0 ]; then + CLANG_FORMAT=$(command -v clang-format-mp-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) +fi +if [ $? -ne 0 ]; then + CLANG_FORMAT=$(command -v clang-format 2>/dev/null) + if [ $? -ne 0 ]; then + echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script." + exit 1 + fi + version=$(clang-format --version) + if [[ ! $version == *"clang-format version $CLANG_FORMAT_DESIRED_VERSION"* ]]; then + echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script." + exit 1 + fi +fi diff --git a/contrib/format.sh b/contrib/format.sh index a51fbaa9a..d757554e0 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -1,31 +1,15 @@ #!/usr/bin/env bash -CLANG_FORMAT_DESIRED_VERSION=11 - -binary=$(command -v clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) -if [ $? -ne 0 ]; then - binary=$(command -v clang-format-mp-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) -fi -if [ $? -ne 0 ]; then - binary=$(command -v clang-format 2>/dev/null) - if [ $? -ne 0 ]; then - echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script." - exit 1 - fi - version=$(clang-format --version) - if [[ ! $version == *"clang-format version $CLANG_FORMAT_DESIRED_VERSION"* ]]; then - echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script." - exit 1 - fi -fi +. $(dirname $0)/format-version.sh cd "$(dirname $0)/../" + if [ "$1" = "verify" ] ; then - if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') | grep '' | wc -l) -ne 0 ] ; then + if [ $($CLANG_FORMAT --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') | grep '' | wc -l) -ne 0 ] ; then exit 2 fi else - $binary -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') &> /dev/null + $CLANG_FORMAT -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') &> /dev/null fi swift_format=$(command -v swiftformat 2>/dev/null) diff --git a/daemon/lokinet.cpp b/daemon/lokinet.cpp index 70c9648f2..af71310a5 100644 --- a/daemon/lokinet.cpp +++ b/daemon/lokinet.cpp @@ -329,9 +329,8 @@ class WindowsServiceStopped LONG GenerateDump(EXCEPTION_POINTERS* pExceptionPointers) { - const auto flags = (MINIDUMP_TYPE)( - MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData - | MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo); + const auto flags = + (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo); std::stringstream ss; ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp"; diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp index b69904276..69403c04d 100644 --- a/llarp/apple/route_manager.hpp +++ b/llarp/apple/route_manager.hpp @@ -15,10 +15,12 @@ namespace llarp::apple /// These are called for poking route holes, but we don't have to do that at all on macos /// because the appex isn't subject to its own rules. - void AddRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override + void + AddRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override {} - void DelRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override + void + DelRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override {} void diff --git a/llarp/dns/message.cpp b/llarp/dns/message.cpp index f4d70763f..48d84f703 100644 --- a/llarp/dns/message.cpp +++ b/llarp/dns/message.cpp @@ -160,7 +160,8 @@ namespace llarp return OwnedBuffer::copy_used(buf); } - void Message::AddServFail(RR_TTL_t) + void + Message::AddServFail(RR_TTL_t) { if (questions.size()) { @@ -386,7 +387,8 @@ namespace llarp std::copy_n(buf.base, buf.sz, rec.rData.data()); } - void Message::AddNXReply(RR_TTL_t) + void + Message::AddNXReply(RR_TTL_t) { if (questions.size()) { diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 11c9d35c2..64e002e3a 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -613,7 +613,8 @@ namespace llarp }); } - std::optional ExitEndpoint::GetStatFor(AddressVariant_t) const + std::optional + ExitEndpoint::GetStatFor(AddressVariant_t) const { /// TODO: implement me return std::nullopt; diff --git a/llarp/handlers/null.hpp b/llarp/handlers/null.hpp index cd97fa82d..bfa0525e8 100644 --- a/llarp/handlers/null.hpp +++ b/llarp/handlers/null.hpp @@ -101,13 +101,14 @@ namespace llarp::handlers void SendPacketToRemote(const llarp_buffer_t&, service::ProtocolType) override{}; - huint128_t ObtainIPForAddr(std::variant) override + huint128_t + ObtainIPForAddr(std::variant) override { return {0}; } - std::optional> ObtainAddrForIP( - huint128_t) const override + std::optional> + ObtainAddrForIP(huint128_t) const override { return std::nullopt; } diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 382e75c64..b2109c479 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -924,13 +924,15 @@ namespace llarp } } - void Session::HandleCLOS(Packet_t) + void + Session::HandleCLOS(Packet_t) { LogInfo("remote closed by ", m_RemoteAddr); Close(); } - void Session::HandlePING(Packet_t) + void + Session::HandlePING(Packet_t) { m_LastRX = m_Parent->Now(); } diff --git a/llarp/link/session.hpp b/llarp/link/session.hpp index fc8df2414..0c54756fa 100644 --- a/llarp/link/session.hpp +++ b/llarp/link/session.hpp @@ -68,7 +68,8 @@ namespace llarp /// recv packet on low layer /// not used by utp - virtual bool Recv_LL(Packet_t) + virtual bool + Recv_LL(Packet_t) { return true; } diff --git a/llarp/net/posix.cpp b/llarp/net/posix.cpp index b04398c0c..6bc764a0b 100644 --- a/llarp/net/posix.cpp +++ b/llarp/net/posix.cpp @@ -93,7 +93,8 @@ namespace llarp::net return IPRange::FindPrivateRange(currentRanges); } - std::optional GetInterfaceIndex(ipaddr_t) const override + std::optional + GetInterfaceIndex(ipaddr_t) const override { // todo: implement me return std::nullopt; diff --git a/llarp/path/path_context.cpp b/llarp/path/path_context.cpp index f856ec3e8..7bb5223b0 100644 --- a/llarp/path/path_context.cpp +++ b/llarp/path/path_context.cpp @@ -412,7 +412,8 @@ namespace llarp return nullptr; } - void PathContext::RemovePathSet(PathSet_ptr) + void + PathContext::RemovePathSet(PathSet_ptr) {} } // namespace path } // namespace llarp diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index eaefcf40c..478060005 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -335,7 +335,8 @@ namespace llarp Build(*maybe, roles); } - bool Builder::UrgentBuild(llarp_time_t) const + bool + Builder::UrgentBuild(llarp_time_t) const { return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4; } diff --git a/llarp/path/pathset.cpp b/llarp/path/pathset.cpp index c3ba852d6..0474544d2 100644 --- a/llarp/path/pathset.cpp +++ b/llarp/path/pathset.cpp @@ -73,7 +73,8 @@ namespace llarp } } - void PathSet::Tick(llarp_time_t) + void + PathSet::Tick(llarp_time_t) { std::unordered_set endpoints; for (auto& item : m_Paths) diff --git a/llarp/path/pathset.hpp b/llarp/path/pathset.hpp index 734b5b26b..3e431bf41 100644 --- a/llarp/path/pathset.hpp +++ b/llarp/path/pathset.hpp @@ -210,19 +210,22 @@ namespace llarp BlacklistSNode(const RouterID) = 0; /// override me in subtype - virtual bool HandleGotIntroMessage(std::shared_ptr) + virtual bool + HandleGotIntroMessage(std::shared_ptr) { return false; } /// override me in subtype - virtual bool HandleGotRouterMessage(std::shared_ptr) + virtual bool + HandleGotRouterMessage(std::shared_ptr) { return false; } /// override me in subtype - virtual bool HandleGotNameMessage(std::shared_ptr) + virtual bool + HandleGotNameMessage(std::shared_ptr) { return false; } diff --git a/llarp/peerstats/peer_db.cpp b/llarp/peerstats/peer_db.cpp index 8226dafc8..d3b93b75b 100644 --- a/llarp/peerstats/peer_db.cpp +++ b/llarp/peerstats/peer_db.cpp @@ -308,7 +308,8 @@ namespace llarp throw std::logic_error{"Peer stats backend not enabled!"}; } - void PeerDb::loadDatabase(std::optional) + void + PeerDb::loadDatabase(std::optional) {} void @@ -349,7 +350,8 @@ namespace llarp PeerDb::configure(const RouterConfig&) {} - bool PeerDb::shouldFlush(llarp_time_t) + bool + PeerDb::shouldFlush(llarp_time_t) { return false; } diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 1395dadd1..03455d118 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -320,7 +320,8 @@ namespace llarp return m_state->ExtractStatus(obj); } - void Endpoint::Tick(llarp_time_t) + void + Endpoint::Tick(llarp_time_t) { const auto now = llarp::time_now_ms(); path::Builder::Tick(now); @@ -1165,7 +1166,8 @@ namespace llarp return m_Identity.pub.Addr(); } - std::optional Endpoint::GetStatFor(AddressVariant_t) const + std::optional + Endpoint::GetStatFor(AddressVariant_t) const { // TODO: implement me return std::nullopt; diff --git a/llarp/service/lookup.hpp b/llarp/service/lookup.hpp index 1507f68dc..9f20cc127 100644 --- a/llarp/service/lookup.hpp +++ b/llarp/service/lookup.hpp @@ -35,7 +35,8 @@ namespace llarp } /// handle lookup result for introsets - virtual bool HandleNameResponse(std::optional
) + virtual bool + HandleNameResponse(std::optional
) { return false; } @@ -76,7 +77,8 @@ namespace llarp RouterID endpoint; /// return true if this lookup is for a remote address - virtual bool IsFor(EndpointBase::AddressVariant_t) const + virtual bool + IsFor(EndpointBase::AddressVariant_t) const { return false; } diff --git a/llarp/win32/windivert.cpp b/llarp/win32/windivert.cpp index b359e1927..7dc181e91 100644 --- a/llarp/win32/windivert.cpp +++ b/llarp/win32/windivert.cpp @@ -125,7 +125,8 @@ namespace llarp::win32 return -1; } - virtual bool WritePacket(net::IPPacket) override + virtual bool + WritePacket(net::IPPacket) override { return false; } diff --git a/pybind/llarp/handlers/pyhandler.hpp b/pybind/llarp/handlers/pyhandler.hpp index 97fdc9572..3f712dcc6 100644 --- a/pybind/llarp/handlers/pyhandler.hpp +++ b/pybind/llarp/handlers/pyhandler.hpp @@ -66,13 +66,14 @@ namespace llarp return false; } - llarp::huint128_t ObtainIPForAddr(std::variant) override + llarp::huint128_t + ObtainIPForAddr(std::variant) override { return {0}; } - std::optional> ObtainAddrForIP( - huint128_t) const override + std::optional> + ObtainAddrForIP(huint128_t) const override { return std::nullopt; } From bd5da108857c1408abdb0fd8f7d7a4e43312bffa Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 24 Oct 2022 07:42:46 -0400 Subject: [PATCH 19/25] fixes issue #2029 when read/writing a .loki privkey file we dont rewind a llarp_buffer_t after use. this is an argument in favor of just removing that type from the code entirely. fixes by using 2 distinct locally scoped llarp_buffer_t, one for read, one for write. --- llarp/service/identity.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/llarp/service/identity.cpp b/llarp/service/identity.cpp index f54a025a5..a28bb2204 100644 --- a/llarp/service/identity.cpp +++ b/llarp/service/identity.cpp @@ -80,7 +80,6 @@ namespace llarp Clear(); std::array tmp; - llarp_buffer_t buf(tmp); // this can throw bool exists = fs::exists(fname); @@ -94,6 +93,7 @@ namespace llarp // check for file if (!exists) { + llarp_buffer_t buf{tmp}; // regen and encode RegenerateKeys(); if (!BEncode(&buf)) @@ -108,6 +108,7 @@ namespace llarp { throw std::runtime_error{fmt::format("failed to write {}: {}", fname, e.what())}; } + return; } if (not fs::is_regular_file(fname)) @@ -125,10 +126,11 @@ namespace llarp throw std::length_error{"service identity too big"}; } // (don't catch io error exceptions) - - if (!bencode_decode_dict(*this, &buf)) - throw std::length_error{"could not decode service identity"}; - + { + llarp_buffer_t buf{tmp}; + if (!bencode_decode_dict(*this, &buf)) + throw std::length_error{"could not decode service identity"}; + } auto crypto = CryptoManager::instance(); // ensure that the encryption key is set From 1231d4e6c40d1be00e05fbfaa59f65338dddf368 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Mon, 24 Oct 2022 20:39:05 -0400 Subject: [PATCH 20/25] add 'networkReady' to endpoint status --- llarp/service/endpoint.cpp | 34 +++++++++++++++++++++++++++------- llarp/service/endpoint.hpp | 3 +++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 03455d118..48c33543a 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -40,6 +40,11 @@ #include #include +namespace +{ + constexpr size_t MIN_ENDPOINTS_FOR_LNS_LOOKUP = 2; +} // namespace + namespace llarp { namespace service @@ -309,6 +314,7 @@ namespace llarp auto obj = path::Builder::ExtractStatus(); obj["exitMap"] = m_ExitMap.ExtractStatus(); obj["identity"] = m_Identity.pub.Addr().ToString(); + obj["networkReady"] = ReadyToDoLookup(); util::StatusObject authCodes; for (const auto& [service, info] : m_RemoteAuthInfos) @@ -946,6 +952,22 @@ namespace llarp return not m_ExitMap.Empty(); } + bool + Endpoint::ReadyToDoLookup(std::optional numPaths) const + { + if (not numPaths) + { + path::Path::UniqueEndpointSet_t paths; + ForEachPath([&paths](auto path) { + if (path and path->IsReady()) + paths.insert(path); + }); + numPaths = paths.size(); + } + + return numPaths >= MIN_ENDPOINTS_FOR_LNS_LOOKUP; + } + void Endpoint::LookupNameAsync( std::string name, @@ -965,23 +987,20 @@ namespace llarp } LogInfo(Name(), " looking up LNS name: ", name); path::Path::UniqueEndpointSet_t paths; - ForEachPath([&](auto path) { + ForEachPath([&paths](auto path) { if (path and path->IsReady()) paths.insert(path); }); - constexpr size_t min_unique_lns_endpoints = 2; - constexpr size_t max_unique_lns_endpoints = 7; - // not enough paths - if (paths.size() < min_unique_lns_endpoints) + if (not ReadyToDoLookup(paths.size())) { LogWarn( Name(), " not enough paths for lns lookup, have ", paths.size(), " need ", - min_unique_lns_endpoints); + MIN_ENDPOINTS_FOR_LNS_LOOKUP); handler(std::nullopt); return; } @@ -1006,11 +1025,12 @@ namespace llarp handler(result); }; + constexpr size_t max_lns_lookup_endpoints = 7; // pick up to max_unique_lns_endpoints random paths to do lookups from std::vector chosenpaths; chosenpaths.insert(chosenpaths.begin(), paths.begin(), paths.end()); std::shuffle(chosenpaths.begin(), chosenpaths.end(), CSRNG{}); - chosenpaths.resize(std::min(paths.size(), max_unique_lns_endpoints)); + chosenpaths.resize(std::min(paths.size(), max_lns_lookup_endpoints)); auto resultHandler = m_state->lnsTracker.MakeResultHandler(name, chosenpaths.size(), maybeInvalidateCache); diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 00a2a3c68..09b960957 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -521,6 +521,9 @@ namespace llarp return false; } + bool + ReadyToDoLookup(std::optional numPaths = std::nullopt) const; + protected: IDataHandler* m_DataHandler = nullptr; Identity m_Identity; From 3b6953badcb9b69bd14eb67d76f638a63b40bc32 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Mon, 24 Oct 2022 21:58:32 -0400 Subject: [PATCH 21/25] clarify strict-connect usage and enforce minimum of 2 nodes --- llarp/config/config.cpp | 4 ++-- llarp/router/router.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 9f8f41397..7572b34bb 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -300,9 +300,9 @@ namespace llarp throw std::invalid_argument{"duplicate strict connect snode: " + value}; }, Comment{ - "Public key of a router which will act as a pinned first-hop. This may be used to", + "Public keys of routers which will act as pinned first-hops. This may be used to", "provide a trusted router (consider that you are not fully anonymous with your", - "first hop).", + "first hop). This REQUIRES two or more nodes to be specified.", }); conf.defineOption( diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 00d357eb7..5214d75a3 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -653,14 +653,15 @@ namespace llarp auto& networkConfig = conf.network; /// build a set of strictConnectPubkeys ( - /// TODO: make this consistent with config -- do we support multiple strict connections - // or not? std::unordered_set strictConnectPubkeys; if (not networkConfig.m_strictConnect.empty()) { const auto& val = networkConfig.m_strictConnect; if (IsServiceNode()) throw std::runtime_error("cannot use strict-connect option as service node"); + if (val.size() < 2) + throw std::runtime_error( + "Must specify more than one strict-connect router if using strict-connect"); strictConnectPubkeys.insert(val.begin(), val.end()); } From 3131297b00348cf3fcdce3611c5c125a78b500f1 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 25 Oct 2022 18:06:25 -0300 Subject: [PATCH 22/25] Fix backwards compatible config option handler Without this, old config (with now-irrelevant settings) won't work in newer lokinet, making lokinet fatal error on startup if one of the no-longer-used options is still present. --- llarp/config/config.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 7572b34bb..aa02da5c2 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1413,6 +1413,7 @@ namespace llarp params->isRelay = isRelay; params->defaultDataDir = m_DataDir; ConfigDefinition conf{isRelay}; + addBackwardsCompatibleConfigOptions(conf); initializeConfig(conf, *params); for (const auto& item : m_Additional) From 9f49e006e4a3b3f9d365eabc2b594c3e36544885 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 25 Oct 2022 18:57:31 -0300 Subject: [PATCH 23/25] Debug Router::Configure; initialize logging earlier - Move logging initialization to early in Configure rather than at the end of FromConfig so that we can add debug logging inside Configure/FromConfig/etc. - add said debug logging to Configure/FromConfig/etc. --- llarp/router/router.cpp | 60 ++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 5214d75a3..58a271f61 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -395,6 +395,31 @@ namespace llarp { m_Config = std::move(c); auto& conf = *m_Config; + + // Do logging config as early as possible to get the configured log level applied + + // Backwards compat: before 0.9.10 we used `type=file` with `file=|-|stdout` for print mode + auto log_type = conf.logging.m_logType; + if (log_type == log::Type::File + && (conf.logging.m_logFile == "stdout" || conf.logging.m_logFile == "-" + || conf.logging.m_logFile.empty())) + log_type = log::Type::Print; + + if (log::get_level_default() != log::Level::off) + log::reset_level(conf.logging.m_logLevel); + log::clear_sinks(); + log::add_sink(log_type, conf.logging.m_logFile); + + enableRPCServer = conf.api.m_enableRPCServer; + + // re-add rpc log sink if rpc enabled, else free it + if (enableRPCServer and llarp::logRingBuffer) + log::add_sink(llarp::logRingBuffer, llarp::log::DEFAULT_PATTERN_MONO); + else + llarp::logRingBuffer = nullptr; + + log::debug(logcat, "Configuring router"); + whitelistRouters = conf.lokid.whitelistRouters; if (whitelistRouters) { @@ -402,33 +427,39 @@ namespace llarp m_lokidRpcClient = std::make_shared(m_lmq, weak_from_this()); } - enableRPCServer = conf.api.m_enableRPCServer; if (enableRPCServer) rpcBindAddr = oxenmq::address(conf.api.m_rpcBindAddr); + log::debug(logcat, "Starting RPC server"); if (not StartRpcServer()) throw std::runtime_error("Failed to start rpc server"); if (conf.router.m_workerThreads > 0) m_lmq->set_general_threads(conf.router.m_workerThreads); + log::debug(logcat, "Starting OMQ server"); m_lmq->start(); _nodedb = std::move(nodedb); m_isServiceNode = conf.router.m_isRelay; + log::debug( + logcat, m_isServiceNode ? "Running as a relay (service node)" : "Running as a client"); if (whitelistRouters) { m_lokidRpcClient->ConnectAsync(lokidRPCAddr); } - // fetch keys + log::debug(logcat, "Initializing key manager"); if (not m_keyManager->initialize(conf, true, isSNode)) throw std::runtime_error("KeyManager failed to initialize"); + + log::debug(logcat, "Initializing from configuration"); if (!FromConfig(conf)) throw std::runtime_error("FromConfig() failed"); + log::debug(logcat, "Initializing identity"); if (not EnsureIdentity()) throw std::runtime_error("EnsureIdentity() failed"); return true; @@ -601,6 +632,7 @@ namespace llarp Router::FromConfig(const Config& conf) { // 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)) { const auto& netid = conf.router.m_netId; @@ -640,7 +672,10 @@ namespace llarp _ourAddress->setPort(*maybe_port); else throw std::runtime_error{"public ip provided without public port"}; + log::debug(logcat, "Using {} for our public address", *_ourAddress); } + else + log::debug(logcat, "No explicit public address given; will auto-detect during link setup"); RouterContact::BlockBogons = conf.router.m_blockBogons; @@ -663,6 +698,7 @@ namespace llarp throw std::runtime_error( "Must specify more than one strict-connect router if using strict-connect"); strictConnectPubkeys.insert(val.begin(), val.end()); + log::debug(logcat, "{} strict-connect routers configured", val.size()); } std::vector configRouters = conf.connect.routers; @@ -803,26 +839,6 @@ namespace llarp hiddenServiceContext().AddEndpoint(conf); } - // Logging config - - // Backwards compat: before 0.9.10 we used `type=file` with `file=|-|stdout` for print mode - auto log_type = conf.logging.m_logType; - if (log_type == log::Type::File - && (conf.logging.m_logFile == "stdout" || conf.logging.m_logFile == "-" - || conf.logging.m_logFile.empty())) - log_type = log::Type::Print; - - if (log::get_level_default() != log::Level::off) - log::reset_level(conf.logging.m_logLevel); - log::clear_sinks(); - log::add_sink(log_type, conf.logging.m_logFile); - - // re-add rpc log sink if rpc enabled, else free it - if (enableRPCServer and llarp::logRingBuffer) - log::add_sink(llarp::logRingBuffer, llarp::log::DEFAULT_PATTERN_MONO); - else - llarp::logRingBuffer = nullptr; - return true; } From a828ef3f6daaaf7dc6894ae3b4c4240fda679365 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 25 Oct 2022 20:10:56 -0300 Subject: [PATCH 24/25] Remove obsolete junk This stuff is already set earlier, in Configure. --- llarp/router/router.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 58a271f61..38216cd54 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -679,12 +679,6 @@ namespace llarp RouterContact::BlockBogons = conf.router.m_blockBogons; - // Lokid Config - whitelistRouters = conf.lokid.whitelistRouters; - lokidRPCAddr = oxenmq::address(conf.lokid.lokidRPCAddr); - - m_isServiceNode = conf.router.m_isRelay; - auto& networkConfig = conf.network; /// build a set of strictConnectPubkeys ( From 1980ca4d5988477c3649e90565a94e21d71b7277 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 25 Oct 2022 20:11:23 -0300 Subject: [PATCH 25/25] Fix bootstrap list bad bootstrap skipping The iterator here to skip an obsolete bootstrap wasn't properly reassigning the iterator, so "didn't work" (though why it was hanging for me is entirely non-obvious). Also refactored it to simplify/clarify it a bit. --- llarp/router/router.cpp | 47 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 38216cd54..73e52bf4d 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -711,58 +711,51 @@ namespace llarp } } - BootstrapList b_list; + bootstrapRCList.clear(); for (const auto& router : configRouters) { - b_list.AddFromFile(router); + log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile); + bootstrapRCList.AddFromFile(router); } for (const auto& rc : conf.bootstrap.routers) { - b_list.emplace(rc); + bootstrapRCList.emplace(rc); } // in case someone has an old bootstrap file and is trying to use a bootstrap // that no longer exists - for (auto rc_itr = b_list.begin(); rc_itr != b_list.end();) - { - if (rc_itr->IsObsoleteBootstrap()) - b_list.erase(rc_itr); - else - rc_itr++; - } - - auto verifyRCs = [&]() { - for (auto& rc : b_list) + auto clearBadRCs = [this]() { + for (auto it = bootstrapRCList.begin(); it != bootstrapRCList.end();) { - if (rc.IsObsoleteBootstrap()) + 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 { - log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID(rc.pubkey)); + ++it; continue; } - if (not rc.Verify(Now())) - { - log::warning(logcat, "ignoring invalid RC: {}", RouterID(rc.pubkey)); - continue; - } - bootstrapRCList.emplace(std::move(rc)); + // we are in one of the above error cases that we warned about: + it = bootstrapRCList.erase(it); } }; - verifyRCs(); + clearBadRCs(); if (bootstrapRCList.empty() and not conf.bootstrap.seednode) { auto fallbacks = llarp::load_bootstrap_fallbacks(); if (auto itr = fallbacks.find(_rc.netID.ToString()); itr != fallbacks.end()) { - b_list = itr->second; - - verifyRCs(); + bootstrapRCList = itr->second; + log::debug(logcat, "loaded {} default fallback bootstrap routers", bootstrapRCList.size()); + clearBadRCs(); } - if (bootstrapRCList.empty() - and not conf.bootstrap.seednode) // empty after trying fallback, if set + if (bootstrapRCList.empty() and not conf.bootstrap.seednode) { + // empty after trying fallback, if set log::error( logcat, "No bootstrap routers were loaded. The default bootstrap file {} does not exist, and "