mirror of https://github.com/oxen-io/lokinet
Merge pull request #2204 from dr7ana/quic-wip
Draft: Wire Protocol Overhaul, Message Handling Refactorpull/2214/head
commit
690ec5fbca
@ -1 +1 @@
|
||||
Subproject commit 0f2504f7a2bfe4803e62cf7a9161806b0718ee5b
|
||||
Subproject commit 33982d24a380268933ebea33976ad806e5c4e4bb
|
@ -1 +1 @@
|
||||
Subproject commit e1b66ced4803e1b0cb05ed554cb5fc82b14c13c0
|
||||
Subproject commit 68b3420bad5f0384f06d378b89ccdc06aba07465
|
@ -0,0 +1 @@
|
||||
Subproject commit bc08bf87258d881aaa83b50c54dea67ea33d0e8e
|
@ -1,6 +1,569 @@
|
||||
#include "crypto.hpp"
|
||||
|
||||
#include <sodium/core.h>
|
||||
#include <sodium/crypto_generichash.h>
|
||||
#include <sodium/crypto_sign.h>
|
||||
#include <sodium/crypto_scalarmult.h>
|
||||
#include <sodium/crypto_scalarmult_ed25519.h>
|
||||
#include <sodium/crypto_stream_xchacha20.h>
|
||||
#include <sodium/crypto_core_ed25519.h>
|
||||
#include <sodium/crypto_aead_xchacha20poly1305.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <sodium/utils.h>
|
||||
#include <oxenc/endian.h>
|
||||
#include <llarp/util/mem.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#ifdef HAVE_CRYPT
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#include <llarp/util/str.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
Crypto* CryptoManager::m_crypto = nullptr;
|
||||
}
|
||||
static bool
|
||||
dh(llarp::SharedSecret& out,
|
||||
const PubKey& client_pk,
|
||||
const PubKey& server_pk,
|
||||
const uint8_t* themPub,
|
||||
const SecretKey& usSec)
|
||||
{
|
||||
llarp::SharedSecret shared;
|
||||
crypto_generichash_state h;
|
||||
|
||||
if (crypto_scalarmult_curve25519(shared.data(), usSec.data(), themPub))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
crypto_generichash_blake2b_init(&h, nullptr, 0U, shared.size());
|
||||
crypto_generichash_blake2b_update(&h, client_pk.data(), 32);
|
||||
crypto_generichash_blake2b_update(&h, server_pk.data(), 32);
|
||||
crypto_generichash_blake2b_update(&h, shared.data(), 32);
|
||||
crypto_generichash_blake2b_final(&h, out.data(), shared.size());
|
||||
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)
|
||||
{
|
||||
llarp::SharedSecret dh_result;
|
||||
|
||||
if (dh(dh_result, sk.toPublic(), pk, pk.data(), sk))
|
||||
{
|
||||
return crypto_generichash_blake2b(shared.data(), 32, n.data(), 32, dh_result.data(), 32)
|
||||
!= -1;
|
||||
}
|
||||
|
||||
llarp::LogWarn("crypto::dh_client - dh failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
dh_server_priv(
|
||||
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;
|
||||
}
|
||||
|
||||
Crypto::Crypto()
|
||||
{
|
||||
if (sodium_init() == -1)
|
||||
{
|
||||
throw std::runtime_error("sodium_init() returned -1");
|
||||
}
|
||||
char* avx2 = std::getenv("AVX2_FORCE_DISABLE");
|
||||
if (avx2 && std::string(avx2) == "1")
|
||||
{
|
||||
ntru_init(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ntru_init(0);
|
||||
}
|
||||
int seed = 0;
|
||||
randombytes(reinterpret_cast<unsigned char*>(&seed), sizeof(seed));
|
||||
srand(seed);
|
||||
}
|
||||
|
||||
std::optional<AlignedBuffer<32>>
|
||||
Crypto::maybe_decrypt_name(std::string_view ciphertext, SymmNonce nounce, std::string_view name)
|
||||
{
|
||||
const auto payloadsize = ciphertext.size() - crypto_aead_xchacha20poly1305_ietf_ABYTES;
|
||||
if (payloadsize != 32)
|
||||
return {};
|
||||
|
||||
SharedSecret derivedKey{};
|
||||
ShortHash namehash{};
|
||||
ustring name_buf{reinterpret_cast<const uint8_t*>(name.data()), name.size()};
|
||||
|
||||
if (not shorthash(namehash, name_buf.data(), name_buf.size()))
|
||||
return {};
|
||||
if (not hmac(derivedKey.data(), name_buf.data(), derivedKey.size(), namehash))
|
||||
return {};
|
||||
AlignedBuffer<32> result{};
|
||||
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
result.data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
reinterpret_cast<const byte_t*>(ciphertext.data()),
|
||||
ciphertext.size(),
|
||||
nullptr,
|
||||
0,
|
||||
nounce.data(),
|
||||
derivedKey.data())
|
||||
== -1)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::xchacha20(uint8_t* buf, size_t size, const SharedSecret& k, const TunnelNonce& n)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return dh_client_priv(shared, pk, sk, n);
|
||||
}
|
||||
/// path dh relay side
|
||||
bool
|
||||
Crypto::dh_server(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
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(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
return dh_client_priv(shared, pk, sk, n);
|
||||
}
|
||||
/// transport dh server side
|
||||
bool
|
||||
Crypto::transport_dh_server(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
return dh_server_priv(shared, pk, sk, n);
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::shorthash(ShortHash& result, uint8_t* buf, size_t size)
|
||||
{
|
||||
return crypto_generichash_blake2b(result.data(), ShortHash::SIZE, buf, size, nullptr, 0) != -1;
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::hmac(uint8_t* result, uint8_t* buf, size_t size, const SharedSecret& secret)
|
||||
{
|
||||
return crypto_generichash_blake2b(result, HMACSIZE, buf, size, secret.data(), HMACSECSIZE)
|
||||
!= -1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash(uint8_t* result, const llarp_buffer_t& buff)
|
||||
{
|
||||
return crypto_generichash_blake2b(result, HASHSIZE, buff.base, buff.sz, nullptr, 0) != -1;
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::sign(Signature& sig, const SecretKey& secret, uint8_t* buf, size_t size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
PubKey pubkey;
|
||||
|
||||
privkey.toPublic(pubkey);
|
||||
|
||||
crypto_hash_sha512_state hs;
|
||||
unsigned char nonce[64];
|
||||
unsigned char hram[64];
|
||||
unsigned char mulres[32];
|
||||
|
||||
// r = H(s || M) where here s is pseudorandom bytes typically generated as
|
||||
// part of hashing the seed (i.e. [a,s] = H(k)), but for derived
|
||||
// PrivateKeys will come from a hash of the root key's s concatenated with
|
||||
// the derivation hash.
|
||||
crypto_hash_sha512_init(&hs);
|
||||
crypto_hash_sha512_update(&hs, privkey.signingHash(), 32);
|
||||
crypto_hash_sha512_update(&hs, buf, size);
|
||||
crypto_hash_sha512_final(&hs, nonce);
|
||||
crypto_core_ed25519_scalar_reduce(nonce, nonce);
|
||||
|
||||
// copy pubkey into sig to make (for now) sig = (R || A)
|
||||
memmove(sig.data() + 32, pubkey.data(), 32);
|
||||
|
||||
// R = r * B
|
||||
crypto_scalarmult_ed25519_base_noclamp(sig.data(), nonce);
|
||||
|
||||
// hram = H(R || A || M)
|
||||
crypto_hash_sha512_init(&hs);
|
||||
crypto_hash_sha512_update(&hs, sig.data(), 64);
|
||||
crypto_hash_sha512_update(&hs, buf, size);
|
||||
crypto_hash_sha512_final(&hs, hram);
|
||||
|
||||
// S = r + H(R || A || M) * s, so sig = (R || S)
|
||||
crypto_core_ed25519_scalar_reduce(hram, hram);
|
||||
crypto_core_ed25519_scalar_mul(mulres, hram, privkey.data());
|
||||
crypto_core_ed25519_scalar_add(sig.data() + 32, mulres, nonce);
|
||||
|
||||
sodium_memzero(nonce, sizeof nonce);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::verify(const PubKey& pub, uint8_t* buf, size_t size, const Signature& sig)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return crypto_sign_verify_detached(sig, buf, size, pub) != -1;
|
||||
}
|
||||
|
||||
/// clamp a 32 byte ec point
|
||||
static void
|
||||
clamp_ed25519(byte_t* out)
|
||||
{
|
||||
out[0] &= 248;
|
||||
out[31] &= 127;
|
||||
out[31] |= 64;
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
static K
|
||||
clamp(const K& p)
|
||||
{
|
||||
K out = p;
|
||||
clamp_ed25519(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
static bool
|
||||
is_clamped(const K& key)
|
||||
{
|
||||
K other(key);
|
||||
clamp_ed25519(other.data());
|
||||
return other == key;
|
||||
}
|
||||
|
||||
constexpr static char derived_key_hash_str[161] =
|
||||
"just imagine what would happen if we all decided to understand. you "
|
||||
"can't in the and by be or then before so just face it this text hurts "
|
||||
"to read? lokinet yolo!";
|
||||
|
||||
template <typename K>
|
||||
static bool
|
||||
make_scalar(AlignedBuffer<32>& out, const K& k, uint64_t i)
|
||||
{
|
||||
// b = BLIND-STRING || k || i
|
||||
std::array<byte_t, 160 + K::SIZE + sizeof(uint64_t)> buf;
|
||||
std::copy(derived_key_hash_str, derived_key_hash_str + 160, buf.begin());
|
||||
std::copy(k.begin(), k.end(), buf.begin() + 160);
|
||||
oxenc::write_host_as_little(i, buf.data() + 160 + K::SIZE);
|
||||
// n = H(b)
|
||||
// h = make_point(n)
|
||||
ShortHash n;
|
||||
return -1
|
||||
!= crypto_generichash_blake2b(n.data(), ShortHash::SIZE, buf.data(), buf.size(), nullptr, 0)
|
||||
&& -1 != crypto_core_ed25519_from_uniform(out.data(), n.data());
|
||||
}
|
||||
|
||||
static AlignedBuffer<32> zero;
|
||||
|
||||
bool
|
||||
Crypto::derive_subkey(
|
||||
PubKey& out_pubkey, const PubKey& root_pubkey, uint64_t key_n, const AlignedBuffer<32>* hash)
|
||||
{
|
||||
// scalar h = H( BLIND-STRING || root_pubkey || key_n )
|
||||
AlignedBuffer<32> h;
|
||||
if (hash)
|
||||
h = *hash;
|
||||
else if (not make_scalar(h, root_pubkey, key_n))
|
||||
{
|
||||
LogError("cannot make scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0 == crypto_scalarmult_ed25519(out_pubkey.data(), h.data(), root_pubkey.data());
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::derive_subkey_private(
|
||||
PrivateKey& out_key, const SecretKey& root_key, uint64_t key_n, const AlignedBuffer<32>* hash)
|
||||
{
|
||||
// Derives a private subkey from a root key.
|
||||
//
|
||||
// The basic idea is:
|
||||
//
|
||||
// h = H( BLIND-STRING || A || key_n )
|
||||
// a - private key
|
||||
// A = aB - public key
|
||||
// s - signing hash
|
||||
// a' = ah - derived private key
|
||||
// A' = a'B = (ah)B - derived public key
|
||||
// s' = H(h || s) - derived signing hash
|
||||
//
|
||||
// libsodium throws some wrenches in the mechanics which are a nuisance,
|
||||
// the biggest of which is that sodium's secret key is *not* `a`; rather
|
||||
// it is the seed. If you want to get the private key (i.e. "a"), you
|
||||
// need to SHA-512 hash it and then clamp that.
|
||||
//
|
||||
// This also makes signature verification harder: we can't just use
|
||||
// sodium's sign function because it wants to be given the seed rather
|
||||
// than the private key, and moreover we can't actually *get* the seed to
|
||||
// make libsodium happy because we only have `ah` above; thus we
|
||||
// reimplemented most of sodium's detached signing function but without
|
||||
// the hash step.
|
||||
//
|
||||
// Lastly, for the signing hash s', we need some value that is both
|
||||
// different from the root s but also unknowable from the public key
|
||||
// (since otherwise `r` in the signing function would be known), so we
|
||||
// generate it from a hash of `h` and the root key's (psuedorandom)
|
||||
// signing hash, `s`.
|
||||
//
|
||||
const auto root_pubkey = root_key.toPublic();
|
||||
|
||||
AlignedBuffer<32> h;
|
||||
if (hash)
|
||||
h = *hash;
|
||||
else if (not make_scalar(h, root_pubkey, key_n))
|
||||
{
|
||||
LogError("cannot make scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
h[0] &= 248;
|
||||
h[31] &= 63;
|
||||
h[31] |= 64;
|
||||
|
||||
PrivateKey a;
|
||||
if (!root_key.toPrivate(a))
|
||||
return false;
|
||||
|
||||
// a' = ha
|
||||
crypto_core_ed25519_scalar_mul(out_key.data(), h.data(), a.data());
|
||||
|
||||
// s' = H(h || s)
|
||||
std::array<byte_t, 64> buf;
|
||||
std::copy(h.begin(), h.end(), buf.begin());
|
||||
std::copy(a.signingHash(), a.signingHash() + 32, buf.begin() + 32);
|
||||
return -1
|
||||
!= crypto_generichash_blake2b(
|
||||
out_key.signingHash(), 32, buf.data(), buf.size(), nullptr, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::seed_to_secretkey(llarp::SecretKey& secret, const llarp::IdentitySecret& seed)
|
||||
{
|
||||
return crypto_sign_ed25519_seed_keypair(secret.data() + 32, secret.data(), seed.data()) != -1;
|
||||
}
|
||||
void
|
||||
Crypto::randomize(const llarp_buffer_t& buff)
|
||||
{
|
||||
randombytes((unsigned char*)buff.base, buff.sz);
|
||||
}
|
||||
|
||||
void
|
||||
Crypto::randbytes(byte_t* ptr, size_t sz)
|
||||
{
|
||||
randombytes((unsigned char*)ptr, sz);
|
||||
}
|
||||
|
||||
void
|
||||
Crypto::identity_keygen(llarp::SecretKey& keys)
|
||||
{
|
||||
PubKey pk;
|
||||
int result = crypto_sign_keypair(pk.data(), keys.data());
|
||||
assert(result != -1);
|
||||
const PubKey sk_pk = keys.toPublic();
|
||||
assert(pk == sk_pk);
|
||||
(void)result;
|
||||
(void)sk_pk;
|
||||
|
||||
// encryption_keygen(keys);
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::check_identity_privkey(const llarp::SecretKey& keys)
|
||||
{
|
||||
AlignedBuffer<crypto_sign_SEEDBYTES> seed;
|
||||
llarp::PubKey pk;
|
||||
llarp::SecretKey sk;
|
||||
if (crypto_sign_ed25519_sk_to_seed(seed.data(), keys.data()) == -1)
|
||||
return false;
|
||||
if (crypto_sign_seed_keypair(pk.data(), sk.data(), seed.data()) == -1)
|
||||
return false;
|
||||
return keys.toPublic() == pk && sk == keys;
|
||||
}
|
||||
|
||||
void
|
||||
Crypto::encryption_keygen(llarp::SecretKey& keys)
|
||||
{
|
||||
auto d = keys.data();
|
||||
randbytes(d, 32);
|
||||
crypto_scalarmult_curve25519_base(d + 32, d);
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::pqe_encrypt(PQCipherBlock& ciphertext, SharedSecret& sharedkey, const PQPubKey& pubkey)
|
||||
{
|
||||
return crypto_kem_enc(ciphertext.data(), sharedkey.data(), pubkey.data()) != -1;
|
||||
}
|
||||
bool
|
||||
Crypto::pqe_decrypt(
|
||||
const PQCipherBlock& ciphertext, SharedSecret& sharedkey, const byte_t* secretkey)
|
||||
{
|
||||
return crypto_kem_dec(sharedkey.data(), ciphertext.data(), secretkey) != -1;
|
||||
}
|
||||
|
||||
void
|
||||
Crypto::pqe_keygen(PQKeyPair& keypair)
|
||||
{
|
||||
auto d = keypair.data();
|
||||
crypto_kem_keypair(d + PQ_SECRETKEYSIZE, d);
|
||||
}
|
||||
|
||||
bool
|
||||
Crypto::check_passwd_hash(std::string pwhash, std::string challenge)
|
||||
{
|
||||
(void)pwhash;
|
||||
(void)challenge;
|
||||
bool ret = false;
|
||||
#ifdef HAVE_CRYPT
|
||||
auto pos = pwhash.find_last_of('$');
|
||||
auto settings = pwhash.substr(0, pos);
|
||||
crypt_data data{};
|
||||
if (char* ptr = crypt_r(challenge.c_str(), settings.c_str(), &data))
|
||||
{
|
||||
ret = ptr == pwhash;
|
||||
}
|
||||
sodium_memzero(&data, sizeof(data));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
seckey_topublic(const SecretKey& sec)
|
||||
{
|
||||
return sec.data() + 32;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_public(const PQKeyPair& k)
|
||||
{
|
||||
return k.data() + PQ_SECRETKEYSIZE;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_secret(const PQKeyPair& k)
|
||||
{
|
||||
return k.data();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
randint()
|
||||
{
|
||||
uint64_t i;
|
||||
randombytes((byte_t*)&i, sizeof(i));
|
||||
return i;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
@ -1,518 +0,0 @@
|
||||
#include "crypto_libsodium.hpp"
|
||||
#include <sodium/crypto_generichash.h>
|
||||
#include <sodium/crypto_sign.h>
|
||||
#include <sodium/crypto_scalarmult.h>
|
||||
#include <sodium/crypto_scalarmult_ed25519.h>
|
||||
#include <sodium/crypto_stream_xchacha20.h>
|
||||
#include <sodium/crypto_core_ed25519.h>
|
||||
#include <sodium/crypto_aead_xchacha20poly1305.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <sodium/utils.h>
|
||||
#include <oxenc/endian.h>
|
||||
#include <llarp/util/mem.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#ifdef HAVE_CRYPT
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#include <llarp/util/str.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern int
|
||||
sodium_init(void);
|
||||
}
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace sodium
|
||||
{
|
||||
static bool
|
||||
dh(llarp::SharedSecret& out,
|
||||
const PubKey& client_pk,
|
||||
const PubKey& server_pk,
|
||||
const uint8_t* themPub,
|
||||
const SecretKey& usSec)
|
||||
{
|
||||
llarp::SharedSecret shared;
|
||||
crypto_generichash_state h;
|
||||
|
||||
if (crypto_scalarmult_curve25519(shared.data(), usSec.data(), themPub))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
crypto_generichash_blake2b_init(&h, nullptr, 0U, shared.size());
|
||||
crypto_generichash_blake2b_update(&h, client_pk.data(), 32);
|
||||
crypto_generichash_blake2b_update(&h, server_pk.data(), 32);
|
||||
crypto_generichash_blake2b_update(&h, shared.data(), 32);
|
||||
crypto_generichash_blake2b_final(&h, out.data(), shared.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
dh_client_priv(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
llarp::SharedSecret dh_result;
|
||||
|
||||
if (dh(dh_result, sk.toPublic(), pk, pk.data(), sk))
|
||||
{
|
||||
return crypto_generichash_blake2b(shared.data(), 32, n.data(), 32, dh_result.data(), 32)
|
||||
!= -1;
|
||||
}
|
||||
llarp::LogWarn("crypto::dh_client - dh failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
dh_server_priv(
|
||||
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;
|
||||
}
|
||||
|
||||
CryptoLibSodium::CryptoLibSodium()
|
||||
{
|
||||
if (sodium_init() == -1)
|
||||
{
|
||||
throw std::runtime_error("sodium_init() returned -1");
|
||||
}
|
||||
char* avx2 = std::getenv("AVX2_FORCE_DISABLE");
|
||||
if (avx2 && std::string(avx2) == "1")
|
||||
{
|
||||
ntru_init(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ntru_init(0);
|
||||
}
|
||||
int seed = 0;
|
||||
randombytes(reinterpret_cast<unsigned char*>(&seed), sizeof(seed));
|
||||
srand(seed);
|
||||
}
|
||||
|
||||
std::optional<AlignedBuffer<32>>
|
||||
CryptoLibSodium::maybe_decrypt_name(
|
||||
std::string_view ciphertext, SymmNonce nounce, std::string_view name)
|
||||
{
|
||||
const auto payloadsize = ciphertext.size() - crypto_aead_xchacha20poly1305_ietf_ABYTES;
|
||||
if (payloadsize != 32)
|
||||
return {};
|
||||
|
||||
SharedSecret derivedKey{};
|
||||
ShortHash namehash{};
|
||||
const llarp_buffer_t namebuf(reinterpret_cast<const char*>(name.data()), name.size());
|
||||
if (not shorthash(namehash, namebuf))
|
||||
return {};
|
||||
if (not hmac(derivedKey.data(), namebuf, namehash))
|
||||
return {};
|
||||
AlignedBuffer<32> result{};
|
||||
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
result.data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
reinterpret_cast<const byte_t*>(ciphertext.data()),
|
||||
ciphertext.size(),
|
||||
nullptr,
|
||||
0,
|
||||
nounce.data(),
|
||||
derivedKey.data())
|
||||
== -1)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::xchacha20(
|
||||
const llarp_buffer_t& buff, const SharedSecret& k, const TunnelNonce& n)
|
||||
{
|
||||
return crypto_stream_xchacha20_xor(buff.base, buff.base, buff.sz, n.data(), k.data()) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::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
|
||||
CryptoLibSodium::dh_client(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
return dh_client_priv(shared, pk, sk, n);
|
||||
}
|
||||
/// path dh relay side
|
||||
bool
|
||||
CryptoLibSodium::dh_server(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
return dh_server_priv(shared, pk, sk, n);
|
||||
}
|
||||
/// transport dh client side
|
||||
bool
|
||||
CryptoLibSodium::transport_dh_client(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
return dh_client_priv(shared, pk, sk, n);
|
||||
}
|
||||
/// transport dh server side
|
||||
bool
|
||||
CryptoLibSodium::transport_dh_server(
|
||||
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
|
||||
{
|
||||
return dh_server_priv(shared, pk, sk, n);
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::shorthash(ShortHash& result, const llarp_buffer_t& buff)
|
||||
{
|
||||
return crypto_generichash_blake2b(
|
||||
result.data(), ShortHash::SIZE, buff.base, buff.sz, nullptr, 0)
|
||||
!= -1;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::hmac(byte_t* result, const llarp_buffer_t& buff, const SharedSecret& secret)
|
||||
{
|
||||
return crypto_generichash_blake2b(
|
||||
result, HMACSIZE, buff.base, buff.sz, secret.data(), HMACSECSIZE)
|
||||
!= -1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash(uint8_t* result, const llarp_buffer_t& buff)
|
||||
{
|
||||
return crypto_generichash_blake2b(result, HASHSIZE, buff.base, buff.sz, nullptr, 0) != -1;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::sign(Signature& sig, const SecretKey& secret, const llarp_buffer_t& buf)
|
||||
{
|
||||
return crypto_sign_detached(sig.data(), nullptr, buf.base, buf.sz, secret.data()) != -1;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::sign(Signature& sig, const PrivateKey& privkey, const llarp_buffer_t& buf)
|
||||
{
|
||||
PubKey pubkey;
|
||||
|
||||
privkey.toPublic(pubkey);
|
||||
|
||||
crypto_hash_sha512_state hs;
|
||||
unsigned char nonce[64];
|
||||
unsigned char hram[64];
|
||||
unsigned char mulres[32];
|
||||
|
||||
// r = H(s || M) where here s is pseudorandom bytes typically generated as
|
||||
// part of hashing the seed (i.e. [a,s] = H(k)), but for derived
|
||||
// PrivateKeys will come from a hash of the root key's s concatenated with
|
||||
// the derivation hash.
|
||||
crypto_hash_sha512_init(&hs);
|
||||
crypto_hash_sha512_update(&hs, privkey.signingHash(), 32);
|
||||
crypto_hash_sha512_update(&hs, buf.base, buf.sz);
|
||||
crypto_hash_sha512_final(&hs, nonce);
|
||||
crypto_core_ed25519_scalar_reduce(nonce, nonce);
|
||||
|
||||
// copy pubkey into sig to make (for now) sig = (R || A)
|
||||
memmove(sig.data() + 32, pubkey.data(), 32);
|
||||
|
||||
// R = r * B
|
||||
crypto_scalarmult_ed25519_base_noclamp(sig.data(), nonce);
|
||||
|
||||
// hram = H(R || A || M)
|
||||
crypto_hash_sha512_init(&hs);
|
||||
crypto_hash_sha512_update(&hs, sig.data(), 64);
|
||||
crypto_hash_sha512_update(&hs, buf.base, buf.sz);
|
||||
crypto_hash_sha512_final(&hs, hram);
|
||||
|
||||
// S = r + H(R || A || M) * s, so sig = (R || S)
|
||||
crypto_core_ed25519_scalar_reduce(hram, hram);
|
||||
crypto_core_ed25519_scalar_mul(mulres, hram, privkey.data());
|
||||
crypto_core_ed25519_scalar_add(sig.data() + 32, mulres, nonce);
|
||||
|
||||
sodium_memzero(nonce, sizeof nonce);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::verify(const PubKey& pub, const llarp_buffer_t& buf, const Signature& sig)
|
||||
{
|
||||
return crypto_sign_verify_detached(sig.data(), buf.base, buf.sz, pub.data()) != -1;
|
||||
}
|
||||
|
||||
/// clamp a 32 byte ec point
|
||||
static void
|
||||
clamp_ed25519(byte_t* out)
|
||||
{
|
||||
out[0] &= 248;
|
||||
out[31] &= 127;
|
||||
out[31] |= 64;
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
static K
|
||||
clamp(const K& p)
|
||||
{
|
||||
K out = p;
|
||||
clamp_ed25519(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
static bool
|
||||
is_clamped(const K& key)
|
||||
{
|
||||
K other(key);
|
||||
clamp_ed25519(other.data());
|
||||
return other == key;
|
||||
}
|
||||
|
||||
constexpr static char derived_key_hash_str[161] =
|
||||
"just imagine what would happen if we all decided to understand. you "
|
||||
"can't in the and by be or then before so just face it this text hurts "
|
||||
"to read? lokinet yolo!";
|
||||
|
||||
template <typename K>
|
||||
static bool
|
||||
make_scalar(AlignedBuffer<32>& out, const K& k, uint64_t i)
|
||||
{
|
||||
// b = BLIND-STRING || k || i
|
||||
std::array<byte_t, 160 + K::SIZE + sizeof(uint64_t)> buf;
|
||||
std::copy(derived_key_hash_str, derived_key_hash_str + 160, buf.begin());
|
||||
std::copy(k.begin(), k.end(), buf.begin() + 160);
|
||||
oxenc::write_host_as_little(i, buf.data() + 160 + K::SIZE);
|
||||
// n = H(b)
|
||||
// h = make_point(n)
|
||||
ShortHash n;
|
||||
return -1
|
||||
!= crypto_generichash_blake2b(
|
||||
n.data(), ShortHash::SIZE, buf.data(), buf.size(), nullptr, 0)
|
||||
&& -1 != crypto_core_ed25519_from_uniform(out.data(), n.data());
|
||||
}
|
||||
|
||||
static AlignedBuffer<32> zero;
|
||||
|
||||
bool
|
||||
CryptoLibSodium::derive_subkey(
|
||||
PubKey& out_pubkey,
|
||||
const PubKey& root_pubkey,
|
||||
uint64_t key_n,
|
||||
const AlignedBuffer<32>* hash)
|
||||
{
|
||||
// scalar h = H( BLIND-STRING || root_pubkey || key_n )
|
||||
AlignedBuffer<32> h;
|
||||
if (hash)
|
||||
h = *hash;
|
||||
else if (not make_scalar(h, root_pubkey, key_n))
|
||||
{
|
||||
LogError("cannot make scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0 == crypto_scalarmult_ed25519(out_pubkey.data(), h.data(), root_pubkey.data());
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::derive_subkey_private(
|
||||
PrivateKey& out_key,
|
||||
const SecretKey& root_key,
|
||||
uint64_t key_n,
|
||||
const AlignedBuffer<32>* hash)
|
||||
{
|
||||
// Derives a private subkey from a root key.
|
||||
//
|
||||
// The basic idea is:
|
||||
//
|
||||
// h = H( BLIND-STRING || A || key_n )
|
||||
// a - private key
|
||||
// A = aB - public key
|
||||
// s - signing hash
|
||||
// a' = ah - derived private key
|
||||
// A' = a'B = (ah)B - derived public key
|
||||
// s' = H(h || s) - derived signing hash
|
||||
//
|
||||
// libsodium throws some wrenches in the mechanics which are a nuisance,
|
||||
// the biggest of which is that sodium's secret key is *not* `a`; rather
|
||||
// it is the seed. If you want to get the private key (i.e. "a"), you
|
||||
// need to SHA-512 hash it and then clamp that.
|
||||
//
|
||||
// This also makes signature verification harder: we can't just use
|
||||
// sodium's sign function because it wants to be given the seed rather
|
||||
// than the private key, and moreover we can't actually *get* the seed to
|
||||
// make libsodium happy because we only have `ah` above; thus we
|
||||
// reimplemented most of sodium's detached signing function but without
|
||||
// the hash step.
|
||||
//
|
||||
// Lastly, for the signing hash s', we need some value that is both
|
||||
// different from the root s but also unknowable from the public key
|
||||
// (since otherwise `r` in the signing function would be known), so we
|
||||
// generate it from a hash of `h` and the root key's (psuedorandom)
|
||||
// signing hash, `s`.
|
||||
//
|
||||
const auto root_pubkey = root_key.toPublic();
|
||||
|
||||
AlignedBuffer<32> h;
|
||||
if (hash)
|
||||
h = *hash;
|
||||
else if (not make_scalar(h, root_pubkey, key_n))
|
||||
{
|
||||
LogError("cannot make scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
h[0] &= 248;
|
||||
h[31] &= 63;
|
||||
h[31] |= 64;
|
||||
|
||||
PrivateKey a;
|
||||
if (!root_key.toPrivate(a))
|
||||
return false;
|
||||
|
||||
// a' = ha
|
||||
crypto_core_ed25519_scalar_mul(out_key.data(), h.data(), a.data());
|
||||
|
||||
// s' = H(h || s)
|
||||
std::array<byte_t, 64> buf;
|
||||
std::copy(h.begin(), h.end(), buf.begin());
|
||||
std::copy(a.signingHash(), a.signingHash() + 32, buf.begin() + 32);
|
||||
return -1
|
||||
!= crypto_generichash_blake2b(
|
||||
out_key.signingHash(), 32, buf.data(), buf.size(), nullptr, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::seed_to_secretkey(llarp::SecretKey& secret, const llarp::IdentitySecret& seed)
|
||||
{
|
||||
return crypto_sign_ed25519_seed_keypair(secret.data() + 32, secret.data(), seed.data()) != -1;
|
||||
}
|
||||
void
|
||||
CryptoLibSodium::randomize(const llarp_buffer_t& buff)
|
||||
{
|
||||
randombytes((unsigned char*)buff.base, buff.sz);
|
||||
}
|
||||
|
||||
void
|
||||
CryptoLibSodium::randbytes(byte_t* ptr, size_t sz)
|
||||
{
|
||||
randombytes((unsigned char*)ptr, sz);
|
||||
}
|
||||
|
||||
void
|
||||
CryptoLibSodium::identity_keygen(llarp::SecretKey& keys)
|
||||
{
|
||||
PubKey pk;
|
||||
int result = crypto_sign_keypair(pk.data(), keys.data());
|
||||
assert(result != -1);
|
||||
const PubKey sk_pk = keys.toPublic();
|
||||
assert(pk == sk_pk);
|
||||
(void)result;
|
||||
(void)sk_pk;
|
||||
|
||||
// encryption_keygen(keys);
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::check_identity_privkey(const llarp::SecretKey& keys)
|
||||
{
|
||||
AlignedBuffer<crypto_sign_SEEDBYTES> seed;
|
||||
llarp::PubKey pk;
|
||||
llarp::SecretKey sk;
|
||||
if (crypto_sign_ed25519_sk_to_seed(seed.data(), keys.data()) == -1)
|
||||
return false;
|
||||
if (crypto_sign_seed_keypair(pk.data(), sk.data(), seed.data()) == -1)
|
||||
return false;
|
||||
return keys.toPublic() == pk && sk == keys;
|
||||
}
|
||||
|
||||
void
|
||||
CryptoLibSodium::encryption_keygen(llarp::SecretKey& keys)
|
||||
{
|
||||
auto d = keys.data();
|
||||
randbytes(d, 32);
|
||||
crypto_scalarmult_curve25519_base(d + 32, d);
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::pqe_encrypt(
|
||||
PQCipherBlock& ciphertext, SharedSecret& sharedkey, const PQPubKey& pubkey)
|
||||
{
|
||||
return crypto_kem_enc(ciphertext.data(), sharedkey.data(), pubkey.data()) != -1;
|
||||
}
|
||||
bool
|
||||
CryptoLibSodium::pqe_decrypt(
|
||||
const PQCipherBlock& ciphertext, SharedSecret& sharedkey, const byte_t* secretkey)
|
||||
{
|
||||
return crypto_kem_dec(sharedkey.data(), ciphertext.data(), secretkey) != -1;
|
||||
}
|
||||
|
||||
void
|
||||
CryptoLibSodium::pqe_keygen(PQKeyPair& keypair)
|
||||
{
|
||||
auto d = keypair.data();
|
||||
crypto_kem_keypair(d + PQ_SECRETKEYSIZE, d);
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoLibSodium::check_passwd_hash(std::string pwhash, std::string challenge)
|
||||
{
|
||||
(void)pwhash;
|
||||
(void)challenge;
|
||||
bool ret = false;
|
||||
#ifdef HAVE_CRYPT
|
||||
auto pos = pwhash.find_last_of('$');
|
||||
auto settings = pwhash.substr(0, pos);
|
||||
crypt_data data{};
|
||||
if (char* ptr = crypt_r(challenge.c_str(), settings.c_str(), &data))
|
||||
{
|
||||
ret = ptr == pwhash;
|
||||
}
|
||||
sodium_memzero(&data, sizeof(data));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
} // namespace sodium
|
||||
|
||||
const byte_t*
|
||||
seckey_topublic(const SecretKey& sec)
|
||||
{
|
||||
return sec.data() + 32;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_public(const PQKeyPair& k)
|
||||
{
|
||||
return k.data() + PQ_SECRETKEYSIZE;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_secret(const PQKeyPair& k)
|
||||
{
|
||||
return k.data();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
randint()
|
||||
{
|
||||
uint64_t i;
|
||||
randombytes((byte_t*)&i, sizeof(i));
|
||||
return i;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
@ -1,113 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "crypto.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace sodium
|
||||
{
|
||||
struct CryptoLibSodium final : public Crypto
|
||||
{
|
||||
CryptoLibSodium();
|
||||
|
||||
~CryptoLibSodium() override = default;
|
||||
|
||||
/// decrypt cipherText given the key generated from name
|
||||
std::optional<AlignedBuffer<32>>
|
||||
maybe_decrypt_name(
|
||||
std::string_view ciphertext, SymmNonce nounce, std::string_view name) override;
|
||||
|
||||
/// xchacha symmetric cipher
|
||||
bool
|
||||
xchacha20(const llarp_buffer_t&, const SharedSecret&, const TunnelNonce&) override;
|
||||
|
||||
/// xchacha symmetric cipher (multibuffer)
|
||||
bool
|
||||
xchacha20_alt(
|
||||
const llarp_buffer_t&,
|
||||
const llarp_buffer_t&,
|
||||
const SharedSecret&,
|
||||
const byte_t*) override;
|
||||
|
||||
/// path dh creator's side
|
||||
bool
|
||||
dh_client(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&) override;
|
||||
/// path dh relay side
|
||||
bool
|
||||
dh_server(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&) override;
|
||||
/// transport dh client side
|
||||
bool
|
||||
transport_dh_client(
|
||||
SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&) override;
|
||||
/// transport dh server side
|
||||
bool
|
||||
transport_dh_server(
|
||||
SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&) override;
|
||||
/// blake2b 256 bit
|
||||
bool
|
||||
shorthash(ShortHash&, const llarp_buffer_t&) override;
|
||||
/// blake2s 256 bit hmac
|
||||
bool
|
||||
hmac(byte_t*, const llarp_buffer_t&, const SharedSecret&) override;
|
||||
/// ed25519 sign
|
||||
bool
|
||||
sign(Signature&, const SecretKey&, const llarp_buffer_t&) override;
|
||||
/// ed25519 sign (custom with derived keys)
|
||||
bool
|
||||
sign(Signature&, const PrivateKey&, const llarp_buffer_t&) override;
|
||||
/// ed25519 verify
|
||||
bool
|
||||
verify(const PubKey&, const llarp_buffer_t&, const Signature&) override;
|
||||
|
||||
/// derive sub keys for public keys. hash is really only intended for
|
||||
/// testing and overrides key_n if given.
|
||||
bool
|
||||
derive_subkey(
|
||||
PubKey& derived,
|
||||
const PubKey& root,
|
||||
uint64_t key_n,
|
||||
const AlignedBuffer<32>* hash = nullptr) override;
|
||||
|
||||
/// derive sub keys for private keys. hash is really only intended for
|
||||
/// testing and overrides key_n if given.
|
||||
bool
|
||||
derive_subkey_private(
|
||||
PrivateKey& derived,
|
||||
const SecretKey& root,
|
||||
uint64_t key_n,
|
||||
const AlignedBuffer<32>* hash = nullptr) override;
|
||||
|
||||
/// seed to secretkey
|
||||
bool
|
||||
seed_to_secretkey(llarp::SecretKey&, const llarp::IdentitySecret&) override;
|
||||
/// randomize buffer
|
||||
void
|
||||
randomize(const llarp_buffer_t&) override;
|
||||
/// randomizer memory
|
||||
void
|
||||
randbytes(byte_t*, size_t) override;
|
||||
/// generate signing keypair
|
||||
void
|
||||
identity_keygen(SecretKey&) override;
|
||||
/// generate encryption keypair
|
||||
void
|
||||
encryption_keygen(SecretKey&) override;
|
||||
/// generate post quantum encrytion key
|
||||
void
|
||||
pqe_keygen(PQKeyPair&) override;
|
||||
/// post quantum decrypt (buffer, sharedkey_dst, sec)
|
||||
bool
|
||||
pqe_decrypt(const PQCipherBlock&, SharedSecret&, const byte_t*) override;
|
||||
/// post quantum encrypt (buffer, sharedkey_dst, pub)
|
||||
bool
|
||||
pqe_encrypt(PQCipherBlock&, SharedSecret&, const PQPubKey&) override;
|
||||
|
||||
bool
|
||||
check_identity_privkey(const SecretKey&) override;
|
||||
|
||||
bool
|
||||
check_passwd_hash(std::string pwhash, std::string challenge) override;
|
||||
};
|
||||
} // namespace sodium
|
||||
|
||||
} // namespace llarp
|
File diff suppressed because it is too large
Load Diff
@ -1,207 +0,0 @@
|
||||
#ifndef LLARP_DHT_CONTEXT
|
||||
#define LLARP_DHT_CONTEXT
|
||||
|
||||
#include "bucket.hpp"
|
||||
#include "dht.h"
|
||||
#include "key.hpp"
|
||||
#include "message.hpp"
|
||||
#include <llarp/dht/messages/findintro.hpp>
|
||||
#include "node.hpp"
|
||||
#include "tx.hpp"
|
||||
#include "txholder.hpp"
|
||||
#include "txowner.hpp"
|
||||
#include <llarp/service/intro_set.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/status.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct AbstractRouter;
|
||||
|
||||
namespace dht
|
||||
{
|
||||
/// number of routers to publish to
|
||||
static constexpr size_t IntroSetRelayRedundancy = 2;
|
||||
|
||||
/// number of dht locations handled per relay
|
||||
static constexpr size_t IntroSetRequestsPerRelay = 2;
|
||||
|
||||
static constexpr size_t IntroSetStorageRedundancy =
|
||||
(IntroSetRelayRedundancy * IntroSetRequestsPerRelay);
|
||||
|
||||
struct AbstractContext
|
||||
{
|
||||
using PendingIntrosetLookups = TXHolder<TXOwner, service::EncryptedIntroSet>;
|
||||
using PendingRouterLookups = TXHolder<RouterID, RouterContact>;
|
||||
using PendingExploreLookups = TXHolder<RouterID, RouterID>;
|
||||
|
||||
virtual ~AbstractContext() = 0;
|
||||
|
||||
virtual bool
|
||||
LookupRouter(const RouterID& target, RouterLookupHandler result) = 0;
|
||||
|
||||
virtual void
|
||||
LookupRouterRecursive(
|
||||
const RouterID& target,
|
||||
const Key_t& whoasked,
|
||||
uint64_t whoaskedTX,
|
||||
const Key_t& askpeer,
|
||||
RouterLookupHandler result = nullptr) = 0;
|
||||
|
||||
/// Ask a Service Node to perform an Introset lookup for us
|
||||
virtual void
|
||||
LookupIntroSetRelayed(
|
||||
const Key_t& target,
|
||||
const Key_t& whoasked,
|
||||
uint64_t whoaskedTX,
|
||||
const Key_t& askpeer,
|
||||
uint64_t relayOrder,
|
||||
service::EncryptedIntroSetLookupHandler result =
|
||||
service::EncryptedIntroSetLookupHandler()) = 0;
|
||||
|
||||
/// Directly as a Service Node for an Introset
|
||||
virtual void
|
||||
LookupIntroSetDirect(
|
||||
const Key_t& target,
|
||||
const Key_t& whoasked,
|
||||
uint64_t whoaskedTX,
|
||||
const Key_t& askpeer,
|
||||
service::EncryptedIntroSetLookupHandler result =
|
||||
service::EncryptedIntroSetLookupHandler()) = 0;
|
||||
|
||||
virtual bool
|
||||
HasRouterLookup(const RouterID& target) const = 0;
|
||||
|
||||
/// issue dht lookup for router via askpeer and send reply to local path
|
||||
virtual void
|
||||
LookupRouterForPath(
|
||||
const RouterID& target, uint64_t txid, const PathID_t& path, const Key_t& askpeer) = 0;
|
||||
|
||||
virtual void
|
||||
LookupIntroSetForPath(
|
||||
const Key_t& addr,
|
||||
uint64_t txid,
|
||||
const PathID_t& path,
|
||||
const Key_t& askpeer,
|
||||
uint64_t relayOrder) = 0;
|
||||
|
||||
virtual void
|
||||
DHTSendTo(const RouterID& peer, IMessage* msg, bool keepalive = true) = 0;
|
||||
|
||||
/// get routers closest to target excluding requester
|
||||
virtual bool
|
||||
HandleExploritoryRouterLookup(
|
||||
const Key_t& requester,
|
||||
uint64_t txid,
|
||||
const RouterID& target,
|
||||
std::vector<std::unique_ptr<IMessage>>& reply) = 0;
|
||||
|
||||
/// handle rc lookup from requester for target
|
||||
virtual void
|
||||
LookupRouterRelayed(
|
||||
const Key_t& requester,
|
||||
uint64_t txid,
|
||||
const Key_t& target,
|
||||
bool recursive,
|
||||
std::vector<std::unique_ptr<IMessage>>& replies) = 0;
|
||||
|
||||
virtual bool
|
||||
RelayRequestForPath(const PathID_t& localPath, const IMessage& msg) = 0;
|
||||
|
||||
/// send introset to peer from source with S counter and excluding peers
|
||||
virtual void
|
||||
PropagateLocalIntroSet(
|
||||
const PathID_t& path,
|
||||
uint64_t sourceTX,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
const Key_t& peer,
|
||||
uint64_t relayOrder) = 0;
|
||||
|
||||
/// send introset to peer from source with S counter and excluding peers
|
||||
virtual void
|
||||
PropagateIntroSetTo(
|
||||
const Key_t& source,
|
||||
uint64_t sourceTX,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
const Key_t& peer,
|
||||
uint64_t relayOrder) = 0;
|
||||
|
||||
virtual void
|
||||
Init(const Key_t& us, AbstractRouter* router) = 0;
|
||||
|
||||
virtual std::optional<llarp::service::EncryptedIntroSet>
|
||||
GetIntroSetByLocation(const Key_t& location) const = 0;
|
||||
|
||||
virtual llarp_time_t
|
||||
Now() const = 0;
|
||||
|
||||
virtual void
|
||||
ExploreNetworkVia(const Key_t& peer) = 0;
|
||||
|
||||
virtual llarp::AbstractRouter*
|
||||
GetRouter() const = 0;
|
||||
|
||||
virtual bool
|
||||
GetRCFromNodeDB(const Key_t& k, llarp::RouterContact& rc) const = 0;
|
||||
|
||||
virtual const Key_t&
|
||||
OurKey() const = 0;
|
||||
|
||||
virtual PendingIntrosetLookups&
|
||||
pendingIntrosetLookups() = 0;
|
||||
|
||||
virtual const PendingIntrosetLookups&
|
||||
pendingIntrosetLookups() const = 0;
|
||||
|
||||
virtual PendingRouterLookups&
|
||||
pendingRouterLookups() = 0;
|
||||
|
||||
virtual const PendingRouterLookups&
|
||||
pendingRouterLookups() const = 0;
|
||||
|
||||
virtual PendingExploreLookups&
|
||||
pendingExploreLookups() = 0;
|
||||
|
||||
virtual const PendingExploreLookups&
|
||||
pendingExploreLookups() const = 0;
|
||||
|
||||
virtual Bucket<ISNode>*
|
||||
services() = 0;
|
||||
|
||||
virtual bool&
|
||||
AllowTransit() = 0;
|
||||
virtual const bool&
|
||||
AllowTransit() const = 0;
|
||||
|
||||
virtual Bucket<RCNode>*
|
||||
Nodes() const = 0;
|
||||
|
||||
virtual void
|
||||
PutRCNodeAsync(const RCNode& val) = 0;
|
||||
|
||||
virtual void
|
||||
DelRCNodeAsync(const Key_t& val) = 0;
|
||||
|
||||
virtual util::StatusObject
|
||||
ExtractStatus() const = 0;
|
||||
|
||||
virtual void
|
||||
StoreRC(const RouterContact rc) const = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<AbstractContext>
|
||||
makeContext();
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
struct llarp_dht_context
|
||||
{
|
||||
std::unique_ptr<llarp::dht::AbstractContext> impl;
|
||||
llarp::AbstractRouter* parent;
|
||||
llarp_dht_context(llarp::AbstractRouter* router);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,43 +1,39 @@
|
||||
#include "explorenetworkjob.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/findrouter.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
|
||||
#include <llarp/nodedb.hpp>
|
||||
|
||||
#include <llarp/tooling/dht_event.hpp>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dht
|
||||
{
|
||||
namespace dht
|
||||
void
|
||||
ExploreNetworkJob::Start(const TXOwner& peer)
|
||||
{
|
||||
void
|
||||
ExploreNetworkJob::Start(const TXOwner& peer)
|
||||
auto msg = new FindRouterMessage(peer.txid);
|
||||
auto router = parent->GetRouter();
|
||||
if (router)
|
||||
{
|
||||
auto msg = new FindRouterMessage(peer.txid);
|
||||
auto router = parent->GetRouter();
|
||||
if (router)
|
||||
{
|
||||
router->NotifyRouterEvent<tooling::FindRouterSentEvent>(router->pubkey(), *msg);
|
||||
}
|
||||
parent->DHTSendTo(peer.node.as_array(), msg);
|
||||
router->notify_router_event<tooling::FindRouterSentEvent>(router->pubkey(), *msg);
|
||||
}
|
||||
parent->DHTSendTo(peer.node.as_array(), msg);
|
||||
}
|
||||
|
||||
void
|
||||
ExploreNetworkJob::SendReply()
|
||||
{
|
||||
llarp::LogDebug("got ", valuesFound.size(), " routers from exploration");
|
||||
void
|
||||
ExploreNetworkJob::SendReply()
|
||||
{
|
||||
llarp::LogDebug("got ", valuesFound.size(), " routers from exploration");
|
||||
|
||||
auto router = parent->GetRouter();
|
||||
for (const auto& pk : valuesFound)
|
||||
{
|
||||
// lookup router
|
||||
if (router and router->nodedb()->Has(pk))
|
||||
continue;
|
||||
parent->LookupRouter(
|
||||
pk, [router, pk](const auto& res) { router->HandleDHTLookupForExplore(pk, res); });
|
||||
}
|
||||
auto router = parent->GetRouter();
|
||||
for (const auto& pk : valuesFound)
|
||||
{
|
||||
// lookup router
|
||||
if (router and router->node_db()->Has(pk))
|
||||
continue;
|
||||
parent->LookupRouter(
|
||||
pk, [router, pk](const auto& res) { router->HandleDHTLookupForExplore(pk, res); });
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
}
|
||||
} // namespace llarp::dht
|
||||
|
@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "dht.h"
|
||||
#include "key.hpp"
|
||||
#include <llarp/path/path_types.hpp>
|
||||
#include <llarp/util/bencode.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
constexpr size_t MAX_MSG_SIZE = 2048;
|
||||
|
||||
struct IMessage
|
||||
{
|
||||
virtual ~IMessage() = default;
|
||||
|
||||
/// construct
|
||||
IMessage(const Key_t& from) : From(from)
|
||||
{}
|
||||
|
||||
using Ptr_t = std::unique_ptr<IMessage>;
|
||||
|
||||
virtual bool
|
||||
HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const = 0;
|
||||
|
||||
virtual bool
|
||||
BEncode(llarp_buffer_t* buf) const = 0;
|
||||
|
||||
virtual bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) = 0;
|
||||
|
||||
Key_t From;
|
||||
PathID_t pathID;
|
||||
uint64_t version = llarp::constants::proto_version;
|
||||
};
|
||||
|
||||
IMessage::Ptr_t
|
||||
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
|
||||
|
||||
bool
|
||||
DecodeMesssageList(
|
||||
Key_t from, llarp_buffer_t* buf, std::vector<IMessage::Ptr_t>& dst, bool relayed = false);
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/router_version.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct ConsensusMessage
|
||||
{
|
||||
/// H
|
||||
ShortHash m_Hash;
|
||||
/// K
|
||||
std::vector<RouterID> m_Keys;
|
||||
/// N
|
||||
uint64_t m_NumberOfEntries;
|
||||
/// O
|
||||
uint64_t m_EntryOffset;
|
||||
/// T
|
||||
uint64_t m_TxID;
|
||||
/// U
|
||||
llarp_time_t m_NextUpdateRequired;
|
||||
/// V
|
||||
RouterVersion m_RotuerVersion;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,139 +0,0 @@
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include "findintro.hpp"
|
||||
#include "gotintro.hpp"
|
||||
#include <llarp/routing/message.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/nodedb.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
FindIntroMessage::~FindIntroMessage() = default;
|
||||
|
||||
bool
|
||||
FindIntroMessage::DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* val)
|
||||
{
|
||||
bool read = false;
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("N", tagName, read, k, val))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("O", relayOrder, read, k, val))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("S", location, read, k, val))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("T", txID, read, k, val))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, k, val))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message id
|
||||
if (!BEncodeWriteDictMsgType(buf, "A", "F"))
|
||||
return false;
|
||||
if (tagName.Empty())
|
||||
{
|
||||
// relay order
|
||||
if (!BEncodeWriteDictInt("O", relayOrder, buf))
|
||||
return false;
|
||||
|
||||
// service address
|
||||
if (!BEncodeWriteDictEntry("S", location, buf))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!BEncodeWriteDictEntry("N", tagName, buf))
|
||||
return false;
|
||||
|
||||
// relay order
|
||||
if (!BEncodeWriteDictInt("O", relayOrder, buf))
|
||||
return false;
|
||||
}
|
||||
// txid
|
||||
if (!BEncodeWriteDictInt("T", txID, buf))
|
||||
return false;
|
||||
// protocol version
|
||||
if (!BEncodeWriteDictInt("V", llarp::constants::proto_version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
FindIntroMessage::HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const
|
||||
{
|
||||
auto& dht = *ctx->impl;
|
||||
if (dht.pendingIntrosetLookups().HasPendingLookupFrom(TXOwner{From, txID}))
|
||||
{
|
||||
llarp::LogWarn("duplicate FIM from ", From, " txid=", txID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (not tagName.Empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// bad request (request for zero-key)
|
||||
if (location.IsZero())
|
||||
{
|
||||
// we dont got it
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
// we are relaying this message for e.g. a client
|
||||
if (relayed)
|
||||
{
|
||||
if (relayOrder >= IntroSetStorageRedundancy)
|
||||
{
|
||||
llarp::LogWarn("Invalid relayOrder received: ", relayOrder);
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
auto closestRCs =
|
||||
dht.GetRouter()->nodedb()->FindManyClosestTo(location, IntroSetStorageRedundancy);
|
||||
|
||||
if (closestRCs.size() <= relayOrder)
|
||||
{
|
||||
llarp::LogWarn("Can't fulfill FindIntro for relayOrder: ", relayOrder);
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& entry = closestRCs[relayOrder];
|
||||
Key_t peer = Key_t(entry.pubkey);
|
||||
dht.LookupIntroSetForPath(location, txID, pathID, peer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we should have this value if introset was propagated properly
|
||||
const auto maybe = dht.GetIntroSetByLocation(location);
|
||||
if (maybe)
|
||||
{
|
||||
replies.emplace_back(new GotIntroMessage({*maybe}, txID));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWarn("Got FIM with relayed == false and we don't have entry");
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/routing/message.hpp>
|
||||
#include <llarp/service/address.hpp>
|
||||
#include <llarp/service/tag.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct FindIntroMessage final : public IMessage
|
||||
{
|
||||
Key_t location;
|
||||
llarp::service::Tag tagName;
|
||||
uint64_t txID = 0;
|
||||
bool relayed = false;
|
||||
uint64_t relayOrder = 0;
|
||||
|
||||
FindIntroMessage(const Key_t& from, bool relay, uint64_t order) : IMessage(from)
|
||||
{
|
||||
relayed = relay;
|
||||
relayOrder = order;
|
||||
}
|
||||
|
||||
FindIntroMessage(const llarp::service::Tag& tag, uint64_t txid)
|
||||
: IMessage({}), tagName(tag), txID(txid)
|
||||
{}
|
||||
|
||||
explicit FindIntroMessage(uint64_t txid, const Key_t& addr, uint64_t order)
|
||||
: IMessage({}), location(addr), txID(txid), relayOrder(order)
|
||||
{
|
||||
tagName.Zero();
|
||||
}
|
||||
|
||||
~FindIntroMessage() override;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,65 +0,0 @@
|
||||
#include "findname.hpp"
|
||||
#include <oxenc/bt_serialize.h>
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include "gotname.hpp"
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/rpc/lokid_rpc_client.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/routing/dht_message.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
FindNameMessage::FindNameMessage(const Key_t& from, Key_t namehash, uint64_t txid)
|
||||
: IMessage(from), NameHash(std::move(namehash)), TxID(txid)
|
||||
{}
|
||||
|
||||
bool
|
||||
FindNameMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
const auto data = oxenc::bt_serialize(oxenc::bt_dict{
|
||||
{"A", "N"sv},
|
||||
{"H", std::string_view{(char*)NameHash.data(), NameHash.size()}},
|
||||
{"T", TxID}});
|
||||
return buf->write(data.begin(), data.end());
|
||||
}
|
||||
|
||||
bool
|
||||
FindNameMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
|
||||
{
|
||||
if (key.startswith("H"))
|
||||
{
|
||||
return NameHash.BDecode(val);
|
||||
}
|
||||
if (key.startswith("T"))
|
||||
{
|
||||
return bencode_read_integer(val, &TxID);
|
||||
}
|
||||
return bencode_discard(val);
|
||||
}
|
||||
|
||||
bool
|
||||
FindNameMessage::HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const
|
||||
{
|
||||
(void)replies;
|
||||
auto r = dht->impl->GetRouter();
|
||||
if (pathID.IsZero() or not r->IsServiceNode())
|
||||
return false;
|
||||
r->RpcClient()->LookupLNSNameHash(NameHash, [r, pathID = pathID, TxID = TxID](auto maybe) {
|
||||
auto path = r->pathContext().GetPathForTransfer(pathID);
|
||||
if (path == nullptr)
|
||||
return;
|
||||
routing::DHTMessage msg;
|
||||
if (maybe.has_value())
|
||||
{
|
||||
msg.M.emplace_back(new GotNameMessage(dht::Key_t{}, TxID, *maybe));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.M.emplace_back(new GotNameMessage(dht::Key_t{}, TxID, service::EncryptedName{}));
|
||||
}
|
||||
path->SendRoutingMessage(msg, r);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace llarp::dht
|
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/dht/message.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct FindNameMessage : public IMessage
|
||||
{
|
||||
explicit FindNameMessage(const Key_t& from, Key_t namehash, uint64_t txid);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const override;
|
||||
|
||||
Key_t NameHash;
|
||||
uint64_t TxID;
|
||||
};
|
||||
|
||||
} // namespace llarp::dht
|
@ -1,180 +0,0 @@
|
||||
#include "findrouter.hpp"
|
||||
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include "gotrouter.hpp"
|
||||
#include <llarp/nodedb.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/routing/dht_message.hpp>
|
||||
|
||||
#include <llarp/tooling/dht_event.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
bool
|
||||
RelayedFindRouterMessage::HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const
|
||||
{
|
||||
auto& dht = *ctx->impl;
|
||||
/// lookup for us, send an immeidate reply
|
||||
const Key_t us = dht.OurKey();
|
||||
const Key_t k{targetKey};
|
||||
if (k == us)
|
||||
{
|
||||
auto path = dht.GetRouter()->pathContext().GetByUpstream(targetKey, pathID);
|
||||
if (path)
|
||||
{
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {dht.GetRouter()->rc()}, false));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Key_t peer;
|
||||
// check if we know this in our nodedb first
|
||||
if (not dht.GetRouter()->SessionToRouterAllowed(targetKey))
|
||||
{
|
||||
// explicitly disallowed by network
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {}, false));
|
||||
return true;
|
||||
}
|
||||
// check netdb
|
||||
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(k);
|
||||
if (rc.pubkey == targetKey)
|
||||
{
|
||||
replies.emplace_back(new GotRouterMessage(k, txid, {rc}, false));
|
||||
return true;
|
||||
}
|
||||
peer = Key_t(rc.pubkey);
|
||||
// lookup if we don't have it in our nodedb
|
||||
dht.LookupRouterForPath(targetKey, txid, pathID, peer);
|
||||
return true;
|
||||
}
|
||||
|
||||
FindRouterMessage::~FindRouterMessage() = default;
|
||||
|
||||
bool
|
||||
FindRouterMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if (!bencode_write_bytestring(buf, "A", 1))
|
||||
return false;
|
||||
if (!bencode_write_bytestring(buf, "R", 1))
|
||||
return false;
|
||||
|
||||
// exploritory or not?
|
||||
if (!bencode_write_bytestring(buf, "E", 1))
|
||||
return false;
|
||||
if (!bencode_write_uint64(buf, exploritory ? 1 : 0))
|
||||
return false;
|
||||
|
||||
// iterative or not?
|
||||
if (!bencode_write_bytestring(buf, "I", 1))
|
||||
return false;
|
||||
if (!bencode_write_uint64(buf, iterative ? 1 : 0))
|
||||
return false;
|
||||
|
||||
// key
|
||||
if (!bencode_write_bytestring(buf, "K", 1))
|
||||
return false;
|
||||
if (!bencode_write_bytestring(buf, targetKey.data(), targetKey.size()))
|
||||
return false;
|
||||
|
||||
// txid
|
||||
if (!bencode_write_bytestring(buf, "T", 1))
|
||||
return false;
|
||||
if (!bencode_write_uint64(buf, txid))
|
||||
return false;
|
||||
|
||||
// version
|
||||
if (!bencode_write_bytestring(buf, "V", 1))
|
||||
return false;
|
||||
if (!bencode_write_uint64(buf, version))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
|
||||
{
|
||||
llarp_buffer_t strbuf;
|
||||
|
||||
if (key.startswith("E"))
|
||||
{
|
||||
uint64_t result;
|
||||
if (!bencode_read_integer(val, &result))
|
||||
return false;
|
||||
|
||||
exploritory = result != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key.startswith("I"))
|
||||
{
|
||||
uint64_t result;
|
||||
if (!bencode_read_integer(val, &result))
|
||||
return false;
|
||||
|
||||
iterative = result != 0;
|
||||
return true;
|
||||
}
|
||||
if (key.startswith("K"))
|
||||
{
|
||||
if (!bencode_read_string(val, &strbuf))
|
||||
return false;
|
||||
if (strbuf.sz != targetKey.size())
|
||||
return false;
|
||||
|
||||
std::copy(strbuf.base, strbuf.base + targetKey.SIZE, targetKey.begin());
|
||||
return true;
|
||||
}
|
||||
if (key.startswith("T"))
|
||||
{
|
||||
return bencode_read_integer(val, &txid);
|
||||
}
|
||||
if (key.startswith("V"))
|
||||
{
|
||||
return bencode_read_integer(val, &version);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
FindRouterMessage::HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const
|
||||
{
|
||||
auto& dht = *ctx->impl;
|
||||
|
||||
auto router = dht.GetRouter();
|
||||
router->NotifyRouterEvent<tooling::FindRouterReceivedEvent>(router->pubkey(), *this);
|
||||
|
||||
if (!dht.AllowTransit())
|
||||
{
|
||||
llarp::LogWarn("Got DHT lookup from ", From, " when we are not allowing dht transit");
|
||||
return false;
|
||||
}
|
||||
if (dht.pendingRouterLookups().HasPendingLookupFrom({From, txid}))
|
||||
{
|
||||
llarp::LogWarn("Duplicate FRM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
RouterContact found;
|
||||
if (targetKey.IsZero())
|
||||
{
|
||||
llarp::LogError("invalid FRM from ", From, " key is zero");
|
||||
return false;
|
||||
}
|
||||
const Key_t k(targetKey);
|
||||
if (exploritory)
|
||||
return dht.HandleExploritoryRouterLookup(From, txid, targetKey, replies);
|
||||
dht.LookupRouterRelayed(From, txid, k, !iterative, replies);
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
#include <llarp/dht/message.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct FindRouterMessage : public IMessage
|
||||
{
|
||||
// inbound parsing
|
||||
FindRouterMessage(const Key_t& from) : IMessage(from)
|
||||
{}
|
||||
|
||||
// find by routerid
|
||||
FindRouterMessage(uint64_t id, const RouterID& target)
|
||||
: IMessage({}), targetKey(target), txid(id)
|
||||
{}
|
||||
|
||||
// exploritory
|
||||
FindRouterMessage(uint64_t id) : IMessage({}), exploritory(true), txid(id)
|
||||
{
|
||||
targetKey.Randomize();
|
||||
}
|
||||
|
||||
~FindRouterMessage() override;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const override;
|
||||
|
||||
RouterID targetKey;
|
||||
bool iterative = false;
|
||||
bool exploritory = false;
|
||||
uint64_t txid = 0;
|
||||
uint64_t version = 0;
|
||||
};
|
||||
|
||||
/// variant of FindRouterMessage relayed via path
|
||||
struct RelayedFindRouterMessage final : public FindRouterMessage
|
||||
{
|
||||
RelayedFindRouterMessage(const Key_t& from) : FindRouterMessage(from)
|
||||
{}
|
||||
|
||||
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
|
||||
/// the path of the result
|
||||
/// TODO: smart path expiration logic needs to be implemented
|
||||
bool
|
||||
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,125 +0,0 @@
|
||||
#include "gotintro.hpp"
|
||||
|
||||
#include <llarp/service/intro.hpp>
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include <memory>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/routing/dht_message.hpp>
|
||||
#include <llarp/tooling/dht_event.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
GotIntroMessage::GotIntroMessage(std::vector<service::EncryptedIntroSet> results, uint64_t tx)
|
||||
: IMessage({}), found(std::move(results)), txid(tx)
|
||||
{}
|
||||
|
||||
bool
|
||||
GotIntroMessage::HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& /*replies*/) const
|
||||
{
|
||||
auto& dht = *ctx->impl;
|
||||
auto* router = dht.GetRouter();
|
||||
|
||||
router->NotifyRouterEvent<tooling::GotIntroReceivedEvent>(
|
||||
router->pubkey(),
|
||||
Key_t(From.data()),
|
||||
(found.size() > 0 ? found[0] : llarp::service::EncryptedIntroSet{}),
|
||||
txid);
|
||||
|
||||
for (const auto& introset : found)
|
||||
{
|
||||
if (!introset.Verify(dht.Now()))
|
||||
{
|
||||
LogWarn(
|
||||
"Invalid introset while handling direct GotIntro "
|
||||
"from ",
|
||||
From);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TXOwner owner(From, txid);
|
||||
|
||||
auto serviceLookup = dht.pendingIntrosetLookups().GetPendingLookupFrom(owner);
|
||||
if (serviceLookup)
|
||||
{
|
||||
if (not found.empty())
|
||||
{
|
||||
dht.pendingIntrosetLookups().Found(owner, serviceLookup->target, found);
|
||||
}
|
||||
else
|
||||
{
|
||||
dht.pendingIntrosetLookups().NotFound(owner, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
LogError("no pending TX for GIM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RelayedGotIntroMessage::HandleMessage(
|
||||
llarp_dht_context* ctx,
|
||||
[[maybe_unused]] std::vector<std::unique_ptr<IMessage>>& replies) const
|
||||
{
|
||||
// TODO: implement me better?
|
||||
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
|
||||
if (pathset)
|
||||
{
|
||||
auto copy = std::make_shared<const RelayedGotIntroMessage>(*this);
|
||||
return pathset->HandleGotIntroMessage(copy);
|
||||
}
|
||||
LogWarn("No path for got intro message pathid=", pathID);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
|
||||
{
|
||||
if (key.startswith("I"))
|
||||
{
|
||||
return BEncodeReadList(found, buf);
|
||||
}
|
||||
if (key.startswith("K"))
|
||||
{
|
||||
if (closer) // duplicate key?
|
||||
return false;
|
||||
dht::Key_t K;
|
||||
if (not K.BDecode(buf))
|
||||
return false;
|
||||
closer = K;
|
||||
return true;
|
||||
}
|
||||
bool read = false;
|
||||
if (!BEncodeMaybeReadDictInt("T", txid, read, key, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("V", version, read, key, buf))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
GotIntroMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictMsgType(buf, "A", "G"))
|
||||
return false;
|
||||
if (!BEncodeWriteDictList("I", found, buf))
|
||||
return false;
|
||||
if (closer)
|
||||
{
|
||||
if (!BEncodeWriteDictEntry("K", *closer, buf))
|
||||
return false;
|
||||
}
|
||||
if (!BEncodeWriteDictInt("T", txid, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/service/intro_set.hpp>
|
||||
#include <llarp/util/copy_or_nullptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
/// acknowledgement to PublishIntroMessage or reply to FindIntroMessage
|
||||
struct GotIntroMessage : public IMessage
|
||||
{
|
||||
/// the found introsets
|
||||
std::vector<service::EncryptedIntroSet> found;
|
||||
/// txid
|
||||
uint64_t txid = 0;
|
||||
/// the key of a router closer in keyspace if iterative lookup
|
||||
std::optional<Key_t> closer;
|
||||
|
||||
GotIntroMessage(const Key_t& from) : IMessage(from)
|
||||
{}
|
||||
|
||||
GotIntroMessage(const GotIntroMessage& other)
|
||||
: IMessage(other.From), found(other.found), txid(other.txid), closer(other.closer)
|
||||
{
|
||||
version = other.version;
|
||||
}
|
||||
|
||||
/// for iterative reply
|
||||
GotIntroMessage(const Key_t& from, const Key_t& _closer, uint64_t _txid)
|
||||
: IMessage(from), txid(_txid), closer(_closer)
|
||||
{}
|
||||
|
||||
/// for recursive reply
|
||||
GotIntroMessage(std::vector<service::EncryptedIntroSet> results, uint64_t txid);
|
||||
|
||||
~GotIntroMessage() override = default;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
|
||||
};
|
||||
|
||||
struct RelayedGotIntroMessage final : public GotIntroMessage
|
||||
{
|
||||
RelayedGotIntroMessage() : GotIntroMessage({})
|
||||
{}
|
||||
|
||||
bool
|
||||
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
|
||||
};
|
||||
|
||||
using GotIntroMessage_constptr = std::shared_ptr<const GotIntroMessage>;
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,62 +0,0 @@
|
||||
#include "gotname.hpp"
|
||||
#include <oxenc/bt_serialize.h>
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
constexpr size_t NameSizeLimit = 128;
|
||||
|
||||
GotNameMessage::GotNameMessage(const Key_t& from, uint64_t txid, service::EncryptedName data)
|
||||
: IMessage(from), result(std::move(data)), TxID(txid)
|
||||
{
|
||||
if (result.ciphertext.size() > NameSizeLimit)
|
||||
throw std::invalid_argument("name data too big");
|
||||
}
|
||||
|
||||
bool
|
||||
GotNameMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
const std::string nonce((const char*)result.nonce.data(), result.nonce.size());
|
||||
const auto data = oxenc::bt_serialize(
|
||||
oxenc::bt_dict{{"A", "M"sv}, {"D", result.ciphertext}, {"N", nonce}, {"T", TxID}});
|
||||
return buf->write(data.begin(), data.end());
|
||||
}
|
||||
|
||||
bool
|
||||
GotNameMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
|
||||
{
|
||||
if (key.startswith("D"))
|
||||
{
|
||||
llarp_buffer_t str{};
|
||||
if (not bencode_read_string(val, &str))
|
||||
return false;
|
||||
if (str.sz > NameSizeLimit)
|
||||
return false;
|
||||
result.ciphertext.resize(str.sz);
|
||||
std::copy_n(str.cur, str.sz, result.ciphertext.data());
|
||||
return true;
|
||||
}
|
||||
if (key.startswith("N"))
|
||||
{
|
||||
return result.nonce.BDecode(val);
|
||||
}
|
||||
if (key.startswith("T"))
|
||||
{
|
||||
return bencode_read_integer(val, &TxID);
|
||||
}
|
||||
return bencode_discard(val);
|
||||
}
|
||||
|
||||
bool
|
||||
GotNameMessage::HandleMessage(struct llarp_dht_context* ctx, std::vector<Ptr_t>&) const
|
||||
{
|
||||
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
|
||||
if (pathset == nullptr)
|
||||
return false;
|
||||
auto copy = std::make_shared<const GotNameMessage>(*this);
|
||||
return pathset->HandleGotNameMessage(copy);
|
||||
}
|
||||
|
||||
} // namespace llarp::dht
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/service/name.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct GotNameMessage : public IMessage
|
||||
{
|
||||
explicit GotNameMessage(const Key_t& from, uint64_t txid, service::EncryptedName data);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const override;
|
||||
|
||||
service::EncryptedName result;
|
||||
uint64_t TxID;
|
||||
};
|
||||
|
||||
} // namespace llarp::dht
|
@ -1,139 +0,0 @@
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include "gotrouter.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/router/i_rc_lookup_handler.hpp>
|
||||
#include <llarp/tooling/rc_event.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
GotRouterMessage::~GotRouterMessage() = default;
|
||||
|
||||
bool
|
||||
GotRouterMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (not bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
// message type
|
||||
if (not BEncodeWriteDictMsgType(buf, "A", "S"))
|
||||
return false;
|
||||
|
||||
if (closerTarget)
|
||||
{
|
||||
if (not BEncodeWriteDictEntry("K", *closerTarget, buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
// near
|
||||
if (not nearKeys.empty())
|
||||
{
|
||||
if (not BEncodeWriteDictList("N", nearKeys, buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (not BEncodeWriteDictList("R", foundRCs, buf))
|
||||
return false;
|
||||
|
||||
// txid
|
||||
if (not BEncodeWriteDictInt("T", txid, buf))
|
||||
return false;
|
||||
|
||||
// version
|
||||
if (not BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
|
||||
{
|
||||
if (key.startswith("K"))
|
||||
{
|
||||
if (closerTarget) // duplicate key?
|
||||
return false;
|
||||
closerTarget = std::make_unique<dht::Key_t>();
|
||||
return closerTarget->BDecode(val);
|
||||
}
|
||||
if (key.startswith("N"))
|
||||
{
|
||||
return BEncodeReadList(nearKeys, val);
|
||||
}
|
||||
if (key.startswith("R"))
|
||||
{
|
||||
return BEncodeReadList(foundRCs, val);
|
||||
}
|
||||
if (key.startswith("T"))
|
||||
{
|
||||
return bencode_read_integer(val, &txid);
|
||||
}
|
||||
bool read = false;
|
||||
if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, key, val))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
GotRouterMessage::HandleMessage(
|
||||
llarp_dht_context* ctx,
|
||||
[[maybe_unused]] std::vector<std::unique_ptr<IMessage>>& replies) const
|
||||
{
|
||||
auto& dht = *ctx->impl;
|
||||
if (relayed)
|
||||
{
|
||||
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
|
||||
auto copy = std::make_shared<const GotRouterMessage>(*this);
|
||||
return pathset && pathset->HandleGotRouterMessage(copy);
|
||||
}
|
||||
// not relayed
|
||||
const TXOwner owner(From, txid);
|
||||
|
||||
if (dht.pendingExploreLookups().HasPendingLookupFrom(owner))
|
||||
{
|
||||
LogDebug("got ", nearKeys.size(), " results in GRM for explore");
|
||||
if (nearKeys.empty())
|
||||
dht.pendingExploreLookups().NotFound(owner, closerTarget);
|
||||
else
|
||||
{
|
||||
dht.pendingExploreLookups().Found(owner, From.as_array(), nearKeys);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// not explore lookup
|
||||
if (dht.pendingRouterLookups().HasPendingLookupFrom(owner))
|
||||
{
|
||||
LogDebug("got ", foundRCs.size(), " results in GRM for lookup");
|
||||
if (foundRCs.empty())
|
||||
dht.pendingRouterLookups().NotFound(owner, closerTarget);
|
||||
else if (foundRCs[0].pubkey.IsZero())
|
||||
return false;
|
||||
else
|
||||
dht.pendingRouterLookups().Found(owner, foundRCs[0].pubkey, foundRCs);
|
||||
return true;
|
||||
}
|
||||
// store if valid
|
||||
for (const auto& rc : foundRCs)
|
||||
{
|
||||
if (not dht.GetRouter()->rcLookupHandler().CheckRC(rc))
|
||||
return false;
|
||||
if (txid == 0) // txid == 0 on gossip
|
||||
{
|
||||
auto* router = dht.GetRouter();
|
||||
router->NotifyRouterEvent<tooling::RCGossipReceivedEvent>(router->pubkey(), rc);
|
||||
router->GossipRCIfNeeded(rc);
|
||||
|
||||
auto peerDb = router->peerDb();
|
||||
if (peerDb)
|
||||
peerDb->handleGossipedRC(rc);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
#include <llarp/constants/proto.hpp>
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/router_contact.hpp>
|
||||
#include <llarp/util/copy_or_nullptr.hpp>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct GotRouterMessage final : public IMessage
|
||||
{
|
||||
GotRouterMessage(const Key_t& from, bool tunneled) : IMessage(from), relayed(tunneled)
|
||||
{}
|
||||
GotRouterMessage(
|
||||
const Key_t& from, uint64_t id, const std::vector<RouterContact>& results, bool tunneled)
|
||||
: IMessage(from), foundRCs(results), txid(id), relayed(tunneled)
|
||||
{}
|
||||
|
||||
GotRouterMessage(const Key_t& from, const Key_t& closer, uint64_t id, bool tunneled)
|
||||
: IMessage(from), closerTarget(new Key_t(closer)), txid(id), relayed(tunneled)
|
||||
{}
|
||||
|
||||
GotRouterMessage(uint64_t id, std::vector<RouterID> _near, bool tunneled)
|
||||
: IMessage({}), nearKeys(std::move(_near)), txid(id), relayed(tunneled)
|
||||
{}
|
||||
|
||||
/// gossip message
|
||||
GotRouterMessage(const RouterContact rc) : IMessage({}), foundRCs({rc}), txid(0)
|
||||
{
|
||||
version = llarp::constants::proto_version;
|
||||
}
|
||||
|
||||
GotRouterMessage(const GotRouterMessage& other)
|
||||
: IMessage(other.From)
|
||||
, foundRCs(other.foundRCs)
|
||||
, nearKeys(other.nearKeys)
|
||||
, closerTarget(copy_or_nullptr(other.closerTarget))
|
||||
, txid(other.txid)
|
||||
, relayed(other.relayed)
|
||||
{
|
||||
version = other.version;
|
||||
}
|
||||
|
||||
~GotRouterMessage() override;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const override;
|
||||
|
||||
std::vector<RouterContact> foundRCs;
|
||||
std::vector<RouterID> nearKeys;
|
||||
std::unique_ptr<Key_t> closerTarget;
|
||||
uint64_t txid = 0;
|
||||
bool relayed = false;
|
||||
};
|
||||
|
||||
using GotRouterMessage_constptr = std::shared_ptr<const GotRouterMessage>;
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,202 +0,0 @@
|
||||
#include "pubintro.hpp"
|
||||
|
||||
#include <llarp/dht/context.hpp>
|
||||
#include "gotintro.hpp"
|
||||
#include <llarp/messages/dht_immediate.hpp>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp/routing/dht_message.hpp>
|
||||
#include <llarp/nodedb.hpp>
|
||||
|
||||
#include <llarp/tooling/dht_event.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
const uint64_t PublishIntroMessage::MaxPropagationDepth = 5;
|
||||
PublishIntroMessage::~PublishIntroMessage() = default;
|
||||
|
||||
bool
|
||||
PublishIntroMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
|
||||
{
|
||||
bool read = false;
|
||||
if (!BEncodeMaybeReadDictEntry("I", introset, read, key, val))
|
||||
return false;
|
||||
if (read)
|
||||
return true;
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("O", relayOrder, read, key, val))
|
||||
return false;
|
||||
if (read)
|
||||
return true;
|
||||
|
||||
uint64_t relayedInt = (relayed ? 1 : 0);
|
||||
if (!BEncodeMaybeReadDictInt("R", relayedInt, read, key, val))
|
||||
return false;
|
||||
if (read)
|
||||
{
|
||||
relayed = relayedInt;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("T", txID, read, key, val))
|
||||
return false;
|
||||
if (read)
|
||||
return true;
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("V", version, read, key, val))
|
||||
return false;
|
||||
if (read)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const
|
||||
{
|
||||
const auto now = ctx->impl->Now();
|
||||
const llarp::dht::Key_t addr{introset.derivedSigningKey.data()};
|
||||
|
||||
auto router = ctx->impl->GetRouter();
|
||||
router->NotifyRouterEvent<tooling::PubIntroReceivedEvent>(
|
||||
router->pubkey(),
|
||||
Key_t(relayed ? router->pubkey() : From.data()),
|
||||
addr,
|
||||
txID,
|
||||
relayOrder);
|
||||
|
||||
auto& dht = *ctx->impl;
|
||||
if (!introset.Verify(now))
|
||||
{
|
||||
llarp::LogWarn("Received PublishIntroMessage with invalid introset: ", introset);
|
||||
// don't propogate or store
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (introset.IsExpired(now + llarp::service::MAX_INTROSET_TIME_DELTA))
|
||||
{
|
||||
// don't propogate or store
|
||||
llarp::LogWarn("Received PublishIntroMessage with expired Introset: ", introset);
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
// identify closest 4 routers
|
||||
auto closestRCs =
|
||||
dht.GetRouter()->nodedb()->FindManyClosestTo(addr, IntroSetStorageRedundancy);
|
||||
if (closestRCs.size() != IntroSetStorageRedundancy)
|
||||
{
|
||||
llarp::LogWarn("Received PublishIntroMessage but only know ", closestRCs.size(), " nodes");
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& us = dht.OurKey();
|
||||
|
||||
// function to identify the closest 4 routers we know of for this introset
|
||||
auto propagateIfNotUs = [&](size_t index) {
|
||||
assert(index < IntroSetStorageRedundancy);
|
||||
|
||||
const auto& rc = closestRCs[index];
|
||||
const Key_t peer{rc.pubkey};
|
||||
|
||||
if (peer == us)
|
||||
{
|
||||
llarp::LogInfo("we are peer ", index, " so storing instead of propagating");
|
||||
|
||||
dht.services()->PutNode(introset);
|
||||
replies.emplace_back(new GotIntroMessage({introset}, txID));
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogInfo("propagating to peer ", index);
|
||||
if (relayed)
|
||||
{
|
||||
dht.PropagateLocalIntroSet(pathID, txID, introset, peer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
dht.PropagateIntroSetTo(From, txID, introset, peer, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (relayed)
|
||||
{
|
||||
if (relayOrder >= IntroSetStorageRedundancy)
|
||||
{
|
||||
llarp::LogWarn("Received PublishIntroMessage with invalid relayOrder: ", relayOrder);
|
||||
replies.emplace_back(new GotIntroMessage({}, txID));
|
||||
return true;
|
||||
}
|
||||
|
||||
llarp::LogInfo("Relaying PublishIntroMessage for ", addr, ", txid=", txID);
|
||||
|
||||
propagateIfNotUs(relayOrder);
|
||||
}
|
||||
else
|
||||
{
|
||||
int candidateNumber = -1;
|
||||
int index = 0;
|
||||
for (const auto& rc : closestRCs)
|
||||
{
|
||||
if (rc.pubkey == dht.OurKey())
|
||||
{
|
||||
candidateNumber = index;
|
||||
break;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
|
||||
if (candidateNumber >= 0)
|
||||
{
|
||||
LogInfo(
|
||||
"Received PubIntro for ",
|
||||
addr,
|
||||
", txid=",
|
||||
txID,
|
||||
" and we are candidate ",
|
||||
candidateNumber);
|
||||
dht.services()->PutNode(introset);
|
||||
replies.emplace_back(new GotIntroMessage({introset}, txID));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWarn(
|
||||
"!!! Received PubIntro with relayed==false but we aren't"
|
||||
" candidate, intro derived key: ",
|
||||
addr,
|
||||
", txid=",
|
||||
txID,
|
||||
", message from: ",
|
||||
From);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PublishIntroMessage::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictMsgType(buf, "A", "I"))
|
||||
return false;
|
||||
if (!BEncodeWriteDictEntry("I", introset, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("O", relayOrder, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("R", relayed, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("T", txID, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("V", llarp::constants::proto_version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
#include <llarp/dht/message.hpp>
|
||||
#include <llarp/service/intro_set.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct PublishIntroMessage final : public IMessage
|
||||
{
|
||||
static const uint64_t MaxPropagationDepth;
|
||||
llarp::service::EncryptedIntroSet introset;
|
||||
bool relayed = false;
|
||||
uint64_t relayOrder = 0;
|
||||
uint64_t txID = 0;
|
||||
PublishIntroMessage(const Key_t& from, bool relayed_) : IMessage(from), relayed(relayed_)
|
||||
{}
|
||||
|
||||
PublishIntroMessage(
|
||||
const llarp::service::EncryptedIntroSet& introset_,
|
||||
uint64_t tx,
|
||||
bool relayed_,
|
||||
uint64_t relayOrder_)
|
||||
: IMessage({}), introset(introset_), relayed(relayed_), relayOrder(relayOrder_), txID(tx)
|
||||
{}
|
||||
|
||||
~PublishIntroMessage() override;
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
|
||||
|
||||
bool
|
||||
HandleMessage(
|
||||
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const override;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,39 +1,36 @@
|
||||
#include "policy.hpp"
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::exit
|
||||
{
|
||||
namespace exit
|
||||
void
|
||||
Policy::bt_encode(oxenc::bt_dict_producer& btdp) const
|
||||
{
|
||||
bool
|
||||
Policy::BEncode(llarp_buffer_t* buf) const
|
||||
try
|
||||
{
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("a", proto, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("b", port, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("d", drop, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("v", version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
btdp.append("a", proto);
|
||||
btdp.append("b", port);
|
||||
btdp.append("d", drop);
|
||||
btdp.append("v", version);
|
||||
}
|
||||
|
||||
bool
|
||||
Policy::DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* buf)
|
||||
catch (...)
|
||||
{
|
||||
bool read = false;
|
||||
if (!BEncodeMaybeReadDictInt("a", proto, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("b", port, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("d", drop, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("v", version, read, k, buf))
|
||||
return false;
|
||||
return read;
|
||||
log::critical(policy_cat, "Error: exit Policy failed to bt encode contents!");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Policy::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
if (!BEncodeMaybeReadDictInt("a", proto, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("b", port, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("d", drop, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("v", version, read, k, buf))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
} // namespace exit
|
||||
} // namespace llarp
|
||||
} // namespace llarp::exit
|
||||
|
@ -1,29 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <oxenc/bt.h>
|
||||
#include <llarp/util/bencode.hpp>
|
||||
|
||||
namespace llarp
|
||||
namespace
|
||||
{
|
||||
namespace exit
|
||||
static auto policy_cat = llarp::log::Cat("lokinet.policy");
|
||||
} // namespace
|
||||
|
||||
namespace llarp::exit
|
||||
{
|
||||
struct Policy
|
||||
{
|
||||
struct Policy
|
||||
{
|
||||
uint64_t proto = 0;
|
||||
uint64_t port = 0;
|
||||
uint64_t drop = 0;
|
||||
uint64_t version = llarp::constants::proto_version;
|
||||
uint64_t proto = 0;
|
||||
uint64_t port = 0;
|
||||
uint64_t drop = 0;
|
||||
uint64_t version = llarp::constants::proto_version;
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
return bencode_decode_dict(*this, buf);
|
||||
}
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
return bencode_decode_dict(*this, buf);
|
||||
}
|
||||
|
||||
bool
|
||||
DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* val);
|
||||
bool
|
||||
decode_key(const llarp_buffer_t& k, llarp_buffer_t* val);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
};
|
||||
} // namespace exit
|
||||
} // namespace llarp
|
||||
void
|
||||
bt_encode(oxenc::bt_dict_producer& btdp) const;
|
||||
};
|
||||
} // namespace llarp::exit
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,72 +0,0 @@
|
||||
#include "iwp.hpp"
|
||||
#include "linklayer.hpp"
|
||||
#include <memory>
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace iwp
|
||||
{
|
||||
LinkLayer_ptr
|
||||
NewInboundLink(
|
||||
std::shared_ptr<KeyManager> keyManager,
|
||||
std::shared_ptr<EventLoop> loop,
|
||||
GetRCFunc getrc,
|
||||
LinkMessageHandler h,
|
||||
SignBufferFunc sign,
|
||||
BeforeConnectFunc_t before,
|
||||
SessionEstablishedHandler est,
|
||||
SessionRenegotiateHandler reneg,
|
||||
TimeoutHandler timeout,
|
||||
SessionClosedHandler closed,
|
||||
PumpDoneHandler pumpDone,
|
||||
WorkerFunc_t work)
|
||||
{
|
||||
return std::make_shared<LinkLayer>(
|
||||
keyManager,
|
||||
loop,
|
||||
getrc,
|
||||
h,
|
||||
sign,
|
||||
before,
|
||||
est,
|
||||
reneg,
|
||||
timeout,
|
||||
closed,
|
||||
pumpDone,
|
||||
work,
|
||||
true);
|
||||
}
|
||||
|
||||
LinkLayer_ptr
|
||||
NewOutboundLink(
|
||||
std::shared_ptr<KeyManager> keyManager,
|
||||
std::shared_ptr<EventLoop> loop,
|
||||
GetRCFunc getrc,
|
||||
LinkMessageHandler h,
|
||||
SignBufferFunc sign,
|
||||
BeforeConnectFunc_t before,
|
||||
SessionEstablishedHandler est,
|
||||
SessionRenegotiateHandler reneg,
|
||||
TimeoutHandler timeout,
|
||||
SessionClosedHandler closed,
|
||||
PumpDoneHandler pumpDone,
|
||||
WorkerFunc_t work)
|
||||
{
|
||||
return std::make_shared<LinkLayer>(
|
||||
keyManager,
|
||||
loop,
|
||||
getrc,
|
||||
h,
|
||||
sign,
|
||||
before,
|
||||
est,
|
||||
reneg,
|
||||
timeout,
|
||||
closed,
|
||||
pumpDone,
|
||||
work,
|
||||
false);
|
||||
}
|
||||
} // namespace iwp
|
||||
} // namespace llarp
|
@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/link/server.hpp>
|
||||
#include "linklayer.hpp"
|
||||
#include <memory>
|
||||
#include <llarp/config/key_manager.hpp>
|
||||
|
||||
namespace llarp::iwp
|
||||
{
|
||||
LinkLayer_ptr
|
||||
NewInboundLink(
|
||||
std::shared_ptr<KeyManager> keyManager,
|
||||
std::shared_ptr<EventLoop> loop,
|
||||
GetRCFunc getrc,
|
||||
LinkMessageHandler h,
|
||||
SignBufferFunc sign,
|
||||
BeforeConnectFunc_t before,
|
||||
SessionEstablishedHandler est,
|
||||
SessionRenegotiateHandler reneg,
|
||||
TimeoutHandler timeout,
|
||||
SessionClosedHandler closed,
|
||||
PumpDoneHandler pumpDone,
|
||||
WorkerFunc_t work);
|
||||
|
||||
LinkLayer_ptr
|
||||
NewOutboundLink(
|
||||
std::shared_ptr<KeyManager> keyManager,
|
||||
std::shared_ptr<EventLoop> loop,
|
||||
GetRCFunc getrc,
|
||||
LinkMessageHandler h,
|
||||
SignBufferFunc sign,
|
||||
BeforeConnectFunc_t before,
|
||||
SessionEstablishedHandler est,
|
||||
SessionRenegotiateHandler reneg,
|
||||
TimeoutHandler timeout,
|
||||
SessionClosedHandler closed,
|
||||
PumpDoneHandler pumpDone,
|
||||
WorkerFunc_t work);
|
||||
|
||||
} // namespace llarp::iwp
|
@ -1,115 +0,0 @@
|
||||
#include "linklayer.hpp"
|
||||
#include "session.hpp"
|
||||
#include <llarp/config/key_manager.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace llarp::iwp
|
||||
{
|
||||
LinkLayer::LinkLayer(
|
||||
std::shared_ptr<KeyManager> keyManager,
|
||||
std::shared_ptr<EventLoop> ev,
|
||||
GetRCFunc getrc,
|
||||
LinkMessageHandler h,
|
||||
SignBufferFunc sign,
|
||||
BeforeConnectFunc_t before,
|
||||
SessionEstablishedHandler est,
|
||||
SessionRenegotiateHandler reneg,
|
||||
TimeoutHandler timeout,
|
||||
SessionClosedHandler closed,
|
||||
PumpDoneHandler pumpDone,
|
||||
WorkerFunc_t worker,
|
||||
bool allowInbound)
|
||||
: ILinkLayer(
|
||||
keyManager, getrc, h, sign, before, est, reneg, timeout, closed, pumpDone, worker)
|
||||
, m_Wakeup{ev->make_waker([this]() { HandleWakeupPlaintext(); })}
|
||||
, m_Inbound{allowInbound}
|
||||
{}
|
||||
|
||||
std::string_view
|
||||
LinkLayer::Name() const
|
||||
{
|
||||
return "iwp";
|
||||
}
|
||||
|
||||
std::string
|
||||
LinkLayer::PrintableName() const
|
||||
{
|
||||
if (m_Inbound)
|
||||
return "inbound iwp link";
|
||||
else
|
||||
return "outbound iwp link";
|
||||
}
|
||||
|
||||
uint16_t
|
||||
LinkLayer::Rank() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
void
|
||||
LinkLayer::RecvFrom(const SockAddr& from, ILinkSession::Packet_t pkt)
|
||||
{
|
||||
std::shared_ptr<ILinkSession> session;
|
||||
auto itr = m_AuthedAddrs.find(from);
|
||||
bool isNewSession = false;
|
||||
if (itr == m_AuthedAddrs.end())
|
||||
{
|
||||
Lock_t lock{m_PendingMutex};
|
||||
auto it = m_Pending.find(from);
|
||||
if (it == m_Pending.end())
|
||||
{
|
||||
if (not m_Inbound)
|
||||
return;
|
||||
isNewSession = true;
|
||||
it = m_Pending.emplace(from, std::make_shared<Session>(this, from)).first;
|
||||
}
|
||||
session = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto s_itr = m_AuthedLinks.find(itr->second); s_itr != m_AuthedLinks.end())
|
||||
session = s_itr->second;
|
||||
}
|
||||
if (session)
|
||||
{
|
||||
bool success = session->Recv_LL(std::move(pkt));
|
||||
if (not success and isNewSession)
|
||||
{
|
||||
LogDebug("Brand new session failed; removing from pending sessions list");
|
||||
m_Pending.erase(from);
|
||||
}
|
||||
WakeupPlaintext();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ILinkSession>
|
||||
LinkLayer::NewOutboundSession(const RouterContact& rc, const AddressInfo& ai)
|
||||
{
|
||||
if (m_Inbound)
|
||||
throw std::logic_error{"inbound link cannot make outbound sessions"};
|
||||
return std::make_shared<Session>(this, rc, ai);
|
||||
}
|
||||
|
||||
void
|
||||
LinkLayer::WakeupPlaintext()
|
||||
{
|
||||
m_Wakeup->Trigger();
|
||||
}
|
||||
|
||||
void
|
||||
LinkLayer::HandleWakeupPlaintext()
|
||||
{
|
||||
// Copy bare pointers out first because HandlePlaintext can end up removing themselves from the
|
||||
// structures.
|
||||
m_WakingUp.clear(); // Reused to minimize allocations.
|
||||
for (const auto& [router_id, session] : m_AuthedLinks)
|
||||
m_WakingUp.push_back(session.get());
|
||||
for (const auto& [addr, session] : m_Pending)
|
||||
m_WakingUp.push_back(session.get());
|
||||
for (auto* session : m_WakingUp)
|
||||
session->HandlePlaintext();
|
||||
PumpDone();
|
||||
}
|
||||
|
||||
} // namespace llarp::iwp
|
@ -1,63 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/constants/link_layer.hpp>
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
#include <llarp/crypto/encrypted.hpp>
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/link/server.hpp>
|
||||
#include <llarp/config/key_manager.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <llarp/ev/ev.hpp>
|
||||
|
||||
namespace llarp::iwp
|
||||
{
|
||||
struct Session;
|
||||
|
||||
struct LinkLayer final : public ILinkLayer
|
||||
{
|
||||
LinkLayer(
|
||||
std::shared_ptr<KeyManager> keyManager,
|
||||
std::shared_ptr<EventLoop> ev,
|
||||
GetRCFunc getrc,
|
||||
LinkMessageHandler h,
|
||||
SignBufferFunc sign,
|
||||
BeforeConnectFunc_t before,
|
||||
SessionEstablishedHandler est,
|
||||
SessionRenegotiateHandler reneg,
|
||||
TimeoutHandler timeout,
|
||||
SessionClosedHandler closed,
|
||||
PumpDoneHandler pumpDone,
|
||||
WorkerFunc_t dowork,
|
||||
bool permitInbound);
|
||||
|
||||
std::shared_ptr<ILinkSession>
|
||||
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override;
|
||||
|
||||
std::string_view
|
||||
Name() const override;
|
||||
|
||||
uint16_t
|
||||
Rank() const override;
|
||||
|
||||
void
|
||||
RecvFrom(const SockAddr& from, ILinkSession::Packet_t pkt) override;
|
||||
|
||||
void
|
||||
WakeupPlaintext();
|
||||
|
||||
std::string
|
||||
PrintableName() const;
|
||||
|
||||
private:
|
||||
void
|
||||
HandleWakeupPlaintext();
|
||||
|
||||
const std::shared_ptr<EventLoopWakeup> m_Wakeup;
|
||||
std::vector<ILinkSession*> m_WakingUp;
|
||||
const bool m_Inbound;
|
||||
};
|
||||
|
||||
using LinkLayer_ptr = std::shared_ptr<LinkLayer>;
|
||||
} // namespace llarp::iwp
|
@ -1,193 +0,0 @@
|
||||
#include "message_buffer.hpp"
|
||||
#include "session.hpp"
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace iwp
|
||||
{
|
||||
OutboundMessage::OutboundMessage(
|
||||
uint64_t msgid,
|
||||
ILinkSession::Message_t msg,
|
||||
llarp_time_t now,
|
||||
ILinkSession::CompletionHandler handler,
|
||||
uint16_t priority)
|
||||
: m_Data{std::move(msg)}
|
||||
, m_MsgID{msgid}
|
||||
, m_Completed{handler}
|
||||
, m_LastFlush{now}
|
||||
, m_StartedAt{now}
|
||||
, m_ResendPriority{priority}
|
||||
{
|
||||
const llarp_buffer_t buf(m_Data);
|
||||
CryptoManager::instance()->shorthash(m_Digest, buf);
|
||||
m_Acks.set(0);
|
||||
}
|
||||
|
||||
ILinkSession::Packet_t
|
||||
OutboundMessage::XMIT() const
|
||||
{
|
||||
size_t extra = std::min(m_Data.size(), FragmentSize);
|
||||
auto xmit = CreatePacket(Command::eXMIT, 10 + 32 + extra, 0, 0);
|
||||
oxenc::write_host_as_big(
|
||||
static_cast<uint16_t>(m_Data.size()), xmit.data() + CommandOverhead + PacketOverhead);
|
||||
oxenc::write_host_as_big(m_MsgID, xmit.data() + 2 + CommandOverhead + PacketOverhead);
|
||||
std::copy_n(
|
||||
m_Digest.begin(), m_Digest.size(), xmit.data() + 10 + CommandOverhead + PacketOverhead);
|
||||
std::copy_n(m_Data.data(), extra, xmit.data() + 10 + CommandOverhead + PacketOverhead + 32);
|
||||
return xmit;
|
||||
}
|
||||
|
||||
void
|
||||
OutboundMessage::Completed()
|
||||
{
|
||||
if (m_Completed)
|
||||
{
|
||||
m_Completed(ILinkSession::DeliveryStatus::eDeliverySuccess);
|
||||
}
|
||||
m_Completed = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
OutboundMessage::ShouldFlush(llarp_time_t now) const
|
||||
{
|
||||
return now - m_LastFlush >= TXFlushInterval;
|
||||
}
|
||||
|
||||
void
|
||||
OutboundMessage::Ack(byte_t bitmask)
|
||||
{
|
||||
m_Acks = std::bitset<8>(bitmask);
|
||||
}
|
||||
|
||||
void
|
||||
OutboundMessage::FlushUnAcked(
|
||||
std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now)
|
||||
{
|
||||
/// overhead for a data packet in plaintext
|
||||
static constexpr size_t Overhead = 10;
|
||||
uint16_t idx = 0;
|
||||
const auto datasz = m_Data.size();
|
||||
while (idx < datasz)
|
||||
{
|
||||
if (not m_Acks[idx / FragmentSize])
|
||||
{
|
||||
const size_t fragsz = idx + FragmentSize < datasz ? FragmentSize : datasz - idx;
|
||||
auto frag = CreatePacket(Command::eDATA, fragsz + Overhead, 0, 0);
|
||||
oxenc::write_host_as_big(idx, frag.data() + 2 + PacketOverhead);
|
||||
oxenc::write_host_as_big(m_MsgID, frag.data() + 4 + PacketOverhead);
|
||||
std::copy(
|
||||
m_Data.begin() + idx,
|
||||
m_Data.begin() + idx + fragsz,
|
||||
frag.data() + PacketOverhead + Overhead + 2);
|
||||
sendpkt(std::move(frag));
|
||||
}
|
||||
idx += FragmentSize;
|
||||
}
|
||||
m_LastFlush = now;
|
||||
}
|
||||
|
||||
bool
|
||||
OutboundMessage::IsTransmitted() const
|
||||
{
|
||||
const auto sz = m_Data.size();
|
||||
for (uint16_t idx = 0; idx < sz; idx += FragmentSize)
|
||||
{
|
||||
if (not m_Acks.test(idx / FragmentSize))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
OutboundMessage::IsTimedOut(const llarp_time_t now) const
|
||||
{
|
||||
// TODO: make configurable by outbound message deliverer
|
||||
return now > m_StartedAt && now - m_StartedAt > DeliveryTimeout;
|
||||
}
|
||||
|
||||
void
|
||||
OutboundMessage::InformTimeout()
|
||||
{
|
||||
if (m_Completed)
|
||||
{
|
||||
m_Completed(ILinkSession::DeliveryStatus::eDeliveryDropped);
|
||||
}
|
||||
m_Completed = nullptr;
|
||||
}
|
||||
|
||||
InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h, llarp_time_t now)
|
||||
: m_Data(size_t{sz}), m_Digset{std::move(h)}, m_MsgID(msgid), m_LastActiveAt{now}
|
||||
{}
|
||||
|
||||
void
|
||||
InboundMessage::HandleData(uint16_t idx, const llarp_buffer_t& buf, llarp_time_t now)
|
||||
{
|
||||
if (idx + buf.sz > m_Data.size())
|
||||
{
|
||||
LogWarn("invalid fragment offset ", idx);
|
||||
return;
|
||||
}
|
||||
byte_t* dst = m_Data.data() + idx;
|
||||
std::copy_n(buf.base, buf.sz, dst);
|
||||
m_Acks.set(idx / FragmentSize);
|
||||
LogTrace("got fragment ", idx / FragmentSize);
|
||||
m_LastActiveAt = now;
|
||||
}
|
||||
|
||||
ILinkSession::Packet_t
|
||||
InboundMessage::ACKS() const
|
||||
{
|
||||
auto acks = CreatePacket(Command::eACKS, 9);
|
||||
oxenc::write_host_as_big(m_MsgID, acks.data() + CommandOverhead + PacketOverhead);
|
||||
acks[PacketOverhead + 10] = AcksBitmask();
|
||||
return acks;
|
||||
}
|
||||
|
||||
byte_t
|
||||
InboundMessage::AcksBitmask() const
|
||||
{
|
||||
return byte_t{(byte_t)m_Acks.to_ulong()};
|
||||
}
|
||||
|
||||
bool
|
||||
InboundMessage::IsCompleted() const
|
||||
{
|
||||
const auto sz = m_Data.size();
|
||||
for (size_t idx = 0; idx < sz; idx += FragmentSize)
|
||||
{
|
||||
if (not m_Acks.test(idx / FragmentSize))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
InboundMessage::ShouldSendACKS(llarp_time_t now) const
|
||||
{
|
||||
return now > m_LastACKSent + ACKResendInterval;
|
||||
}
|
||||
|
||||
bool
|
||||
InboundMessage::IsTimedOut(const llarp_time_t now) const
|
||||
{
|
||||
return now > m_LastActiveAt && now - m_LastActiveAt > DeliveryTimeout;
|
||||
}
|
||||
|
||||
void
|
||||
InboundMessage::SendACKS(std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now)
|
||||
{
|
||||
sendpkt(ACKS());
|
||||
m_LastACKSent = now;
|
||||
}
|
||||
|
||||
bool
|
||||
InboundMessage::Verify() const
|
||||
{
|
||||
ShortHash gotten;
|
||||
const llarp_buffer_t buf(m_Data);
|
||||
CryptoManager::instance()->shorthash(gotten, buf);
|
||||
return gotten == m_Digset;
|
||||
}
|
||||
} // namespace iwp
|
||||
} // namespace llarp
|
@ -1,127 +0,0 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <llarp/constants/link_layer.hpp>
|
||||
#include <llarp/link/session.hpp>
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/buffer.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace iwp
|
||||
{
|
||||
enum Command
|
||||
{
|
||||
/// keep alive message
|
||||
ePING = 0,
|
||||
/// begin transission
|
||||
eXMIT = 1,
|
||||
/// fragment data
|
||||
eDATA = 2,
|
||||
/// acknolege fragments
|
||||
eACKS = 3,
|
||||
/// negative ack
|
||||
eNACK = 4,
|
||||
/// multiack
|
||||
eMACK = 5,
|
||||
/// close session
|
||||
eCLOS = 0xff,
|
||||
};
|
||||
|
||||
/// max size of data fragments
|
||||
static constexpr size_t FragmentSize = 1024;
|
||||
/// plaintext header overhead size
|
||||
static constexpr size_t CommandOverhead = 2;
|
||||
|
||||
struct OutboundMessage
|
||||
{
|
||||
OutboundMessage() = default;
|
||||
OutboundMessage(
|
||||
uint64_t msgid,
|
||||
ILinkSession::Message_t data,
|
||||
llarp_time_t now,
|
||||
ILinkSession::CompletionHandler handler,
|
||||
uint16_t priority);
|
||||
|
||||
ILinkSession::Message_t m_Data;
|
||||
uint64_t m_MsgID = 0;
|
||||
std::bitset<MAX_LINK_MSG_SIZE / FragmentSize> m_Acks;
|
||||
ILinkSession::CompletionHandler m_Completed;
|
||||
llarp_time_t m_LastFlush = 0s;
|
||||
ShortHash m_Digest;
|
||||
llarp_time_t m_StartedAt = 0s;
|
||||
uint16_t m_ResendPriority;
|
||||
|
||||
bool
|
||||
operator<(const OutboundMessage& other) const
|
||||
{
|
||||
// yes, the first order is reversed as higher means more important
|
||||
// second part is for queue order
|
||||
int prioA = -m_ResendPriority, prioB = -other.m_ResendPriority;
|
||||
return std::tie(prioA, m_MsgID) < std::tie(prioB, other.m_MsgID);
|
||||
}
|
||||
|
||||
ILinkSession::Packet_t
|
||||
XMIT() const;
|
||||
|
||||
void
|
||||
Ack(byte_t bitmask);
|
||||
|
||||
void
|
||||
FlushUnAcked(std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now);
|
||||
|
||||
bool
|
||||
ShouldFlush(llarp_time_t now) const;
|
||||
|
||||
void
|
||||
Completed();
|
||||
|
||||
bool
|
||||
IsTransmitted() const;
|
||||
|
||||
bool
|
||||
IsTimedOut(llarp_time_t now) const;
|
||||
|
||||
void
|
||||
InformTimeout();
|
||||
};
|
||||
|
||||
struct InboundMessage
|
||||
{
|
||||
InboundMessage() = default;
|
||||
InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h, llarp_time_t now);
|
||||
|
||||
ILinkSession::Message_t m_Data;
|
||||
ShortHash m_Digset;
|
||||
uint64_t m_MsgID = 0;
|
||||
llarp_time_t m_LastACKSent = 0s;
|
||||
llarp_time_t m_LastActiveAt = 0s;
|
||||
std::bitset<MAX_LINK_MSG_SIZE / FragmentSize> m_Acks;
|
||||
|
||||
void
|
||||
HandleData(uint16_t idx, const llarp_buffer_t& buf, llarp_time_t now);
|
||||
|
||||
bool
|
||||
IsCompleted() const;
|
||||
|
||||
bool
|
||||
IsTimedOut(llarp_time_t now) const;
|
||||
|
||||
bool
|
||||
Verify() const;
|
||||
|
||||
byte_t
|
||||
AcksBitmask() const;
|
||||
|
||||
bool
|
||||
ShouldSendACKS(llarp_time_t now) const;
|
||||
|
||||
void
|
||||
SendACKS(std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now);
|
||||
|
||||
ILinkSession::Packet_t
|
||||
ACKS() const;
|
||||
};
|
||||
|
||||
} // namespace iwp
|
||||
} // namespace llarp
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue