ALPN verification

- laying the groundwork for functional client->service node connections. this requires ALPNs verification as a secondary method of identification to the remote key
- refactored btreq stream creation to use improved stream creation logic in libquic
pull/2232/head
dr7ana 6 months ago
parent 0e73605ffd
commit 3e9d5a97a8

@ -214,7 +214,7 @@ namespace llarp::exit
BaseSession::HandleTrafficDrop(llarp::path::Path_ptr p, const PathID_t& path, uint64_t s) BaseSession::HandleTrafficDrop(llarp::path::Path_ptr p, const PathID_t& path, uint64_t s)
{ {
llarp::LogError("dropped traffic on exit ", exit_router, " S=", s, " P=", path); llarp::LogError("dropped traffic on exit ", exit_router, " S=", s, " P=", path);
p->EnterState(path::ePathIgnore, router->now()); p->EnterState(path::IGNORE, router->now());
return true; return true;
} }
@ -238,7 +238,7 @@ namespace llarp::exit
{ {
if (BuildCooldownHit(now)) if (BuildCooldownHit(now))
return false; return false;
if (IsReady() and NumInStatus(path::ePathBuilding) < numDesiredPaths) if (IsReady() and NumInStatus(path::BUILDING) < numDesiredPaths)
return path::Builder::UrgentBuild(now); return path::Builder::UrgentBuild(now);
return false; return false;
} }

@ -21,10 +21,16 @@ namespace llarp
{ {
namespace link namespace link
{ {
Endpoint::Endpoint(std::shared_ptr<oxen::quic::Endpoint> ep, LinkManager& lm)
: endpoint{std::move(ep)}
, link_manager{lm}
, _is_service_node{link_manager.is_service_node()}
{}
std::shared_ptr<link::Connection> std::shared_ptr<link::Connection>
Endpoint::get_conn(const RemoteRC& rc) const Endpoint::get_conn(const RemoteRC& rc) const
{ {
if (auto itr = active_conns.find(rc.router_id()); itr != active_conns.end()) if (auto itr = service_conns.find(rc.router_id()); itr != service_conns.end())
return itr->second; return itr->second;
// if (auto itr = pending_conns.find(rc.router_id()); itr != pending_conns.end()) // if (auto itr = pending_conns.find(rc.router_id()); itr != pending_conns.end())
@ -36,7 +42,7 @@ namespace llarp
std::shared_ptr<link::Connection> std::shared_ptr<link::Connection>
Endpoint::get_conn(const RouterID& rid) const Endpoint::get_conn(const RouterID& rid) const
{ {
if (auto itr = active_conns.find(rid); itr != active_conns.end()) if (auto itr = service_conns.find(rid); itr != service_conns.end())
return itr->second; return itr->second;
// if (auto itr = pending_conns.find(rid); itr != pending_conns.end()) // if (auto itr = pending_conns.find(rid); itr != pending_conns.end())
@ -48,7 +54,7 @@ namespace llarp
bool bool
Endpoint::have_client_conn(const RouterID& remote) const Endpoint::have_client_conn(const RouterID& remote) const
{ {
if (auto itr = active_conns.find(remote); itr != active_conns.end()) if (auto itr = service_conns.find(remote); itr != service_conns.end())
{ {
return not itr->second->remote_is_relay; return not itr->second->remote_is_relay;
} }
@ -64,7 +70,7 @@ namespace llarp
bool bool
Endpoint::have_conn(const RouterID& remote) const Endpoint::have_conn(const RouterID& remote) const
{ {
return active_conns.count(remote) or pending_conns.count(remote); return service_conns.count(remote) or pending_conns.count(remote);
} }
std::pair<size_t, size_t> std::pair<size_t, size_t>
@ -72,7 +78,7 @@ namespace llarp
{ {
size_t in{0}, out{0}; size_t in{0}, out{0};
for (const auto& c : active_conns) for (const auto& c : service_conns)
{ {
if (c.second->inbound) if (c.second->inbound)
++in; ++in;
@ -88,7 +94,7 @@ namespace llarp
{ {
size_t count = 0; size_t count = 0;
for (const auto& c : active_conns) for (const auto& c : service_conns)
{ {
if (not(c.second->remote_is_relay and clients_only)) if (not(c.second->remote_is_relay and clients_only))
count += 1; count += 1;
@ -100,9 +106,9 @@ namespace llarp
bool bool
Endpoint::get_random_connection(RemoteRC& router) const Endpoint::get_random_connection(RemoteRC& router) const
{ {
if (const auto size = active_conns.size(); size) if (const auto size = service_conns.size(); size)
{ {
auto itr = active_conns.begin(); auto itr = service_conns.begin();
std::advance(itr, randint() % size); std::advance(itr, randint() % size);
RouterID rid{itr->second->conn->remote_key()}; RouterID rid{itr->second->conn->remote_key()};
@ -123,7 +129,7 @@ namespace llarp
void void
Endpoint::for_each_connection(std::function<void(link::Connection&)> func) Endpoint::for_each_connection(std::function<void(link::Connection&)> func)
{ {
for (const auto& [rid, conn] : active_conns) for (const auto& [rid, conn] : service_conns)
func(*conn); func(*conn);
} }
@ -134,7 +140,7 @@ namespace llarp
link_manager._router.loop()->call([this, rid = _rid]() { link_manager._router.loop()->call([this, rid = _rid]() {
// deletion from pending_conns, pending_conn_msg_queue, active_conns, etc is taken care // deletion from pending_conns, pending_conn_msg_queue, active_conns, etc is taken care
// of by LinkManager::on_conn_closed // of by LinkManager::on_conn_closed
if (auto itr = active_conns.find(rid); itr != active_conns.end()) if (auto itr = service_conns.find(rid); itr != service_conns.end())
{ {
auto& conn = *itr->second->conn; auto& conn = *itr->second->conn;
conn.close_connection(); conn.close_connection();
@ -195,7 +201,7 @@ namespace llarp
_router.loop()->call([this, msg = std::move(m), func = std::move(func)]() mutable { _router.loop()->call([this, msg = std::move(m), func = std::move(func)]() mutable {
auto body = msg.body_str(); auto body = msg.body_str();
auto respond = [m = std::move(msg)](std::string response) mutable { auto respond = [m = std::move(msg)](std::string response) mutable {
m.respond(std::move(response), not m); m.respond(std::move(response), m.is_error());
}; };
std::invoke(func, this, body, std::move(respond)); std::invoke(func, this, body, std::move(respond));
}); });
@ -207,6 +213,7 @@ namespace llarp
LinkManager::LinkManager(Router& r) LinkManager::LinkManager(Router& r)
: _router{r} : _router{r}
, _is_service_node{_router.is_service_node()}
, quic{std::make_unique<oxen::quic::Network>()} , quic{std::make_unique<oxen::quic::Network>()}
, tls_creds{oxen::quic::GNUTLSCreds::make_from_ed_keys( , tls_creds{oxen::quic::GNUTLSCreds::make_from_ed_keys(
{reinterpret_cast<const char*>(_router.identity().data()), size_t{32}}, {reinterpret_cast<const char*>(_router.identity().data()), size_t{32}},
@ -239,20 +246,44 @@ namespace llarp
[this](oxen::quic::connection_interface& ci, uint64_t ec) { [this](oxen::quic::connection_interface& ci, uint64_t ec) {
return on_conn_closed(ci, ec); return on_conn_closed(ci, ec);
}, },
[this](oxen::quic::dgram_interface& di, bstring dgram) { recv_data_message(di, dgram); }); [this](oxen::quic::dgram_interface& di, bstring dgram) { recv_data_message(di, dgram); },
tls_creds->set_key_verify_callback([this](const ustring_view& key, const ustring_view&) { is_service_node() ? alpns::SERVICE_INBOUND : alpns::CLIENT_INBOUND,
is_service_node() ? alpns::SERVICE_OUTBOUND : alpns::CLIENT_OUTBOUND);
tls_creds->set_key_verify_callback([this](const ustring_view& key, const ustring_view& alpn) {
auto is_snode = is_service_node();
RouterID other{key.data()}; RouterID other{key.data()};
bool result = node_db->registered_routers().count(other); auto us = router().is_bootstrap_seed() ? "Bootstrap seed node"s : "Service node"s;
log::critical( if (is_snode)
logcat, {
"{} node was {} to confirm remote (RID:{}) is registered; allowing connection!", if (alpn == alpns::C_ALPNS)
router().is_bootstrap_seed() ? "Bootstrap seed node" : "Service node", {
result ? "able" : "unable", log::critical(logcat, "{} node accepting client connection (remote ID:{})!", us, other);
other); return true;
}
if (alpn == alpns::SN_ALPNS)
{
// verify as service node!
bool result = node_db->registered_routers().count(other);
log::critical(
logcat,
"{} node was {} to confirm remote (RID:{}) is registered; allowing connection!",
us,
result ? "able" : "unable",
other);
return result;
}
return result; log::critical(logcat, "{} node received unknown ALPN; rejecting connection!", us);
return false;
}
throw std::runtime_error{"Clients should not be validating inbound connections!"};
}); });
if (_router.is_service_node()) if (_router.is_service_node())
{ {
@ -266,18 +297,19 @@ namespace llarp
{ {
const auto& scid = ci.scid(); const auto& scid = ci.scid();
RouterID rid{ci.remote_key()}; RouterID rid{ci.remote_key()};
ep.connid_map.emplace(scid, rid); ep.service_connid_map.emplace(scid, rid);
auto [itr, b] = ep.active_conns.emplace(rid, nullptr); auto [itr, b] = ep.service_conns.emplace(rid, nullptr);
log::critical(logcat, "Queueing BTStream to be opened..."); log::critical(logcat, "Queueing BTStream to be opened...");
auto control_stream = ci.queue_stream<oxen::quic::BTRequestStream>([this, rid = rid]( auto control_stream = ci.queue_incoming_stream<oxen::quic::BTRequestStream>(
oxen::quic::Stream&, [this, rid = rid](oxen::quic::Stream&, uint64_t error_code) {
uint64_t error_code) { log::warning(
log::warning( logcat,
logcat, "BTRequestStream closed unexpectedly (ec:{}); closing connection...", error_code); "BTRequestStream closed unexpectedly (ec:{}); closing connection...",
ep.close_connection(rid); error_code);
}); ep.close_connection(rid);
});
log::critical(logcat, "Queued BTStream to be opened ID:{}", control_stream->stream_id()); log::critical(logcat, "Queued BTStream to be opened ID:{}", control_stream->stream_id());
assert(control_stream->stream_id() == 0); assert(control_stream->stream_id() == 0);
@ -307,8 +339,8 @@ namespace llarp
if (auto itr = ep.pending_conns.find(rid); itr != ep.pending_conns.end()) if (auto itr = ep.pending_conns.find(rid); itr != ep.pending_conns.end())
{ {
ep.connid_map.emplace(scid, rid); ep.service_connid_map.emplace(scid, rid);
auto [it, b] = ep.active_conns.emplace(rid, nullptr); auto [it, b] = ep.service_conns.emplace(rid, nullptr);
it->second = std::move(itr->second); it->second = std::move(itr->second);
ep.pending_conns.erase(itr); ep.pending_conns.erase(itr);
@ -338,7 +370,7 @@ namespace llarp
if (msg.is_control) if (msg.is_control)
{ {
log::critical(logcat, "Dispatching {} request!", *msg.endpoint); log::critical(logcat, "Dispatching {} request!", *msg.endpoint);
ep.active_conns[rid]->control_stream->command( ep.service_conns[rid]->control_stream->command(
std::move(*msg.endpoint), std::move(msg.body), std::move(msg.func)); std::move(*msg.endpoint), std::move(msg.body), std::move(msg.func));
} }
else else
@ -373,15 +405,16 @@ namespace llarp
log::critical(quic_cat, "Pending quic connection CID:{} purged successfully", scid); log::critical(quic_cat, "Pending quic connection CID:{} purged successfully", scid);
} }
else if (const auto& c_itr = ep.connid_map.find(scid); c_itr != ep.connid_map.end()) else if (const auto& c_itr = ep.service_connid_map.find(scid);
c_itr != ep.service_connid_map.end())
{ {
const auto& rid = c_itr->second; const auto& rid = c_itr->second;
assert(_rid == rid); // this should hold true assert(_rid == rid); // this should hold true
if (auto m_itr = ep.active_conns.find(rid); m_itr != ep.active_conns.end()) if (auto m_itr = ep.service_conns.find(rid); m_itr != ep.service_conns.end())
ep.active_conns.erase(m_itr); ep.service_conns.erase(m_itr);
ep.connid_map.erase(c_itr); ep.service_connid_map.erase(c_itr);
log::critical(quic_cat, "Quic connection CID:{} purged successfully", scid); log::critical(quic_cat, "Quic connection CID:{} purged successfully", scid);
} }
@ -604,7 +637,7 @@ namespace llarp
bool bool
LinkManager::is_service_node() const LinkManager::is_service_node() const
{ {
return _router.is_service_node(); return _is_service_node;
} }
// TODO: this? perhaps no longer necessary in the same way? // TODO: this? perhaps no longer necessary in the same way?
@ -660,12 +693,12 @@ namespace llarp
} }
void void
LinkManager::gossip_rc( LinkManager::gossip_rc(const RouterID& last_sender, const RemoteRC& rc)
const RouterID& gossip_src, const RouterID& last_sender, std::string serialized_rc)
{ {
int count = 0; int count = 0;
const auto& gossip_src = rc.router_id();
for (auto& [rid, conn] : ep.active_conns) for (auto& [rid, conn] : ep.service_conns)
{ {
// don't send back to the gossip source or the last sender // don't send back to the gossip source or the last sender
if (rid == gossip_src or rid == last_sender) if (rid == gossip_src or rid == last_sender)
@ -678,7 +711,7 @@ namespace llarp
send_control_message( send_control_message(
rid, rid,
"gossip_rc"s, "gossip_rc"s,
GossipRCMessage::serialize(gossip_src, last_sender, serialized_rc), GossipRCMessage::serialize(last_sender, rc),
[](oxen::quic::message) mutable { [](oxen::quic::message) mutable {
log::critical(logcat, "PLACEHOLDER FOR GOSSIP RC RESPONSE HANDLER"); log::critical(logcat, "PLACEHOLDER FOR GOSSIP RC RESPONSE HANDLER");
}); });
@ -704,7 +737,6 @@ namespace llarp
btdc.required("rc"); btdc.required("rc");
rc = RemoteRC{btdc.consume_dict_data()}; rc = RemoteRC{btdc.consume_dict_data()};
src.from_string(btdc.require<std::string>("sender")); src.from_string(btdc.require<std::string>("sender"));
sender.from_string(btdc.require<std::string>("src"));
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -715,7 +747,7 @@ namespace llarp
if (node_db->verify_store_gossip_rc(rc)) if (node_db->verify_store_gossip_rc(rc))
{ {
log::critical(link_cat, "Received updated RC, forwarding to relay peers."); log::critical(link_cat, "Received updated RC, forwarding to relay peers.");
gossip_rc(src, _router.local_rid(), std::string{rc.view()}); gossip_rc(_router.local_rid(), rc);
} }
else else
log::critical(link_cat, "Received known or old RC, not storing or forwarding."); log::critical(link_cat, "Received known or old RC, not storing or forwarding.");
@ -934,7 +966,7 @@ namespace llarp
"fetch_router_ids"s, "fetch_router_ids"s,
m.body_str(), m.body_str(),
[source_rid = std::move(source), original = std::move(m)](oxen::quic::message m) mutable { [source_rid = std::move(source), original = std::move(m)](oxen::quic::message m) mutable {
original.respond(m.body_str(), not m); original.respond(m.body_str(), m.is_error());
}); });
return; return;
} }
@ -994,9 +1026,9 @@ namespace llarp
void void
LinkManager::handle_find_name_response(oxen::quic::message m) LinkManager::handle_find_name_response(oxen::quic::message m)
{ {
if (not m) if (m.timed_out)
{ {
log::info(link_cat, "FindNameMessage failed!"); log::info(link_cat, "FindNameMessage request timed out!");
return; return;
} }
@ -1130,7 +1162,7 @@ namespace llarp
"publish_intro", "publish_intro",
PublishIntroMessage::serialize(introset, relay_order, is_relayed), PublishIntroMessage::serialize(introset, relay_order, is_relayed),
[respond = std::move(respond)](oxen::quic::message m) { [respond = std::move(respond)](oxen::quic::message m) {
if (not m) if (m.timed_out)
return; // drop if timed out; requester will have timed out as well return; // drop if timed out; requester will have timed out as well
respond(m.body_str()); respond(m.body_str());
}); });
@ -1165,10 +1197,13 @@ namespace llarp
addr); addr);
} }
// DISCUSS: I feel like ::handle_publish_intro_response should be the callback that handles the
// response to a relayed publish_intro (above line 1131-ish)
void void
LinkManager::handle_publish_intro_response(oxen::quic::message m) LinkManager::handle_publish_intro_response(oxen::quic::message m)
{ {
if (not m) if (m.timed_out)
{ {
log::info(link_cat, "PublishIntroMessage timed out!"); log::info(link_cat, "PublishIntroMessage timed out!");
return; return;
@ -1271,7 +1306,7 @@ namespace llarp
link_cat, link_cat,
"Relayed FindIntroMessage returned successful response; transmitting to initial " "Relayed FindIntroMessage returned successful response; transmitting to initial "
"requester"); "requester");
else if (not relay_response) else if (relay_response.timed_out)
log::critical( log::critical(
link_cat, "Relayed FindIntroMessage timed out! Notifying initial requester"); link_cat, "Relayed FindIntroMessage timed out! Notifying initial requester");
else else
@ -1298,7 +1333,7 @@ namespace llarp
void void
LinkManager::handle_find_intro_response(oxen::quic::message m) LinkManager::handle_find_intro_response(oxen::quic::message m)
{ {
if (not m) if (m.timed_out)
{ {
log::info(link_cat, "FindIntroMessage timed out!"); log::info(link_cat, "FindIntroMessage timed out!");
return; return;
@ -1491,12 +1526,12 @@ namespace llarp
"then relaying response"); "then relaying response");
_router.path_context().put_transit_hop(hop); _router.path_context().put_transit_hop(hop);
} }
if (not m) if (m.timed_out)
log::info(link_cat, "Upstream timed out on path build; relaying timeout"); log::info(link_cat, "Upstream timed out on path build; relaying timeout");
else else
log::info(link_cat, "Upstream returned path build failure; relaying response"); log::info(link_cat, "Upstream returned path build failure; relaying response");
m.respond(m.body_str(), not m); m.respond(m.body_str(), m.is_error());
}); });
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -1608,12 +1643,12 @@ namespace llarp
void void
LinkManager::handle_obtain_exit_response(oxen::quic::message m) LinkManager::handle_obtain_exit_response(oxen::quic::message m)
{ {
if (not m) if (m.timed_out)
{ {
log::info(link_cat, "ObtainExitMessage timed out!"); log::info(link_cat, "ObtainExitMessage timed out!");
return; return;
} }
if (m.is_error) if (m.is_error())
{ {
// TODO: what to do here // TODO: what to do here
} }
@ -1686,12 +1721,12 @@ namespace llarp
void void
LinkManager::handle_update_exit_response(oxen::quic::message m) LinkManager::handle_update_exit_response(oxen::quic::message m)
{ {
if (not m) if (m.timed_out)
{ {
log::info(link_cat, "UpdateExitMessage timed out!"); log::info(link_cat, "UpdateExitMessage timed out!");
return; return;
} }
if (m.is_error) if (m.is_error())
{ {
// TODO: what to do here // TODO: what to do here
} }
@ -1771,12 +1806,12 @@ namespace llarp
void void
LinkManager::handle_close_exit_response(oxen::quic::message m) LinkManager::handle_close_exit_response(oxen::quic::message m)
{ {
if (not m) if (m.timed_out)
{ {
log::info(link_cat, "CloseExitMessage timed out!"); log::info(link_cat, "CloseExitMessage timed out!");
return; return;
} }
if (m.is_error) if (m.is_error())
{ {
// TODO: what to do here // TODO: what to do here
} }

@ -34,27 +34,42 @@ namespace llarp
using stream_closed_hook = oxen::quic::stream_close_callback; using stream_closed_hook = oxen::quic::stream_close_callback;
using keep_alive = oxen::quic::opt::keep_alive; using keep_alive = oxen::quic::opt::keep_alive;
using inbound_alpns = oxen::quic::opt::inbound_alpns;
using outbound_alpns = oxen::quic::opt::outbound_alpns;
inline const keep_alive ROUTER_KEEP_ALIVE{10s}; inline const keep_alive ROUTER_KEEP_ALIVE{10s};
inline const keep_alive CLIENT_KEEP_ALIVE{0s}; inline const keep_alive CLIENT_KEEP_ALIVE{0s};
namespace alpns
{
inline const auto SN_ALPNS = "SERVICE_NODE"_us;
inline const auto C_ALPNS = "CLIENT"_us;
inline const inbound_alpns SERVICE_INBOUND{{SN_ALPNS, C_ALPNS}};
inline const outbound_alpns SERVICE_OUTBOUND{{SN_ALPNS}};
inline const inbound_alpns CLIENT_INBOUND{};
inline const outbound_alpns CLIENT_OUTBOUND{{C_ALPNS}};
} // namespace alpns
namespace link namespace link
{ {
struct Connection; struct Connection;
struct Endpoint struct Endpoint
{ {
Endpoint(std::shared_ptr<oxen::quic::Endpoint> ep, LinkManager& lm) Endpoint(std::shared_ptr<oxen::quic::Endpoint> ep, LinkManager& lm);
: endpoint{std::move(ep)}, link_manager{lm}
{}
std::shared_ptr<oxen::quic::Endpoint> endpoint; std::shared_ptr<oxen::quic::Endpoint> endpoint;
LinkManager& link_manager; LinkManager& link_manager;
// for outgoing packets, we route via RouterID; map RouterID->Connection // for outgoing packets, we route via RouterID; map RouterID->Connection
// for incoming packets, we get a ConnectionID; map ConnectionID->RouterID // for incoming packets, we get a ConnectionID; map ConnectionID->RouterID
std::unordered_map<RouterID, std::shared_ptr<link::Connection>> active_conns; std::unordered_map<RouterID, std::shared_ptr<link::Connection>> service_conns;
std::unordered_map<oxen::quic::ConnectionID, RouterID> connid_map; std::unordered_map<oxen::quic::ConnectionID, RouterID> service_connid_map;
std::unordered_map<RouterID, std::shared_ptr<link::Connection>> client_conns;
std::unordered_map<oxen::quic::ConnectionID, RouterID> client_connid_map;
// for pending connections, cleared in LinkManager::on_conn_open // for pending connections, cleared in LinkManager::on_conn_open
std::unordered_map<RouterID, std::shared_ptr<link::Connection>> pending_conns; std::unordered_map<RouterID, std::shared_ptr<link::Connection>> pending_conns;
@ -93,6 +108,7 @@ namespace llarp
close_connection(RouterID rid); close_connection(RouterID rid);
private: private:
const bool _is_service_node;
}; };
} // namespace link } // namespace link
@ -198,6 +214,8 @@ namespace llarp
Router& _router; Router& _router;
const bool _is_service_node;
// FIXME: Lokinet currently expects to be able to kill all network functionality before // FIXME: Lokinet currently expects to be able to kill all network functionality before
// finishing other shutdown things, including destroying this class, and that is all in // finishing other shutdown things, including destroying this class, and that is all in
// Network's destructor, so we need to be able to destroy it before this class. // Network's destructor, so we need to be able to destroy it before this class.
@ -228,7 +246,7 @@ namespace llarp
public: public:
const link::Endpoint& const link::Endpoint&
endpoint() endpoint() const
{ {
return ep; return ep;
} }
@ -240,7 +258,7 @@ namespace llarp
} }
void void
gossip_rc(const RouterID& gossip_src, const RouterID& last_sender, std::string serialized_rc); gossip_rc(const RouterID& last_sender, const RemoteRC& rc);
void void
handle_gossip_rc(oxen::quic::message m); handle_gossip_rc(oxen::quic::message m);
@ -429,7 +447,7 @@ namespace llarp
// add to pending conns // add to pending conns
auto [itr, b] = pending_conns.emplace(rid, nullptr); auto [itr, b] = pending_conns.emplace(rid, nullptr);
auto control_stream = conn_interface->template get_new_stream<oxen::quic::BTRequestStream>( auto control_stream = conn_interface->template open_stream<oxen::quic::BTRequestStream>(
[this, rid = rid](oxen::quic::Stream&, uint64_t error_code) { [this, rid = rid](oxen::quic::Stream&, uint64_t error_code) {
log::warning( log::warning(
logcat, logcat,

@ -9,15 +9,14 @@ namespace llarp
namespace GossipRCMessage namespace GossipRCMessage
{ {
inline static std::string inline static std::string
serialize(const RouterID& gossip_src, const RouterID& last_sender, std::string rc) serialize(const RouterID& last_sender, const RemoteRC& rc)
{ {
oxenc::bt_dict_producer btdp; oxenc::bt_dict_producer btdp;
try try
{ {
btdp.append_encoded("rc", rc); btdp.append_encoded("rc", rc.view());
btdp.append("sender", last_sender.ToView()); btdp.append("sender", last_sender.ToView());
btdp.append("src", gossip_src.ToView());
} }
catch (...) catch (...)
{ {

@ -369,21 +369,21 @@ namespace llarp
src, src,
FetchRCMessage::serialize(_router.last_rc_fetch, needed), FetchRCMessage::serialize(_router.last_rc_fetch, needed),
[this, src, initial](oxen::quic::message m) mutable { [this, src, initial](oxen::quic::message m) mutable {
if (not m) if (m.timed_out)
{ {
log::info(logcat, "RC fetch to {} failed!", src); log::info(logcat, "RC fetch to {} timed out!", src);
fetch_rcs_result(initial, true); fetch_rcs_result(initial, m.timed_out);
return; return;
} }
try try
{ {
oxenc::bt_dict_consumer btdc{m.body()}; oxenc::bt_dict_consumer btdc{m.body()};
// TODO: fix this shit after removing ::timed_out from message type // TODO: can this just combine with the above failure case...?
if (not m) if (m.is_error())
{ {
auto reason = btdc.require<std::string_view>(messages::STATUS_KEY); auto reason = btdc.require<std::string_view>(messages::STATUS_KEY);
log::info(logcat, "RC fetch to {} returned error: {}", src, reason); log::info(logcat, "RC fetch to {} returned error: {}", src, reason);
fetch_rcs_result(initial, true); fetch_rcs_result(initial, m.is_error());
return; return;
} }
@ -438,9 +438,11 @@ namespace llarp
src, src,
FetchRIDMessage::serialize(target), FetchRIDMessage::serialize(target),
[this, src, target, initial](oxen::quic::message m) mutable { [this, src, target, initial](oxen::quic::message m) mutable {
if (not m) if (m.is_error())
{ {
log::info(link_cat, "RID fetch from {} via {} timed out", src, target); auto err = "RID fetch from {} via {} {}"_format(
src, target, m.timed_out ? "timed out" : "failed");
log::info(link_cat, err);
ingest_rid_fetch_responses(target); ingest_rid_fetch_responses(target);
fetch_rids_result(initial); fetch_rids_result(initial);
return; return;
@ -796,15 +798,18 @@ namespace llarp
_registered_routers.insert(greylist.begin(), greylist.end()); _registered_routers.insert(greylist.begin(), greylist.end());
_registered_routers.insert(greenlist.begin(), greenlist.end()); _registered_routers.insert(greenlist.begin(), greenlist.end());
router_whitelist.clear(); _router_whitelist.clear();
router_whitelist.insert(whitelist.begin(), whitelist.end()); _router_whitelist.insert(whitelist.begin(), whitelist.end());
router_greylist.clear(); _router_greylist.clear();
router_greylist.insert(greylist.begin(), greylist.end()); _router_greylist.insert(greylist.begin(), greylist.end());
router_greenlist.clear(); _router_greenlist.clear();
router_greenlist.insert(greenlist.begin(), greenlist.end()); _router_greenlist.insert(greenlist.begin(), greenlist.end());
log::critical( log::critical(
logcat, "Service node whitelist now has {} active router RIDs", router_whitelist.size()); logcat,
"Oxend provided {}:{} (whitelist:registered)",
_router_whitelist.size(),
_registered_routers.size());
} }
std::optional<RouterID> std::optional<RouterID>
@ -812,7 +817,7 @@ namespace llarp
{ {
std::optional<RouterID> rand = std::nullopt; std::optional<RouterID> rand = std::nullopt;
std::sample(router_whitelist.begin(), router_whitelist.end(), &*rand, 1, csrng); std::sample(_router_whitelist.begin(), _router_whitelist.end(), &*rand, 1, csrng);
return rand; return rand;
} }
@ -826,7 +831,7 @@ namespace llarp
return false; return false;
} }
return known_rids.count(remote) or router_greylist.count(remote); return known_rids.count(remote) or _router_greylist.count(remote);
} }
bool bool

@ -146,9 +146,9 @@ namespace llarp
- gray: fully funded, but decommissioned routers - gray: fully funded, but decommissioned routers
- green: registered, but not fully-staked routers - green: registered, but not fully-staked routers
*/ */
std::set<RouterID> router_whitelist{}; std::set<RouterID> _router_whitelist{};
std::set<RouterID> router_greylist{}; std::set<RouterID> _router_greylist{};
std::set<RouterID> router_greenlist{}; std::set<RouterID> _router_greenlist{};
// All registered relays (service nodes) // All registered relays (service nodes)
std::set<RouterID> _registered_routers; std::set<RouterID> _registered_routers;
@ -346,13 +346,13 @@ namespace llarp
const std::set<RouterID>& const std::set<RouterID>&
whitelist() const whitelist() const
{ {
return known_rids; return _router_whitelist;
} }
const std::set<RouterID>& const std::set<RouterID>&
greylist() const greylist() const
{ {
return router_greylist; return _router_greylist;
} }
std::set<RouterID>& std::set<RouterID>&

@ -44,7 +44,7 @@ namespace llarp::path
intro.router = hops[hsz - 1].rc.router_id(); intro.router = hops[hsz - 1].rc.router_id();
intro.path_id = hops[hsz - 1].txID; intro.path_id = hops[hsz - 1].txID;
if (auto parent = m_PathSet.lock()) if (auto parent = m_PathSet.lock())
EnterState(ePathBuilding, parent->Now()); EnterState(BUILDING, parent->Now());
} }
bool bool
@ -118,7 +118,7 @@ namespace llarp::path
if ((not self) or (not response_cb)) if ((not self) or (not response_cb))
return; return;
if (not m) if (m.timed_out)
{ {
response_cb(messages::TIMEOUT_RESPONSE); response_cb(messages::TIMEOUT_RESPONSE);
return; return;
@ -186,7 +186,7 @@ namespace llarp::path
{ {
if (Expired(llarp::time_now_ms())) if (Expired(llarp::time_now_ms()))
return false; return false;
return intro.latency > 0s && _status == ePathEstablished; return intro.latency > 0s && _status == ESTABLISHED;
} }
bool bool
@ -227,12 +227,12 @@ namespace llarp::path
if (now == 0s) if (now == 0s)
now = router.now(); now = router.now();
if (st == ePathFailed) if (st == FAILED)
{ {
_status = st; _status = st;
return; return;
} }
if (st == ePathExpired && _status == ePathBuilding) if (st == EXPIRED && _status == BUILDING)
{ {
_status = st; _status = st;
if (auto parent = m_PathSet.lock()) if (auto parent = m_PathSet.lock())
@ -240,16 +240,16 @@ namespace llarp::path
parent->HandlePathBuildTimeout(shared_from_this()); parent->HandlePathBuildTimeout(shared_from_this());
} }
} }
else if (st == ePathBuilding) else if (st == BUILDING)
{ {
LogInfo("path ", name(), " is building"); LogInfo("path ", name(), " is building");
buildStarted = now; buildStarted = now;
} }
else if (st == ePathEstablished && _status == ePathBuilding) else if (st == ESTABLISHED && _status == BUILDING)
{ {
LogInfo("path ", name(), " is built, took ", ToString(now - buildStarted)); LogInfo("path ", name(), " is built, took ", ToString(now - buildStarted));
} }
else if (st == ePathTimeout && _status == ePathEstablished) else if (st == TIMEOUT && _status == ESTABLISHED)
{ {
LogInfo("path ", name(), " died"); LogInfo("path ", name(), " died");
_status = st; _status = st;
@ -258,11 +258,11 @@ namespace llarp::path
parent->HandlePathDied(shared_from_this()); parent->HandlePathDied(shared_from_this());
} }
} }
else if (st == ePathEstablished && _status == ePathTimeout) else if (st == ESTABLISHED && _status == TIMEOUT)
{ {
LogInfo("path ", name(), " reanimated"); LogInfo("path ", name(), " reanimated");
} }
else if (st == ePathIgnore) else if (st == IGNORE)
{ {
LogInfo("path ", name(), " ignored"); LogInfo("path ", name(), " ignored");
} }
@ -309,22 +309,22 @@ namespace llarp::path
switch (_status) switch (_status)
{ {
case ePathBuilding: case BUILDING:
obj["status"] = "building"; obj["status"] = "building";
break; break;
case ePathEstablished: case ESTABLISHED:
obj["status"] = "established"; obj["status"] = "established";
break; break;
case ePathTimeout: case TIMEOUT:
obj["status"] = "timeout"; obj["status"] = "timeout";
break; break;
case ePathExpired: case EXPIRED:
obj["status"] = "expired"; obj["status"] = "expired";
break; break;
case ePathFailed: case FAILED:
obj["status"] = "failed"; obj["status"] = "failed";
break; break;
case ePathIgnore: case IGNORE:
obj["status"] = "ignored"; obj["status"] = "ignored";
break; break;
default: default:
@ -385,7 +385,7 @@ namespace llarp::path
m_RXRate = 0; m_RXRate = 0;
m_TXRate = 0; m_TXRate = 0;
if (_status == ePathBuilding) if (_status == BUILDING)
{ {
if (buildStarted == 0s) if (buildStarted == 0s)
return; return;
@ -396,13 +396,13 @@ namespace llarp::path
{ {
LogWarn(name(), " waited for ", ToString(dlt), " and no path was built"); LogWarn(name(), " waited for ", ToString(dlt), " and no path was built");
r->router_profiling().MarkPathFail(this); r->router_profiling().MarkPathFail(this);
EnterState(ePathExpired, now); EnterState(EXPIRED, now);
return; return;
} }
} }
} }
// check to see if this path is dead // check to see if this path is dead
if (_status == ePathEstablished) if (_status == ESTABLISHED)
{ {
auto dlt = now - m_LastLatencyTestTime; auto dlt = now - m_LastLatencyTestTime;
if (dlt > path::LATENCY_INTERVAL && m_LastLatencyTestID == 0) if (dlt > path::LATENCY_INTERVAL && m_LastLatencyTestID == 0)
@ -420,13 +420,13 @@ namespace llarp::path
{ {
LogWarn(name(), " waited for ", ToString(dlt), " and path looks dead"); LogWarn(name(), " waited for ", ToString(dlt), " and path looks dead");
r->router_profiling().MarkPathFail(this); r->router_profiling().MarkPathFail(this);
EnterState(ePathTimeout, now); EnterState(TIMEOUT, now);
} }
} }
if (_status == ePathIgnore and now - m_LastRecvMessage >= path::ALIVE_TIMEOUT) if (_status == IGNORE and now - m_LastRecvMessage >= path::ALIVE_TIMEOUT)
{ {
// clean up this path as we dont use it anymore // clean up this path as we dont use it anymore
EnterState(ePathExpired, now); EnterState(EXPIRED, now);
} }
} }
@ -436,15 +436,15 @@ namespace llarp::path
bool bool
Path::Expired(llarp_time_t now) const Path::Expired(llarp_time_t now) const
{ {
if (_status == ePathFailed) if (_status == FAILED)
return true; return true;
if (_status == ePathBuilding) if (_status == BUILDING)
return false; return false;
if (_status == ePathTimeout) if (_status == TIMEOUT)
{ {
return now >= m_LastRecvMessage + PathReanimationTimeout; return now >= m_LastRecvMessage + PathReanimationTimeout;
} }
if (_status == ePathEstablished or _status == ePathIgnore) if (_status == ESTABLISHED or _status == IGNORE)
{ {
return now >= ExpireTime(); return now >= ExpireTime();
} }

@ -122,7 +122,7 @@ namespace llarp::path
/// current number of paths we created in status /// current number of paths we created in status
uint64_t uint64_t
CurrentOwnedPaths(path::PathStatus status = path::PathStatus::ePathEstablished); CurrentOwnedPaths(path::PathStatus status = path::PathStatus::ESTABLISHED);
Router* Router*
router() const router() const

@ -261,7 +261,7 @@ namespace llarp
const auto now = Now(); const auto now = Now();
for (auto& item : m_Paths) for (auto& item : m_Paths)
{ {
item.second->EnterState(ePathIgnore, now); item.second->EnterState(IGNORE, now);
} }
return true; return true;
} }
@ -275,7 +275,7 @@ namespace llarp
bool bool
Builder::ShouldRemove() const Builder::ShouldRemove() const
{ {
return IsStopped() and NumInStatus(ePathEstablished) == 0; return IsStopped() and NumInStatus(ESTABLISHED) == 0;
} }
bool bool
@ -505,40 +505,40 @@ namespace llarp
// be worth doing sooner rather than later. Leaving some TODOs below where fail // be worth doing sooner rather than later. Leaving some TODOs below where fail
// and success live. // and success live.
auto response_cb = [path](oxen::quic::message m) { auto response_cb = [path](oxen::quic::message m) {
if (m)
{
// TODO: inform success (what this means needs revisiting, badly)
path->EnterState(path::ESTABLISHED);
return;
}
try try
{ {
if (m) // TODO: inform failure (what this means needs revisiting, badly)
if (m.timed_out)
{ {
// TODO: inform success (what this means needs revisiting, badly) log::warning(path_cat, "Path build request timed out!");
path->EnterState(path::ePathEstablished); path->EnterState(path::TIMEOUT);
return;
}
if (not m)
{
log::warning(path_cat, "Path build request failed!");
} }
else else
{ {
oxenc::bt_dict_consumer d{m.body()}; oxenc::bt_dict_consumer d{m.body()};
auto status = d.require<std::string_view>(messages::STATUS_KEY); auto status = d.require<std::string_view>(messages::STATUS_KEY);
log::warning(path_cat, "Path build returned failure status: {}", status); log::warning(path_cat, "Path build returned failure status: {}", status);
path->EnterState(path::FAILED);
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
log::warning(path_cat, "Failed parsing path build response."); log::warning(path_cat, "Exception caught parsing path build response: {}", e.what());
} }
// TODO: inform failure (what this means needs revisiting, badly)
path->EnterState(path::ePathFailed);
}; };
if (not router->send_control_message( if (not router->send_control_message(
path->upstream(), "path_build", std::move(frames).str(), std::move(response_cb))) path->upstream(), "path_build", std::move(frames).str(), std::move(response_cb)))
{ {
log::warning(path_cat, "Error sending path_build control message"); log::warning(path_cat, "Error sending path_build control message");
// TODO: inform failure (what this means needs revisiting, badly) path->EnterState(path::FAILED, router->now());
path->EnterState(path::ePathFailed, router->now());
} }
} }

@ -13,10 +13,10 @@ namespace llarp::path
PathSet::ShouldBuildMore(llarp_time_t now) const PathSet::ShouldBuildMore(llarp_time_t now) const
{ {
(void)now; (void)now;
const auto building = NumInStatus(ePathBuilding); const auto building = NumInStatus(BUILDING);
if (building >= numDesiredPaths) if (building >= numDesiredPaths)
return false; return false;
const auto established = NumInStatus(ePathEstablished); const auto established = NumInStatus(ESTABLISHED);
return established < numDesiredPaths; return established < numDesiredPaths;
} }
@ -255,7 +255,7 @@ namespace llarp::path
auto itr = m_Paths.begin(); auto itr = m_Paths.begin();
while (itr != m_Paths.end()) while (itr != m_Paths.end())
{ {
if (itr->second->Status() == ePathEstablished && itr->second->SupportsAnyRoles(roles)) if (itr->second->Status() == ESTABLISHED && itr->second->SupportsAnyRoles(roles))
++count; ++count;
++itr; ++itr;
} }

@ -47,12 +47,12 @@ namespace llarp
/// status of a path /// status of a path
enum PathStatus enum PathStatus
{ {
ePathBuilding, BUILDING,
ePathEstablished, ESTABLISHED,
ePathTimeout, TIMEOUT,
ePathFailed, FAILED,
ePathIgnore, IGNORE,
ePathExpired EXPIRED
}; };
/// Stats about all our path builds /// Stats about all our path builds

@ -873,8 +873,7 @@ namespace llarp
router_contact.resign(); router_contact.resign();
save_rc(); save_rc();
_link_manager->gossip_rc( _link_manager->gossip_rc(local_rid(), router_contact.to_remote());
local_rid(), local_rid(), std::string{oxen::quic::to_sv(router_contact.view())});
last_rc_gossip = now_timepoint; last_rc_gossip = now_timepoint;

@ -299,7 +299,7 @@ namespace llarp::service
// expire convotags // expire convotags
EndpointUtil::ExpireConvoSessions(now, Sessions()); EndpointUtil::ExpireConvoSessions(now, Sessions());
if (NumInStatus(path::ePathEstablished) > 1) if (NumInStatus(path::ESTABLISHED) > 1)
{ {
for (const auto& item : _startup_ons_mappings) for (const auto& item : _startup_ons_mappings)
{ {
@ -1539,7 +1539,7 @@ namespace llarp::service
if (BuildCooldownHit(now)) if (BuildCooldownHit(now))
return false; return false;
const auto requiredPaths = std::max(numDesiredPaths, path::MIN_INTRO_PATHS); const auto requiredPaths = std::max(numDesiredPaths, path::MIN_INTRO_PATHS);
if (NumInStatus(path::ePathBuilding) >= requiredPaths) if (NumInStatus(path::BUILDING) >= requiredPaths)
return false; return false;
return NumPathsExistingAt(now + (path::DEFAULT_LIFETIME - path::INTRO_PATH_SPREAD)) return NumPathsExistingAt(now + (path::DEFAULT_LIFETIME - path::INTRO_PATH_SPREAD))
< requiredPaths; < requiredPaths;

@ -143,7 +143,7 @@ namespace llarp::service
{ {
// ignore new path if we are marked dead // ignore new path if we are marked dead
LogInfo(Name(), " marked bad, ignoring new path"); LogInfo(Name(), " marked bad, ignoring new path");
p->EnterState(path::ePathIgnore, Now()); p->EnterState(path::IGNORE, Now());
} }
else if (p->Endpoint() == next_intro.router) else if (p->Endpoint() == next_intro.router)
{ {
@ -375,7 +375,7 @@ namespace llarp::service
if (marked_bad or path::Builder::BuildCooldownHit(now)) if (marked_bad or path::Builder::BuildCooldownHit(now))
return false; return false;
if (NumInStatus(path::ePathBuilding) >= std::max(numDesiredPaths / size_t{2}, size_t{1})) if (NumInStatus(path::BUILDING) >= std::max(numDesiredPaths / size_t{2}, size_t{1}))
return false; return false;
size_t numValidPaths = 0; size_t numValidPaths = 0;

@ -24,6 +24,11 @@ namespace llarp
using bstring = std::basic_string<std::byte>; using bstring = std::basic_string<std::byte>;
using bstring_view = std::basic_string_view<std::byte>; using bstring_view = std::basic_string_view<std::byte>;
inline ustring operator""_us(const char* str, size_t len) noexcept
{
return {reinterpret_cast<const unsigned char*>(str), len};
}
// Helper function to switch between string_view and ustring_view // Helper function to switch between string_view and ustring_view
inline ustring_view inline ustring_view
to_usv(std::string_view v) to_usv(std::string_view v)

Loading…
Cancel
Save