Outbound context absorbed sendcontex

- message transmission routed through refactored handling
- still work to be done, but now to make it compile at least
pull/2213/head
dr7ana 7 months ago
parent 41312abab0
commit 3ae8fce77d

@ -80,7 +80,7 @@ namespace llarp::exit
return std::vector<RouterContact>{*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

@ -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<llarp::exit::BaseSession> 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(),

@ -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

@ -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;

@ -1648,9 +1648,7 @@ namespace llarp
}
try
{
}
{}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());

@ -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<std::string, void (LinkManager::*)(oxen::quic::message)> 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);

@ -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<RouterContact>
@ -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

@ -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 <llarp/router/router.hpp>

@ -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
}

@ -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;

@ -44,26 +44,26 @@ namespace llarp::rpc
void
EndpointAuthRPC::AuthenticateAsync(
std::shared_ptr<llarp::service::ProtocolMessage> msg,
std::function<void(service::AuthResult)> hook)
std::function<void(std::string, bool)> 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<std::string> 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);

@ -32,7 +32,7 @@ namespace llarp::rpc
void
AuthenticateAsync(
std::shared_ptr<llarp::service::ProtocolMessage> msg,
std::function<void(service::AuthResult)> hook) override;
std::function<void(std::string, bool)> hook) override;
bool
AsyncAuthPending(service::ConvoTag tag) const override;

@ -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); });

@ -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<AsyncKeyExchange> user, std::shared_ptr<ProtocolFrameMessage> frame);

@ -137,7 +137,7 @@ namespace llarp::service
void
AuthenticateAsync(
std::shared_ptr<ProtocolMessage> msg, std::function<void(AuthResult)> hook) override
std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> 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};

@ -57,7 +57,7 @@ namespace llarp::service
/// result later
virtual void
AuthenticateAsync(
std::shared_ptr<ProtocolMessage> msg, std::function<void(AuthResult)> hook) = 0;
std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> hook) = 0;
/// return true if we are asynchronously processing authentication on this convotag
virtual bool

@ -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<ProtocolMessage> msg, std::function<void(AuthResult)> hook)
std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> 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<byte_t> 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<ProtocolMessage> 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;
}

@ -12,7 +12,6 @@
#include <llarp/service/identity.hpp>
#include <llarp/service/pendingbuffer.hpp>
#include <llarp/service/protocol.hpp>
#include <llarp/service/sendcontext.hpp>
#include <llarp/service/protocol_type.hpp>
#include <llarp/service/session.hpp>
#include <llarp/service/endpoint_types.hpp>
@ -422,10 +421,11 @@ namespace llarp
void
AsyncProcessAuthMessage(
std::shared_ptr<ProtocolMessage> msg, std::function<void(AuthResult)> hook);
std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> 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();

@ -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()
{

@ -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)

@ -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<ProtocolFrameMessage>();
frame->clear();
auto ex = std::make_shared<AsyncKeyExchange>(
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<unsigned char*>(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<Introduction> 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<void(std::string, bool)> 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<void(std::string, bool)> 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<ProtocolFrameMessage>();
frame->clear();
auto ex = std::make_shared<AsyncKeyExchange>(
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<ProtocolFrameMessage>();
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<ProtocolMessage>();
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

@ -1,6 +1,7 @@
#pragma once
#include <llarp/path/pathbuilder.hpp>
#include <llarp/service/auth.hpp>
#include <llarp/service/convotag.hpp>
#include <llarp/util/status.hpp>
@ -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<void(std::string, bool)> 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<void(std::string, bool)> 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();

@ -1,10 +1,9 @@
#include "protocol.hpp"
#include "endpoint.hpp"
#include <llarp/path/path.hpp>
#include <llarp/routing/handler.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/meta/memfn.hpp>
#include "endpoint.hpp"
#include <llarp/router/router.hpp>
#include <utility>
@ -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<uint64_t>(proto));
// btdp.append("a", static_cast<uint64_t>(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<uint64_t>(proto));
// btdp.append("a", static_cast<uint64_t>(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<decltype(params)>(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

@ -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<char>
@ -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<ProtocolMessage> 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

@ -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()))
{

@ -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<const char*>(base), sz};
}
byte_t*
begin()
{

Loading…
Cancel
Save