pull/258/head
Ryan Tharp 5 years ago
commit 1372d029f6

@ -510,8 +510,12 @@ set(LIB_SRC
llarp/dht/bucket.cpp
llarp/dht/context.cpp
llarp/dht/dht.cpp
llarp/dht/explorenetworkjob.cpp
llarp/dht/kademlia.cpp
llarp/dht/key.cpp
llarp/dht/localtaglookup.cpp
llarp/dht/localrouterlookup.cpp
llarp/dht/localserviceaddresslookup.cpp
llarp/dht/message.cpp
llarp/dht/messages/findintro.cpp
llarp/dht/messages/findrouter.cpp
@ -519,6 +523,12 @@ set(LIB_SRC
llarp/dht/messages/gotrouter.cpp
llarp/dht/messages/pubintro.cpp
llarp/dht/node.cpp
llarp/dht/publishservicejob.cpp
llarp/dht/recursiverouterlookup.cpp
llarp/dht/serviceaddresslookup.cpp
llarp/dht/taglookup.cpp
llarp/dht/tx.cpp
llarp/dht/txholder.cpp
llarp/dht/txowner.cpp
llarp/dns.cpp
llarp/dnsc.cpp
@ -612,13 +622,16 @@ set(DNS_SRC
set(TEST_SRC
# helpers
test/main.cpp
test/dht/mock_context.cpp
test/test_util.cpp
# actual test cases
test/crypto/test_llarp_crypto_types.cpp
test/crypto/test_llarp_crypto.cpp
test/dht/test_llarp_dht_bucket.cpp
test/dht/test_llarp_dht_explorenetworkjob.cpp
test/dht/test_llarp_dht_kademlia.cpp
test/dht/test_llarp_dht_key.cpp
test/dht/test_llarp_dht_tx.cpp
test/dht/test_llarp_dht_txowner.cpp
test/dns/test_llarp_dns_dns.cpp
test/exit/test_llarp_exit_context.cpp

@ -6,6 +6,7 @@
#include <getopt.h>
#include <signal.h>
#include <wordexp.h>
#include <string>
#include <iostream>
@ -56,6 +57,22 @@ handle_signal_win32(DWORD fdwCtrlType)
}
#endif
/// resolve ~ and symlinks into actual paths (so we know the real path on disk,
/// to remove assumptions and confusion with permissions)
std::string
resolvePath(std::string conffname)
{
wordexp_t exp_result;
wordexp(conffname.c_str(), &exp_result, 0);
char *resolvedPath = realpath(exp_result.we_wordv[0], NULL);
if(!resolvedPath)
{
llarp::LogWarn("Can't resolve path: ", exp_result.we_wordv[0]);
return "";
}
return resolvedPath;
}
int
main(int argc, char *argv[])
{
@ -108,7 +125,7 @@ main(int argc, char *argv[])
}
}
std::string conffname;
std::string conffname; // suggestions: confFName? conf_fname?
if(optind < argc)
{
@ -116,15 +133,33 @@ main(int argc, char *argv[])
fs::path fname = fs::path(argv[optind]);
fs::path basedir = fname.parent_path();
conffname = fname.string();
conffname = resolvePath(conffname);
std::error_code ec;
// llarp::LogDebug("Basedir: ", basedir);
if(basedir.string().empty())
{
if(!llarp_ensure_config(fname.string().c_str(), nullptr, overWrite,
asRouter))
return 1;
// relative path to config
// does this file exist?
if(genconfigOnly)
{
if(!llarp_ensure_config(conffname.c_str(), nullptr, overWrite,
asRouter))
return 1;
}
else
{
if(!fs::exists(fname, ec))
{
llarp::LogError("Config file not found ", conffname);
return 1;
}
}
}
else
{
std::error_code ec;
// absolute path to config
if(!fs::create_directories(basedir, ec))
{
if(ec)
@ -134,9 +169,22 @@ main(int argc, char *argv[])
return 1;
}
}
if(!llarp_ensure_config(fname.string().c_str(), basedir.string().c_str(),
overWrite, asRouter))
return 1;
if(genconfigOnly)
{
// find or create file
if(!llarp_ensure_config(conffname.c_str(), basedir.string().c_str(),
overWrite, asRouter))
return 1;
}
else
{
// does this file exist?
if(!fs::exists(conffname, ec))
{
llarp::LogError("Config file not found ", conffname);
return 1;
}
}
}
}
else
@ -149,6 +197,8 @@ main(int argc, char *argv[])
#endif
fs::path basepath = homedir / fs::path(".lokinet");
fs::path fpath = basepath / "lokinet.ini";
// I don't think this is necessary with this condition
// conffname = resolvePath(conffname);
llarp::LogDebug("Find or create ", basepath.string());
std::error_code ec;
@ -164,6 +214,7 @@ main(int argc, char *argv[])
}
}
// if using default INI file, we're create it even if you don't ask us too
if(!llarp_ensure_config(fpath.string().c_str(), basepath.string().c_str(),
overWrite, asRouter))
return 1;
@ -176,6 +227,7 @@ main(int argc, char *argv[])
}
// this is important, can downgrade from Info though
llarp::LogInfo("Running from: ", cpp17::filesystem::current_path());
llarp::LogInfo("Using config file: ", conffname);
ctx = llarp_main_init(conffname.c_str(), multiThreaded);
int code = 1;

@ -1,6 +1,7 @@
#include <llarp.hpp>
#include <llarp.h>
#include <crypto/crypto_libsodium.hpp>
#include <dht/context.hpp>
#include <dns/dotlokilookup.hpp>
#include <dnsd.hpp>
@ -97,8 +98,7 @@ namespace llarp
int
Context::LoadDatabase()
{
crypto = std::unique_ptr< llarp::Crypto >(
new llarp::Crypto{llarp::Crypto::sodium{}});
crypto = std::make_unique< sodium::CryptoLibSodium >();
nodedb = new llarp_nodedb(crypto.get(), router->disk);
if(!llarp_nodedb::ensure_dir(nodedb_dir.c_str()))

@ -19,8 +19,6 @@
namespace llarp
{
/// label functors
/// PKE(result, publickey, secretkey, nonce)
using path_dh_func = std::function< bool(
SharedSecret &, const PubKey &, const SecretKey &, const TunnelNonce &) >;
@ -29,88 +27,83 @@ namespace llarp
using transport_dh_func = std::function< bool(
SharedSecret &, const PubKey &, const SecretKey &, const TunnelNonce &) >;
/// SD/SE(buffer, key, nonce)
using sym_cipher_func = std::function< bool(
llarp_buffer_t, const SharedSecret &, const TunnelNonce &) >;
/// SD/SE(dst, src, key, nonce)
using sym_cipher_alt_func = std::function< bool(
llarp_buffer_t, llarp_buffer_t, const SharedSecret &, const byte_t *) >;
/// H(result, body)
using hash_func = std::function< bool(byte_t *, llarp_buffer_t) >;
/// SH(result, body)
using shorthash_func = std::function< bool(ShortHash &, llarp_buffer_t) >;
/// MDS(result, body, shared_secret)
using hmac_func =
std::function< bool(byte_t *, llarp_buffer_t, const SharedSecret &) >;
/// S(sig, secretkey, body)
using sign_func =
std::function< bool(Signature &, const SecretKey &, llarp_buffer_t) >;
/// V(pubkey, body, sig)
using verify_func =
std::function< bool(const PubKey &, llarp_buffer_t, const Signature &) >;
/// converts seed to secretkey
using seed_to_secret_func =
std::function< bool(llarp::SecretKey &, const llarp::IdentitySecret &) >;
/// library crypto configuration
struct Crypto
{
virtual ~Crypto() = 0;
/// xchacha symmetric cipher
sym_cipher_func xchacha20;
virtual bool
xchacha20(llarp_buffer_t, const SharedSecret &, const TunnelNonce &) = 0;
/// xchacha symmetric cipher (multibuffer)
sym_cipher_alt_func xchacha20_alt;
virtual bool
xchacha20_alt(llarp_buffer_t, llarp_buffer_t, const SharedSecret &,
const byte_t *) = 0;
/// path dh creator's side
path_dh_func dh_client;
virtual bool
dh_client(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &) = 0;
/// path dh relay side
path_dh_func dh_server;
virtual bool
dh_server(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &) = 0;
/// transport dh client side
transport_dh_func transport_dh_client;
virtual bool
transport_dh_client(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &) = 0;
/// transport dh server side
transport_dh_func transport_dh_server;
virtual bool
transport_dh_server(SharedSecret &, const PubKey &, const SecretKey &,
const TunnelNonce &) = 0;
/// blake2b 512 bit
hash_func hash;
virtual bool
hash(byte_t *, llarp_buffer_t) = 0;
/// blake2b 256 bit
shorthash_func shorthash;
virtual bool
shorthash(ShortHash &, llarp_buffer_t) = 0;
/// blake2s 256 bit hmac
hmac_func hmac;
virtual bool
hmac(byte_t *, llarp_buffer_t, const SharedSecret &) = 0;
/// ed25519 sign
sign_func sign;
virtual bool
sign(Signature &, const SecretKey &, llarp_buffer_t) = 0;
/// ed25519 verify
verify_func verify;
virtual bool
verify(const PubKey &, llarp_buffer_t, const Signature &) = 0;
/// seed to secretkey
seed_to_secret_func seed_to_secretkey;
virtual bool
seed_to_secretkey(llarp::SecretKey &, const llarp::IdentitySecret &) = 0;
/// randomize buffer
std::function< void(llarp_buffer_t) > randomize;
virtual void randomize(llarp_buffer_t) = 0;
/// randomizer memory
std::function< void(void *, size_t) > randbytes;
virtual void
randbytes(void *, size_t) = 0;
/// generate signing keypair
std::function< void(SecretKey &) > identity_keygen;
virtual void
identity_keygen(SecretKey &) = 0;
/// generate encryption keypair
std::function< void(SecretKey &) > encryption_keygen;
virtual void
encryption_keygen(SecretKey &) = 0;
/// generate post quantum encrytion key
std::function< void(PQKeyPair &) > pqe_keygen;
virtual void
pqe_keygen(PQKeyPair &) = 0;
/// post quantum decrypt (buffer, sharedkey_dst, sec)
std::function< bool(const PQCipherBlock &, SharedSecret &, const byte_t *) >
pqe_decrypt;
virtual bool
pqe_decrypt(const PQCipherBlock &, SharedSecret &, const byte_t *) = 0;
/// post quantum encrypt (buffer, sharedkey_dst, pub)
std::function< bool(PQCipherBlock &, SharedSecret &, const PQPubKey &) >
pqe_encrypt;
// Give a basic type tag for the constructor to pick libsodium
struct sodium
{
};
Crypto(Crypto::sodium tag);
virtual bool
pqe_encrypt(PQCipherBlock &, SharedSecret &, const PQPubKey &) = 0;
};
inline Crypto::~Crypto()
{
}
/// return random 64bit unsigned interger
uint64_t
randint();

@ -1,4 +1,4 @@
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign.h>
@ -18,24 +18,6 @@ namespace llarp
{
namespace sodium
{
static bool
xchacha20(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;
}
static bool
xchacha20_alt(llarp_buffer_t out, 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;
}
static bool
dh(llarp::SharedSecret &out, const PubKey &client_pk,
const PubKey &server_pk, const uint8_t *themPub, const SecretKey &usSec)
@ -44,7 +26,9 @@ namespace llarp
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);
@ -54,8 +38,8 @@ namespace llarp
}
static bool
dh_client(llarp::SharedSecret &shared, const PubKey &pk,
const SecretKey &sk, const TunnelNonce &n)
dh_client_priv(llarp::SharedSecret &shared, const PubKey &pk,
const SecretKey &sk, const TunnelNonce &n)
{
llarp::SharedSecret dh_result;
@ -70,8 +54,8 @@ namespace llarp
}
static bool
dh_server(llarp::SharedSecret &shared, const PubKey &pk,
const SecretKey &sk, const TunnelNonce &n)
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))
@ -84,113 +68,184 @@ namespace llarp
return false;
}
static bool
hash(uint8_t *result, llarp_buffer_t buff)
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;
this->randbytes(&seed, sizeof(seed));
srand(seed);
}
bool
CryptoLibSodium::xchacha20(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(llarp_buffer_t out, 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::hash(uint8_t *result, llarp_buffer_t buff)
{
return crypto_generichash_blake2b(result, HASHSIZE, buff.base, buff.sz,
nullptr, 0)
!= -1;
}
static bool
shorthash(ShortHash &result, llarp_buffer_t buff)
bool
CryptoLibSodium::shorthash(ShortHash &result, llarp_buffer_t buff)
{
return crypto_generichash_blake2b(result.data(), ShortHash::SIZE,
buff.base, buff.sz, nullptr, 0)
!= -1;
}
static bool
hmac(byte_t *result, llarp_buffer_t buff, const SharedSecret &secret)
bool
CryptoLibSodium::hmac(byte_t *result, llarp_buffer_t buff,
const SharedSecret &secret)
{
return crypto_generichash_blake2b(result, HMACSIZE, buff.base, buff.sz,
secret.data(), HMACSECSIZE)
!= -1;
}
static bool
sign(Signature &result, const SecretKey &secret, llarp_buffer_t buff)
bool
CryptoLibSodium::sign(Signature &result, const SecretKey &secret,
llarp_buffer_t buff)
{
int rc = crypto_sign_detached(result.data(), nullptr, buff.base, buff.sz,
secret.data());
return rc != -1;
}
static bool
verify(const PubKey &pub, llarp_buffer_t buff, const Signature &sig)
bool
CryptoLibSodium::verify(const PubKey &pub, llarp_buffer_t buff,
const Signature &sig)
{
int rc = crypto_sign_verify_detached(sig.data(), buff.base, buff.sz,
pub.data());
return rc != -1;
}
static bool
seed_to_secretkey(llarp::SecretKey &secret,
const llarp::IdentitySecret &seed)
bool
CryptoLibSodium::seed_to_secretkey(llarp::SecretKey &secret,
const llarp::IdentitySecret &seed)
{
byte_t pk[crypto_sign_ed25519_PUBLICKEYBYTES];
return crypto_sign_ed25519_seed_keypair(pk, secret.data(), seed.data())
!= -1;
}
static void
randomize(llarp_buffer_t buff)
void
CryptoLibSodium::randomize(llarp_buffer_t buff)
{
randombytes((unsigned char *)buff.base, buff.sz);
}
static inline void
randbytes(void *ptr, size_t sz)
void
CryptoLibSodium::randbytes(void *ptr, size_t sz)
{
randombytes((unsigned char *)ptr, sz);
}
static void
sigkeygen(llarp::SecretKey &keys)
void
CryptoLibSodium::identity_keygen(llarp::SecretKey &keys)
{
byte_t *d = keys.data();
crypto_sign_keypair(d + 32, d);
}
static void
enckeygen(llarp::SecretKey &keys)
void
CryptoLibSodium::encryption_keygen(llarp::SecretKey &keys)
{
auto d = keys.data();
randombytes(d, 32);
crypto_scalarmult_curve25519_base(d + 32, d);
}
} // namespace sodium
const byte_t *
seckey_topublic(const SecretKey &sec)
{
return sec.data() + 32;
}
namespace pq
{
bool
encrypt(PQCipherBlock &ciphertext, SharedSecret &sharedkey,
const PQPubKey &pubkey)
CryptoLibSodium::pqe_encrypt(PQCipherBlock &ciphertext,
SharedSecret &sharedkey,
const PQPubKey &pubkey)
{
return crypto_kem_enc(ciphertext.data(), sharedkey.data(), pubkey.data())
!= -1;
}
bool
decrypt(const PQCipherBlock &ciphertext, SharedSecret &sharedkey,
const byte_t *secretkey)
CryptoLibSodium::pqe_decrypt(const PQCipherBlock &ciphertext,
SharedSecret &sharedkey,
const byte_t *secretkey)
{
return crypto_kem_dec(sharedkey.data(), ciphertext.data(), secretkey)
!= -1;
}
void
keygen(PQKeyPair &keypair)
CryptoLibSodium::pqe_keygen(PQKeyPair &keypair)
{
auto d = keypair.data();
crypto_kem_keypair(d + PQ_SECRETKEYSIZE, d);
}
} // namespace pq
} // namespace sodium
const byte_t *
seckey_topublic(const SecretKey &sec)
{
return sec.data() + 32;
}
const byte_t *
pq_keypair_to_public(const PQKeyPair &k)
@ -204,40 +259,6 @@ namespace llarp
return k.data();
}
Crypto::Crypto(Crypto::sodium tag)
{
(void)tag;
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);
this->xchacha20 = llarp::sodium::xchacha20;
this->xchacha20_alt = llarp::sodium::xchacha20_alt;
this->dh_client = llarp::sodium::dh_client;
this->dh_server = llarp::sodium::dh_server;
this->transport_dh_client = llarp::sodium::dh_client;
this->transport_dh_server = llarp::sodium::dh_server;
this->hash = llarp::sodium::hash;
this->shorthash = llarp::sodium::shorthash;
this->hmac = llarp::sodium::hmac;
this->sign = llarp::sodium::sign;
this->verify = llarp::sodium::verify;
this->randomize = llarp::sodium::randomize;
this->randbytes = llarp::sodium::randbytes;
this->identity_keygen = llarp::sodium::sigkeygen;
this->encryption_keygen = llarp::sodium::enckeygen;
this->seed_to_secretkey = llarp::sodium::seed_to_secretkey;
this->pqe_encrypt = llarp::pq::encrypt;
this->pqe_decrypt = llarp::pq::decrypt;
this->pqe_keygen = llarp::pq::keygen;
int seed = 0;
this->randbytes(&seed, sizeof(seed));
srand(seed);
}
uint64_t
randint()
{

@ -0,0 +1,89 @@
#ifndef LLARP_CRYPTO_LIBSODIUM_HPP
#define LLARP_CRYPTO_LIBSODIUM_HPP
#include <crypto/crypto.hpp>
namespace llarp
{
namespace sodium
{
struct CryptoLibSodium final : public Crypto
{
CryptoLibSodium();
~CryptoLibSodium()
{
}
/// xchacha symmetric cipher
bool
xchacha20(llarp_buffer_t, const SharedSecret &,
const TunnelNonce &) override;
/// xchacha symmetric cipher (multibuffer)
bool
xchacha20_alt(llarp_buffer_t, 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 512 bit
bool
hash(byte_t *, llarp_buffer_t) override;
/// blake2b 256 bit
bool
shorthash(ShortHash &, llarp_buffer_t) override;
/// blake2s 256 bit hmac
bool
hmac(byte_t *, llarp_buffer_t, const SharedSecret &) override;
/// ed25519 sign
bool
sign(Signature &, const SecretKey &, llarp_buffer_t) override;
/// ed25519 verify
bool
verify(const PubKey &, llarp_buffer_t, const Signature &) override;
/// seed to secretkey
bool
seed_to_secretkey(llarp::SecretKey &,
const llarp::IdentitySecret &) override;
/// randomize buffer
void randomize(llarp_buffer_t) override;
/// randomizer memory
void
randbytes(void *, 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;
};
} // namespace sodium
} // namespace llarp
#endif

@ -24,10 +24,6 @@ namespace llarp
SharedSecret shared;
auto DH = crypto->dh_client;
auto Encrypt = crypto->xchacha20;
auto MDS = crypto->hmac;
llarp_buffer_t buf;
buf.base = body;
buf.cur = buf.base;
@ -40,14 +36,14 @@ namespace llarp
TunnelNonce nonce(noncePtr);
// derive shared key
if(!DH(shared, otherPubkey, ourSecretKey, nonce))
if(!crypto->dh_client(shared, otherPubkey, ourSecretKey, nonce))
{
llarp::LogError("DH failed");
return false;
}
// encrypt body
if(!Encrypt(buf, shared, nonce))
if(!crypto->xchacha20(buf, shared, nonce))
{
llarp::LogError("encrypt failed");
return false;
@ -58,7 +54,7 @@ namespace llarp
buf.cur = buf.base;
buf.sz = size() - SHORTHASHSIZE;
if(!MDS(hash, buf, shared))
if(!crypto->hmac(hash, buf, shared))
{
llarp::LogError("Failed to generate message auth");
return false;
@ -82,14 +78,10 @@ namespace llarp
TunnelNonce nonce(noncePtr);
PubKey otherPubkey(noncePtr + TUNNONCESIZE);
// use dh_server because we are not the creator of this message
auto DH = crypto->dh_server;
auto Decrypt = crypto->xchacha20;
auto MDS = crypto->hmac;
SharedSecret shared;
if(!DH(shared, otherPubkey, ourSecretKey, nonce))
// use dh_server because we are not the creator of this message
if(!crypto->dh_server(shared, otherPubkey, ourSecretKey, nonce))
{
llarp::LogError("DH failed");
return false;
@ -101,7 +93,7 @@ namespace llarp
buf.sz = size() - SHORTHASHSIZE;
ShortHash digest;
if(!MDS(digest.data(), buf, shared))
if(!crypto->hmac(digest.data(), buf, shared))
{
llarp::LogError("Digest failed");
return false;
@ -117,7 +109,7 @@ namespace llarp
buf.cur = body;
buf.sz = size() - EncryptedFrameOverheadSize;
if(!Decrypt(buf, shared, nonce))
if(!crypto->xchacha20(buf, shared, nonce))
{
llarp::LogError("decrypt failed");
return false;

@ -58,6 +58,24 @@ namespace llarp
}
};
inline bool
operator==(const PubKey &lhs, const PubKey &rhs)
{
return lhs.as_array() == rhs.as_array();
}
inline bool
operator==(const PubKey &lhs, const RouterID &rhs)
{
return lhs.as_array() == rhs.as_array();
}
inline bool
operator==(const RouterID &lhs, const PubKey &rhs)
{
return lhs.as_array() == rhs.as_array();
}
struct SecretKey final : public AlignedBuffer< SECKEYSIZE >
{
SecretKey() : AlignedBuffer< SECKEYSIZE >(){};

@ -1,10 +1,18 @@
#include <dht/context.hpp>
#include <dht/explorenetworkjob.hpp>
#include <dht/localrouterlookup.hpp>
#include <dht/localserviceaddresslookup.hpp>
#include <dht/localtaglookup.hpp>
#include <dht/messages/findrouter.hpp>
#include <dht/messages/gotintro.hpp>
#include <dht/messages/gotrouter.hpp>
#include <dht/messages/pubintro.hpp>
#include <dht/node.hpp>
#include <dht/publishservicejob.hpp>
#include <dht/recursiverouterlookup.hpp>
#include <dht/serviceaddresslookup.hpp>
#include <dht/taglookup.hpp>
#include <messages/dht.hpp>
#include <messages/dht_immediate.hpp>
#include <router/router.hpp>
@ -15,18 +23,11 @@ namespace llarp
{
namespace dht
{
Context::Context()
{
randombytes((byte_t *)&ids, sizeof(uint64_t));
allowTransit = false;
}
AbstractContext::~AbstractContext() {}
Context::~Context()
Context::Context() : router(nullptr), allowTransit(false)
{
if(nodes)
delete nodes;
if(services)
delete services;
randombytes((byte_t *)&ids, sizeof(uint64_t));
}
void
@ -45,53 +46,6 @@ namespace llarp
llarp::LogError("failed to select random nodes for exploration");
}
struct ExploreNetworkJob : public TX< RouterID, RouterID >
{
ExploreNetworkJob(const RouterID &peer, Context *ctx)
: TX< RouterID, RouterID >(TXOwner{}, peer, ctx)
{
}
bool
Validate(const RouterID &) const override
{
// TODO: check with lokid
return true;
}
void
Start(const TXOwner &peer) override
{
parent->DHTSendTo(peer.node.as_array(),
new FindRouterMessage(peer.txid));
}
bool
GetNextPeer(Key_t &, const std::set< Key_t > &) override
{
return false;
}
void
DoNextRequest(const Key_t &) override
{
}
void
SendReply() override
{
llarp::LogInfo("got ", valuesFound.size(), " routers from exploration");
for(const auto &pk : valuesFound)
{
// lookup router
parent->LookupRouter(
pk,
std::bind(&llarp::Router::HandleDHTLookupForExplore,
parent->router, pk, std::placeholders::_1));
}
}
};
void
Context::ExploreNetworkVia(const Key_t &askpeer)
{
@ -272,8 +226,8 @@ namespace llarp
{
router = r;
ourKey = us;
nodes = new Bucket< RCNode >(ourKey, llarp::randint);
services = new Bucket< ISNode >(ourKey, llarp::randint);
nodes = std::make_unique< Bucket< RCNode > >(ourKey, llarp::randint);
services = std::make_unique< Bucket< ISNode > >(ourKey, llarp::randint);
llarp::LogDebug("initialize dht with key ", ourKey);
// start exploring
@ -308,7 +262,7 @@ namespace llarp
llarp::routing::DHTMessage reply;
if(!msg->HandleMessage(router->dht, reply.M))
return false;
if(reply.M.size())
if(!reply.M.empty())
{
auto path = router->paths.GetByUpstream(router->pubkey(), id);
return path && path->SendRoutingMessage(&reply, router);
@ -316,112 +270,6 @@ namespace llarp
return true;
}
struct ServiceAddressLookup
: public TX< service::Address, service::IntroSet >
{
IntroSetLookupHandler handleResult;
uint64_t R;
ServiceAddressLookup(const TXOwner &asker, const service::Address &addr,
Context *ctx, uint64_t r,
IntroSetLookupHandler handler)
: TX< service::Address, service::IntroSet >(asker, addr, ctx)
, handleResult(handler)
, R(r)
{
peersAsked.insert(ctx->OurKey());
}
bool
Validate(const service::IntroSet &value) const override
{
if(!value.Verify(parent->Crypto(), parent->Now()))
{
llarp::LogWarn("Got invalid introset from service lookup");
return false;
}
if(value.A.Addr() != target)
{
llarp::LogWarn("got introset with wrong target from service lookup");
return false;
}
return true;
}
bool
GetNextPeer(Key_t &next, const std::set< Key_t > &exclude) override
{
Key_t k = target.ToKey();
return parent->nodes->FindCloseExcluding(k, next, exclude);
}
void
Start(const TXOwner &peer) override
{
parent->DHTSendTo(peer.node.as_array(),
new FindIntroMessage(peer.txid, target, R));
}
void
DoNextRequest(const Key_t &ask) override
{
if(R)
parent->LookupIntroSetRecursive(target, whoasked.node, whoasked.txid,
ask, R - 1);
else
parent->LookupIntroSetIterative(target, whoasked.node, whoasked.txid,
ask);
}
virtual void
SendReply() override
{
if(handleResult)
handleResult(valuesFound);
parent->DHTSendTo(whoasked.node.as_array(),
new GotIntroMessage(valuesFound, whoasked.txid));
}
};
struct LocalServiceAddressLookup : public ServiceAddressLookup
{
PathID_t localPath;
LocalServiceAddressLookup(const PathID_t &pathid, uint64_t txid,
const service::Address &addr, Context *ctx,
__attribute__((unused)) const Key_t &askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 5,
nullptr)
, localPath(pathid)
{
}
void
SendReply() override
{
auto path = parent->router->paths.GetByUpstream(
parent->OurKey().as_array(), localPath);
if(!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::DHTMessage msg;
msg.M.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if(!path->SendRoutingMessage(&msg, parent->router))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
};
void
Context::LookupIntroSetForPath(const service::Address &addr, uint64_t txid,
const llarp::PathID_t &path,
@ -434,62 +282,6 @@ namespace llarp
new LocalServiceAddressLookup(path, txid, addr, this, askpeer));
}
struct PublishServiceJob : public TX< service::Address, service::IntroSet >
{
uint64_t S;
std::set< Key_t > dontTell;
service::IntroSet I;
PublishServiceJob(const TXOwner &asker, const service::IntroSet &introset,
Context *ctx, uint64_t s,
const std::set< Key_t > &exclude)
: TX< service::Address, service::IntroSet >(asker, introset.A.Addr(),
ctx)
, S(s)
, dontTell(exclude)
, I(introset)
{
}
bool
Validate(const service::IntroSet &introset) const override
{
if(I.A != introset.A)
{
llarp::LogWarn(
"publish introset acknowledgement acked a different service");
return false;
}
return true;
}
void
Start(const TXOwner &peer) override
{
std::vector< Key_t > exclude;
for(const auto &router : dontTell)
exclude.push_back(router);
parent->DHTSendTo(peer.node.as_array(),
new PublishIntroMessage(I, peer.txid, S, exclude));
}
bool
GetNextPeer(Key_t &, const std::set< Key_t > &) override
{
return false;
}
void
DoNextRequest(const Key_t &) override
{
}
void
SendReply() override
{
// don't need this
}
};
void
Context::PropagateIntroSetTo(const Key_t &from, uint64_t txid,
const service::IntroSet &introset,
@ -508,7 +300,7 @@ namespace llarp
Context::LookupIntroSetRecursive(const service::Address &addr,
const Key_t &whoasked, uint64_t txid,
const Key_t &askpeer, uint64_t R,
IntroSetLookupHandler handler)
service::IntroSetLookupHandler handler)
{
TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids);
@ -521,7 +313,7 @@ namespace llarp
Context::LookupIntroSetIterative(const service::Address &addr,
const Key_t &whoasked, uint64_t txid,
const Key_t &askpeer,
IntroSetLookupHandler handler)
service::IntroSetLookupHandler handler)
{
TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids);
@ -530,76 +322,6 @@ namespace llarp
new ServiceAddressLookup(asker, addr, this, 0, handler));
}
struct TagLookup : public TX< service::Tag, service::IntroSet >
{
uint64_t R;
TagLookup(const TXOwner &asker, const service::Tag &tag, Context *ctx,
uint64_t r)
: TX< service::Tag, service::IntroSet >(asker, tag, ctx), R(r)
{
}
bool
Validate(const service::IntroSet &introset) const override
{
if(!introset.Verify(parent->Crypto(), parent->Now()))
{
llarp::LogWarn("got invalid introset from tag lookup");
return false;
}
if(introset.topic != target)
{
llarp::LogWarn("got introset with missmatched topic in tag lookup");
return false;
}
return true;
}
void
Start(const TXOwner &peer) override
{
parent->DHTSendTo(peer.node.as_array(),
new FindIntroMessage(target, peer.txid, R));
}
bool
GetNextPeer(Key_t &, const std::set< Key_t > &) override
{
return false;
}
void
DoNextRequest(const Key_t &) override
{
}
void
SendReply() override
{
std::set< service::IntroSet > found;
for(const auto &remoteTag : valuesFound)
{
found.insert(remoteTag);
}
// collect our local values if we haven't hit a limit
if(found.size() < 2)
{
for(const auto &localTag :
parent->FindRandomIntroSetsWithTagExcluding(target, 1, found))
{
found.insert(localTag);
}
}
std::vector< service::IntroSet > values;
for(const auto &introset : found)
{
values.push_back(introset);
}
parent->DHTSendTo(whoasked.node.as_array(),
new GotIntroMessage(values, whoasked.txid));
}
};
void
Context::LookupTagRecursive(const service::Tag &tag, const Key_t &whoasked,
uint64_t whoaskedTX, const Key_t &askpeer,
@ -613,42 +335,6 @@ namespace llarp
" R=", R);
}
struct LocalTagLookup : public TagLookup
{
PathID_t localPath;
LocalTagLookup(const PathID_t &path, uint64_t txid,
const service::Tag &target, Context *ctx)
: TagLookup(TXOwner{ctx->OurKey(), txid}, target, ctx, 0)
, localPath(path)
{
}
void
SendReply() override
{
auto path = parent->router->paths.GetByUpstream(
parent->OurKey().as_array(), localPath);
if(!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::DHTMessage msg;
msg.M.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if(!path->SendRoutingMessage(&msg, parent->router))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
};
void
Context::LookupTagForPath(const service::Tag &tag, uint64_t txid,
const llarp::PathID_t &path, const Key_t &askpeer)
@ -699,101 +385,6 @@ namespace llarp
return true;
}
struct RecursiveRouterLookup : public TX< RouterID, RouterContact >
{
RouterLookupHandler resultHandler;
RecursiveRouterLookup(const TXOwner &whoasked, const RouterID &target,
Context *ctx, RouterLookupHandler result)
: TX< RouterID, RouterContact >(whoasked, target, ctx)
, resultHandler(result)
{
peersAsked.insert(ctx->OurKey());
}
bool
Validate(const RouterContact &rc) const override
{
if(!rc.Verify(parent->Crypto(), parent->Now()))
{
llarp::LogWarn("rc from lookup result is invalid");
return false;
}
return true;
}
bool
GetNextPeer(Key_t &, const std::set< Key_t > &) override
{
return false;
}
void
DoNextRequest(const Key_t &) override
{
}
void
Start(const TXOwner &peer) override
{
parent->DHTSendTo(peer.node.as_array(),
new FindRouterMessage(peer.txid, target));
}
virtual void
SendReply() override
{
if(resultHandler)
{
resultHandler(valuesFound);
}
else
{
parent->DHTSendTo(
whoasked.node.as_array(),
new GotRouterMessage({}, whoasked.txid, valuesFound, false));
}
}
};
struct LocalRouterLookup : public RecursiveRouterLookup
{
PathID_t localPath;
LocalRouterLookup(const PathID_t &path, uint64_t txid,
const RouterID &target, Context *ctx)
: RecursiveRouterLookup(TXOwner{ctx->OurKey(), txid}, target, ctx,
nullptr)
, localPath(path)
{
}
void
SendReply() override
{
auto path = parent->router->paths.GetByUpstream(
parent->OurKey().as_array(), localPath);
if(!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::DHTMessage msg;
msg.M.emplace_back(new GotRouterMessage(parent->OurKey(), whoasked.txid,
valuesFound, true));
if(!path->SendRoutingMessage(&msg, parent->router))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
};
void
Context::LookupRouterForPath(const RouterID &target, uint64_t txid,
const llarp::PathID_t &path,
@ -824,13 +415,13 @@ namespace llarp
}
llarp::Crypto *
Context::Crypto()
Context::Crypto() const
{
return &router->crypto;
return router->crypto.get();
}
llarp_time_t
Context::Now()
Context::Now() const
{
return llarp_ev_loop_time_now_ms(router->netloop);
}

@ -1,5 +1,5 @@
#ifndef LLARP_DHT_CONTEXT_HPP
#define LLARP_DHT_CONTEXT_HPP
#ifndef LLARP_DHT_CONTEXT
#define LLARP_DHT_CONTEXT
#include <dht/bucket.hpp>
#include <dht/dht.h>
@ -7,6 +7,8 @@
#include <dht/message.hpp>
#include <dht/messages/findintro.hpp>
#include <dht/node.hpp>
#include <dht/tx.hpp>
#include <dht/txholder.hpp>
#include <dht/txowner.hpp>
#include <service/IntroSet.hpp>
#include <util/time.hpp>
@ -19,96 +21,61 @@ namespace llarp
namespace dht
{
struct Context;
template < typename K, typename V >
struct TX
struct AbstractContext
{
TX(const TXOwner& asker, const K& k, Context* p)
: target(k), whoasked(asker)
{
parent = p;
}
virtual ~TX(){};
K target;
Context* parent;
std::set< Key_t > peersAsked;
std::vector< V > valuesFound;
TXOwner whoasked;
virtual ~AbstractContext() = 0;
virtual bool
Validate(const V& value) const = 0;
LookupRouter(const RouterID& target, RouterLookupHandler result) = 0;
void
OnFound(const Key_t askedPeer, const V& value)
{
peersAsked.insert(askedPeer);
if(Validate(value))
valuesFound.push_back(value);
}
/// on behalf of whoasked request introset for target from dht router with
/// key askpeer
virtual void
LookupIntroSetRecursive(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler result = nullptr) = 0;
virtual void
Start(const TXOwner& peer) = 0;
LookupIntroSetIterative(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer,
service::IntroSetLookupHandler result = nullptr) = 0;
virtual bool
GetNextPeer(Key_t& next, const std::set< Key_t >& exclude) = 0;
virtual std::set< service::IntroSet >
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {}) = 0;
virtual void
DoNextRequest(const Key_t& peer) = 0;
DHTSendTo(const RouterID& peer, IMessage* msg, bool keepalive = true) = 0;
/// return true if we want to persist this tx
bool
AskNextPeer(const Key_t& prevPeer, const std::unique_ptr< Key_t >& next)
{
peersAsked.insert(prevPeer);
Key_t peer;
if(next)
{
// explicit next peer provided
peer = *next;
}
else if(!GetNextPeer(peer, peersAsked))
{
// no more peers
llarp::LogInfo("no more peers for request asking for", target);
return false;
}
virtual llarp_time_t
Now() const = 0;
const Key_t targetKey{target};
if((prevPeer ^ targetKey) < (peer ^ targetKey))
{
// next peer is not closer
llarp::LogInfo("next peer ", peer, " is not closer to ", target,
" than ", prevPeer);
return false;
}
else
{
peersAsked.insert(peer);
}
DoNextRequest(peer);
return true;
}
virtual llarp::Crypto*
Crypto() const = 0;
virtual void
SendReply() = 0;
};
virtual llarp::Router*
GetRouter() const = 0;
using IntroSetLookupHandler =
std::function< void(const std::vector< service::IntroSet >&) >;
virtual const Key_t&
OurKey() const = 0;
using RouterLookupHandler =
std::function< void(const std::vector< RouterContact >&) >;
virtual Bucket< RCNode >* Nodes() const = 0;
};
struct Context
struct Context final : public AbstractContext
{
Context();
~Context();
~Context()
{
}
llarp::Crypto*
Crypto();
Crypto() const override;
/// on behalf of whoasked request introset for target from dht router with
/// key askpeer
@ -116,13 +83,13 @@ namespace llarp
LookupIntroSetRecursive(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R,
IntroSetLookupHandler result = nullptr);
service::IntroSetLookupHandler result = nullptr) override;
void
LookupIntroSetIterative(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer,
IntroSetLookupHandler result = nullptr);
service::IntroSetLookupHandler result = nullptr) override;
/// on behalf of whoasked request router with public key target from dht
/// router with key askpeer
@ -132,11 +99,13 @@ namespace llarp
RouterLookupHandler result = nullptr);
bool
LookupRouter(const RouterID& target, RouterLookupHandler result)
LookupRouter(const RouterID& target, RouterLookupHandler result) override
{
Key_t askpeer;
if(!nodes->FindClosest(Key_t(target), askpeer))
{
return false;
}
LookupRouterRecursive(target, OurKey(), 0, askpeer, result);
return true;
}
@ -172,7 +141,7 @@ namespace llarp
/// send a dht message to peer, if keepalive is true then keep the session
/// with that peer alive for 10 seconds
void
DHTSendTo(const RouterID& peer, IMessage* msg, bool keepalive = true);
DHTSendTo(const RouterID& peer, IMessage* msg, bool keepalive = true) override;
/// get routers closest to target excluding requester
bool
@ -183,7 +152,7 @@ namespace llarp
std::set< service::IntroSet >
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {});
const std::set< service::IntroSet >& excludes = {}) override;
/// handle rc lookup from requester for target
void
@ -221,143 +190,24 @@ namespace llarp
void
Explore(size_t N = 3);
llarp::Router* router = nullptr;
llarp::Router* router;
// for router contacts
Bucket< RCNode >* nodes = nullptr;
std::unique_ptr< Bucket< RCNode > > nodes;
// for introduction sets
Bucket< ISNode >* services = nullptr;
bool allowTransit = false;
std::unique_ptr< Bucket< ISNode > > services;
bool allowTransit;
Bucket< RCNode >* Nodes() const override { return nodes.get(); }
const Key_t&
OurKey() const
OurKey() const override
{
return ourKey;
}
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS = 5000UL >
struct TXHolder
{
// tx who are waiting for a reply for each key
std::unordered_multimap< K, TXOwner, K_Hash > waiting;
// tx timesouts by key
std::unordered_map< K, llarp_time_t, K_Hash > timeouts;
// maps remote peer with tx to handle reply from them
std::unordered_map< TXOwner, std::unique_ptr< TX< K, V > >,
TXOwner::Hash >
tx;
const TX< K, V >*
GetPendingLookupFrom(const TXOwner& owner) const
{
auto itr = tx.find(owner);
if(itr == tx.end())
return nullptr;
else
return itr->second.get();
}
bool
HasLookupFor(const K& target) const
{
return timeouts.find(target) != timeouts.end();
}
bool
HasPendingLookupFrom(const TXOwner& owner) const
{
return GetPendingLookupFrom(owner) != nullptr;
}
void
NewTX(const TXOwner& askpeer, const TXOwner& whoasked, const K& k,
TX< K, V >* t)
{
(void)whoasked;
tx.emplace(askpeer, std::unique_ptr< TX< K, V > >(t));
auto count = waiting.count(k);
waiting.insert(std::make_pair(k, askpeer));
auto itr = timeouts.find(k);
if(itr == timeouts.end())
{
timeouts.insert(
std::make_pair(k, time_now_ms() + requestTimeoutMS));
}
if(count == 0)
t->Start(askpeer);
}
/// mark tx as not fond
void
NotFound(const TXOwner& from, const std::unique_ptr< Key_t >& next)
{
bool sendReply = true;
auto txitr = tx.find(from);
if(txitr == tx.end())
return;
// ask for next peer
if(txitr->second->AskNextPeer(from.node, next))
sendReply = false;
llarp::LogWarn("Target key ", txitr->second->target);
Inform(from, txitr->second->target, {}, sendReply, sendReply);
}
void
Found(const TXOwner& from, const K& k, const std::vector< V >& values)
{
Inform(from, k, values, true);
}
/// inform all watches for key of values found
void
Inform(TXOwner from, K key, std::vector< V > values,
bool sendreply = false, bool removeTimeouts = true)
{
auto range = waiting.equal_range(key);
auto itr = range.first;
while(itr != range.second)
{
auto txitr = tx.find(itr->second);
if(txitr != tx.end())
{
for(const auto& value : values)
txitr->second->OnFound(from.node, value);
if(sendreply)
{
txitr->second->SendReply();
tx.erase(txitr);
}
}
++itr;
}
if(sendreply)
waiting.erase(key);
if(removeTimeouts)
timeouts.erase(key);
}
void
Expire(llarp_time_t now)
{
auto itr = timeouts.begin();
while(itr != timeouts.end())
{
if(now > itr->second && now - itr->second >= requestTimeoutMS)
{
Inform(TXOwner{}, itr->first, {}, true, false);
itr = timeouts.erase(itr);
}
else
++itr;
}
}
};
llarp::Router*
GetRouter() const override { return router; }
TXHolder< service::Address, service::IntroSet, service::Address::Hash >
pendingIntrosetLookups;
@ -376,7 +226,7 @@ namespace llarp
}
llarp_time_t
Now();
Now() const override;
void
ExploreNetworkVia(const Key_t& peer);

@ -0,0 +1,32 @@
#include <dht/explorenetworkjob.hpp>
#include <dht/context.hpp>
#include <dht/messages/findrouter.hpp>
#include <router/router.hpp>
namespace llarp
{
namespace dht
{
void
ExploreNetworkJob::Start(const TXOwner &peer)
{
parent->DHTSendTo(peer.node.as_array(), new FindRouterMessage(peer.txid));
}
void
ExploreNetworkJob::SendReply()
{
llarp::LogInfo("got ", valuesFound.size(), " routers from exploration");
auto router = parent->GetRouter();
using std::placeholders::_1;
for(const auto &pk : valuesFound)
{
// lookup router
parent->LookupRouter(
pk, std::bind(&Router::HandleDHTLookupForExplore, router, pk, _1));
}
}
} // namespace dht
} // namespace llarp

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

@ -0,0 +1,46 @@
#include <dht/localrouterlookup.hpp>
#include <dht/context.hpp>
#include <dht/messages/gotrouter.hpp>
#include <messages/dht.hpp>
#include <router/router.hpp>
#include <util/logger.hpp>
namespace llarp
{
namespace dht
{
LocalRouterLookup::LocalRouterLookup(const PathID_t &path, uint64_t txid,
const RouterID &target, AbstractContext *ctx)
: RecursiveRouterLookup(TXOwner{ctx->OurKey(), txid}, target, ctx,
nullptr)
, localPath(path)
{
}
void
LocalRouterLookup::SendReply()
{
auto path = parent->GetRouter()->paths.GetByUpstream(
parent->OurKey().as_array(), localPath);
if(!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::DHTMessage msg;
msg.M.emplace_back(new GotRouterMessage(parent->OurKey(), whoasked.txid,
valuesFound, true));
if(!path->SendRoutingMessage(&msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace dht
} // namespace llarp

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

@ -0,0 +1,45 @@
#include <dht/localserviceaddresslookup.hpp>
#include <dht/context.hpp>
#include <dht/messages/gotintro.hpp>
#include <router/router.hpp>
#include <util/logger.hpp>
namespace llarp
{
namespace dht
{
LocalServiceAddressLookup::LocalServiceAddressLookup(
const PathID_t &pathid, uint64_t txid, const service::Address &addr,
AbstractContext *ctx, __attribute__((unused)) const Key_t &askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 5,
nullptr)
, localPath(pathid)
{
}
void
LocalServiceAddressLookup::SendReply()
{
auto path = parent->GetRouter()->paths.GetByUpstream(
parent->OurKey().as_array(), localPath);
if(!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::DHTMessage msg;
msg.M.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if(!path->SendRoutingMessage(&msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace dht
} // namespace llarp

@ -0,0 +1,27 @@
#ifndef LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
#define LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
#include <dht/serviceaddresslookup.hpp>
#include <path/path_types.hpp>
namespace llarp
{
namespace dht
{
struct LocalServiceAddressLookup : public ServiceAddressLookup
{
PathID_t localPath;
LocalServiceAddressLookup(const PathID_t &pathid, uint64_t txid,
const service::Address &addr, AbstractContext *ctx,
__attribute__((unused)) const Key_t &askpeer);
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

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

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

@ -25,7 +25,7 @@ namespace llarp
std::vector< std::unique_ptr< IMessage > > &replies) const
{
auto &dht = ctx->impl;
auto crypto = &dht.router->crypto;
auto crypto = dht.router->crypto.get();
for(const auto &introset : I)
{

@ -52,14 +52,18 @@ namespace llarp
return false;
}
auto &dht = ctx->impl;
if(!I.Verify(&dht.router->crypto, now))
if(!I.Verify(dht.router->crypto.get(), now))
{
llarp::LogWarn("invalid introset: ", I);
// don't propogate or store
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
if(I.W && !I.W->IsValid(dht.router->crypto.shorthash, now))
using namespace std::placeholders;
shorthash_func shorthash =
std::bind(&Crypto::shorthash, dht.router->crypto.get(), _1, _2);
if(I.W && !I.W->IsValid(shorthash, now))
{
llarp::LogWarn("proof of work not good enough for IntroSet");
// don't propogate or store

@ -41,9 +41,8 @@ namespace llarp
ID.Zero();
}
ISNode(const service::IntroSet& other)
ISNode(const service::IntroSet& other) : introset(other)
{
introset = other;
introset.A.CalculateAddress(ID.as_array());
}

@ -0,0 +1,46 @@
#include <dht/publishservicejob.hpp>
#include <dht/context.hpp>
#include <dht/messages/pubintro.hpp>
namespace llarp
{
namespace dht
{
PublishServiceJob::PublishServiceJob(const TXOwner &asker,
const service::IntroSet &introset,
AbstractContext *ctx, uint64_t s,
const std::set< Key_t > &exclude)
: TX< service::Address, service::IntroSet >(asker, introset.A.Addr(),
ctx)
, S(s)
, dontTell(exclude)
, I(introset)
{
}
bool
PublishServiceJob::Validate(const service::IntroSet &introset) const
{
if(I.A != introset.A)
{
llarp::LogWarn(
"publish introset acknowledgement acked a different service");
return false;
}
return true;
}
void
PublishServiceJob::Start(const TXOwner &peer)
{
std::vector< Key_t > exclude;
for(const auto &router : dontTell)
{
exclude.push_back(router);
}
parent->DHTSendTo(peer.node.as_array(),
new PublishIntroMessage(I, peer.txid, S, exclude));
}
} // namespace dht
} // namespace llarp

@ -0,0 +1,51 @@
#ifndef LLARP_DHT_PUBLISHSERVICEJOB
#define LLARP_DHT_PUBLISHSERVICEJOB
#include <dht/tx.hpp>
#include <dht/txowner.hpp>
#include <service/address.hpp>
#include <service/IntroSet.hpp>
#include <set>
namespace llarp
{
namespace dht
{
struct PublishServiceJob : public TX< service::Address, service::IntroSet >
{
uint64_t S;
std::set< Key_t > dontTell;
service::IntroSet I;
PublishServiceJob(const TXOwner &asker, const service::IntroSet &introset,
AbstractContext *ctx, uint64_t s,
const std::set< Key_t > &exclude);
bool
Validate(const service::IntroSet &introset) const override;
void
Start(const TXOwner &peer) override;
bool
GetNextPeer(Key_t &, const std::set< Key_t > &) override
{
return false;
}
void
DoNextRequest(const Key_t &) override
{
}
void
SendReply() override
{
// don't need this
}
};
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1,55 @@
#include <dht/recursiverouterlookup.hpp>
#include <dht/context.hpp>
#include <dht/messages/findrouter.hpp>
#include <dht/messages/gotrouter.hpp>
namespace llarp
{
namespace dht
{
RecursiveRouterLookup::RecursiveRouterLookup(const TXOwner &whoasked,
const RouterID &target,
AbstractContext *ctx,
RouterLookupHandler result)
: TX< RouterID, RouterContact >(whoasked, target, ctx)
, resultHandler(result)
{
peersAsked.insert(ctx->OurKey());
}
bool
RecursiveRouterLookup::Validate(const RouterContact &rc) const
{
if(!rc.Verify(parent->Crypto(), parent->Now()))
{
llarp::LogWarn("rc from lookup result is invalid");
return false;
}
return true;
}
void
RecursiveRouterLookup::Start(const TXOwner &peer)
{
parent->DHTSendTo(peer.node.as_array(),
new FindRouterMessage(peer.txid, target));
}
void
RecursiveRouterLookup::SendReply()
{
if(resultHandler)
{
resultHandler(valuesFound);
}
else
{
parent->DHTSendTo(
whoasked.node.as_array(),
new GotRouterMessage({}, whoasked.txid, valuesFound, false));
}
}
} // namespace dht
} // namespace llarp

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

@ -0,0 +1,79 @@
#include <dht/serviceaddresslookup.hpp>
#include <dht/context.hpp>
#include <dht/messages/findintro.hpp>
#include <dht/messages/gotintro.hpp>
namespace llarp
{
namespace dht
{
ServiceAddressLookup::ServiceAddressLookup(
const TXOwner &asker, const service::Address &addr, AbstractContext *ctx,
uint64_t r, service::IntroSetLookupHandler handler)
: TX< service::Address, service::IntroSet >(asker, addr, ctx)
, handleResult(handler)
, R(r)
{
peersAsked.insert(ctx->OurKey());
}
bool
ServiceAddressLookup::Validate(const service::IntroSet &value) const
{
if(!value.Verify(parent->Crypto(), parent->Now()))
{
llarp::LogWarn("Got invalid introset from service lookup");
return false;
}
if(value.A.Addr() != target)
{
llarp::LogWarn("got introset with wrong target from service lookup");
return false;
}
return true;
}
bool
ServiceAddressLookup::GetNextPeer(Key_t &next,
const std::set< Key_t > &exclude)
{
Key_t k = target.ToKey();
return parent->Nodes()->FindCloseExcluding(k, next, exclude);
}
void
ServiceAddressLookup::Start(const TXOwner &peer)
{
parent->DHTSendTo(peer.node.as_array(),
new FindIntroMessage(peer.txid, target, R));
}
void
ServiceAddressLookup::DoNextRequest(const Key_t &ask)
{
if(R)
{
parent->LookupIntroSetRecursive(target, whoasked.node, whoasked.txid,
ask, R - 1);
}
else
{
parent->LookupIntroSetIterative(target, whoasked.node, whoasked.txid,
ask);
}
}
void
ServiceAddressLookup::SendReply()
{
if(handleResult)
{
handleResult(valuesFound);
}
parent->DHTSendTo(whoasked.node.as_array(),
new GotIntroMessage(valuesFound, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -0,0 +1,44 @@
#ifndef LLARP_DHT_SERVICEADDRESSLOOKUP
#define LLARP_DHT_SERVICEADDRESSLOOKUP
#include <dht/key.hpp>
#include <dht/tx.hpp>
#include <service/address.hpp>
#include <service/IntroSet.hpp>
namespace llarp
{
namespace dht
{
struct TXOwner;
struct ServiceAddressLookup
: public TX< service::Address, service::IntroSet >
{
service::IntroSetLookupHandler handleResult;
uint64_t R;
ServiceAddressLookup(const TXOwner &asker, const service::Address &addr,
AbstractContext *ctx, uint64_t r,
service::IntroSetLookupHandler handler);
bool
Validate(const service::IntroSet &value) const override;
bool
GetNextPeer(Key_t &next, const std::set< Key_t > &exclude) override;
void
Start(const TXOwner &peer) override;
void
DoNextRequest(const Key_t &ask) override;
virtual void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1,59 @@
#include <dht/taglookup.hpp>
#include <dht/context.hpp>
#include <dht/messages/gotintro.hpp>
namespace llarp
{
namespace dht
{
bool
TagLookup::Validate(const service::IntroSet &introset) const
{
if(!introset.Verify(parent->Crypto(), parent->Now()))
{
llarp::LogWarn("got invalid introset from tag lookup");
return false;
}
if(introset.topic != target)
{
llarp::LogWarn("got introset with missmatched topic in tag lookup");
return false;
}
return true;
}
void
TagLookup::Start(const TXOwner &peer)
{
parent->DHTSendTo(peer.node.as_array(),
new FindIntroMessage(target, peer.txid, R));
}
void
TagLookup::SendReply()
{
std::set< service::IntroSet > found;
for(const auto &remoteTag : valuesFound)
{
found.insert(remoteTag);
}
// collect our local values if we haven't hit a limit
if(found.size() < 2)
{
for(const auto &localTag :
parent->FindRandomIntroSetsWithTagExcluding(target, 1, found))
{
found.insert(localTag);
}
}
std::vector< service::IntroSet > values;
for(const auto &introset : found)
{
values.push_back(introset);
}
parent->DHTSendTo(whoasked.node.as_array(),
new GotIntroMessage(values, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -0,0 +1,44 @@
#ifndef LLARP_DHT_TAGLOOKUP
#define LLARP_DHT_TAGLOOKUP
#include <dht/tx.hpp>
#include <service/IntroSet.hpp>
#include <service/tag.hpp>
namespace llarp
{
namespace dht
{
struct TagLookup : public TX< service::Tag, service::IntroSet >
{
uint64_t R;
TagLookup(const TXOwner &asker, const service::Tag &tag, AbstractContext *ctx,
uint64_t r)
: TX< service::Tag, service::IntroSet >(asker, tag, ctx), R(r)
{
}
bool
Validate(const service::IntroSet &introset) const override;
void
Start(const TXOwner &peer) override;
bool
GetNextPeer(Key_t &, const std::set< Key_t > &) override
{
return false;
}
void
DoNextRequest(const Key_t &) override
{
}
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1 @@
#include <dht/tx.hpp>

@ -0,0 +1,104 @@
#ifndef LLARP_DHT_TX
#define LLARP_DHT_TX
#include <dht/key.hpp>
#include <dht/txowner.hpp>
#include <util/logger.hpp>
#include <set>
#include <vector>
namespace llarp
{
namespace dht
{
struct AbstractContext;
template < typename K, typename V >
struct TX
{
K target;
AbstractContext* parent;
std::set< Key_t > peersAsked;
std::vector< V > valuesFound;
TXOwner whoasked;
TX(const TXOwner& asker, const K& k, AbstractContext* p)
: target(k), parent(p), whoasked(asker)
{
}
virtual ~TX(){};
void
OnFound(const Key_t& askedPeer, const V& value);
/// return true if we want to persist this tx
bool
AskNextPeer(const Key_t& prevPeer, const std::unique_ptr< Key_t >& next);
virtual bool
Validate(const V& value) const = 0;
virtual void
Start(const TXOwner& peer) = 0;
virtual bool
GetNextPeer(Key_t& next, const std::set< Key_t >& exclude) = 0;
virtual void
DoNextRequest(const Key_t& peer) = 0;
virtual void
SendReply() = 0;
};
template < typename K, typename V >
inline void
TX< K, V >::OnFound(const Key_t& askedPeer, const V& value)
{
peersAsked.insert(askedPeer);
if(Validate(value))
{
valuesFound.push_back(value);
}
}
template < typename K, typename V >
inline bool
TX< K, V >::AskNextPeer(const Key_t& prevPeer,
const std::unique_ptr< Key_t >& next)
{
peersAsked.insert(prevPeer);
Key_t peer;
if(next)
{
// explicit next peer provided
peer = *next;
}
else if(!GetNextPeer(peer, peersAsked))
{
// no more peers
llarp::LogInfo("no more peers for request asking for ", target);
return false;
}
const Key_t targetKey{target};
if((prevPeer ^ targetKey) < (peer ^ targetKey))
{
// next peer is not closer
llarp::LogInfo("next peer ", peer, " is not closer to ", target,
" than ", prevPeer);
return false;
}
else
{
peersAsked.insert(peer);
}
DoNextRequest(peer);
return true;
}
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1 @@
#include <dht/txholder.hpp>

@ -0,0 +1,190 @@
#ifndef LLARP_DHT_TXHOLDER
#define LLARP_DHT_TXHOLDER
#include <dht/tx.hpp>
#include <dht/txowner.hpp>
#include <util/logger.hpp>
#include <util/time.hpp>
#include <memory>
#include <unordered_map>
namespace llarp
{
namespace dht
{
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS = 5000UL >
struct TXHolder
{
using TXPtr = std::unique_ptr< TX< K, V > >;
// tx who are waiting for a reply for each key
std::unordered_multimap< K, TXOwner, K_Hash > waiting;
// tx timesouts by key
std::unordered_map< K, llarp_time_t, K_Hash > timeouts;
// maps remote peer with tx to handle reply from them
std::unordered_map< TXOwner, TXPtr, TXOwner::Hash > tx;
const TX< K, V >*
GetPendingLookupFrom(const TXOwner& owner) const;
bool
HasLookupFor(const K& target) const
{
return timeouts.find(target) != timeouts.end();
}
bool
HasPendingLookupFrom(const TXOwner& owner) const
{
return GetPendingLookupFrom(owner) != nullptr;
}
void
NewTX(const TXOwner& askpeer, const TXOwner& whoasked, const K& k,
TX< K, V >* t);
/// mark tx as not fond
void
NotFound(const TXOwner& from, const std::unique_ptr< Key_t >& next);
void
Found(const TXOwner& from, const K& k, const std::vector< V >& values)
{
Inform(from, k, values, true);
}
/// inform all watches for key of values found
void
Inform(TXOwner from, K key, std::vector< V > values,
bool sendreply = false, bool removeTimeouts = true);
void
Expire(llarp_time_t now);
};
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS >
const TX< K, V >*
TXHolder< K, V, K_Hash, requestTimeoutMS >::GetPendingLookupFrom(
const TXOwner& owner) const
{
auto itr = tx.find(owner);
if(itr == tx.end())
{
return nullptr;
}
else
{
return itr->second.get();
}
}
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS >
void
TXHolder< K, V, K_Hash, requestTimeoutMS >::NewTX(const TXOwner& askpeer,
const TXOwner& whoasked,
const K& k, TX< K, V >* t)
{
(void)whoasked;
tx.emplace(askpeer, std::unique_ptr< TX< K, V > >(t));
auto count = waiting.count(k);
waiting.emplace(k, askpeer);
auto itr = timeouts.find(k);
if(itr == timeouts.end())
{
timeouts.emplace(k, time_now_ms() + requestTimeoutMS);
}
if(count == 0)
{
t->Start(askpeer);
}
}
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS >
void
TXHolder< K, V, K_Hash, requestTimeoutMS >::NotFound(
const TXOwner& from, const std::unique_ptr< Key_t >& next)
{
bool sendReply = true;
auto txitr = tx.find(from);
if(txitr == tx.end())
{
return;
}
// ask for next peer
if(txitr->second->AskNextPeer(from.node, next))
{
sendReply = false;
}
llarp::LogWarn("Target key ", txitr->second->target);
Inform(from, txitr->second->target, {}, sendReply, sendReply);
}
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS >
void
TXHolder< K, V, K_Hash, requestTimeoutMS >::Inform(TXOwner from, K key,
std::vector< V > values,
bool sendreply,
bool removeTimeouts)
{
auto range = waiting.equal_range(key);
auto itr = range.first;
while(itr != range.second)
{
auto txitr = tx.find(itr->second);
if(txitr != tx.end())
{
for(const auto& value : values)
{
txitr->second->OnFound(from.node, value);
}
if(sendreply)
{
txitr->second->SendReply();
tx.erase(txitr);
}
}
++itr;
}
if(sendreply)
{
waiting.erase(key);
}
if(removeTimeouts)
{
timeouts.erase(key);
}
}
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS >
void
TXHolder< K, V, K_Hash, requestTimeoutMS >::Expire(llarp_time_t now)
{
auto itr = timeouts.begin();
while(itr != timeouts.end())
{
if(now > itr->second && now - itr->second >= requestTimeoutMS)
{
Inform(TXOwner{}, itr->first, {}, true, false);
itr = timeouts.erase(itr);
}
else
{
++itr;
}
}
}
} // namespace dht
} // namespace llarp
#endif

@ -7,6 +7,7 @@ namespace llarp
{
namespace dns
{
constexpr uint16_t qTypeAAAA = 28;
constexpr uint16_t qTypeTXT = 16;
constexpr uint16_t qTypeMX = 15;
constexpr uint16_t qTypePTR = 12;

@ -247,14 +247,17 @@ namespace llarp
{
hdr_fields |= (1 << 15) | (1 << 3);
const auto& question = questions[0];
answers.emplace_back();
auto& nx = answers.back();
nx.rr_name = question.qname;
nx.rr_type = question.qtype;
nx.rr_class = question.qclass;
nx.ttl = ttl;
nx.rData.resize(1);
nx.rData.data()[0] = 0;
if(question.qtype != qTypeAAAA)
{
answers.emplace_back();
auto& nx = answers.back();
nx.rr_name = question.qname;
nx.rr_type = question.qtype;
nx.rr_class = question.qclass;
nx.ttl = ttl;
nx.rData.resize(1);
nx.rData.data()[0] = 0;
}
}
}

@ -16,7 +16,7 @@ namespace llarp
, m_Counter(0)
, m_LastUse(0)
{
r->crypto.identity_keygen(m_ExitIdentity);
r->crypto->identity_keygen(m_ExitIdentity);
}
BaseSession::~BaseSession()
@ -78,7 +78,7 @@ namespace llarp
obtain.S = p->NextSeqNo();
obtain.T = llarp::randint();
PopulateRequest(obtain);
if(!obtain.Sign(&router->crypto, m_ExitIdentity))
if(!obtain.Sign(router->crypto.get(), m_ExitIdentity))
{
llarp::LogError("Failed to sign exit request");
return;
@ -107,7 +107,7 @@ namespace llarp
{
llarp::LogInfo(p->Name(), " closing exit path");
llarp::routing::CloseExitMessage msg;
if(!(msg.Sign(&router->crypto, m_ExitIdentity)
if(!(msg.Sign(router->crypto.get(), m_ExitIdentity)
&& p->SendExitClose(&msg, router)))
llarp::LogWarn(p->Name(), " failed to send exit close message");
}

@ -246,7 +246,7 @@ namespace llarp
Crypto *
ExitEndpoint::GetCrypto()
{
return &m_Router->crypto;
return m_Router->crypto.get();
}
huint32_t

@ -9,8 +9,9 @@ namespace llarp
{
struct NullEndpoint final : public llarp::service::Endpoint
{
NullEndpoint(const std::string &name, llarp::Router *r)
: llarp::service::Endpoint(name, r){};
NullEndpoint(const std::string &name, llarp::Router *r,
llarp::service::Context *parent)
: llarp::service::Endpoint(name, r, parent){};
bool HandleWriteIPPacket(llarp_buffer_t,
std::function< huint32_t(void) >) override

@ -29,8 +29,9 @@ namespace llarp
self->Flush();
}
TunEndpoint::TunEndpoint(const std::string &nickname, llarp::Router *r)
: service::Endpoint(nickname, r)
TunEndpoint::TunEndpoint(const std::string &nickname, llarp::Router *r,
service::Context *parent)
: service::Endpoint(nickname, r, parent)
, m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop, r->netloop)
, m_NetworkToUserPktQueue(nickname + "_recvq", r->netloop, r->netloop)
, m_Resolver(r->netloop, this)
@ -204,10 +205,7 @@ namespace llarp
return false;
}
std::string qname = msg.questions[0].qname;
if(msg.questions[0].qtype == dns::qTypeCNAME)
{
}
else if(msg.questions[0].qtype == dns::qTypeMX)
if(msg.questions[0].qtype == dns::qTypeMX)
{
// mx record
llarp::service::Address addr;
@ -228,19 +226,44 @@ namespace llarp
else
msg.AddNXReply();
}
else if(msg.questions[0].qname == "localhost.loki"
|| msg.questions[0].qname == "localhost.loki.")
{
size_t counter = 0;
context->ForEachService(
[&](const std::string &,
const std::unique_ptr< service::Endpoint > &service) -> bool {
service::Address addr = service->GetIdentity().pub.Addr();
msg.AddCNAMEReply(addr.ToString(), 1);
++counter;
return true;
});
if(counter == 0)
msg.AddNXReply();
}
else
msg.AddNXReply();
}
else if(msg.questions[0].qtype == dns::qTypeA)
{
// forward dns
llarp::service::Address addr;
if(qname == "random.snode" || qname == "random.snode.")
// forward dns
if(msg.questions[0].qname == "localhost.loki"
|| msg.questions[0].qname == "localhost.loki.")
{
RouterID random;
if(Router()->GetRandomGoodRouter(random))
msg.AddCNAMEReply(random.ToString(), 1);
else
size_t counter = 0;
context->ForEachService(
[&](const std::string &,
const std::unique_ptr< service::Endpoint > &service) -> bool {
if(service->HasIfAddr())
{
huint32_t ip = service->GetIfAddr();
msg.AddINReply(ip);
++counter;
}
return true;
});
if(counter == 0)
msg.AddNXReply();
}
else if(addr.FromString(qname, ".loki"))
@ -317,14 +340,18 @@ namespace llarp
// always hook mx records
if(msg.questions[0].qtype == llarp::dns::qTypeMX)
return true;
// always hook random.snode
// hook random.snode for CNAME
if(msg.questions[0].qname == "random.snode"
|| msg.questions[0].qname == "random.snode.")
return true;
// always hook .loki
// hook localhost.loki
if(msg.questions[0].qname == "localhost.loki"
|| msg.questions[0].qname == "localhost.loki.")
return true;
// hook .loki A records
if(addr.FromString(msg.questions[0].qname, ".loki"))
return true;
// always hook .snode
// hook .snode A records
if(addr.FromString(msg.questions[0].qname, ".snode"))
return true;
// hook any ranges we own

@ -20,7 +20,8 @@ namespace llarp
struct TunEndpoint : public service::Endpoint, public dns::IQueryHandler
{
TunEndpoint(const std::string& nickname, llarp::Router* r);
TunEndpoint(const std::string& nickname, llarp::Router* r,
llarp::service::Context* parent);
~TunEndpoint();
virtual bool
@ -70,6 +71,13 @@ namespace llarp
bool
QueueOutboundTraffic(llarp::net::IPv4Packet&& pkt);
/// we have a resolvable ip address
bool
HasIfAddr() const override
{
return true;
}
/// get the local interface's address
huint32_t
GetIfAddr() const;

@ -28,6 +28,8 @@ namespace llarp
{
namespace utp
{
using namespace std::placeholders;
bool
InboundMessage::IsExpired(llarp_time_t now) const
{
@ -549,7 +551,7 @@ namespace llarp
NewServerFromRouter(llarp::Router* r)
{
return NewServer(
&r->crypto, r->encryption, std::bind(&llarp::Router::rc, r),
r->crypto.get(), r->encryption, std::bind(&llarp::Router::rc, r),
std::bind(&llarp::Router::HandleRecvLinkMessageBuffer, r,
std::placeholders::_1, std::placeholders::_2),
std::bind(&llarp::Router::OnSessionEstablished, r,
@ -665,8 +667,10 @@ namespace llarp
remoteRC = msg->rc;
Crypto()->shorthash(txKey, remoteRC.pubkey.as_buffer());
if(!DoKeyExchange(Crypto()->transport_dh_server, rxKey, msg->N,
remoteRC.enckey, parent->TransportSecretKey()))
if(!DoKeyExchange(std::bind(&Crypto::transport_dh_server, Crypto(), _1,
_2, _3, _4),
rxKey, msg->N, remoteRC.enckey,
parent->TransportSecretKey()))
return false;
byte_t tmp[LinkIntroMessage::MaxSize];
@ -706,8 +710,10 @@ namespace llarp
Close();
return false;
}
if(!DoKeyExchange(Crypto()->transport_dh_client, txKey, replymsg.N,
remoteRC.enckey, parent->RouterEncryptionSecret()))
if(!DoKeyExchange(std::bind(&Crypto::transport_dh_client, Crypto(), _1,
_2, _3, _4),
txKey, replymsg.N, remoteRC.enckey,
parent->RouterEncryptionSecret()))
return false;
llarp::LogDebug("Sent reply LIM");
@ -761,8 +767,10 @@ namespace llarp
}
remoteRC = msg->rc;
gotLIM = true;
if(!DoKeyExchange(Crypto()->transport_dh_server, rxKey, msg->N,
remoteRC.enckey, parent->RouterEncryptionSecret()))
if(!DoKeyExchange(
std::bind(&Crypto::transport_dh_server, Crypto(), _1, _2, _3, _4),
rxKey, msg->N, remoteRC.enckey, parent->RouterEncryptionSecret()))
{
Close();
return false;
@ -814,9 +822,11 @@ namespace llarp
Close();
return;
}
if(!DoKeyExchange(Crypto()->transport_dh_client, txKey, msg.N,
remoteTransportPubKey,
parent->RouterEncryptionSecret()))
if(!DoKeyExchange(
std::bind(&Crypto::transport_dh_client, Crypto(), _1, _2, _3, _4),
txKey, msg.N, remoteTransportPubKey,
parent->RouterEncryptionSecret()))
{
llarp::LogError("failed to mix keys for outbound session to ",
remoteAddr);
@ -988,8 +998,9 @@ namespace llarp
// set remote rc
remoteRC = msg->rc;
// recalcuate rx key
return DoKeyExchange(Crypto()->transport_dh_server, rxKey, msg->N,
remoteRC.enckey, parent->RouterEncryptionSecret());
return DoKeyExchange(
std::bind(&Crypto::transport_dh_server, Crypto(), _1, _2, _3, _4),
rxKey, msg->N, remoteRC.enckey, parent->RouterEncryptionSecret());
}
bool
@ -1012,8 +1023,9 @@ namespace llarp
if(!SendMessageBuffer(buf))
return false;
// regen our tx Key
return DoKeyExchange(Crypto()->transport_dh_client, txKey, lim.N,
remoteRC.enckey, parent->RouterEncryptionSecret());
return DoKeyExchange(
std::bind(&Crypto::transport_dh_client, Crypto(), _1, _2, _3, _4),
txKey, lim.N, remoteRC.enckey, parent->RouterEncryptionSecret());
}
bool
@ -1080,7 +1092,9 @@ namespace llarp
// get message
if(m_RecvMsgs.find(msgid) == m_RecvMsgs.end())
{
m_RecvMsgs.emplace(msgid, InboundMessage{});
}
auto itr = m_RecvMsgs.find(msgid);
// add message activity

@ -117,7 +117,7 @@ namespace llarp
bool
LinkIntroMessage::HandleMessage(llarp::Router* router) const
{
if(!Verify(&router->crypto))
if(!Verify(router->crypto.get()))
return false;
return session->GotLIM(this);
}

@ -269,19 +269,21 @@ namespace llarp
return;
}
// generate path key as we are in a worker thread
auto DH = self->context->Crypto()->dh_server;
if(!DH(self->hop->pathKey, self->record.commkey,
self->context->EncryptionSecretKey(), self->record.tunnelNonce))
auto crypto = self->context->Crypto();
if(!crypto->dh_server(self->hop->pathKey, self->record.commkey,
self->context->EncryptionSecretKey(),
self->record.tunnelNonce))
{
llarp::LogError("LRCM DH Failed ", info);
delete self;
return;
}
// generate hash of hop key for nonce mutation
self->context->Crypto()->shorthash(self->hop->nonceXOR,
self->hop->pathKey.as_buffer());
crypto->shorthash(self->hop->nonceXOR, self->hop->pathKey.as_buffer());
using namespace std::placeholders;
if(self->record.work
&& self->record.work->IsValid(self->context->Crypto()->shorthash, now))
&& self->record.work->IsValid(
std::bind(&Crypto::shorthash, crypto, _1, _2), now))
{
llarp::LogDebug("LRCM extended lifetime by ",
self->record.work->extendedLifetime, " seconds for ",

@ -23,9 +23,9 @@ namespace llarp
struct in6_addr netmask;
PubKey pubkey;
ExitInfo(const PubKey &pk, const nuint32_t &ipv4_exit) : IBEncodeMessage()
ExitInfo(const PubKey &pk, const nuint32_t &ipv4_exit) : IBEncodeMessage(),
pubkey(pk)
{
pubkey = pk;
memset(address.s6_addr, 0, 16);
address.s6_addr[11] = 0xff;
address.s6_addr[10] = 0xff;
@ -37,12 +37,11 @@ namespace llarp
{
}
ExitInfo(const ExitInfo &other) : IBEncodeMessage()
ExitInfo(const ExitInfo &other) : IBEncodeMessage(other.version),
pubkey(other.pubkey)
{
pubkey = other.pubkey;
memcpy(address.s6_addr, other.address.s6_addr, 16);
memcpy(netmask.s6_addr, other.netmask.s6_addr, 16);
version = other.version;
}
~ExitInfo();

@ -43,7 +43,7 @@ namespace llarp
llarp::Crypto*
PathContext::Crypto()
{
return &m_Router->crypto;
return m_Router->crypto.get();
}
llarp::Logic*
@ -155,24 +155,26 @@ namespace llarp
IHopHandler*
PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id)
{
auto own = MapGet(m_OurPaths, id,
[](__attribute__((unused)) const PathSet* s) -> bool {
// TODO: is this right?
return true;
},
[remote, id](PathSet* p) -> IHopHandler* {
return p->GetByUpstream(remote, id);
});
auto own = MapGet(
m_OurPaths, id,
[](__attribute__((unused)) const PathSet* s) -> bool {
// TODO: is this right?
return true;
},
[remote, id](PathSet* p) -> IHopHandler* {
return p->GetByUpstream(remote, id);
});
if(own)
return own;
return MapGet(m_TransitPaths, id,
[remote](const std::shared_ptr< TransitHop >& hop) -> bool {
return hop->info.upstream == remote;
},
[](const std::shared_ptr< TransitHop >& h) -> IHopHandler* {
return h.get();
});
return MapGet(
m_TransitPaths, id,
[remote](const std::shared_ptr< TransitHop >& hop) -> bool {
return hop->info.upstream == remote;
},
[](const std::shared_ptr< TransitHop >& h) -> IHopHandler* {
return h.get();
});
}
bool
@ -189,13 +191,14 @@ namespace llarp
IHopHandler*
PathContext::GetByDownstream(const RouterID& remote, const PathID_t& id)
{
return MapGet(m_TransitPaths, id,
[remote](const std::shared_ptr< TransitHop >& hop) -> bool {
return hop->info.downstream == remote;
},
[](const std::shared_ptr< TransitHop >& h) -> IHopHandler* {
return h.get();
});
return MapGet(
m_TransitPaths, id,
[remote](const std::shared_ptr< TransitHop >& hop) -> bool {
return hop->info.downstream == remote;
},
[](const std::shared_ptr< TransitHop >& h) -> IHopHandler* {
return h.get();
});
}
PathSet*
@ -506,7 +509,7 @@ namespace llarp
TunnelNonce n = Y;
for(const auto& hop : hops)
{
r->crypto.xchacha20(buf, hop.shared, n);
r->crypto->xchacha20(buf, hop.shared, n);
n ^= hop.nonceXOR;
}
RelayUpstreamMessage msg;
@ -546,7 +549,7 @@ namespace llarp
for(const auto& hop : hops)
{
n ^= hop.nonceXOR;
r->crypto.xchacha20(buf, hop.shared, n);
r->crypto->xchacha20(buf, hop.shared, n);
}
return HandleRoutingMessage(buf, r);
}
@ -605,7 +608,7 @@ namespace llarp
if(buf.sz < MESSAGE_PAD_SIZE)
{
// randomize padding
r->crypto.randbytes(buf.cur, MESSAGE_PAD_SIZE - buf.sz);
r->crypto->randbytes(buf.cur, MESSAGE_PAD_SIZE - buf.sz);
buf.sz = MESSAGE_PAD_SIZE;
}
buf.cur = buf.base;
@ -716,7 +719,7 @@ namespace llarp
/// allows exits to close from their end
if(SupportsAnyRoles(ePathRoleExit | ePathRoleSVC))
{
if(msg->Verify(&r->crypto, EndpointPubKey()))
if(msg->Verify(r->crypto.get(), EndpointPubKey()))
{
llarp::LogInfo(Name(), " had its exit closed");
_role &= ~ePathRoleExit;
@ -775,7 +778,7 @@ namespace llarp
{
if(m_ExitObtainTX && msg->T == m_ExitObtainTX)
{
if(!msg->Verify(&r->crypto, EndpointPubKey()))
if(!msg->Verify(r->crypto.get(), EndpointPubKey()))
{
llarp::LogError(Name(), "RXM invalid signature");
return false;
@ -794,7 +797,7 @@ namespace llarp
{
if(m_ExitObtainTX && msg->T == m_ExitObtainTX)
{
if(!msg->Verify(&r->crypto, EndpointPubKey()))
if(!msg->Verify(r->crypto.get(), EndpointPubKey()))
{
llarp::LogError(Name(), " GXM signature failed");
return false;

@ -167,7 +167,7 @@ namespace llarp
, numHops(hops)
{
p_router->paths.AddPathBuilder(this);
p_router->crypto.encryption_keygen(enckey);
p_router->crypto->encryption_keygen(enckey);
_run.store(true);
keygens.store(0);
}
@ -281,7 +281,7 @@ namespace llarp
lastBuild = Now();
// async generate keys
AsyncPathKeyExchangeContext< Builder >* ctx =
new AsyncPathKeyExchangeContext< Builder >(&router->crypto);
new AsyncPathKeyExchangeContext< Builder >(router->crypto.get());
ctx->router = router;
ctx->pathset = this;
auto path = new llarp::path::Path(hops, this, roles);

@ -75,7 +75,7 @@ namespace llarp
{
dlt = MESSAGE_PAD_SIZE - dlt;
// randomize padding
r->crypto.randbytes(buf.cur, dlt);
r->crypto->randbytes(buf.cur, dlt);
buf.sz += dlt;
}
buf.cur = buf.base;
@ -89,7 +89,7 @@ namespace llarp
RelayDownstreamMessage msg;
msg.pathid = info.rxID;
msg.Y = Y ^ nonceXOR;
r->crypto.xchacha20(buf, pathKey, Y);
r->crypto->xchacha20(buf, pathKey, Y);
msg.X = buf;
llarp::LogDebug("relay ", msg.X.size(), " bytes downstream from ",
info.upstream, " to ", info.downstream);
@ -100,7 +100,7 @@ namespace llarp
TransitHop::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp::Router* r)
{
r->crypto.xchacha20(buf, pathKey, Y);
r->crypto->xchacha20(buf, pathKey, Y);
if(IsEndpoint(r->pubkey()))
{
m_LastActivity = r->Now();
@ -157,13 +157,13 @@ namespace llarp
TransitHop::HandleObtainExitMessage(
const llarp::routing::ObtainExitMessage* msg, llarp::Router* r)
{
if(msg->Verify(&r->crypto)
if(msg->Verify(r->crypto.get())
&& r->exitContext.ObtainNewExit(msg->I, info.rxID, msg->E != 0))
{
llarp::routing::GrantExitMessage grant;
grant.S = NextSeqNo();
grant.T = msg->T;
if(!grant.Sign(&r->crypto, r->identity))
if(!grant.Sign(r->crypto.get(), r->identity))
{
llarp::LogError("Failed to sign grant exit message");
return false;
@ -175,7 +175,7 @@ namespace llarp
llarp::routing::RejectExitMessage reject;
reject.S = NextSeqNo();
reject.T = msg->T;
if(!reject.Sign(&r->crypto, r->identity))
if(!reject.Sign(r->crypto.get(), r->identity))
{
llarp::LogError("Failed to sign reject exit message");
return false;
@ -189,13 +189,13 @@ namespace llarp
{
llarp::routing::DataDiscardMessage discard(info.rxID, msg->S);
auto ep = r->exitContext.FindEndpointForPath(info.rxID);
if(ep && msg->Verify(&r->crypto, ep->PubKey()))
if(ep && msg->Verify(r->crypto.get(), ep->PubKey()))
{
ep->Close();
// ep is now gone af
llarp::routing::CloseExitMessage reply;
reply.S = NextSeqNo();
if(reply.Sign(&r->crypto, r->identity))
if(reply.Sign(r->crypto.get(), r->identity))
return SendRoutingMessage(&reply, r);
}
return SendRoutingMessage(&discard, r);
@ -218,7 +218,7 @@ namespace llarp
auto ep = r->exitContext.FindEndpointForPath(msg->P);
if(ep)
{
if(!msg->Verify(&r->crypto, ep->PubKey()))
if(!msg->Verify(r->crypto.get(), ep->PubKey()))
return false;
if(ep->UpdateLocalPath(info.rxID))

@ -2,6 +2,7 @@
#include <constants/proto.hpp>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <dht/context.hpp>
#include <dht/node.hpp>
#include <link/iwp.hpp>
@ -196,7 +197,7 @@ namespace llarp
Router::OnSessionEstablished(llarp::RouterContact rc)
{
async_verify_RC(rc, nullptr);
llarp::LogInfo("session with ", rc.pubkey, "established");
llarp::LogInfo("session with ", rc.pubkey, " established");
}
Router::Router(struct llarp_threadpool *_tp, struct llarp_ev_loop *_netloop,
@ -205,7 +206,7 @@ namespace llarp
, netloop(_netloop)
, tp(_tp)
, logic(_logic)
, crypto(llarp::Crypto::sodium{})
, crypto(std::make_unique< sodium::CryptoLibSodium >())
, paths(this)
, exitContext(this)
, dht(llarp_dht_context_new(this))
@ -343,7 +344,7 @@ namespace llarp
{
return;
}
if(results[0].Verify(&crypto, Now()))
if(results[0].Verify(crypto.get(), Now()))
{
nodedb->Insert(results[0]);
TryConnectAsync(results[0], 10);
@ -391,7 +392,7 @@ namespace llarp
llarp::LogError("failure to decode or verify of remote RC");
return;
}
if(remote.Verify(&crypto, Now()))
if(remote.Verify(crypto.get(), Now()))
{
llarp::LogDebug("verified signature");
// store into filesystem
@ -415,15 +416,16 @@ namespace llarp
if(!EnsureEncryptionKey())
return false;
if(usingSNSeed)
return llarp_loadServiceNodeIdentityKey(&crypto, ident_keyfile, identity);
return llarp_loadServiceNodeIdentityKey(crypto.get(), ident_keyfile,
identity);
else
return llarp_findOrCreateIdentity(&crypto, ident_keyfile, identity);
return llarp_findOrCreateIdentity(crypto.get(), ident_keyfile, identity);
}
bool
Router::EnsureEncryptionKey()
{
return llarp_findOrCreateEncryption(&crypto, encryption_keyfile,
return llarp_findOrCreateEncryption(crypto.get(), encryption_keyfile,
this->encryption);
}
@ -459,7 +461,7 @@ namespace llarp
Router::SaveRC()
{
llarp::LogDebug("verify RC signature");
if(!_rc.Verify(&crypto, Now()))
if(!_rc.Verify(crypto.get(), Now()))
{
rc().Dump< MAX_RC_SIZE >();
llarp::LogError("RC is invalid, not saving");
@ -585,7 +587,7 @@ namespace llarp
return;
for(const auto &rc : results)
{
if(rc.Verify(&crypto, Now()))
if(rc.Verify(crypto.get(), Now()))
nodedb->Insert(rc);
else
return;
@ -672,11 +674,11 @@ namespace llarp
llarp::RouterContact nextRC = _rc;
if(rotateKeys)
{
crypto.encryption_keygen(nextOnionKey);
crypto->encryption_keygen(nextOnionKey);
nextRC.enckey = llarp::seckey_topublic(nextOnionKey);
}
nextRC.last_updated = Now();
if(!nextRC.Sign(&crypto, identity))
if(!nextRC.Sign(crypto.get(), identity))
return false;
_rc = nextRC;
if(rotateKeys)
@ -817,7 +819,7 @@ namespace llarp
bool
Router::Sign(llarp::Signature &sig, llarp_buffer_t buf) const
{
return crypto.sign(sig, identity, buf);
return crypto->sign(sig, identity, buf);
}
void
@ -967,7 +969,7 @@ namespace llarp
job->nodedb = nodedb;
job->logic = logic;
// job->crypto = &crypto; // we already have this
// job->crypto = crypto.get(); // we already have this
job->cryptoworker = tp;
job->diskworker = disk;
if(rc.IsPublicRouter())
@ -1003,6 +1005,21 @@ namespace llarp
}
llarp::LogInfo("Bound RPC server to ", rpcBindAddr);
}
if(whitelistRouters)
{
rpcCaller = std::make_unique<llarp::rpc::Caller>(this);
rpcCaller->SetBasicAuth(lokidRPCUser, lokidRPCPassword);
while(!rpcCaller->Start(lokidRPCAddr))
{
llarp::LogError("failed to start jsonrpc caller to ", lokidRPCAddr);
#if defined(ANDROID) || defined(RPI)
sleep(1);
#else
std::this_thread::sleep_for(std::chrono::seconds(1));
#endif
}
llarp::LogInfo("RPC Caller to ", lokidRPCAddr, " started");
}
llarp_threadpool_start(tp);
llarp_threadpool_start(disk);
@ -1042,8 +1059,7 @@ namespace llarp
if(ExitEnabled())
{
llarp::nuint32_t a = publicAddr.xtonl();
// TODO: enable this once the network can serialize xi
//_rc.exits.emplace_back(_rc.pubkey, a);
_rc.exits.emplace_back(_rc.pubkey, a);
llarp::LogInfo(
"Neato tehl33toh, You are a freaking exit relay. w00t!!!!! your "
"exit "
@ -1051,7 +1067,7 @@ namespace llarp
a);
}
llarp::LogInfo("Signing rc...");
if(!_rc.Sign(&crypto, identity))
if(!_rc.Sign(crypto.get(), identity))
{
llarp::LogError("failed to sign rc");
return false;
@ -1104,11 +1120,11 @@ namespace llarp
{
// we are a client
// regenerate keys and resign rc before everything else
crypto.identity_keygen(identity);
crypto.encryption_keygen(encryption);
crypto->identity_keygen(identity);
crypto->encryption_keygen(encryption);
_rc.pubkey = llarp::seckey_topublic(identity);
_rc.enckey = llarp::seckey_topublic(encryption);
if(!_rc.Sign(&crypto, identity))
if(!_rc.Sign(crypto.get(), identity))
{
llarp::LogError("failed to regenerate keys and sign RC");
return false;
@ -1408,11 +1424,13 @@ namespace llarp
{
// fallback defaults
// To NeuroScr: why run findFree* here instead of in tun.cpp?
// I think it should be in tun.cpp, better to closer to time of usage
// that way new tun may have grab a range we may have also grabbed here
static const std::unordered_map< std::string,
std::function< std::string(void) > >
netConfigDefaults = {
{"ifname", llarp::findFreeLokiTunIfName},
{"ifaddr", llarp::findFreePrivateRange},
{"ifname", []() -> std::string { return "auto"; }},
{"ifaddr", []() -> std::string { return "auto"; }},
{"local-dns", []() -> std::string { return "127.0.0.1:53"; }},
{"upstream-dns", []() -> std::string { return "1.1.1.1:53"; }}};
// populate with fallback defaults if values not present
@ -1591,6 +1609,14 @@ namespace llarp
{
self->lokidRPCAddr = val;
}
if(StrEq(key, "username"))
{
self->lokidRPCUser = val;
}
if(StrEq(key, "password"))
{
self->lokidRPCPassword = val;
}
}
else if(StrEq(section, "dns"))
{
@ -1608,6 +1634,7 @@ namespace llarp
else if(StrEq(section, "connect")
|| (StrEq(section, "bootstrap") && StrEq(key, "add-node")))
{
//llarp::LogDebug("connect section has ", key, "=", val);
self->bootstrapRCList.emplace_back();
auto &rc = self->bootstrapRCList.back();
if(!rc.Read(val))
@ -1617,7 +1644,7 @@ namespace llarp
self->bootstrapRCList.pop_back();
return;
}
if(rc.Verify(&self->crypto, self->Now()))
if(rc.Verify(self->crypto.get(), self->Now()))
{
llarp::LogInfo("Added bootstrap node ", RouterID(rc.pubkey));
}

@ -26,9 +26,10 @@
#include <functional>
#include <list>
#include <map>
#include <vector>
#include <unordered_map>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
namespace llarp
{
@ -105,7 +106,7 @@ namespace llarp
llarp_ev_loop *netloop;
llarp_threadpool *tp;
llarp::Logic *logic;
llarp::Crypto crypto;
std::unique_ptr< llarp::Crypto > crypto;
llarp::path::PathContext paths;
llarp::exit::Context exitContext;
llarp::SecretKey identity;
@ -174,7 +175,9 @@ namespace llarp
/// lokid caller
const std::string DefaultLokidRPCAddr = "127.0.0.1:22023";
std::unique_ptr< llarp::rpc::Caller > rpcCaller;
std::string lokidRPCAddr = DefaultLokidRPCAddr;
std::string lokidRPCAddr = DefaultLokidRPCAddr;
std::string lokidRPCUser = "";
std::string lokidRPCPassword = "";
std::set< std::unique_ptr< llarp::ILinkLayer >,
CompareLinks< llarp::ILinkLayer > >

@ -8,6 +8,7 @@
#include <util/aligned.hpp>
#include <util/bencode.hpp>
#include <functional>
#include <vector>
#define MAX_RC_SIZE (1024)
@ -188,6 +189,9 @@ namespace llarp
bool
VerifySignature(llarp::Crypto *crypto) const;
};
using RouterLookupHandler =
std::function< void(const std::vector< RouterContact >&) >;
} // namespace llarp
#endif

@ -44,6 +44,13 @@ namespace llarp
using Hash = AlignedBuffer< SIZE >::Hash;
};
inline bool
operator==(const RouterID& lhs, const RouterID& rhs)
{
return lhs.as_array() == rhs.as_array();
}
} // namespace llarp
#endif

@ -3,6 +3,7 @@
#include <router/router.hpp>
#ifdef USE_ABYSS
#include <util/encode.hpp>
#include <libabyss.hpp>
#endif
@ -14,8 +15,9 @@ namespace llarp
struct CallerHandler : public ::abyss::http::IRPCClientHandler
{
CallerHandler(::abyss::http::ConnImpl* impl)
: ::abyss::http::IRPCClientHandler(impl)
CallerImpl* m_Parent;
CallerHandler(::abyss::http::ConnImpl* impl, CallerImpl* parent)
: ::abyss::http::IRPCClientHandler(impl), m_Parent(parent)
{
}
@ -44,16 +46,12 @@ namespace llarp
}
void
PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
(void)hdr;
// TODO: add http auth (?)
}
PopulateReqHeaders(abyss::http::Headers_t& hdr);
};
struct GetServiceNodeListHandler final : public CallerHandler
{
using PubkeyList_t = std::vector< PubKey >;
using PubkeyList_t = std::vector< RouterID >;
using Callback_t = std::function< void(const PubkeyList_t&, bool) >;
~GetServiceNodeListHandler()
@ -61,8 +59,9 @@ namespace llarp
}
Callback_t handler;
GetServiceNodeListHandler(::abyss::http::ConnImpl* impl, Callback_t h)
: CallerHandler(impl), handler(h)
GetServiceNodeListHandler(::abyss::http::ConnImpl* impl,
CallerImpl* parent, Callback_t h)
: CallerHandler(impl, parent), handler(h)
{
}
@ -92,8 +91,12 @@ namespace llarp
if(key_itr->IsString())
{
keys.emplace_back();
if(!HexDecode(key_itr->GetString(), keys.back().begin(),
decltype(keys)::value_type::SIZE))
std::string str = key_itr->GetString();
if(str.size() != Base32DecodeSize(keys.back().size()))
{
keys.pop_back();
}
else if(!Base32Decode(str, keys.back()))
{
keys.pop_back();
}
@ -114,10 +117,13 @@ namespace llarp
struct CallerImpl : public ::abyss::http::JSONRPC
{
Router* router;
llarp_time_t m_NextKeyUpdate;
llarp_time_t m_NextKeyUpdate = 0;
const llarp_time_t KeyUpdateInterval = 1000 * 60 * 2;
using PubkeyList_t = GetServiceNodeListHandler::PubkeyList_t;
std::string username;
std::string password;
CallerImpl(Router* r) : ::abyss::http::JSONRPC(), router(r)
{
}
@ -133,13 +139,20 @@ namespace llarp
Flush();
}
void
SetBasicAuth(const std::string& user, const std::string& passwd)
{
username = user;
password = passwd;
}
void
AsyncUpdatePubkeyList()
{
LogInfo("Updating service node list");
::abyss::json::Value params;
params.SetObject();
QueueRPC("/get_all_service_node_keys", std::move(params),
QueueRPC("get_all_service_nodes_keys", std::move(params),
std::bind(&CallerImpl::NewAsyncUpdatePubkeyListConn, this,
std::placeholders::_1));
}
@ -154,7 +167,7 @@ namespace llarp
NewAsyncUpdatePubkeyListConn(abyss::http::ConnImpl* impl)
{
return new GetServiceNodeListHandler(
impl,
impl, this,
std::bind(&CallerImpl::HandleServiceNodeListUpdated, this,
std::placeholders::_1, std::placeholders::_2));
}
@ -180,6 +193,18 @@ namespace llarp
}
};
void
CallerHandler::PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
if(m_Parent->username.empty() || m_Parent->password.empty())
return;
std::stringstream ss;
ss << "Basic ";
std::string cred = m_Parent->username + ":" + m_Parent->password;
llarp::Base64Encode(ss, (const byte_t*)cred.c_str(), cred.size());
hdr.emplace("Authorization", ss.str());
}
struct Handler : public ::abyss::httpd::IRPCHandler
{
Router* router;
@ -354,6 +379,11 @@ namespace llarp
{
(void)now;
}
void
SetBasicAuth(const std::string&, const std::string&)
{
}
};
#endif
@ -385,6 +415,12 @@ namespace llarp
m_Impl->Tick(now);
}
void
Caller::SetBasicAuth(const std::string& user, const std::string& passwd)
{
m_Impl->SetBasicAuth(user, passwd);
}
Server::Server(Router* r) : m_Impl(new ServerImpl(r))
{
}

@ -40,6 +40,10 @@ namespace llarp
Caller(Router* r);
~Caller();
/// set http basic auth for use with remote rpc endpoint
void
SetBasicAuth(const std::string& user, const std::string& password);
/// start with jsonrpc endpoint address
bool
Start(const std::string& remote);
@ -48,10 +52,6 @@ namespace llarp
void
Stop();
/// test if a router is valid
bool
VerifyRouter(const PubKey& pk);
/// do per second tick
void
Tick(llarp_time_t now);

@ -122,7 +122,8 @@ namespace llarp
if(!A.Verify(crypto, buf, Z))
return false;
// validate PoW
if(W && !W->IsValid(crypto->shorthash, now))
using namespace std::placeholders;
if(W && !W->IsValid(std::bind(&Crypto::shorthash, crypto, _1, _2), now))
return false;
// valid timestamps
// add max clock skew

@ -10,6 +10,7 @@
#include <util/time.hpp>
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
@ -153,6 +154,10 @@ namespace llarp
bool
Verify(llarp::Crypto* crypto, llarp_time_t now) const;
};
using IntroSetLookupHandler =
std::function< void(const std::vector< IntroSet >&) >;
} // namespace service
} // namespace llarp

@ -30,6 +30,22 @@ namespace llarp
return true;
}
void
Context::ForEachService(
std::function< bool(const std::string &,
const std::unique_ptr< Endpoint > &) >
visit)
{
auto itr = m_Endpoints.begin();
while(itr != m_Endpoints.end())
{
if(visit(itr->first, itr->second))
++itr;
else
return;
}
}
bool
Context::RemoveEndpoint(const std::string &name)
{
@ -274,17 +290,18 @@ namespace llarp
static std::map< std::string,
std::function< llarp::service::Endpoint *(
const std::string &, llarp::Router *) > >
const std::string &, llarp::Router *,
llarp::service::Context *) > >
endpointConstructors = {
{"tun",
[](const std::string &nick,
llarp::Router *r) -> llarp::service::Endpoint * {
return new llarp::handlers::TunEndpoint(nick, r);
[](const std::string &nick, llarp::Router *r,
llarp::service::Context *c) -> llarp::service::Endpoint * {
return new llarp::handlers::TunEndpoint(nick, r, c);
}},
{"null",
[](const std::string &nick,
llarp::Router *r) -> llarp::service::Endpoint * {
return new llarp::handlers::NullEndpoint(nick, r);
[](const std::string &nick, llarp::Router *r,
llarp::service::Context *c) -> llarp::service::Endpoint * {
return new llarp::handlers::NullEndpoint(nick, r, c);
}}};
{
@ -297,7 +314,7 @@ namespace llarp
}
// construct
service.reset(itr->second(conf.first, m_Router));
service.reset(itr->second(conf.first, m_Router, this));
// if ephemeral, then we need to regen key
// if privkey file, then set it and load it

@ -61,6 +61,12 @@ namespace llarp
bool
iterate(struct endpoint_iter &i);
/// function visitor returns false to prematurely break iteration
void
ForEachService(std::function< bool(const std::string &,
const std::unique_ptr< Endpoint > &) >
visit);
/// hint at possible path usage and trigger building early
bool
Prefetch(const llarp::service::Address &addr);

@ -16,8 +16,10 @@ namespace llarp
{
namespace service
{
Endpoint::Endpoint(const std::string& name, llarp::Router* r)
Endpoint::Endpoint(const std::string& name, llarp::Router* r,
Context* parent)
: path::Builder(r, r->dht, 6, DEFAULT_HOP_LENGTH)
, context(parent)
, m_Router(r)
, m_Name(name)
{
@ -116,7 +118,7 @@ namespace llarp
return;
}
m_IntroSet.topic = m_Tag;
if(!m_Identity.SignIntroSet(m_IntroSet, &m_Router->crypto, now))
if(!m_Identity.SignIntroSet(m_IntroSet, m_Router->crypto.get(), now))
{
llarp::LogWarn("failed to sign introset for endpoint ", Name());
return;
@ -352,7 +354,7 @@ namespace llarp
bool
Endpoint::HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg)
{
auto crypto = &m_Router->crypto;
auto crypto = m_Router->crypto.get();
std::set< IntroSet > remote;
for(const auto& introset : msg->I)
{
@ -492,7 +494,7 @@ namespace llarp
bool
Endpoint::LoadKeyFile()
{
auto crypto = &m_Router->crypto;
auto crypto = m_Router->crypto.get();
if(m_Keyfile.size())
{
if(!m_Identity.EnsureKeys(m_Keyfile, crypto))
@ -1233,7 +1235,7 @@ namespace llarp
f.C.Zero();
transfer.Y.Randomize();
transfer.P = remoteIntro.pathID;
if(!f.EncryptAndSign(&Router()->crypto, m, K, m_Identity))
if(!f.EncryptAndSign(Router()->crypto.get(), m, K, m_Identity))
{
llarp::LogError("failed to encrypt and sign");
return false;
@ -1260,12 +1262,13 @@ namespace llarp
}
}
// no converstation
return EnsurePathToService(remote,
[](Address, OutboundContext* c) {
if(c)
c->UpdateIntroSet(true);
},
5000, false);
return EnsurePathToService(
remote,
[](Address, OutboundContext* c) {
if(c)
c->UpdateIntroSet(true);
},
5000, false);
}
bool
@ -1491,9 +1494,11 @@ namespace llarp
// compure post handshake session key
// PKE (A, B, N)
SharedSecret sharedSecret;
if(!self->m_LocalIdentity.KeyExchange(self->crypto->dh_client,
sharedSecret, self->remote,
self->frame.N))
using namespace std::placeholders;
path_dh_func dh_client =
std::bind(&Crypto::dh_client, self->crypto, _1, _2, _3, _4);
if(!self->m_LocalIdentity.KeyExchange(dh_client, sharedSecret,
self->remote, self->frame.N))
{
llarp::LogError("failed to derive x25519 shared key component");
}
@ -1726,7 +1731,7 @@ namespace llarp
Endpoint::SendContext::EncryptAndSendTo(llarp_buffer_t payload,
ProtocolType t)
{
auto crypto = m_Endpoint->Router()->crypto;
auto crypto = m_Endpoint->Router()->crypto.get();
SharedSecret shared;
routing::PathTransferMessage msg;
ProtocolFrame& f = msg.T;
@ -1762,7 +1767,7 @@ namespace llarp
m.PutBuffer(payload);
m.tag = f.T;
if(!f.EncryptAndSign(&crypto, m, shared, m_Endpoint->m_Identity))
if(!f.EncryptAndSign(crypto, m, shared, m_Endpoint->m_Identity))
{
llarp::LogError("failed to sign");
return;
@ -1804,7 +1809,7 @@ namespace llarp
llarp::Crypto*
Endpoint::Crypto()
{
return &m_Router->crypto;
return m_Router->crypto.get();
}
llarp_threadpool*

@ -20,6 +20,8 @@ namespace llarp
{
namespace service
{
// foward declare
struct Context;
// forward declare
struct AsyncKeyExchange;
@ -35,7 +37,7 @@ namespace llarp
static const size_t MAX_OUTBOUND_CONTEXT_COUNT = 4;
Endpoint(const std::string& nickname, llarp::Router* r);
Endpoint(const std::string& nickname, llarp::Router* r, Context* parent);
~Endpoint();
void
@ -47,6 +49,20 @@ namespace llarp
virtual void
Tick(llarp_time_t now);
/// return true if we have a resolvable ip address
virtual bool
HasIfAddr() const
{
return false;
}
/// get our ifaddr if it is set
virtual huint32_t
GetIfAddr() const
{
return huint32_t{0};
}
/// router's logic
llarp::Logic*
RouterLogic();
@ -381,6 +397,9 @@ namespace llarp
IntroSetPublished();
protected:
/// parent context that owns this endpoint
Context* const context;
void
RegenAndPublishIntroSet(llarp_time_t now, bool forceRebuild = false);

@ -269,7 +269,11 @@ namespace llarp
}
// PKE (A, B, N)
SharedSecret sharedSecret;
if(!self->m_LocalIdentity.KeyExchange(crypto->dh_server, sharedSecret,
using namespace std::placeholders;
path_dh_func dh_server =
std::bind(&Crypto::dh_server, self->crypto, _1, _2, _3, _4);
if(!self->m_LocalIdentity.KeyExchange(dh_server, sharedSecret,
self->msg->sender, self->frame.N))
{
llarp::LogError("x25519 key exchange failed");

@ -31,13 +31,19 @@ namespace llarp
return b * d.quot;
}
static size_t
Base32DecodeSize(size_t sz)
{
return DecodeSize<5, 8>(sz);
}
template < typename Stack, typename V >
bool
Base32Decode(const Stack& stack, V& value)
{
int tmp = 0, bits = 0;
size_t ret = 0;
size_t len = DecodeSize< 5, 8 >(value.size());
size_t len = Base32DecodeSize(value.size());
size_t outLen = value.size();
for(size_t i = 0; i < len; i++)
{
@ -146,6 +152,68 @@ namespace llarp
return sz == 0;
}
static const char base64_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
template < typename OStream_t >
void
Base64Encode(OStream_t& out, const uint8_t* src, size_t len)
{
size_t i = 0;
size_t j = 0;
uint8_t buf[4] = {0};
uint8_t tmp[3] = {0};
while(len--)
{
tmp[i++] = *(src++);
if(3 == i)
{
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
// encode
for(i = 0; i < 4; ++i)
{
out << base64_table[buf[i]];
}
// reset
i = 0;
}
}
// remainder
if(i > 0)
{
// fill `tmp' with `\0' at most 3 times
for(j = i; j < 3; ++j)
{
tmp[j] = 0;
}
// encode remainder
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
for(j = 0; (j < i + 1); ++j)
{
out << base64_table[buf[j]];
}
// pad
while((i++ < 3))
{
out << '=';
}
}
}
} // namespace llarp
#endif

@ -1,4 +1,4 @@
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <iostream>
@ -6,16 +6,15 @@
namespace llarp
{
struct IdentityKeyTest : public ::testing::Test
struct IdentityKeyTest : public ::testing::Test
{
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
llarp::IdentitySecret seed;
IdentityKeyTest() : crypto(llarp::Crypto::sodium{})
IdentityKeyTest()
{
}
llarp::Crypto*
Crypto()
{
@ -27,15 +26,13 @@ namespace llarp
{
seed.Randomize();
}
};
TEST_F(IdentityKeyTest, TestSeedToSecretKey)
{
SecretKey secret;
ASSERT_TRUE(crypto.seed_to_secretkey(secret, seed));
AlignedBuffer<128> random;
AlignedBuffer< 128 > random;
random.Randomize();
Signature sig;
ASSERT_TRUE(crypto.sign(sig, secret, random.as_buffer()));
@ -47,10 +44,10 @@ namespace llarp
struct PQCryptoTest : public ::testing::Test
{
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
PQKeyPair keys;
PQCryptoTest() : crypto(llarp::Crypto::sodium{})
PQCryptoTest()
{
}

@ -0,0 +1 @@
#include <dht/mock_context.hpp>

@ -0,0 +1,46 @@
#ifndef TEST_LLARP_MOCK_CONTEXT
#define TEST_LLARP_MOCK_CONTEXT
#include <dht/context.hpp>
#include <gmock/gmock.h>
namespace llarp
{
namespace test
{
struct MockContext final : public dht::AbstractContext
{
MOCK_METHOD2(LookupRouter, bool(const RouterID&, RouterLookupHandler));
MOCK_METHOD6(LookupIntroSetRecursive,
void(const service::Address&, const dht::Key_t&, uint64_t,
const dht::Key_t&, uint64_t,
service::IntroSetLookupHandler));
MOCK_METHOD5(LookupIntroSetIterative,
void(const service::Address&, const dht::Key_t&, uint64_t,
const dht::Key_t&, service::IntroSetLookupHandler));
MOCK_METHOD3(
FindRandomIntroSetsWithTagExcluding,
std::set< service::IntroSet >(const service::Tag&, size_t,
const std::set< service::IntroSet >&));
MOCK_METHOD3(DHTSendTo, void(const RouterID&, dht::IMessage*, bool));
MOCK_CONST_METHOD0(Now, llarp_time_t());
MOCK_CONST_METHOD0(Crypto, llarp::Crypto*());
MOCK_CONST_METHOD0(GetRouter, llarp::Router*());
MOCK_CONST_METHOD0(OurKey, const dht::Key_t&());
MOCK_CONST_METHOD0(Nodes, dht::Bucket< dht::RCNode >*());
};
} // namespace test
} // namespace llarp
#endif

@ -0,0 +1,105 @@
#include <dht/explorenetworkjob.hpp>
#include <dht/messages/findrouter.hpp>
#include <dht/mock_context.hpp>
#include <test_util.hpp>
#include <gtest/gtest.h>
using namespace llarp;
using namespace ::testing;
using test::makeBuf;
struct TestDhtExploreNetworkJob : public ::testing::Test
{
RouterID peer;
test::MockContext context;
dht::ExploreNetworkJob exploreNetworkJob;
TestDhtExploreNetworkJob()
: peer(makeBuf< RouterID >(0x01)), exploreNetworkJob(peer, &context)
{
}
};
TEST_F(TestDhtExploreNetworkJob, validate)
{
const RouterID other = makeBuf< RouterID >(0x02);
ASSERT_TRUE(exploreNetworkJob.Validate(other));
}
TEST_F(TestDhtExploreNetworkJob, get_next_peer)
{
dht::Key_t key = makeBuf< dht::Key_t >(0x02);
std::set< dht::Key_t > exclude;
ASSERT_FALSE(exploreNetworkJob.GetNextPeer(key, exclude));
}
TEST_F(TestDhtExploreNetworkJob, do_next)
{
const dht::Key_t key = makeBuf< dht::Key_t >(0x02);
ASSERT_NO_THROW(exploreNetworkJob.DoNextRequest(key));
}
TEST_F(TestDhtExploreNetworkJob, start)
{
// Verify input arguments are passed correctly.
// The actual logic is inside the `dht::AbstractContext` implementation.
const auto txKey = makeBuf< dht::Key_t >(0x02);
uint64_t txId = 4;
dht::TXOwner txOwner(txKey, txId);
// clang-format off
EXPECT_CALL(context, DHTSendTo(
Eq(txKey.as_array()),
WhenDynamicCastTo< dht::FindRouterMessage* >(NotNull()),
true)
).Times(1);
// clang-format off
ASSERT_NO_THROW(exploreNetworkJob.Start(txOwner));
}
TEST_F(TestDhtExploreNetworkJob, send_reply)
{
// Concerns:
// - Empty collection
// - Lookup router fails (returns false)
// - Number of calls matches collection size
{
exploreNetworkJob.valuesFound.clear();
EXPECT_CALL(context, LookupRouter(_, _)).Times(0);
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
}
{
exploreNetworkJob.valuesFound.clear();
exploreNetworkJob.valuesFound.push_back(makeBuf<RouterID>(0x00));
exploreNetworkJob.valuesFound.push_back(makeBuf<RouterID>(0x01));
exploreNetworkJob.valuesFound.push_back(makeBuf<RouterID>(0x02));
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
EXPECT_CALL(context, LookupRouter(Ne(makeBuf<RouterID>(0x01)), _)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(context, LookupRouter(Eq(makeBuf<RouterID>(0x01)), _)).WillOnce(Return(false));
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
}
{
exploreNetworkJob.valuesFound.clear();
exploreNetworkJob.valuesFound.push_back(makeBuf<RouterID>(0x00));
exploreNetworkJob.valuesFound.push_back(makeBuf<RouterID>(0x01));
exploreNetworkJob.valuesFound.push_back(makeBuf<RouterID>(0x02));
EXPECT_CALL(context, GetRouter()).WillOnce(Return(nullptr));
EXPECT_CALL(context, LookupRouter(_, _)).Times(3).WillRepeatedly(Return(true));
ASSERT_NO_THROW(exploreNetworkJob.SendReply());
}
}

@ -0,0 +1,170 @@
#include <dht/tx.hpp>
#include <test_util.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace llarp;
using namespace ::testing;
using llarp::test::makeBuf;
// Mock implementation of TX.
struct TestTx final : public dht::TX< dht::Key_t, std::string >
{
TestTx(const dht::TXOwner& asker, const dht::Key_t& k,
dht::AbstractContext* p)
: dht::TX< dht::Key_t, std::string >(asker, k, p)
{
}
MOCK_CONST_METHOD1(Validate, bool(const std::string&));
MOCK_METHOD1(Start, void(const dht::TXOwner&));
MOCK_METHOD2(GetNextPeer, bool(dht::Key_t&, const std::set< dht::Key_t >&));
MOCK_METHOD1(DoNextRequest, void(const dht::Key_t&));
MOCK_METHOD0(SendReply, void());
};
struct TestDhtTx : public Test
{
dht::TXOwner asker;
dht::Key_t key;
TestTx tx;
TestDhtTx() : tx(asker, key, nullptr)
{
}
};
TEST_F(TestDhtTx, on_found)
{
// Concerns
// - Validate returns true
// - Repeated call on success
// - Validate returns false
// - Repeated call on failure
// - Repeated call on success after failure
const auto key = makeBuf< dht::Key_t >(0x00);
std::string val("good value");
// Validate returns true
{
EXPECT_CALL(tx, Validate(val)).WillOnce(Return(true));
tx.OnFound(key, val);
ASSERT_THAT(tx.peersAsked, Contains(key));
ASSERT_THAT(tx.valuesFound, Contains(val));
}
// Repeated call on success
{
EXPECT_CALL(tx, Validate(val)).WillOnce(Return(true));
tx.OnFound(key, val);
ASSERT_THAT(tx.peersAsked, Contains(key));
ASSERT_THAT(tx.valuesFound, Contains(val));
}
const auto key1 = makeBuf< dht::Key_t >(0x01);
std::string badVal("bad value");
// Validate returns false
{
EXPECT_CALL(tx, Validate(badVal)).WillOnce(Return(false));
tx.OnFound(key1, badVal);
ASSERT_THAT(tx.peersAsked, Contains(key1));
ASSERT_THAT(tx.valuesFound, Not(Contains(badVal)));
}
// Repeated call on failure
{
EXPECT_CALL(tx, Validate(badVal)).WillOnce(Return(false));
tx.OnFound(key1, badVal);
ASSERT_THAT(tx.peersAsked, Contains(key1));
ASSERT_THAT(tx.valuesFound, Not(Contains(badVal)));
}
// Repeated call on success after failure
{
EXPECT_CALL(tx, Validate(badVal)).WillOnce(Return(true));
tx.OnFound(key1, badVal);
ASSERT_THAT(tx.peersAsked, Contains(key1));
ASSERT_THAT(tx.valuesFound, Contains(badVal));
}
}
TEST_F(TestDhtTx, ask_next_peer)
{
// Concerns:
// - GetNextPeer fails
// - Next Peer is not closer
// - next ptr is null
// - next ptr is not null
const auto key0 = makeBuf< dht::Key_t >(0x00);
const auto key1 = makeBuf< dht::Key_t >(0x01);
const auto key2 = makeBuf< dht::Key_t >(0x02);
{
// GetNextPeer fails
EXPECT_CALL(tx, GetNextPeer(_, _)).WillOnce(Return(false));
EXPECT_CALL(tx, DoNextRequest(key1)).Times(0);
ASSERT_FALSE(tx.AskNextPeer(key0, {}));
ASSERT_THAT(tx.peersAsked, Contains(key0));
tx.peersAsked.clear();
}
{
// Next Peer is not closer
EXPECT_CALL(tx, GetNextPeer(_, _))
.WillOnce(DoAll(SetArgReferee< 0 >(key1), Return(true)));
EXPECT_CALL(tx, DoNextRequest(key1)).Times(0);
ASSERT_FALSE(tx.AskNextPeer(key0, {}));
ASSERT_THAT(tx.peersAsked, Contains(key0));
tx.peersAsked.clear();
}
{
// next ptr is null
EXPECT_CALL(tx, GetNextPeer(_, _))
.WillOnce(DoAll(SetArgReferee< 0 >(key1), Return(true)));
EXPECT_CALL(tx, DoNextRequest(key1)).Times(1);
ASSERT_TRUE(tx.AskNextPeer(key2, {}));
ASSERT_THAT(tx.peersAsked, Contains(key2));
tx.peersAsked.clear();
}
{
// next ptr is not null
EXPECT_CALL(tx, GetNextPeer(_, _)).Times(0);
EXPECT_CALL(tx, DoNextRequest(key1)).Times(1);
auto ptr = std::make_unique< dht::Key_t >(key1);
ASSERT_TRUE(tx.AskNextPeer(key2, ptr));
ASSERT_THAT(tx.peersAsked, Contains(key2));
tx.peersAsked.clear();
}
}

@ -4,6 +4,8 @@
#include <messages/link_intro.hpp>
#include <messages/discard.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <gtest/gtest.h>
struct LinkLayerTest : public ::testing::Test
@ -97,7 +99,7 @@ struct LinkLayerTest : public ::testing::Test
}
};
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
Context Alice;
Context Bob;
@ -109,11 +111,7 @@ struct LinkLayerTest : public ::testing::Test
llarp_time_t oldRCLifetime;
LinkLayerTest()
: crypto(llarp::Crypto::sodium{})
, Alice(crypto)
, Bob(crypto)
, netLoop(nullptr)
LinkLayerTest() : Alice(crypto), Bob(crypto), netLoop(nullptr)
{
}

@ -1,17 +1,19 @@
#include <gtest/gtest.h>
#include <messages/exit.hpp>
#include <crypto/crypto.hpp>
#include <messages/exit.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <gtest/gtest.h>
using ObtainExitMessage = llarp::routing::ObtainExitMessage;
class ObtainExitTest : public ::testing::Test
{
public:
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
llarp::SecretKey alice;
ObtainExitTest() : crypto(llarp::Crypto::sodium{})
ObtainExitTest()
{
}

@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <service/address.hpp>
#include <gtest/gtest.h>
struct ServiceAddressTest : public ::testing::Test
{
const std::string snode =

@ -1,18 +1,19 @@
#include <gtest/gtest.h>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <path/path.hpp>
#include <service/address.hpp>
#include <service/Identity.hpp>
#include <service/IntroSet.hpp>
#include <util/time.hpp>
#include <gtest/gtest.h>
struct HiddenServiceTest : public ::testing::Test
{
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
llarp::service::Identity ident;
HiddenServiceTest() : crypto(llarp::Crypto::sodium{})
HiddenServiceTest()
{
}

@ -1,6 +1,7 @@
#include <libabyss.hpp>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <ev/ev.h>
#include <net/net.hpp>
#include <util/threading.hpp>
@ -9,7 +10,7 @@
struct AbyssTestBase : public ::testing::Test
{
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
llarp_threadpool* threadpool = nullptr;
llarp_ev_loop* loop = nullptr;
std::unique_ptr< llarp::Logic > logic;
@ -18,7 +19,7 @@ struct AbyssTestBase : public ::testing::Test
const std::string method = "test.method";
bool called = false;
AbyssTestBase() : crypto(llarp::Crypto::sodium{})
AbyssTestBase()
{
}

@ -1,6 +1,7 @@
#include <crypto/encrypted_frame.hpp>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <messages/relay_commit.hpp>
#include <gtest/gtest.h>
@ -13,10 +14,10 @@ using LRCR = llarp::LR_CommitRecord;
class FrameTest : public ::testing::Test
{
public:
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
SecretKey alice, bob;
FrameTest() : crypto(llarp::Crypto::sodium{})
FrameTest()
{
}

@ -1,6 +1,7 @@
#include <router/router.hpp>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <functional>
#include <random>
@ -13,11 +14,11 @@ using FindOrCreateFunc = std::function< bool(llarp::Crypto *, const fs::path &,
struct FindOrCreate : public ::testing::TestWithParam< FindOrCreateFunc >
{
FindOrCreate() : crypto(llarp::Crypto::sodium{})
FindOrCreate()
{
}
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
};
// Concerns

@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <router_contact.hpp>
static const byte_t DEF_VALUE[] = "unittest";
@ -10,8 +11,7 @@ struct RCTest : public ::testing::Test
using RC_t = llarp::RouterContact;
using SecKey_t = llarp::SecretKey;
RCTest()
: crypto(llarp::Crypto::sodium{}), oldval(llarp::NetID::DefaultValue())
RCTest() : oldval(llarp::NetID::DefaultValue())
{
llarp::NetID::DefaultValue() = llarp::NetID(DEF_VALUE);
}
@ -21,7 +21,7 @@ struct RCTest : public ::testing::Test
llarp::NetID::DefaultValue() = oldval;
}
llarp::Crypto crypto;
llarp::sodium::CryptoLibSodium crypto;
const llarp::NetID oldval;
};

@ -2,6 +2,7 @@
#define TEST_UTIL_HPP
#include <util/fs.hpp>
#include <util/types.hpp>
namespace llarp
{
@ -10,6 +11,15 @@ namespace llarp
std::string
randFilename();
template < typename Buf >
Buf
makeBuf(byte_t val)
{
Buf b;
b.Fill(val);
return b;
}
struct FileGuard
{
const fs::path &p;

Loading…
Cancel
Save