Compilation fixes

- almost all errors have been commented out for refactor or already refactored
- committing this prior to sorting out the cmake structure
- upcoming include-what-you-use application
pull/2213/head
dr7ana 7 months ago
parent 3ae8fce77d
commit 0e451db77f

@ -206,7 +206,6 @@ add_library(lokinet-service-deprecated-kitchensink
endpoint_base.cpp
exit/context.cpp
exit/endpoint.cpp
exit/exit_messages.cpp
exit/policy.cpp
exit/session.cpp
handlers/exit.cpp
@ -228,24 +227,10 @@ add_library(lokinet-service-deprecated-kitchensink
service/name.cpp
service/outbound_context.cpp
service/protocol.cpp
service/sendcontext.cpp
service/session.cpp
service/tag.cpp
)
# interal tooling for pybind
add_library(lokinet-tooling INTERFACE)
if(WITH_HIVE)
add_library(lokinet-hive-tooling
STATIC
tooling/router_hive.cpp
tooling/hive_router.cpp
tooling/hive_context.cpp
)
target_link_libraries(lokinet-tooling INTERFACE lokinet-hive-tooling)
endif()
# interface library for setting commone includes, linkage and flags.
add_library(lokinet-base INTERFACE)
target_include_directories(lokinet-base
@ -264,7 +249,8 @@ add_library(lokinet-amalgum INTERFACE)
# helper function to link a library to lokinet-base, enable lto, add to lokinet-amalgum and then link to other libs
function(lokinet_link_lib libname)
message(DEBUG "created target: ${libname}")
# Absolutely fuck this line, it doesn't "create" the target, as the target already exists
# message(DEBUG "created target: ${libname}")
enable_lto(${libname})
target_link_libraries(${libname} PUBLIC lokinet-base ${ARGN})
target_link_libraries(lokinet-amalgum INTERFACE ${libname})
@ -275,11 +261,7 @@ lokinet_link_lib(lokinet-util lokinet-libntrup)
lokinet_link_lib(lokinet-cryptography lokinet-libcrypt lokinet-util)
lokinet_link_lib(lokinet-peerstats lokinet-context)
lokinet_link_lib(lokinet-consensus lokinet-context)
lokinet_link_lib(lokinet-layer-link lokinet-peerstats)
if(TARGET lokinet-hive-tooling)
lokinet_link_lib(lokinet-hive-tooling lokinet-context)
endif()
lokinet_link_lib(lokinet-layer-link lokinet-cryptography lokinet-peerstats)
if(TARGET lokinet-dns-systemd)
lokinet_link_lib(lokinet-dns-systemd

@ -1,22 +1,21 @@
#include <llarp.hpp>
#include "constants/version.hpp"
#include "constants/evloop.hpp"
#include "config/config.hpp"
#include "crypto/crypto.hpp"
#include "ev/ev.hpp"
#include <memory>
#include "nodedb.hpp"
#include "router/router.hpp"
#include "service/context.hpp"
#include "util/logging.hpp"
#include <llarp.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/constants/evloop.hpp>
#include <llarp/config/config.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/ev/ev.hpp>
#include <llarp/router/router.hpp>
#include <llarp/service/context.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/service_manager.hpp>
#include <CLI/App.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/Config.hpp>
#include <memory>
#include <csignal>
#include <stdexcept>
@ -89,7 +88,9 @@ namespace llarp
Context::makeNodeDB()
{
return std::make_shared<NodeDB>(
nodedb_dirname, [r = router.get()](auto call) { r->queue_disk_io(std::move(call)); });
nodedb_dirname,
[r = router.get()](auto call) { r->queue_disk_io(std::move(call)); },
router.get());
}
std::shared_ptr<Router>

@ -1,22 +1,15 @@
#include "context.hpp"
#include "explorenetworkjob.hpp"
#include "localrouterlookup.hpp"
#include "localserviceaddresslookup.hpp"
#include "localtaglookup.hpp"
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/dht/messages/pubintro.hpp>
#include "node.hpp"
#include "publishservicejob.hpp"
#include "recursiverouterlookup.hpp"
#include "serviceaddresslookup.hpp"
#include "taglookup.hpp"
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/rc_lookup_handler.hpp>

@ -1,42 +1,41 @@
#include "context.hpp"
#include "dht.h"
#include <llarp/router_contact.hpp>
llarp_dht_context::llarp_dht_context(llarp::Router* router)
{
parent = router;
impl = llarp::dht::make_handler();
}
// llarp_dht_context::llarp_dht_context(llarp::Router* router)
// {
// parent = router;
// impl = llarp::dht::make_handler();
// }
struct llarp_dht_context*
llarp_dht_context_new(llarp::Router* router)
{
return new llarp_dht_context(router);
}
// struct llarp_dht_context*
// llarp_dht_context_new(llarp::Router* router)
// {
// return new llarp_dht_context(router);
// }
void
llarp_dht_context_free(struct llarp_dht_context* ctx)
{
delete ctx;
}
// void
// llarp_dht_context_free(struct llarp_dht_context* ctx)
// {
// delete ctx;
// }
void
__llarp_dht_remove_peer(struct llarp_dht_context* ctx, const byte_t* id)
{
ctx->impl->Nodes()->DelNode(llarp::dht::Key_t(id));
}
// void
// __llarp_dht_remove_peer(struct llarp_dht_context* ctx, const byte_t* id)
// {
// ctx->impl->Nodes()->DelNode(llarp::dht::Key_t(id));
// }
void
llarp_dht_allow_transit(llarp_dht_context* ctx)
{
ctx->impl->AllowTransit() = true;
}
// void
// llarp_dht_allow_transit(llarp_dht_context* ctx)
// {
// ctx->impl->AllowTransit() = true;
// }
void
llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key)
{
ctx->impl->Init(llarp::dht::Key_t(key), ctx->parent);
}
// void
// llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key)
// {
// ctx->impl->Init(llarp::dht::Key_t(key), ctx->parent);
// }
void
llarp_dht_lookup_router(struct llarp_dht_context* ctx, struct llarp_router_lookup_job* job)

@ -1,38 +0,0 @@
#include "explorenetworkjob.hpp"
#include <llarp/router/router.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/tooling/dht_event.hpp>
namespace llarp::dht
{
void
ExploreNetworkJob::Start(const TXOwner& peer)
{
auto msg = new FindRouterMessage(peer.txid);
auto router = parent->GetRouter();
if (router)
{
router->notify_router_event<tooling::FindRouterSentEvent>(router->pubkey(), *msg);
}
parent->DHTSendTo(peer.node.as_array(), msg);
}
void
ExploreNetworkJob::SendReply()
{
llarp::LogDebug("got ", valuesFound.size(), " routers from exploration");
auto router = parent->GetRouter();
for (const auto& pk : valuesFound)
{
// lookup router
if (router and router->node_db()->Has(pk))
continue;
parent->LookupRouter(
pk, [router, pk](const auto& res) { router->HandleDHTLookupForExplore(pk, res); });
}
}
} // namespace llarp::dht

@ -1,30 +0,0 @@
#ifndef LLARP_DHT_EXPLORENETWORKJOB
#define LLARP_DHT_EXPLORENETWORKJOB
#include "tx.hpp"
#include <llarp/router_id.hpp>
namespace llarp::dht
{
struct ExploreNetworkJob : public TX<RouterID, RouterID>
{
ExploreNetworkJob(const RouterID& peer, AbstractDHTMessageHandler* ctx)
: TX<RouterID, RouterID>(TXOwner{}, peer, ctx)
{}
bool
Validate(const RouterID&) const override
{
// TODO: check with lokid
return true;
}
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,61 +0,0 @@
#include "localrouterlookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/util/logging.hpp>
namespace llarp::dht
{
LocalRouterLookup::LocalRouterLookup(
const PathID_t& path, uint64_t txid, const RouterID& _target, AbstractDHTMessageHandler* ctx)
: RecursiveRouterLookup(TXOwner{ctx->OurKey(), txid}, _target, ctx, nullptr), localPath(path)
{}
void
LocalRouterLookup::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
if (valuesFound.size())
{
RouterContact found;
for (const auto& rc : valuesFound)
{
if (rc.OtherIsNewer(found))
found = rc;
}
valuesFound.clear();
if (not found.pubkey.IsZero())
{
valuesFound.resize(1);
valuesFound[0] = found;
}
else
{
llarp::LogWarn("We found a null RC for dht request, dropping it");
}
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(
new GotRouterMessage(parent->OurKey(), whoasked.txid, valuesFound, true));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,27 +0,0 @@
#ifndef LLARP_DHT_LOCALROUTERLOOKUP
#define LLARP_DHT_LOCALROUTERLOOKUP
#include "recursiverouterlookup.hpp"
#include <llarp/path/path_types.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/router_id.hpp>
namespace llarp::dht
{
struct LocalRouterLookup : public RecursiveRouterLookup
{
PathID_t localPath;
LocalRouterLookup(
const PathID_t& path,
uint64_t txid,
const RouterID& target,
AbstractDHTMessageHandler* ctx);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,58 +0,0 @@
#include "localserviceaddresslookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/util/logging.hpp>
namespace llarp::dht
{
LocalServiceAddressLookup::LocalServiceAddressLookup(
const PathID_t& pathid,
uint64_t txid,
uint64_t relayOrder,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
[[maybe_unused]] const Key_t& askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, relayOrder, nullptr)
, localPath(pathid)
{}
void
LocalServiceAddressLookup::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
// pick newest if we have more than 1 result
if (valuesFound.size())
{
service::EncryptedIntroSet found;
for (const auto& introset : valuesFound)
{
if (found.OtherIsNewer(introset))
found = introset;
}
valuesFound.clear();
valuesFound.emplace_back(found);
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,28 +0,0 @@
#ifndef LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
#define LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
#include "serviceaddresslookup.hpp"
#include <llarp/path/path_types.hpp>
namespace llarp::dht
{
struct LocalServiceAddressLookup : public ServiceAddressLookup
{
PathID_t localPath;
LocalServiceAddressLookup(
const PathID_t& pathid,
uint64_t txid,
uint64_t relayOrder,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
[[maybe_unused]] const Key_t& askpeer);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,42 +0,0 @@
#include "localtaglookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
namespace llarp::dht
{
LocalTagLookup::LocalTagLookup(
const PathID_t& path,
uint64_t txid,
const service::Tag& _target,
AbstractDHTMessageHandler* ctx)
: TagLookup(TXOwner{ctx->OurKey(), txid}, _target, ctx, 0), localPath(path)
{}
void
LocalTagLookup::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,23 +0,0 @@
#ifndef LLARP_DHT_LOOKUPTAGLOOKUP
#define LLARP_DHT_LOOKUPTAGLOOKUP
#include "taglookup.hpp"
namespace llarp::dht
{
struct LocalTagLookup : public TagLookup
{
PathID_t localPath;
LocalTagLookup(
const PathID_t& path,
uint64_t txid,
const service::Tag& target,
AbstractDHTMessageHandler* ctx);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,138 +0,0 @@
#include "context.hpp"
#include "oxenc/bt_serialize.h"
#include <memory>
#include <llarp/util/bencode.hpp>
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/dht/messages/pubintro.hpp>
#include <llarp/dht/messages/findname.hpp>
#include <llarp/dht/messages/gotname.hpp>
namespace llarp::dht
{
struct MessageDecoder
{
const Key_t& From;
std::unique_ptr<AbstractDHTMessage> msg;
bool firstKey = true;
bool relayed = false;
MessageDecoder(const Key_t& from, bool wasRelayed) : From(from), relayed(wasRelayed)
{}
bool
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
llarp_buffer_t strbuf;
// check for empty dict
if (!key)
return !firstKey;
// first key
if (firstKey)
{
if (!(key->startswith("A")))
return false;
if (!bencode_read_string(buffer, &strbuf))
return false;
// bad msg size?
if (strbuf.sz != 1)
return false;
llarp::LogDebug("Handle DHT message ", *strbuf.base, " relayed=", relayed);
switch (*strbuf.base)
{
case 'N':
msg = std::make_unique<FindNameMessage>(From, Key_t{}, 0);
break;
case 'M':
msg = std::make_unique<GotNameMessage>(From, 0, service::EncryptedName{});
break;
case 'F':
msg = std::make_unique<FindIntroMessage>(From, relayed, 0);
break;
case 'R':
if (relayed)
msg = std::make_unique<RelayedFindRouterMessage>(From);
else
msg = std::make_unique<FindRouterMessage>(From);
break;
case 'S':
msg = std::make_unique<GotRouterMessage>(From, relayed);
break;
case 'I':
msg = std::make_unique<PublishIntroMessage>(From, relayed);
break;
case 'G':
if (relayed)
{
msg = std::make_unique<RelayedGotIntroMessage>();
break;
}
else
{
msg = std::make_unique<GotIntroMessage>(From);
break;
}
default:
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
// bad msg type
return false;
}
firstKey = false;
return msg != nullptr;
}
return msg->decode_key(*key, buffer);
}
};
std::unique_ptr<AbstractDHTMessage>
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed)
{
MessageDecoder dec(from, relayed);
if (!bencode_read_dict(dec, buf))
return nullptr;
return std::move(dec.msg);
}
struct ListDecoder
{
ListDecoder(
bool hasRelayed, const Key_t& from, std::vector<std::unique_ptr<AbstractDHTMessage>>& list)
: relayed(hasRelayed), From(from), l(list)
{}
bool relayed;
const Key_t& From;
std::vector<std::unique_ptr<AbstractDHTMessage>>& l;
bool
operator()(llarp_buffer_t* buffer, bool has)
{
if (!has)
return true;
auto msg = DecodeMessage(From, buffer, relayed);
if (msg)
{
l.emplace_back(std::move(msg));
return true;
}
return false;
}
};
bool
DecodeMessageList(
Key_t from,
llarp_buffer_t* buf,
std::vector<std::unique_ptr<AbstractDHTMessage>>& list,
bool relayed)
{
ListDecoder dec(relayed, from, list);
return bencode_read_list(dec, buf);
}
} // namespace llarp::dht

@ -1,81 +0,0 @@
#include "publishservicejob.hpp"
#include "context.hpp"
#include <llarp/dht/messages/pubintro.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/router/router.hpp>
#include <utility>
namespace llarp::dht
{
PublishServiceJob::PublishServiceJob(
const TXOwner& asker,
const service::EncryptedIntroSet& introset_,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder_)
: TX<TXOwner, service::EncryptedIntroSet>(asker, asker, ctx)
, relayOrder(relayOrder_)
, introset(introset_)
{}
bool
PublishServiceJob::Validate(const service::EncryptedIntroSet& value) const
{
if (value.derivedSigningKey != introset.derivedSigningKey)
{
llarp::LogWarn("publish introset acknowledgement acked a different service");
return false;
}
const llarp_time_t now = llarp::time_now_ms();
return value.verify(now);
}
void
PublishServiceJob::Start(const TXOwner& peer)
{
parent->DHTSendTo(
peer.node.as_array(), new PublishIntroMessage(introset, peer.txid, false, relayOrder));
}
void
PublishServiceJob::SendReply()
{
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage({introset}, whoasked.txid));
}
LocalPublishServiceJob::LocalPublishServiceJob(
const TXOwner& peer,
const PathID_t& fromID,
uint64_t _txid,
const service::EncryptedIntroSet& introset,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder)
: PublishServiceJob(peer, introset, ctx, relayOrder), localPath(fromID), txid(_txid)
{}
void
LocalPublishServiceJob::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(new GotIntroMessage({introset}, txid));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,51 +0,0 @@
#ifndef LLARP_DHT_PUBLISHSERVICEJOB
#define LLARP_DHT_PUBLISHSERVICEJOB
#include "tx.hpp"
#include "txowner.hpp"
#include <llarp/service/address.hpp>
#include <llarp/service/intro_set.hpp>
#include <set>
namespace llarp::dht
{
struct PublishServiceJob : public TX<TXOwner, service::EncryptedIntroSet>
{
uint64_t relayOrder;
service::EncryptedIntroSet introset;
PublishServiceJob(
const TXOwner& asker,
const service::EncryptedIntroSet& introset,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder);
bool
Validate(const service::EncryptedIntroSet& introset) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
struct LocalPublishServiceJob : public PublishServiceJob
{
PathID_t localPath;
uint64_t txid;
LocalPublishServiceJob(
const TXOwner& peer,
const PathID_t& fromID,
uint64_t txid,
const service::EncryptedIntroSet& introset,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,71 +0,0 @@
#include "recursiverouterlookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/router/router.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <utility>
namespace llarp
{
namespace dht
{
RecursiveRouterLookup::RecursiveRouterLookup(
const TXOwner& _whoasked,
const RouterID& _target,
AbstractDHTMessageHandler* ctx,
RouterLookupHandler result)
: TX<RouterID, RouterContact>(_whoasked, _target, ctx), resultHandler(std::move(result))
{
peersAsked.insert(ctx->OurKey());
}
bool
RecursiveRouterLookup::Validate(const RouterContact& rc) const
{
if (!rc.Verify(parent->Now()))
{
llarp::LogWarn("rc from lookup result is invalid");
return false;
}
return true;
}
void
RecursiveRouterLookup::Start(const TXOwner& peer)
{
parent->DHTSendTo(peer.node.as_array(), new FindRouterMessage(peer.txid, target));
}
void
RecursiveRouterLookup::SendReply()
{
if (valuesFound.size())
{
RouterContact found;
for (const auto& rc : valuesFound)
{
if (found.OtherIsNewer(rc) && parent->GetRouter()->rc_lookup_handler().check_rc(rc))
found = rc;
}
valuesFound.clear();
valuesFound.emplace_back(found);
}
if (resultHandler)
{
resultHandler(valuesFound);
}
if (whoasked.node != parent->OurKey())
{
parent->DHTSendTo(
whoasked.node.as_array(),
new GotRouterMessage({}, whoasked.txid, valuesFound, false),
false);
}
}
} // namespace dht
} // namespace llarp

@ -1,34 +0,0 @@
#ifndef LLARP_DHT_RECURSIVEROUTERLOOKUP
#define LLARP_DHT_RECURSIVEROUTERLOOKUP
#include "tx.hpp"
#include <llarp/router_contact.hpp>
#include <llarp/router_id.hpp>
namespace llarp
{
namespace dht
{
struct RecursiveRouterLookup : public TX<RouterID, RouterContact>
{
RouterLookupHandler resultHandler;
RecursiveRouterLookup(
const TXOwner& whoasked,
const RouterID& target,
AbstractDHTMessageHandler* ctx,
RouterLookupHandler result);
bool
Validate(const RouterContact& rc) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -1,70 +0,0 @@
#include "serviceaddresslookup.hpp"
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <utility>
namespace llarp
{
namespace dht
{
ServiceAddressLookup::ServiceAddressLookup(
const TXOwner& asker,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
uint32_t order,
service::EncryptedIntroSetLookupHandler handler)
: TX<TXOwner, service::EncryptedIntroSet>(asker, asker, ctx)
, location(addr)
, handleResult(std::move(handler))
, relayOrder(order)
{
peersAsked.insert(ctx->OurKey());
}
bool
ServiceAddressLookup::Validate(const service::EncryptedIntroSet& value) const
{
if (!value.verify(parent->Now()))
{
llarp::LogWarn("Got invalid introset from service lookup");
return false;
}
if (value.derivedSigningKey != location)
{
llarp::LogWarn("got introset with wrong target from service lookup");
return false;
}
return true;
}
void
ServiceAddressLookup::Start(const TXOwner& peer)
{
parent->DHTSendTo(
peer.node.as_array(), new FindIntroMessage(peer.txid, location, relayOrder));
}
void
ServiceAddressLookup::SendReply()
{
// get newest introset
if (valuesFound.size())
{
llarp::service::EncryptedIntroSet found;
for (const auto& introset : valuesFound)
{
if (found.OtherIsNewer(introset))
found = introset;
}
valuesFound.clear();
valuesFound.emplace_back(found);
}
if (handleResult)
{
handleResult(valuesFound);
}
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage(valuesFound, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -1,41 +0,0 @@
#ifndef LLARP_DHT_SERVICEADDRESSLOOKUP
#define LLARP_DHT_SERVICEADDRESSLOOKUP
#include "key.hpp"
#include "tx.hpp"
#include <llarp/service/address.hpp>
#include <llarp/service/intro_set.hpp>
namespace llarp
{
namespace dht
{
struct TXOwner;
struct ServiceAddressLookup : public TX<TXOwner, service::EncryptedIntroSet>
{
Key_t location;
service::EncryptedIntroSetLookupHandler handleResult;
uint32_t relayOrder;
ServiceAddressLookup(
const TXOwner& asker,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
uint32_t relayOrder,
service::EncryptedIntroSetLookupHandler handler);
bool
Validate(const service::EncryptedIntroSet& value) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -1,40 +0,0 @@
#include "taglookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotintro.hpp>
namespace llarp
{
namespace dht
{
bool
TagLookup::Validate(const service::EncryptedIntroSet& introset) const
{
if (!introset.verify(parent->Now()))
{
llarp::LogWarn("got invalid introset from tag lookup");
return false;
}
if (not introset.topic)
return false;
if (*introset.topic != target)
{
llarp::LogWarn("got introset with mismatched topic in tag lookup");
return false;
}
return true;
}
void
TagLookup::Start(const TXOwner& peer)
{
parent->DHTSendTo(peer.node.as_array(), new FindIntroMessage(target, peer.txid));
}
void
TagLookup::SendReply()
{
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage({}, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -1,35 +0,0 @@
#ifndef LLARP_DHT_TAGLOOKUP
#define LLARP_DHT_TAGLOOKUP
#include "tx.hpp"
#include <llarp/service/intro_set.hpp>
#include <llarp/service/tag.hpp>
namespace llarp
{
namespace dht
{
struct TagLookup : public TX<service::Tag, service::EncryptedIntroSet>
{
uint64_t recursionDepth;
TagLookup(
const TXOwner& asker,
const service::Tag& tag,
AbstractDHTMessageHandler* ctx,
uint64_t recursion)
: TX<service::Tag, service::EncryptedIntroSet>(asker, tag, ctx), recursionDepth(recursion)
{}
bool
Validate(const service::EncryptedIntroSet& introset) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -3,77 +3,77 @@
#include "key.hpp"
#include "txowner.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/status.hpp>
#include <set>
#include <vector>
namespace llarp::dht
namespace llarp
{
struct AbstractDHTMessageHandler;
struct Router;
template <typename K, typename V>
struct TX
namespace dht
{
K target;
AbstractDHTMessageHandler* parent;
std::set<Key_t> peersAsked;
std::vector<V> valuesFound;
TXOwner whoasked;
TX(const TXOwner& asker, const K& k, AbstractDHTMessageHandler* p)
: target(k), parent(p), whoasked(asker)
{}
template <typename K, typename V>
struct TX
{
K target;
Router* router;
std::set<Key_t> peersAsked;
std::vector<V> valuesFound;
TXOwner whoasked;
virtual ~TX() = default;
TX(const TXOwner& asker, const K& k, Router* r) : target(k), router{r}, whoasked(asker)
{}
void
OnFound(const Key_t& askedPeer, const V& value);
virtual ~TX() = default;
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{
{"whoasked", whoasked.ExtractStatus()}, {"target", target.ExtractStatus()}};
std::vector<util::StatusObject> foundObjs;
std::transform(
valuesFound.begin(),
valuesFound.end(),
std::back_inserter(foundObjs),
[](const auto& item) -> util::StatusObject { return item.ExtractStatus(); });
void
OnFound(const Key_t& askedPeer, const V& value);
obj["found"] = foundObjs;
std::vector<std::string> asked;
std::transform(
peersAsked.begin(),
peersAsked.end(),
std::back_inserter(asked),
[](const auto& item) -> std::string { return item.ToString(); });
obj["asked"] = asked;
return obj;
}
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{
{"whoasked", whoasked.ExtractStatus()}, {"target", target.ExtractStatus()}};
std::vector<util::StatusObject> foundObjs;
std::transform(
valuesFound.begin(),
valuesFound.end(),
std::back_inserter(foundObjs),
[](const auto& item) -> util::StatusObject { return item.ExtractStatus(); });
virtual bool
Validate(const V& value) const = 0;
obj["found"] = foundObjs;
std::vector<std::string> asked;
std::transform(
peersAsked.begin(),
peersAsked.end(),
std::back_inserter(asked),
[](const auto& item) -> std::string { return item.ToString(); });
obj["asked"] = asked;
return obj;
}
virtual void
Start(const TXOwner& peer) = 0;
virtual bool
Validate(const V& value) const = 0;
virtual void
SendReply() = 0;
};
virtual void
Start(const TXOwner& peer) = 0;
};
template <typename K, typename V>
inline void
TX<K, V>::OnFound(const Key_t& askedPeer, const V& value)
{
peersAsked.insert(askedPeer);
if (Validate(value))
template <typename K, typename V>
inline void
TX<K, V>::OnFound(const Key_t& askedPeer, const V& value)
{
valuesFound.push_back(value);
peersAsked.insert(askedPeer);
if (Validate(value))
{
valuesFound.push_back(value);
}
}
}
} // namespace llarp::dht
} // namespace dht
} // namespace llarp
#endif

@ -9,208 +9,204 @@
#include <memory>
#include <unordered_map>
namespace llarp
namespace llarp::dht
{
namespace dht
template <typename K, typename V>
struct TXHolder
{
template <typename K, typename V>
struct TXHolder
{
using TXPtr = std::unique_ptr<TX<K, V>>;
// tx who are waiting for a reply for each key
std::unordered_multimap<K, TXOwner> waiting;
// tx timesouts by key
std::unordered_map<K, llarp_time_t> timeouts;
// maps remote peer with tx to handle reply from them
std::unordered_map<TXOwner, TXPtr> tx;
const TX<K, V>*
GetPendingLookupFrom(const TXOwner& owner) const;
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{};
std::vector<util::StatusObject> txObjs, timeoutsObjs, waitingObjs;
std::transform(
tx.begin(),
tx.end(),
std::back_inserter(txObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"owner", item.first.ExtractStatus()}, {"tx", item.second->ExtractStatus()}};
});
obj["tx"] = txObjs;
std::transform(
timeouts.begin(),
timeouts.end(),
std::back_inserter(timeoutsObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"time", to_json(item.second)}, {"target", item.first.ExtractStatus()}};
});
obj["timeouts"] = timeoutsObjs;
std::transform(
waiting.begin(),
waiting.end(),
std::back_inserter(waitingObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"target", item.first.ExtractStatus()},
{"whoasked", item.second.ExtractStatus()}};
});
obj["waiting"] = waitingObjs;
return obj;
}
bool
HasLookupFor(const K& target) const
{
return timeouts.find(target) != timeouts.end();
}
bool
HasPendingLookupFrom(const TXOwner& owner) const
{
return GetPendingLookupFrom(owner) != nullptr;
}
using TXPtr = std::unique_ptr<TX<K, V>>;
// tx who are waiting for a reply for each key
std::unordered_multimap<K, TXOwner> waiting;
// tx timesouts by key
std::unordered_map<K, llarp_time_t> timeouts;
// maps remote peer with tx to handle reply from them
std::unordered_map<TXOwner, TXPtr> tx;
void
NewTX(
const TXOwner& askpeer,
const TXOwner& whoasked,
const K& k,
TX<K, V>* t,
llarp_time_t requestTimeoutMS = 15s);
/// mark tx as not fond
void
NotFound(const TXOwner& from, const std::unique_ptr<Key_t>& next);
void
Found(const TXOwner& from, const K& k, const std::vector<V>& values)
{
Inform(from, k, values, true);
}
/// inform all watches for key of values found
void
Inform(
TXOwner from,
K key,
std::vector<V> values,
bool sendreply = false,
bool removeTimeouts = true);
const TX<K, V>*
GetPendingLookupFrom(const TXOwner& owner) const;
void
Expire(llarp_time_t now);
};
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{};
std::vector<util::StatusObject> txObjs, timeoutsObjs, waitingObjs;
std::transform(
tx.begin(),
tx.end(),
std::back_inserter(txObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"owner", item.first.ExtractStatus()}, {"tx", item.second->ExtractStatus()}};
});
obj["tx"] = txObjs;
std::transform(
timeouts.begin(),
timeouts.end(),
std::back_inserter(timeoutsObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"time", to_json(item.second)}, {"target", item.first.ExtractStatus()}};
});
obj["timeouts"] = timeoutsObjs;
std::transform(
waiting.begin(),
waiting.end(),
std::back_inserter(waitingObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"target", item.first.ExtractStatus()}, {"whoasked", item.second.ExtractStatus()}};
});
obj["waiting"] = waitingObjs;
return obj;
}
template <typename K, typename V>
const TX<K, V>*
TXHolder<K, V>::GetPendingLookupFrom(const TXOwner& owner) const
bool
HasLookupFor(const K& target) const
{
auto itr = tx.find(owner);
if (itr == tx.end())
{
return nullptr;
}
return timeouts.find(target) != timeouts.end();
}
return itr->second.get();
bool
HasPendingLookupFrom(const TXOwner& owner) const
{
return GetPendingLookupFrom(owner) != nullptr;
}
template <typename K, typename V>
void
TXHolder<K, V>::NewTX(
NewTX(
const TXOwner& askpeer,
const TXOwner& whoasked,
const K& k,
TX<K, V>* t,
llarp_time_t requestTimeoutMS)
{
(void)whoasked;
tx.emplace(askpeer, std::unique_ptr<TX<K, V>>(t));
auto count = waiting.count(k);
waiting.emplace(k, askpeer);
llarp_time_t requestTimeoutMS = 15s);
auto itr = timeouts.find(k);
if (itr == timeouts.end())
{
timeouts.emplace(k, time_now_ms() + requestTimeoutMS);
}
if (count == 0)
{
t->Start(askpeer);
}
}
/// mark tx as not fond
void
NotFound(const TXOwner& from, const std::unique_ptr<Key_t>& next);
template <typename K, typename V>
void
TXHolder<K, V>::NotFound(const TXOwner& from, const std::unique_ptr<Key_t>&)
Found(const TXOwner& from, const K& k, const std::vector<V>& values)
{
auto txitr = tx.find(from);
if (txitr == tx.end())
{
return;
}
Inform(from, txitr->second->target, {}, true, true);
Inform(from, k, values, true);
}
template <typename K, typename V>
/// inform all watches for key of values found
void
TXHolder<K, V>::Inform(
TXOwner from, K key, std::vector<V> values, bool sendreply, bool removeTimeouts)
Inform(
TXOwner from,
K key,
std::vector<V> values,
bool sendreply = false,
bool removeTimeouts = true);
void
Expire(llarp_time_t now);
};
template <typename K, typename V>
const TX<K, V>*
TXHolder<K, V>::GetPendingLookupFrom(const TXOwner& owner) const
{
auto itr = tx.find(owner);
if (itr == tx.end())
{
auto range = waiting.equal_range(key);
auto itr = range.first;
while (itr != range.second)
{
auto txitr = tx.find(itr->second);
if (txitr != tx.end())
{
for (const auto& value : values)
{
txitr->second->OnFound(from.node, value);
}
if (sendreply)
{
txitr->second->SendReply();
tx.erase(txitr);
}
}
++itr;
}
return nullptr;
}
if (sendreply)
{
waiting.erase(key);
}
return itr->second.get();
}
template <typename K, typename V>
void
TXHolder<K, V>::NewTX(
const TXOwner& askpeer,
const TXOwner& whoasked,
const K& k,
TX<K, V>* t,
llarp_time_t requestTimeoutMS)
{
(void)whoasked;
tx.emplace(askpeer, std::unique_ptr<TX<K, V>>(t));
auto count = waiting.count(k);
waiting.emplace(k, askpeer);
if (removeTimeouts)
{
timeouts.erase(key);
}
auto itr = timeouts.find(k);
if (itr == timeouts.end())
{
timeouts.emplace(k, time_now_ms() + requestTimeoutMS);
}
if (count == 0)
{
t->Start(askpeer);
}
}
template <typename K, typename V>
void
TXHolder<K, V>::Expire(llarp_time_t now)
template <typename K, typename V>
void
TXHolder<K, V>::NotFound(const TXOwner& from, const std::unique_ptr<Key_t>&)
{
auto txitr = tx.find(from);
if (txitr == tx.end())
{
auto itr = timeouts.begin();
while (itr != timeouts.end())
return;
}
Inform(from, txitr->second->target, {}, true, true);
}
template <typename K, typename V>
void
TXHolder<K, V>::Inform(
TXOwner from, K key, std::vector<V> values, bool sendreply, bool removeTimeouts)
{
auto range = waiting.equal_range(key);
auto itr = range.first;
while (itr != range.second)
{
auto txitr = tx.find(itr->second);
if (txitr != tx.end())
{
if (now >= itr->second)
for (const auto& value : values)
{
Inform(TXOwner{}, itr->first, {}, true, false);
itr = timeouts.erase(itr);
txitr->second->OnFound(from.node, value);
}
else
if (sendreply)
{
++itr;
txitr->second->SendReply();
tx.erase(txitr);
}
}
++itr;
}
if (sendreply)
{
waiting.erase(key);
}
if (removeTimeouts)
{
timeouts.erase(key);
}
}
template <typename K, typename V>
void
TXHolder<K, V>::Expire(llarp_time_t now)
{
auto itr = timeouts.begin();
while (itr != timeouts.end())
{
if (now >= itr->second)
{
Inform(TXOwner{}, itr->first, {}, true, false);
itr = timeouts.erase(itr);
}
else
{
++itr;
}
}
} // namespace dht
} // namespace llarp
}
} // namespace llarp::dht
#endif

@ -4,49 +4,46 @@
#include <llarp/util/status.hpp>
#include <cstdint>
namespace llarp
namespace llarp::dht
{
namespace dht
struct TXOwner
{
struct TXOwner
{
Key_t node;
uint64_t txid = 0;
Key_t node;
uint64_t txid = 0;
TXOwner() = default;
TXOwner(const TXOwner&) = default;
TXOwner(TXOwner&&) = default;
TXOwner() = default;
TXOwner(const TXOwner&) = default;
TXOwner(TXOwner&&) = default;
TXOwner&
operator=(const TXOwner&) = default;
TXOwner&
operator=(const TXOwner&) = default;
TXOwner(const Key_t& k, uint64_t id) : node(k), txid(id)
{}
TXOwner(const Key_t& k, uint64_t id) : node(k), txid(id)
{}
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{
{"txid", txid},
{"node", node.ToHex()},
};
return obj;
}
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{
{"txid", txid},
{"node", node.ToHex()},
};
return obj;
}
bool
operator==(const TXOwner& other) const
{
return std::tie(txid, node) == std::tie(other.txid, other.node);
}
bool
operator==(const TXOwner& other) const
{
return std::tie(txid, node) == std::tie(other.txid, other.node);
}
bool
operator<(const TXOwner& other) const
{
return std::tie(txid, node) < std::tie(other.txid, other.node);
}
};
} // namespace dht
} // namespace llarp
bool
operator<(const TXOwner& other) const
{
return std::tie(txid, node) < std::tie(other.txid, other.node);
}
};
} // namespace llarp::dht
namespace std
{

@ -7,6 +7,8 @@
#include "llarp/ev/ev.hpp"
#include "llarp/dns/srv_data.hpp"
#include <llarp/link/tunnel.hpp>
#include <functional>
#include <memory>
#include <string>
@ -19,11 +21,6 @@
namespace llarp
{
namespace quic
{
class TunnelManager;
}
namespace dns
{
class Server;
@ -111,7 +108,7 @@ namespace llarp
virtual AddressVariant_t
LocalAddress() const = 0;
virtual quic::TunnelManager*
virtual link::TunnelManager*
GetQUICTunnel() = 0;
virtual std::optional<AddressVariant_t>

@ -3,7 +3,6 @@
#include <llarp/handlers/exit.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/quic/tunnel.hpp>
namespace llarp::exit
{
@ -14,38 +13,38 @@ namespace llarp::exit
huint128_t ip,
llarp::handlers::ExitEndpoint* parent)
: createdAt{parent->Now()}
, m_Parent{parent}
, m_remoteSignKey{remoteIdent}
, m_CurrentPath{beginPath}
, m_IP{ip}
, m_RewriteSource{rewriteIP}
, parent{parent}
, remote_signkey{remoteIdent}
, current_path{beginPath}
, IP{ip}
, rewrite_source{rewriteIP}
{
m_LastActive = parent->Now();
last_active = parent->Now();
}
Endpoint::~Endpoint()
{
if (m_CurrentPath)
m_Parent->DelEndpointInfo(m_CurrentPath->RXID());
if (current_path)
parent->DelEndpointInfo(current_path->RXID());
}
void
Endpoint::Close()
{
m_Parent->RemoveExit(this);
parent->RemoveExit(this);
}
util::StatusObject
Endpoint::ExtractStatus() const
{
auto now = m_Parent->Now();
auto now = parent->Now();
util::StatusObject obj{
{"identity", m_remoteSignKey.ToString()},
{"ip", m_IP.ToString()},
{"txRate", m_TxRate},
{"rxRate", m_RxRate},
{"identity", remote_signkey.ToString()},
{"ip", IP.ToString()},
{"txRate", tx_rate},
{"rxRate", rx_rate},
{"createdAt", to_json(createdAt)},
{"exiting", !m_RewriteSource},
{"exiting", !rewrite_source},
{"looksDead", LooksDead(now)},
{"expiresSoon", ExpiresSoon(now)},
{"expired", IsExpired(now)}};
@ -55,10 +54,10 @@ namespace llarp::exit
bool
Endpoint::UpdateLocalPath(const llarp::PathID_t& nextPath)
{
if (!m_Parent->UpdateEndpointPath(m_remoteSignKey, nextPath))
if (!parent->UpdateEndpointPath(remote_signkey, nextPath))
return false;
const RouterID us{m_Parent->GetRouter()->pubkey()};
m_CurrentPath = m_Parent->GetRouter()->path_context().GetByUpstream(us, nextPath);
const RouterID us{parent->GetRouter()->pubkey()};
current_path = parent->GetRouter()->path_context().GetByUpstream(us, nextPath);
return true;
}
@ -66,8 +65,8 @@ namespace llarp::exit
Endpoint::Tick(llarp_time_t now)
{
(void)now;
m_RxRate = 0;
m_TxRate = 0;
rx_rate = 0;
tx_rate = 0;
}
bool
@ -85,8 +84,8 @@ namespace llarp::exit
bool
Endpoint::ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const
{
if (m_CurrentPath)
return m_CurrentPath->ExpiresSoon(now, dlt);
if (current_path)
return current_path->ExpiresSoon(now, dlt);
return true;
}
@ -100,138 +99,145 @@ namespace llarp::exit
return true;
auto lastPing = path->LastRemoteActivityAt();
if (lastPing == 0s || (now > lastPing && now - lastPing > timeout))
return now > m_LastActive && now - m_LastActive > timeout;
return now > last_active && now - last_active > timeout;
else if (lastPing > 0s) // NOLINT
return now > lastPing && now - lastPing > timeout;
return lastPing > 0s;
}
bool
Endpoint::QueueOutboundTraffic(
PathID_t path, std::vector<byte_t> buf, uint64_t counter, service::ProtocolType t)
{
const service::ConvoTag tag{path.as_array()};
if (t == service::ProtocolType::QUIC)
/* bool
Endpoint::QueueOutboundTraffic(
PathID_t path, std::vector<byte_t> buf, uint64_t counter, service::ProtocolType t)
{
auto quic = m_Parent->GetQUICTunnel();
if (not quic)
return false;
m_TxRate += buf.size();
quic->receive_packet(tag, std::move(buf));
m_LastActive = m_Parent->Now();
return true;
}
// queue overflow
if (m_UpstreamQueue.size() > MaxUpstreamQueueSize)
return false;
const service::ConvoTag tag{path.as_array()};
llarp::net::IPPacket pkt{std::move(buf)};
if (pkt.empty())
return false;
// current_path->send_path_control_message(std::string method, std::string body,
std::function<void (oxen::quic::message)> func)
if (pkt.IsV6() && m_Parent->SupportsV6())
{
huint128_t dst;
if (m_RewriteSource)
dst = m_Parent->GetIfAddr();
else
dst = pkt.dstv6();
pkt.UpdateIPv6Address(m_IP, dst);
}
else if (pkt.IsV4() && !m_Parent->SupportsV6())
{
huint32_t dst;
if (m_RewriteSource)
dst = net::TruncateV6(m_Parent->GetIfAddr());
else
dst = pkt.dstv4();
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(m_IP)), xhtonl(dst));
}
else
{
return false;
}
m_TxRate += pkt.size();
m_UpstreamQueue.emplace(std::move(pkt), counter);
m_LastActive = m_Parent->Now();
return true;
}
if (t == service::ProtocolType::QUIC)
{
auto quic = parent->GetQUICTunnel();
if (not quic)
return false;
tx_rate += buf.size();
quic->receive_packet(tag, std::move(buf));
last_active = parent->Now();
return true;
}
// queue overflow
if (m_UpstreamQueue.size() > MaxUpstreamQueueSize)
return false;
bool
Endpoint::QueueInboundTraffic(std::vector<byte_t> buf, service::ProtocolType type)
{
if (type != service::ProtocolType::QUIC)
{
llarp::net::IPPacket pkt{std::move(buf)};
if (pkt.empty())
return false;
huint128_t src;
if (m_RewriteSource)
src = m_Parent->GetIfAddr();
else
src = pkt.srcv6();
if (pkt.IsV6())
pkt.UpdateIPv6Address(src, m_IP);
if (pkt.IsV6() && parent->SupportsV6())
{
huint128_t dst;
if (rewrite_source)
dst = parent->GetIfAddr();
else
dst = pkt.dstv6();
pkt.UpdateIPv6Address(IP, dst);
}
else if (pkt.IsV4() && !parent->SupportsV6())
{
huint32_t dst;
if (rewrite_source)
dst = net::TruncateV6(parent->GetIfAddr());
else
dst = pkt.dstv4();
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(IP)), xhtonl(dst));
}
else
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(src)), xhtonl(net::TruncateV6(m_IP)));
buf = pkt.steal();
}
{
return false;
}
tx_rate += pkt.size();
m_UpstreamQueue.emplace(std::move(pkt), counter);
last_active = parent->Now();
return true;
} */
const uint8_t queue_idx = buf.size() / llarp::routing::EXIT_PAD_SIZE;
if (m_DownstreamQueues.find(queue_idx) == m_DownstreamQueues.end())
m_DownstreamQueues.emplace(queue_idx, InboundTrafficQueue_t{});
auto& queue = m_DownstreamQueues.at(queue_idx);
if (queue.size() == 0)
{
queue.emplace_back();
queue.back().protocol = type;
return queue.back().PutBuffer(std::move(buf), m_Counter++);
}
auto& msg = queue.back();
if (msg.Size() + buf.size() > llarp::routing::EXIT_PAD_SIZE)
{
queue.emplace_back();
queue.back().protocol = type;
return queue.back().PutBuffer(std::move(buf), m_Counter++);
}
msg.protocol = type;
return msg.PutBuffer(std::move(buf), m_Counter++);
bool
Endpoint::QueueInboundTraffic(std::vector<byte_t>, service::ProtocolType)
{
// TODO: this will go away with removing flush
// if (type != service::ProtocolType::QUIC)
// {
// llarp::net::IPPacket pkt{std::move(buf)};
// if (pkt.empty())
// return false;
// huint128_t src;
// if (m_RewriteSource)
// src = m_Parent->GetIfAddr();
// else
// src = pkt.srcv6();
// if (pkt.IsV6())
// pkt.UpdateIPv6Address(src, m_IP);
// else
// pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(src)), xhtonl(net::TruncateV6(m_IP)));
// buf = pkt.steal();
// }
// const uint8_t queue_idx = buf.size() / llarp::routing::EXIT_PAD_SIZE;
// if (m_DownstreamQueues.find(queue_idx) == m_DownstreamQueues.end())
// m_DownstreamQueues.emplace(queue_idx, InboundTrafficQueue_t{});
// auto& queue = m_DownstreamQueues.at(queue_idx);
// if (queue.size() == 0)
// {
// queue.emplace_back();
// queue.back().protocol = type;
// return queue.back().PutBuffer(std::move(buf), m_Counter++);
// }
// auto& msg = queue.back();
// if (msg.Size() + buf.size() > llarp::routing::EXIT_PAD_SIZE)
// {
// queue.emplace_back();
// queue.back().protocol = type;
// return queue.back().PutBuffer(std::move(buf), m_Counter++);
// }
// msg.protocol = type;
// return msg.PutBuffer(std::move(buf), m_Counter++);
return true;
}
bool
Endpoint::Flush()
{
// flush upstream queue
while (m_UpstreamQueue.size())
{
m_Parent->QueueOutboundTraffic(const_cast<net::IPPacket&>(m_UpstreamQueue.top().pkt).steal());
m_UpstreamQueue.pop();
}
// while (m_UpstreamQueue.size())
// {
// parent->QueueOutboundTraffic(const_cast<net::IPPacket&>(m_UpstreamQueue.top().pkt).steal());
// m_UpstreamQueue.pop();
// }
// flush downstream queue
auto path = GetCurrentPath();
bool sent = path != nullptr;
if (path)
{
for (auto& item : m_DownstreamQueues)
{
auto& queue = item.second;
while (queue.size())
{
auto& msg = queue.front();
msg.sequence_number = path->NextSeqNo();
if (path->SendRoutingMessage(msg, m_Parent->GetRouter()))
{
m_RxRate += msg.Size();
sent = true;
}
queue.pop_front();
}
}
}
for (auto& item : m_DownstreamQueues)
item.second.clear();
// if (path)
// {
// for (auto& item : m_DownstreamQueues)
// {
// auto& queue = item.second;
// while (queue.size())
// {
// auto& msg = queue.front();
// msg.sequence_number = path->NextSeqNo();
// if (path->SendRoutingMessage(msg, m_Parent->GetRouter()))
// {
// m_RxRate += msg.Size();
// sent = true;
// }
// queue.pop_front();
// }
// }
// }
// for (auto& item : m_DownstreamQueues)
// item.second.clear();
return sent;
}
} // namespace llarp::exit

@ -65,9 +65,9 @@ namespace llarp
/// queue outbound traffic
/// does ip rewrite here
bool
QueueOutboundTraffic(
PathID_t txid, std::vector<byte_t> data, uint64_t counter, service::ProtocolType t);
// bool
// QueueOutboundTraffic(
// PathID_t txid, std::vector<byte_t> data, uint64_t counter, service::ProtocolType t);
/// update local path id and cascade information to parent
/// return true if success
@ -77,66 +77,43 @@ namespace llarp
llarp::path::HopHandler_ptr
GetCurrentPath() const
{
return m_CurrentPath;
return current_path;
}
const llarp::PubKey&
PubKey() const
{
return m_remoteSignKey;
return remote_signkey;
}
uint64_t
TxRate() const
{
return m_TxRate;
return tx_rate;
}
uint64_t
RxRate() const
{
return m_RxRate;
return rx_rate;
}
huint128_t
LocalIP() const
{
return m_IP;
return IP;
}
const llarp_time_t createdAt;
private:
llarp::handlers::ExitEndpoint* m_Parent;
llarp::PubKey m_remoteSignKey;
llarp::path::HopHandler_ptr m_CurrentPath;
llarp::huint128_t m_IP;
uint64_t m_TxRate, m_RxRate;
llarp_time_t m_LastActive;
bool m_RewriteSource;
using InboundTrafficQueue_t = std::deque<llarp::routing::TransferTrafficMessage>;
using TieredQueue = std::map<uint8_t, InboundTrafficQueue_t>;
// maps number of fragments the message will fit in to the queue for it
TieredQueue m_DownstreamQueues;
struct UpstreamBuffer
{
UpstreamBuffer(llarp::net::IPPacket p, uint64_t c) : pkt{std::move(p)}, counter(c)
{}
llarp::net::IPPacket pkt;
uint64_t counter;
bool
operator<(const UpstreamBuffer& other) const
{
return counter < other.counter;
}
};
using UpstreamQueue_t = std::priority_queue<UpstreamBuffer>;
UpstreamQueue_t m_UpstreamQueue;
uint64_t m_Counter;
llarp::handlers::ExitEndpoint* parent;
llarp::PubKey remote_signkey;
llarp::path::HopHandler_ptr current_path;
llarp::huint128_t IP;
uint64_t tx_rate, rx_rate;
llarp_time_t last_active;
bool rewrite_source;
};
} // namespace exit
} // namespace llarp

@ -1,364 +0,0 @@
#include "exit_messages.hpp"
#include <llarp/crypto/crypto.hpp>
#include <llarp/routing/handler.hpp>
namespace llarp::routing
{
bool
ObtainExitMessage::Sign(const llarp::SecretKey& sk)
{
pubkey = seckey_topublic(sk);
sig.Zero();
auto bte = bt_encode();
return CryptoManager::instance()->sign(
sig, sk, reinterpret_cast<uint8_t*>(bte.data()), bte.size());
}
bool
ObtainExitMessage::Verify() const
{
ObtainExitMessage copy;
copy = *this;
copy.sig.Zero();
auto bte = copy.bt_encode();
return CryptoManager::instance()->verify(
pubkey, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
std::string
ObtainExitMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("E", flag);
btdp.append("I", pubkey.ToView());
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("Z", sig.ToView());
}
catch (...)
{
log::critical(route_cat, "Error: ObtainExitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
ObtainExitMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictInt("E", flag, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("I", pubkey, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
return false;
return read;
}
bool
ObtainExitMessage::handle_message(AbstractRoutingMessageHandler* h, Router* r) const
{
return h->HandleObtainExitMessage(*this, r);
}
std::string
GrantExitMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("Y", nonce.ToView());
btdp.append("Z", sig.ToView());
}
catch (...)
{
log::critical(route_cat, "Error: GrantExitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
GrantExitMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Y", nonce, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
return false;
return read;
}
bool
GrantExitMessage::Verify(const llarp::PubKey& pk) const
{
GrantExitMessage copy;
copy = *this;
copy.sig.Zero();
auto bte = copy.bt_encode();
return CryptoManager::instance()->verify(
pk, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
bool
GrantExitMessage::Sign(const llarp::SecretKey& sk)
{
sig.Zero();
nonce.Randomize();
auto bte = bt_encode();
return CryptoManager::instance()->sign(
sig, sk, reinterpret_cast<uint8_t*>(bte.data()), bte.size());
}
bool
GrantExitMessage::handle_message(AbstractRoutingMessageHandler* h, Router* r) const
{
return h->HandleGrantExitMessage(*this, r);
}
std::string
RejectExitMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("B", backoff_time);
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("Y", nonce.ToView());
btdp.append("Z", sig.ToView());
}
catch (...)
{
log::critical(route_cat, "Error: RejectExitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
RejectExitMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictInt("B", backoff_time, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Y", nonce, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
return false;
return read;
}
bool
RejectExitMessage::Sign(const llarp::SecretKey& sk)
{
sig.Zero();
nonce.Randomize();
auto bte = bt_encode();
return CryptoManager::instance()->sign(
sig, sk, reinterpret_cast<uint8_t*>(bte.data()), bte.size());
}
bool
RejectExitMessage::Verify(const llarp::PubKey& pk) const
{
RejectExitMessage copy;
copy = *this;
copy.sig.Zero();
auto bte = copy.bt_encode();
return CryptoManager::instance()->verify(
pk, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
bool
RejectExitMessage::handle_message(AbstractRoutingMessageHandler* h, Router* r) const
{
return h->HandleRejectExitMessage(*this, r);
}
std::string
UpdateExitMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("P", path_id.ToView());
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("Z", sig.ToView());
}
catch (...)
{
log::critical(route_cat, "Error: UpdateExitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
UpdateExitMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("P", path_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
return false;
return read;
}
bool
UpdateExitMessage::Verify(const llarp::PubKey& pk) const
{
UpdateExitMessage copy;
copy = *this;
copy.sig.Zero();
auto bte = copy.bt_encode();
return CryptoManager::instance()->verify(
pk, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
bool
UpdateExitMessage::Sign(const llarp::SecretKey& sk)
{
nonce.Randomize();
auto bte = bt_encode();
return CryptoManager::instance()->sign(
sig, sk, reinterpret_cast<uint8_t*>(bte.data()), bte.size());
}
bool
UpdateExitMessage::handle_message(AbstractRoutingMessageHandler* h, Router* r) const
{
return h->HandleUpdateExitMessage(*this, r);
}
std::string
UpdateExitVerifyMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
}
catch (...)
{
log::critical(route_cat, "Error: UpdateExitVerifyMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
UpdateExitVerifyMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
return read;
}
bool
UpdateExitVerifyMessage::handle_message(AbstractRoutingMessageHandler* h, Router* r) const
{
return h->HandleUpdateExitVerifyMessage(*this, r);
}
std::string
CloseExitMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("S", sequence_number);
btdp.append("Y", nonce.ToView());
btdp.append("Z", sig.ToView());
}
catch (...)
{
log::critical(route_cat, "Error: CloseExitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
CloseExitMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Y", nonce, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
return false;
return read;
}
bool
CloseExitMessage::Verify(const llarp::PubKey& pk) const
{
CloseExitMessage copy;
copy = *this;
copy.sig.Zero();
auto bte = copy.bt_encode();
return CryptoManager::instance()->verify(
pk, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
bool
CloseExitMessage::Sign(const llarp::SecretKey& sk)
{
sig.Zero();
nonce.Randomize();
auto bte = bt_encode();
return CryptoManager::instance()->sign(
sig, sk, reinterpret_cast<uint8_t*>(bte.data()), bte.size());
}
bool
CloseExitMessage::handle_message(AbstractRoutingMessageHandler* h, Router* r) const
{
return h->HandleCloseExitMessage(*this, r);
}
} // namespace llarp::routing

@ -1,195 +0,0 @@
#pragma once
#include <llarp/crypto/types.hpp>
#include "policy.hpp"
#include <vector>
namespace llarp::routing
{
struct ObtainExitMessage final : public AbstractRoutingMessage
{
uint64_t flag{0}; // 0 for snode, 1 for internet access
llarp::PubKey pubkey;
uint64_t tx_id{0};
llarp::Signature sig;
ObtainExitMessage() : AbstractRoutingMessage()
{}
~ObtainExitMessage() override = default;
void
clear() override
{
flag = 0;
pubkey.Zero();
tx_id = 0;
sig.Zero();
}
/// populates I and signs
bool
Sign(const llarp::SecretKey& sk);
bool
Verify() const;
std::string
bt_encode() const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override;
};
struct GrantExitMessage final : public AbstractRoutingMessage
{
uint64_t tx_id;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
std::string
bt_encode() const override;
bool
Sign(const llarp::SecretKey& sk);
bool
Verify(const llarp::PubKey& pk) const;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override;
void
clear() override
{
tx_id = 0;
nonce.Zero();
sig.Zero();
}
};
struct RejectExitMessage final : public AbstractRoutingMessage
{
uint64_t backoff_time;
uint64_t tx_id;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
void
clear() override
{
backoff_time = 0;
tx_id = 0;
nonce.Zero();
sig.Zero();
}
bool
Sign(const llarp::SecretKey& sk);
bool
Verify(const llarp::PubKey& pk) const;
std::string
bt_encode() const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override;
};
struct UpdateExitVerifyMessage final : public AbstractRoutingMessage
{
uint64_t tx_id;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
~UpdateExitVerifyMessage() override = default;
void
clear() override
{
tx_id = 0;
nonce.Zero();
sig.Zero();
}
std::string
bt_encode() const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override;
};
struct UpdateExitMessage final : public AbstractRoutingMessage
{
llarp::PathID_t path_id;
uint64_t tx_id;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
bool
Sign(const llarp::SecretKey& sk);
bool
Verify(const llarp::PubKey& pk) const;
std::string
bt_encode() const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override;
void
clear() override
{
path_id.Zero();
tx_id = 0;
nonce.Zero();
sig.Zero();
}
};
struct CloseExitMessage final : public AbstractRoutingMessage
{
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
std::string
bt_encode() const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override;
bool
Sign(const llarp::SecretKey& sk);
bool
Verify(const llarp::PubKey& pk) const;
void
clear() override
{
nonce.Zero();
sig.Zero();
}
};
} // namespace llarp::routing

@ -4,7 +4,6 @@
#include <llarp/nodedb.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/path/path.hpp>
#include <llarp/quic/tunnel.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <utility>
@ -99,6 +98,7 @@ namespace llarp::exit
// p->SetExitTrafficHandler(util::memFn(&BaseSession::HandleTraffic, this));
// p->AddObtainExitHandler(util::memFn(&BaseSession::HandleGotExit, this));
// TODO: add callback here
if (p->obtain_exit(
exit_key, std::is_same_v<decltype(p), ExitSession> ? 1 : 0, p->TXID().bt_encode()))
log::info(link_cat, "Asking {} for exit", exit_router);
@ -171,9 +171,12 @@ namespace llarp::exit
if (p->SupportsAnyRoles(path::ePathRoleExit))
{
LogInfo(p->name(), " closing exit path");
routing::CloseExitMessage msg;
if (!(msg.Sign(exit_key) && p->SendExitClose(msg, router)))
LogWarn(p->name(), " failed to send exit close message");
// TODO: add callback here
if (p->close_exit(exit_key, p->TXID().bt_encode()))
log::info(link_cat, "");
else
log::warning(link_cat, "{} failed to send exit close message", p->name());
}
};
ForEachPath(sendExitClose);
@ -183,31 +186,28 @@ namespace llarp::exit
bool
BaseSession::HandleTraffic(
llarp::path::Path_ptr path,
const llarp_buffer_t& buf,
uint64_t counter,
service::ProtocolType t)
llarp::path::Path_ptr, const llarp_buffer_t&, uint64_t, service::ProtocolType)
{
const service::ConvoTag tag{path->RXID().as_array()};
if (t == service::ProtocolType::QUIC)
{
auto quic = m_Parent->GetQUICTunnel();
if (not quic)
return false;
quic->receive_packet(tag, buf);
return true;
}
if (packet_write_func)
{
llarp::net::IPPacket pkt{buf.view_all()};
if (pkt.empty())
return false;
_last_use = router->now();
m_Downstream.emplace(counter, pkt);
return true;
}
// const service::ConvoTag tag{path->RXID().as_array()};
// if (t == service::ProtocolType::QUIC)
// {
// auto quic = m_Parent->GetQUICTunnel();
// if (not quic)
// return false;
// quic->receive_packet(tag, buf);
// return true;
// }
// if (packet_write_func)
// {
// llarp::net::IPPacket pkt{buf.view_all()};
// if (pkt.empty())
// return false;
// _last_use = router->now();
// m_Downstream.emplace(counter, pkt);
// return true;
// }
return false;
}
@ -220,29 +220,31 @@ namespace llarp::exit
}
bool
BaseSession::QueueUpstreamTraffic(
llarp::net::IPPacket pkt, const size_t N, service::ProtocolType t)
BaseSession::QueueUpstreamTraffic(llarp::net::IPPacket, const size_t, service::ProtocolType)
{
auto& queue = m_Upstream[pkt.size() / N];
// auto& queue = m_Upstream[pkt.size() / N];
// queue overflow
if (queue.size() >= MaxUpstreamQueueLength)
return false;
if (queue.size() == 0)
{
queue.emplace_back();
queue.back().protocol = t;
return queue.back().PutBuffer(llarp_buffer_t{pkt}, _counter++);
}
auto& back = queue.back();
// pack to nearest N
if (back.Size() + pkt.size() > N)
{
queue.emplace_back();
queue.back().protocol = t;
return queue.back().PutBuffer(llarp_buffer_t{pkt}, _counter++);
}
back.protocol = t;
return back.PutBuffer(llarp_buffer_t{pkt}, _counter++);
// if (queue.size() >= MaxUpstreamQueueLength)
// return false;
// if (queue.size() == 0)
// {
// queue.emplace_back();
// queue.back().protocol = t;
// return queue.back().PutBuffer(llarp_buffer_t{pkt}, _counter++);
// }
// auto& back = queue.back();
// // pack to nearest N
// if (back.Size() + pkt.size() > N)
// {
// queue.emplace_back();
// queue.back().protocol = t;
// return queue.back().PutBuffer(llarp_buffer_t{pkt}, _counter++);
// }
// back.protocol = t;
// return back.PutBuffer(llarp_buffer_t{pkt}, _counter++);
return true;
}
bool
@ -277,25 +279,25 @@ namespace llarp::exit
auto path = PickEstablishedPath(llarp::path::ePathRoleExit);
if (path)
{
for (auto& [i, queue] : m_Upstream)
{
while (queue.size())
{
auto& msg = queue.front();
msg.sequence_number = path->NextSeqNo();
path->SendRoutingMessage(msg, router);
queue.pop_front();
}
}
// for (auto& [i, queue] : m_Upstream)
// {
// while (queue.size())
// {
// auto& msg = queue.front();
// msg.sequence_number = path->NextSeqNo();
// path->SendRoutingMessage(msg, router);
// queue.pop_front();
// }
// }
}
else
{
if (m_Upstream.size())
llarp::LogWarn("no path for exit session");
// discard upstream
for (auto& [i, queue] : m_Upstream)
queue.clear();
m_Upstream.clear();
// if (m_Upstream.size())
// llarp::LogWarn("no path for exit session");
// // discard upstream
// for (auto& [i, queue] : m_Upstream)
// queue.clear();
// m_Upstream.clear();
if (numHops == 1)
{
@ -338,12 +340,12 @@ namespace llarp::exit
void
BaseSession::FlushDownstream()
{
while (m_Downstream.size())
{
if (packet_write_func)
packet_write_func(const_cast<net::IPPacket&>(m_Downstream.top().second).steal());
m_Downstream.pop();
}
// while (m_Downstream.size())
// {
// if (packet_write_func)
// packet_write_func(const_cast<net::IPPacket&>(m_Downstream.top().second).steal());
// m_Downstream.pop();
// }
}
SNodeSession::SNodeSession(
@ -377,23 +379,26 @@ namespace llarp::exit
void
ExitSession::send_packet_to_remote(std::string buf)
{
net::IPPacket pkt{buf};
if (pkt.empty())
if (buf.empty())
return;
pkt.ZeroAddresses();
// QueueUpstreamTraffic(std::move(pkt), llarp::routing::EXIT_PAD_SIZE, t);
if (auto path = PickEstablishedPath(llarp::path::ePathRoleExit))
{}
else
{}
}
void
SNodeSession::send_packet_to_remote(std::string buf)
{
net::IPPacket pkt{buf};
if (pkt.empty())
if (buf.empty())
return;
pkt.ZeroSourceAddress();
// QueueUpstreamTraffic(std::move(pkt), llarp::routing::EXIT_PAD_SIZE, t);
if (auto path = PickEstablishedPath(llarp::path::ePathRoleExit))
{
//
}
else
{}
}
} // namespace llarp::exit

@ -12,7 +12,7 @@ namespace llarp
{
class EndpointBase;
namespace quic
namespace link
{
class TunnelManager;
}
@ -163,12 +163,12 @@ namespace llarp
}
};
uint64_t _counter;
[[maybe_unused]] uint64_t _counter;
llarp_time_t _last_use;
std::vector<SessionReadyFunc> m_PendingCallbacks;
const bool m_BundleRC;
EndpointBase* const m_Parent;
[[maybe_unused]] const bool m_BundleRC;
[[maybe_unused]] EndpointBase* const m_Parent;
void
CallPendingCallbacks(bool success);

@ -7,7 +7,6 @@
#include <llarp/util/str.hpp>
#include <llarp/util/bits.hpp>
#include <llarp/quic/tunnel.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <cassert>
@ -18,10 +17,9 @@ namespace llarp::handlers
ExitEndpoint::ExitEndpoint(std::string name, Router* r)
: router(r)
, name(std::move(name))
, tunnel_manager{std::make_shared<quic::TunnelManager>(*this)}
, tunnel_manager{std::make_shared<link::TunnelManager>(*this)}
{
should_init_tun = true;
tunnel_manager = std::make_shared<quic::TunnelManager>(*this);
}
ExitEndpoint::~ExitEndpoint() = default;
@ -749,12 +747,12 @@ namespace llarp::handlers
if_name = *maybe;
}
LogInfo(Name(), " set ifname to ", if_name);
if (auto* quic = GetQUICTunnel())
{
quic->listen([ifaddr = net::TruncateV6(if_addr)](std::string_view, uint16_t port) {
return llarp::SockAddr{ifaddr, huint16_t{port}};
});
}
// if (auto* quic = GetQUICTunnel())
// {
// quic->listen([ifaddr = net::TruncateV6(if_addr)](std::string_view, uint16_t port) {
// return llarp::SockAddr{ifaddr, huint16_t{port}};
// });
// }
}
huint128_t
@ -783,7 +781,7 @@ namespace llarp::handlers
return ip;
}
quic::TunnelManager*
link::TunnelManager*
ExitEndpoint::GetQUICTunnel()
{
return tunnel_manager.get();

@ -162,7 +162,7 @@ namespace llarp
void
Flush();
quic::TunnelManager*
link::TunnelManager*
GetQUICTunnel() override;
huint128_t
@ -226,7 +226,7 @@ namespace llarp
SockAddr resolver_addr;
std::vector<SockAddr> upstream_resolvers;
std::shared_ptr<quic::TunnelManager> tunnel_manager;
std::shared_ptr<link::TunnelManager> tunnel_manager;
using PacketQueue_t = std::
priority_queue<net::IPPacket, std::vector<net::IPPacket>, net::IPPacket::CompareOrder>;

@ -50,11 +50,9 @@ namespace llarp::handlers
m_PacketRouter->HandleIPPacketFrom(std::move(*from), std::move(pkt));
return true;
}
else
{
LogWarn("did not handle packet, no endpoint with convotag T=", tag);
return false;
}
LogWarn("did not handle packet, no endpoint with convotag T=", tag);
return false;
}
if (t != service::ProtocolType::QUIC)
return false;
@ -70,7 +68,8 @@ namespace llarp::handlers
LogWarn("invalid incoming quic packet, dropping");
return false;
}
quic->receive_packet(tag, buf);
// TODO:
// quic->receive_packet(tag, buf);
return true;
}

@ -21,7 +21,6 @@
#include <llarp/service/protocol_type.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/quic/tunnel.hpp>
#include <llarp/rpc/endpoint_rpc.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/logging/buffer.hpp>
@ -391,8 +390,11 @@ namespace llarp::handlers
if (not data.empty())
{
std::string_view bdata{data.data(), data.size()};
LogDebug(Name(), " parsing address map data: ", bdata);
const auto parsed = oxenc::bt_deserialize<oxenc::bt_dict>(bdata);
for (const auto& [key, value] : parsed)
{
huint128_t ip{};
@ -454,12 +456,13 @@ namespace llarp::handlers
}
}
if (auto* quic = GetQUICTunnel())
{
quic->listen([this](std::string_view, uint16_t port) {
return llarp::SockAddr{net::TruncateV6(GetIfAddr()), huint16_t{port}};
});
}
// if (auto* quic = GetQUICTunnel())
// {
// TODO:
// quic->listen([this](std::string_view, uint16_t port) {
// return llarp::SockAddr{net::TruncateV6(GetIfAddr()), huint16_t{port}};
// });
// }
return Endpoint::Configure(conf, dnsConf);
}
@ -469,19 +472,6 @@ namespace llarp::handlers
return m_IPToAddr.find(ip) != m_IPToAddr.end();
}
void
TunEndpoint::Pump(llarp_time_t now)
{
// flush network to user
while (not m_NetworkToUserPktQueue.empty())
{
m_NetIf->WritePacket(m_NetworkToUserPktQueue.top().pkt);
m_NetworkToUserPktQueue.pop();
}
service::Endpoint::Pump(now);
}
static bool
is_random_snode(const dns::Message& msg)
{
@ -1367,7 +1357,9 @@ namespace llarp::handlers
return false;
}
LogInfo("tag active T=", tag);
quic->receive_packet(tag, buf);
// TODO:
// quic->receive_packet(tag, buf);
return true;
}
@ -1473,7 +1465,10 @@ namespace llarp::handlers
{
pkt.UpdateIPv6Address(src, dst);
}
m_NetworkToUserPktQueue.push(std::move(write));
// TODO: send this along but without a fucking huint182_t
// m_NetworkToUserPktQueue.push(std::move(write));
// wake up so we ensure that all packets are written to user
router()->TriggerPump();
return true;

@ -5,7 +5,7 @@ namespace llarp::link
Connection::Connection(
std::shared_ptr<oxen::quic::connection_interface>& c,
std::shared_ptr<oxen::quic::BTRequestStream>& s,
RouterContact& rc)
const RouterContact& rc)
: conn{c}, control_stream{s}, remote_rc{std::move(rc)}
{}

@ -20,7 +20,7 @@ namespace llarp::link
Connection(
std::shared_ptr<oxen::quic::connection_interface>& c,
std::shared_ptr<oxen::quic::BTRequestStream>& s,
RouterContact& rc);
const RouterContact& rc);
};
} // namespace llarp::link

@ -675,7 +675,8 @@ namespace llarp
{
m.respond(
serialize_response(
{{"STATUS", FindRouterMessage::RETRY_ITER}, {"TARGET", target_addr.data()}}),
{{"STATUS", FindRouterMessage::RETRY_ITER},
{"TARGET", reinterpret_cast<const char*>(target_addr.data())}}),
true);
}
}
@ -1656,4 +1657,22 @@ namespace llarp
}
}
void
LinkManager::handle_convo_intro(oxen::quic::message m)
{
if (m.timed_out)
{
log::info(link_cat, "Path control message timed out!");
return;
}
try
{}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
return;
}
}
} // namespace llarp

@ -1,18 +1,29 @@
#pragma once
#include <llarp/endpoint_base.hpp>
#include <llarp/net/sock_addr.hpp>
#include <llarp/service/convotag.hpp>
#include <chrono>
#include <charconv>
#include <cstdint>
#include <queue>
#include <unordered_set>
#include <string>
#include <string_view>
#include <uvw/tcp.h>
namespace llarp
{
class EndpointBase;
}
namespace llarp::link
{
struct Endpoint;
using namespace std::chrono_literals;
namespace tunnel
{
// The server sends back a 0x00 to signal that the remote TCP connection was established and
@ -176,7 +187,7 @@ namespace llarp::link
// Server instance; this listens on pseudo-port 0 (if it listens). This is automatically
// instantiated the first time `listen()` is called; if not instantiated we simply drop any
// inbound client-to-server quic packets.
std::unique_ptr<Server> server_;
// std::unique_ptr<Server> server_;
void
make_server();

@ -1,11 +1,11 @@
#include <lokinet.h>
#include <llarp.hpp>
#include <llarp/config/config.hpp>
#include <llarp/crypto/crypto_libsodium.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/router/router.hpp>
#include <llarp/service/context.hpp>
#include <llarp/quic/tunnel.hpp>
#include <llarp/link/tunnel.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/util/logging.hpp>
@ -305,7 +305,7 @@ struct lokinet_context
[[nodiscard]] auto
endpoint(std::string name = "default") const
{
return impl->router->hiddenServiceContext().GetEndpointByName(name);
return impl->router->hidden_service_context().GetEndpointByName(name);
}
std::unordered_map<int, bool> streams;
@ -490,7 +490,7 @@ extern "C"
return -3;
auto lock = ctx->acquire();
// add a temp cryptography implementation here so rc.Verify works
llarp::CryptoManager instance{new llarp::sodium::CryptoLibSodium{}};
llarp::CryptoManager instance{new llarp::Crypto{}};
if (data[0] == 'l')
{
if (not ctx->config->bootstrap.routers.BDecode(&buf))
@ -577,7 +577,7 @@ extern "C"
return -3;
if (not ctx->impl->LooksAlive())
return -2;
return ctx->endpoint()->IsReady() ? 0 : -1;
return ctx->endpoint()->is_ready() ? 0 : -1;
}
int EXPORT
@ -593,12 +593,12 @@ extern "C"
ms = 10;
iterations = 1;
}
while (not ep->IsReady() and iterations > 0)
while (not ep->is_ready() and iterations > 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds{ms / 10});
iterations--;
}
return ep->IsReady() ? 0 : -1;
return ep->is_ready() ? 0 : -1;
}
void EXPORT
@ -945,7 +945,7 @@ extern "C"
else
return EHOSTUNREACH;
}
if (auto maybe = llarp::service::ParseAddress(std::string{remote->remote_host}))
if (auto maybe = llarp::service::parse_address(std::string{remote->remote_host}))
{
llarp::net::IPPacket pkt = llarp::net::IPPacket::UDP(
llarp::nuint32_t{0},
@ -957,10 +957,10 @@ extern "C"
if (pkt.empty())
return EINVAL;
std::promise<int> ret;
ctx->impl->router->loop()->call([addr = *maybe, pkt = std::move(pkt), ep, &ret]() {
ctx->impl->router->loop()->call([addr = *maybe, pkt = pkt.to_string(), ep, &ret]() {
if (auto tag = ep->GetBestConvoTagFor(addr))
{
if (ep->SendToOrQueue(*tag, pkt.ConstBuffer(), llarp::service::ProtocolType::TrafficV4))
if (ep->send_to(*tag, pkt))
{
ret.set_value(0);
return;
@ -997,7 +997,7 @@ extern "C"
else
return EHOSTUNREACH;
}
if (auto maybe = llarp::service::ParseAddress(std::string{remote->remote_host}))
if (auto maybe = llarp::service::parse_address(std::string{remote->remote_host}))
{
{
// check for pre existing flow
@ -1012,14 +1012,19 @@ extern "C"
}
}
}
std::promise<bool> gotten;
ctx->impl->router->loop()->call([addr = *maybe, ep, &gotten]() {
ep->MarkAddressOutbound(addr);
auto res = ep->EnsurePathTo(
addr, [&gotten](auto result) { gotten.set_value(result.has_value()); }, 5s);
if (not res)
ctx->impl->router->loop()->call([maybe_addr = *maybe, ep, &gotten]() {
if (auto* addr = std::get_if<llarp::service::Address>(&maybe_addr))
{
gotten.set_value(false);
ep->MarkAddressOutbound(*addr);
auto res = ep->EnsurePathTo(
*addr, [&gotten](auto result) { gotten.set_value(result.has_value()); }, 5s);
if (not res)
{
gotten.set_value(false);
}
}
});
if (gotten.get_future().get())

@ -18,8 +18,8 @@ namespace llarp
try
{
btdp.append("E", is_exploratory);
btdp.append("I", is_iterative);
btdp.append("E", is_exploratory ? 1 : 0);
btdp.append("I", is_iterative ? 1 : 0);
btdp.append("K", rid.ToView());
}
catch (...)
@ -37,8 +37,8 @@ namespace llarp
try
{
btdp.append("E", is_exploratory);
btdp.append("I", is_iterative);
btdp.append("E", is_exploratory ? 1 : 0);
btdp.append("I", is_iterative ? 1 : 0);
btdp.append("K", std::move(rid));
}
catch (...)

@ -1,127 +0,0 @@
#pragma once
#include "link_message.hpp"
#include <llarp/routing/handler.hpp>
#include <llarp/routing/message.hpp>
#include <llarp/util/bencode.hpp>
namespace llarp
{
struct LinkDiscardMessage final : public AbstractLinkMessage
{
LinkDiscardMessage() : AbstractLinkMessage()
{}
std::string
bt_encode() const override
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "x");
}
catch (...)
{
log::critical(link_cat, "Error: RelayDownstreamMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
void
clear() override
{
version = 0;
}
const char*
name() const override
{
return "Discard";
}
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override
{
if (key.startswith("a"))
{
llarp_buffer_t strbuf;
if (!bencode_read_string(buf, &strbuf))
return false;
if (strbuf.sz != 1)
return false;
return *strbuf.cur == 'x';
}
return false;
}
bool
handle_message(Router* /*router*/) const override
{
return true;
}
};
namespace routing
{
struct DataDiscardMessage final : public AbstractRoutingMessage
{
PathID_t path_id;
DataDiscardMessage() = default;
DataDiscardMessage(const PathID_t& dst, uint64_t s) : path_id(dst)
{
sequence_number = s;
version = llarp::constants::proto_version;
}
void
clear() override
{
version = 0;
}
bool
handle_message(AbstractRoutingMessageHandler* h, Router* r) const override
{
return h->HandleDataDiscardMessage(*this, r);
}
bool
decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf) override
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("P", path_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
return read;
}
std::string
bt_encode() const override
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("A", "D");
btdp.append("P", path_id.ToView());
btdp.append("S", sequence_number);
btdp.append("V", version);
}
catch (...)
{
log::critical(route_cat, "Error: DataDiscardMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
};
} // namespace routing
} // namespace llarp

@ -1,493 +0,0 @@
#include "relay_commit.hpp"
#include "relay_status.hpp"
#include <llarp/crypto/crypto.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/path/transit_hop.hpp>
#include <llarp/router/router.hpp>
#include <llarp/router/outbound_message_handler.hpp>
#include <llarp/routing/path_confirm_message.hpp>
#include <llarp/util/bencode.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/tooling/path_event.hpp>
#include <functional>
#include <optional>
namespace llarp
{
bool
LR_CommitMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
if (key.startswith("c"))
{
/// so we dont put it into the shitty queue
pathid.Fill('c');
return BEncodeReadArray(frames, buf);
}
bool read = false;
if (!BEncodeMaybeVerifyVersion("v", version, llarp::constants::proto_version, read, key, buf))
return false;
return read;
}
void
LR_CommitMessage::clear()
{
std::for_each(frames.begin(), frames.end(), [](auto& f) { f.Clear(); });
version = 0;
}
std::string
LR_CommitMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "c");
{
auto sublist = btdp.append_list("c");
for (auto& f : frames)
sublist.append({reinterpret_cast<const char*>(f.data()), f.size()});
}
btdp.append("v", llarp::constants::proto_version);
}
catch (...)
{
log::critical(link_cat, "Error: LR_CommitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
LR_CommitMessage::handle_message(Router* router) const
{
if (frames.size() != path::MAX_LEN)
{
llarp::LogError("LRCM invalid number of records, ", frames.size(), "!=", path::MAX_LEN);
return false;
}
if (!router->path_context().AllowingTransit())
{
llarp::LogError("got LRCM when not permitting transit");
return false;
}
return AsyncDecrypt(&router->path_context());
}
bool
LR_CommitRecord::BEncode(llarp_buffer_t* buf) const
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictEntry("c", commkey, buf))
return false;
if (!BEncodeWriteDictEntry("i", nextHop, buf))
return false;
if (lifetime > 10s && lifetime < path::DEFAULT_LIFETIME)
{
if (!BEncodeWriteDictInt("i", lifetime.count(), buf))
return false;
}
if (!BEncodeWriteDictEntry("n", tunnelNonce, buf))
return false;
if (!BEncodeWriteDictEntry("r", rxid, buf))
return false;
if (!BEncodeWriteDictEntry("t", txid, buf))
return false;
if (nextRC)
{
if (!BEncodeWriteDictEntry("u", *nextRC, buf))
return false;
}
if (not bencode_write_uint64_entry(buf, "v", 1, llarp::constants::proto_version))
return false;
if (work and not BEncodeWriteDictEntry("w", *work, buf))
return false;
return bencode_end(buf);
}
bool
LR_CommitRecord::OnKey(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
if (!key)
return true;
bool read = false;
if (!BEncodeMaybeReadDictEntry("c", commkey, read, *key, buffer))
return false;
if (!BEncodeMaybeReadDictEntry("i", nextHop, read, *key, buffer))
return false;
if (!BEncodeMaybeReadDictInt("l", lifetime, read, *key, buffer))
return false;
if (!BEncodeMaybeReadDictEntry("n", tunnelNonce, read, *key, buffer))
return false;
if (!BEncodeMaybeReadDictEntry("r", rxid, read, *key, buffer))
return false;
if (!BEncodeMaybeReadDictEntry("t", txid, read, *key, buffer))
return false;
if (key->startswith("u"))
{
nextRC = std::make_unique<RouterContact>();
return nextRC->BDecode(buffer);
}
if (!BEncodeMaybeVerifyVersion(
"v", version, llarp::constants::proto_version, read, *key, buffer))
return false;
if (key->startswith("w"))
{
// check for duplicate
if (work)
{
llarp::LogWarn("duplicate POW in LRCR");
return false;
}
work = std::make_unique<PoW>();
return bencode_decode_dict(*work, buffer);
}
return read;
}
bool
LR_CommitRecord::BDecode(llarp_buffer_t* buf)
{
return bencode_read_dict(util::memFn(&LR_CommitRecord::OnKey, this), buf);
}
bool
LR_CommitRecord::operator==(const LR_CommitRecord& other) const
{
if (work && other.work)
{
if (*work != *other.work)
return false;
}
return nextHop == other.nextHop && commkey == other.commkey && txid == other.txid
&& rxid == other.rxid;
}
struct LRCMFrameDecrypt
{
using Context = llarp::path::PathContext;
using Hop = llarp::path::TransitHop;
using Decrypter = AsyncFrameDecrypter<LRCMFrameDecrypt>;
using Decrypter_ptr = std::unique_ptr<Decrypter>;
Decrypter_ptr decrypter;
std::array<EncryptedFrame, 8> frames;
Context* context;
// decrypted record
LR_CommitRecord record;
// the actual hop
std::shared_ptr<Hop> hop;
oxen::quic::Address from_addr;
LRCMFrameDecrypt(Context* ctx, Decrypter_ptr dec, const LR_CommitMessage* commit)
: decrypter(std::move(dec))
, frames(commit->frames)
, context(ctx)
, hop(std::make_shared<Hop>())
, from_addr{
commit->conn->remote_rc.IsPublicRouter() ? oxen::quic::Address{}
: commit->conn->remote_rc.addr}
{
hop->info.downstream = commit->conn->remote_rc.pubkey;
}
~LRCMFrameDecrypt() = default;
static void
OnForwardLRCMResult(
Router* router,
std::shared_ptr<path::TransitHop> path,
const PathID_t pathid,
const RouterID nextHop,
const SharedSecret pathKey,
SendStatus sendStatus)
{
uint64_t status = LR_StatusRecord::FAIL_DEST_INVALID;
switch (sendStatus)
{
case SendStatus::Success:
// do nothing, will forward success message later
return;
case SendStatus::Timeout:
status = LR_StatusRecord::FAIL_TIMEOUT;
break;
case SendStatus::NoLink:
status = LR_StatusRecord::FAIL_CANNOT_CONNECT;
break;
case SendStatus::InvalidRouter:
status = LR_StatusRecord::FAIL_DEST_INVALID;
break;
case SendStatus::RouterNotFound:
status = LR_StatusRecord::FAIL_DEST_UNKNOWN;
break;
case SendStatus::Congestion:
status = LR_StatusRecord::FAIL_CONGESTION;
break;
default:
LogError("llarp::SendStatus value not in enum class");
std::abort();
break;
}
router->queue_work([router, path, pathid, nextHop, pathKey, status] {
LR_StatusMessage::CreateAndSend(router, path, pathid, nextHop, pathKey, status);
});
}
/// this is done from logic thread
static void
SendLRCM(std::shared_ptr<LRCMFrameDecrypt> self)
{
if (self->context->HasTransitHop(self->hop->info))
{
llarp::LogError("duplicate transit hop ", self->hop->info);
LR_StatusMessage::CreateAndSend(
self->context->router(),
self->hop,
self->hop->info.rxID,
self->hop->info.downstream,
self->hop->pathKey,
LR_StatusRecord::FAIL_DUPLICATE_HOP);
self->hop = nullptr;
return;
}
if (self->from_addr.is_addressable())
{
// only do ip limiting from non service nodes
#ifndef LOKINET_HIVE
if (self->context->CheckPathLimitHitByIP(self->from_addr.to_string()))
{
// we hit a limit so tell it to slow tf down
llarp::LogError("client path build hit limit ", self->from_addr);
OnForwardLRCMResult(
self->context->router(),
self->hop,
self->hop->info.rxID,
self->hop->info.downstream,
self->hop->pathKey,
SendStatus::Congestion);
self->hop = nullptr;
return;
}
#endif
}
if (not self->context->router()->PathToRouterAllowed(self->hop->info.upstream))
{
// we are not allowed to forward it ... now what?
llarp::LogError(
"path to ",
self->hop->info.upstream,
"not allowed, dropping build request on the floor");
OnForwardLRCMResult(
self->context->router(),
self->hop,
self->hop->info.rxID,
self->hop->info.downstream,
self->hop->pathKey,
SendStatus::InvalidRouter);
self->hop = nullptr;
return;
}
// persist sessions to upstream and downstream routers until the commit
// ends
self->context->router()->persist_connection_until(
self->hop->info.downstream, self->hop->ExpireTime() + 10s);
self->context->router()->persist_connection_until(
self->hop->info.upstream, self->hop->ExpireTime() + 10s);
// put hop
self->context->PutTransitHop(self->hop);
// forward to next hop
using std::placeholders::_1;
auto func = [self](auto status) {
OnForwardLRCMResult(
self->context->router(),
self->hop,
self->hop->info.rxID,
self->hop->info.downstream,
self->hop->pathKey,
status);
self->hop = nullptr;
};
self->context->ForwardLRCM(self->hop->info.upstream, self->frames, func);
// trigger idempotent pump to ensure that the build messages propagate
self->context->router()->TriggerPump();
}
// this is called from the logic thread
static void
SendPathConfirm(std::shared_ptr<LRCMFrameDecrypt> self)
{
// send path confirmation
// TODO: other status flags?
uint64_t status = LR_StatusRecord::SUCCESS;
if (self->context->HasTransitHop(self->hop->info))
{
status = LR_StatusRecord::FAIL_DUPLICATE_HOP;
}
else
{
// persist session to downstream until path expiration
self->context->router()->persist_connection_until(
self->hop->info.downstream, self->hop->ExpireTime() + 10s);
// put hop
self->context->PutTransitHop(self->hop);
}
if (!LR_StatusMessage::CreateAndSend(
self->context->router(),
self->hop,
self->hop->info.rxID,
self->hop->info.downstream,
self->hop->pathKey,
status))
{
llarp::LogError("failed to send path confirmation for ", self->hop->info);
}
self->hop = nullptr;
}
// TODO: If decryption has succeeded here but we otherwise don't
// want to or can't accept the path build request, send
// a status message saying as much.
static void
HandleDecrypted(llarp_buffer_t* buf, std::shared_ptr<LRCMFrameDecrypt> self)
{
auto now = self->context->router()->now();
auto& info = self->hop->info;
if (!buf)
{
llarp::LogError("LRCM decrypt failed from ", info.downstream);
self->decrypter = nullptr;
return;
}
buf->cur = buf->base + EncryptedFrameOverheadSize;
llarp::LogDebug("decrypted LRCM from ", info.downstream);
// successful decrypt
if (!self->record.BDecode(buf))
{
llarp::LogError("malformed frame inside LRCM from ", info.downstream);
self->decrypter = nullptr;
return;
}
info.txID = self->record.txid;
info.rxID = self->record.rxid;
if (info.txID.IsZero() || info.rxID.IsZero())
{
llarp::LogError("LRCM refusing zero pathid");
self->decrypter = nullptr;
return;
}
info.upstream = self->record.nextHop;
// generate path key as we are in a worker thread
auto crypto = CryptoManager::instance();
if (!crypto->dh_server(
self->hop->pathKey,
self->record.commkey,
self->context->EncryptionSecretKey(),
self->record.tunnelNonce))
{
llarp::LogError("LRCM DH Failed ", info);
self->decrypter = nullptr;
return;
}
// generate hash of hop key for nonce mutation
crypto->shorthash(self->hop->nonceXOR, self->hop->pathKey.data(), self->hop->pathKey.size());
if (self->record.work && self->record.work->IsValid(now))
{
llarp::LogDebug(
"LRCM extended lifetime by ",
ToString(self->record.work->extendedLifetime),
" for ",
info);
self->hop->lifetime += self->record.work->extendedLifetime;
}
else if (self->record.lifetime < path::DEFAULT_LIFETIME && self->record.lifetime > 10s)
{
self->hop->lifetime = self->record.lifetime;
llarp::LogDebug(
"LRCM short lifespan set to ", ToString(self->hop->lifetime), " for ", info);
}
// TODO: check if we really want to accept it
self->hop->started = now;
// self->context->router()->NotifyRouterEvent<tooling::PathRequestReceivedEvent>(
// self->context->router()->pubkey(), self->hop);
size_t sz = self->frames[0].size();
// shift
std::array<EncryptedFrame, 8> frames;
frames[0] = self->frames[1];
frames[1] = self->frames[2];
frames[2] = self->frames[3];
frames[3] = self->frames[4];
frames[4] = self->frames[5];
frames[5] = self->frames[6];
frames[6] = self->frames[7];
// put our response on the end
frames[7] = EncryptedFrame(sz - EncryptedFrameOverheadSize);
// random junk for now
frames[7].Randomize();
self->frames = std::move(frames);
if (self->context->HopIsUs(info.upstream))
{
// we are the farthest hop
llarp::LogDebug("We are the farthest hop for ", info);
// send a LRSM down the path
self->context->loop()->call([self] {
SendPathConfirm(self);
self->decrypter = nullptr;
});
}
else
{
// forward upstream
// we are still in the worker thread so post job to logic
self->context->loop()->call([self] {
SendLRCM(self);
self->decrypter = nullptr;
});
}
// trigger idempotent pump to ensure that the build messages propagate
self->context->router()->TriggerPump();
}
};
bool
LR_CommitMessage::AsyncDecrypt(llarp::path::PathContext* context) const
{
auto decrypter = std::make_unique<LRCMFrameDecrypt::Decrypter>(
context->EncryptionSecretKey(), &LRCMFrameDecrypt::HandleDecrypted);
// copy frames so we own them
auto frameDecrypt = std::make_shared<LRCMFrameDecrypt>(context, std::move(decrypter), this);
// decrypt frames async
frameDecrypt->decrypter->AsyncDecrypt(
frameDecrypt->frames[0], frameDecrypt, [r = context->router()](auto func) {
r->loop()->call([&]() { func(); });
});
return true;
}
} // namespace llarp

@ -1,325 +0,0 @@
#include <llarp/crypto/crypto.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_confirm_message.hpp>
#include <llarp/util/bencode.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/tooling/path_event.hpp>
#include <functional>
#include <utility>
namespace llarp
{
struct LRSM_AsyncHandler : public std::enable_shared_from_this<LRSM_AsyncHandler>
{
using HopHandler_ptr = std::shared_ptr<llarp::path::AbstractHopHandler>;
std::array<EncryptedFrame, 8> frames;
uint64_t status = 0;
HopHandler_ptr hop;
Router* router;
PathID_t pathid;
LRSM_AsyncHandler(
std::array<EncryptedFrame, 8> _frames,
uint64_t _status,
HopHandler_ptr _hop,
Router* _router,
PathID_t pathid)
: frames{std::move(_frames)}
, status{_status}
, hop{std::move(_hop)}
, router{_router}
, pathid{std::move(pathid)}
{}
~LRSM_AsyncHandler() = default;
void
handle()
{
router->notify_router_event<tooling::PathStatusReceivedEvent>(
router->pubkey(), pathid, status);
hop->HandleLRSM(status, frames, router);
}
void
queue_handle()
{
auto func = [self = shared_from_this()] { self->handle(); };
router->queue_work(func);
}
};
bool
LR_StatusMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if (key.startswith("c"))
{
return BEncodeReadArray(frames, buf);
}
if (key.startswith("p"))
{
if (!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
{
return false;
}
}
else if (key.startswith("s"))
{
if (!BEncodeMaybeReadDictInt("s", status, read, key, buf))
{
return false;
}
}
else if (key.startswith("v"))
{
if (!BEncodeMaybeVerifyVersion("v", version, llarp::constants::proto_version, read, key, buf))
{
return false;
}
}
return read;
}
void
LR_StatusMessage::clear()
{
std::for_each(frames.begin(), frames.end(), [](auto& f) { f.Clear(); });
version = 0;
status = 0;
}
std::string
LR_StatusMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "s");
{
auto sublist = btdp.append_list("c");
for (auto& f : frames)
sublist.append({reinterpret_cast<const char*>(f.data()), f.size()});
}
btdp.append("p", pathid.ToView());
btdp.append("s", status);
btdp.append("v", llarp::constants::proto_version);
}
catch (...)
{
log::critical(link_cat, "Error: LR_StatusMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
LR_StatusMessage::handle_message(Router* router) const
{
llarp::LogDebug("Received LR_Status message from (", conn->remote_rc.pubkey, ")");
if (frames.size() != path::MAX_LEN)
{
llarp::LogError("LRSM invalid number of records, ", frames.size(), "!=", path::MAX_LEN);
return false;
}
auto path = router->path_context().GetByUpstream(conn->remote_rc.pubkey, pathid);
if (not path)
{
llarp::LogWarn("unhandled LR_Status message: no associated path found pathid=", pathid);
return false;
}
auto handler = std::make_shared<LRSM_AsyncHandler>(frames, status, path, router, pathid);
handler->queue_handle();
return true;
}
void
LR_StatusMessage::SetDummyFrames()
{
for (auto& f : frames)
f.Randomize();
}
// call this from a worker thread
bool
LR_StatusMessage::CreateAndSend(
Router* router,
std::shared_ptr<path::TransitHop> hop,
const PathID_t pathid,
const RouterID nextHop,
const SharedSecret pathKey,
uint64_t status)
{
auto message = std::make_shared<LR_StatusMessage>();
message->status = status;
message->pathid = pathid;
message->SetDummyFrames();
message->AddFrame(pathKey, status);
QueueSendMessage(router, nextHop, message, hop);
return true; // can't guarantee delivery here, as far as we know it's fine
}
bool
LR_StatusMessage::AddFrame(const SharedSecret& pathKey, uint64_t newStatus)
{
frames[7] = frames[6];
frames[6] = frames[5];
frames[5] = frames[4];
frames[4] = frames[3];
frames[3] = frames[2];
frames[2] = frames[1];
frames[1] = frames[0];
auto& frame = frames[0];
frame.Randomize();
LR_StatusRecord record;
record.status = newStatus;
record.version = llarp::constants::proto_version;
llarp_buffer_t buf(frame.data(), frame.size());
buf.cur = buf.base + EncryptedFrameOverheadSize;
// encode record
if (!record.BEncode(&buf))
{
// failed to encode?
LogError(name(), " Failed to generate Status Record");
DumpBuffer(buf);
return false;
}
// use ephemeral keypair for frame
if (!frame.DoEncrypt(pathKey, true))
{
LogError(name(), " Failed to encrypt LRSR");
DumpBuffer(buf);
return false;
}
return true;
}
void
LR_StatusMessage::QueueSendMessage(
Router* router,
const RouterID nextHop,
std::shared_ptr<LR_StatusMessage> msg,
std::shared_ptr<path::TransitHop> hop)
{
router->loop()->call([router, nextHop, msg = std::move(msg), hop = std::move(hop)] {
SendMessage(router, nextHop, msg, hop);
});
}
void
LR_StatusMessage::SendMessage(
Router* router,
const RouterID nextHop,
std::shared_ptr<LR_StatusMessage> msg,
std::shared_ptr<path::TransitHop> hop)
{
llarp::LogDebug("Attempting to send LR_Status message to (", nextHop, ")");
auto resultCallback = [hop, router, msg, nextHop](auto status) {
if ((msg->status & LR_StatusRecord::SUCCESS) != LR_StatusRecord::SUCCESS
or status != SendStatus::Success)
{
llarp::LogError("Failed to propagate LR_Status message to ", nextHop);
hop->QueueDestroySelf(router);
}
};
// send the status message to previous hop
// if it fails we are hitting a failure case we can't cope with so ... drop.
// TODO: replace with new message serialization
// if (not router->SendToOrQueue(nextHop, *msg, resultCallback))
// resultCallback(SendStatus::Congestion);
// trigger idempotent pump to make sure stuff gets sent
router->TriggerPump();
}
bool
LR_StatusRecord::BEncode(llarp_buffer_t* buf) const
{
return bencode_start_dict(buf) && BEncodeWriteDictInt("s", status, buf)
&& bencode_write_uint64_entry(buf, "v", 1, llarp::constants::proto_version)
&& bencode_end(buf);
}
bool
LR_StatusRecord::OnKey(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
if (!key)
return true;
bool read = false;
if (!BEncodeMaybeReadDictInt("s", status, read, *key, buffer))
return false;
if (!BEncodeMaybeVerifyVersion(
"v", version, llarp::constants::proto_version, read, *key, buffer))
return false;
return read;
}
bool
LR_StatusRecord::BDecode(llarp_buffer_t* buf)
{
return bencode_read_dict(util::memFn(&LR_StatusRecord::OnKey, this), buf);
}
bool
LR_StatusRecord::operator==(const LR_StatusRecord& other) const
{
return status == other.status;
}
using namespace std::literals;
static constexpr std::array code_strings = {
std::make_pair(LR_StatusRecord::SUCCESS, "success"sv),
std::make_pair(LR_StatusRecord::FAIL_TIMEOUT, "timeout"sv),
std::make_pair(LR_StatusRecord::FAIL_CONGESTION, "congestion"sv),
std::make_pair(LR_StatusRecord::FAIL_DEST_UNKNOWN, "destination unknown"sv),
std::make_pair(LR_StatusRecord::FAIL_DECRYPT_ERROR, "decrypt error"sv),
std::make_pair(LR_StatusRecord::FAIL_MALFORMED_RECORD, "malformed record"sv),
std::make_pair(LR_StatusRecord::FAIL_DEST_INVALID, "destination invalid"sv),
std::make_pair(LR_StatusRecord::FAIL_CANNOT_CONNECT, "cannot connect"sv),
std::make_pair(LR_StatusRecord::FAIL_DUPLICATE_HOP, "duplicate hop"sv)};
std::string
LRStatusCodeToString(uint64_t status)
{
std::string s = "[";
for (const auto& [val, message] : code_strings)
{
if ((status & val) == val)
{
if (s.size() > 1)
s += ", ";
s += message;
}
}
s += ']';
return s;
}
} // namespace llarp

@ -1,5 +1,7 @@
#include "traffic_policy.hpp"
#include "llarp/util/str.hpp"
#include <llarp/util/bencode.hpp>
#include <llarp/util/str.hpp>
namespace llarp::net
{

@ -93,7 +93,7 @@ namespace llarp
std::optional<RouterContact>
GetRandom(Filter visit) const
{
return router.loop()->call_get([this, visit]() -> std::optional<RouterContact> {
return router.loop()->call_get([visit]() -> std::optional<RouterContact> {
std::vector<const decltype(entries)::value_type*> entries;
for (const auto& entry : entries)
entries.push_back(entry);

@ -49,7 +49,7 @@ namespace llarp
/// send routing message and increment sequence number
virtual bool
SendRoutingMessage(const routing::AbstractRoutingMessage& msg, Router* r) = 0;
SendRoutingMessage(std::string payload, Router* r) = 0;
// handle data in upstream direction
virtual bool

@ -2,16 +2,13 @@
#include "pathbuilder.hpp"
#include "transit_hop.hpp"
#include <llarp/exit/exit_messages.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/messages/dht.hpp>
#include <llarp/messages/discard.hpp>
#include <llarp/messages/exit.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/tooling/path_event.hpp>
#include <oxenc/endian.h>
@ -552,7 +549,7 @@ namespace llarp::path
}
void
Path::HandleAllDownstream(std::vector<RelayDownstreamMessage> msgs, Router* r)
Path::HandleAllDownstream(std::vector<RelayDownstreamMessage> msgs, Router* /* r */)
{
for (const auto& msg : msgs)
{
@ -582,34 +579,27 @@ namespace llarp::path
std::move around.
*/
bool
Path::SendRoutingMessage(const routing::AbstractRoutingMessage& msg, Router* r)
Path::SendRoutingMessage(std::string payload, Router*)
{
std::array<byte_t, MAX_LINK_MSG_SIZE / 2> tmp;
llarp_buffer_t buf(tmp);
auto bte = msg.bt_encode();
buf.write(bte.begin(), bte.end());
std::string buf(MAX_LINK_MSG_SIZE / 2, '\0');
buf.insert(0, payload);
// make nonce
TunnelNonce N;
N.Randomize();
buf.sz = buf.cur - buf.base;
// pad smaller messages
if (buf.sz < PAD_SIZE)
if (payload.size() < PAD_SIZE)
{
// randomize padding
CryptoManager::instance()->randbytes(buf.cur, PAD_SIZE - buf.sz);
buf.sz = PAD_SIZE;
CryptoManager::instance()->randbytes(
reinterpret_cast<unsigned char*>(buf.data()) + payload.size(), PAD_SIZE - payload.size());
}
buf.cur = buf.base;
LogDebug(
"send routing message ",
msg.sequence_number,
" with ",
buf.sz,
" bytes to endpoint ",
Endpoint());
return HandleUpstream(buf, N, r);
log::debug(path_cat, "Sending {}B routing message to {}", buf.size(), Endpoint());
// TODO: path relaying here
return true;
}
template <typename Samples_t>

@ -3,7 +3,6 @@
#include "abstracthophandler.hpp"
#include "path_types.hpp"
#include "pathset.hpp"
// #include "pathbuilder.hpp"
#include <llarp/constants/path.hpp>
#include <llarp/crypto/encrypted_frame.hpp>
@ -27,7 +26,6 @@
namespace llarp
{
struct Router;
struct LR_CommitMessage;
namespace path
{
@ -219,7 +217,7 @@ namespace llarp
std::function<void(oxen::quic::message m)> func = nullptr) override;
bool
SendRoutingMessage(const routing::AbstractRoutingMessage& msg, Router* r) override;
SendRoutingMessage(std::string payload, Router* r) override;
bool
IsReady() const;

@ -1,7 +1,6 @@
#include "path.hpp"
#include "path_context.hpp"
#include <llarp/messages/relay_commit.hpp>
#include <llarp/router/router.hpp>
namespace llarp::path
@ -375,31 +374,6 @@ namespace llarp::path
}
}
routing::MessageHandler_ptr
PathContext::GetHandler(const PathID_t& id)
{
routing::MessageHandler_ptr h = nullptr;
auto pathset = GetLocalPathSet(id);
if (pathset)
{
h = pathset->GetPathByID(id);
}
if (h)
return h;
const RouterID us(OurRouterID());
auto& map = m_TransitPaths;
{
SyncTransitMap_t::Lock_t lock(map.first);
auto range = map.second.equal_range(id);
for (auto i = range.first; i != range.second; ++i)
{
if (i->second->info.upstream == us)
return i->second;
}
}
return nullptr;
}
void
PathContext::RemovePathSet(PathSet_ptr)
{}

@ -1,12 +1,12 @@
#pragma once
#include <llarp/crypto/encrypted_frame.hpp>
#include <llarp/net/ip_address.hpp>
#include "abstracthophandler.hpp"
#include "path_types.hpp"
#include "pathset.hpp"
#include "transit_hop.hpp"
#include <llarp/routing/handler.hpp>
#include <llarp/crypto/encrypted_frame.hpp>
#include <llarp/net/ip_address.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <llarp/util/decaying_hashset.hpp>
#include <llarp/util/types.hpp>
@ -17,9 +17,6 @@
namespace llarp
{
struct Router;
struct LR_CommitMessage;
struct RelayDownstreamMessage;
struct RelayUpstreamMessage;
struct RouterID;
namespace path
@ -61,9 +58,6 @@ namespace llarp
bool
HasTransitHop(const TransitHopInfo& info);
bool
HandleRelayCommit(const LR_CommitMessage& msg);
void
PutTransitHop(std::shared_ptr<TransitHop> hop);
@ -88,9 +82,6 @@ namespace llarp
PathSet_ptr
GetLocalPathSet(const PathID_t& id);
routing::MessageHandler_ptr
GetHandler(const PathID_t& id);
using EndpointPathPtrSet = std::set<Path_ptr, ComparePtr<Path_ptr>>;
/// get a set of all paths that we own who's endpoint is r
EndpointPathPtrSet
@ -99,12 +90,6 @@ namespace llarp
bool
HopIsUs(const RouterID& k) const;
bool
HandleLRUM(const RelayUpstreamMessage& msg);
bool
HandleLRDM(const RelayDownstreamMessage& msg);
void
AddOwnPath(PathSet_ptr set, Path_ptr p);

@ -5,12 +5,10 @@
#include <llarp/crypto/crypto.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/messages/path.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/router.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/tooling/path_event.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
@ -420,7 +418,9 @@ namespace llarp
std::string path_shortName = "[path " + router->ShortName() + "-";
path_shortName = path_shortName + std::to_string(router->NextPathBuildNumber()) + "]";
auto path = std::make_shared<path::Path>(hops, GetWeak(), roles, std::move(path_shortName));
auto path =
std::make_shared<path::Path>(router, hops, GetWeak(), roles, std::move(path_shortName));
log::info(
path_cat, "{} building path -> {} : {}", Name(), path->ShortName(), path->HopsString());

@ -3,9 +3,7 @@
#include "transit_hop.hpp"
#include <llarp/exit/context.hpp>
#include <llarp/exit/exit_messages.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/messages/discard.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/buffer.hpp>
@ -43,8 +41,7 @@ namespace llarp::path
return started + lifetime;
}
TransitHopInfo::TransitHopInfo(const RouterID& down, const LR_CommitRecord& record)
: txID(record.txid), rxID(record.rxid), upstream(record.nextHop), downstream(down)
TransitHopInfo::TransitHopInfo(const RouterID& down) : downstream(down)
{}
/** Note: this is one of two places where AbstractRoutingMessage::bt_encode() is called, the
@ -63,26 +60,26 @@ namespace llarp::path
std::move around.
*/
bool
TransitHop::SendRoutingMessage(const routing::AbstractRoutingMessage& msg, Router* r)
TransitHop::SendRoutingMessage(std::string payload, Router* r)
{
if (!IsEndpoint(r->pubkey()))
return false;
auto buf = msg.bt_encode();
TunnelNonce N;
N.Randomize();
// pad to nearest MESSAGE_PAD_SIZE bytes
auto dlt = buf.size() % PAD_SIZE;
auto dlt = payload.size() % PAD_SIZE;
if (dlt)
{
dlt = PAD_SIZE - dlt;
// randomize padding
CryptoManager::instance()->randbytes(reinterpret_cast<uint8_t*>(buf.data()), dlt);
CryptoManager::instance()->randbytes(reinterpret_cast<uint8_t*>(payload.data()), dlt);
}
return HandleDownstream(buf, N, r);
// TODO: relay message along
return true;
}
void
@ -166,7 +163,7 @@ namespace llarp::path
for (const auto& msg : msgs)
{
const llarp_buffer_t buf(msg.enc);
if (!r->ParseRoutingMessageBuffer(buf, this, info.rxID))
if (!r->ParseRoutingMessageBuffer(buf, *this, info.rxID))
{
LogWarn("invalid upstream data on endpoint ", info);
}
@ -190,7 +187,7 @@ namespace llarp::path
info.downstream,
" to ",
info.upstream);
r->send_data_message(info.upstream, msg);
r->send_data_message(info.upstream, msg.bt_encode());
}
}
r->TriggerPump();
@ -207,6 +204,7 @@ namespace llarp::path
msg.enc.size(),
info.upstream,
info.downstream);
// TODO: is this right?
r->send_data_message(info.downstream, msg.bt_encode());
}

@ -9,8 +9,6 @@
namespace llarp
{
struct LR_CommitRecord;
namespace dht
{
struct GotIntroMessage;
@ -21,7 +19,7 @@ namespace llarp
struct TransitHopInfo
{
TransitHopInfo() = default;
TransitHopInfo(const RouterID& down, const LR_CommitRecord& record);
TransitHopInfo(const RouterID& down);
PathID_t txID, rxID;
RouterID upstream;
@ -116,10 +114,7 @@ namespace llarp
// send routing message when end of path
bool
SendRoutingMessage(const routing::AbstractRoutingMessage& msg, Router* r) override;
bool
HandleDHTMessage(const dht::AbstractDHTMessage& msg, Router* r) override;
SendRoutingMessage(std::string payload, Router* r) override;
void
FlushUpstream(Router* r) override;

@ -1,9 +1,7 @@
#include "rc_gossiper.hpp"
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/util/time.hpp>
#include <llarp/constants/link_layer.hpp>
#include <llarp/tooling/rc_event.hpp>
#include <llarp/link/link_manager.hpp>
namespace llarp
@ -95,10 +93,10 @@ namespace llarp
}
// send a GRCM as gossip method
DHTImmediateMessage gossip;
gossip.msgs.emplace_back(new dht::GotRouterMessage(dht::Key_t{}, 0, {rc}, false));
// DHTImmediateMessage gossip;
// gossip.msgs.emplace_back(new dht::GotRouterMessage(dht::Key_t{}, 0, {rc}, false));
std::vector<RouterID> gossipTo;
// std::vector<RouterID> gossipTo;
/*
* TODO: gossip RC via libquic

@ -17,11 +17,6 @@ namespace llarp
struct Router;
class EventLoop;
namespace dht
{
struct AbstractDHTMessageHandler;
} // namespace dht
namespace service
{
struct Context;

@ -12,8 +12,6 @@
#include <llarp/messages/dht.hpp>
#include <llarp/messages/link_message.hpp>
#include <llarp/net/net.hpp>
#include <llarp/tooling/peer_stats_event.hpp>
#include <llarp/tooling/router_event.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/meta/memfn.hpp>
@ -506,8 +504,9 @@ namespace llarp
bool
Router::ParseRoutingMessageBuffer(
const llarp_buffer_t&, routing::AbstractRoutingMessageHandler*, const PathID_t&)
const llarp_buffer_t&, path::AbstractHopHandler&, const PathID_t&)
{
// TODO: will go away with the removal of flush upstream/downstream
return false;
}
@ -1539,10 +1538,4 @@ namespace llarp
return *llarp::net::Platform::Default_ptr();
}
void
Router::handle_router_event(std::unique_ptr<tooling::RouterEvent> event) const
{
LogDebug(event->ToString());
}
} // namespace llarp

@ -18,13 +18,9 @@
#include <llarp/profiling.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/consensus/reachability_testing.hpp>
#include <llarp/tooling/router_event.hpp>
#include <llarp/routing/handler.hpp>
#include <llarp/routing/message_parser.hpp>
#include <llarp/rpc/lokid_rpc_client.hpp>
#include <llarp/rpc/rpc_server.hpp>
#include <llarp/service/context.hpp>
#include <stdexcept>
#include <llarp/util/buffer.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/mem.hpp>
@ -33,6 +29,7 @@
#include <llarp/util/time.hpp>
#include <llarp/util/service_manager.hpp>
#include <stdexcept>
#include <functional>
#include <list>
#include <map>
@ -109,7 +106,6 @@ namespace llarp
exit::Context _exit_context;
SecretKey _identity;
SecretKey _encryption;
std::shared_ptr<dht::AbstractDHTMessageHandler> _dh_t;
std::shared_ptr<Contacts> _contacts;
std::shared_ptr<NodeDB> _node_db;
llarp_time_t _started_at;
@ -162,10 +158,6 @@ namespace llarp
bool
insufficient_peers() const;
protected:
void
handle_router_event(std::unique_ptr<tooling::RouterEvent> event) const;
public:
void
for_each_connection(std::function<void(link::Connection&)> func);
@ -320,15 +312,6 @@ namespace llarp
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& unfunded);
template <class EventType, class... Params>
void
notify_router_event([[maybe_unused]] Params&&... args) const
{
// TODO: no-op when appropriate
auto event = std::make_unique<EventType>(args...);
handle_router_event(std::move(event));
}
void
queue_work(std::function<void(void)> func);
@ -536,7 +519,7 @@ namespace llarp
/// return false
bool
ParseRoutingMessageBuffer(
const llarp_buffer_t& buf, routing::AbstractRoutingMessageHandler* h, const PathID_t& rxid);
const llarp_buffer_t& buf, path::AbstractHopHandler& p, const PathID_t& rxid);
void
ConnectToRandomRouters(int N);

@ -95,10 +95,12 @@ namespace llarp
signature.from_string(btlc.consume_string());
signed_bt_dict = btlc.consume_string();
// TODO: parse bt dict
}
catch (...)
{
log::critical(llarp_cat, "Error: RouterContact failed to populate bt encoded contents!");
log::warning(llarp_cat, "Error: RouterContact failed to populate bt encoded contents!");
}
}
@ -114,7 +116,7 @@ namespace llarp
}
catch (...)
{
log::critical(llarp_cat, "Error: RouterContact failed to bt encode contents!");
log::warning(llarp_cat, "Error: RouterContact failed to bt encode contents!");
}
return std::move(btlp).str();
@ -154,7 +156,7 @@ namespace llarp
btdp.append("i", netID.ToView());
btdp.append("k", pubkey.bt_encode());
btdp.append("p", enckey.ToView());
btdp.append("r", routerVersion);
btdp.append("r", routerVersion->ToString());
if (not srvRecords.empty())
{
@ -280,8 +282,10 @@ namespace llarp
RouterContact::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictList("a", addr, read, key, buf))
return false;
// TOFIX: fuck everything about llarp_buffer_t
// if (!BEncodeMaybeReadDictEntry("a", addr, read, key, buf))
// return false;
if (!BEncodeMaybeReadDictEntry("i", netID, read, key, buf))
return false;

@ -131,8 +131,8 @@ namespace llarp
operator==(const RouterContact& other) const
{
return addr == other.addr && enckey == other.enckey && pubkey == other.pubkey
&& signature == other.signature
&& last_updated == other.last_updated && netID == other.netID;
&& signature == other.signature && last_updated == other.last_updated
&& netID == other.netID;
}
bool

@ -1,4 +1,5 @@
#include "endpoint_rpc.hpp"
#include <llarp/service/endpoint.hpp>
namespace llarp::rpc

@ -1,6 +1,8 @@
#pragma once
#include <llarp/service/auth.hpp>
#include <llarp/service/convotag.hpp>
#include <oxenmq/oxenmq.h>
namespace llarp::service
@ -24,7 +26,8 @@ namespace llarp::rpc
std::unordered_set<std::string> token_whitelist,
LMQ_ptr lmq,
Endpoint_ptr endpoint);
virtual ~EndpointAuthRPC() = default;
~EndpointAuthRPC() override = default;
void
Start();

@ -12,7 +12,6 @@
#include <nlohmann/json.hpp>
#include <llarp/exit/context.hpp>
#include <llarp/net/ip_range.hpp>
#include <llarp/quic/tunnel.hpp>
#include <llarp/service/context.hpp>
#include <llarp/service/outbound_context.hpp>
#include <llarp/service/auth.hpp>
@ -214,7 +213,8 @@ namespace llarp::rpc
if (quicconnect.request.closeID)
{
quic->forget(quicconnect.request.closeID);
// TODO:
// quic->forget(quicconnect.request.closeID);
SetJSONResponse("OK", quicconnect.response);
return;
}
@ -223,12 +223,13 @@ namespace llarp::rpc
try
{
auto [addr, id] = quic->open(
quicconnect.request.remoteHost, quicconnect.request.port, [](auto&&) {}, laddr);
// TODO:
// auto [addr, id] = quic->open(
// quicconnect.request.remoteHost, quicconnect.request.port, [](auto&&) {}, laddr);
util::StatusObject status;
status["addr"] = addr.ToString();
status["id"] = id;
// status["addr"] = addr.ToString();
// status["id"] = id;
SetJSONResponse(status, quicconnect.response);
}
@ -269,7 +270,8 @@ namespace llarp::rpc
if (quiclistener.request.closeID)
{
quic->forget(quiclistener.request.closeID);
// TODO:
// quic->forget(quiclistener.request.closeID);
SetJSONResponse("OK", quiclistener.response);
return;
}
@ -280,7 +282,8 @@ namespace llarp::rpc
try
{
SockAddr addr{quiclistener.request.remoteHost, huint16_t{quiclistener.request.port}};
id = quic->listen(addr);
// TODO:
// id = quic->listen(addr);
}
catch (std::exception& e)
{

@ -1,11 +1,12 @@
#include "auth.hpp"
#include <unordered_map>
#include "protocol.hpp"
#include <llarp/router/router.hpp>
#include "protocol.hpp"
#include <llarp/util/str.hpp>
#include <llarp/util/fs.hpp>
#include <unordered_map>
namespace llarp::service
{
/// maybe get auth result from string

@ -10,6 +10,7 @@
#include <llarp/dht/key.hpp>
#include <llarp/link/contacts.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/link/tunnel.hpp>
#include <llarp/messages/dht.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/net/ip_range.hpp>
@ -19,7 +20,6 @@
#include <llarp/router/router.hpp>
#include <llarp/router/route_poker.hpp>
#include <llarp/tooling/dht_event.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/meta/memfn.hpp>
@ -50,7 +50,7 @@ namespace llarp::service
_recv_event_queue.enable();
if (Loop()->MaybeGetUVWLoop())
_tunnel_manager = std::make_unique<quic::TunnelManager>(*this);
_tunnel_manager = std::make_unique<link::TunnelManager>(*this);
}
bool
@ -167,7 +167,7 @@ namespace llarp::service
auto result = ptr->EnsurePathToService(
saddr,
[ptr, name, ranges, result_handler, poker](auto addr, auto* ctx) {
[ptr, name, ranges, result_handler, poker](auto addr, OutboundContext* ctx) {
if (ctx == nullptr)
{
result_handler(false, "could not establish flow to {}"_format(name));
@ -175,24 +175,23 @@ namespace llarp::service
}
// make a lambda that sends the reply after doing auth
auto apply_result =
[ptr, poker, addr, result_handler, ranges](AuthResult result) {
if (result.code != AuthResultCode::eAuthAccepted)
{
result_handler(false, result.reason);
return;
}
auto apply_result = [ptr, poker, addr, result_handler, ranges](
std::string result, bool success) {
if (success)
{
for (const auto& range : ranges)
ptr->MapExitRange(range, addr);
for (const auto& range : ranges)
ptr->MapExitRange(range, addr);
if (poker)
poker->put_up();
if (poker)
poker->put_up();
result_handler(true, result);
}
result_handler(true, result.reason);
};
result_handler(false, result);
};
ctx->AsyncSendAuth(apply_result);
ctx->send_auth_async(apply_result);
},
ptr->PathAlignmentTimeout());
@ -662,11 +661,12 @@ namespace llarp::service
}
}
// add quic ethertype if we have listeners set up
if (auto* quic = GetQUICTunnel())
{
if (quic->hasListeners())
intro_set().supported_protocols.push_back(ProtocolType::QUIC);
}
// if (auto* quic = GetQUICTunnel())
// {
// TODO:
// if (quic->hasListeners())
// intro_set().supported_protocols.push_back(ProtocolType::QUIC);
// }
intro_set().intros.clear();
for (auto& intro : intros)
@ -730,7 +730,7 @@ namespace llarp::service
return _state->remote_sessions.size() + _state->snode_sessions.size();
}
constexpr auto PublishIntrosetTimeout = 20s;
[[maybe_unused]] constexpr auto PublishIntrosetTimeout = 20s;
void
Endpoint::ResetInternalState()
@ -784,7 +784,7 @@ namespace llarp::service
constexpr auto MaxOutboundContextPerRemote = 1;
void
Endpoint::PutNewOutboundContext(const service::IntroSet& introset, llarp_time_t left)
Endpoint::PutNewOutboundContext(const service::IntroSet& introset, llarp_time_t)
{
const Address addr{introset.address_keys.Addr()};
@ -799,8 +799,9 @@ namespace llarp::service
auto sessionRange = remoteSessions.equal_range(addr);
for (auto itr = sessionRange.first; itr != sessionRange.second; ++itr)
{
itr->second->AddReadyHook(
[addr, this](auto session) { InformPathToService(addr, session); }, left);
// TODO:
// itr->second->AddReadyHook(
// [addr, this](auto session) { InformPathToService(addr, session); }, left);
}
}
@ -1058,7 +1059,7 @@ namespace llarp::service
void
Endpoint::SendAuthResult(
path::Path_ptr path, PathID_t replyPath, ConvoTag tag, std::string result, bool success)
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)
@ -1109,8 +1110,10 @@ namespace llarp::service
return;
}
}
_send_queue.tryPushBack(
SendEvent{std::make_shared<routing::PathTransferMessage>(f, replyPath), path});
// TODO:
// _send_queue.tryPushBack(
// SendEvent{std::make_shared<routing::PathTransferMessage>(f, replyPath), path});
}
void
@ -1120,7 +1123,7 @@ namespace llarp::service
}
void
Endpoint::ResetConvoTag(ConvoTag tag, path::Path_ptr p, PathID_t from)
Endpoint::ResetConvoTag(ConvoTag tag, path::Path_ptr p, PathID_t /* from */)
{
// send reset convo tag message
ProtocolFrameMessage f{};
@ -1131,8 +1134,9 @@ namespace llarp::service
{
LogWarn("invalidating convotag T=", tag);
RemoveConvoTag(tag);
_send_queue.tryPushBack(
SendEvent{std::make_shared<routing::PathTransferMessage>(f, from), p});
// TODO:
// _send_queue.tryPushBack(
// SendEvent{std::make_shared<routing::PathTransferMessage>(f, from), p});
}
}
@ -1235,12 +1239,12 @@ namespace llarp::service
[hook](auto, auto* ctx) -> bool {
if (ctx)
{
hook(ctx->currentConvoTag);
}
else
{
hook(std::nullopt);
hook(ctx->get_current_tag());
return true;
}
hook(std::nullopt);
return false;
},
timeout);
}
@ -1436,7 +1440,7 @@ namespace llarp::service
}
void
Endpoint::Pump(llarp_time_t now)
Endpoint::Pump(llarp_time_t)
{
FlushRecvData();
// send downstream packets to user for snode
@ -1462,39 +1466,38 @@ namespace llarp::service
msg.tag,
msg.payload.size());
if (HandleInboundPacket(msg.tag, msg.payload, msg.proto, msg.seqno))
{
ConvoTagRX(msg.tag);
}
else
{
LogWarn("Failed to handle inbound message");
}
// if (HandleInboundPacket(msg.tag, msg.payload, msg.proto, msg.seqno))
// {
// ConvoTagRX(msg.tag);
// }
// else
// {
// 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)
{
outctx->FlushUpstream();
outctx->Pump(now);
}
// TODO: locking on this container
for (const auto& [r, session] : _state->snode_sessions)
session->FlushUpstream();
// for (const auto& [addr, outctx] : _state->remote_sessions)
// {
// outctx->FlushUpstream();
// outctx->Pump(now);
// }
// // TODO: locking on this container
// for (const auto& [r, session] : _state->snode_sessions)
// session->FlushUpstream();
// send queue flush
while (not _send_queue.empty())
{
SendEvent item = _send_queue.popFront();
item.first->sequence_number = item.second->NextSeqNo();
if (item.second->SendRoutingMessage(*item.first, r))
ConvoTagTX(item.first->protocol_frame_msg.convo_tag);
}
// // send queue flush
// while (not _send_queue.empty())
// {
// SendEvent item = _send_queue.popFront();
// item.first->sequence_number = item.second->NextSeqNo();
// if (item.second->SendRoutingMessage(*item.first, r))
// ConvoTagTX(item.first->protocol_frame_msg.convo_tag);
// }
UpstreamFlush(r);
}
@ -1544,14 +1547,15 @@ namespace llarp::service
auto itr = range.first;
while (itr != range.second)
{
if (itr->second->ReadyToSend() and itr->second->estimatedRTT > 0s)
{
if (itr->second->estimatedRTT < rtt)
{
ret = tag;
rtt = itr->second->estimatedRTT;
}
}
// TODO:
// if (itr->second->ReadyToSend() and itr->second->estimatedRTT > 0s)
// {
// if (itr->second->estimatedRTT < rtt)
// {
// ret = tag;
// rtt = itr->second->estimatedRTT;
// }
// }
itr++;
}
}
@ -1712,7 +1716,7 @@ namespace llarp::service
return itr->second;
}
quic::TunnelManager*
link::TunnelManager*
Endpoint::GetQUICTunnel()
{
return _tunnel_manager.get();

@ -68,9 +68,8 @@ namespace llarp
std::shared_ptr<ProtocolMessage> msg;
};
struct Endpoint : public path::Builder,
public EndpointBase,
public std::enable_shared_from_this<Endpoint>
struct Endpoint : public path::Builder, public EndpointBase
// public std::enable_shared_from_this<Endpoint>
{
Endpoint(Router* r, Context* parent);
~Endpoint() override;
@ -446,7 +445,7 @@ namespace llarp
/// Returns a pointer to the quic::Tunnel object handling quic connections for this endpoint.
/// Returns nullptr if quic is not supported.
quic::TunnelManager*
link::TunnelManager*
GetQUICTunnel() override;
protected:
@ -500,7 +499,7 @@ namespace llarp
std::unique_ptr<EndpointState> _state;
std::shared_ptr<IAuthPolicy> _auth_policy;
std::unordered_map<Address, AuthInfo> _remote_auth_infos;
std::unique_ptr<quic::TunnelManager> _tunnel_manager;
std::unique_ptr<link::TunnelManager> _tunnel_manager;
/// (ons name, optional exit range, optional auth info) for looking up on startup
std::unordered_map<std::string, std::pair<std::optional<IPRange>, std::optional<AuthInfo>>>

@ -5,68 +5,61 @@
#include "outbound_context.hpp"
#include <llarp/util/str.hpp>
namespace llarp
namespace llarp::service
{
namespace service
bool
EndpointState::Configure(const NetworkConfig& conf)
{
bool
EndpointState::Configure(const NetworkConfig& conf)
{
if (conf.m_keyfile.has_value())
key_file = conf.m_keyfile->string();
snode_blacklist = conf.m_snodeBlacklist;
is_exit_enabled = conf.m_AllowExit;
for (const auto& record : conf.m_SRVRecords)
{
local_introset.SRVs.push_back(record.toTuple());
}
if (conf.m_keyfile.has_value())
key_file = conf.m_keyfile->string();
snode_blacklist = conf.m_snodeBlacklist;
is_exit_enabled = conf.m_AllowExit;
return true;
for (const auto& record : conf.m_SRVRecords)
{
local_introset.SRVs.push_back(record.toTuple());
}
util::StatusObject
EndpointState::ExtractStatus(util::StatusObject& obj) const
{
obj["lastPublished"] = to_json(last_publish);
obj["lastPublishAttempt"] = to_json(last_publish_attempt);
obj["introset"] = local_introset.ExtractStatus();
static auto getSecond = [](const auto& item) -> auto
{
return item.second->ExtractStatus();
};
return true;
}
std::transform(
dead_sessions.begin(),
dead_sessions.end(),
std::back_inserter(obj["deadSessions"]),
getSecond);
std::transform(
remote_sessions.begin(),
remote_sessions.end(),
std::back_inserter(obj["remoteSessions"]),
getSecond);
std::transform(
pending_lookups.begin(),
pending_lookups.end(),
std::back_inserter(obj["lookups"]),
getSecond);
std::transform(
snode_sessions.begin(),
snode_sessions.end(),
std::back_inserter(obj["snodeSessions"]),
[](const auto& item) { return item.second->ExtractStatus(); });
util::StatusObject
EndpointState::ExtractStatus(util::StatusObject& obj) const
{
obj["lastPublished"] = to_json(last_publish);
obj["lastPublishAttempt"] = to_json(last_publish_attempt);
obj["introset"] = local_introset.ExtractStatus();
// static auto getSecond = [](const auto& item) -> auto
// {
// return item.second.ExtractStatus();
// };
util::StatusObject sessionObj{};
// std::transform(
// dead_sessions.begin(),
// dead_sessions.end(),
// std::back_inserter(obj["deadSessions"]),
// getSecond);
// std::transform(
// remote_sessions.begin(),
// remote_sessions.end(),
// std::back_inserter(obj["remoteSessions"]),
// getSecond);
// std::transform(
// snode_sessions.begin(),
// snode_sessions.end(),
// std::back_inserter(obj["snodeSessions"]),
// [](const auto& item) { return item.second->ExtractStatus(); });
for (const auto& item : m_Sessions)
{
std::string k = item.first.ToHex();
sessionObj[k] = item.second.ExtractStatus();
}
util::StatusObject sessionObj{};
obj["converstations"] = sessionObj;
return obj;
}
} // namespace service
} // namespace llarp
// TODO:
// for (const auto& item : m_Sessions)
// {
// std::string k = item.first.ToHex();
// sessionObj[k] = item.second.ExtractStatus();
// }
obj["converstations"] = sessionObj;
return obj;
}
} // namespace llarp::service

@ -1,197 +1,172 @@
#include "endpoint_util.hpp"
#include <llarp/exit/session.hpp>
#include "outbound_context.hpp"
#include "lookup.hpp"
#include <llarp/exit/session.hpp>
#include <llarp/util/logging.hpp>
namespace llarp
namespace llarp::service
{
namespace service
void
EndpointUtil::ExpireSNodeSessions(llarp_time_t now, SNodeConnectionMap& sessions)
{
void
EndpointUtil::ExpireSNodeSessions(llarp_time_t now, SNodeConnectionMap& sessions)
auto itr = sessions.begin();
while (itr != sessions.end())
{
auto itr = sessions.begin();
while (itr != sessions.end())
if (itr->second->ShouldRemove() && itr->second->IsStopped())
{
if (itr->second->ShouldRemove() && itr->second->IsStopped())
{
itr = sessions.erase(itr);
continue;
}
// expunge next tick
if (itr->second->IsExpired(now))
{
itr->second->Stop();
}
else
{
itr->second->Tick(now);
}
++itr;
itr = sessions.erase(itr);
continue;
}
}
void
EndpointUtil::ExpirePendingTx(llarp_time_t now, PendingLookupsMap& lookups)
{
std::vector<std::unique_ptr<IServiceLookup>> timedout;
for (auto itr = lookups.begin(); itr != lookups.end();)
// expunge next tick
if (itr->second->IsExpired(now))
{
if (!itr->second->IsTimedOut(now))
{
++itr;
continue;
}
timedout.emplace_back(std::move(itr->second));
itr = lookups.erase(itr);
itr->second->Stop();
}
for (const auto& lookup : timedout)
else
{
LogWarn(lookup->name, " timed out txid=", lookup->txid);
lookup->HandleTimeout();
itr->second->Tick(now);
}
++itr;
}
}
void
EndpointUtil::ExpirePendingRouterLookups(llarp_time_t now, PendingRoutersMap& routers)
void
EndpointUtil::ExpirePendingRouterLookups(llarp_time_t now, PendingRoutersMap& routers)
{
for (auto itr = routers.begin(); itr != routers.end();)
{
for (auto itr = routers.begin(); itr != routers.end();)
if (!itr->second.IsExpired(now))
{
if (!itr->second.IsExpired(now))
{
++itr;
continue;
}
LogWarn("lookup for ", itr->first, " timed out");
itr->second.InformResult({});
itr = routers.erase(itr);
++itr;
continue;
}
LogWarn("lookup for ", itr->first, " timed out");
itr->second.InformResult({});
itr = routers.erase(itr);
}
}
void
EndpointUtil::DeregisterDeadSessions(llarp_time_t now, ConnectionMap& sessions)
void
EndpointUtil::DeregisterDeadSessions(llarp_time_t now, ConnectionMap& sessions)
{
auto itr = sessions.begin();
while (itr != sessions.end())
{
auto itr = sessions.begin();
while (itr != sessions.end())
if (itr->second->IsDone(now))
{
if (itr->second->IsDone(now))
{
itr = sessions.erase(itr);
}
else
{
++itr;
}
itr = sessions.erase(itr);
}
else
{
++itr;
}
}
}
void
EndpointUtil::TickRemoteSessions(
llarp_time_t now,
ConnectionMap& remoteSessions,
ConnectionMap& deadSessions,
std::unordered_map<ConvoTag, Session>& sessions)
void
EndpointUtil::TickRemoteSessions(
llarp_time_t now,
ConnectionMap& remoteSessions,
ConnectionMap& deadSessions,
std::unordered_map<ConvoTag, Session>& sessions)
{
auto itr = remoteSessions.begin();
while (itr != remoteSessions.end())
{
auto itr = remoteSessions.begin();
while (itr != remoteSessions.end())
itr->second->Tick(now);
if (itr->second->Pump(now))
{
itr->second->Tick(now);
if (itr->second->Pump(now))
{
LogInfo(
"marking session as dead T=",
itr->second->currentConvoTag,
" to ",
itr->second->Addr());
itr->second->Stop();
sessions.erase(itr->second->currentConvoTag);
deadSessions.emplace(std::move(*itr));
itr = remoteSessions.erase(itr);
}
else
{
++itr;
}
LogInfo(
"marking session as dead T=",
itr->second->get_current_tag(),
" to ",
itr->second->Addr());
itr->second->Stop();
sessions.erase(itr->second->get_current_tag());
deadSessions.emplace(std::move(*itr));
itr = remoteSessions.erase(itr);
}
for (auto& item : deadSessions)
else
{
item.second->Tick(now);
++itr;
}
}
for (auto& item : deadSessions)
{
item.second->Tick(now);
}
}
void
EndpointUtil::ExpireConvoSessions(
llarp_time_t now, std::unordered_map<ConvoTag, Session>& sessions)
void
EndpointUtil::ExpireConvoSessions(
llarp_time_t now, std::unordered_map<ConvoTag, Session>& sessions)
{
auto itr = sessions.begin();
while (itr != sessions.end())
{
auto itr = sessions.begin();
while (itr != sessions.end())
if (itr->second.IsExpired(now))
{
if (itr->second.IsExpired(now))
{
LogInfo("Expire session T=", itr->first, " to ", itr->second.Addr());
itr = sessions.erase(itr);
}
else
++itr;
LogInfo("Expire session T=", itr->first, " to ", itr->second.Addr());
itr = sessions.erase(itr);
}
else
++itr;
}
}
void
EndpointUtil::StopRemoteSessions(ConnectionMap& remoteSessions)
void
EndpointUtil::StopRemoteSessions(ConnectionMap& remoteSessions)
{
for (auto& item : remoteSessions)
{
for (auto& item : remoteSessions)
{
item.second->Stop();
}
item.second->Stop();
}
}
void
EndpointUtil::StopSnodeSessions(SNodeConnectionMap& sessions)
void
EndpointUtil::StopSnodeSessions(SNodeConnectionMap& sessions)
{
for (auto& item : sessions)
{
for (auto& item : sessions)
{
item.second->Stop();
}
item.second->Stop();
}
}
bool
EndpointUtil::HasPathToService(const Address& addr, const ConnectionMap& remoteSessions)
bool
EndpointUtil::HasPathToService(const Address& addr, const ConnectionMap& remoteSessions)
{
auto range = remoteSessions.equal_range(addr);
auto itr = range.first;
while (itr != range.second)
{
auto range = remoteSessions.equal_range(addr);
auto itr = range.first;
while (itr != range.second)
{
if (itr->second->ReadyToSend())
return true;
++itr;
}
return false;
if (itr->second->ReadyToSend())
return true;
++itr;
}
return false;
}
bool
EndpointUtil::GetConvoTagsForService(
const std::unordered_map<ConvoTag, Session>& sessions,
const Address& info,
std::set<ConvoTag>& tags)
bool
EndpointUtil::GetConvoTagsForService(
const std::unordered_map<ConvoTag, Session>& sessions,
const Address& info,
std::set<ConvoTag>& tags)
{
bool inserted = false;
auto itr = sessions.begin();
while (itr != sessions.end())
{
bool inserted = false;
auto itr = sessions.begin();
while (itr != sessions.end())
if (itr->second.remote.Addr() == info)
{
if (itr->second.remote.Addr() == info)
if (tags.emplace(itr->first).second)
{
if (tags.emplace(itr->first).second)
{
inserted = true;
}
inserted = true;
}
++itr;
}
return inserted;
++itr;
}
} // namespace service
} // namespace llarp
return inserted;
}
} // namespace llarp::service

@ -9,9 +9,6 @@ namespace llarp::service
static void
ExpireSNodeSessions(llarp_time_t now, SNodeConnectionMap& sessions);
static void
ExpirePendingTx(llarp_time_t now, PendingLookupsMap& lookups);
static void
ExpirePendingRouterLookups(llarp_time_t now, PendingRoutersMap& routers);

@ -334,7 +334,7 @@ namespace llarp::service
auto sublist = btdc.consume_list_consumer();
while (not sublist.is_finished())
{
supported_protocols.emplace_back(sublist.consume_integer<uint64_t>());
supported_protocols.emplace_back(ProtocolType{sublist.consume_integer<uint64_t>()});
}
}

@ -84,47 +84,6 @@ namespace llarp::service
return addr;
}
bool
OutboundContext::OnIntroSetUpdate(
const Address&,
std::optional<IntroSet> foundIntro,
const RouterID& endpoint,
std::chrono::milliseconds,
uint64_t relayOrder)
{
if (marked_bad)
return true;
updatingIntroSet = false;
if (foundIntro)
{
if (foundIntro->time_signed == 0s)
{
LogWarn(Name(), " got introset with zero timestamp: ", *foundIntro);
return true;
}
if (current_intro.time_signed > foundIntro->time_signed)
{
LogInfo("introset is old, dropping");
return true;
}
const std::chrono::milliseconds now = Now();
if (foundIntro->IsExpired(now))
{
LogError("got expired introset from lookup from ", endpoint);
return true;
}
current_intro = *foundIntro;
ShiftIntroRouter(RouterID{});
}
else if (relayOrder > 0)
{
++lookup_fails;
LogWarn(Name(), " failed to look up introset, fails=", lookup_fails);
}
return true;
}
bool
OutboundContext::ReadyToSend() const
{
@ -215,28 +174,58 @@ namespace llarp::service
log::info(link_cat, "{} updating introset", Name());
last_introset_update = now;
// we want to use the parent endpoint's paths because outbound context
// does not implement path::PathSet::HandleGotIntroMessage
const auto paths = GetManyPathsWithUniqueEndpoints(&ep, 2, location);
[[maybe_unused]] uint64_t relayOrder = 0;
uint64_t relayOrder = 0;
for ([[maybe_unused]] const auto& path : paths)
for (const auto& path : paths)
{
// TODO: implement this
// HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
// m_Endpoint,
// util::memFn(&OutboundContext::OnIntroSetUpdate, shared_from_this()),
// location,
// PubKey{addr.as_array()},
// path->Endpoint(),
// relayOrder,
// m_Endpoint->GenTXID(),
// (IntrosetUpdateInterval / 2) + (2 * path->intro.latency) +
// IntrosetLookupGraceInterval);
// relayOrder++;
// if (job->SendRequestViaPath(path, m_Endpoint->router()))
// updatingIntroSet = true;
path->find_intro(location, false, relayOrder, [this](oxen::quic::message m) mutable {
if (marked_bad)
{
log::info(link_cat, "Outbound context has been marked bad (whatever that means)");
return;
}
updatingIntroSet = false;
if (m)
{
std::string introset;
try
{
oxenc::bt_dict_consumer btdc{m.body()};
introset = btdc.require<std::string>("INTROSET");
}
catch (...)
{
log::warning(link_cat, "Failed to parse find name response!");
throw;
}
service::EncryptedIntroSet enc{introset};
const auto intro = enc.decrypt(PubKey{addr.as_array()});
if (intro.time_signed == 0s)
{
log::warning(link_cat, "{} recieved introset with zero timestamp");
return;
}
if (current_intro.time_signed > intro.time_signed)
{
log::info(link_cat, "{} received outdated introset; dropping", Name());
return;
}
if (intro.IsExpired(llarp::time_now_ms()))
{
log::warning(link_cat, "{} received expired introset", Name());
return;
}
current_intro = intro;
ShiftIntroRouter();
}
});
}
}
@ -544,7 +533,7 @@ namespace llarp::service
ep.GetIdentity(),
current_intro.sntru_pubkey,
remote_intro,
ep,
&ep,
current_tag);
if (const auto maybe = ep.MaybeGetAuthInfoForEndpoint(remote_identity.Addr()); not maybe)

@ -58,6 +58,12 @@ namespace llarp::service
~OutboundContext() override;
ConvoTag
get_current_tag() const
{
return current_tag;
}
void
gen_intro_async(std::string payload);
@ -111,7 +117,7 @@ namespace llarp::service
/// shift the intro off the current router it is using
void
ShiftIntroRouter(const RouterID remote);
ShiftIntroRouter(const RouterID remote = RouterID{});
/// return true if we are ready to send
bool
@ -166,14 +172,6 @@ namespace llarp::service
std::chrono::milliseconds
RTT() const;
bool
OnIntroSetUpdate(
const Address& addr,
std::optional<IntroSet> i,
const RouterID& endpoint,
std::chrono::milliseconds,
uint64_t relayOrder);
private:
/// swap remoteIntro with next intro
void

@ -275,7 +275,7 @@ namespace llarp::service
if (bte.empty())
{
log::error(logcat, "Failed to decode inner protocol message");
DumpBuffer(*buf);
// DumpBuffer(*buf);
self->msg.reset();
return;
}
@ -304,8 +304,12 @@ namespace llarp::service
// PKE (A, B, N)
SharedSecret shared_secret;
path_dh_func dh_server = [crypto = CryptoManager::instance()](auto&& params...) -> bool {
return crypto->dh_server(std::forward<decltype(params)>(params));
path_dh_func dh_server = [crypto = CryptoManager::instance()](
llarp::SharedSecret& shared,
const PubKey& pk,
const SecretKey& sk,
const TunnelNonce& n) -> bool {
return crypto->dh_server(shared, pk, sk, n);
};
if (!self->m_LocalIdentity.KeyExchange(

@ -1,168 +0,0 @@
#include "sendcontext.hpp"
#include <llarp/path/path.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_transfer_message.hpp>
#include "endpoint.hpp"
#include <utility>
#include <unordered_set>
#include <llarp/crypto/crypto.hpp>
namespace llarp::service
{
static constexpr size_t SendContextQueueSize = 512;
SendContext::SendContext(
ServiceInfo ident, const Introduction& intro, path::PathSet* send, Endpoint* ep)
: remoteIdent(std::move(ident))
, remoteIntro(intro)
, m_PathSet(send)
, service_endpoint(ep)
, createdAt(ep->Now())
{}
bool
SendContext::Send(std::shared_ptr<ProtocolFrameMessage> msg, path::Path_ptr path)
{
if (path->IsReady()
and m_SendQueue.tryPushBack(std::make_pair(
std::make_shared<routing::PathTransferMessage>(*msg, remoteIntro.path_id), path))
== thread::QueueReturn::Success)
{
service_endpoint->router()->TriggerPump();
return true;
}
return false;
}
void
SendContext::FlushUpstream()
{
auto r = service_endpoint->router();
std::unordered_set<path::Path_ptr, path::Ptr_Hash> flushpaths;
auto rttRMS = 0ms;
while (auto maybe = m_SendQueue.tryPopFront())
{
auto& [msg, path] = *maybe;
msg->sequence_number = path->NextSeqNo();
if (path->SendRoutingMessage(*msg, r))
{
lastGoodSend = r->now();
flushpaths.emplace(path);
service_endpoint->ConvoTagTX(msg->protocol_frame_msg.convo_tag);
const auto rtt = (path->intro.latency + remoteIntro.latency) * 2;
rttRMS += rtt * rtt.count();
}
}
// flush the select path's upstream
for (const auto& path : flushpaths)
{
path->FlushUpstream(r);
}
if (flushpaths.empty())
return;
estimatedRTT = std::chrono::milliseconds{
static_cast<int64_t>(std::sqrt(rttRMS.count() / flushpaths.size()))};
}
/// send on an established convo tag
void
SendContext::EncryptAndSendTo(const llarp_buffer_t& payload, ProtocolType t)
{
SharedSecret shared;
auto f = std::make_shared<ProtocolFrameMessage>();
f->flag = 0;
f->nonce.Randomize();
f->convo_tag = currentConvoTag;
f->sequence_number = ++sequenceNo;
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
if (!path)
{
ShiftIntroRouter(remoteIntro.router);
LogWarn(m_PathSet->Name(), " cannot encrypt and send: no path for intro ", remoteIntro);
return;
}
if (!service_endpoint->GetCachedSessionKeyFor(f->convo_tag, shared))
{
LogWarn(
m_PathSet->Name(),
" could not send, has no cached session key on session T=",
f->convo_tag);
return;
}
auto m = std::make_shared<ProtocolMessage>();
service_endpoint->PutIntroFor(f->convo_tag, remoteIntro);
service_endpoint->PutReplyIntroFor(f->convo_tag, path->intro);
m->proto = t;
if (auto maybe = service_endpoint->GetSeqNoForConvo(f->convo_tag))
{
m->seqno = *maybe;
}
else
{
LogWarn(m_PathSet->Name(), " could not get sequence number for session T=", f->convo_tag);
return;
}
m->introReply = path->intro;
f->path_id = m->introReply.path_id;
m->sender = service_endpoint->GetIdentity().pub;
m->tag = f->convo_tag;
m->put_buffer(payload);
service_endpoint->router()->queue_work([f, m, shared, path, this] {
if (not f->EncryptAndSign(*m, shared, service_endpoint->GetIdentity()))
{
LogError(m_PathSet->Name(), " failed to sign message");
return;
}
Send(f, path);
});
}
void
SendContext::AsyncSendAuth(std::function<void(AuthResult)> resultHandler)
{
if (const auto maybe = service_endpoint->MaybeGetAuthInfoForEndpoint(remoteIdent.Addr()))
{
// send auth message
const llarp_buffer_t authdata{maybe->token};
AsyncGenIntro(authdata, ProtocolType::Auth);
authResultListener = resultHandler;
}
else
resultHandler({AuthResultCode::eAuthAccepted, "no auth needed"});
}
void
SendContext::AsyncEncryptAndSendTo(const llarp_buffer_t& data, ProtocolType protocol)
{
if (IntroSent())
{
EncryptAndSendTo(data, protocol);
return;
}
// have we generated the initial intro but not sent it yet? bail here so we don't cause
// bullshittery
if (IntroGenerated() and not IntroSent())
{
LogWarn(
m_PathSet->Name(),
" we have generated an intial handshake but have not sent it yet so we drop a packet "
"to prevent bullshittery");
return;
}
const auto maybe = service_endpoint->MaybeGetAuthInfoForEndpoint(remoteIdent.Addr());
if (maybe.has_value())
{
// send auth message
const llarp_buffer_t authdata(maybe->token);
AsyncGenIntro(authdata, ProtocolType::Auth);
}
else
{
AsyncGenIntro(data, protocol);
}
}
} // namespace llarp::service

@ -1,85 +0,0 @@
#pragma once
#include "intro.hpp"
#include "protocol.hpp"
#include <llarp/path/pathset.hpp>
#include <llarp/constants/path.hpp>
#include <llarp/service/convotag.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/types.hpp>
#include <llarp/util/thread/queue.hpp>
#include <deque>
namespace llarp::service
{
struct ServiceInfo;
struct Endpoint;
struct Introduction;
struct SendContext
{
SendContext(ServiceInfo ident, const Introduction& intro, path::PathSet* send, Endpoint* ep);
void
AsyncEncryptAndSendTo(const llarp_buffer_t& payload, ProtocolType t);
/// queue send a fully encrypted hidden service frame
/// via a path
bool
Send(std::shared_ptr<ProtocolFrameMessage> f, path::Path_ptr path);
/// flush upstream traffic when in router thread
void
FlushUpstream();
SharedSecret sharedKey;
ServiceInfo remoteIdent;
Introduction remoteIntro;
ConvoTag currentConvoTag;
path::PathSet* const m_PathSet;
// Endpoint* const m_DataHandler;
Endpoint* const service_endpoint;
uint64_t sequenceNo = 0;
llarp_time_t lastGoodSend = 0s;
const llarp_time_t createdAt;
llarp_time_t sendTimeout = path::BUILD_TIMEOUT;
llarp_time_t connectTimeout = path::BUILD_TIMEOUT * 2;
llarp_time_t shiftTimeout = (path::BUILD_TIMEOUT * 5) / 2;
llarp_time_t estimatedRTT = 0s;
bool markedBad = false;
std::function<void(AuthResult)> authResultListener;
virtual bool
ShiftIntroduction(bool rebuild = true)
{
(void)rebuild;
return true;
}
virtual void
ShiftIntroRouter(const RouterID) = 0;
virtual void
UpdateIntroSet() = 0;
virtual void
MarkCurrentIntroBad(llarp_time_t now) = 0;
void
AsyncSendAuth(std::function<void(AuthResult)> replyHandler);
private:
virtual bool
IntroGenerated() const = 0;
virtual bool
IntroSent() const = 0;
void
EncryptAndSendTo(const llarp_buffer_t& payload, ProtocolType t);
virtual void
AsyncGenIntro(const llarp_buffer_t& payload, ProtocolType t) = 0;
};
} // namespace llarp::service

@ -1,130 +0,0 @@
#pragma once
#include "router_event.hpp"
#include <llarp/dht/key.hpp>
#include <llarp/service/intro_set.hpp>
#include <llarp/dht/messages/findrouter.hpp>
namespace tooling
{
struct PubIntroSentEvent : public RouterEvent
{
llarp::dht::Key_t introsetPubkey;
llarp::RouterID relay;
uint64_t relayIndex;
PubIntroSentEvent(
const llarp::RouterID& ourRouter,
const llarp::dht::Key_t& introsetPubkey_,
const llarp::RouterID& relay_,
uint64_t relayIndex_)
: RouterEvent("DHT: PubIntroSentEvent", ourRouter, false)
, introsetPubkey(introsetPubkey_)
, relay(relay_)
, relayIndex(relayIndex_)
{}
std::string
ToString() const
{
return RouterEvent::ToString() + " ---- introset pubkey: " + introsetPubkey.ShortHex()
+ ", relay: " + relay.ShortString() + ", relayIndex: " + std::to_string(relayIndex);
}
};
struct PubIntroReceivedEvent : public RouterEvent
{
llarp::dht::Key_t from;
llarp::dht::Key_t location;
uint64_t txid;
uint64_t relayOrder;
PubIntroReceivedEvent(
const llarp::RouterID& ourRouter,
const llarp::dht::Key_t& from_,
const llarp::dht::Key_t& location_,
uint64_t txid_,
uint64_t relayOrder_)
: RouterEvent("DHT: PubIntroReceivedEvent", ourRouter, true)
, from(from_)
, location(location_)
, txid(txid_)
, relayOrder(relayOrder_)
{}
std::string
ToString() const override
{
return RouterEvent::ToString() + "from " + from.ShortHex()
+ " location=" + location.ShortHex() + " order=" + std::to_string(relayOrder)
+ " txid=" + std::to_string(txid);
}
};
struct GotIntroReceivedEvent : public RouterEvent
{
llarp::dht::Key_t From;
llarp::service::EncryptedIntroSet Introset;
uint64_t RelayOrder;
uint64_t TxID;
GotIntroReceivedEvent(
const llarp::RouterID& ourRouter_,
const llarp::dht::Key_t& from_,
const llarp::service::EncryptedIntroSet& introset_,
uint64_t txid_)
: RouterEvent("DHT:: GotIntroReceivedEvent", ourRouter_, true)
, From(from_)
, Introset(introset_)
, TxID(txid_)
{}
std::string
ToString() const override
{
return RouterEvent::ToString() + "from " + From.ShortHex()
+ " location=" + Introset.derivedSigningKey.ShortHex()
+ " order=" + std::to_string(RelayOrder) + " txid=" + std::to_string(TxID);
}
};
struct FindRouterEvent : public RouterEvent
{
llarp::dht::Key_t from;
llarp::RouterID targetKey;
bool iterative;
bool exploritory;
uint64_t txid;
uint64_t version;
FindRouterEvent(const llarp::RouterID& ourRouter, const llarp::dht::FindRouterMessage& msg)
: RouterEvent("DHT: FindRouterEvent", ourRouter, true)
, from(msg.From)
, targetKey(msg.targetKey)
, iterative(msg.iterative)
, exploritory(msg.exploratory)
, txid(msg.txid)
, version(msg.version)
{}
std::string
ToString() const override
{
return RouterEvent::ToString() + " from " + from.ShortHex()
+ ", targetKey: " + targetKey.ToString() + ", iterative: " + std::to_string(iterative)
+ ", exploritory " + std::to_string(exploritory) + ", txid " + std::to_string(txid)
+ ", version " + std::to_string(version);
}
};
struct FindRouterReceivedEvent : public FindRouterEvent
{
using FindRouterEvent::FindRouterEvent;
};
struct FindRouterSentEvent : public FindRouterEvent
{
using FindRouterEvent::FindRouterEvent;
};
} // namespace tooling

@ -1,30 +0,0 @@
#include "hive_context.hpp"
#include "hive_router.hpp"
namespace tooling
{
HiveContext::HiveContext(RouterHive* hive) : m_hive(hive)
{}
std::shared_ptr<llarp::Router>
HiveContext::makeRouter(const llarp::EventLoop_ptr& loop)
{
return std::make_shared<HiveRouter>(loop, makeVPNPlatform(), m_hive);
}
HiveRouter*
HiveContext::getRouterAsHiveRouter()
{
if (not router)
return nullptr;
HiveRouter* hiveRouter = dynamic_cast<HiveRouter*>(router.get());
if (hiveRouter == nullptr)
throw std::runtime_error("HiveContext has a router not of type HiveRouter");
return hiveRouter;
}
} // namespace tooling

@ -1,28 +0,0 @@
#pragma once
#include <llarp.hpp>
#include "hive_router.hpp"
namespace tooling
{
/// HiveContext is a subclass of llarp::Context which allows RouterHive to
/// perform custom behavior which might be undesirable in production code.
struct HiveContext : public llarp::Context
{
HiveContext(RouterHive* hive);
std::shared_ptr<llarp::Router>
makeRouter(const llarp::EventLoop_ptr& loop) override;
/// Get this context's router as a HiveRouter.
///
/// Returns nullptr if there is no router or throws an exception if the
/// router is somehow not an instance of HiveRouter.
HiveRouter*
getRouterAsHiveRouter();
protected:
RouterHive* m_hive = nullptr;
};
} // namespace tooling

@ -1,36 +0,0 @@
#include "hive_router.hpp"
#include "router_hive.hpp"
namespace tooling
{
HiveRouter::HiveRouter(
llarp::EventLoop_ptr loop, std::shared_ptr<llarp::vpn::Platform> plat, RouterHive* hive)
: Router(loop, plat), m_hive(hive)
{}
bool
HiveRouter::disableGossipingRC_TestingOnly()
{
return m_disableGossiping;
}
void
HiveRouter::disableGossiping()
{
m_disableGossiping = true;
}
void
HiveRouter::enableGossiping()
{
m_disableGossiping = false;
}
void
HiveRouter::HandleRouterEvent(RouterEventPtr event) const
{
m_hive->NotifyEvent(std::move(event));
}
} // namespace tooling

@ -1,38 +0,0 @@
#pragma once
#include <llarp/router/router.hpp>
namespace tooling
{
/// HiveRouter is a subclass of Router which overrides specific behavior in
/// order to perform testing-related functions. It exists largely to prevent
/// this behavior (which may often be "dangerous") from leaking into release
/// code.
struct HiveRouter : public llarp::Router
{
explicit HiveRouter(
llarp::EventLoop_ptr loop,
std::shared_ptr<llarp::vpn::Platform> vpnPlatform,
RouterHive* hive);
virtual ~HiveRouter() = default;
/// Override logic to prevent base Router class from gossiping its RC.
virtual bool
disableGossipingRC_TestingOnly() override;
void
disableGossiping();
void
enableGossiping();
protected:
bool m_disableGossiping = false;
RouterHive* m_hive = nullptr;
virtual void
HandleRouterEvent(RouterEventPtr event) const override;
};
} // namespace tooling

@ -1,132 +0,0 @@
#include "router_event.hpp"
#include <llarp/path/path_types.hpp>
#include <llarp/path/path.hpp>
#include <llarp/path/transit_hop.hpp>
namespace tooling
{
struct PathAttemptEvent : public RouterEvent
{
std::vector<llarp::path::PathHopConfig> hops;
llarp::PathID_t pathid;
PathAttemptEvent(const llarp::RouterID& routerID, std::shared_ptr<const llarp::path::Path> path)
: RouterEvent("PathAttemptEvent", routerID, false)
, hops(path->hops)
, pathid(path->hops[0].rxID)
{}
std::string
ToString() const
{
std::string result = RouterEvent::ToString();
result += "---- [";
size_t i = 0;
for (const auto& hop : hops)
{
i++;
result += llarp::RouterID(hop.rc.pubkey).ShortString();
result += "]";
if (i != hops.size())
{
result += " -> [";
}
}
return result;
}
};
struct PathRequestReceivedEvent : public RouterEvent
{
llarp::RouterID prevHop;
llarp::RouterID nextHop;
llarp::PathID_t txid;
llarp::PathID_t rxid;
bool isEndpoint = false;
PathRequestReceivedEvent(
const llarp::RouterID& routerID, std::shared_ptr<const llarp::path::TransitHop> hop)
: RouterEvent("PathRequestReceivedEvent", routerID, true)
, prevHop(hop->info.downstream)
, nextHop(hop->info.upstream)
, txid(hop->info.txID)
, rxid(hop->info.rxID)
, isEndpoint(routerID == nextHop ? true : false)
{}
std::string
ToString() const
{
std::string result = RouterEvent::ToString();
result += "---- [";
result += prevHop.ShortString();
result += "] -> [*";
result += routerID.ShortString();
result += "] -> [";
if (isEndpoint)
{
result += "nowhere]";
}
else
{
result += nextHop.ShortString();
result += "]";
}
return result;
}
};
struct PathStatusReceivedEvent : public RouterEvent
{
llarp::PathID_t rxid;
uint64_t status;
PathStatusReceivedEvent(
const llarp::RouterID& routerID, const llarp::PathID_t rxid_, uint64_t status_)
: RouterEvent("PathStatusReceivedEvent", routerID, true), rxid(rxid_), status(status_)
{}
std::string
ToString() const
{
std::string result = RouterEvent::ToString();
result += "---- path rxid: " + rxid.ShortHex();
result += ", status: " + std::to_string(status);
return result;
}
};
struct PathBuildRejectedEvent : public RouterEvent
{
llarp::PathID_t rxid;
llarp::RouterID rejectedBy;
PathBuildRejectedEvent(
const llarp::RouterID& routerID,
const llarp::PathID_t rxid_,
const llarp::RouterID& rejectedBy_)
: RouterEvent("PathBuildRejectedEvent", routerID, false)
, rxid(rxid_)
, rejectedBy(rejectedBy_)
{}
std::string
ToString() const
{
std::string result = RouterEvent::ToString();
result += "---- path rxid: " + rxid.ShortHex();
result += ", rejectedBy: " + rejectedBy.ShortString();
return result;
}
};
} // namespace tooling

@ -1,42 +0,0 @@
#pragma once
#include "router_event.hpp"
namespace tooling
{
struct LinkSessionEstablishedEvent : public RouterEvent
{
llarp::RouterID remoteId;
bool inbound = false;
LinkSessionEstablishedEvent(
const llarp::RouterID& ourRouterId, const llarp::RouterID& remoteId_, bool inbound_)
: RouterEvent("Link: LinkSessionEstablishedEvent", ourRouterId, false)
, remoteId(remoteId_)
, inbound(inbound_)
{}
std::string
ToString() const
{
return RouterEvent::ToString() + (inbound ? "inbound" : "outbound")
+ " : LinkSessionEstablished with " + remoteId.ToString();
}
};
struct ConnectionAttemptEvent : public RouterEvent
{
llarp::RouterID remoteId;
ConnectionAttemptEvent(const llarp::RouterID& ourRouterId, const llarp::RouterID& remoteId_)
: RouterEvent("Link: ConnectionAttemptEvent", ourRouterId, false), remoteId(remoteId_)
{}
std::string
ToString() const
{
return RouterEvent::ToString() + " : LinkSessionEstablished with " + remoteId.ToString();
}
};
} // namespace tooling

@ -1,53 +0,0 @@
#pragma once
#include "router_event.hpp"
#include <llarp/router_contact.hpp>
namespace tooling
{
struct RCGossipReceivedEvent : public RouterEvent
{
RCGossipReceivedEvent(const llarp::RouterID& routerID, const llarp::RouterContact& rc_)
: RouterEvent("RCGossipReceivedEvent", routerID, true), rc(rc_)
{}
std::string
ToString() const override
{
return RouterEvent::ToString()
+ " ---- other RouterID: " + llarp::RouterID(rc.pubkey).ShortString();
}
std::string
LongString() const
{
return RouterEvent::ToString() + " ---- RC: " + rc.ToString();
}
llarp::RouterContact rc;
};
struct RCGossipSentEvent : public RouterEvent
{
RCGossipSentEvent(const llarp::RouterID& routerID, const llarp::RouterContact& rc_)
: RouterEvent("RCGossipSentEvent", routerID, true), rc(rc_)
{}
std::string
ToString() const override
{
return RouterEvent::ToString()
+ " ---- sending RC for RouterID: " + llarp::RouterID(rc.pubkey).ShortString();
}
std::string
LongString() const
{
return RouterEvent::ToString() + " ---- RC: " + rc.ToString();
}
llarp::RouterContact rc;
};
} // namespace tooling

@ -1,56 +0,0 @@
#pragma once
#include <llarp/router_id.hpp>
#include <string>
#include <vector>
#include <memory>
namespace llarp
{
struct PathID_t;
namespace path
{
struct Path;
struct PathHopConfig;
struct TransitHop;
} // namespace path
} // namespace llarp
namespace tooling
{
struct RouterHive;
struct RouterEvent
{
RouterEvent(std::string eventType, llarp::RouterID routerID, bool triggered)
: eventType(eventType), routerID(routerID), triggered(triggered)
{}
virtual ~RouterEvent() = default;
virtual std::string
ToString() const
{
std::string result;
result += eventType;
result += " [";
result += routerID.ShortString();
result += "] -- ";
return result;
}
const std::string eventType;
llarp::RouterID routerID;
bool triggered = false;
};
using RouterEventPtr = std::unique_ptr<RouterEvent>;
} // namespace tooling

@ -1,249 +0,0 @@
#include "router_hive.hpp"
#include <llarp.hpp>
#include <llarp/util/str.hpp>
#include <llarp/router/router.hpp>
#include <chrono>
#include <algorithm>
#include <csignal>
using namespace std::chrono_literals;
namespace tooling
{
void
RouterHive::AddRouter(const std::shared_ptr<llarp::Config>& config, bool isSNode)
{
auto& container = (isSNode ? relays : clients);
llarp::RuntimeOptions opts;
opts.isSNode = isSNode;
Context_ptr context = std::make_shared<HiveContext>(this);
context->Configure(config);
context->Setup(opts);
auto routerId = llarp::RouterID(context->router->pubkey());
container[routerId] = context;
fmt::print("Generated router with ID {}\n", routerId);
}
void
RouterHive::AddRelay(const std::shared_ptr<llarp::Config>& config)
{
AddRouter(config, true);
}
void
RouterHive::AddClient(const std::shared_ptr<llarp::Config>& config)
{
AddRouter(config, false);
}
void
RouterHive::StartRouters(bool isRelay)
{
auto& container = (isRelay ? relays : clients);
for (const auto& [routerId, ctx] : container)
{
routerMainThreads.emplace_back([ctx = ctx, isRelay = isRelay]() {
ctx->Run(llarp::RuntimeOptions{false, false, isRelay});
});
std::this_thread::sleep_for(2ms);
}
}
void
RouterHive::StartRelays()
{
StartRouters(true);
}
void
RouterHive::StartClients()
{
StartRouters(false);
}
void
RouterHive::StopRouters()
{
llarp::LogInfo("Signalling all routers to stop");
for (auto& [routerId, ctx] : relays)
{
ctx->loop->call([ctx = ctx]() { ctx->HandleSignal(SIGINT); });
}
for (auto& [routerId, ctx] : clients)
{
ctx->loop->call([ctx = ctx]() { ctx->HandleSignal(SIGINT); });
}
llarp::LogInfo("Waiting on routers to be stopped");
for (auto [routerId, ctx] : relays)
{
while (ctx->IsUp())
{
std::this_thread::sleep_for(10ms);
}
}
for (auto [routerId, ctx] : clients)
{
while (ctx->IsUp())
{
std::this_thread::sleep_for(10ms);
}
}
llarp::LogInfo("Joining all router threads");
for (auto& thread : routerMainThreads)
{
while (not thread.joinable())
{
std::this_thread::sleep_for(500ms);
}
thread.join();
}
llarp::LogInfo("RouterHive::StopRouters finished");
}
void
RouterHive::NotifyEvent(RouterEventPtr event)
{
std::lock_guard<std::mutex> guard{eventQueueMutex};
eventQueue.push_back(std::move(event));
}
RouterEventPtr
RouterHive::GetNextEvent()
{
std::lock_guard<std::mutex> guard{eventQueueMutex};
if (not eventQueue.empty())
{
auto ptr = std::move(eventQueue.front());
eventQueue.pop_front();
return ptr;
}
return nullptr;
}
std::deque<RouterEventPtr>
RouterHive::GetAllEvents()
{
std::lock_guard<std::mutex> guard{eventQueueMutex};
std::deque<RouterEventPtr> events;
if (not eventQueue.empty())
{
eventQueue.swap(events);
}
return events;
}
void
RouterHive::VisitRouter(Context_ptr ctx, std::function<void(Context_ptr)> visit)
{
// TODO: this should be called from each router's appropriate Loop, e.g.:
// ctx->loop->call([visit, ctx]() { visit(ctx); });
// however, this causes visit calls to be deferred
visit(ctx);
}
HiveRouter*
RouterHive::GetRelay(const llarp::RouterID& id, bool needMutexLock)
{
auto guard =
needMutexLock ? std::make_optional<std::lock_guard<std::mutex>>(routerMutex) : std::nullopt;
auto itr = relays.find(id);
if (itr == relays.end())
return nullptr;
auto ctx = itr->second;
return ctx->getRouterAsHiveRouter();
}
std::vector<size_t>
RouterHive::RelayConnectedRelays()
{
std::lock_guard guard{routerMutex};
std::vector<size_t> results;
results.resize(relays.size());
std::mutex results_lock;
size_t i = 0;
size_t done_count = 0;
for (auto& [routerId, ctx] : relays)
{
ctx->loop->call([&, i, ctx = ctx]() {
size_t count = ctx->router->NumberOfConnectedRouters();
std::lock_guard guard{results_lock};
results[i] = count;
done_count++;
});
i++;
}
while (true)
{
size_t read_done_count = 0;
{
std::lock_guard guard{results_lock};
read_done_count = done_count;
}
if (read_done_count == relays.size())
break;
std::this_thread::sleep_for(100ms);
}
return results;
}
// TODO: DRY -- this smells a lot like RelayConnectedRelays()
std::vector<llarp::RouterContact>
RouterHive::GetRelayRCs()
{
std::lock_guard<std::mutex> guard{routerMutex};
std::vector<llarp::RouterContact> results;
results.resize(relays.size());
size_t i = 0;
for (auto [routerId, ctx] : relays)
{
results[i] = ctx->router->rc();
i++;
}
return results;
}
void
RouterHive::ForEachRelay(std::function<void(Context_ptr)> visit)
{
for (auto [routerId, ctx] : relays)
{
VisitRouter(ctx, visit);
}
}
void
RouterHive::ForEachClient(std::function<void(Context_ptr)> visit)
{
for (auto [routerId, ctx] : clients)
{
VisitRouter(ctx, visit);
}
}
/// safely visit every router context
void
RouterHive::ForEachRouter(std::function<void(Context_ptr)> visit)
{
ForEachRelay(visit);
ForEachClient(visit);
}
} // namespace tooling

@ -1,95 +0,0 @@
#pragma once
#include "router_event.hpp"
#include <llarp.hpp>
#include <llarp/config/config.hpp>
#include <llarp/tooling/hive_context.hpp>
#include <vector>
#include <deque>
#include <thread>
#include <mutex>
struct llarp_config;
struct llarp_main;
namespace llarp
{
struct Context;
} // namespace llarp
namespace tooling
{
struct HiveRouter; // Hive's version of Router
struct RouterHive
{
using Context_ptr = std::shared_ptr<HiveContext>;
private:
void
StartRouters(bool isRelay);
void
AddRouter(const std::shared_ptr<llarp::Config>& config, bool isRelay);
/// safely visit router (asynchronously)
void
VisitRouter(Context_ptr ctx, std::function<void(Context_ptr)> visit);
public:
RouterHive() = default;
void
AddRelay(const std::shared_ptr<llarp::Config>& conf);
void
AddClient(const std::shared_ptr<llarp::Config>& conf);
void
StartRelays();
void
StartClients();
void
StopRouters();
void
NotifyEvent(RouterEventPtr event);
RouterEventPtr
GetNextEvent();
std::deque<RouterEventPtr>
GetAllEvents();
// functions to safely visit each relay and/or client's HiveContext
void
ForEachRelay(std::function<void(Context_ptr)> visit);
void
ForEachClient(std::function<void(Context_ptr)> visit);
void
ForEachRouter(std::function<void(Context_ptr)> visit);
HiveRouter*
GetRelay(const llarp::RouterID& id, bool needMutexLock = true);
std::vector<size_t>
RelayConnectedRelays();
std::vector<llarp::RouterContact>
GetRelayRCs();
std::mutex routerMutex;
std::unordered_map<llarp::RouterID, Context_ptr> relays;
std::unordered_map<llarp::RouterID, Context_ptr> clients;
std::vector<std::thread> routerMainThreads;
std::mutex eventQueueMutex;
std::deque<RouterEventPtr> eventQueue;
};
} // namespace tooling

@ -92,4 +92,7 @@ namespace llarp
std::string
lowercase_ascii_string(std::string src);
std::string_view
TrimWhitespace(std::string_view str);
} // namespace llarp

Loading…
Cancel
Save