From 3ae8fce77dea355fd0fb6d47bc5cc4585ca05159 Mon Sep 17 00:00:00 2001 From: dr7ana Date: Wed, 18 Oct 2023 05:48:09 -0700 Subject: [PATCH] Outbound context absorbed sendcontex - message transmission routed through refactored handling - still work to be done, but now to make it compile at least --- llarp/exit/session.cpp | 8 +- llarp/handlers/exit.cpp | 19 +-- llarp/handlers/null.hpp | 3 +- llarp/handlers/tun.hpp | 3 +- llarp/link/link_manager.cpp | 4 +- llarp/link/link_manager.hpp | 6 +- llarp/nodedb.cpp | 5 +- llarp/nodedb.hpp | 5 +- llarp/path/path.cpp | 1 + llarp/router_contact.hpp | 2 +- llarp/rpc/endpoint_rpc.cpp | 21 +-- llarp/rpc/endpoint_rpc.hpp | 2 +- llarp/service/async_key_exchange.cpp | 15 +- llarp/service/async_key_exchange.hpp | 3 +- llarp/service/auth.cpp | 4 +- llarp/service/auth.hpp | 2 +- llarp/service/endpoint.cpp | 45 ++++-- llarp/service/endpoint.hpp | 6 +- llarp/service/intro.cpp | 16 ++ llarp/service/intro.hpp | 2 + llarp/service/outbound_context.cpp | 219 ++++++++++++++++++--------- llarp/service/outbound_context.hpp | 34 +++-- llarp/service/protocol.cpp | 82 ++++------ llarp/service/protocol.hpp | 43 ++---- llarp/service/sendcontext.cpp | 2 +- llarp/util/buffer.hpp | 6 + 26 files changed, 318 insertions(+), 240 deletions(-) diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index fe6b9832c..70bed01cf 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -80,7 +80,7 @@ namespace llarp::exit return std::vector{*maybe}; return std::nullopt; } - + return GetHopsAlignedToForBuild(exit_router); } @@ -377,7 +377,7 @@ namespace llarp::exit void ExitSession::send_packet_to_remote(std::string buf) { - net::IPPacket pkt{buf.view_all()}; + net::IPPacket pkt{buf}; if (pkt.empty()) return; pkt.ZeroAddresses(); @@ -388,12 +388,12 @@ namespace llarp::exit void SNodeSession::send_packet_to_remote(std::string buf) { - net::IPPacket pkt{buf.view_all()}; + net::IPPacket pkt{buf}; if (pkt.empty()) return; pkt.ZeroSourceAddress(); - + // QueueUpstreamTraffic(std::move(pkt), llarp::routing::EXIT_PAD_SIZE, t); } } // namespace llarp::exit diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 0b1ec7a72..6ab5f8fee 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -106,20 +106,21 @@ namespace llarp::handlers { if (not itr->second->LooksDead(Now())) { - if (itr->second->QueueInboundTraffic(payload.copy(), type)) - return true; + return router->send_data_message(itr->second->PubKey(), std::move(payload)); } } if (not router->PathToRouterAllowed(*rid)) return false; - ObtainSNodeSession(*rid, [pkt = std::move(payload)](auto session) mutable { - if (session and session->IsReady()) - { - session->send_packet_to_remote(std::move(pkt)); - } - }); + ObtainSNodeSession( + *rid, + [pkt = std::move(payload)](std::shared_ptr session) mutable { + if (session and session->IsReady()) + { + session->send_packet_to_remote(std::move(pkt)); + } + }); } return true; } @@ -404,7 +405,7 @@ namespace llarp::handlers } } auto tryFlushingTraffic = [this, buf = std::move(buf), pk](exit::Endpoint* const ep) -> bool { - if (!ep->QueueInboundTraffic(buf, service::ProtocolType::TrafficV4)) + if (!ep->QueueInboundTraffic(buf._buf, service::ProtocolType::TrafficV4)) { LogWarn( Name(), diff --git a/llarp/handlers/null.hpp b/llarp/handlers/null.hpp index 1d216456a..7b16c5c93 100644 --- a/llarp/handlers/null.hpp +++ b/llarp/handlers/null.hpp @@ -74,8 +74,7 @@ namespace llarp::handlers return true; } - void - send_packet_to_remote(std::string) override {}; + void send_packet_to_remote(std::string) override{}; std::string GetIfName() const override diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index 89d07f1c9..f4241d901 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -72,8 +72,7 @@ namespace llarp::handlers bool Configure(const NetworkConfig& conf, const DnsConfig& dnsConf) override; - void - send_packet_to_remote(std::string) override{}; + void send_packet_to_remote(std::string) override{}; std::string GetIfName() const override; diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 610a24515..11dab5c26 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -1648,9 +1648,7 @@ namespace llarp } try - { - - } + {} catch (const std::exception& e) { log::warning(link_cat, "Exception: {}", e.what()); diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index c7f11e01c..e57190cf7 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -310,6 +310,9 @@ namespace llarp void handle_update_exit(oxen::quic::message); // relay void handle_close_exit(oxen::quic::message); // relay + // Misc + void handle_convo_intro(oxen::quic::message); + std::unordered_map rpc_commands = { {"find_name", &LinkManager::handle_find_name}, {"find_router", &LinkManager::handle_find_router}, @@ -320,7 +323,8 @@ namespace llarp {"path_latency", &LinkManager::handle_path_latency}, {"update_exit", &LinkManager::handle_update_exit}, {"obtain_exit", &LinkManager::handle_obtain_exit}, - {"close_exit", &LinkManager::handle_close_exit}}; + {"close_exit", &LinkManager::handle_close_exit}, + {"convo_intro", &LinkManager::handle_convo_intro}}; // Path relaying void handle_path_control(oxen::quic::message); diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 6b198496d..0bcbefa6c 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -185,7 +185,8 @@ namespace llarp bool NodeDB::has_router(RouterID pk) const { - return router.loop()->call_get([this, pk]() { return entries.find(pk) != entries.end(); }); + return router.loop()->call_get( + [this, pk]() -> bool { return entries.find(pk) != entries.end(); }); } std::optional @@ -243,7 +244,7 @@ namespace llarp size_t NodeDB::num_loaded() const { - return router.loop()->call_get([this]() { return entries.size(); }); + return router.loop()->call_get([this]() -> size_t { return entries.size(); }); } void diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 6082c2857..8bc1289a6 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -2,10 +2,11 @@ #include "router_contact.hpp" #include "router_id.hpp" -#include "dht/key.hpp" -#include "crypto/crypto.hpp" + #include "util/common.hpp" #include "util/fs.hpp" +#include "dht/key.hpp" +#include "crypto/crypto.hpp" #include "util/thread/threading.hpp" #include "util/thread/annotations.hpp" #include diff --git a/llarp/path/path.cpp b/llarp/path/path.cpp index 9884532e1..13eeb0980 100644 --- a/llarp/path/path.cpp +++ b/llarp/path/path.cpp @@ -138,6 +138,7 @@ namespace llarp::path "path_control", std::move(outer_dict).str(), [response_cb = std::move(func)](oxen::quic::message m) { + if (m) { // do path hop logic here } diff --git a/llarp/router_contact.hpp b/llarp/router_contact.hpp index a1c7e450c..677536263 100644 --- a/llarp/router_contact.hpp +++ b/llarp/router_contact.hpp @@ -64,7 +64,7 @@ namespace llarp { /// for unit tests static bool BlockBogons; - + static llarp_time_t Lifetime; static llarp_time_t UpdateInterval; static llarp_time_t StaleInsertionAge; diff --git a/llarp/rpc/endpoint_rpc.cpp b/llarp/rpc/endpoint_rpc.cpp index a5edd2c34..ca2e4e41a 100644 --- a/llarp/rpc/endpoint_rpc.cpp +++ b/llarp/rpc/endpoint_rpc.cpp @@ -44,26 +44,26 @@ namespace llarp::rpc void EndpointAuthRPC::AuthenticateAsync( std::shared_ptr msg, - std::function hook) + std::function hook) { service::ConvoTag tag = msg->tag; m_PendingAuths.insert(tag); const auto from = msg->sender.Addr(); - auto reply = m_Endpoint->Loop()->make_caller([this, tag, hook](service::AuthResult result) { + auto reply = m_Endpoint->Loop()->make_caller([this, tag, hook](std::string code, bool success) { m_PendingAuths.erase(tag); - hook(result); + hook(code, success); }); if (m_AuthWhitelist.count(from)) { // explicitly whitelisted source - reply(service::AuthResult{service::AuthResultCode::eAuthAccepted, "explicitly whitelisted"}); + reply("explicitly whitelisted", true); return; } if (msg->proto != llarp::service::ProtocolType::Auth) { // not an auth message, reject - reply(service::AuthResult{service::AuthResultCode::eAuthRejected, "protocol error"}); + reply("protocol error", false); return; } @@ -71,7 +71,7 @@ namespace llarp::rpc if (m_AuthStaticTokens.count(payload)) { - reply(service::AuthResult{service::AuthResultCode::eAuthAccepted, "explicitly whitelisted"}); + reply("explicitly whitelisted", true); return; } @@ -80,13 +80,12 @@ namespace llarp::rpc if (m_AuthStaticTokens.empty()) { // we don't have a connection to the backend so it's failed - reply(service::AuthResult{ - service::AuthResultCode::eAuthFailed, "remote has no connection to auth backend"}); + reply("remote has no connection to auth backend", false); } else { // static auth mode - reply(service::AuthResult{service::AuthResultCode::eAuthRejected, "access not permitted"}); + reply("access not permitted", true); } return; } @@ -100,6 +99,7 @@ namespace llarp::rpc [self = shared_from_this(), reply = std::move(reply)]( bool success, std::vector data) { service::AuthResult result{service::AuthResultCode::eAuthFailed, "no reason given"}; + if (success and not data.empty()) { if (const auto maybe = service::ParseAuthResultCode(data[0])) @@ -115,7 +115,8 @@ namespace llarp::rpc result.reason = data[1]; } } - reply(result); + + reply(result.reason, success); }, metainfo, payload); diff --git a/llarp/rpc/endpoint_rpc.hpp b/llarp/rpc/endpoint_rpc.hpp index 02e573d6d..b521537eb 100644 --- a/llarp/rpc/endpoint_rpc.hpp +++ b/llarp/rpc/endpoint_rpc.hpp @@ -32,7 +32,7 @@ namespace llarp::rpc void AuthenticateAsync( std::shared_ptr msg, - std::function hook) override; + std::function hook) override; bool AsyncAuthPending(service::ConvoTag tag) const override; diff --git a/llarp/service/async_key_exchange.cpp b/llarp/service/async_key_exchange.cpp index 38e5bbd5d..2cfecad42 100644 --- a/llarp/service/async_key_exchange.cpp +++ b/llarp/service/async_key_exchange.cpp @@ -15,8 +15,7 @@ namespace llarp::service const PQPubKey& introsetPubKey, const Introduction& remote, Endpoint* h, - const ConvoTag& t, - ProtocolType proto) + const ConvoTag& t) : loop(std::move(l)) , m_remote(std::move(r)) , m_LocalIdentity(localident) @@ -24,9 +23,7 @@ namespace llarp::service , remoteIntro(remote) , handler(h) , tag(t) - { - msg.proto = proto; - } + {} void AsyncKeyExchange::Result( @@ -47,13 +44,15 @@ namespace llarp::service // derive ntru session key component SharedSecret secret; auto crypto = CryptoManager::instance(); + crypto->pqe_encrypt(frame->cipher, secret, self->introPubKey); - // randomize Nonce frame->nonce.Randomize(); - // compure post handshake session key + + // compute post handshake session key // PKE (A, B, N) SharedSecret sharedSecret; path_dh_func dh_client = util::memFn(&Crypto::dh_client, crypto); + if (!self->m_LocalIdentity.KeyExchange(dh_client, sharedSecret, self->m_remote, frame->nonce)) { LogError("failed to derive x25519 shared key component"); @@ -67,8 +66,6 @@ namespace llarp::service self->msg.tag = self->tag; // set sender self->msg.sender = self->m_LocalIdentity.pub; - // set version - self->msg.version = llarp::constants::proto_version; // encrypt and sign if (frame->EncryptAndSign(self->msg, secret, self->m_LocalIdentity)) self->loop->call([self, frame] { AsyncKeyExchange::Result(self, frame); }); diff --git a/llarp/service/async_key_exchange.hpp b/llarp/service/async_key_exchange.hpp index 108046563..3957bc4ac 100644 --- a/llarp/service/async_key_exchange.hpp +++ b/llarp/service/async_key_exchange.hpp @@ -27,8 +27,7 @@ namespace llarp::service const PQPubKey& introsetPubKey, const Introduction& remote, Endpoint* h, - const ConvoTag& t, - ProtocolType proto); + const ConvoTag& t); static void Result(std::shared_ptr user, std::shared_ptr frame); diff --git a/llarp/service/auth.cpp b/llarp/service/auth.cpp index 90faef6f3..b4edf2ae4 100644 --- a/llarp/service/auth.cpp +++ b/llarp/service/auth.cpp @@ -137,7 +137,7 @@ namespace llarp::service void AuthenticateAsync( - std::shared_ptr msg, std::function hook) override + std::shared_ptr msg, std::function hook) override { auto reply = m_Router->loop()->make_caller( [tag = msg->tag, hook, self = shared_from_this()](AuthResult result) { @@ -145,7 +145,7 @@ namespace llarp::service util::Lock _lock{self->m_Access}; self->m_Pending.erase(tag); } - hook(result); + hook(result.reason, result.code == AuthResultCode::eAuthAccepted); }); { util::Lock _lock{m_Access}; diff --git a/llarp/service/auth.hpp b/llarp/service/auth.hpp index fea367594..eb2f1a3c0 100644 --- a/llarp/service/auth.hpp +++ b/llarp/service/auth.hpp @@ -57,7 +57,7 @@ namespace llarp::service /// result later virtual void AuthenticateAsync( - std::shared_ptr msg, std::function hook) = 0; + std::shared_ptr msg, std::function hook) = 0; /// return true if we are asynchronously processing authentication on this convotag virtual bool diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 67a9300be..f725eec7a 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -182,11 +182,13 @@ namespace llarp::service result_handler(false, result.reason); return; } + for (const auto& range : ranges) ptr->MapExitRange(range, addr); if (poker) poker->put_up(); + result_handler(true, result.reason); }; @@ -959,11 +961,13 @@ namespace llarp::service { PutSenderFor(msg->tag, msg->sender, true); Introduction intro = msg->introReply; + if (HasInboundConvo(msg->sender.Addr())) { intro.path_id = from; intro.router = p->Endpoint(); } + PutReplyIntroFor(msg->tag, intro); ConvoTagRX(msg->tag); return ProcessDataMessage(msg); @@ -1036,7 +1040,7 @@ namespace llarp::service void Endpoint::AsyncProcessAuthMessage( - std::shared_ptr msg, std::function hook) + std::shared_ptr msg, std::function hook) { if (_auth_policy) { @@ -1048,29 +1052,29 @@ namespace llarp::service } else { - router()->loop()->call([h = std::move(hook)] { h({AuthResultCode::eAuthAccepted, "OK"}); }); + router()->loop()->call([h = std::move(hook)] { h("OK", true); }); } } void - Endpoint::SendAuthResult(path::Path_ptr path, PathID_t replyPath, ConvoTag tag, AuthResult result) + Endpoint::SendAuthResult( + path::Path_ptr path, PathID_t replyPath, ConvoTag tag, std::string result, bool success) { // not applicable because we are not an exit or don't have an endpoint auth policy if ((not _state->is_exit_enabled) or _auth_policy == nullptr) return; + ProtocolFrameMessage f{}; - f.flag = AuthResultCodeAsInt(result.code); + f.flag = int(not success); f.convo_tag = tag; f.path_id = path->intro.path_id; f.nonce.Randomize(); - if (result.code == AuthResultCode::eAuthAccepted) + + if (success) { ProtocolMessage msg; + msg.put_buffer(result); - std::vector reason{}; - reason.resize(result.reason.size()); - std::copy_n(result.reason.c_str(), reason.size(), reason.data()); - msg.PutBuffer(reason); if (_auth_policy) msg.proto = ProtocolType::Auth; else @@ -1081,13 +1085,16 @@ namespace llarp::service LogError("Failed to send auth reply: no reply intro"); return; } + msg.sender = _identity.pub; SharedSecret sessionKey{}; + if (not GetCachedSessionKeyFor(tag, sessionKey)) { LogError("failed to send auth reply: no cached session key"); return; } + if (not f.EncryptAndSign(msg, sessionKey, _identity)) { LogError("Failed to encrypt and sign auth reply"); @@ -1225,7 +1232,7 @@ namespace llarp::service return EnsurePathToService( *ptr, - [hook](auto, auto* ctx) { + [hook](auto, auto* ctx) -> bool { if (ctx) { hook(ctx->currentConvoTag); @@ -1438,22 +1445,23 @@ namespace llarp::service // handle inbound traffic sorted util::ascending_priority_queue queue; + while (not _inbound_queue.empty()) { // succ it out queue.emplace(std::move(*_inbound_queue.popFront())); } + while (not queue.empty()) { const auto& msg = queue.top(); - LogDebug( + log::debug( + logcat, + "{} handling inbound packet (size {}B) on tag {}", Name(), - " handle inbound packet on ", msg.tag, - " ", - msg.payload.size(), - " bytes seqno=", - msg.seqno); + msg.payload.size()); + if (HandleInboundPacket(msg.tag, msg.payload, msg.proto, msg.seqno)) { ConvoTagRX(msg.tag); @@ -1462,10 +1470,13 @@ namespace llarp::service { LogWarn("Failed to handle inbound message"); } + queue.pop(); + a } auto r = router(); + // TODO: locking on this container for (const auto& [addr, outctx] : _state->remote_sessions) { @@ -1694,8 +1705,10 @@ namespace llarp::service Endpoint::MaybeGetAuthInfoForEndpoint(Address remote) { const auto itr = _remote_auth_infos.find(remote); + if (itr == _remote_auth_infos.end()) return std::nullopt; + return itr->second; } diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 9051566bf..5d11fcdb1 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -422,10 +421,11 @@ namespace llarp void AsyncProcessAuthMessage( - std::shared_ptr msg, std::function hook); + std::shared_ptr msg, std::function hook); void - SendAuthResult(path::Path_ptr path, PathID_t replyPath, ConvoTag tag, AuthResult st); + SendAuthResult( + path::Path_ptr path, PathID_t replyPath, ConvoTag tag, std::string result, bool success); uint64_t GenTXID(); diff --git a/llarp/service/intro.cpp b/llarp/service/intro.cpp index 81db1aedf..c239da5ab 100644 --- a/llarp/service/intro.cpp +++ b/llarp/service/intro.cpp @@ -67,6 +67,22 @@ namespace llarp::service } } + void + Introduction::bt_encode(oxenc::bt_dict_producer& subdict) const + { + try + { + subdict.append("k", router.ToView()); + subdict.append("l", latency.count()); + subdict.append("p", path_id.ToView()); + subdict.append("x", expiry.count()); + } + catch (...) + { + log::critical(intro_cat, "Error: Introduction failed to bt encode contents!"); + } + } + void Introduction::Clear() { diff --git a/llarp/service/intro.hpp b/llarp/service/intro.hpp index 699da4431..7dd780c86 100644 --- a/llarp/service/intro.hpp +++ b/llarp/service/intro.hpp @@ -47,6 +47,8 @@ namespace llarp::service void bt_encode(oxenc::bt_list_producer& btlp) const; + void + bt_encode(oxenc::bt_dict_producer& subdict) const; bool BDecode(llarp_buffer_t* buf) diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index e9077956b..0ff11d140 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -38,7 +38,6 @@ namespace llarp::service , addr{current_intro.address_keys.Addr()} , remote_identity{current_intro.address_keys} , created_at{ep.Now()} - { assert(not introset.intros.empty()); updatingIntroSet = false; @@ -72,7 +71,7 @@ namespace llarp::service ep.PutIntroFor(current_tag, remote_intro); ShiftIntroRouter(next_intro.router); // if we have not made a handshake to the remote endpoint do so - if (not generated_intro) + if (not generated_convo_intro) { KeepAlive(); } @@ -133,7 +132,7 @@ namespace llarp::service return false; if (remote_intro.router.IsZero()) return false; - return sent_intro and GetPathByRouter(remote_intro.router); + return sent_convo_intro and GetPathByRouter(remote_intro.router); } void @@ -199,59 +198,6 @@ namespace llarp::service } } - void - OutboundContext::AsyncGenIntro(const llarp_buffer_t& payload, ProtocolType t) - { - if (generated_intro) - { - LogWarn(Name(), " dropping packet as we are not fully handshaked right now"); - return; - } - if (remote_intro.router.IsZero()) - { - LogWarn(Name(), " dropping intro frame we have no intro ready yet"); - return; - } - - auto path = GetPathByRouter(remote_intro.router); - if (path == nullptr) - { - LogError(Name(), " has no path to ", remote_intro.router, " when we should have had one"); - return; - } - auto frame = std::make_shared(); - frame->clear(); - auto ex = std::make_shared( - ep.Loop(), - remote_identity, - ep.GetIdentity(), - current_intro.sntru_pubkey, - remote_intro, - ep, - current_tag, - t); - - ex->hook = [self = shared_from_this(), path](auto frame) { - if (not self->Send(std::move(frame), path)) - return; - self->ep.Loop()->call_later( - self->remote_intro.latency, [self]() { self->sent_intro = true; }); - }; - - ex->msg.PutBuffer(payload); - ex->msg.introReply = path->intro; - frame->path_id = ex->msg.introReply.path_id; - frame->flag = 0; - generated_intro = true; - // ensure we have a sender put for this convo tag - ep.PutSenderFor(current_tag, current_intro.address_keys, false); - // encrypt frame async - ep.router()->queue_work( - [ex, frame] { return AsyncKeyExchange::Encrypt(ex, frame); }); - - LogInfo(Name(), " send intro frame T=", current_tag); - } - std::string OutboundContext::Name() const { @@ -265,7 +211,7 @@ namespace llarp::service const auto now = Now(); if (updatingIntroSet or marked_bad or now < last_introset_update + IntrosetUpdateInterval) return; - + log::info(link_cat, "{} updating introset", Name()); last_introset_update = now; @@ -273,7 +219,7 @@ namespace llarp::service // does not implement path::PathSet::HandleGotIntroMessage const auto paths = GetManyPathsWithUniqueEndpoints(&ep, 2, location); [[maybe_unused]] uint64_t relayOrder = 0; - + for ([[maybe_unused]] const auto& path : paths) { // TODO: implement this @@ -316,12 +262,11 @@ namespace llarp::service void OutboundContext::KeepAlive() { - ustring buf(64, '\0'); - - CryptoManager::instance()->randomize(buf.data(), buf.size()); - - SendPacketToRemote(buf, ProtocolType::Control); + std::string buf(64, '\0'); + + CryptoManager::instance()->randomize(reinterpret_cast(buf.data()), buf.size()); + send_packet_to_remote(buf); last_keep_alive = Now(); } @@ -348,7 +293,6 @@ namespace llarp::service { // timeout on other side UpdateIntroSet(); - MarkCurrentIntroBad(now); ShiftIntroRouter(remote_intro.router); } // check for stale intros @@ -384,7 +328,7 @@ namespace llarp::service if (not next_intro.router.IsZero()) ep.EnsureRouterIsKnown(next_intro.router); - if (ReadyToSend() and not ready_hooks.empty()) + if (ReadyToSend()) { const auto path = GetPathByRouter(remote_intro.router); if (not path) @@ -465,12 +409,12 @@ namespace llarp::service bool success = false, shifted = false; const auto now = Now(); auto shift_timeout = send_timeout * 5 / 2; - + if (abs(now - last_shift) < shift_timeout) return false; - + std::vector intros = current_intro.intros; - + if (intros.size() > 1) { std::shuffle(intros.begin(), intros.end(), CSRNG{}); @@ -540,7 +484,6 @@ namespace llarp::service if (num == 0) { // we have no more paths to this endpoint so we want to pivot off of it - MarkCurrentIntroBad(Now()); ShiftIntroRouter(endpoint); if (next_intro.router != endpoint) BuildOneAlignedTo(next_intro.router); @@ -552,10 +495,13 @@ namespace llarp::service OutboundContext::ShouldKeepAlive(std::chrono::milliseconds now) const { const auto SendKeepAliveInterval = send_timeout / 2; + if (not got_inbound_traffic) return false; + if (last_inbound_traffic == 0s) return false; + return (now - last_keep_alive) >= SendKeepAliveInterval; } @@ -563,14 +509,147 @@ namespace llarp::service OutboundContext::Tick(std::chrono::milliseconds now) { path::Builder::Tick(now); + if (ShouldKeepAlive(now)) KeepAlive(); } + void + OutboundContext::send_auth_async(std::function resultHandler) + { + if (const auto maybe = ep.MaybeGetAuthInfoForEndpoint(remote_identity.Addr())) + gen_intro_async_impl(maybe->token, std::move(resultHandler)); + else + resultHandler("No auth needed", true); + } + + void + OutboundContext::gen_intro_async_impl( + std::string payload, std::function func) + { + auto path = GetPathByRouter(remote_intro.router); + + if (path == nullptr) + { + log::warning(logcat, "{} unexpectedly has no path to remote {}", Name(), remote_intro.router); + return; + } + + auto frame = std::make_shared(); + frame->clear(); + + auto ex = std::make_shared( + ep.Loop(), + remote_identity, + ep.GetIdentity(), + current_intro.sntru_pubkey, + remote_intro, + ep, + current_tag); + + if (const auto maybe = ep.MaybeGetAuthInfoForEndpoint(remote_identity.Addr()); not maybe) + ex->msg.proto = ProtocolType::Auth; + + ex->hook = [this, path, cb = std::move(func)](auto frame) mutable { + auto hook = [&, frame, path](oxen::quic::message) { + // TODO: revisit this + ep.HandleHiddenServiceFrame(path, *frame.get()); + }; + + if (path->send_path_control_message("convo_intro", frame->bt_encode(), hook)) + sent_convo_intro = true; + }; + + ex->msg.put_buffer(payload); + ex->msg.introReply = path->intro; + frame->path_id = ex->msg.introReply.path_id; + frame->flag = 0; + generated_convo_intro = true; + // ensure we have a sender put for this convo tag + ep.PutSenderFor(current_tag, current_intro.address_keys, false); + // encrypt frame async + ep.router()->queue_work([ex, frame] { return AsyncKeyExchange::Encrypt(ex, frame); }); + + log::info(logcat, "{} send convo intro frame for tag {}", Name(), current_tag); + } + + void + OutboundContext::gen_intro_async(std::string payload) + { + if (generated_convo_intro) + { + LogWarn(Name(), " dropping packet as we are not fully handshaked right now"); + return; + } + if (remote_intro.router.IsZero()) + { + LogWarn(Name(), " dropping convo intro frame we have no intro ready yet"); + return; + } + + gen_intro_async_impl(std::move(payload)); + } + void OutboundContext::send_packet_to_remote(std::string buf) { - AsyncEncryptAndSendTo(buf, t); + if (sent_convo_intro) + { + encrypt_and_send(std::move(buf)); + return; + } + + if (generated_convo_intro) + { + log::warning(link_cat, "{} has generated an unsent initial handshake; dropping packet"); + return; + } + + gen_intro_async(std::move(buf)); + } + + void + OutboundContext::encrypt_and_send(std::string buf) + { + SharedSecret shared; + auto f = std::make_shared(); + f->flag = 0; + f->nonce.Randomize(); + f->convo_tag = current_tag; + + auto path = GetPathByRouter(remote_intro.router); + + if (!path) + { + ShiftIntroRouter(remote_intro.router); + log::warning( + logcat, "{} cannot encrypt and send: no path for intro {}", Name(), remote_intro); + return; + } + + if (!ep.GetCachedSessionKeyFor(f->convo_tag, shared)) + { + log::warning( + logcat, "{} could not send; no cached session keys for tag {}", Name(), f->convo_tag); + return; + } + + auto msg = std::make_shared(); + ep.PutIntroFor(f->convo_tag, remote_intro); + ep.PutReplyIntroFor(f->convo_tag, path->intro); + + msg->introReply = path->intro; + f->path_id = msg->introReply.path_id; + msg->sender = ep.GetIdentity().pub; + msg->tag = f->convo_tag; + msg->put_buffer(buf); + + router->loop()->call_soon([this, f, msg, shared, path]() { + if (f->EncryptAndSign(*msg, shared, ep.GetIdentity())) + path->send_path_control_message("convo_intro", msg->bt_encode()); + else + log::warning(logcat, "{} failed to sign protocol frame message!", Name()); + }); } } // namespace llarp::service diff --git a/llarp/service/outbound_context.hpp b/llarp/service/outbound_context.hpp index 7c2e9f657..cffcff092 100644 --- a/llarp/service/outbound_context.hpp +++ b/llarp/service/outbound_context.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -29,16 +30,16 @@ namespace llarp::service Introduction remote_intro; ConvoTag current_tag; - + uint64_t update_introset_tx = 0; uint16_t lookup_fails = 0; uint16_t build_fails = 0; - + bool got_inbound_traffic = false; - bool generated_intro = false; - bool sent_intro = false; + bool generated_convo_intro = false; + bool sent_convo_intro = false; bool marked_bad = false; - + const std::chrono::milliseconds created_at; std::chrono::milliseconds last_send = 0ms; std::chrono::milliseconds send_timeout = path::BUILD_TIMEOUT; @@ -48,14 +49,28 @@ namespace llarp::service std::chrono::milliseconds last_introset_update = 0ms; std::chrono::milliseconds last_keep_alive = 0ms; + void + gen_intro_async_impl( + std::string payload, std::function func = nullptr); + public: OutboundContext(const IntroSet& introSet, Endpoint* parent); - + ~OutboundContext() override; + void + gen_intro_async(std::string payload); + void encrypt_and_send(std::string buf); + /// for exits + void + send_packet_to_remote(std::string buf) override; + + void + send_auth_async(std::function resultHandler); + void Tick(std::chrono::milliseconds now) override; @@ -102,10 +117,6 @@ namespace llarp::service bool ReadyToSend() const; - /// for exits - void - send_packet_to_remote(std::string buf) override; - bool ShouldBuildMore(std::chrono::milliseconds now) const override; @@ -121,9 +132,6 @@ namespace llarp::service bool CheckPathIsDead(path::Path_ptr p, std::chrono::milliseconds dlt); - void - AsyncGenIntro(const llarp_buffer_t& payload, ProtocolType t); - /// issues a lookup to find the current intro set of the remote service void UpdateIntroSet(); diff --git a/llarp/service/protocol.cpp b/llarp/service/protocol.cpp index 772716661..f1f32b4f5 100644 --- a/llarp/service/protocol.cpp +++ b/llarp/service/protocol.cpp @@ -1,10 +1,9 @@ #include "protocol.hpp" +#include "endpoint.hpp" + #include -#include #include #include -#include -#include "endpoint.hpp" #include #include @@ -21,10 +20,10 @@ namespace llarp::service ProtocolMessage::~ProtocolMessage() = default; void - ProtocolMessage::PutBuffer(const llarp_buffer_t& buf) + ProtocolMessage::put_buffer(std::string buf) { - payload.resize(buf.sz); - memcpy(payload.data(), buf.base, buf.sz); + payload.resize(buf.size()); + memcpy(payload.data(), buf.data(), buf.size()); } void @@ -39,26 +38,22 @@ namespace llarp::service ProtocolMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf) { bool read = false; - if (!BEncodeMaybeReadDictInt("a", proto, read, k, buf)) - return false; + // if (!BEncodeMaybeReadDictInt("a", proto, read, k, buf)) + // return false; if (k.startswith("d")) { llarp_buffer_t strbuf; if (!bencode_read_string(buf, &strbuf)) return false; - PutBuffer(strbuf); + put_buffer(strbuf.to_string()); return true; } if (!BEncodeMaybeReadDictEntry("i", introReply, read, k, buf)) return false; - if (!BEncodeMaybeReadDictInt("n", seqno, read, k, buf)) - return false; if (!BEncodeMaybeReadDictEntry("s", sender, read, k, buf)) return false; if (!BEncodeMaybeReadDictEntry("t", tag, read, k, buf)) return false; - if (!BEncodeMaybeReadDictInt("v", version, read, k, buf)) - return false; return read; } @@ -69,7 +64,7 @@ namespace llarp::service try { - btdp.append("a", static_cast(proto)); + // btdp.append("a", static_cast(proto)); if (not payload.empty()) btdp.append( @@ -80,19 +75,16 @@ namespace llarp::service introReply.bt_encode(subdict); } - btdp.append("n", seqno); - { auto subdict = btdp.append_dict("s"); sender.bt_encode(subdict); } btdp.append("t", tag.ToView()); - btdp.append("v", version); } catch (...) { - log::critical(route_cat, "Error: ProtocolMessage failed to bt encode contents!"); + log::critical(logcat, "Error: ProtocolMessage failed to bt encode contents!"); } return std::move(btdp).str(); @@ -105,7 +97,7 @@ namespace llarp::service try { - btdp.append("a", static_cast(proto)); + // btdp.append("a", static_cast(proto)); { auto subdict = btdp.append_dict("s"); @@ -113,11 +105,10 @@ namespace llarp::service } btdp.append("t", tag.ToView()); - btdp.append("v", version); } catch (...) { - log::critical(route_cat, "Error: ProtocolMessage failed to bt encode auth info"); + log::critical(logcat, "Error: ProtocolMessage failed to bt encode auth info"); } auto view = btdp.view(); @@ -128,8 +119,6 @@ namespace llarp::service return data; } - ProtocolFrameMessage::~ProtocolFrameMessage() = default; - std::string ProtocolFrameMessage::bt_encode() const { @@ -144,12 +133,11 @@ namespace llarp::service btdp.append("N", nonce.ToView()); btdp.append("R", flag); btdp.append("T", convo_tag.ToView()); - btdp.append("V", version); btdp.append("Z", sig.ToView()); } catch (...) { - log::critical(route_cat, "Error: ProtocolFrameMessage failed to bt encode contents!"); + log::critical(logcat, "Error: ProtocolFrameMessage failed to bt encode contents!"); } return std::move(btdp).str(); @@ -176,14 +164,10 @@ namespace llarp::service return false; if (!BEncodeMaybeReadDictEntry("N", nonce, read, key, val)) return false; - if (!BEncodeMaybeReadDictInt("S", sequence_number, read, key, val)) - return false; if (!BEncodeMaybeReadDictInt("R", flag, read, key, val)) return false; if (!BEncodeMaybeReadDictEntry("T", convo_tag, read, key, val)) return false; - if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, key, val)) - return false; if (!BEncodeMaybeReadDictEntry("Z", sig, read, key, val)) return false; return read; @@ -320,7 +304,9 @@ namespace llarp::service // PKE (A, B, N) SharedSecret shared_secret; - path_dh_func dh_server = util::memFn(&Crypto::dh_server, CryptoManager::instance()); + path_dh_func dh_server = [crypto = CryptoManager::instance()](auto&& params...) -> bool { + return crypto->dh_server(std::forward(params)); + }; if (!self->m_LocalIdentity.KeyExchange( dh_server, shared_secret, self->msg->sender, self->frame.nonce)) @@ -345,8 +331,8 @@ namespace llarp::service self->handler->AsyncProcessAuthMessage( msg, [path, msg, from, handler = self->handler, fromIntro = self->fromIntro, shared_key]( - AuthResult result) { - if (result.code == AuthResultCode::eAuthAccepted) + std::string result, bool success) { + if (success) { if (handler->WantsOutboundSession(msg->sender.Addr())) { @@ -358,34 +344,22 @@ namespace llarp::service } handler->PutReplyIntroFor(msg->tag, msg->introReply); handler->PutCachedSessionKeyFor(msg->tag, shared_key); - handler->SendAuthResult(path, from, msg->tag, result); - LogInfo("auth okay for T=", msg->tag, " from ", msg->sender.Addr()); + handler->SendAuthResult(path, from, msg->tag, result, success); + + log::info( + logcat, "Auth accepted for tag {} from sender {}", msg->tag, msg->sender.Addr()); ProtocolMessage::ProcessAsync(path, from, msg); } else { - LogWarn("auth not okay for T=", msg->tag, ": ", result.reason); + log::warning(logcat, "Auth invalid for tag {} (code: {})", msg->tag, result); } + handler->Pump(time_now_ms()); }); } }; - ProtocolFrameMessage& - ProtocolFrameMessage::operator=(const ProtocolFrameMessage& other) - { - cipher = other.cipher; - enc = other.enc; - path_id = other.path_id; - nonce = other.nonce; - sig = other.sig; - convo_tag = other.convo_tag; - flag = other.flag; - sequence_number = other.sequence_number; - version = other.version; - return *this; - } - struct AsyncDecrypt { ServiceInfo si; @@ -478,8 +452,7 @@ namespace llarp::service ProtocolFrameMessage::operator==(const ProtocolFrameMessage& other) const { return cipher == other.cipher && enc == other.enc && nonce == other.nonce && sig == other.sig - && convo_tag == other.convo_tag && sequence_number == other.sequence_number - && version == other.version; + && convo_tag == other.convo_tag; } bool @@ -493,10 +466,9 @@ namespace llarp::service } bool - ProtocolFrameMessage::handle_message( - routing::AbstractRoutingMessageHandler* h, Router* /*r*/) const + ProtocolFrameMessage::handle_message(Router* /*r*/) const { - return h->HandleHiddenServiceFrame(*this); + return true; } } // namespace llarp::service diff --git a/llarp/service/protocol.hpp b/llarp/service/protocol.hpp index e1e2a3483..b7cfd20ba 100644 --- a/llarp/service/protocol.hpp +++ b/llarp/service/protocol.hpp @@ -29,11 +29,6 @@ namespace llarp constexpr std::size_t MAX_PROTOCOL_MESSAGE_SIZE = 2048 * 2; - /* Note: Talk to Tom and Jason about switching the names of ProtocolFrameMessage (carrier - object) and ProtocolMessage (inner object) to something like ProtocolMessageCarrier and - ProtocolMessage? - */ - /// inner message struct ProtocolMessage { @@ -47,8 +42,7 @@ namespace llarp ServiceInfo sender; Endpoint* handler = nullptr; ConvoTag tag; - uint64_t seqno = 0; - uint64_t version = llarp::constants::proto_version; + std::chrono::milliseconds creation_time{time_now_ms()}; /// encode metainfo for lmq endpoint auth std::vector @@ -61,7 +55,7 @@ namespace llarp bt_encode() const; void - PutBuffer(const llarp_buffer_t& payload); + put_buffer(std::string buf); static void ProcessAsync(path::Path_ptr p, PathID_t from, std::shared_ptr self); @@ -69,12 +63,12 @@ namespace llarp bool operator>(const ProtocolMessage& other) const { - return seqno > other.seqno; + return creation_time > other.creation_time; } }; /// outer message - struct ProtocolFrameMessage final : public routing::AbstractRoutingMessage + struct ProtocolFrameMessage { PQCipherBlock cipher; Encrypted<2048> enc; @@ -84,26 +78,14 @@ namespace llarp PathID_t path_id; service::ConvoTag convo_tag; - ProtocolFrameMessage(const ProtocolFrameMessage& other) - : routing::AbstractRoutingMessage(other) - , cipher(other.cipher) - , enc(other.enc) - , flag(other.flag) - , nonce(other.nonce) - , sig(other.sig) - , path_id(other.path_id) - , convo_tag(other.convo_tag) - { - sequence_number = other.sequence_number; - version = other.version; - } + ProtocolFrameMessage(const ProtocolFrameMessage& other) = default; - ProtocolFrameMessage() : routing::AbstractRoutingMessage{} + ProtocolFrameMessage() { clear(); } - ~ProtocolFrameMessage() override; + ~ProtocolFrameMessage() = default; bool operator==(const ProtocolFrameMessage& other) const; @@ -115,7 +97,7 @@ namespace llarp } ProtocolFrameMessage& - operator=(const ProtocolFrameMessage& other); + operator=(const ProtocolFrameMessage& other) = default; bool EncryptAndSign( @@ -136,7 +118,7 @@ namespace llarp DecryptPayloadInto(const SharedSecret& sharedkey, ProtocolMessage& into) const; bool - decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override; + decode_key(const llarp_buffer_t& key, llarp_buffer_t* val); /** Note: this method needs to be re-examined where it is called in the other class methods, like ::Sign(), ::EncryptAndSign(), and ::Verify(). In all 3 of these cases, the subsequent @@ -144,7 +126,7 @@ namespace llarp redesigned llarp_buffer, or some span backport. */ std::string - bt_encode() const override; + bt_encode() const; bool BDecode(llarp_buffer_t* buf) @@ -153,7 +135,7 @@ namespace llarp } void - clear() override + clear() { cipher.Zero(); enc.Clear(); @@ -162,14 +144,13 @@ namespace llarp nonce.Zero(); sig.Zero(); flag = 0; - version = llarp::constants::proto_version; } bool Verify(const ServiceInfo& from) const; bool - handle_message(routing::AbstractRoutingMessageHandler* h, Router* r) const override; + handle_message(Router* r) const; }; } // namespace service } // namespace llarp diff --git a/llarp/service/sendcontext.cpp b/llarp/service/sendcontext.cpp index 6f7d5586b..ff514c7d2 100644 --- a/llarp/service/sendcontext.cpp +++ b/llarp/service/sendcontext.cpp @@ -110,7 +110,7 @@ namespace llarp::service f->path_id = m->introReply.path_id; m->sender = service_endpoint->GetIdentity().pub; m->tag = f->convo_tag; - m->PutBuffer(payload); + m->put_buffer(payload); service_endpoint->router()->queue_work([f, m, shared, path, this] { if (not f->EncryptAndSign(*m, shared, service_endpoint->GetIdentity())) { diff --git a/llarp/util/buffer.hpp b/llarp/util/buffer.hpp index 81b623a6f..e7caa8e21 100644 --- a/llarp/util/buffer.hpp +++ b/llarp/util/buffer.hpp @@ -182,6 +182,12 @@ struct /* [[deprecated("this type is stupid, use something else")]] */ llarp_buf explicit llarp_buffer_t(T&& t) : llarp_buffer_t{t.data(), t.size()} {} + std::string + to_string() const + { + return {reinterpret_cast(base), sz}; + } + byte_t* begin() {