Exit endpoints implemented

- free standing functions in link_manager
- sign and serialize functionalities siloed in llarp/messages/exit.hpp
pull/2204/head
dr7ana 8 months ago
parent 4ed6a01e02
commit 65bd224cf0

@ -133,15 +133,6 @@ namespace llarp
return crypto_stream_xchacha20_xor(buf, buf, size, n.data(), k.data()) == 0;
}
bool
Crypto::xchacha20_alt(
const llarp_buffer_t& out, const llarp_buffer_t& in, const SharedSecret& k, const byte_t* n)
{
if (in.sz > out.sz)
return false;
return crypto_stream_xchacha20_xor(out.base, in.base, in.sz, n, k.data()) == 0;
}
bool
Crypto::dh_client(
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
@ -195,6 +186,18 @@ namespace llarp
return crypto_sign_detached(sig.data(), nullptr, buf, size, secret.data()) != -1;
}
bool
Crypto::sign(uint8_t* sig, uint8_t* sk, uint8_t* buf, size_t size)
{
return crypto_sign_detached(sig, nullptr, buf, size, sk) != -1;
}
bool
Crypto::sign(uint8_t* sig, const SecretKey& sk, ustring_view buf)
{
return crypto_sign_detached(sig, nullptr, buf.data(), buf.size(), sk.data()) != -1;
}
bool
Crypto::sign(Signature& sig, const PrivateKey& privkey, uint8_t* buf, size_t size)
{
@ -245,6 +248,14 @@ namespace llarp
return crypto_sign_verify_detached(sig.data(), buf, size, pub.data()) != -1;
}
bool
Crypto::verify(ustring_view pub, ustring_view buf, ustring_view sig)
{
return (pub.size() == 32 && sig.size() == 64)
? crypto_sign_verify_detached(sig.data(), buf.data(), buf.size(), pub.data()) != -1
: false;
}
bool
Crypto::verify(uint8_t* pub, uint8_t* buf, size_t size, uint8_t* sig)
{

@ -11,6 +11,12 @@
namespace llarp
{
/*
TODO:
- make uint8_t pointers const where needed
-
*/
struct Crypto
{
Crypto();
@ -25,10 +31,6 @@ namespace llarp
bool
xchacha20(uint8_t*, size_t size, const SharedSecret&, const TunnelNonce&);
/// xchacha symmetric cipher (multibuffer)
bool
xchacha20_alt(const llarp_buffer_t&, const llarp_buffer_t&, const SharedSecret&, const byte_t*);
/// path dh creator's side
bool
dh_client(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&);
@ -50,12 +52,18 @@ namespace llarp
/// ed25519 sign
bool
sign(Signature&, const SecretKey&, uint8_t* buf, size_t size);
/// ed25519 sign, using pointers
bool
sign(uint8_t* sig, uint8_t* sk, uint8_t* buf, size_t size);
bool
sign(uint8_t* sig, const SecretKey& sk, ustring_view buf);
/// ed25519 sign (custom with derived keys)
bool
sign(Signature&, const PrivateKey&, uint8_t* buf, size_t size);
/// ed25519 verify
bool
verify(const PubKey&, uint8_t*, size_t, const Signature&);
bool verify(ustring_view, ustring_view, ustring_view);
bool
verify(uint8_t*, uint8_t*, size_t, uint8_t*);

@ -39,8 +39,6 @@ namespace llarp::routing
btdp.append("I", pubkey.ToView());
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("V", version);
btdp.append("X", address_lifetime);
btdp.append("Z", sig.ToView());
}
catch (...)
@ -63,10 +61,6 @@ namespace llarp::routing
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("X", address_lifetime, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
return false;
return read;
@ -87,7 +81,6 @@ namespace llarp::routing
{
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("V", version);
btdp.append("Y", nonce.ToView());
btdp.append("Z", sig.ToView());
}
@ -107,8 +100,6 @@ namespace llarp::routing
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Y", nonce, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
@ -155,7 +146,6 @@ namespace llarp::routing
btdp.append("B", backoff_time);
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("V", version);
btdp.append("Y", nonce.ToView());
btdp.append("Z", sig.ToView());
}
@ -177,8 +167,6 @@ namespace llarp::routing
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Y", nonce, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
@ -225,7 +213,6 @@ namespace llarp::routing
btdp.append("P", path_id.ToView());
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("V", version);
btdp.append("Z", sig.ToView());
}
catch (...)
@ -244,8 +231,6 @@ namespace llarp::routing
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("P", path_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))
@ -290,7 +275,6 @@ namespace llarp::routing
{
btdp.append("S", sequence_number);
btdp.append("T", tx_id);
btdp.append("V", version);
}
catch (...)
{
@ -308,8 +292,6 @@ namespace llarp::routing
return false;
if (!BEncodeMaybeReadDictInt("T", tx_id, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
return read;
}
@ -326,9 +308,7 @@ namespace llarp::routing
try
{
btdp.append("A", "C");
btdp.append("S", sequence_number);
btdp.append("V", version);
btdp.append("Y", nonce.ToView());
btdp.append("Z", sig.ToView());
}
@ -346,8 +326,6 @@ namespace llarp::routing
bool read = false;
if (!BEncodeMaybeReadDictInt("S", sequence_number, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Y", nonce, read, k, buf))
return false;
if (!BEncodeMaybeReadDictEntry("Z", sig, read, k, buf))

@ -13,7 +13,6 @@ namespace llarp::routing
uint64_t flag{0}; // 0 for snode, 1 for internet access
llarp::PubKey pubkey;
uint64_t tx_id{0};
uint64_t address_lifetime{0};
llarp::Signature sig;
ObtainExitMessage() : AbstractRoutingMessage()
@ -27,7 +26,6 @@ namespace llarp::routing
flag = 0;
pubkey.Zero();
tx_id = 0;
address_lifetime = 0;
sig.Zero();
}
@ -50,10 +48,8 @@ namespace llarp::routing
struct GrantExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
uint64_t tx_id;
Nonce_t nonce;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
std::string
@ -82,10 +78,9 @@ namespace llarp::routing
struct RejectExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
uint64_t backoff_time;
uint64_t tx_id;
Nonce_t nonce;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
void
@ -115,9 +110,8 @@ namespace llarp::routing
struct UpdateExitVerifyMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
uint64_t tx_id;
Nonce_t nonce;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
~UpdateExitVerifyMessage() override = default;
@ -142,10 +136,9 @@ namespace llarp::routing
struct UpdateExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
llarp::PathID_t path_id;
uint64_t tx_id;
Nonce_t nonce;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
bool
@ -175,9 +168,7 @@ namespace llarp::routing
struct CloseExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
Nonce_t nonce;
llarp::AlignedBuffer<16> nonce;
llarp::Signature sig;
std::string

@ -559,7 +559,8 @@ namespace llarp
{
if (m.timed_out)
{
// do something smart here inshallah
log::info(link_cat, "FindNameMessage timed out!");
return;
}
std::string payload;
@ -583,17 +584,17 @@ namespace llarp
{
if (payload == FindNameMessage::EXCEPTION)
{
log::critical(link_cat, "FindNameMessage failed with unkown error!");
log::info(link_cat, "FindNameMessage failed with unkown error!");
// resend?
}
else if (payload == FindNameMessage::NOT_FOUND)
{
log::critical(link_cat, "FindNameMessage failed with unkown error!");
log::info(link_cat, "FindNameMessage failed with unkown error!");
// what to do here?
}
else
log::critical(link_cat, "FindNameMessage failed with unkown error!");
log::info(link_cat, "FindNameMessage failed with unkown error!");
}
}
@ -697,7 +698,7 @@ namespace llarp
{
if (m.timed_out)
{
log::critical(link_cat, "FindRouterMessage timed out!");
log::info(link_cat, "FindRouterMessage timed out!");
return;
}
@ -729,7 +730,7 @@ namespace llarp
{
if (status == FindRouterMessage::EXCEPTION)
{
log::critical(link_cat, "FindRouterMessage failed with remote exception!");
log::info(link_cat, "FindRouterMessage failed with remote exception!");
// Do something smart here probably
return;
}
@ -738,19 +739,19 @@ namespace llarp
if (status == FindRouterMessage::RETRY_EXP)
{
log::critical(link_cat, "FindRouterMessage failed, retrying as exploratory!");
log::info(link_cat, "FindRouterMessage failed, retrying as exploratory!");
send_control_message(
target, "find_router", FindRouterMessage::serialize(target, false, true, 0));
}
else if (status == FindRouterMessage::RETRY_ITER)
{
log::critical(link_cat, "FindRouterMessage failed, retrying as iterative!");
log::info(link_cat, "FindRouterMessage failed, retrying as iterative!");
send_control_message(
target, "find_router", FindRouterMessage::serialize(target, true, false, 0));
}
else if (status == FindRouterMessage::RETRY_NEW)
{
log::critical(link_cat, "FindRouterMessage failed, retrying with new recipient!");
log::info(link_cat, "FindRouterMessage failed, retrying with new recipient!");
send_control_message(
target, "find_router", FindRouterMessage::serialize(target, false, false, 0));
}
@ -886,6 +887,12 @@ namespace llarp
void
LinkManager::handle_publish_intro_response(oxen::quic::message m)
{
if (m.timed_out)
{
log::info(link_cat, "PublishIntroMessage timed out!");
return;
}
std::string payload;
try
@ -907,12 +914,12 @@ namespace llarp
{
if (payload == PublishIntroMessage::EXCEPTION)
{
log::critical(link_cat, "PublishIntroMessage failed with remote exception!");
log::info(link_cat, "PublishIntroMessage failed with remote exception!");
// Do something smart here probably
return;
}
log::critical(link_cat, "PublishIntroMessage failed with error code: {}", payload);
log::info(link_cat, "PublishIntroMessage failed with error code: {}", payload);
if (payload == PublishIntroMessage::INVALID_INTROSET)
{}
@ -980,7 +987,22 @@ namespace llarp
peer_key,
"find_intro",
FindIntroMessage::serialize(
dht::Key_t{peer_key}, tag_name, tx_id, is_relayed, relay_order));
dht::Key_t{peer_key}, tag_name, tx_id, is_relayed, relay_order),
[original_msg = std::move(m)](oxen::quic::message relay_response) mutable {
if (relay_response)
log::info(
link_cat,
"Relayed FindIntroMessage returned successful response; transmitting to initial "
"requester");
else if (relay_response.timed_out)
log::critical(
link_cat, "Relayed FindIntroMessage timed out! Notifying initial requester");
else
log::critical(
link_cat, "Relayed FindIntroMessage failed! Notifying initial requester");
original_msg.respond(relay_response.body_str(), not relay_response);
});
}
else
{
@ -1001,7 +1023,7 @@ namespace llarp
{
if (m.timed_out)
{
log::critical(link_cat, "FindIntroMessage timed out!");
log::info(link_cat, "FindIntroMessage timed out!");
return;
}
@ -1010,11 +1032,7 @@ namespace llarp
try
{
oxenc::bt_dict_consumer btdc{m.body()};
if (m)
payload = btdc.require<std::string>("INTROSET");
else
payload = btdc.require<std::string>("STATUS");
payload = btdc.require<std::string>((m) ? "INTROSET" : "STATUS");
}
catch (const std::exception& e)
{
@ -1030,7 +1048,7 @@ namespace llarp
}
else
{
log::critical(link_cat, "FindIntroMessage failed with error: {}", payload);
log::info(link_cat, "FindIntroMessage failed with error: {}", payload);
// Do something smart here probably
}
}
@ -1158,47 +1176,79 @@ namespace llarp
void
LinkManager::handle_obtain_exit(oxen::quic::message m)
{
// TODO: implement transit_hop things like nextseqno(), info.rxID, etc
std::string copy{m.body_str()};
ustring pubkey, signature;
uint64_t flag, tx_id, seq_no;
try
{
oxenc::bt_dict_consumer btdc{copy};
uint64_t flag;
ustring_view pubkey, sig;
std::string_view tx_id;
oxenc::bt_list_consumer btlc{m.body()};
auto dict_data = btlc.consume_dict_data();
oxenc::bt_dict_consumer btdc{dict_data};
sig = to_usv(btlc.consume_string_view());
flag = btdc.require<uint64_t>("E");
pubkey = btdc.require<ustring>("I");
seq_no = btdc.require<uint64_t>("S");
tx_id = btdc.require<uint64_t>("T");
signature = btdc.require<ustring>("Z");
pubkey = btdc.require<ustring_view>("I");
tx_id = btdc.require<std::string_view>("T");
RouterID target{pubkey.data()};
auto transit_hop = std::static_pointer_cast<path::TransitHop>(
router.path_context().GetByUpstream(target, PathID_t{to_usv(tx_id).data()}));
const auto rx_id = transit_hop->info.rxID;
const auto next_seqno = transit_hop->NextSeqNo();
auto success =
(CryptoManager::instance()->verify(pubkey, to_usv(dict_data), sig)
and router.exitContext().ObtainNewExit(PubKey{pubkey.data()}, rx_id, flag != 0));
m.respond(
ObtainExit::sign_and_serialize_response(router.identity(), next_seqno, tx_id),
not success);
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response({{"STATUS", ObtainExit::EXCEPTION}}), true);
return;
throw;
}
RouterID target{pubkey.data()};
if (CryptoManager::instance()->verify(
pubkey.data(), reinterpret_cast<uint8_t*>(copy.data()), copy.size(), signature.data()))
{}
}
void
LinkManager::handle_obtain_exit_response(oxen::quic::message m)
{
if (m.timed_out)
{
log::info(link_cat, "ObtainExitMessage timed out!");
return;
}
if (m.is_error)
{
// TODO: what to do here
}
try
{
oxenc::bt_dict_consumer btdc{m.body()};
std::string_view tx_id;
ustring_view sig;
oxenc::bt_list_consumer btlc{m.body()};
auto dict_data = btlc.consume_dict_data();
oxenc::bt_dict_consumer btdc{dict_data};
sig = to_usv(btlc.consume_string_view());
tx_id = btdc.require<std::string_view>("T");
auto path_ptr = std::static_pointer_cast<path::Path>(
router.path_context().GetByDownstream(router.pubkey(), PathID_t{to_usv(tx_id).data()}));
if (CryptoManager::instance()->verify(router.pubkey(), to_usv(dict_data), sig))
path_ptr->enable_exit_traffic();
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response({{"STATUS", "EXCEPTION"}}), true);
return;
throw;
}
}
@ -1207,12 +1257,38 @@ namespace llarp
{
try
{
oxenc::bt_dict_consumer btdc{m.body()};
std::string_view path_id, tx_id;
ustring_view sig;
oxenc::bt_list_consumer btlc{m.body()};
auto dict_data = btlc.consume_dict_data();
oxenc::bt_dict_consumer btdc{dict_data};
sig = to_usv(btlc.consume_string_view());
path_id = btdc.require<std::string_view>("P");
tx_id = btdc.require<std::string_view>("T");
auto transit_hop = std::static_pointer_cast<path::TransitHop>(
router.path_context().GetByUpstream(router.pubkey(), PathID_t{to_usv(tx_id).data()}));
const auto next_seqno = transit_hop->NextSeqNo();
if (auto exit_ep = router.exitContext().FindEndpointForPath(PathID_t{to_usv(path_id).data()}))
{
if (CryptoManager::instance()->verify(exit_ep->PubKey().data(), to_usv(dict_data), sig))
{
(exit_ep->UpdateLocalPath(transit_hop->info.rxID))
? m.respond(
UpdateExit::sign_and_serialize_response(router.identity(), next_seqno, tx_id))
: m.respond(serialize_response({{"STATUS", UpdateExit::UPDATE_FAILED}}), true);
}
// If we fail to verify the message, no-op
}
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response({{"STATUS", "EXCEPTION"}}), true);
m.respond(serialize_response({{"STATUS", UpdateExit::EXCEPTION}}), true);
return;
}
}
@ -1220,14 +1296,45 @@ namespace llarp
void
LinkManager::handle_update_exit_response(oxen::quic::message m)
{
if (m.timed_out)
{
log::info(link_cat, "UpdateExitMessage timed out!");
return;
}
if (m.is_error)
{
// TODO: what to do here
}
try
{
oxenc::bt_dict_consumer btdc{m.body()};
std::string tx_id;
ustring_view sig;
oxenc::bt_list_consumer btlc{m.body()};
auto dict_data = btlc.consume_dict_data();
oxenc::bt_dict_consumer btdc{dict_data};
sig = to_usv(btlc.consume_string_view());
tx_id = btdc.require<std::string_view>("T");
auto path_ptr = std::static_pointer_cast<path::Path>(
router.path_context().GetByDownstream(router.pubkey(), PathID_t{to_usv(tx_id).data()}));
if (CryptoManager::instance()->verify(router.pubkey(), to_usv(dict_data), sig))
{
if (path_ptr->update_exit(std::stoul(tx_id)))
{
// TODO: talk to tom and Jason about how this stupid shit was a no-op originally
// see Path::HandleUpdateExitVerifyMessage
}
else
{}
}
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response({{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -1237,12 +1344,37 @@ namespace llarp
{
try
{
oxenc::bt_dict_consumer btdc{m.body()};
std::string_view tx_id;
ustring_view sig;
oxenc::bt_list_consumer btlc{m.body()};
auto dict_data = btlc.consume_dict_data();
oxenc::bt_dict_consumer btdc{dict_data};
sig = to_usv(btlc.consume_string_view());
tx_id = btdc.require<std::string_view>("T");
auto transit_hop = std::static_pointer_cast<path::TransitHop>(
router.path_context().GetByUpstream(router.pubkey(), PathID_t{to_usv(tx_id).data()}));
const auto rx_id = transit_hop->info.rxID;
const auto next_seqno = transit_hop->NextSeqNo();
if (auto exit_ep = router.exitContext().FindEndpointForPath(rx_id))
{
if (CryptoManager::instance()->verify(exit_ep->PubKey().data(), to_usv(dict_data), sig))
{
exit_ep->Close();
m.respond(CloseExit::sign_and_serialize_response(router.identity(), next_seqno, tx_id));
}
}
m.respond(serialize_response({{"STATUS", CloseExit::UPDATE_FAILED}}), true);
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response({{"STATUS", "EXCEPTION"}}), true);
m.respond(serialize_response({{"STATUS", CloseExit::EXCEPTION}}), true);
return;
}
}
@ -1250,14 +1382,39 @@ namespace llarp
void
LinkManager::handle_close_exit_response(oxen::quic::message m)
{
if (m.timed_out)
{
log::info(link_cat, "CloseExitMessage timed out!");
return;
}
if (m.is_error)
{
// TODO: what to do here
}
try
{
oxenc::bt_dict_consumer btdc{m.body()};
std::string_view nonce, tx_id;
ustring_view sig;
oxenc::bt_list_consumer btlc{m.body()};
auto dict_data = btlc.consume_dict_data();
oxenc::bt_dict_consumer btdc{dict_data};
sig = to_usv(btlc.consume_string_view());
tx_id = btdc.require<std::string_view>("T");
nonce = btdc.require<std::string_view>("Y");
auto path_ptr = std::static_pointer_cast<path::Path>(
router.path_context().GetByDownstream(router.pubkey(), PathID_t{to_usv(tx_id).data()}));
if (path_ptr->SupportsAnyRoles(path::ePathRoleExit | path::ePathRoleSVC)
and CryptoManager::instance()->verify(router.pubkey(), to_usv(dict_data), sig))
path_ptr->close_exit();
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response({{"STATUS", "EXCEPTION"}}), true);
return;
}
}

@ -335,7 +335,10 @@ namespace llarp
{"find_name", &LinkManager::handle_find_name_response},
{"find_router", &LinkManager::handle_find_router_response},
{"publish_intro", &LinkManager::handle_publish_intro_response},
{"find_intro", &LinkManager::handle_find_intro_response}};
{"find_intro", &LinkManager::handle_find_intro_response},
{"update_exit", &LinkManager::handle_update_exit_response},
{"obtain_exit", &LinkManager::handle_obtain_exit_response},
{"close_exit", &LinkManager::handle_close_exit_response}};
std::string
serialize_response(oxenc::bt_dict supplement = {});

@ -36,6 +36,7 @@ namespace llarp
{
inline auto EXCEPTION = "EXCEPTION"sv;
inline auto NOT_FOUND = "NOT FOUND"sv;
inline auto TIMED_OUT = "TIMED OUT"sv;
inline auto INVALID_ORDER = "INVALID ORDER"sv;
inline auto INSUFFICIENT_NODES = "INSUFFICIENT NODES"sv;

@ -4,22 +4,176 @@
namespace llarp
{
/*
TODO:
- change these parameters to ustringviews and ustrings where needed
*/
namespace ObtainExit
{
inline auto EXCEPTION = "EXCEPTION"sv;
}
// flag: 0 = Exit, 1 = Snode
inline std::string
sign_and_serialize(
SecretKey sk, uint64_t flag, std::string pubkey, uint64_t seq_no, std::string tx_id)
{
oxenc::bt_list_producer btlp;
std::string sig(64, '\0');
{
auto btdp = btlp.append_dict();
btdp.append("E", flag);
btdp.append("I", pubkey);
btdp.append("S", seq_no);
btdp.append("T", tx_id);
if (not CryptoManager::instance()->sign(
reinterpret_cast<uint8_t*>(sig.data()), sk, to_usv(btdp.view())))
throw std::runtime_error{
"Error: ObtainExitMessage failed to sign and serialize contents!"};
}
btlp.append(sig.data());
return std::move(btlp).str();
}
inline std::string
sign_and_serialize_response(SecretKey sk, uint64_t seq_no, std::string_view tx_id)
{
oxenc::bt_list_producer btlp;
std::string sig(64, '\0');
std::string nonce(16, '\0');
randombytes(reinterpret_cast<uint8_t*>(nonce.data()), 16);
{
oxenc::bt_dict_producer btdp;
btdp.append("S", seq_no);
btdp.append("T", tx_id);
btdp.append("Y", nonce);
if (CryptoManager::instance()->sign(
reinterpret_cast<uint8_t*>(sig.data()), sk, to_usv(btdp.view())))
throw std::runtime_error{
"Error: ObtainExitMessage response failed to sign and serialize contents!"};
}
btlp.append(sig.data());
return std::move(btlp).str();
}
} // namespace ObtainExit
namespace UpdateExit
{
inline auto EXCEPTION = "EXCEPTION"sv;
inline auto UPDATE_FAILED = "EXIT UPDATE FAILED"sv;
inline std::string
sign_and_serialize(SecretKey sk, std::string path_id, std::string seq_no, std::string tx_id)
{
oxenc::bt_list_producer btlp;
std::string sig(64, '\0');
{
auto btdp = btlp.append_dict();
btdp.append("P", path_id);
btdp.append("S", seq_no);
btdp.append("T", tx_id);
if (not CryptoManager::instance()->sign(
reinterpret_cast<uint8_t*>(sig.data()), sk, to_usv(btdp.view())))
throw std::runtime_error{
"Error: UpdateExitMessage failed to sign and serialize contents!"};
}
}
btlp.append(sig.data());
return std::move(btlp).str();
}
inline std::string
sign_and_serialize_response(SecretKey sk, uint64_t seq_no, std::string_view tx_id)
{
oxenc::bt_list_producer btlp;
std::string sig(64, '\0');
std::string nonce(16, '\0');
randombytes(reinterpret_cast<uint8_t*>(nonce.data()), 16);
{
oxenc::bt_dict_producer btdp;
btdp.append("S", seq_no);
btdp.append("T", tx_id);
btdp.append("Y", nonce);
if (CryptoManager::instance()->sign(
reinterpret_cast<uint8_t*>(sig.data()), sk, to_usv(btdp.view())))
throw std::runtime_error{
"Error: UpdateExitMessage response failed to sign and serialize contents!"};
}
btlp.append(sig.data());
return std::move(btlp).str();
}
} // namespace UpdateExit
namespace CloseExit
{
inline auto EXCEPTION = "EXCEPTION"sv;
inline auto UPDATE_FAILED = "CLOSE EXIT FAILED"sv;
inline std::string
sign_and_serialize(SecretKey sk, std::string seq_no, std::string tx_id)
{
oxenc::bt_list_producer btlp;
std::string sig(64, '\0');
std::string nonce(16, '\0');
randombytes(reinterpret_cast<uint8_t*>(nonce.data()), 16);
{
auto btdp = btlp.append_dict();
btdp.append("S", seq_no);
btdp.append("T", tx_id);
btdp.append("Y", nonce);
if (not CryptoManager::instance()->sign(
reinterpret_cast<uint8_t*>(sig.data()), sk, to_usv(btdp.view())))
throw std::runtime_error{
"Error: CloseExitMessage failed to sign and serialize contents!"};
}
btlp.append(sig.data());
return std::move(btlp).str();
}
inline std::string
sign_and_serialize_response(SecretKey sk, uint64_t seq_no, std::string_view tx_id)
{
oxenc::bt_list_producer btlp;
std::string sig(64, '\0');
std::string nonce(16, '\0');
randombytes(reinterpret_cast<uint8_t*>(nonce.data()), 16);
{
oxenc::bt_dict_producer btdp;
btdp.append("S", seq_no);
btdp.append("T", tx_id);
btdp.append("Y", nonce);
if (CryptoManager::instance()->sign(
reinterpret_cast<uint8_t*>(sig.data()), sk, to_usv(btdp.view())))
throw std::runtime_error{
"Error: CloseExitMessage response failed to sign and serialize contents!"};
}
}
btlp.append(sig.data());
return std::move(btlp).str();
}
} // namespace CloseExit
} // namespace llarp

@ -425,6 +425,22 @@ namespace llarp::path
return true;
}
bool
Path::update_exit(uint64_t tx_id)
{
if (m_UpdateExitTX && tx_id == m_UpdateExitTX)
{
if (m_ExitUpdated)
return m_ExitUpdated(shared_from_this());
}
if (m_CloseExitTX && tx_id == m_CloseExitTX)
{
if (m_ExitClosed)
return m_ExitClosed(shared_from_this());
}
return false;
}
void
Path::Tick(llarp_time_t now, Router* r)
{

@ -248,6 +248,23 @@ namespace llarp
return now >= (ExpireTime() - dlt);
}
void
enable_exit_traffic()
{
log::info(path_cat, "{} {} granted exit", name(), Endpoint());
_role |= ePathRoleExit;
}
void
close_exit()
{
log::info(path_cat, "{} hd its exit closed", name());
_role &= ePathRoleExit;
}
bool
update_exit(uint64_t tx_id);
bool
Expired(llarp_time_t now) const override;
@ -277,8 +294,10 @@ namespace llarp
bool
HandleCloseExitMessage(const routing::CloseExitMessage& msg, Router* r) override;
bool
HandleGrantExitMessage(const routing::GrantExitMessage& msg, Router* r) override;
bool
HandleRejectExitMessage(const routing::RejectExitMessage& msg, Router* r) override;

@ -251,16 +251,6 @@ namespace llarp::path
[](const std::shared_ptr<TransitHop>& h) -> HopHandler_ptr { return h; });
}
bool
PathContext::TransitHopPreviousIsRouter(const PathID_t& path, const RouterID& otherRouter)
{
SyncTransitMap_t::Lock_t lock(m_TransitPaths.first);
auto itr = m_TransitPaths.second.find(path);
if (itr == m_TransitPaths.second.end())
return false;
return itr->second->info.downstream == otherRouter;
}
HopHandler_ptr
PathContext::GetByDownstream(const RouterID& remote, const PathID_t& id)
{
@ -273,6 +263,16 @@ namespace llarp::path
[](const std::shared_ptr<TransitHop>& h) -> HopHandler_ptr { return h; });
}
bool
PathContext::TransitHopPreviousIsRouter(const PathID_t& path, const RouterID& otherRouter)
{
SyncTransitMap_t::Lock_t lock(m_TransitPaths.first);
auto itr = m_TransitPaths.second.find(path);
if (itr == m_TransitPaths.second.end())
return false;
return itr->second->info.downstream == otherRouter;
}
PathSet_ptr
PathContext::GetLocalPathSet(const PathID_t& id)
{

@ -436,7 +436,6 @@ namespace llarp
const auto& nextHop = lastHop ? path_hops[i].rc.pubkey : path_hops[i + 1].rc.pubkey;
// TODO: talk to Tom about what he thinks about this
PathBuildMessage::setup_hop_keys(path_hops[i], nextHop);
auto frame_str = PathBuildMessage::serialize(path_hops[i]);
@ -458,9 +457,6 @@ namespace llarp
frames.append(dummy);
}
// TODO: talk to Tom about whether we do still this or not
// router->notify_router_event<tooling::PathAttemptEvent>(router->pubkey(), path);
auto self = GetSelf();
router->path_context().AddOwnPath(self, path);
PathBuildStarted(path);

@ -25,6 +25,13 @@ namespace llarp
using bstring = std::basic_string<std::byte>;
using bstring_view = std::basic_string_view<std::byte>;
// Helper function to switch between string_view and ustring_view
inline ustring_view
to_usv(std::string_view v)
{
return {reinterpret_cast<const uint8_t*>(v.data()), v.size()};
}
struct llarp_buffer
{
private:

@ -15,44 +15,6 @@
namespace llarp
{
bool
CaselessLessThan::operator()(std::string_view lhs, std::string_view rhs) const
{
const size_t s = std::min(lhs.size(), rhs.size());
for (size_t i = 0; i < s; ++i)
{
auto l = std::tolower(lhs[i]);
auto r = std::tolower(rhs[i]);
if (l < r)
{
return true;
}
if (l > r)
{
return false;
}
}
return lhs.size() < rhs.size();
}
bool
IsFalseValue(std::string_view str)
{
static const std::set<std::string_view, CaselessLessThan> vals{"no", "false", "0", "off"};
return vals.count(str) > 0;
}
bool
IsTrueValue(std::string_view str)
{
static const std::set<std::string_view, CaselessLessThan> vals{"yes", "true", "1", "on"};
return vals.count(str) > 0;
}
constexpr static char whitespace[] = " \t\n\r\f\v";
std::string_view
@ -127,22 +89,6 @@ namespace llarp
return results;
}
void
trim(std::string_view& s)
{
constexpr auto simple_whitespace = " \t\r\n"sv;
auto pos = s.find_first_not_of(simple_whitespace);
if (pos == std::string_view::npos)
{ // whole string is whitespace
s.remove_prefix(s.size());
return;
}
s.remove_prefix(pos);
pos = s.find_last_not_of(simple_whitespace);
assert(pos != std::string_view::npos);
s.remove_suffix(s.size() - (pos + 1));
}
std::string
lowercase_ascii_string(std::string src)
{
@ -151,45 +97,4 @@ namespace llarp
ch = ch + ('a' - 'A');
return src;
}
std::string
friendly_duration(std::chrono::nanoseconds dur)
{
const double dsecs = std::chrono::duration<double>(dur).count();
return fmt::format(
dur >= 24h ? "{0}d{1}h{2}m{3}s"
: dur >= 1h ? "{1}h{2}m{3}s"
: dur >= 1min ? "{2}m{3}s"
: dur >= 1s ? "{4:.3f}s"
: dur >= 1ms ? "{5:.3f}s"
: dur >= 1us ? u8"{6:.3f}µs"
: "{7}ns",
dur / 24h,
dur / 1h,
dur / 1min,
dur / 1s,
dsecs,
dsecs * 1'000,
dsecs * 1'000'000,
dur.count());
}
std::wstring
to_wide(std::string data)
{
std::wstring buf;
buf.resize(data.size());
#ifdef _WIN32
// win32 specific codepath because balmer made windows so that man may suffer
if (MultiByteToWideChar(CP_UTF8, 0, data.c_str(), data.size(), buf.data(), buf.size()) == 0)
throw win32::error{GetLastError(), "failed to convert string to wide string"};
#else
// this dumb but probably works (i guess?)
std::transform(
data.begin(), data.end(), buf.begin(), [](const auto& ch) -> wchar_t { return ch; });
#endif
return buf;
}
} // namespace llarp

@ -9,44 +9,6 @@
namespace llarp
{
bool
IsFalseValue(std::string_view str);
struct CaselessLessThan
{
bool
operator()(std::string_view lhs, std::string_view rhs) const;
};
bool
IsTrueValue(std::string_view str);
/// Trim leading and trailing (ascii) whitespace from the given string;
/// returns a std::string_view of the trimmed part of the string.
[[nodiscard]] std::string_view
TrimWhitespace(std::string_view str);
using namespace std::literals;
/// Returns true if the first string is equal to the second string, compared case-insensitively.
inline bool
string_iequal(std::string_view s1, std::string_view s2)
{
return std::equal(s1.begin(), s1.end(), s2.begin(), s2.end(), [](char a, char b) {
return std::tolower(static_cast<unsigned char>(a))
== std::tolower(static_cast<unsigned char>(b));
});
}
/// Returns true if the first string matches any of the given strings case-insensitively.
/// Arguments must be string literals, std::string, or std::string_views
template <typename S1, typename... S>
bool
string_iequal_any(const S1& s1, const S&... s)
{
return (... || string_iequal(s1, s));
}
/// Returns true if the first argument begins with the second argument
inline constexpr bool
starts_with(std::string_view str, std::string_view prefix)
@ -112,11 +74,6 @@ namespace llarp
return join(delimiter, c.begin(), c.end());
}
/// Simple version of whitespace trimming: mutates the given string view to remove leading
/// space, \t, \r, \n. (More exotic and locale-dependent whitespace is not removed).
void
trim(std::string_view& s);
/// Parses an integer of some sort from a string, requiring that the entire string be consumed
/// during parsing. Return false if parsing failed, sets `value` and returns true if the entire
/// string was consumed.
@ -135,13 +92,4 @@ namespace llarp
std::string
lowercase_ascii_string(std::string src);
/// Converts a duration into a human friendlier string.
std::string
friendly_duration(std::chrono::nanoseconds dur);
/// convert a "normal" string into a wide string
std::wstring
to_wide(std::string data);
} // namespace llarp

Loading…
Cancel
Save