From 6b1e3fbbc0d8d2999dcf0d2094d87e31e34eac4a Mon Sep 17 00:00:00 2001 From: dr7ana Date: Mon, 16 Oct 2023 06:39:57 -0700 Subject: [PATCH] Touched up path build message handling --- llarp/crypto/crypto.cpp | 54 ++++++++ llarp/crypto/crypto.hpp | 8 ++ llarp/exit/endpoint.hpp | 1 - llarp/link/link_manager.cpp | 242 +++++++++++++++++++----------------- llarp/messages/exit.hpp | 19 +-- llarp/messages/path.hpp | 32 ++--- llarp/path/pathbuilder.cpp | 1 + 7 files changed, 211 insertions(+), 146 deletions(-) diff --git a/llarp/crypto/crypto.cpp b/llarp/crypto/crypto.cpp index 9de7ee666..471fa3187 100644 --- a/llarp/crypto/crypto.cpp +++ b/llarp/crypto/crypto.cpp @@ -45,6 +45,28 @@ namespace llarp return true; } + static bool + dh(uint8_t* out, + const uint8_t* client_pk, + const uint8_t* server_pk, + const uint8_t* themPub, + const uint8_t* usSec) + { + llarp::SharedSecret shared; + crypto_generichash_state h; + + if (crypto_scalarmult_curve25519(shared.data(), usSec, themPub)) + { + return false; + } + crypto_generichash_blake2b_init(&h, nullptr, 0U, shared.size()); + crypto_generichash_blake2b_update(&h, client_pk, 32); + crypto_generichash_blake2b_update(&h, server_pk, 32); + crypto_generichash_blake2b_update(&h, shared.data(), 32); + crypto_generichash_blake2b_final(&h, out, shared.size()); + return true; + } + static bool dh_client_priv( llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n) @@ -56,6 +78,7 @@ namespace llarp return crypto_generichash_blake2b(shared.data(), 32, n.data(), 32, dh_result.data(), 32) != -1; } + llarp::LogWarn("crypto::dh_client - dh failed"); return false; } @@ -65,11 +88,27 @@ namespace llarp llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n) { llarp::SharedSecret dh_result; + if (dh(dh_result, pk, sk.toPublic(), pk.data(), sk)) { return crypto_generichash_blake2b(shared.data(), 32, n.data(), 32, dh_result.data(), 32) != -1; } + + llarp::LogWarn("crypto::dh_server - dh failed"); + return false; + } + + static bool + dh_server_priv(uint8_t* shared, const uint8_t* pk, const uint8_t* sk, const uint8_t* nonce) + { + llarp::SharedSecret dh_result; + + if (dh(dh_result.data(), pk, sk, pk, sk)) + { + return crypto_generichash_blake2b(shared, 32, nonce, 32, dh_result.data(), 32) != -1; + } + llarp::LogWarn("crypto::dh_server - dh failed"); return false; } @@ -133,6 +172,12 @@ namespace llarp return crypto_stream_xchacha20_xor(buf, buf, size, n.data(), k.data()) == 0; } + bool + Crypto::xchacha20(uint8_t* buf, size_t size, const uint8_t* secret, const uint8_t* nonce) + { + return crypto_stream_xchacha20_xor(buf, buf, size, nonce, secret) == 0; + } + bool Crypto::dh_client( llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n) @@ -146,6 +191,15 @@ namespace llarp { return dh_server_priv(shared, pk, sk, n); } + bool + Crypto::dh_server( + uint8_t* shared_secret, + const uint8_t* other_pk, + const uint8_t* local_pk, + const uint8_t* nonce) + { + return dh_server_priv(shared_secret, other_pk, local_pk, nonce); + } /// transport dh client side bool Crypto::transport_dh_client( diff --git a/llarp/crypto/crypto.hpp b/llarp/crypto/crypto.hpp index fd5adaf4d..25d7b2705 100644 --- a/llarp/crypto/crypto.hpp +++ b/llarp/crypto/crypto.hpp @@ -30,6 +30,8 @@ namespace llarp /// xchacha symmetric cipher bool xchacha20(uint8_t*, size_t size, const SharedSecret&, const TunnelNonce&); + bool + xchacha20(uint8_t*, size_t size, const uint8_t*, const uint8_t*); /// path dh creator's side bool @@ -37,6 +39,12 @@ namespace llarp /// path dh relay side bool dh_server(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&); + bool + dh_server( + uint8_t* shared_secret, + const uint8_t* other_pk, + const uint8_t* local_pk, + const uint8_t* nonce); /// transport dh client side bool transport_dh_client(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&); diff --git a/llarp/exit/endpoint.hpp b/llarp/exit/endpoint.hpp index 9f0943f8d..45e11f160 100644 --- a/llarp/exit/endpoint.hpp +++ b/llarp/exit/endpoint.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 35efaf78b..b0de20791 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -536,7 +536,9 @@ namespace llarp } _router.rpc_client()->lookup_ons_hash( - name_hash, [this, msg = std::move(m)](std::optional maybe) mutable { + name_hash, + [this, + msg = std::move(m)]([[maybe_unused]] std::optional maybe) mutable { if (maybe) msg.respond(serialize_response({{"NAME", maybe->ciphertext}})); else @@ -1108,77 +1110,93 @@ namespace llarp { if (!_router.path_context().AllowingTransit()) { - log::warning("got path build request when not permitting transit"); + log::warning(link_cat, "got path build request when not permitting transit"); m.respond(serialize_response({{"STATUS", PathBuildMessage::NO_TRANSIT}}), true); return; } try { - // not using list_consumer here because we need to move the first (our) frame - // to the end and re-send, unless we're the terminal hop. This could be done - // with list_consumer, but it would involve messy mucking around with the - // encoded list. Revisit if optimization issue (shouldn't be). - auto frame_list = oxenc::bt_deserialize(m.body()); - if (frames.size() != path::MAX_LEN) - { - log::info( - link_cat, - "Path build request has invalid number of records, ", - frame_list.size(), - "!=", - path::MAX_LEN); - m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_FRAMES}}), true); - return; - } - - const auto& hash = frame_list[0].at("hash"); - auto& frame_str = frame_list[0].at("frame"); - - oxenc::bt_dict_consumer frame_dict{frame_str}; - - auto hop_info = frame_dict.require("encrypted"); - TunnelNonce nonce; - nonce.from_string_view(frame_dict.require("nonce")); - Pubkey otherPubkey; - otherPubkey.from_string_view(frame_dict.require("pubkey")); + std::string payload{m.body()}, frame_payload; + std::string frame, hash, hop_payload, commkey, rx_id, tx_id, upstream; + ustring other_pubkey, outer_nonce, inner_nonce; + uint64_t lifetime; auto crypto = CryptoManager::instance(); - SharedSecret shared; - // derive shared secret using ephemeral pubkey and our secret key (and nonce) - if (!crypto->dh_server(shared, otherPubkey, _router.identity(), nonce)) + try { - log::info("DH failed during path build."); - m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); - return; + oxenc::bt_list_consumer btlc{payload}; + frame_payload = btlc.consume_string(); + + oxenc::bt_dict_consumer frame_info{frame_payload}; + hash = frame_info.require("HASH"); + frame = frame_info.require("FRAME"); + + oxenc::bt_dict_consumer hop_dict{frame}; + hop_payload = frame_info.require("ENCRYPTED"); + outer_nonce = frame_info.require("NONCE"); + other_pubkey = frame_info.require("PUBKEY"); + + SharedSecret shared; + // derive shared secret using ephemeral pubkey and our secret key (and nonce) + if (!crypto->dh_server( + shared.data(), other_pubkey.data(), _router.pubkey(), inner_nonce.data())) + { + log::info(link_cat, "DH server initialization failed during path build"); + m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); + return; + } + + // hash data and check against given hash + ShortHash digest; + if (!crypto->hmac( + digest.data(), + reinterpret_cast(frame.data()), + frame.size(), + shared)) + { + log::error(link_cat, "HMAC failed on path build request"); + m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); + return; + } + if (!std::equal( + digest.begin(), digest.end(), reinterpret_cast(hash.data()))) + { + log::info(link_cat, "HMAC mismatch on path build request"); + m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); + return; + } + + // decrypt frame with our hop info + if (!crypto->xchacha20( + reinterpret_cast(hop_payload.data()), + hop_payload.size(), + shared.data(), + outer_nonce.data())) + { + log::info(link_cat, "Decrypt failed on path build request"); + m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); + return; + } + + oxenc::bt_dict_consumer hop_info{hop_payload}; + commkey = hop_info.require("COMMKEY"); + lifetime = hop_info.require("LIFETIME"); + inner_nonce = hop_info.require("NONCE"); + rx_id = hop_info.require("RX"); + tx_id = hop_info.require("TX"); + upstream = hop_info.require("UPSTREAM"); + } + catch (...) + { + log::warning(link_cat, "Error: failed to deserialize path build message"); + throw; } - // hash data and check against given hash - ShortHash digest; - if (!crypto->hmac( - digest.data(), - reinterpret_cast(frame_str.data()), - frame_str.size(), - shared)) + if (frame.empty()) { - log::error(link_cat, "HMAC failed on path build request"); - m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); - return; - } - if (!std::equal( - digest.begin(), digest.end(), reinterpret_cast(hash.data()))) - { - log::info("HMAC mismatch on path build request"); - m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); - return; - } - - // decrypt frame with our hop info - if (!crypto->xchacha20( - reinterpret_cast(hop_info.data()), hop_info.size(), shared, nonce)) - { - log::info("decrypt failed on path build request"); - m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); + log::info(link_cat, "Path build request received invalid frame"); + m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_FRAMES}}), true); return; } @@ -1189,18 +1207,20 @@ namespace llarp // TODO: also need downstream for IP / path build limiting clients auto hop = std::make_shared(); // hop->info.downstream = m.from(); // TODO: RouterID m.from() or similar - auto hop_dict = oxenc::bt_dict_consumer{hop_info}; // extract pathIDs and check if zero or used - hop->info.txID.from_string_view(hop_dict.require("txid")); - hop->info.rxID.from_string_view(hop_dict.require("rxid")); - if (info.txID.IsZero() || info.rxID.IsZero()) + auto& hop_info = hop->info; + hop_info.txID.from_string_view(tx_id); + hop_info.rxID.from_string_view(rx_id); + + if (hop_info.txID.IsZero() || hop_info.rxID.IsZero()) { - log::info("Invalid PathID; PathIDs must be non-zero."); + log::warning(link_cat, "Invalid PathID; PathIDs must be non-zero"); m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_PATHID}}), true); return; } - hop->info.upstream.from_string_view(hop_dict.require("next"); + + hop_info.upstream.from_string_view(upstream); // TODO: need downstream (above), and also the whole transit hop container is garbage. // namely the PathID uniqueness checking uses the PathIDs and upstream/downstream @@ -1208,19 +1228,17 @@ namespace llarp // a different upstream, that would be "unique" but we wouldn't know where // to route messages (nevermind that messages don't currently know the RouterID // they came from). - if (_router.path_context.HasTransitHop(hop->info)) + if (_router.path_context().HasTransitHop(hop_info)) { - log::info("Invalid PathID; PathIDs must be unique."); + log::warning(link_cat, "Invalid PathID; PathIDs must be unique"); m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_PATHID}}), true); return; } - otherPubkey.from_string_view(hop_dict.require("commkey")); - nonce.from_string_view(hop_dict.require("nonce")); - - if (!crypto->dh_server(hop->pathKey, otherPubkey, _router.identity(), nonce)) + if (!crypto->dh_server( + hop->pathKey.data(), other_pubkey.data(), _router.pubkey(), inner_nonce.data())) { - log::info("DH failed during path build."); + log::warning(link_cat, "DH failed during path build."); m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_CRYPTO}}), true); return; } @@ -1228,51 +1246,50 @@ namespace llarp crypto->shorthash(hop->nonceXOR, hop->pathKey.data(), hop->pathKey.size()); // set and check path lifetime - hop->lifetime = 1ms * hop_dict.require("lifetime"); + hop->lifetime = 1ms * lifetime; + if (hop->lifetime >= path::DEFAULT_LIFETIME) { - log::info("path build attempt with too long of a lifetime."); + log::warning(link_cat, "Path build attempt with too long of a lifetime."); m.respond(serialize_response({{"STATUS", PathBuildMessage::BAD_LIFETIME}}), true); return; } - hop->started = _router.now(); - _router.persist_connection_until(hop->info.downstream, hop->ExpireTime() + 10s); - if (hop->info.upstream == _router.pubkey()) + hop->started = _router.now(); + _router.persist_connection_until(hop_info.downstream, hop->ExpireTime() + 10s); + + if (hop_info.upstream == _router.pubkey()) { // we are terminal hop and everything is okay - _router.path_context.PutTransitHop(hop); + _router.path_context().PutTransitHop(hop); m.respond(serialize_response({{"STATUS", PathBuildMessage::OK}}), false); return; } - else - { - // rotate our frame to the end of the list and forward upstream - frame_list.splice(frame_list.end(), frame_list, frame_list.begin()); + // rotate our frame to the end of the list and forward upstream - send_control_message( - hop->info.upstream, - "path_build", - bt_serialize(frame_list), - [hop, this, prev_message = std::move(m)](oxen::quic::message response) { - if (response) - { - log::info( - link_cat, - "Upstream returned successful path build response; giving hop info to Router, " - "then relaying response"); - _router.path_context.PutTransitHop(hop); - m.respond(response.body_str(), false); - return; - } - else if (response.timed_out) - log::info(link_cat, "Upstream timed out on path build; relaying timeout"); - else - log::info(link_cat, "Upstream returned path build failure; relaying response"); + auto payload_list = oxenc::bt_deserialize(payload); + payload_list.splice(payload_list.end(), payload_list, payload_list.begin()); - m.respond(response.body_str(), true); - }); - } + send_control_message( + hop->info.upstream, + "path_build", + bt_serialize(payload_list), + [hop, this, prev_message = std::move(m)](oxen::quic::message m) { + if (m) + { + log::info( + link_cat, + "Upstream returned successful path build response; giving hop info to Router, " + "then relaying response"); + _router.path_context().PutTransitHop(hop); + } + if (m.timed_out) + log::info(link_cat, "Upstream timed out on path build; relaying timeout"); + else + log::info(link_cat, "Upstream returned path build failure; relaying response"); + + m.respond(m.body_str(), not m); + }); } catch (const std::exception& e) { @@ -1410,15 +1427,12 @@ namespace llarp _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); + m.respond(ObtainExit::sign_and_serialize_response(_router.identity(), tx_id), not success); } catch (const std::exception& e) { @@ -1485,16 +1499,13 @@ namespace llarp auto transit_hop = std::static_pointer_cast( _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(UpdateExit::sign_and_serialize_response(_router.identity(), tx_id)) : m.respond(serialize_response({{"STATUS", UpdateExit::UPDATE_FAILED}}), true); } // If we fail to verify the message, no-op @@ -1573,14 +1584,13 @@ namespace llarp _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 (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(CloseExit::sign_and_serialize_response(_router.identity(), tx_id)); } } diff --git a/llarp/messages/exit.hpp b/llarp/messages/exit.hpp index e377c2a98..da6226ace 100644 --- a/llarp/messages/exit.hpp +++ b/llarp/messages/exit.hpp @@ -16,8 +16,7 @@ namespace llarp // 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) + sign_and_serialize(SecretKey sk, uint64_t flag, std::string pubkey, std::string tx_id) { oxenc::bt_list_producer btlp; std::string sig(64, '\0'); @@ -27,7 +26,6 @@ namespace llarp btdp.append("E", flag); btdp.append("I", pubkey); - btdp.append("S", seq_no); btdp.append("T", tx_id); if (not CryptoManager::instance()->sign( @@ -41,7 +39,7 @@ namespace llarp } inline std::string - sign_and_serialize_response(SecretKey sk, uint64_t seq_no, std::string_view tx_id) + sign_and_serialize_response(SecretKey sk, std::string_view tx_id) { oxenc::bt_list_producer btlp; std::string sig(64, '\0'); @@ -51,7 +49,6 @@ namespace llarp { oxenc::bt_dict_producer btdp; - btdp.append("S", seq_no); btdp.append("T", tx_id); btdp.append("Y", nonce); @@ -73,7 +70,7 @@ namespace llarp 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) + sign_and_serialize(SecretKey sk, std::string path_id, std::string tx_id) { oxenc::bt_list_producer btlp; std::string sig(64, '\0'); @@ -82,7 +79,6 @@ namespace llarp 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( @@ -96,7 +92,7 @@ namespace llarp } inline std::string - sign_and_serialize_response(SecretKey sk, uint64_t seq_no, std::string_view tx_id) + sign_and_serialize_response(SecretKey sk, std::string_view tx_id) { oxenc::bt_list_producer btlp; std::string sig(64, '\0'); @@ -106,7 +102,6 @@ namespace llarp { oxenc::bt_dict_producer btdp; - btdp.append("S", seq_no); btdp.append("T", tx_id); btdp.append("Y", nonce); @@ -127,7 +122,7 @@ namespace llarp inline auto UPDATE_FAILED = "CLOSE EXIT FAILED"sv; inline std::string - sign_and_serialize(SecretKey sk, std::string seq_no, std::string tx_id) + sign_and_serialize(SecretKey sk, std::string tx_id) { oxenc::bt_list_producer btlp; std::string sig(64, '\0'); @@ -137,7 +132,6 @@ namespace llarp { auto btdp = btlp.append_dict(); - btdp.append("S", seq_no); btdp.append("T", tx_id); btdp.append("Y", nonce); @@ -152,7 +146,7 @@ namespace llarp } inline std::string - sign_and_serialize_response(SecretKey sk, uint64_t seq_no, std::string_view tx_id) + sign_and_serialize_response(SecretKey sk, std::string_view tx_id) { oxenc::bt_list_producer btlp; std::string sig(64, '\0'); @@ -162,7 +156,6 @@ namespace llarp { oxenc::bt_dict_producer btdp; - btdp.append("S", seq_no); btdp.append("T", tx_id); btdp.append("Y", nonce); diff --git a/llarp/messages/path.hpp b/llarp/messages/path.hpp index 0fb176f81..f2e60c424 100644 --- a/llarp/messages/path.hpp +++ b/llarp/messages/path.hpp @@ -27,7 +27,7 @@ namespace llarp if (!crypto->dh_client(hop.shared, hop.rc.pubkey, hop.commkey, hop.nonce)) { auto err = fmt::format("Failed to generate shared key for path build!"); - log::error(path_cat, err); + log::warning(path_cat, err); throw std::runtime_error{std::move(err)}; } // generate nonceXOR value self->hop->pathKey @@ -46,12 +46,12 @@ namespace llarp { oxenc::bt_dict_producer btdp; - btdp.append("lifetime", path::DEFAULT_LIFETIME.count()); - btdp.append("txid", hop.txID.ToView()); - btdp.append("rxid", hop.rxID.ToView()); - btdp.append("nonce", hop.nonce.ToView()); - btdp.append("next", hop.upstream.ToView()); - btdp.append("commkey", hop.commkey.toPublic().ToView()); + btdp.append("COMMKEY", hop.commkey.toPublic().ToView()); + btdp.append("LIFETIME", path::DEFAULT_LIFETIME.count()); + btdp.append("NONCE", hop.nonce.ToView()); + btdp.append("RX", hop.rxID.ToView()); + btdp.append("TX", hop.txID.ToView()); + btdp.append("UPSTREAM", hop.upstream.ToView()); hop_info = std::move(btdp).str(); } @@ -66,7 +66,7 @@ namespace llarp // derive (outer) shared key if (!crypto->dh_client(shared, hop.rc.pubkey, framekey, outer_nonce)) { - log::error(path_cat, "DH client failed during hop info encryption!"); + log::warning(path_cat, "DH client failed during hop info encryption!"); throw std::runtime_error{"DH failed during hop info encryption"}; } @@ -77,8 +77,8 @@ namespace llarp shared, outer_nonce)) { - log::error(path_cat, "Hop info encryption failed!"); - throw std::runtime_error{"Hop info encrypttion failed"}; + log::warning(path_cat, "Hop info encryption failed!"); + throw std::runtime_error{"Hop info encryption failed"}; } std::string hashed_data; @@ -86,9 +86,9 @@ namespace llarp { oxenc::bt_dict_producer btdp; - btdp.append("encrypted", hop_info); - btdp.append("pubkey", framekey.toPublic().ToView()); - btdp.append("nonce", outer_nonce.ToView()); + btdp.append("ENCRYPTED", hop_info); + btdp.append("NONCE", outer_nonce.ToView()); + btdp.append("PUBKEY", framekey.toPublic().ToView()); hashed_data = std::move(btdp).str(); } @@ -102,14 +102,14 @@ namespace llarp hashed_data.size(), shared)) { - log::error(path_cat, "Failed to generate HMAC for hop info"); + log::warning(path_cat, "Failed to generate HMAC for hop info"); throw std::runtime_error{"Failed to generate HMAC for hop info"}; } oxenc::bt_dict_producer btdp; - btdp.append("hash", hash); - btdp.append("frame", hashed_data); + btdp.append("HASH", hash); + btdp.append("FRAME", hashed_data); return std::move(btdp).str(); } diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index a48505bba..9554b7fc8 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -478,6 +478,7 @@ namespace llarp path->EnterState(path::ePathFailed, router->now()); } + // TODO: we don't use this concept anymore? router->persist_connection_until(path->upstream(), path->ExpireTime()); }