From b70ecade2b24901a632114d123544bf1ca936003 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Jun 2021 08:02:10 -0400 Subject: [PATCH 01/21] correct the logic for inbound convos send back traffic on the correct path --- llarp/service/endpoint.cpp | 176 +++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 95 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index f995a3b84..587d6604c 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -400,7 +400,7 @@ namespace llarp { for (const auto& item : Sessions()) { - if (item.second.remote.Addr() == addr && item.second.inbound) + if (item.second.remote.Addr() == addr and item.second.inbound) return true; } return false; @@ -421,7 +421,7 @@ namespace llarp Endpoint::PutSenderFor(const ConvoTag& tag, const ServiceInfo& info, bool inbound) { auto itr = Sessions().find(tag); - if (itr == Sessions().end()) + if (itr == Sessions().end() and not(WantsOutboundSession(info.Addr()) and inbound)) { itr = Sessions().emplace(tag, Session{}).first; itr->second.inbound = inbound; @@ -1079,14 +1079,7 @@ namespace llarp { msg->sender.UpdateAddr(); PutSenderFor(msg->tag, msg->sender, true); - PutReplyIntroFor(msg->tag, path->intro); - Introduction intro; - intro.pathID = from; - intro.router = PubKey{path->Endpoint()}; - intro.expiresAt = std::min(path->ExpireTime(), msg->introReply.expiresAt); - intro.latency = path->intro.latency; - PutIntroFor(msg->tag, intro); - PutReplyIntroFor(msg->tag, path->intro); + PutReplyIntroFor(msg->tag, msg->introReply); ConvoTagRX(msg->tag); return ProcessDataMessage(msg); } @@ -1792,11 +1785,11 @@ namespace llarp return false; } - // inbound conversation const auto now = Now(); if (HasInboundConvo(remote)) { + // inbound conversation LogTrace("Have inbound convo"); auto transfer = std::make_shared(); ProtocolFrame& f = transfer->T; @@ -1806,86 +1799,85 @@ namespace llarp { // the remote guy's intro Introduction remoteIntro; - Introduction replyPath; SharedSecret K; const auto tag = *maybe; - if (!GetCachedSessionKeyFor(tag, K)) + if (not GetCachedSessionKeyFor(tag, K)) { - LogError("no cached key for T=", tag); + LogError(Name(), " no cached key for inbound session from ", remote, " T=", tag); return false; } - if (!GetIntroFor(tag, remoteIntro)) + if (not GetReplyIntroFor(tag, remoteIntro)) { - LogError("no intro for T=", tag); + LogError(Name(), "no reply intro for inbound session from ", remote, " T=", tag); return false; } - if (GetReplyIntroFor(tag, replyPath)) + // get path for intro + auto p = GetPathByRouter(remoteIntro.router); + + if (not p) { - // get path for intro - ForEachPath([&](path::Path_ptr path) { - if (path->intro == replyPath) - { - p = path; - return; - } - if (p && p->ExpiresSoon(now) && path->IsReady() - && path->intro.router == replyPath.router) - { - p = path; - } - }); + LogWarn( + Name(), + " has no path for intro router ", + RouterID{remoteIntro.router}, + " for inbound convo T=", + tag); + return false; } - else - p = GetPathByRouter(remoteIntro.router); - if (p) + f.T = tag; + // TODO: check expiration of our end + auto m = std::make_shared(f.T); + m->PutBuffer(data); + f.N.Randomize(); + f.C.Zero(); + f.R = 0; + transfer->Y.Randomize(); + m->proto = t; + m->introReply = p->intro; + m->sender = m_Identity.pub; + if (auto maybe = GetSeqNoForConvo(f.T)) { - f.T = tag; - // TODO: check expiration of our end - auto m = std::make_shared(f.T); - m->PutBuffer(data); - f.N.Randomize(); - f.C.Zero(); - f.R = 0; - transfer->Y.Randomize(); - m->proto = t; - m->introReply = p->intro; - PutReplyIntroFor(f.T, m->introReply); - m->sender = m_Identity.pub; - if (auto maybe = GetSeqNoForConvo(f.T)) - { - m->seqno = *maybe; - } - else - { - LogWarn(Name(), " no session T=", f.T); - return false; - } - f.S = m->seqno; - f.F = m->introReply.pathID; - transfer->P = remoteIntro.pathID; - auto self = this; - Router()->QueueWork([transfer, p, m, K, self]() { - if (not transfer->T.EncryptAndSign(*m, K, self->m_Identity)) - { - LogError("failed to encrypt and sign"); - return; - } - self->m_SendQueue.tryPushBack(SendEvent_t{transfer, p}); - }); - return true; + m->seqno = *maybe; } else { - LogTrace("SendToOrQueue failed to return via inbound: no path"); + LogWarn(Name(), " could not set sequence number, no session T=", f.T); + return false; } + f.S = m->seqno; + f.F = m->introReply.pathID; + transfer->P = remoteIntro.pathID; + auto self = this; + Router()->QueueWork([transfer, p, m, K, self]() { + if (not transfer->T.EncryptAndSign(*m, K, self->m_Identity)) + { + LogError("failed to encrypt and sign for sessionn T=", transfer->T.T); + return; + } + self->m_SendQueue.tryPushBack(SendEvent_t{transfer, p}); + }); + return true; } else { - LogWarn("Have inbound convo from ", remote, " but get-best returned none; bug?"); + LogWarn( + Name(), + " SendToOrQueue on inbound convo from ", + remote, + " but get-best returned none; bug?"); } } + if (not WantsOutboundSession(remote)) + { + LogWarn( + Name(), + " SendToOrQueue on outbound session we did not mark as outbound (remote=", + remote, + ")"); + return false; + } // Failed to find a suitable inbound convo, look for outbound LogTrace("Not an inbound convo"); @@ -1900,34 +1892,28 @@ namespace llarp return true; } } - // if we want to make an outbound session - if (WantsOutboundSession(remote)) - { - LogTrace("Making an outbound session and queuing the data"); - // add pending traffic - auto& traffic = m_state->m_PendingTraffic; - traffic[remote].emplace_back(data, t); - EnsurePathToService( - remote, - [self = this](Address addr, OutboundContext* ctx) { - if (ctx) - { - for (auto& pending : self->m_state->m_PendingTraffic[addr]) - { - ctx->AsyncEncryptAndSendTo(pending.Buffer(), pending.protocol); - } - } - else + LogTrace("Making an outbound session and queuing the data"); + // add pending traffic + auto& traffic = m_state->m_PendingTraffic; + traffic[remote].emplace_back(data, t); + EnsurePathToService( + remote, + [self = this](Address addr, OutboundContext* ctx) { + if (ctx) + { + for (auto& pending : self->m_state->m_PendingTraffic[addr]) { - LogWarn("no path made to ", addr); + ctx->AsyncEncryptAndSendTo(pending.Buffer(), pending.protocol); } - self->m_state->m_PendingTraffic.erase(addr); - }, - PathAlignmentTimeout()); - return true; - } - LogDebug("SendOrQueue failed: no inbound/outbound sessions"); - return false; + } + else + { + LogWarn("no path made to ", addr); + } + self->m_state->m_PendingTraffic.erase(addr); + }, + PathAlignmentTimeout()); + return true; } bool From 5c3b4090d2eb13c70394ef786d369074d1e37d51 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Jun 2021 08:17:44 -0400 Subject: [PATCH 02/21] dont mark inbound sessions as outbound when we get a DNS lookup for it --- llarp/handlers/tun.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 7ab8f1dcb..e6dba331f 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -397,6 +397,13 @@ namespace llarp service::Address addr, auto msg, bool isV6) -> bool { using service::Address; using service::OutboundContext; + if(HasInboundConvo(addr)) + { + // if we have an inbound convo to this address don't mark as outbound so we don't have a state race + // this codepath is hit when an application verifies that reverse and forward dns records match for an inbound session + SendDNSReply(addr, this, msg, reply, isV6); + return true; + } MarkAddressOutbound(addr); return EnsurePathToService( addr, @@ -424,6 +431,7 @@ namespace llarp service::Address addr, auto msg) -> bool { using service::Address; using service::OutboundContext; + // TODO: how do we handle SRV record lookups for inbound sessions? MarkAddressOutbound(addr); return EnsurePathToService( addr, From 71d17dc2c90dde6f154495a8f299aa3f817e09c9 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Jun 2021 09:49:54 -0400 Subject: [PATCH 03/21] format and logging ignore outbound session auth messages --- contrib/py/admin/lokinetmon | 2 +- llarp/handlers/tun.cpp | 7 ++++--- llarp/service/endpoint.cpp | 37 ++++++++++++++++++++++++++++--------- llarp/service/protocol.cpp | 12 +++++++++--- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/contrib/py/admin/lokinetmon b/contrib/py/admin/lokinetmon index 4c36b34e6..d1caba481 100755 --- a/contrib/py/admin/lokinetmon +++ b/contrib/py/admin/lokinetmon @@ -155,7 +155,7 @@ class Monitor: def time_to(timestamp): """ return time until timestamp in seconds formatted""" if timestamp: - val = int((timestamp - now()) / 1000) + val = (timestamp - now()) / 1000.0 if val < 0: return "{} seconds ago".format(0-val) else: diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index e6dba331f..cab17108c 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -397,10 +397,11 @@ namespace llarp service::Address addr, auto msg, bool isV6) -> bool { using service::Address; using service::OutboundContext; - if(HasInboundConvo(addr)) + if (HasInboundConvo(addr)) { - // if we have an inbound convo to this address don't mark as outbound so we don't have a state race - // this codepath is hit when an application verifies that reverse and forward dns records match for an inbound session + // if we have an inbound convo to this address don't mark as outbound so we don't have a + // state race this codepath is hit when an application verifies that reverse and forward + // dns records match for an inbound session SendDNSReply(addr, this, msg, reply, isV6); return true; } diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 587d6604c..7e6f8f786 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -420,9 +420,24 @@ namespace llarp void Endpoint::PutSenderFor(const ConvoTag& tag, const ServiceInfo& info, bool inbound) { + if (info.Addr().IsZero()) + { + LogError(Name(), " cannot put invalid service info ", info, " T=", tag); + return; + } auto itr = Sessions().find(tag); - if (itr == Sessions().end() and not(WantsOutboundSession(info.Addr()) and inbound)) + if (itr == Sessions().end()) { + if (WantsOutboundSession(info.Addr()) and inbound) + { + LogWarn( + Name(), + " not adding sender for ", + info.Addr(), + " session is inbound and we want outbound T=", + tag); + return; + } itr = Sessions().emplace(tag, Session{}).first; itr->second.inbound = inbound; itr->second.remote = info; @@ -1077,9 +1092,13 @@ namespace llarp Endpoint::HandleDataMessage( path::Path_ptr path, const PathID_t from, std::shared_ptr msg) { - msg->sender.UpdateAddr(); PutSenderFor(msg->tag, msg->sender, true); - PutReplyIntroFor(msg->tag, msg->introReply); + Introduction intro = msg->introReply; + if (HasInboundConvo(msg->sender.Addr())) + { + intro.pathID = from; + } + PutReplyIntroFor(msg->tag, intro); ConvoTagRX(msg->tag); return ProcessDataMessage(msg); } @@ -1798,7 +1817,7 @@ namespace llarp if (const auto maybe = GetBestConvoTagFor(remote)) { // the remote guy's intro - Introduction remoteIntro; + Introduction replyIntro; SharedSecret K; const auto tag = *maybe; @@ -1807,20 +1826,20 @@ namespace llarp LogError(Name(), " no cached key for inbound session from ", remote, " T=", tag); return false; } - if (not GetReplyIntroFor(tag, remoteIntro)) + if (not GetReplyIntroFor(tag, replyIntro)) { LogError(Name(), "no reply intro for inbound session from ", remote, " T=", tag); return false; } // get path for intro - auto p = GetPathByRouter(remoteIntro.router); + auto p = GetPathByRouter(replyIntro.router); if (not p) { LogWarn( Name(), " has no path for intro router ", - RouterID{remoteIntro.router}, + RouterID{replyIntro.router}, " for inbound convo T=", tag); return false; @@ -1847,8 +1866,8 @@ namespace llarp return false; } f.S = m->seqno; - f.F = m->introReply.pathID; - transfer->P = remoteIntro.pathID; + f.F = p->intro.pathID; + transfer->P = replyIntro.pathID; auto self = this; Router()->QueueWork([transfer, p, m, K, self]() { if (not transfer->T.EncryptAndSign(*m, K, self->m_Identity)) diff --git a/llarp/service/protocol.cpp b/llarp/service/protocol.cpp index 89c6a09aa..8ecf32ac8 100644 --- a/llarp/service/protocol.cpp +++ b/llarp/service/protocol.cpp @@ -367,9 +367,15 @@ namespace llarp AuthResult result) { if (result.code == AuthResultCode::eAuthAccepted) { - handler->PutSenderFor(msg->tag, msg->sender, true); - handler->PutIntroFor(msg->tag, msg->introReply); - handler->PutReplyIntroFor(msg->tag, fromIntro); + if (handler->WantsOutboundSession(msg->sender.Addr())) + { + handler->PutSenderFor(msg->tag, msg->sender, false); + } + else + { + handler->PutSenderFor(msg->tag, msg->sender, true); + } + handler->PutReplyIntroFor(msg->tag, msg->introReply); handler->PutCachedSessionKeyFor(msg->tag, sharedKey); handler->SendAuthResult(path, from, msg->tag, result); LogInfo("auth okay for T=", msg->tag, " from ", msg->sender.Addr()); From e48feb8b9a5220f733ab49f048caecaffe909339 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Jun 2021 14:50:22 -0400 Subject: [PATCH 04/21] kill outbound context when we remove our convotag --- llarp/service/outbound_context.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 85ebbb869..19748f2f0 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -337,6 +337,14 @@ namespace llarp { SwapIntros(); } + if (ReadyToSend() and IntroSent()) + { + // if we dont have a cached session key after sending intro we are in a fugged state so + // expunge + SharedSecret discardme; + if (not m_DataHandler->GetCachedSessionKeyFor(currentConvoTag, discardme)) + return true; + } if ((remoteIntro.router.IsZero() or m_BadIntros.count(remoteIntro)) and GetPathByRouter(m_NextIntro.router)) From d9cae4a6c6e86246a93182108669b6eeca1cb1b9 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Jun 2021 17:25:19 -0400 Subject: [PATCH 05/21] in outbound context, ShouldBuildMore intro.ExpiresSoon delta is too big and has no overlap, change it so that --- llarp/service/outbound_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 19748f2f0..cbf88fff0 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -444,7 +444,7 @@ namespace llarp ForEachPath([now, &numValidPaths](path::Path_ptr path) { if (not path->IsReady()) return; - if (not path->intro.ExpiresSoon(now, path::default_lifetime - path::intro_path_spread)) + if (not path->intro.ExpiresSoon(now, path::intro_path_spread)) numValidPaths++; }); return numValidPaths < numDesiredPaths; From 7f9a60066b3afa56f3c7396d93da3ccec5059381 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 15 Jun 2021 20:53:40 -0400 Subject: [PATCH 06/21] make sure we have a path to the next introduction we want to use --- llarp/service/outbound_context.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index cbf88fff0..120033296 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -441,13 +441,18 @@ namespace llarp return false; size_t numValidPaths = 0; - ForEachPath([now, &numValidPaths](path::Path_ptr path) { + bool havePathToNextIntro = false; + ForEachPath([now, this, &havePathToNextIntro, &numValidPaths](path::Path_ptr path) { if (not path->IsReady()) return; - if (not path->intro.ExpiresSoon(now, path::intro_path_spread)) + if (not path->intro.ExpiresSoon(now, path::default_lifetime - path::intro_path_spread)) + { numValidPaths++; + if (path->intro.router == m_NextIntro.router) + havePathToNextIntro = true; + } }); - return numValidPaths < numDesiredPaths; + return numValidPaths < numDesiredPaths or not havePathToNextIntro; } void From 00d4942d85a9a4db80974318f819a0a0dd7e1744 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Jun 2021 21:16:10 -0400 Subject: [PATCH 07/21] more --- contrib/py/admin/lokinetmon | 2 +- llarp/service/outbound_context.cpp | 52 +++++++++++++++--------------- llarp/service/outbound_context.hpp | 1 - 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/contrib/py/admin/lokinetmon b/contrib/py/admin/lokinetmon index d1caba481..8ef8e18ba 100755 --- a/contrib/py/admin/lokinetmon +++ b/contrib/py/admin/lokinetmon @@ -449,7 +449,7 @@ class Monitor: for intro in context['introset']['intros'] or []: y_pos = self._display_intro(y_pos, intro, "introset intro", context['paths']) for path in context['paths']: - y_pos = self._display_intro(y_pos, path['intro'], "inbound path intro", context['paths']) + y_pos = self._display_intro(y_pos, path['intro'], "inbound path [created {}]".format(self.time_to(path['buildStarted'])), context['paths']) return y_pos diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 120033296..2ab08bc67 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -314,11 +314,6 @@ namespace llarp obj["currentRemoteIntroset"] = currentIntroSet.ExtractStatus(); obj["nextIntro"] = m_NextIntro.ExtractStatus(); obj["readyToSend"] = ReadyToSend(); - std::transform( - m_BadIntros.begin(), - m_BadIntros.end(), - std::back_inserter(obj["badIntros"]), - [](const auto& item) -> util::StatusObject { return item.first.ExtractStatus(); }); return obj; } @@ -346,10 +341,6 @@ namespace llarp return true; } - if ((remoteIntro.router.IsZero() or m_BadIntros.count(remoteIntro)) - and GetPathByRouter(m_NextIntro.router)) - SwapIntros(); - if (m_GotInboundTraffic and m_LastInboundTraffic + sendTimeout <= now) { // timeout on other side @@ -359,22 +350,34 @@ namespace llarp } // check for stale intros // update the introset if we think we need to - if (currentIntroSet.HasStaleIntros(now, path::intro_path_spread)) + if (currentIntroSet.HasStaleIntros(now, path::intro_path_spread) or remoteIntro.ExpiresSoon(now, path::intro_path_spread)) { UpdateIntroSet(); + ShiftIntroduction(false); + } + + if(ReadyToSend()) + { + if(not remoteIntro.router.IsZero() and not GetPathByRouter(remoteIntro.router)) + { + std::vector otherPivots; + ForEachPath([router=remoteIntro.router, &otherPivots](auto path) + { + if(path and path->IsReady() and path->Endpoint() != router) + { + otherPivots.emplace_back(path->intro); + } + }); + if(not otherPivots.empty()) + { + std::shuffle(otherPivots.begin(), otherPivots.end(), CSRNG{}); + remoteIntro = otherPivots[0]; + } + } } // lookup router in intro if set and unknown if (not m_NextIntro.router.IsZero()) m_Endpoint->EnsureRouterIsKnown(m_NextIntro.router); - // expire bad intros - auto itr = m_BadIntros.begin(); - while (itr != m_BadIntros.end()) - { - if (now > itr->second && now - itr->second > path::default_lifetime) - itr = m_BadIntros.erase(itr); - else - ++itr; - } if (ReadyToSend() and not m_ReadyHooks.empty()) { @@ -453,7 +456,7 @@ namespace llarp } }); return numValidPaths < numDesiredPaths or not havePathToNextIntro; - } +} void OutboundContext::MarkCurrentIntroBad(llarp_time_t now) @@ -462,10 +465,8 @@ namespace llarp } void - OutboundContext::MarkIntroBad(const Introduction& intro, llarp_time_t now) + OutboundContext::MarkIntroBad(const Introduction& , llarp_time_t ) { - // insert bad intro - m_BadIntros[intro] = now; } bool @@ -501,13 +502,12 @@ namespace llarp continue; if (m_Endpoint->SnodeBlacklist().count(intro.router)) continue; - if (m_BadIntros.find(intro) == m_BadIntros.end() && remoteIntro.router == intro.router) + if (remoteIntro.router == intro.router) { if (intro.expiresAt > m_NextIntro.expiresAt) { success = true; m_NextIntro = intro; - return true; } } } @@ -521,7 +521,7 @@ namespace llarp m_Endpoint->EnsureRouterIsKnown(intro.router); if (intro.ExpiresSoon(now)) continue; - if (m_BadIntros.find(intro) == m_BadIntros.end() && m_NextIntro != intro) + if (m_NextIntro != intro) { if (intro.expiresAt > m_NextIntro.expiresAt) { diff --git a/llarp/service/outbound_context.hpp b/llarp/service/outbound_context.hpp index 4242e85bc..8e27500e6 100644 --- a/llarp/service/outbound_context.hpp +++ b/llarp/service/outbound_context.hpp @@ -161,7 +161,6 @@ namespace llarp uint64_t m_UpdateIntrosetTX = 0; IntroSet currentIntroSet; Introduction m_NextIntro; - std::unordered_map m_BadIntros; llarp_time_t lastShift = 0s; uint16_t m_LookupFails = 0; uint16_t m_BuildFails = 0; From 963250c0ef60efa2147376302f9dbfc0f2811d17 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 16 Jun 2021 09:52:32 -0400 Subject: [PATCH 08/21] format --- llarp/service/endpoint.cpp | 2 +- llarp/service/outbound_context.cpp | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 7e6f8f786..09c999ebb 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -1090,7 +1090,7 @@ namespace llarp bool Endpoint::HandleDataMessage( - path::Path_ptr path, const PathID_t from, std::shared_ptr msg) + path::Path_ptr, const PathID_t from, std::shared_ptr msg) { PutSenderFor(msg->tag, msg->sender, true); Introduction intro = msg->introReply; diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 2ab08bc67..b7c1c4dcc 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -350,25 +350,25 @@ namespace llarp } // check for stale intros // update the introset if we think we need to - if (currentIntroSet.HasStaleIntros(now, path::intro_path_spread) or remoteIntro.ExpiresSoon(now, path::intro_path_spread)) + if (currentIntroSet.HasStaleIntros(now, path::intro_path_spread) + or remoteIntro.ExpiresSoon(now, path::intro_path_spread)) { UpdateIntroSet(); ShiftIntroduction(false); } - if(ReadyToSend()) + if (ReadyToSend()) { - if(not remoteIntro.router.IsZero() and not GetPathByRouter(remoteIntro.router)) + if (not remoteIntro.router.IsZero() and not GetPathByRouter(remoteIntro.router)) { std::vector otherPivots; - ForEachPath([router=remoteIntro.router, &otherPivots](auto path) - { - if(path and path->IsReady() and path->Endpoint() != router) - { - otherPivots.emplace_back(path->intro); - } - }); - if(not otherPivots.empty()) + ForEachPath([router = remoteIntro.router, &otherPivots](auto path) { + if (path and path->IsReady() and path->Endpoint() != router) + { + otherPivots.emplace_back(path->intro); + } + }); + if (not otherPivots.empty()) { std::shuffle(otherPivots.begin(), otherPivots.end(), CSRNG{}); remoteIntro = otherPivots[0]; @@ -456,7 +456,7 @@ namespace llarp } }); return numValidPaths < numDesiredPaths or not havePathToNextIntro; -} + } void OutboundContext::MarkCurrentIntroBad(llarp_time_t now) @@ -465,9 +465,8 @@ namespace llarp } void - OutboundContext::MarkIntroBad(const Introduction& , llarp_time_t ) - { - } + OutboundContext::MarkIntroBad(const Introduction&, llarp_time_t) + {} bool OutboundContext::IntroSent() const From 4b11858bb041f4ed0d830bc51fa9a80f117a3ab5 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 16 Jun 2021 10:05:15 -0400 Subject: [PATCH 09/21] make clang compile, remove unused variable --- llarp/service/endpoint.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 09c999ebb..72a0a02cf 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -1803,9 +1803,6 @@ namespace llarp LogTrace("SendToOrQueue: dropping because data.sz == 0"); return false; } - - const auto now = Now(); - if (HasInboundConvo(remote)) { // inbound conversation From ae36fd42bb2550b493bc72cd141115cd637ba9c5 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 16 Jun 2021 14:10:21 -0400 Subject: [PATCH 10/21] remove badIntros from lokinetmon as rpc no longer has them in it --- contrib/py/admin/lokinetmon | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contrib/py/admin/lokinetmon b/contrib/py/admin/lokinetmon index 8ef8e18ba..2c45b2435 100755 --- a/contrib/py/admin/lokinetmon +++ b/contrib/py/admin/lokinetmon @@ -489,12 +489,8 @@ class Monitor: for intro in context['currentRemoteIntroset']['intros'] or []: y_pos = self._display_intro(y_pos, intro, "introset intro", paths) y_pos += 1 - for intro in context['badIntros'] or []: - y_pos = self._display_intro(y_pos, intro, "bad intro", paths) - y_pos += 1 return y_pos - def display_data(self): """ draw main window """ if self.data is not None: From 9f353238af2a96f4f8a11816b2bdb0c63c48e859 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 17 Jun 2021 05:05:55 -0400 Subject: [PATCH 11/21] ReadyToSend also should include checking we have a path to the remote --- llarp/service/outbound_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index b7c1c4dcc..e557cfa39 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -151,7 +151,7 @@ namespace llarp return false; if (remoteIntro.router.IsZero()) return false; - return IntroSent(); + return IntroSent() and GetPathByRouter(remoteIntro.router); } void From d45f0f8951f0c2639657be1cc31ef6224596336e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 17 Jun 2021 05:06:23 -0400 Subject: [PATCH 12/21] value initialize introduction so that expiresAt defaults to zero --- llarp/service/outbound_context.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index e557cfa39..c5440af5a 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -158,10 +158,10 @@ namespace llarp OutboundContext::ShiftIntroRouter(const RouterID r) { const auto now = Now(); - Introduction selectedIntro; + Introduction selectedIntro{}; for (const auto& intro : currentIntroSet.intros) { - if (intro.expiresAt > selectedIntro.expiresAt && intro.router != r) + if (intro.expiresAt > selectedIntro.expiresAt and intro.router != r) { selectedIntro = intro; } From 1a0e6a7ac1fe8d80fe6b497d553acd111f2b2a72 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 17 Jun 2021 05:06:57 -0400 Subject: [PATCH 13/21] remove redundant check as ReadyToSend also checks IntroSent() --- llarp/service/outbound_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index c5440af5a..f0126662e 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -332,7 +332,7 @@ namespace llarp { SwapIntros(); } - if (ReadyToSend() and IntroSent()) + if (ReadyToSend()) { // if we dont have a cached session key after sending intro we are in a fugged state so // expunge From b5efb8c6049b4c9ea98c66e7695081d1d1f14070 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 17 Jun 2021 05:07:29 -0400 Subject: [PATCH 14/21] rename local variable to be clear about meaning, add comment --- llarp/service/outbound_context.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index f0126662e..71996e12c 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -361,17 +361,19 @@ namespace llarp { if (not remoteIntro.router.IsZero() and not GetPathByRouter(remoteIntro.router)) { - std::vector otherPivots; - ForEachPath([router = remoteIntro.router, &otherPivots](auto path) { - if (path and path->IsReady() and path->Endpoint() != router) + // pick another good intro if we have no path on our current intro + std::vector otherIntros; + ForEachPath([now, router = remoteIntro.router, &otherIntros](auto path) { + if (path and path->IsReady() and path->Endpoint() != router + and not path->ExpiresSoon(now, path::intro_path_spread)) { - otherPivots.emplace_back(path->intro); + otherIntros.emplace_back(path->intro); } }); - if (not otherPivots.empty()) + if (not otherIntros.empty()) { - std::shuffle(otherPivots.begin(), otherPivots.end(), CSRNG{}); - remoteIntro = otherPivots[0]; + std::shuffle(otherIntros.begin(), otherIntros.end(), CSRNG{}); + remoteIntro = otherIntros[0]; } } } From 3393b5a5a767ea6e242bff4894de2380ccf0d8d0 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 17 Jun 2021 08:08:46 -0400 Subject: [PATCH 15/21] make it so lookups dont time out --- llarp/service/endpoint.cpp | 2 +- llarp/service/hidden_service_address_lookup.hpp | 3 +++ llarp/service/outbound_context.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 72a0a02cf..6577bc24c 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -1465,7 +1465,7 @@ namespace llarp path->Endpoint(), order, GenTXID(), - timeout + (2 * path->intro.latency)); + timeout + (2 * path->intro.latency) + IntrosetLookupGraceInterval); LogInfo( "doing lookup for ", remote, diff --git a/llarp/service/hidden_service_address_lookup.hpp b/llarp/service/hidden_service_address_lookup.hpp index 2e656a885..164b365d2 100644 --- a/llarp/service/hidden_service_address_lookup.hpp +++ b/llarp/service/hidden_service_address_lookup.hpp @@ -8,6 +8,9 @@ namespace llarp { namespace service { + /// interval for which we will add to lookup timeout interval + constexpr auto IntrosetLookupGraceInterval = 20s; + struct Endpoint; struct HiddenServiceAddressLookup : public IServiceLookup { diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 71996e12c..5103ae257 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -289,7 +289,7 @@ namespace llarp path->Endpoint(), relayOrder, m_Endpoint->GenTXID(), - (IntrosetUpdateInterval / 2) + (2 * path->intro.latency)); + (IntrosetUpdateInterval / 2) + (2 * path->intro.latency) + IntrosetLookupGraceInterval); relayOrder++; if (job->SendRequestViaPath(path, m_Endpoint->Router())) updatingIntroSet = true; From 1c457e28587a764bfda1859f9343a09a9f4f8983 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 17 Jun 2021 20:04:15 -0400 Subject: [PATCH 16/21] bump version to 0.9.4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f98a5671e..ea2651591 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ if(CCACHE_PROGRAM) endif() project(lokinet - VERSION 0.9.3 + VERSION 0.9.4 DESCRIPTION "lokinet - IP packet onion router" LANGUAGES C CXX) From ee5723ecdc5ca5024563f1f14eb3086de1645c3c Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sat, 19 Jun 2021 07:45:22 -0400 Subject: [PATCH 17/21] add upperbound to number of endpoints used in lns lookups --- llarp/service/endpoint.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 6577bc24c..4f0e0d646 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -932,6 +932,7 @@ namespace llarp }); 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) @@ -966,10 +967,16 @@ namespace llarp handler(result); }; + // 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)); + auto resultHandler = - m_state->lnsTracker.MakeResultHandler(name, paths.size(), maybeInvalidateCache); + m_state->lnsTracker.MakeResultHandler(name, chosenpaths.size(), maybeInvalidateCache); - for (const auto& path : paths) + for (const auto& path : chosenpaths) { LogInfo(Name(), " lookup ", name, " from ", path->Endpoint()); auto job = new LookupNameJob{this, GenTXID(), name, resultHandler}; From 872a8d80455c65a43eb78bead9998bb9bd3a7b43 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 11 Jun 2021 11:47:24 -0400 Subject: [PATCH 18/21] use exisitng convotag first instead of trying to send to directly --- llarp/handlers/tun.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index cab17108c..ccbb88221 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -1109,10 +1109,13 @@ namespace llarp } // try sending it on an existing convotag // this succeds for inbound convos, probably. - if (SendToOrQueue(to, pkt.ConstBuffer(), type)) + if (auto maybe = GetBestConvoTagFor(to)) { - MarkIPActive(dst); - return; + if (SendToOrQueue(*maybe, pkt.ConstBuffer(), type)) + { + MarkIPActive(dst); + return; + } } // try establishing a path to this guy // will fail if it's an inbound convo From 0900ab88d1c2aa3e519ca2ba905168c9e11bedc4 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 21 Jun 2021 16:01:38 -0400 Subject: [PATCH 19/21] publish introsets on nearest routers fetch introset from random routers --- llarp/service/endpoint.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 4f0e0d646..796d9e536 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -602,7 +602,10 @@ namespace llarp bool Endpoint::PublishIntroSet(const EncryptedIntroSet& introset, AbstractRouter* r) { - const auto paths = GetManyPathsWithUniqueEndpoints(this, llarp::dht::IntroSetRelayRedundancy); + const auto paths = GetManyPathsWithUniqueEndpoints( + this, + llarp::dht::IntroSetRelayRedundancy, + dht::Key_t{introset.derivedSigningKey.as_array()}); if (paths.size() != llarp::dht::IntroSetRelayRedundancy) { @@ -1448,7 +1451,7 @@ namespace llarp if (not m_IntrosetLookupFilter.Insert(remote)) return true; - const auto paths = GetManyPathsWithUniqueEndpoints(this, NumParallelLookups, remote.ToKey()); + const auto paths = GetManyPathsWithUniqueEndpoints(this, NumParallelLookups); using namespace std::placeholders; const dht::Key_t location = remote.ToKey(); From 67f8a7116ff06bdf12008be5e18c11edd179af6d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 21 Jun 2021 16:02:03 -0400 Subject: [PATCH 20/21] if we get a discard message from the pivot discard the outbound context if the remote intro is also expired --- llarp/service/outbound_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 5103ae257..54ad74602 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -49,6 +49,7 @@ namespace llarp ShiftIntroduction(false); UpdateIntroSet(); SwapIntros(); + markedBad = remoteIntro.IsExpired(Now()); } return true; } @@ -399,6 +400,8 @@ namespace llarp { // send a keep alive to keep this session alive KeepAlive(); + if (markedBad) + return true; } // if we are dead return true so we are removed return timeout > 0s ? (now >= timeout && now - timeout > sendTimeout) From 9d0dffe08645983e646b950e07f2f2438848fe42 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 22 Jun 2021 09:26:03 -0400 Subject: [PATCH 21/21] only permit 1 pending session per udp endpoint --- llarp/link/server.cpp | 3 +-- llarp/link/server.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/llarp/link/server.cpp b/llarp/link/server.cpp index 6e40b0df4..b8c9f748f 100644 --- a/llarp/link/server.cpp +++ b/llarp/link/server.cpp @@ -481,10 +481,9 @@ namespace llarp bool ILinkLayer::PutSession(const std::shared_ptr& s) { - static constexpr size_t MaxSessionsPerEndpoint = 5; Lock_t lock(m_PendingMutex); const auto address = s->GetRemoteEndpoint(); - if (m_Pending.count(address) >= MaxSessionsPerEndpoint) + if (m_Pending.count(address)) return false; m_Pending.emplace(address, s); return true; diff --git a/llarp/link/server.hpp b/llarp/link/server.hpp index cc3b5e84e..e58e4da56 100644 --- a/llarp/link/server.hpp +++ b/llarp/link/server.hpp @@ -245,7 +245,7 @@ namespace llarp SecretKey m_SecretKey; using AuthedLinks = std::unordered_multimap>; - using Pending = std::unordered_multimap>; + using Pending = std::unordered_map>; mutable DECLARE_LOCK(Mutex_t, m_AuthedLinksMutex, ACQUIRED_BEFORE(m_PendingMutex)); AuthedLinks m_AuthedLinks GUARDED_BY(m_AuthedLinksMutex); mutable DECLARE_LOCK(Mutex_t, m_PendingMutex, ACQUIRED_AFTER(m_AuthedLinksMutex));