mirror of
https://github.com/oxen-io/lokinet
synced 2023-12-14 06:53:00 +01:00
Merge pull request #2218 from dr7ana/rc-bencode
RC Refactor + (some) BT-encode fixes
This commit is contained in:
commit
1939ba0b3d
|
@ -41,7 +41,7 @@ if(APPLE)
|
|||
set(LOKINET_APPLE_BUILD 5)
|
||||
endif()
|
||||
|
||||
set(RELEASE_MOTTO "Our Lord And Savior" CACHE STRING "Release motto")
|
||||
set(LOKINET_RELEASE_MOTTO "Anonymous, decentralized, IP-based overlay network" CACHE STRING "Release motto")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ main(int argc, char* argv[])
|
|||
#else
|
||||
cpr::Get(
|
||||
cpr::Url{bootstrap_url},
|
||||
cpr::Header{{"User-Agent", std::string{llarp::VERSION_FULL}}},
|
||||
cpr::Header{{"User-Agent", std::string{llarp::LOKINET_VERSION_FULL}}},
|
||||
cpr::Ssl(cpr::ssl::CaPath{X509_get_default_cert_dir()}));
|
||||
#endif
|
||||
if (resp.status_code != 200)
|
||||
|
|
|
@ -403,7 +403,7 @@ namespace
|
|||
{
|
||||
if (options.version)
|
||||
{
|
||||
std::cout << llarp::VERSION_FULL << std::endl;
|
||||
std::cout << llarp::LOKINET_VERSION_FULL << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -548,7 +548,8 @@ namespace
|
|||
static void
|
||||
run_main_context(std::optional<fs::path> confFile, const llarp::RuntimeOptions opts)
|
||||
{
|
||||
llarp::LogInfo(fmt::format("starting up {} {}", llarp::VERSION_FULL, llarp::RELEASE_MOTTO));
|
||||
llarp::LogInfo(fmt::format(
|
||||
"starting up {} {}", llarp::LOKINET_VERSION_FULL, llarp::LOKINET_RELEASE_MOTTO));
|
||||
try
|
||||
{
|
||||
std::shared_ptr<llarp::Config> conf;
|
||||
|
|
|
@ -91,7 +91,6 @@ add_dependencies(lokinet-utils genversion)
|
|||
lokinet_add_library(lokinet-time-place
|
||||
ev/ev.cpp
|
||||
ev/libuv.cpp
|
||||
net/exit_info.cpp # only router_contact
|
||||
net/ip.cpp
|
||||
net/ip_address.cpp
|
||||
net/ip_packet.cpp
|
||||
|
@ -99,6 +98,8 @@ lokinet_add_library(lokinet-time-place
|
|||
net/net_int.cpp
|
||||
net/sock_addr.cpp
|
||||
router_contact.cpp
|
||||
router_contact_local.cpp
|
||||
router_contact_remote.cpp
|
||||
router_id.cpp
|
||||
router_version.cpp # to be deleted shortly
|
||||
service/address.cpp
|
||||
|
|
|
@ -9,17 +9,18 @@ namespace llarp
|
|||
load_bootstrap_fallbacks()
|
||||
{
|
||||
std::unordered_map<std::string, BootstrapList> fallbacks;
|
||||
using init_list = std::initializer_list<std::pair<std::string, std::string_view>>;
|
||||
// clang-format off
|
||||
for (const auto& [network, bootstrap] : init_list{
|
||||
|
||||
for (const auto& [network, bootstrap] : std::initializer_list<std::pair<std::string, std::string_view>>{
|
||||
@BOOTSTRAP_FALLBACKS@
|
||||
})
|
||||
// clang-format on
|
||||
{
|
||||
llarp_buffer_t buf{bootstrap.data(), bootstrap.size()};
|
||||
if (network != RouterContact::ACTIVE_NETID)
|
||||
continue;
|
||||
|
||||
auto& bsl = fallbacks[network];
|
||||
bsl.BDecode(&buf);
|
||||
bsl.bt_decode(bootstrap);
|
||||
}
|
||||
|
||||
return fallbacks;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -6,66 +6,65 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
void
|
||||
BootstrapList::Clear()
|
||||
bool
|
||||
BootstrapList::bt_decode(std::string_view buf)
|
||||
{
|
||||
clear();
|
||||
try
|
||||
{
|
||||
oxenc::bt_list_consumer btlc{buf};
|
||||
|
||||
while (not btlc.is_finished())
|
||||
emplace(btlc.consume_dict_consumer());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log::warning(logcat, "Unable to decode bootstrap RemoteRC");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BootstrapList::BDecode(llarp_buffer_t* buf)
|
||||
std::string_view
|
||||
BootstrapList::bt_encode() const
|
||||
{
|
||||
return bencode_read_list(
|
||||
[&](llarp_buffer_t* b, bool more) -> bool {
|
||||
if (more)
|
||||
{
|
||||
RouterContact rc{};
|
||||
if (not rc.BDecode(b))
|
||||
{
|
||||
LogError("invalid rc in bootstrap list: ", llarp::buffer_printer{*b});
|
||||
return false;
|
||||
}
|
||||
emplace(std::move(rc));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
buf);
|
||||
}
|
||||
oxenc::bt_list_producer btlp{};
|
||||
|
||||
bool
|
||||
BootstrapList::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
return BEncodeWriteList(begin(), end(), buf);
|
||||
for (const auto& it : *this)
|
||||
btlp.append(it.view());
|
||||
|
||||
return btlp.view();
|
||||
}
|
||||
|
||||
void
|
||||
BootstrapList::AddFromFile(fs::path fpath)
|
||||
BootstrapList::read_from_file(const fs::path& fpath)
|
||||
{
|
||||
bool isListFile = false;
|
||||
|
||||
if (std::ifstream inf(fpath.c_str(), std::ios::binary); inf.is_open())
|
||||
{
|
||||
std::ifstream inf(fpath.c_str(), std::ios::binary);
|
||||
if (inf.is_open())
|
||||
{
|
||||
const char ch = inf.get();
|
||||
isListFile = ch == 'l';
|
||||
}
|
||||
const char ch = inf.get();
|
||||
isListFile = ch == 'l';
|
||||
}
|
||||
|
||||
if (isListFile)
|
||||
{
|
||||
if (not BDecodeReadFile(fpath, *this))
|
||||
auto content = util::file_to_string(fpath);
|
||||
|
||||
if (not bt_decode(content))
|
||||
{
|
||||
throw std::runtime_error{fmt::format("failed to read bootstrap list file '{}'", fpath)};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RouterContact rc;
|
||||
if (not rc.Read(fpath))
|
||||
RemoteRC rc;
|
||||
if (not rc.read(fpath))
|
||||
{
|
||||
throw std::runtime_error{
|
||||
fmt::format("failed to decode bootstrap RC, file='{}', rc={}", fpath, rc)};
|
||||
fmt::format("failed to decode bootstrap RC, file='{}', rc={}", fpath, rc.to_string())};
|
||||
}
|
||||
this->insert(rc);
|
||||
insert(rc);
|
||||
}
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -9,19 +9,22 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
struct BootstrapList final : public std::set<RouterContact>
|
||||
struct BootstrapList final : public std::set<RemoteRC>
|
||||
{
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf);
|
||||
bt_decode(std::string_view buf);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
std::string_view
|
||||
bt_encode() const;
|
||||
|
||||
void
|
||||
AddFromFile(fs::path fpath);
|
||||
read_from_file(const fs::path& fpath);
|
||||
|
||||
void
|
||||
Clear();
|
||||
clear_list()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, BootstrapList>
|
||||
|
|
|
@ -10,17 +10,19 @@ namespace llarp
|
|||
load_bootstrap_fallbacks()
|
||||
{
|
||||
std::unordered_map<std::string, BootstrapList> fallbacks;
|
||||
using init_list = std::initializer_list<std::pair<std::string, std::string_view>>;
|
||||
// clang-format off
|
||||
for (const auto& [network, bootstrap] : init_list{
|
||||
//
|
||||
})
|
||||
// clang-format on
|
||||
|
||||
for (const auto& [network, bootstrap] :
|
||||
std::initializer_list<std::pair<std::string, std::string_view>>{
|
||||
//
|
||||
})
|
||||
{
|
||||
llarp_buffer_t buf{bootstrap.data(), bootstrap.size()};
|
||||
if (network != RouterContact::ACTIVE_NETID)
|
||||
continue;
|
||||
|
||||
auto& bsl = fallbacks[network];
|
||||
bsl.BDecode(&buf);
|
||||
bsl.bt_decode(bootstrap);
|
||||
}
|
||||
|
||||
return fallbacks;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -58,14 +58,15 @@ namespace llarp
|
|||
conf.defineOption<std::string>(
|
||||
"router",
|
||||
"netid",
|
||||
Default{llarp::DEFAULT_NETID},
|
||||
Default{llarp::LOKINET_DEFAULT_NETID},
|
||||
Comment{
|
||||
"Network ID; this is '"s + llarp::DEFAULT_NETID + "' for mainnet, 'gamma' for testnet.",
|
||||
"Network ID; this is '"s + llarp::LOKINET_DEFAULT_NETID
|
||||
+ "' for mainnet, 'gamma' for testnet.",
|
||||
},
|
||||
[this](std::string arg) {
|
||||
if (arg.size() > NetID::size())
|
||||
if (arg.size() > NETID_SIZE)
|
||||
throw std::invalid_argument{
|
||||
fmt::format("netid is too long, max length is {}", NetID::size())};
|
||||
fmt::format("netid is too long, max length is {}", NETID_SIZE)};
|
||||
|
||||
m_netId = std::move(arg);
|
||||
});
|
||||
|
@ -1321,7 +1322,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
PeerSelectionConfig::Acceptable(const std::set<RouterContact>& rcs) const
|
||||
PeerSelectionConfig::Acceptable(const std::set<RemoteRC>& rcs) const
|
||||
{
|
||||
if (m_UniqueHopsNetmaskSize == 0)
|
||||
return true;
|
||||
|
@ -1329,7 +1330,7 @@ namespace llarp
|
|||
std::set<IPRange> seenRanges;
|
||||
for (const auto& hop : rcs)
|
||||
{
|
||||
const auto network_addr = net::In6ToHUInt(hop.addr.in6().sin6_addr) & netmask;
|
||||
const auto network_addr = net::In6ToHUInt(hop.addr6()->in6().sin6_addr) & netmask;
|
||||
if (auto [it, inserted] = seenRanges.emplace(network_addr, netmask); not inserted)
|
||||
{
|
||||
return false;
|
||||
|
@ -1444,7 +1445,7 @@ namespace llarp
|
|||
{
|
||||
try
|
||||
{
|
||||
ini = util::slurp_file(*fname);
|
||||
ini = util::file_to_string(*fname);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
|
@ -1529,7 +1530,7 @@ namespace llarp
|
|||
// open a filestream
|
||||
try
|
||||
{
|
||||
util::dump_file(confFile, confStr);
|
||||
util::buffer_to_file(confFile, confStr);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace llarp
|
|||
|
||||
/// return true if this set of router contacts is acceptable against this config
|
||||
bool
|
||||
Acceptable(const std::set<RouterContact>& hops) const;
|
||||
Acceptable(const std::set<RemoteRC>& hops) const;
|
||||
};
|
||||
|
||||
struct NetworkConfig
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace llarp
|
|||
{
|
||||
try
|
||||
{
|
||||
m_Data = util::slurp_file(fname);
|
||||
m_Data = util::file_to_string(fname);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
|
@ -51,8 +51,8 @@ namespace llarp
|
|||
m_encKeyPath = deriveFile(our_enc_key_filename, config.router.m_encryptionKeyFile);
|
||||
m_transportKeyPath = deriveFile(our_transport_key_filename, config.router.m_transportKeyFile);
|
||||
|
||||
RouterContact rc;
|
||||
bool exists = rc.Read(m_rcPath);
|
||||
RemoteRC rc;
|
||||
bool exists = rc.read(m_rcPath);
|
||||
if (not exists and not genIfAbsent)
|
||||
{
|
||||
LogError("Could not read RouterContact at path ", m_rcPath);
|
||||
|
@ -61,7 +61,7 @@ namespace llarp
|
|||
|
||||
// we need to back up keys if our self.signed doesn't appear to have a
|
||||
// valid signature
|
||||
m_needBackup = (isSNode and not rc.VerifySignature());
|
||||
m_needBackup = (isSNode and not rc.verify());
|
||||
|
||||
// if our RC file can't be verified, assume it is out of date (e.g. uses
|
||||
// older encryption) and needs to be regenerated. before doing so, backup
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
namespace llarp
|
||||
{
|
||||
// clang-format off
|
||||
const std::array<uint16_t, 3> VERSION{{@lokinet_VERSION_MAJOR@, @lokinet_VERSION_MINOR@, @lokinet_VERSION_PATCH@}};
|
||||
const std::array<uint64_t, 4> ROUTER_VERSION{{llarp::constants::proto_version, @lokinet_VERSION_MAJOR@, @lokinet_VERSION_MINOR@, @lokinet_VERSION_PATCH@}};
|
||||
const char* const VERSION_TAG = "@VERSIONTAG@";
|
||||
const char* const VERSION_FULL = "lokinet-@lokinet_VERSION_MAJOR@.@lokinet_VERSION_MINOR@.@lokinet_VERSION_PATCH@-@VERSIONTAG@";
|
||||
const std::array<uint16_t, 3> LOKINET_VERSION{{@lokinet_VERSION_MAJOR@, @lokinet_VERSION_MINOR@, @lokinet_VERSION_PATCH@}};
|
||||
const char* const LOKINET_VERSION_TAG = "@VERSIONTAG@";
|
||||
const char* const LOKINET_VERSION_FULL = "lokinet-@lokinet_VERSION_MAJOR@.@lokinet_VERSION_MINOR@.@lokinet_VERSION_PATCH@-@LOKINET_VERSION_TAG@";
|
||||
|
||||
const char* const RELEASE_MOTTO = "@RELEASE_MOTTO@";
|
||||
const char* const DEFAULT_NETID = "lokinet";
|
||||
const char* const LOKINET_RELEASE_MOTTO = "@RELEASE_MOTTO@";
|
||||
const char* const LOKINET_DEFAULT_NETID = "lokinet";
|
||||
// clang-format on
|
||||
} // namespace llarp
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
namespace llarp
|
||||
{
|
||||
// Given a full lokinet version of: lokinet-1.2.3-abc these are:
|
||||
extern const std::array<uint16_t, 3> VERSION; // [1, 2, 3]
|
||||
extern const std::array<uint64_t, 4> ROUTER_VERSION; // [proto, 1, 2, 3]
|
||||
extern const char* const VERSION_TAG; // "abc"
|
||||
extern const char* const VERSION_FULL; // "lokinet-1.2.3-abc"
|
||||
extern const std::array<uint16_t, 3> LOKINET_VERSION;
|
||||
extern const char* const LOKINET_VERSION_TAG;
|
||||
extern const char* const LOKINET_VERSION_FULL;
|
||||
|
||||
extern const char* const RELEASE_MOTTO;
|
||||
extern const char* const DEFAULT_NETID;
|
||||
extern const char* const LOKINET_RELEASE_MOTTO;
|
||||
extern const char* const LOKINET_DEFAULT_NETID;
|
||||
} // namespace llarp
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = llarp::log::Cat("llarp-context");
|
||||
|
||||
bool
|
||||
Context::CallSafe(std::function<void(void)> f)
|
||||
{
|
||||
|
@ -59,7 +57,8 @@ namespace llarp
|
|||
throw std::runtime_error("Cannot call Setup() on context without a Config");
|
||||
|
||||
if (opts.showBanner)
|
||||
llarp::LogInfo(fmt::format("{} {}", llarp::VERSION_FULL, llarp::RELEASE_MOTTO));
|
||||
llarp::LogInfo(
|
||||
fmt::format("{} {}", llarp::LOKINET_VERSION_FULL, llarp::LOKINET_RELEASE_MOTTO));
|
||||
|
||||
if (!loop)
|
||||
{
|
||||
|
@ -162,7 +161,7 @@ namespace llarp
|
|||
#ifndef _WIN32
|
||||
if (sig == SIGUSR1)
|
||||
{
|
||||
if (router and not router->IsServiceNode())
|
||||
if (router and not router->is_service_node())
|
||||
{
|
||||
LogInfo("SIGUSR1: resetting network state");
|
||||
router->Thaw();
|
||||
|
|
|
@ -273,6 +273,14 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
crypto::verify(const PubKey& pub, ustring_view data, ustring_view sig)
|
||||
{
|
||||
return (pub.size() == 32 && sig.size() == 64)
|
||||
? crypto_sign_verify_detached(sig.data(), data.data(), data.size(), pub.data()) != -1
|
||||
: false;
|
||||
}
|
||||
|
||||
bool
|
||||
crypto::verify(const PubKey& pub, uint8_t* buf, size_t size, const Signature& sig)
|
||||
{
|
||||
|
@ -428,11 +436,6 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
crypto::seed_to_secretkey(llarp::SecretKey& secret, const llarp::IdentitySecret& seed)
|
||||
{
|
||||
return crypto_sign_ed25519_seed_keypair(secret.data() + 32, secret.data(), seed.data()) != -1;
|
||||
}
|
||||
void
|
||||
crypto::randomize(uint8_t* buf, size_t len)
|
||||
{
|
||||
|
@ -517,19 +520,19 @@ namespace llarp
|
|||
#endif
|
||||
|
||||
const byte_t*
|
||||
seckey_topublic(const SecretKey& sec)
|
||||
seckey_to_pubkey(const SecretKey& sec)
|
||||
{
|
||||
return sec.data() + 32;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_public(const PQKeyPair& k)
|
||||
pq_keypair_to_pubkey(const PQKeyPair& k)
|
||||
{
|
||||
return k.data() + PQ_SECRETKEYSIZE;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_secret(const PQKeyPair& k)
|
||||
pq_keypair_to_seckey(const PQKeyPair& k)
|
||||
{
|
||||
return k.data();
|
||||
}
|
||||
|
|
|
@ -64,6 +64,8 @@ namespace llarp
|
|||
sign(Signature&, const PrivateKey&, uint8_t* buf, size_t size);
|
||||
/// ed25519 verify
|
||||
bool
|
||||
verify(const PubKey&, ustring_view, ustring_view);
|
||||
bool
|
||||
verify(const PubKey&, uint8_t*, size_t, const Signature&);
|
||||
bool verify(ustring_view, ustring_view, ustring_view);
|
||||
bool
|
||||
|
@ -87,9 +89,6 @@ namespace llarp
|
|||
uint64_t key_n,
|
||||
const AlignedBuffer<32>* hash = nullptr);
|
||||
|
||||
/// seed to secretkey
|
||||
bool
|
||||
seed_to_secretkey(llarp::SecretKey&, const llarp::IdentitySecret&);
|
||||
/// randomize buffer
|
||||
void
|
||||
randomize(uint8_t* buf, size_t len);
|
||||
|
@ -124,13 +123,13 @@ namespace llarp
|
|||
randint();
|
||||
|
||||
const byte_t*
|
||||
seckey_topublic(const SecretKey& secret);
|
||||
seckey_to_pubkey(const SecretKey& secret);
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_public(const PQKeyPair& keypair);
|
||||
pq_keypair_to_pubkey(const PQKeyPair& keypair);
|
||||
|
||||
const byte_t*
|
||||
pq_keypair_to_secret(const PQKeyPair& keypair);
|
||||
pq_keypair_to_seckey(const PQKeyPair& keypair);
|
||||
|
||||
/// rng type that uses llarp::randint(), which is cryptographically secure
|
||||
struct CSRNG
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "types.hpp"
|
||||
|
||||
#include <llarp/router_id.hpp>
|
||||
#include <llarp/util/buffer.hpp>
|
||||
#include <llarp/util/file.hpp>
|
||||
|
||||
|
@ -32,6 +33,30 @@ namespace llarp
|
|||
return oxenc::to_hex(begin(), end());
|
||||
}
|
||||
|
||||
PubKey::operator RouterID() const
|
||||
{
|
||||
return {as_array()};
|
||||
}
|
||||
|
||||
PubKey&
|
||||
PubKey::operator=(const byte_t* ptr)
|
||||
{
|
||||
std::copy(ptr, ptr + SIZE, begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const PubKey& lhs, const PubKey& rhs)
|
||||
{
|
||||
return lhs.as_array() == rhs.as_array();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const PubKey& lhs, const RouterID& rhs)
|
||||
{
|
||||
return lhs.as_array() == rhs.as_array();
|
||||
}
|
||||
|
||||
bool
|
||||
SecretKey::LoadFromFile(const fs::path& fname)
|
||||
{
|
||||
|
@ -39,7 +64,7 @@ namespace llarp
|
|||
std::array<byte_t, 128> tmp;
|
||||
try
|
||||
{
|
||||
sz = util::slurp_file(fname, tmp.data(), tmp.size());
|
||||
sz = util::file_to_buffer(fname, tmp.data(), tmp.size());
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
|
@ -93,67 +118,17 @@ namespace llarp
|
|||
bool
|
||||
SecretKey::SaveToFile(const fs::path& fname) const
|
||||
{
|
||||
std::string tmp(128, 0);
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (!bt_encode(&buf))
|
||||
return false;
|
||||
auto bte = bt_encode();
|
||||
|
||||
tmp.resize(buf.cur - buf.base);
|
||||
try
|
||||
{
|
||||
util::dump_file(fname, tmp);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IdentitySecret::LoadFromFile(const fs::path& fname)
|
||||
{
|
||||
std::array<byte_t, SIZE> buf;
|
||||
size_t sz;
|
||||
try
|
||||
{
|
||||
sz = util::slurp_file(fname, buf.data(), buf.size());
|
||||
util::buffer_to_file(fname, bte);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
llarp::LogError("failed to load service node seed: ", e.what());
|
||||
return false;
|
||||
}
|
||||
if (sz != SIZE)
|
||||
{
|
||||
llarp::LogError("service node seed size invalid: ", sz, " != ", SIZE);
|
||||
return false;
|
||||
}
|
||||
std::copy(buf.begin(), buf.end(), begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
byte_t*
|
||||
Signature::Lo()
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
Signature::Lo() const
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
byte_t*
|
||||
Signature::Hi()
|
||||
{
|
||||
return data() + 32;
|
||||
}
|
||||
|
||||
const byte_t*
|
||||
Signature::Hi() const
|
||||
{
|
||||
return data() + 32;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "constants.hpp"
|
||||
|
||||
#include <llarp/router_id.hpp>
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/fs.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
@ -15,7 +14,9 @@ namespace llarp
|
|||
using SharedSecret = AlignedBuffer<SHAREDKEYSIZE>;
|
||||
using KeyExchangeNonce = AlignedBuffer<32>;
|
||||
|
||||
struct PubKey final : public AlignedBuffer<PUBKEYSIZE>
|
||||
struct RouterID;
|
||||
|
||||
struct PubKey : public AlignedBuffer<PUBKEYSIZE>
|
||||
{
|
||||
PubKey() = default;
|
||||
|
||||
|
@ -37,36 +38,17 @@ namespace llarp
|
|||
static PubKey
|
||||
from_string(const std::string& s);
|
||||
|
||||
operator RouterID() const
|
||||
{
|
||||
return {as_array()};
|
||||
}
|
||||
operator RouterID() const;
|
||||
|
||||
PubKey&
|
||||
operator=(const byte_t* ptr)
|
||||
{
|
||||
std::copy(ptr, ptr + SIZE, begin());
|
||||
return *this;
|
||||
}
|
||||
operator=(const byte_t* ptr);
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator==(const PubKey& lhs, const PubKey& rhs)
|
||||
{
|
||||
return lhs.as_array() == rhs.as_array();
|
||||
}
|
||||
bool
|
||||
operator==(const PubKey& lhs, const PubKey& rhs);
|
||||
|
||||
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();
|
||||
}
|
||||
bool
|
||||
operator==(const PubKey& lhs, const RouterID& rhs);
|
||||
|
||||
struct PrivateKey;
|
||||
|
||||
|
@ -161,58 +143,24 @@ namespace llarp
|
|||
toPublic(PubKey& pubkey) const;
|
||||
};
|
||||
|
||||
/// IdentitySecret is a secret key from a service node secret seed
|
||||
struct IdentitySecret final : public AlignedBuffer<32>
|
||||
{
|
||||
IdentitySecret() : AlignedBuffer<32>()
|
||||
{}
|
||||
|
||||
/// no copy constructor
|
||||
explicit IdentitySecret(const IdentitySecret&) = delete;
|
||||
// no byte data constructor
|
||||
explicit IdentitySecret(const byte_t*) = delete;
|
||||
|
||||
/// load service node seed from file
|
||||
bool
|
||||
LoadFromFile(const fs::path& fname);
|
||||
|
||||
std::string_view
|
||||
ToString() const
|
||||
{
|
||||
return "[IdentitySecret]";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<PubKey> = true;
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<SecretKey> = true;
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<PrivateKey> = true;
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<IdentitySecret> = true;
|
||||
|
||||
using ShortHash = AlignedBuffer<SHORTHASHSIZE>;
|
||||
using LongHash = AlignedBuffer<HASHSIZE>;
|
||||
|
||||
struct Signature final : public AlignedBuffer<SIGSIZE>
|
||||
{
|
||||
byte_t*
|
||||
Hi();
|
||||
|
||||
const byte_t*
|
||||
Hi() const;
|
||||
|
||||
byte_t*
|
||||
Lo();
|
||||
|
||||
const byte_t*
|
||||
Lo() const;
|
||||
//
|
||||
};
|
||||
|
||||
using TunnelNonce = AlignedBuffer<TUNNONCESIZE>;
|
||||
using SymmNonce = AlignedBuffer<NONCESIZE>;
|
||||
using SymmKey = AlignedBuffer<32>;
|
||||
using SymmKey = AlignedBuffer<32>; // not used
|
||||
|
||||
using PQCipherBlock = AlignedBuffer<PQ_CIPHERTEXTSIZE + 1>;
|
||||
using PQPubKey = AlignedBuffer<PQ_PUBKEYSIZE>;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace llarp::dht
|
|||
bool
|
||||
operator()(const RouterContact& left, const RouterContact& right) const
|
||||
{
|
||||
return (left.pubkey ^ us) < (right.pubkey ^ us);
|
||||
return (left.router_id() ^ us) < (right.router_id() ^ us);
|
||||
}
|
||||
};
|
||||
} // namespace llarp::dht
|
||||
|
|
|
@ -19,19 +19,19 @@ namespace llarp::dht
|
|||
ID.Zero();
|
||||
}
|
||||
|
||||
RCNode(const RouterContact& other) : rc(other), ID(other.pubkey)
|
||||
RCNode(const RouterContact& other) : rc(other), ID(other.router_id())
|
||||
{}
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const
|
||||
{
|
||||
return rc.ExtractStatus();
|
||||
return rc.extract_status();
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const RCNode& other) const
|
||||
{
|
||||
return rc.last_updated < other.rc.last_updated;
|
||||
return rc.timestamp() < other.rc.timestamp();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -69,13 +69,13 @@ namespace llarp::exit
|
|||
snode_blacklist.insert(std::move(snode));
|
||||
}
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
BaseSession::GetHopsForBuild()
|
||||
{
|
||||
if (numHops == 1)
|
||||
{
|
||||
if (auto maybe = router->node_db()->get_rc(exit_router))
|
||||
return std::vector<RouterContact>{*maybe};
|
||||
return std::vector<RemoteRC>{*maybe};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ namespace llarp::exit
|
|||
throw;
|
||||
}
|
||||
|
||||
RouterContact result{std::move(payload)};
|
||||
RemoteRC result{std::move(payload)};
|
||||
r->node_db()->put_rc_if_newer(result);
|
||||
r->connect_to(result);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace llarp
|
|||
bool
|
||||
CheckPathDead(path::Path_ptr p, llarp_time_t dlt);
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
GetHopsForBuild() override;
|
||||
|
||||
bool
|
||||
|
|
|
@ -578,29 +578,7 @@ namespace llarp::handlers
|
|||
void
|
||||
ExitEndpoint::SRVRecordsChanged()
|
||||
{
|
||||
router->modify_rc(
|
||||
[srvRecords = SRVRecords()](RouterContact rc) -> std::optional<RouterContact> {
|
||||
// check if there are any new srv records
|
||||
bool shouldUpdate = false;
|
||||
|
||||
for (const auto& rcSrv : rc.srvRecords)
|
||||
{
|
||||
if (srvRecords.count(rcSrv) == 0)
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
// no new records so don't modify
|
||||
if (not shouldUpdate)
|
||||
return std::nullopt;
|
||||
|
||||
// we got new entries so we clear the whole vector on the rc and recreate it
|
||||
rc.srvRecords.clear();
|
||||
for (auto& record : srvRecords)
|
||||
rc.srvRecords.emplace_back(record);
|
||||
// set the verssion to 1 because we have srv records
|
||||
rc.version = 1;
|
||||
return rc;
|
||||
});
|
||||
// TODO: Investigate the usage or the term exit RE: service nodes acting as exits
|
||||
}
|
||||
|
||||
std::optional<EndpointBase::SendStat>
|
||||
|
|
|
@ -623,7 +623,7 @@ namespace llarp::handlers
|
|||
throw;
|
||||
}
|
||||
|
||||
r->node_db()->put_rc_if_newer(RouterContact{payload});
|
||||
r->node_db()->put_rc_if_newer(RemoteRC{payload});
|
||||
msg.AddTXTReply(payload);
|
||||
}
|
||||
else
|
||||
|
@ -658,7 +658,7 @@ namespace llarp::handlers
|
|||
}
|
||||
else if (subdomain == "netid")
|
||||
{
|
||||
msg.AddTXTReply(fmt::format("netid={};", router()->rc().netID));
|
||||
msg.AddTXTReply(fmt::format("netid={};", RouterContact::ACTIVE_NETID));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace llarp::link
|
|||
Connection::Connection(
|
||||
std::shared_ptr<oxen::quic::connection_interface>& c,
|
||||
std::shared_ptr<oxen::quic::BTRequestStream>& s,
|
||||
const RouterContact& rc)
|
||||
const RemoteRC& rc)
|
||||
: conn{c}, control_stream{s}, remote_rc{std::move(rc)}
|
||||
{}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace llarp::link
|
|||
{
|
||||
std::shared_ptr<oxen::quic::connection_interface> conn;
|
||||
std::shared_ptr<oxen::quic::BTRequestStream> control_stream;
|
||||
RouterContact remote_rc;
|
||||
RemoteRC remote_rc;
|
||||
|
||||
// one side of a connection will be responsible for some things, e.g. heartbeat
|
||||
bool inbound{false};
|
||||
|
@ -20,7 +20,7 @@ namespace llarp::link
|
|||
Connection(
|
||||
std::shared_ptr<oxen::quic::connection_interface>& c,
|
||||
std::shared_ptr<oxen::quic::BTRequestStream>& s,
|
||||
const RouterContact& rc);
|
||||
const RemoteRC& rc);
|
||||
};
|
||||
} // namespace llarp::link
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace llarp
|
|||
|
||||
while (itr != nodes.end())
|
||||
{
|
||||
if (itr->second.rc.IsExpired(now))
|
||||
if (itr->second.rc.is_expired(now))
|
||||
itr = nodes.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
|
|
|
@ -18,9 +18,9 @@ namespace llarp
|
|||
namespace link
|
||||
{
|
||||
std::shared_ptr<link::Connection>
|
||||
Endpoint::get_conn(const RouterContact& rc) const
|
||||
Endpoint::get_conn(const RemoteRC& rc) const
|
||||
{
|
||||
if (auto itr = conns.find(rc.pubkey); itr != conns.end())
|
||||
if (auto itr = conns.find(rc.router_id()); itr != conns.end())
|
||||
return itr->second;
|
||||
|
||||
return nullptr;
|
||||
|
@ -83,7 +83,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
Endpoint::get_random_connection(RouterContact& router) const
|
||||
Endpoint::get_random_connection(RemoteRC& router) const
|
||||
{
|
||||
if (const auto size = conns.size(); size)
|
||||
{
|
||||
|
@ -301,16 +301,16 @@ namespace llarp
|
|||
|
||||
// This function assumes the RC has already had its signature verified and connection is allowed.
|
||||
void
|
||||
LinkManager::connect_to(const RouterContact& rc)
|
||||
LinkManager::connect_to(const RemoteRC& rc)
|
||||
{
|
||||
if (auto conn = ep.get_conn(rc.pubkey); conn)
|
||||
if (auto conn = ep.get_conn(rc.router_id()); conn)
|
||||
{
|
||||
// TODO: should implement some connection failed logic, but not the same logic that
|
||||
// would be executed for another failure case
|
||||
return;
|
||||
}
|
||||
|
||||
auto& remote_addr = rc.addr;
|
||||
const auto& remote_addr = rc.addr();
|
||||
|
||||
// TODO: confirm remote end is using the expected pubkey (RouterID).
|
||||
// TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation)
|
||||
|
@ -451,7 +451,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
LinkManager::get_random_connected(RouterContact& router) const
|
||||
LinkManager::get_random_connected(RemoteRC& router) const
|
||||
{
|
||||
return ep.get_random_connection(router);
|
||||
}
|
||||
|
@ -487,13 +487,15 @@ namespace llarp
|
|||
|
||||
do
|
||||
{
|
||||
auto filter = [exclude](const auto& rc) -> bool { return exclude.count(rc.pubkey) == 0; };
|
||||
auto filter = [exclude](const auto& rc) -> bool {
|
||||
return exclude.count(rc.router_id()) == 0;
|
||||
};
|
||||
|
||||
if (auto maybe_other = node_db->GetRandom(filter))
|
||||
{
|
||||
exclude.insert(maybe_other->pubkey);
|
||||
exclude.insert(maybe_other->router_id());
|
||||
|
||||
if (not rc_lookup->is_session_allowed(maybe_other->pubkey))
|
||||
if (not rc_lookup->is_session_allowed(maybe_other->router_id()))
|
||||
continue;
|
||||
|
||||
connect_to(*maybe_other);
|
||||
|
@ -609,18 +611,19 @@ namespace llarp
|
|||
target_rid.FromString(target_key);
|
||||
|
||||
const auto target_addr = dht::Key_t{reinterpret_cast<uint8_t*>(target_key.data())};
|
||||
const auto& local_rid = _router.rc().pubkey;
|
||||
const auto& local_rid = _router.rc().router_id();
|
||||
const auto local_key = dht::Key_t{local_rid};
|
||||
|
||||
if (is_exploratory)
|
||||
{
|
||||
std::string neighbors{};
|
||||
|
||||
const auto closest_rcs =
|
||||
_router.node_db()->find_many_closest_to(target_addr, RC_LOOKUP_STORAGE_REDUNDANCY);
|
||||
|
||||
for (const auto& rc : closest_rcs)
|
||||
{
|
||||
const auto& rid = rc.pubkey;
|
||||
const auto& rid = rc.router_id();
|
||||
if (_router.router_profiling().IsBadForConnect(rid) || target_rid == rid
|
||||
|| local_rid == rid)
|
||||
continue;
|
||||
|
@ -635,12 +638,12 @@ namespace llarp
|
|||
else
|
||||
{
|
||||
const auto closest_rc = _router.node_db()->find_closest_to(target_addr);
|
||||
const auto& closest_rid = closest_rc.pubkey;
|
||||
const auto& closest_rid = closest_rc.router_id();
|
||||
const auto closest_key = dht::Key_t{closest_rid};
|
||||
|
||||
if (target_addr == closest_key)
|
||||
{
|
||||
if (closest_rc.ExpiresSoon(llarp::time_now_ms()))
|
||||
if (closest_rc.expires_within_delta(llarp::time_now_ms()))
|
||||
{
|
||||
send_control_message(
|
||||
target_rid,
|
||||
|
@ -652,7 +655,7 @@ namespace llarp
|
|||
}
|
||||
else
|
||||
{
|
||||
m.respond(serialize_response({{"RC", closest_rc.bt_encode()}}));
|
||||
m.respond(serialize_response({{"RC", closest_rc.view()}}));
|
||||
}
|
||||
}
|
||||
else if (not is_iterative)
|
||||
|
@ -718,7 +721,7 @@ namespace llarp
|
|||
|
||||
if (m)
|
||||
{
|
||||
_router.node_db()->put_rc_if_newer(RouterContact{payload});
|
||||
_router.node_db()->put_rc_if_newer(RemoteRC{payload});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -837,7 +840,7 @@ namespace llarp
|
|||
|
||||
const auto now = _router.now();
|
||||
const auto addr = dht::Key_t{reinterpret_cast<uint8_t*>(derived_signing_key.data())};
|
||||
const auto local_key = _router.rc().pubkey;
|
||||
const auto local_key = _router.rc().router_id();
|
||||
|
||||
if (not service::EncryptedIntroSet::verify(introset, derived_signing_key, sig))
|
||||
{
|
||||
|
@ -878,7 +881,7 @@ namespace llarp
|
|||
log::info(link_cat, "Relaying PublishIntroMessage for {}", addr);
|
||||
|
||||
const auto& peer_rc = closest_rcs[relay_order];
|
||||
const auto& peer_key = peer_rc.pubkey;
|
||||
const auto& peer_key = peer_rc.router_id();
|
||||
|
||||
if (peer_key == local_key)
|
||||
{
|
||||
|
@ -908,7 +911,7 @@ namespace llarp
|
|||
|
||||
for (const auto& rc : closest_rcs)
|
||||
{
|
||||
if (rc.pubkey == local_key)
|
||||
if (rc.router_id() == local_key)
|
||||
{
|
||||
rc_index = index;
|
||||
break;
|
||||
|
@ -1024,7 +1027,7 @@ namespace llarp
|
|||
log::info(link_cat, "Relaying FindIntroMessage for {}", addr);
|
||||
|
||||
const auto& peer_rc = closest_rcs[relay_order];
|
||||
const auto& peer_key = peer_rc.pubkey;
|
||||
const auto& peer_key = peer_rc.router_id();
|
||||
|
||||
send_control_message(
|
||||
peer_key,
|
||||
|
|
|
@ -52,7 +52,8 @@ namespace llarp
|
|||
|
||||
// TODO: see which of these is actually useful and delete the other
|
||||
std::shared_ptr<link::Connection>
|
||||
get_conn(const RouterContact&) const;
|
||||
get_conn(const RemoteRC&) const;
|
||||
|
||||
std::shared_ptr<link::Connection>
|
||||
get_conn(const RouterID&) const;
|
||||
|
||||
|
@ -66,12 +67,11 @@ namespace llarp
|
|||
num_connected(bool clients_only) const;
|
||||
|
||||
bool
|
||||
get_random_connection(RouterContact& router) const;
|
||||
get_random_connection(RemoteRC& router) const;
|
||||
|
||||
template <typename... Opt>
|
||||
bool
|
||||
establish_connection(
|
||||
const oxen::quic::Address& remote, const RouterContact& rc, Opt&&... opts);
|
||||
establish_connection(const oxen::quic::Address& remote, const RemoteRC& rc, Opt&&... opts);
|
||||
|
||||
void
|
||||
for_each_connection(std::function<void(link::Connection&)> func);
|
||||
|
@ -239,7 +239,7 @@ namespace llarp
|
|||
connect_to(const RouterID& router);
|
||||
|
||||
void
|
||||
connect_to(const RouterContact& rc);
|
||||
connect_to(const RemoteRC& rc);
|
||||
|
||||
void
|
||||
close_connection(RouterID rid);
|
||||
|
@ -257,7 +257,7 @@ namespace llarp
|
|||
get_num_connected_clients() const;
|
||||
|
||||
bool
|
||||
get_random_connected(RouterContact& router) const;
|
||||
get_random_connected(RemoteRC& router) const;
|
||||
|
||||
void
|
||||
check_persisting_conns(llarp_time_t now);
|
||||
|
@ -364,7 +364,7 @@ namespace llarp
|
|||
template <typename... Opt>
|
||||
bool
|
||||
Endpoint::establish_connection(
|
||||
const oxen::quic::Address& remote, const RouterContact& rc, Opt&&... opts)
|
||||
const oxen::quic::Address& remote, const RemoteRC& rc, Opt&&... opts)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -372,8 +372,8 @@ namespace llarp
|
|||
endpoint->connect(remote, link_manager.tls_creds, std::forward<Opt>(opts)...);
|
||||
|
||||
// emplace immediately for connection open callback to find scid
|
||||
connid_map.emplace(conn_interface->scid(), rc.pubkey);
|
||||
auto [itr, b] = conns.emplace(rc.pubkey, nullptr);
|
||||
connid_map.emplace(conn_interface->scid(), rc.router_id());
|
||||
auto [itr, b] = conns.emplace(rc.router_id(), nullptr);
|
||||
|
||||
auto control_stream =
|
||||
conn_interface->template get_new_stream<oxen::quic::BTRequestStream>();
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace llarp
|
|||
|
||||
hop.nonce.Randomize();
|
||||
// do key exchange
|
||||
if (!crypto::dh_client(hop.shared, hop.rc.pubkey, hop.commkey, hop.nonce))
|
||||
if (!crypto::dh_client(hop.shared, hop.rc.router_id(), hop.commkey, hop.nonce))
|
||||
{
|
||||
auto err = fmt::format("Failed to generate shared key for path build!");
|
||||
log::warning(path_cat, err);
|
||||
|
@ -60,7 +60,7 @@ namespace llarp
|
|||
outer_nonce.Randomize();
|
||||
|
||||
// derive (outer) shared key
|
||||
if (!crypto::dh_client(shared, hop.rc.pubkey, framekey, outer_nonce))
|
||||
if (!crypto::dh_client(shared, hop.rc.router_id(), framekey, outer_nonce))
|
||||
{
|
||||
log::warning(path_cat, "DH client failed during hop info encryption!");
|
||||
throw std::runtime_error{"DH failed during hop info encryption"};
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace llarp
|
|||
bool
|
||||
RelayUpstreamMessage::handle_message(Router* r) const
|
||||
{
|
||||
auto path = r->path_context().GetByDownstream(conn->remote_rc.pubkey, pathid);
|
||||
auto path = r->path_context().GetByDownstream(conn->remote_rc.router_id(), pathid);
|
||||
if (path)
|
||||
{
|
||||
return path->HandleUpstream(llarp_buffer_t(enc), nonce, r);
|
||||
|
@ -110,7 +110,7 @@ namespace llarp
|
|||
bool
|
||||
RelayDownstreamMessage::handle_message(Router* r) const
|
||||
{
|
||||
auto path = r->path_context().GetByUpstream(conn->remote_rc.pubkey, pathid);
|
||||
auto path = r->path_context().GetByUpstream(conn->remote_rc.router_id(), pathid);
|
||||
if (path)
|
||||
{
|
||||
return path->HandleDownstream(llarp_buffer_t(enc), nonce, r);
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "exit_info.hpp"
|
||||
|
||||
#include <llarp/util/bencode.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
bool
|
||||
ExitInfo::bt_encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
SockAddr exitaddr = ipAddress.createSockAddr();
|
||||
const auto* exitaddr6 = static_cast<const sockaddr_in6*>(exitaddr);
|
||||
|
||||
SockAddr netmaskaddr = netmask.createSockAddr();
|
||||
const auto* netmaskaddr6 = static_cast<const sockaddr_in6*>(netmaskaddr);
|
||||
|
||||
char tmp[128] = {0};
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
if (!inet_ntop(AF_INET6, &exitaddr6->sin6_addr, tmp, sizeof(tmp)))
|
||||
return false;
|
||||
if (!BEncodeWriteDictString("a", std::string(tmp), buf))
|
||||
return false;
|
||||
|
||||
if (!inet_ntop(AF_INET6, &netmaskaddr6->sin6_addr, tmp, sizeof(tmp)))
|
||||
return false;
|
||||
if (!BEncodeWriteDictString("b", std::string(tmp), buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeWriteDictEntry("k", pubkey, buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeWriteDictInt("v", version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
static bool
|
||||
bdecode_ip_string(llarp_buffer_t* buf, in6_addr& ip)
|
||||
{
|
||||
char tmp[128] = {0};
|
||||
llarp_buffer_t strbuf;
|
||||
if (!bencode_read_string(buf, &strbuf))
|
||||
return false;
|
||||
|
||||
if (strbuf.sz >= sizeof(tmp))
|
||||
return false;
|
||||
|
||||
memcpy(tmp, strbuf.base, strbuf.sz);
|
||||
tmp[strbuf.sz] = 0;
|
||||
return inet_pton(AF_INET6, tmp, &ip.s6_addr[0]) == 1;
|
||||
}
|
||||
|
||||
bool
|
||||
ExitInfo::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
if (!BEncodeMaybeReadDictEntry("k", pubkey, read, k, buf))
|
||||
return false;
|
||||
if (!BEncodeMaybeReadDictInt("v", version, read, k, buf))
|
||||
return false;
|
||||
if (k.startswith("a"))
|
||||
{
|
||||
in6_addr tmp;
|
||||
if (not bdecode_ip_string(buf, tmp))
|
||||
return false;
|
||||
|
||||
SockAddr addr(tmp);
|
||||
ipAddress = IpAddress(addr);
|
||||
return true;
|
||||
}
|
||||
if (k.startswith("b"))
|
||||
{
|
||||
in6_addr tmp;
|
||||
if (not bdecode_ip_string(buf, tmp))
|
||||
return false;
|
||||
SockAddr addr(tmp);
|
||||
netmask = IpAddress(addr);
|
||||
return true;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
std::string
|
||||
ExitInfo::ToString() const
|
||||
{
|
||||
/*
|
||||
// TODO: derive these from ipAdress
|
||||
throw std::runtime_error("FIXME: need in6_addr and netmask from IpAddress");
|
||||
in6_addr address;
|
||||
in6_addr netmask;
|
||||
|
||||
Printer printer(stream, level, spaces);
|
||||
|
||||
std::ostringstream ss;
|
||||
char tmp[128] = {0};
|
||||
|
||||
if (inet_ntop(AF_INET6, (void*)&address, tmp, sizeof(tmp)))
|
||||
ss << tmp;
|
||||
else
|
||||
return stream;
|
||||
ss << std::string("/");
|
||||
#if defined(ANDROID)
|
||||
snprintf(tmp, sizeof(tmp), "%zu", llarp::bits::count_array_bits(netmask.s6_addr));
|
||||
ss << tmp;
|
||||
#else
|
||||
ss << std::to_string(llarp::bits::count_array_bits(netmask.s6_addr));
|
||||
#endif
|
||||
printer.printValue(ss.str());
|
||||
*/
|
||||
return fmt::format("[Exit {}]", ipAddress.ToString());
|
||||
}
|
||||
|
||||
} // namespace llarp
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "ip_address.hpp"
|
||||
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/util/bencode.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
/**
|
||||
* exit_info.h
|
||||
*
|
||||
* utilities for handling exits on the llarp network
|
||||
*/
|
||||
|
||||
/// Exit info model
|
||||
namespace llarp
|
||||
{
|
||||
/// deprecated don't use me , this is only for backwards compat
|
||||
struct ExitInfo
|
||||
{
|
||||
IpAddress ipAddress;
|
||||
IpAddress netmask;
|
||||
PubKey pubkey;
|
||||
uint64_t version = llarp::constants::proto_version;
|
||||
|
||||
ExitInfo() = default;
|
||||
|
||||
ExitInfo(const PubKey& pk, const IpAddress& address) : ipAddress(address), pubkey(pk)
|
||||
{}
|
||||
|
||||
bool
|
||||
bt_encode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
return bencode_decode_dict(*this, buf);
|
||||
}
|
||||
|
||||
bool
|
||||
decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf);
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<ExitInfo> = true;
|
||||
|
||||
} // namespace llarp
|
|
@ -14,9 +14,7 @@ static const std::string RC_FILE_EXT = ".signed";
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("nodedb");
|
||||
|
||||
NodeDB::Entry::Entry(RouterContact value) : rc(std::move(value)), insertedAt(llarp::time_now_ms())
|
||||
NodeDB::Entry::Entry(RemoteRC value) : rc(std::move(value)), insertedAt(llarp::time_now_ms())
|
||||
{}
|
||||
|
||||
static void
|
||||
|
@ -72,14 +70,16 @@ namespace llarp
|
|||
router.loop()->call([this]() {
|
||||
m_NextFlushAt += FlushInterval;
|
||||
// make copy of all rcs
|
||||
std::vector<RouterContact> copy;
|
||||
std::vector<RemoteRC> copy;
|
||||
|
||||
for (const auto& item : entries)
|
||||
copy.push_back(item.second.rc);
|
||||
|
||||
// flush them to disk in one big job
|
||||
// TODO: split this up? idk maybe some day...
|
||||
disk([this, data = std::move(copy)]() {
|
||||
for (const auto& rc : data)
|
||||
rc.Write(get_path_by_pubkey(rc.pubkey));
|
||||
rc.write(get_path_by_pubkey(rc.router_id()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -121,22 +121,16 @@ namespace llarp
|
|||
if (not(fs::is_regular_file(f) and f.extension() == RC_FILE_EXT))
|
||||
return true;
|
||||
|
||||
RouterContact rc{};
|
||||
RemoteRC rc{};
|
||||
|
||||
if (not rc.Read(f))
|
||||
if (not rc.read(f))
|
||||
{
|
||||
// try loading it, purge it if it is junk
|
||||
purge.emplace(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (not rc.FromOurNetwork())
|
||||
{
|
||||
// skip entries that are not from our network
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rc.IsExpired(time_now_ms()))
|
||||
if (rc.is_expired(time_now_ms()))
|
||||
{
|
||||
// rc expired dont load it and purge it later
|
||||
purge.emplace(f);
|
||||
|
@ -145,8 +139,8 @@ namespace llarp
|
|||
|
||||
// validate signature and purge entries with invalid signatures
|
||||
// load ones with valid signatures
|
||||
if (rc.VerifySignature())
|
||||
entries.emplace(rc.pubkey, rc);
|
||||
if (rc.verify())
|
||||
entries.emplace(rc.router_id(), rc);
|
||||
else
|
||||
purge.emplace(f);
|
||||
|
||||
|
@ -172,7 +166,7 @@ namespace llarp
|
|||
|
||||
router.loop()->call([this]() {
|
||||
for (const auto& item : entries)
|
||||
item.second.rc.Write(get_path_by_pubkey(item.first));
|
||||
item.second.rc.write(get_path_by_pubkey(item.first));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -183,10 +177,10 @@ namespace llarp
|
|||
[this, pk]() -> bool { return entries.find(pk) != entries.end(); });
|
||||
}
|
||||
|
||||
std::optional<RouterContact>
|
||||
std::optional<RemoteRC>
|
||||
NodeDB::get_rc(RouterID pk) const
|
||||
{
|
||||
return router.loop()->call_get([this, pk]() -> std::optional<RouterContact> {
|
||||
return router.loop()->call_get([this, pk]() -> std::optional<RemoteRC> {
|
||||
const auto itr = entries.find(pk);
|
||||
|
||||
if (itr == entries.end())
|
||||
|
@ -213,9 +207,9 @@ namespace llarp
|
|||
auto itr = entries.begin();
|
||||
while (itr != entries.end())
|
||||
{
|
||||
if (itr->second.insertedAt < cutoff and keep.count(itr->second.rc.pubkey) == 0)
|
||||
if (itr->second.insertedAt < cutoff and keep.count(itr->second.rc.router_id()) == 0)
|
||||
{
|
||||
removed.insert(itr->second.rc.pubkey);
|
||||
removed.insert(itr->second.rc.router_id());
|
||||
itr = entries.erase(itr);
|
||||
}
|
||||
else
|
||||
|
@ -227,11 +221,12 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
NodeDB::put_rc(RouterContact rc)
|
||||
NodeDB::put_rc(RemoteRC rc)
|
||||
{
|
||||
router.loop()->call([this, rc]() {
|
||||
entries.erase(rc.pubkey);
|
||||
entries.emplace(rc.pubkey, rc);
|
||||
const auto& rid = rc.router_id();
|
||||
entries.erase(rid);
|
||||
entries.emplace(rid, rc);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -242,17 +237,17 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
NodeDB::put_rc_if_newer(RouterContact rc)
|
||||
NodeDB::put_rc_if_newer(RemoteRC rc)
|
||||
{
|
||||
router.loop()->call([this, rc]() {
|
||||
auto itr = entries.find(rc.pubkey);
|
||||
if (itr == entries.end() or itr->second.rc.OtherIsNewer(rc))
|
||||
auto itr = entries.find(rc.router_id());
|
||||
if (itr == entries.end() or itr->second.rc.other_is_newer(rc))
|
||||
{
|
||||
// delete if existing
|
||||
if (itr != entries.end())
|
||||
entries.erase(itr);
|
||||
// add new entry
|
||||
entries.emplace(rc.pubkey, rc);
|
||||
entries.emplace(rc.router_id(), rc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -275,32 +270,31 @@ namespace llarp
|
|||
});
|
||||
}
|
||||
|
||||
llarp::RouterContact
|
||||
RemoteRC
|
||||
NodeDB::find_closest_to(llarp::dht::Key_t location) const
|
||||
{
|
||||
return router.loop()->call_get([this, location]() {
|
||||
llarp::RouterContact rc;
|
||||
return router.loop()->call_get([this, location]() -> RemoteRC {
|
||||
RemoteRC rc;
|
||||
const llarp::dht::XorMetric compare(location);
|
||||
|
||||
VisitAll([&rc, compare](const auto& otherRC) {
|
||||
if (rc.pubkey.IsZero())
|
||||
const auto& rid = rc.router_id();
|
||||
|
||||
if (rid.IsZero() || compare(dht::Key_t{otherRC.router_id()}, dht::Key_t{rid}))
|
||||
{
|
||||
rc = otherRC;
|
||||
return;
|
||||
}
|
||||
if (compare(
|
||||
llarp::dht::Key_t{otherRC.pubkey.as_array()},
|
||||
llarp::dht::Key_t{rc.pubkey.as_array()}))
|
||||
rc = otherRC;
|
||||
});
|
||||
return rc;
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<RouterContact>
|
||||
std::vector<RemoteRC>
|
||||
NodeDB::find_many_closest_to(llarp::dht::Key_t location, uint32_t numRouters) const
|
||||
{
|
||||
return router.loop()->call_get([this, location, numRouters]() {
|
||||
std::vector<const RouterContact*> all;
|
||||
return router.loop()->call_get([this, location, numRouters]() -> std::vector<RemoteRC> {
|
||||
std::vector<const RemoteRC*> all;
|
||||
|
||||
all.reserve(entries.size());
|
||||
for (auto& entry : entries)
|
||||
|
@ -314,7 +308,7 @@ namespace llarp
|
|||
return compare(*a, *b);
|
||||
});
|
||||
|
||||
std::vector<RouterContact> closest;
|
||||
std::vector<RemoteRC> closest;
|
||||
closest.reserve(numRouters);
|
||||
for (auto it = all.begin(); it != it_mid; ++it)
|
||||
closest.push_back(**it);
|
||||
|
|
|
@ -26,9 +26,9 @@ namespace llarp
|
|||
{
|
||||
struct Entry
|
||||
{
|
||||
const RouterContact rc;
|
||||
const RemoteRC rc;
|
||||
llarp_time_t insertedAt;
|
||||
explicit Entry(RouterContact rc);
|
||||
explicit Entry(RemoteRC rc);
|
||||
};
|
||||
|
||||
using NodeMap = std::unordered_map<RouterID, Entry>;
|
||||
|
@ -73,11 +73,11 @@ namespace llarp
|
|||
Tick(llarp_time_t now);
|
||||
|
||||
/// find the absolute closets router to a dht location
|
||||
RouterContact
|
||||
RemoteRC
|
||||
find_closest_to(dht::Key_t location) const;
|
||||
|
||||
/// find many routers closest to dht key
|
||||
std::vector<RouterContact>
|
||||
std::vector<RemoteRC>
|
||||
find_many_closest_to(dht::Key_t location, uint32_t numRouters) const;
|
||||
|
||||
/// return true if we have an rc by its ident pubkey
|
||||
|
@ -85,14 +85,14 @@ namespace llarp
|
|||
has_router(RouterID pk) const;
|
||||
|
||||
/// maybe get an rc by its ident pubkey
|
||||
std::optional<RouterContact>
|
||||
std::optional<RemoteRC>
|
||||
get_rc(RouterID pk) const;
|
||||
|
||||
template <typename Filter>
|
||||
std::optional<RouterContact>
|
||||
std::optional<RemoteRC>
|
||||
GetRandom(Filter visit) const
|
||||
{
|
||||
return router.loop()->call_get([visit]() -> std::optional<RouterContact> {
|
||||
return router.loop()->call_get([visit]() -> std::optional<RemoteRC> {
|
||||
std::vector<const decltype(entries)::value_type*> entries;
|
||||
for (const auto& entry : entries)
|
||||
entries.push_back(entry);
|
||||
|
@ -150,7 +150,7 @@ namespace llarp
|
|||
{
|
||||
if (visit(itr->second.rc))
|
||||
{
|
||||
removed.insert(itr->second.rc.pubkey);
|
||||
removed.insert(itr->second.rc.router_id());
|
||||
itr = entries.erase(itr);
|
||||
}
|
||||
else
|
||||
|
@ -167,10 +167,10 @@ namespace llarp
|
|||
|
||||
/// put this rc into the cache if it is not there or newer than the one there already
|
||||
void
|
||||
put_rc_if_newer(RouterContact rc);
|
||||
put_rc_if_newer(RemoteRC rc);
|
||||
|
||||
/// unconditional put of rc into cache
|
||||
void
|
||||
put_rc(RouterContact rc);
|
||||
put_rc(RemoteRC rc);
|
||||
};
|
||||
} // namespace llarp
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace llarp::path
|
|||
{
|
||||
Path::Path(
|
||||
Router* rtr,
|
||||
const std::vector<RouterContact>& h,
|
||||
const std::vector<RemoteRC>& h,
|
||||
std::weak_ptr<PathSet> pathset,
|
||||
PathRole startingRoles,
|
||||
std::string shortName)
|
||||
|
@ -40,7 +40,7 @@ namespace llarp::path
|
|||
hops[idx].txID = hops[idx + 1].rxID;
|
||||
}
|
||||
// initialize parts of the introduction
|
||||
intro.router = hops[hsz - 1].rc.pubkey;
|
||||
intro.router = hops[hsz - 1].rc.router_id();
|
||||
intro.path_id = hops[hsz - 1].txID;
|
||||
if (auto parent = m_PathSet.lock())
|
||||
EnterState(ePathBuilding, parent->Now());
|
||||
|
@ -152,13 +152,13 @@ namespace llarp::path
|
|||
RouterID
|
||||
Path::Endpoint() const
|
||||
{
|
||||
return hops[hops.size() - 1].rc.pubkey;
|
||||
return hops[hops.size() - 1].rc.router_id();
|
||||
}
|
||||
|
||||
PubKey
|
||||
Path::EndpointPubKey() const
|
||||
{
|
||||
return hops[hops.size() - 1].rc.pubkey;
|
||||
return hops[hops.size() - 1].rc.router_id();
|
||||
}
|
||||
|
||||
PathID_t
|
||||
|
@ -184,13 +184,13 @@ namespace llarp::path
|
|||
bool
|
||||
Path::is_endpoint(const RouterID& r, const PathID_t& id) const
|
||||
{
|
||||
return hops[hops.size() - 1].rc.pubkey == r && hops[hops.size() - 1].txID == id;
|
||||
return hops[hops.size() - 1].rc.router_id() == r && hops[hops.size() - 1].txID == id;
|
||||
}
|
||||
|
||||
RouterID
|
||||
Path::upstream() const
|
||||
{
|
||||
return hops[0].rc.pubkey;
|
||||
return hops[0].rc.router_id();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
|
@ -208,7 +208,7 @@ namespace llarp::path
|
|||
{
|
||||
if (!hops.empty())
|
||||
hops_str += " -> ";
|
||||
hops_str += RouterID(hop.rc.pubkey).ToString();
|
||||
hops_str += hop.rc.router_id().ToView();
|
||||
}
|
||||
return hops_str;
|
||||
}
|
||||
|
@ -262,9 +262,9 @@ namespace llarp::path
|
|||
PathHopConfig::ExtractStatus() const
|
||||
{
|
||||
util::StatusObject obj{
|
||||
{"ip", rc.addr.to_string()},
|
||||
{"ip", rc.addr().to_string()},
|
||||
{"lifetime", to_json(lifetime)},
|
||||
{"router", rc.pubkey.ToHex()},
|
||||
{"router", rc.router_id().ToHex()},
|
||||
{"txid", txID.ToHex()},
|
||||
{"rxid", rxID.ToHex()}};
|
||||
return obj;
|
||||
|
@ -330,11 +330,13 @@ namespace llarp::path
|
|||
{
|
||||
if (auto parent = m_PathSet.lock())
|
||||
{
|
||||
std::vector<RouterContact> newHops;
|
||||
std::vector<RemoteRC> new_hops;
|
||||
|
||||
for (const auto& hop : hops)
|
||||
newHops.emplace_back(hop.rc);
|
||||
new_hops.emplace_back(hop.rc);
|
||||
|
||||
LogInfo(name(), " rebuilding on ", ShortName());
|
||||
parent->Build(newHops);
|
||||
parent->Build(new_hops);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace llarp
|
|||
|
||||
Path(
|
||||
Router* rtr,
|
||||
const std::vector<RouterContact>& routers,
|
||||
const std::vector<RemoteRC>& routers,
|
||||
std::weak_ptr<PathSet> parent,
|
||||
PathRole startingRoles,
|
||||
std::string shortName);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace llarp
|
|||
/// path id
|
||||
PathID_t txID, rxID;
|
||||
// router contact of router
|
||||
RouterContact rc;
|
||||
RemoteRC rc;
|
||||
// temp public encryption key
|
||||
SecretKey commkey;
|
||||
/// shared secret at this hop
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace llarp
|
|||
|
||||
hop.nonce.Randomize();
|
||||
// do key exchange
|
||||
if (!crypto::dh_client(hop.shared, hop.rc.pubkey, hop.commkey, hop.nonce))
|
||||
if (!crypto::dh_client(hop.shared, hop.rc.router_id(), hop.commkey, hop.nonce))
|
||||
{
|
||||
auto err = fmt::format("{} failed to generate shared key for path build!", Name());
|
||||
log::error(path_cat, err);
|
||||
|
@ -121,7 +121,7 @@ namespace llarp
|
|||
outer_nonce.Randomize();
|
||||
|
||||
// derive (outer) shared key
|
||||
if (!crypto::dh_client(shared, hop.rc.pubkey, framekey, outer_nonce))
|
||||
if (!crypto::dh_client(shared, hop.rc.router_id(), framekey, outer_nonce))
|
||||
{
|
||||
log::error(path_cat, "DH client failed during hop info encryption!");
|
||||
throw std::runtime_error{"DH failed during hop info encryption"};
|
||||
|
@ -211,23 +211,25 @@ namespace llarp
|
|||
return obj;
|
||||
}
|
||||
|
||||
std::optional<RouterContact>
|
||||
std::optional<RemoteRC>
|
||||
Builder::SelectFirstHop(const std::set<RouterID>& exclude) const
|
||||
{
|
||||
std::optional<RouterContact> found = std::nullopt;
|
||||
std::optional<RemoteRC> found = std::nullopt;
|
||||
router->for_each_connection([&](link::Connection& conn) {
|
||||
const auto& rc = conn.remote_rc;
|
||||
const auto& rid = rc.router_id();
|
||||
|
||||
#ifndef TESTNET
|
||||
if (router->IsBootstrapNode(rc.pubkey))
|
||||
if (router->IsBootstrapNode(rid))
|
||||
return;
|
||||
#endif
|
||||
if (exclude.count(rc.pubkey))
|
||||
if (exclude.count(rid))
|
||||
return;
|
||||
|
||||
if (BuildCooldownHit(rc.pubkey))
|
||||
if (BuildCooldownHit(rid))
|
||||
return;
|
||||
|
||||
if (router->router_profiling().IsBadForPath(rc.pubkey))
|
||||
if (router->router_profiling().IsBadForPath(rid))
|
||||
return;
|
||||
|
||||
found = rc;
|
||||
|
@ -235,15 +237,15 @@ namespace llarp
|
|||
return found;
|
||||
}
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
Builder::GetHopsForBuild()
|
||||
{
|
||||
auto filter = [r = router](const auto& rc) -> bool {
|
||||
return not r->router_profiling().IsBadForPath(rc.pubkey, 1);
|
||||
return not r->router_profiling().IsBadForPath(rc.router_id(), 1);
|
||||
};
|
||||
if (const auto maybe = router->node_db()->GetRandom(filter))
|
||||
{
|
||||
return GetHopsAlignedToForBuild(maybe->pubkey);
|
||||
return GetHopsAlignedToForBuild(maybe->router_id());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -308,12 +310,12 @@ namespace llarp
|
|||
return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4;
|
||||
}
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
Builder::GetHopsAlignedToForBuild(RouterID endpoint, const std::set<RouterID>& exclude)
|
||||
{
|
||||
const auto pathConfig = router->config()->paths;
|
||||
|
||||
std::vector<RouterContact> hops;
|
||||
std::vector<RemoteRC> hops;
|
||||
{
|
||||
const auto maybe = SelectFirstHop(exclude);
|
||||
if (not maybe.has_value())
|
||||
|
@ -324,7 +326,7 @@ namespace llarp
|
|||
hops.emplace_back(*maybe);
|
||||
};
|
||||
|
||||
RouterContact endpointRC;
|
||||
RemoteRC endpointRC;
|
||||
if (const auto maybe = router->node_db()->get_rc(endpoint))
|
||||
{
|
||||
endpointRC = *maybe;
|
||||
|
@ -341,19 +343,21 @@ namespace llarp
|
|||
else
|
||||
{
|
||||
auto filter =
|
||||
[&hops, r = router, endpointRC, pathConfig, exclude](const auto& rc) -> bool {
|
||||
if (exclude.count(rc.pubkey))
|
||||
[&hops, r = router, endpointRC, pathConfig, exclude](const RemoteRC& rc) -> bool {
|
||||
const auto& rid = rc.router_id();
|
||||
|
||||
if (exclude.count(rid))
|
||||
return false;
|
||||
|
||||
std::set<RouterContact> hopsSet;
|
||||
std::set<RemoteRC> hopsSet;
|
||||
hopsSet.insert(endpointRC);
|
||||
hopsSet.insert(hops.begin(), hops.end());
|
||||
|
||||
if (r->router_profiling().IsBadForPath(rc.pubkey, 1))
|
||||
if (r->router_profiling().IsBadForPath(rid, 1))
|
||||
return false;
|
||||
for (const auto& hop : hopsSet)
|
||||
{
|
||||
if (hop.pubkey == rc.pubkey)
|
||||
if (hop.router_id() == rid)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -362,7 +366,7 @@ namespace llarp
|
|||
if (not pathConfig.Acceptable(hopsSet))
|
||||
return false;
|
||||
#endif
|
||||
return rc.pubkey != endpointRC.pubkey;
|
||||
return rc.router_id() != endpointRC.router_id();
|
||||
};
|
||||
|
||||
if (const auto maybe = router->node_db()->GetRandom(filter))
|
||||
|
@ -393,7 +397,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
Builder::Build(std::vector<RouterContact> hops, PathRole roles)
|
||||
Builder::Build(std::vector<RemoteRC> hops, PathRole roles)
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
|
@ -402,7 +406,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
lastBuild = llarp::time_now_ms();
|
||||
const RouterID edge{hops[0].pubkey};
|
||||
const auto& edge = hops[0].router_id();
|
||||
|
||||
if (not router->pathbuild_limiter().Attempt(edge))
|
||||
{
|
||||
|
@ -429,7 +433,8 @@ namespace llarp
|
|||
{
|
||||
bool lastHop = (i == (n_hops - 1));
|
||||
|
||||
const auto& nextHop = lastHop ? path_hops[i].rc.pubkey : path_hops[i + 1].rc.pubkey;
|
||||
const auto& nextHop =
|
||||
lastHop ? path_hops[i].rc.router_id() : path_hops[i + 1].rc.router_id();
|
||||
|
||||
PathBuildMessage::setup_hop_keys(path_hops[i], nextHop);
|
||||
auto frame_str = PathBuildMessage::serialize(path_hops[i]);
|
||||
|
@ -533,7 +538,7 @@ namespace llarp
|
|||
DoPathBuildBackoff();
|
||||
for (const auto& hop : p->hops)
|
||||
{
|
||||
const RouterID target{hop.rc.pubkey};
|
||||
const auto& target = hop.rc.router_id();
|
||||
// look up router and see if it's still on the network
|
||||
log::info(path_cat, "Looking up RouterID {} due to path build timeout", target);
|
||||
|
||||
|
|
|
@ -115,17 +115,17 @@ namespace llarp::path
|
|||
bool
|
||||
BuildOneAlignedTo(const RouterID endpoint) override;
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
GetHopsAlignedToForBuild(RouterID endpoint, const std::set<RouterID>& exclude = {});
|
||||
|
||||
void
|
||||
Build(std::vector<RouterContact> hops, PathRole roles = ePathRoleAny) override;
|
||||
Build(std::vector<RemoteRC> hops, PathRole roles = ePathRoleAny) override;
|
||||
|
||||
/// pick a first hop
|
||||
std::optional<RouterContact>
|
||||
std::optional<RemoteRC>
|
||||
SelectFirstHop(const std::set<RouterID>& exclude = {}) const;
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
GetHopsForBuild() override;
|
||||
|
||||
void
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace llarp
|
|||
|
||||
/// manual build on these hops
|
||||
virtual void
|
||||
Build(std::vector<RouterContact> hops, PathRole roles = ePathRoleAny) = 0;
|
||||
Build(std::vector<RemoteRC> hops, PathRole roles = ePathRoleAny) = 0;
|
||||
|
||||
/// tick owned paths
|
||||
virtual void
|
||||
|
@ -252,7 +252,7 @@ namespace llarp
|
|||
virtual void
|
||||
send_packet_to_remote(std::string buf) = 0;
|
||||
|
||||
virtual std::optional<std::vector<RouterContact>>
|
||||
virtual std::optional<std::vector<RemoteRC>>
|
||||
GetHopsForBuild() = 0;
|
||||
|
||||
void
|
||||
|
|
|
@ -10,8 +10,6 @@ using oxenc::bt_dict_producer;
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("profiling");
|
||||
|
||||
RouterProfile::RouterProfile(bt_dict_consumer dict)
|
||||
{
|
||||
BDecode(std::move(dict));
|
||||
|
@ -204,7 +202,7 @@ namespace llarp
|
|||
first = false;
|
||||
else
|
||||
{
|
||||
auto& profile = m_Profiles[hop.rc.pubkey];
|
||||
auto& profile = m_Profiles[hop.rc.router_id()];
|
||||
profile.pathFailCount += 1;
|
||||
profile.lastUpdated = llarp::time_now_ms();
|
||||
}
|
||||
|
@ -217,7 +215,7 @@ namespace llarp
|
|||
util::Lock lock{m_ProfilesMutex};
|
||||
for (const auto& hop : p->hops)
|
||||
{
|
||||
auto& profile = m_Profiles[hop.rc.pubkey];
|
||||
auto& profile = m_Profiles[hop.rc.router_id()];
|
||||
profile.pathTimeoutCount += 1;
|
||||
profile.lastUpdated = llarp::time_now_ms();
|
||||
}
|
||||
|
@ -230,7 +228,7 @@ namespace llarp
|
|||
const auto sz = p->hops.size();
|
||||
for (const auto& hop : p->hops)
|
||||
{
|
||||
auto& profile = m_Profiles[hop.rc.pubkey];
|
||||
auto& profile = m_Profiles[hop.rc.router_id()];
|
||||
// redeem previous fails by halfing the fail count and setting timeout to zero
|
||||
profile.pathFailCount /= 2;
|
||||
profile.pathTimeoutCount = 0;
|
||||
|
@ -262,7 +260,7 @@ namespace llarp
|
|||
|
||||
try
|
||||
{
|
||||
util::dump_file(fpath, buf);
|
||||
util::buffer_to_file(fpath, buf);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -299,7 +297,7 @@ namespace llarp
|
|||
{
|
||||
try
|
||||
{
|
||||
std::string data = util::slurp_file(fname);
|
||||
std::string data = util::file_to_string(fname);
|
||||
util::Lock lock{m_ProfilesMutex};
|
||||
BDecode(bt_dict_consumer{data});
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
RCGossiper::IsOurRC(const RouterContact& rc) const
|
||||
RCGossiper::IsOurRC(const LocalRC& rc) const
|
||||
{
|
||||
return rc.pubkey == rid;
|
||||
return rc.router_id() == rid;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -64,14 +64,14 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
RCGossiper::GossipRC(const RouterContact& rc)
|
||||
RCGossiper::GossipRC(const LocalRC& rc)
|
||||
{
|
||||
// only distribute public routers
|
||||
if (not rc.IsPublicRouter())
|
||||
if (not rc.is_public_router())
|
||||
return false;
|
||||
if (link_manager == nullptr)
|
||||
return false;
|
||||
const RouterID pubkey(rc.pubkey);
|
||||
const RouterID pubkey(rc.router_id());
|
||||
// filter check
|
||||
if (filter.Contains(pubkey))
|
||||
return false;
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace llarp
|
|||
/// The maximum number of peers we will flood a gossiped RC to when propagating an RC
|
||||
constexpr size_t MaxGossipPeers = 20;
|
||||
struct LinkManager;
|
||||
struct RouterContact;
|
||||
struct LocalRC;
|
||||
|
||||
struct RCGossiper
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace llarp
|
|||
~RCGossiper() = default;
|
||||
|
||||
bool
|
||||
GossipRC(const RouterContact& rc);
|
||||
GossipRC(const LocalRC& rc);
|
||||
|
||||
void
|
||||
Decay(Time_t now);
|
||||
|
@ -32,7 +32,7 @@ namespace llarp
|
|||
ShouldGossipOurRC(Time_t now) const;
|
||||
|
||||
bool
|
||||
IsOurRC(const RouterContact& rc) const;
|
||||
IsOurRC(const LocalRC& rc) const;
|
||||
|
||||
void
|
||||
Init(LinkManager*, const RouterID&, Router*);
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace llarp
|
|||
void
|
||||
RCLookupHandler::get_rc(const RouterID& rid, RCRequestCallback callback, bool forceLookup)
|
||||
{
|
||||
RouterContact remoteRC;
|
||||
RemoteRC remoteRC;
|
||||
|
||||
if (not forceLookup)
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ namespace llarp
|
|||
throw;
|
||||
}
|
||||
|
||||
RouterContact result{std::move(payload)};
|
||||
RemoteRC result{std::move(payload)};
|
||||
|
||||
if (callback)
|
||||
callback(result.router_id(), result, true);
|
||||
|
@ -202,24 +202,24 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
RCLookupHandler::check_rc(const RouterContact& rc) const
|
||||
RCLookupHandler::check_rc(const RemoteRC& rc) const
|
||||
{
|
||||
if (not is_session_allowed(rc.pubkey))
|
||||
if (not is_session_allowed(rc.router_id()))
|
||||
{
|
||||
contacts->delete_rc_node_async(dht::Key_t{rc.pubkey});
|
||||
contacts->delete_rc_node_async(dht::Key_t{rc.router_id()});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (not rc.Verify(llarp::time_now_ms()))
|
||||
if (not rc.verify())
|
||||
{
|
||||
LogWarn("RC for ", RouterID(rc.pubkey), " is invalid");
|
||||
log::info(link_cat, "Invalid RC (rid: {})", rc.router_id());
|
||||
return false;
|
||||
}
|
||||
|
||||
// update nodedb if required
|
||||
if (rc.IsPublicRouter())
|
||||
if (rc.is_public_router())
|
||||
{
|
||||
LogDebug("Adding or updating RC for ", RouterID(rc.pubkey), " to nodedb and dht.");
|
||||
log::info(link_cat, "Adding or updating RC (rid: {}) to nodeDB and DHT", rc.router_id());
|
||||
node_db->put_rc_if_newer(rc);
|
||||
contacts->put_rc_node_async(rc);
|
||||
}
|
||||
|
@ -248,29 +248,6 @@ namespace llarp
|
|||
});
|
||||
}
|
||||
|
||||
bool
|
||||
RCLookupHandler::check_renegotiate_valid(RouterContact newrc, RouterContact oldrc)
|
||||
{
|
||||
// mismatch of identity ?
|
||||
if (newrc.pubkey != oldrc.pubkey)
|
||||
return false;
|
||||
|
||||
if (!is_session_allowed(newrc.pubkey))
|
||||
return false;
|
||||
|
||||
auto func = [this, newrc] { check_rc(newrc); };
|
||||
work_func(func);
|
||||
|
||||
// update dht if required
|
||||
if (contacts->rc_nodes()->HasNode(dht::Key_t{newrc.pubkey}))
|
||||
{
|
||||
contacts->rc_nodes()->PutNode(newrc);
|
||||
}
|
||||
|
||||
// TODO: check for other places that need updating the RC
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RCLookupHandler::periodic_update(llarp_time_t now)
|
||||
{
|
||||
|
@ -278,15 +255,15 @@ namespace llarp
|
|||
std::unordered_set<RouterID> routersToLookUp;
|
||||
|
||||
node_db->VisitInsertedBefore(
|
||||
[&](const RouterContact& rc) { routersToLookUp.insert(rc.pubkey); },
|
||||
now - RouterContact::UpdateInterval);
|
||||
[&](const RouterContact& rc) { routersToLookUp.insert(rc.router_id()); },
|
||||
now - RouterContact::REPUBLISH);
|
||||
|
||||
for (const auto& router : routersToLookUp)
|
||||
{
|
||||
get_rc(router, nullptr, true);
|
||||
}
|
||||
|
||||
node_db->remove_stale_rcs(boostrap_rid_list, now - RouterContact::StaleInsertionAge);
|
||||
node_db->remove_stale_rcs(boostrap_rid_list, now - RouterContact::STALE);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -301,7 +278,8 @@ namespace llarp
|
|||
{
|
||||
for (const auto& rc : bootstrap_rc_list)
|
||||
{
|
||||
log::info(link_cat, "Doing explore via bootstrap node: {}", RouterID(rc.pubkey));
|
||||
const auto& rid = rc.router_id();
|
||||
log::info(link_cat, "Doing explore via bootstrap node: {}", rid);
|
||||
|
||||
// TODO: replace this concept
|
||||
// dht->ExploreNetworkVia(dht::Key_t{rc.pubkey});
|
||||
|
@ -336,7 +314,7 @@ namespace llarp
|
|||
return;
|
||||
}
|
||||
// service nodes gossip, not explore
|
||||
if (contacts->router()->IsServiceNode())
|
||||
if (contacts->router()->is_service_node())
|
||||
return;
|
||||
|
||||
// explore via every connected peer
|
||||
|
@ -367,7 +345,7 @@ namespace llarp
|
|||
LinkManager* linkManager,
|
||||
service::Context* hiddenServiceContext,
|
||||
const std::unordered_set<RouterID>& strictConnectPubkeys,
|
||||
const std::set<RouterContact>& bootstrapRCList,
|
||||
const std::set<RemoteRC>& bootstrapRCList,
|
||||
bool isServiceNode_arg)
|
||||
{
|
||||
contacts = c;
|
||||
|
@ -383,7 +361,7 @@ namespace llarp
|
|||
|
||||
for (const auto& rc : bootstrap_rc_list)
|
||||
{
|
||||
boostrap_rid_list.insert(rc.pubkey);
|
||||
boostrap_rid_list.insert(rc.router_id());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,7 +370,7 @@ namespace llarp
|
|||
{
|
||||
for (const auto& rc : bootstrap_rc_list)
|
||||
{
|
||||
if (rc.pubkey == remote)
|
||||
if (rc.router_id() == remote)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/router_contact.hpp>
|
||||
#include <llarp/router_id.hpp>
|
||||
#include <llarp/util/thread/threading.hpp>
|
||||
|
||||
|
@ -24,7 +25,6 @@ namespace llarp
|
|||
|
||||
struct Contacts;
|
||||
struct LinkManager;
|
||||
struct RouterContact;
|
||||
|
||||
enum class RCRequestResult
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ namespace llarp
|
|||
};
|
||||
|
||||
using RCRequestCallback =
|
||||
std::function<void(const RouterID&, std::optional<RouterContact>, bool success)>;
|
||||
std::function<void(const RouterID&, std::optional<RemoteRC>, bool success)>;
|
||||
|
||||
struct RCLookupHandler
|
||||
{
|
||||
|
@ -80,14 +80,11 @@ namespace llarp
|
|||
is_registered(const RouterID& remote) const;
|
||||
|
||||
bool
|
||||
check_rc(const RouterContact& rc) const;
|
||||
check_rc(const RemoteRC& rc) const;
|
||||
|
||||
bool
|
||||
get_random_whitelist_router(RouterID& router) const;
|
||||
|
||||
bool
|
||||
check_renegotiate_valid(RouterContact newrc, RouterContact oldrc);
|
||||
|
||||
void
|
||||
periodic_update(llarp_time_t now);
|
||||
|
||||
|
@ -106,7 +103,7 @@ namespace llarp
|
|||
LinkManager* linkManager,
|
||||
service::Context* hiddenServiceContext,
|
||||
const std::unordered_set<RouterID>& strictConnectPubkeys,
|
||||
const std::set<RouterContact>& bootstrapRCList,
|
||||
const std::set<RemoteRC>& bootstrapRCList,
|
||||
bool isServiceNode_arg);
|
||||
|
||||
std::unordered_set<RouterID>
|
||||
|
@ -128,7 +125,7 @@ namespace llarp
|
|||
/// service nodes)
|
||||
std::unordered_set<RouterID> strict_connect_pubkeys;
|
||||
|
||||
std::set<RouterContact> bootstrap_rc_list;
|
||||
std::set<RemoteRC> bootstrap_rc_list;
|
||||
std::unordered_set<RouterID> boostrap_rid_list;
|
||||
|
||||
// Now that all calls are made through the event loop, any access to these
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("route-poker");
|
||||
|
||||
void
|
||||
RoutePoker::add_route(oxen::quic::Address ip)
|
||||
{
|
||||
|
@ -119,7 +117,7 @@ namespace llarp
|
|||
bool
|
||||
RoutePoker::is_enabled() const
|
||||
{
|
||||
if (router.IsServiceNode())
|
||||
if (router.is_service_node())
|
||||
return false;
|
||||
if (const auto& conf = router.config())
|
||||
return conf->network.m_EnableRoutePoker;
|
||||
|
@ -221,7 +219,7 @@ namespace llarp
|
|||
|
||||
// explicit route pokes for first hops
|
||||
router.for_each_connection(
|
||||
[this](link::Connection conn) { add_route(conn.remote_rc.addr); });
|
||||
[this](link::Connection conn) { add_route(conn.remote_rc.addr()); });
|
||||
|
||||
add_route(router.link_manager().local());
|
||||
// add default route
|
||||
|
@ -240,7 +238,7 @@ namespace llarp
|
|||
{
|
||||
// unpoke routes for first hops
|
||||
router.for_each_connection(
|
||||
[this](link::Connection conn) { delete_route(conn.remote_rc.addr); });
|
||||
[this](link::Connection conn) { delete_route(conn.remote_rc.addr()); });
|
||||
if (is_enabled() and is_up)
|
||||
{
|
||||
vpn::AbstractRouteManager& route = router.vpn_platform()->RouteManager();
|
||||
|
|
|
@ -36,8 +36,6 @@ static constexpr std::chrono::milliseconds ROUTER_TICK_INTERVAL = 250ms;
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("router");
|
||||
|
||||
Router::Router(EventLoop_ptr loop, std::shared_ptr<vpn::Platform> vpnPlatform)
|
||||
: _route_poker{std::make_shared<RoutePoker>(*this)}
|
||||
, _lmq{std::make_shared<oxenmq::OxenMQ>()}
|
||||
|
@ -178,7 +176,7 @@ namespace llarp
|
|||
|
||||
util::StatusObject stats{
|
||||
{"running", true},
|
||||
{"version", llarp::VERSION_FULL},
|
||||
{"version", llarp::LOKINET_VERSION_FULL},
|
||||
{"uptime", to_json(Uptime())},
|
||||
{"numPathsBuilt", pathsCount},
|
||||
{"numPeersConnected", peers},
|
||||
|
@ -201,7 +199,7 @@ namespace llarp
|
|||
void
|
||||
Router::Freeze()
|
||||
{
|
||||
if (IsServiceNode())
|
||||
if (is_service_node())
|
||||
return;
|
||||
|
||||
for_each_connection(
|
||||
|
@ -211,13 +209,14 @@ namespace llarp
|
|||
void
|
||||
Router::Thaw()
|
||||
{
|
||||
if (IsServiceNode())
|
||||
if (is_service_node())
|
||||
return;
|
||||
|
||||
std::unordered_set<RouterID> peer_pubkeys;
|
||||
|
||||
for_each_connection(
|
||||
[&peer_pubkeys](link::Connection& conn) { peer_pubkeys.emplace(conn.remote_rc.pubkey); });
|
||||
for_each_connection([&peer_pubkeys](link::Connection& conn) {
|
||||
peer_pubkeys.emplace(conn.remote_rc.router_id());
|
||||
});
|
||||
|
||||
loop()->call([this, &peer_pubkeys]() {
|
||||
for (auto& pk : peer_pubkeys)
|
||||
|
@ -232,10 +231,10 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
Router::GossipRCIfNeeded(const RouterContact rc)
|
||||
Router::GossipRCIfNeeded(const LocalRC rc)
|
||||
{
|
||||
/// if we are not a service node forget about gossip
|
||||
if (not IsServiceNode())
|
||||
if (not is_service_node())
|
||||
return;
|
||||
/// wait for random uptime
|
||||
if (std::chrono::milliseconds{Uptime()} < _randomStartDelay)
|
||||
|
@ -246,14 +245,14 @@ namespace llarp
|
|||
bool
|
||||
Router::GetRandomGoodRouter(RouterID& router)
|
||||
{
|
||||
if (IsServiceNode())
|
||||
if (is_service_node())
|
||||
{
|
||||
return _rc_lookup_handler.get_random_whitelist_router(router);
|
||||
}
|
||||
|
||||
if (auto maybe = node_db()->GetRandom([](const auto&) -> bool { return true; }))
|
||||
{
|
||||
router = maybe->pubkey;
|
||||
router = maybe->router_id();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -272,7 +271,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
Router::connect_to(const RouterContact& rc)
|
||||
Router::connect_to(const RemoteRC& rc)
|
||||
{
|
||||
_link_manager.connect_to(rc);
|
||||
}
|
||||
|
@ -315,7 +314,7 @@ namespace llarp
|
|||
{
|
||||
_encryption = _key_manager->encryptionKey;
|
||||
|
||||
if (IsServiceNode())
|
||||
if (is_service_node())
|
||||
{
|
||||
#if defined(ANDROID) || defined(IOS)
|
||||
LogError("running a service node on mobile device is not possible.");
|
||||
|
@ -397,9 +396,9 @@ namespace llarp
|
|||
|
||||
log::debug(logcat, "Configuring router");
|
||||
|
||||
is_service_node = conf.router.m_isRelay;
|
||||
_is_service_node = conf.router.m_isRelay;
|
||||
|
||||
if (is_service_node)
|
||||
if (_is_service_node)
|
||||
{
|
||||
rpc_addr = oxenmq::address(conf.lokid.lokidRPCAddr);
|
||||
_rpc_client = std::make_shared<rpc::LokidRpcClient>(_lmq, weak_from_this());
|
||||
|
@ -418,9 +417,9 @@ namespace llarp
|
|||
_node_db = std::move(nodedb);
|
||||
|
||||
log::debug(
|
||||
logcat, is_service_node ? "Running as a relay (service node)" : "Running as a client");
|
||||
logcat, _is_service_node ? "Running as a relay (service node)" : "Running as a client");
|
||||
|
||||
if (is_service_node)
|
||||
if (_is_service_node)
|
||||
{
|
||||
_rpc_client->ConnectAsync(rpc_addr);
|
||||
}
|
||||
|
@ -439,34 +438,10 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
/// called in disk worker thread
|
||||
void
|
||||
Router::HandleSaveRC() const
|
||||
{
|
||||
std::string fname = our_rc_file.string();
|
||||
router_contact.Write(fname.c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
Router::SaveRC()
|
||||
Router::is_service_node() const
|
||||
{
|
||||
LogDebug("verify RC signature");
|
||||
if (!router_contact.Verify(now()))
|
||||
{
|
||||
Dump<MAX_RC_SIZE>(rc());
|
||||
LogError("RC is invalid, not saving");
|
||||
return false;
|
||||
}
|
||||
if (is_service_node)
|
||||
_node_db->put_rc(router_contact);
|
||||
queue_disk_io([&]() { HandleSaveRC(); });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Router::IsServiceNode() const
|
||||
{
|
||||
return is_service_node;
|
||||
return _is_service_node;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -508,7 +483,7 @@ namespace llarp
|
|||
bool
|
||||
Router::have_snode_whitelist() const
|
||||
{
|
||||
return IsServiceNode() and _rc_lookup_handler.has_received_whitelist();
|
||||
return is_service_node() and _rc_lookup_handler.has_received_whitelist();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -564,18 +539,20 @@ namespace llarp
|
|||
return _link_manager.get_num_connected_clients();
|
||||
}
|
||||
|
||||
void
|
||||
Router::save_rc()
|
||||
{
|
||||
_node_db->put_rc(router_contact.view());
|
||||
queue_disk_io([&]() { router_contact.write(our_rc_file); });
|
||||
}
|
||||
|
||||
bool
|
||||
Router::update_rc()
|
||||
{
|
||||
SecretKey nextOnionKey;
|
||||
RouterContact nextRC = router_contact;
|
||||
if (!nextRC.Sign(identity()))
|
||||
return false;
|
||||
if (!nextRC.Verify(time_now_ms(), false))
|
||||
return false;
|
||||
router_contact = std::move(nextRC);
|
||||
if (IsServiceNode())
|
||||
return SaveRC();
|
||||
router_contact.resign();
|
||||
if (is_service_node())
|
||||
save_rc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -585,20 +562,17 @@ namespace llarp
|
|||
// Set netid before anything else
|
||||
log::debug(logcat, "Network ID set to {}", conf.router.m_netId);
|
||||
if (!conf.router.m_netId.empty()
|
||||
&& strcmp(conf.router.m_netId.c_str(), llarp::DEFAULT_NETID) != 0)
|
||||
&& strcmp(conf.router.m_netId.c_str(), llarp::LOKINET_DEFAULT_NETID) != 0)
|
||||
{
|
||||
const auto& netid = conf.router.m_netId;
|
||||
llarp::LogWarn(
|
||||
"!!!! you have manually set netid to be '",
|
||||
netid,
|
||||
"' which does not equal '",
|
||||
llarp::DEFAULT_NETID,
|
||||
llarp::LOKINET_DEFAULT_NETID,
|
||||
"' you will run as a different network, good luck "
|
||||
"and don't forget: something something MUH traffic "
|
||||
"shape correlation !!!!");
|
||||
NetID::DefaultValue() = NetID(reinterpret_cast<const byte_t*>(netid.c_str()));
|
||||
// reset netid in our rc
|
||||
router_contact.netID = llarp::NetID();
|
||||
}
|
||||
|
||||
// Router config
|
||||
|
@ -628,16 +602,17 @@ namespace llarp
|
|||
else
|
||||
log::debug(logcat, "No explicit public address given; will auto-detect during link setup");
|
||||
|
||||
RouterContact::BlockBogons = conf.router.m_blockBogons;
|
||||
RouterContact::BLOCK_BOGONS = conf.router.m_blockBogons;
|
||||
|
||||
auto& networkConfig = conf.network;
|
||||
|
||||
/// build a set of strictConnectPubkeys (
|
||||
/// build a set of strictConnectPubkeys
|
||||
std::unordered_set<RouterID> strictConnectPubkeys;
|
||||
|
||||
if (not networkConfig.m_strictConnect.empty())
|
||||
{
|
||||
const auto& val = networkConfig.m_strictConnect;
|
||||
if (IsServiceNode())
|
||||
if (is_service_node())
|
||||
throw std::runtime_error("cannot use strict-connect option as service node");
|
||||
if (val.size() < 2)
|
||||
throw std::runtime_error(
|
||||
|
@ -666,7 +641,7 @@ namespace llarp
|
|||
for (const auto& router : configRouters)
|
||||
{
|
||||
log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile);
|
||||
bootstrap_rc_list.AddFromFile(router);
|
||||
bootstrap_rc_list.read_from_file(router);
|
||||
}
|
||||
|
||||
for (const auto& rc : conf.bootstrap.routers)
|
||||
|
@ -674,37 +649,10 @@ namespace llarp
|
|||
bootstrap_rc_list.emplace(rc);
|
||||
}
|
||||
|
||||
// in case someone has an old bootstrap file and is trying to use a bootstrap
|
||||
// that no longer exists
|
||||
auto clearBadRCs = [this]() {
|
||||
for (auto it = bootstrap_rc_list.begin(); it != bootstrap_rc_list.end();)
|
||||
{
|
||||
if (it->IsObsoleteBootstrap())
|
||||
log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID{it->pubkey});
|
||||
else if (not it->Verify(now()))
|
||||
log::warning(logcat, "ignoring invalid bootstrap RC: {}", RouterID{it->pubkey});
|
||||
else
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
// we are in one of the above error cases that we warned about:
|
||||
it = bootstrap_rc_list.erase(it);
|
||||
}
|
||||
};
|
||||
|
||||
clearBadRCs();
|
||||
|
||||
if (bootstrap_rc_list.empty() and not conf.bootstrap.seednode)
|
||||
{
|
||||
auto fallbacks = llarp::load_bootstrap_fallbacks();
|
||||
if (auto itr = fallbacks.find(router_contact.netID.ToString()); itr != fallbacks.end())
|
||||
{
|
||||
bootstrap_rc_list = itr->second;
|
||||
log::debug(
|
||||
logcat, "loaded {} default fallback bootstrap routers", bootstrap_rc_list.size());
|
||||
clearBadRCs();
|
||||
}
|
||||
|
||||
if (bootstrap_rc_list.empty() and not conf.bootstrap.seednode)
|
||||
{
|
||||
// empty after trying fallback, if set
|
||||
|
@ -717,6 +665,24 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
// in case someone has an old bootstrap file and is trying to use a bootstrap
|
||||
// that no longer exists
|
||||
for (auto it = bootstrap_rc_list.begin(); it != bootstrap_rc_list.end();)
|
||||
{
|
||||
if (it->is_obsolete_bootstrap())
|
||||
log::warning(logcat, "ignoring obsolete boostrap RC: {}", it->router_id());
|
||||
else if (not it->verify())
|
||||
log::warning(logcat, "ignoring invalid bootstrap RC: {}", it->router_id());
|
||||
else
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we are in one of the above error cases that we warned about:
|
||||
it = bootstrap_rc_list.erase(it);
|
||||
}
|
||||
|
||||
if (conf.bootstrap.seednode)
|
||||
LogInfo("we are a seed node");
|
||||
else
|
||||
|
@ -733,10 +699,10 @@ namespace llarp
|
|||
&_hidden_service_context,
|
||||
strictConnectPubkeys,
|
||||
bootstrap_rc_list,
|
||||
is_service_node);
|
||||
_is_service_node);
|
||||
|
||||
// FIXME: kludge for now, will be part of larger cleanup effort.
|
||||
if (is_service_node)
|
||||
if (_is_service_node)
|
||||
InitInboundLinks();
|
||||
else
|
||||
InitOutboundLinks();
|
||||
|
@ -765,7 +731,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
// API config
|
||||
if (not IsServiceNode())
|
||||
if (not is_service_node())
|
||||
{
|
||||
hidden_service_context().AddEndpoint(conf);
|
||||
}
|
||||
|
@ -773,19 +739,13 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Router::CheckRenegotiateValid(RouterContact newrc, RouterContact oldrc)
|
||||
{
|
||||
return _rc_lookup_handler.check_renegotiate_valid(newrc, oldrc);
|
||||
}
|
||||
|
||||
bool
|
||||
Router::IsBootstrapNode(const RouterID r) const
|
||||
{
|
||||
return std::count_if(
|
||||
bootstrap_rc_list.begin(),
|
||||
bootstrap_rc_list.end(),
|
||||
[r](const RouterContact& rc) -> bool { return rc.pubkey == r; })
|
||||
[r](const RemoteRC& rc) -> bool { return rc.router_id() == r; })
|
||||
> 0;
|
||||
}
|
||||
|
||||
|
@ -800,17 +760,24 @@ namespace llarp
|
|||
Router::report_stats()
|
||||
{
|
||||
const auto now = llarp::time_now_ms();
|
||||
LogInfo(node_db()->num_loaded(), " RCs loaded");
|
||||
LogInfo(bootstrap_rc_list.size(), " bootstrap peers");
|
||||
LogInfo(NumberOfConnectedRouters(), " router connections");
|
||||
if (IsServiceNode())
|
||||
log::info(
|
||||
logcat,
|
||||
"{} RCs loaded with {} bootstrap peers and {} router connections!",
|
||||
node_db()->num_loaded(),
|
||||
bootstrap_rc_list.size(),
|
||||
NumberOfConnectedRouters());
|
||||
|
||||
if (is_service_node())
|
||||
{
|
||||
LogInfo(NumberOfConnectedClients(), " client connections");
|
||||
LogInfo(ToString(router_contact.Age(now)), " since we last updated our RC");
|
||||
LogInfo(ToString(router_contact.TimeUntilExpires(now)), " until our RC expires");
|
||||
log::info(
|
||||
logcat,
|
||||
"Local service node has {} client connections since last RC update ({} to expiry)",
|
||||
NumberOfConnectedClients(),
|
||||
router_contact.age(now),
|
||||
router_contact.time_to_expiry(now));
|
||||
}
|
||||
if (_last_stats_report > 0s)
|
||||
LogInfo(ToString(now - _last_stats_report), " last reported stats");
|
||||
log::info(logcat, "Last reported stats time {}", now - _last_stats_report);
|
||||
_last_stats_report = now;
|
||||
}
|
||||
|
||||
|
@ -819,8 +786,8 @@ namespace llarp
|
|||
{
|
||||
std::string status;
|
||||
auto out = std::back_inserter(status);
|
||||
fmt::format_to(out, "v{}", fmt::join(llarp::VERSION, "."));
|
||||
if (IsServiceNode())
|
||||
fmt::format_to(out, "v{}", fmt::join(llarp::LOKINET_VERSION, "."));
|
||||
if (is_service_node())
|
||||
{
|
||||
fmt::format_to(
|
||||
out,
|
||||
|
@ -896,12 +863,13 @@ namespace llarp
|
|||
_rc_lookup_handler.periodic_update(now);
|
||||
|
||||
const bool has_whitelist = _rc_lookup_handler.has_received_whitelist();
|
||||
const bool is_snode = IsServiceNode();
|
||||
const bool is_snode = is_service_node();
|
||||
const bool is_decommed = appears_decommed();
|
||||
bool should_gossip = appears_funded();
|
||||
|
||||
if (is_snode
|
||||
and (router_contact.ExpiresSoon(now, std::chrono::milliseconds(randint() % 10000)) or (now - router_contact.last_updated) > rc_regen_interval))
|
||||
and (router_contact.expires_within_delta(now, std::chrono::milliseconds(randint() % 10000))
|
||||
or (now - router_contact.timestamp().time_since_epoch()) > rc_regen_interval))
|
||||
{
|
||||
LogInfo("regenerating RC");
|
||||
if (update_rc())
|
||||
|
@ -921,24 +889,24 @@ namespace llarp
|
|||
GossipRCIfNeeded(router_contact);
|
||||
}
|
||||
// remove RCs for nodes that are no longer allowed by network policy
|
||||
node_db()->RemoveIf([&](const RouterContact& rc) -> bool {
|
||||
node_db()->RemoveIf([&](const RemoteRC& rc) -> bool {
|
||||
// don't purge bootstrap nodes from nodedb
|
||||
if (IsBootstrapNode(rc.pubkey))
|
||||
if (IsBootstrapNode(rc.router_id()))
|
||||
{
|
||||
log::trace(logcat, "Not removing {}: is bootstrap node", rc.pubkey);
|
||||
log::trace(logcat, "Not removing {}: is bootstrap node", rc.router_id());
|
||||
return false;
|
||||
}
|
||||
// if for some reason we stored an RC that isn't a valid router
|
||||
// purge this entry
|
||||
if (not rc.IsPublicRouter())
|
||||
if (not rc.is_public_router())
|
||||
{
|
||||
log::debug(logcat, "Removing {}: not a valid router", rc.pubkey);
|
||||
log::debug(logcat, "Removing {}: not a valid router", rc.router_id());
|
||||
return true;
|
||||
}
|
||||
/// clear out a fully expired RC
|
||||
if (rc.IsExpired(now))
|
||||
if (rc.is_expired(now))
|
||||
{
|
||||
log::debug(logcat, "Removing {}: RC is expired", rc.pubkey);
|
||||
log::debug(logcat, "Removing {}: RC is expired", rc.router_id());
|
||||
return true;
|
||||
}
|
||||
// clients have no notion of a whilelist
|
||||
|
@ -946,23 +914,23 @@ namespace llarp
|
|||
// routers that are not whitelisted for first hops
|
||||
if (not is_snode)
|
||||
{
|
||||
log::trace(logcat, "Not removing {}: we are a client and it looks fine", rc.pubkey);
|
||||
log::trace(logcat, "Not removing {}: we are a client and it looks fine", rc.router_id());
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we don't have the whitelist yet don't remove the entry
|
||||
if (not has_whitelist)
|
||||
{
|
||||
log::debug(logcat, "Skipping check on {}: don't have whitelist yet", rc.pubkey);
|
||||
log::debug(logcat, "Skipping check on {}: don't have whitelist yet", rc.router_id());
|
||||
return false;
|
||||
}
|
||||
// if we have no whitelist enabled or we have
|
||||
// the whitelist enabled and we got the whitelist
|
||||
// check against the whitelist and remove if it's not
|
||||
// in the whitelist OR if there is no whitelist don't remove
|
||||
if (has_whitelist and not _rc_lookup_handler.is_session_allowed(rc.pubkey))
|
||||
if (has_whitelist and not _rc_lookup_handler.is_session_allowed(rc.router_id()))
|
||||
{
|
||||
log::debug(logcat, "Removing {}: not a valid router", rc.pubkey);
|
||||
log::debug(logcat, "Removing {}: not a valid router", rc.router_id());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -971,10 +939,10 @@ namespace llarp
|
|||
if (not is_snode or not has_whitelist)
|
||||
{
|
||||
// find all deregistered relays
|
||||
std::unordered_set<PubKey> close_peers;
|
||||
std::unordered_set<RouterID> close_peers;
|
||||
|
||||
for_each_connection([this, &close_peers](link::Connection& conn) {
|
||||
const auto& pk = conn.remote_rc.pubkey;
|
||||
const auto& pk = conn.remote_rc.router_id();
|
||||
|
||||
if (conn.remote_is_relay and not _rc_lookup_handler.is_session_allowed(pk))
|
||||
close_peers.insert(pk);
|
||||
|
@ -982,7 +950,7 @@ namespace llarp
|
|||
|
||||
// mark peers as de-registered
|
||||
for (auto& peer : close_peers)
|
||||
_link_manager.deregister_peer(std::move(peer));
|
||||
_link_manager.deregister_peer(peer);
|
||||
}
|
||||
|
||||
_link_manager.check_persisting_conns(now);
|
||||
|
@ -1051,7 +1019,7 @@ namespace llarp
|
|||
std::set<dht::Key_t> peer_keys;
|
||||
|
||||
for_each_connection(
|
||||
[&peer_keys](link::Connection& conn) { peer_keys.emplace(conn.remote_rc.pubkey); });
|
||||
[&peer_keys](link::Connection& conn) { peer_keys.emplace(conn.remote_rc.router_id()); });
|
||||
|
||||
_contacts->rc_nodes()->RemoveIf(
|
||||
[&peer_keys](const dht::Key_t& k) -> bool { return peer_keys.count(k) == 0; });
|
||||
|
@ -1062,32 +1030,12 @@ namespace llarp
|
|||
_last_tick = llarp::time_now_ms();
|
||||
}
|
||||
|
||||
void
|
||||
Router::modify_rc(std::function<std::optional<RouterContact>(RouterContact)> modify)
|
||||
{
|
||||
if (auto maybe = modify(rc()))
|
||||
{
|
||||
router_contact = *maybe;
|
||||
update_rc();
|
||||
_rcGossiper.GossipRC(rc());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Router::GetRandomConnectedRouter(RouterContact& result) const
|
||||
Router::GetRandomConnectedRouter(RemoteRC& result) const
|
||||
{
|
||||
return _link_manager.get_random_connected(result);
|
||||
}
|
||||
|
||||
void
|
||||
Router::HandleDHTLookupForExplore(RouterID /*remote*/, const std::vector<RouterContact>& results)
|
||||
{
|
||||
for (const auto& rc : results)
|
||||
{
|
||||
_rc_lookup_handler.check_rc(rc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Router::set_router_whitelist(
|
||||
const std::vector<RouterID>& whitelist,
|
||||
|
@ -1112,80 +1060,48 @@ namespace llarp
|
|||
if (is_running || is_stopping)
|
||||
return false;
|
||||
|
||||
// set public signing key
|
||||
router_contact.pubkey = seckey_topublic(identity());
|
||||
// set router version if service node
|
||||
if (IsServiceNode())
|
||||
{
|
||||
router_contact.routerVersion = RouterVersion(llarp::VERSION, llarp::constants::proto_version);
|
||||
}
|
||||
router_contact = LocalRC::make(identity(), public_ip());
|
||||
|
||||
if (IsServiceNode() and not router_contact.IsPublicRouter())
|
||||
if (is_service_node() and not router_contact.is_public_router())
|
||||
{
|
||||
LogError("we are configured as relay but have no reachable addresses");
|
||||
return false;
|
||||
}
|
||||
|
||||
// set public encryption key
|
||||
router_contact.enckey = seckey_topublic(encryption());
|
||||
|
||||
LogInfo("Signing rc...");
|
||||
if (!router_contact.Sign(identity()))
|
||||
{
|
||||
LogError("failed to sign rc");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsServiceNode())
|
||||
{
|
||||
if (!SaveRC())
|
||||
if (not router_contact.is_public_router())
|
||||
{
|
||||
LogError("failed to save RC");
|
||||
log::error(logcat, "Router is configured as relay but has no reachable addresses!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsServiceNode())
|
||||
{
|
||||
// initialize as service node
|
||||
if (!InitServiceNode())
|
||||
save_rc();
|
||||
|
||||
if (not init_service_node())
|
||||
{
|
||||
LogError("Failed to initialize service node");
|
||||
log::error(logcat, "Router failed to initialize service node!");
|
||||
return false;
|
||||
}
|
||||
|
||||
log::info(logcat, "Router initialized as service node!");
|
||||
const RouterID us = pubkey();
|
||||
LogInfo("initalized service node: ", us);
|
||||
// init gossiper here
|
||||
_rcGossiper.Init(&_link_manager, us, this);
|
||||
// relays do not use profiling
|
||||
router_profiling().Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are a client
|
||||
// regenerate keys and resign rc before everything else
|
||||
// we are a client, regenerate keys and resign rc before everything else
|
||||
crypto::identity_keygen(_identity);
|
||||
crypto::encryption_keygen(_encryption);
|
||||
router_contact.pubkey = seckey_topublic(identity());
|
||||
router_contact.enckey = seckey_topublic(encryption());
|
||||
if (!router_contact.Sign(identity()))
|
||||
{
|
||||
LogError("failed to regenerate keys and sign RC");
|
||||
return false;
|
||||
}
|
||||
router_contact.set_router_id(seckey_to_pubkey(identity())); // resigns RC
|
||||
}
|
||||
|
||||
LogInfo("starting hidden service context...");
|
||||
log::info(logcat, "Starting hidden service context...");
|
||||
|
||||
if (!hidden_service_context().StartAll())
|
||||
{
|
||||
LogError("Failed to start hidden service context");
|
||||
log::error(logcat, "Failed to start hidden service context!");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
LogInfo("Loading nodedb from disk...");
|
||||
_node_db->load_from_disk();
|
||||
}
|
||||
log::info(logcat, "Loading NodeDB from disk...");
|
||||
_node_db->load_from_disk();
|
||||
|
||||
_contacts = std::make_shared<Contacts>(llarp::dht::Key_t(pubkey()), *this);
|
||||
|
||||
|
@ -1193,16 +1109,17 @@ namespace llarp
|
|||
{
|
||||
node_db()->put_rc(rc);
|
||||
_contacts->rc_nodes()->PutNode(rc);
|
||||
LogInfo("added bootstrap node ", RouterID{rc.pubkey});
|
||||
log::info(logcat, "Added bootstrap node (rid: {})", rc.router_id());
|
||||
}
|
||||
|
||||
LogInfo("have ", _node_db->num_loaded(), " routers");
|
||||
log::info(logcat, "Router populated NodeDB with {} routers", _node_db->num_loaded());
|
||||
|
||||
_loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); });
|
||||
_route_poker->start();
|
||||
is_running.store(true);
|
||||
_started_at = now();
|
||||
if (IsServiceNode())
|
||||
|
||||
if (is_service_node())
|
||||
{
|
||||
// do service node testing if we are in service node whitelist mode
|
||||
_loop->call_every(consensus::REACHABILITY_TESTING_TIMER_INTERVAL, weak_from_this(), [this] {
|
||||
|
@ -1223,13 +1140,16 @@ namespace llarp
|
|||
{
|
||||
if (not SessionToRouterAllowed(router))
|
||||
{
|
||||
LogDebug(
|
||||
router,
|
||||
" is no longer a registered service node so we remove it from the testing list");
|
||||
log::debug(
|
||||
logcat,
|
||||
"{} is no longer a registered service node; dropping from test list",
|
||||
router);
|
||||
router_testing.remove_node_from_failing(router);
|
||||
continue;
|
||||
}
|
||||
LogDebug("Establishing session to ", router, " for SN testing");
|
||||
|
||||
log::debug(logcat, "Establishing session to {} for service node testing", router);
|
||||
|
||||
// try to make a session to this random router
|
||||
// this will do a dht lookup if needed
|
||||
_link_manager.connect_to(router);
|
||||
|
@ -1406,7 +1326,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
Router::InitServiceNode()
|
||||
Router::init_service_node()
|
||||
{
|
||||
LogInfo("accepting transit traffic");
|
||||
paths.AllowTransit();
|
||||
|
@ -1430,7 +1350,7 @@ namespace llarp
|
|||
bool
|
||||
Router::HasClientExit() const
|
||||
{
|
||||
if (IsServiceNode())
|
||||
if (is_service_node())
|
||||
return false;
|
||||
const auto& ep = hidden_service_context().GetDefault();
|
||||
return ep and ep->HasExit();
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace llarp
|
|||
// use file based logging?
|
||||
bool use_file_logging = false;
|
||||
// our router contact
|
||||
RouterContact router_contact;
|
||||
LocalRC router_contact;
|
||||
std::shared_ptr<oxenmq::OxenMQ> _lmq;
|
||||
path::BuildLimiter _pathbuild_limiter;
|
||||
std::shared_ptr<EventLoopWakeup> loop_wakeup;
|
||||
|
@ -94,7 +94,7 @@ namespace llarp
|
|||
std::atomic<bool> is_running;
|
||||
|
||||
int _outbound_udp_socket = -1;
|
||||
bool is_service_node = false;
|
||||
bool _is_service_node = false;
|
||||
|
||||
std::optional<SockAddr> _ourAddress;
|
||||
oxen::quic::Address _local_addr;
|
||||
|
@ -147,6 +147,9 @@ namespace llarp
|
|||
void
|
||||
report_stats();
|
||||
|
||||
void
|
||||
save_rc();
|
||||
|
||||
bool
|
||||
update_rc();
|
||||
|
||||
|
@ -167,7 +170,7 @@ namespace llarp
|
|||
connect_to(const RouterID& rid);
|
||||
|
||||
void
|
||||
connect_to(const RouterContact& rc);
|
||||
connect_to(const RemoteRC& rc);
|
||||
|
||||
Contacts*
|
||||
contacts() const
|
||||
|
@ -274,7 +277,7 @@ namespace llarp
|
|||
return paths;
|
||||
}
|
||||
|
||||
const RouterContact&
|
||||
const LocalRC&
|
||||
rc() const
|
||||
{
|
||||
return router_contact;
|
||||
|
@ -295,9 +298,6 @@ namespace llarp
|
|||
return _rc_lookup_handler.whitelist();
|
||||
}
|
||||
|
||||
void
|
||||
modify_rc(std::function<std::optional<RouterContact>(RouterContact)> modify);
|
||||
|
||||
void
|
||||
set_router_whitelist(
|
||||
const std::vector<RouterID>& whitelist,
|
||||
|
@ -381,7 +381,7 @@ namespace llarp
|
|||
status_line();
|
||||
|
||||
void
|
||||
GossipRCIfNeeded(const RouterContact rc);
|
||||
GossipRCIfNeeded(const LocalRC rc);
|
||||
|
||||
void
|
||||
InitInboundLinks();
|
||||
|
@ -395,14 +395,14 @@ namespace llarp
|
|||
/// initialize us as a service node
|
||||
/// return true on success
|
||||
bool
|
||||
InitServiceNode();
|
||||
init_service_node();
|
||||
|
||||
bool
|
||||
IsRunning() const;
|
||||
|
||||
/// return true if we are running in service node mode
|
||||
bool
|
||||
IsServiceNode() const;
|
||||
is_service_node() const;
|
||||
|
||||
std::optional<std::string>
|
||||
OxendErrorState() const;
|
||||
|
@ -452,12 +452,6 @@ namespace llarp
|
|||
bool
|
||||
PathToRouterAllowed(const RouterID& router) const;
|
||||
|
||||
void
|
||||
HandleSaveRC() const;
|
||||
|
||||
bool
|
||||
SaveRC();
|
||||
|
||||
/// return true if we are a client with an exit configured
|
||||
bool
|
||||
HasClientExit() const;
|
||||
|
@ -465,7 +459,7 @@ namespace llarp
|
|||
const byte_t*
|
||||
pubkey() const
|
||||
{
|
||||
return seckey_topublic(_identity);
|
||||
return seckey_to_pubkey(_identity);
|
||||
}
|
||||
|
||||
/// send to remote router or queue for sending
|
||||
|
@ -489,13 +483,6 @@ namespace llarp
|
|||
|
||||
bool IsBootstrapNode(RouterID) const;
|
||||
|
||||
/// check if newRc matches oldRC and update local rc for this remote contact
|
||||
/// if valid
|
||||
/// returns true on valid and updated
|
||||
/// returns false otherwise
|
||||
bool
|
||||
CheckRenegotiateValid(RouterContact newRc, RouterContact oldRC);
|
||||
|
||||
/// call internal router ticker
|
||||
void
|
||||
Tick();
|
||||
|
@ -525,10 +512,7 @@ namespace llarp
|
|||
NumberOfConnectedClients() const;
|
||||
|
||||
bool
|
||||
GetRandomConnectedRouter(RouterContact& result) const;
|
||||
|
||||
void
|
||||
HandleDHTLookupForExplore(RouterID remote, const std::vector<RouterContact>& results);
|
||||
GetRandomConnectedRouter(RemoteRC& result) const;
|
||||
|
||||
bool
|
||||
HasSessionTo(const RouterID& remote) const;
|
||||
|
|
|
@ -12,437 +12,109 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("RC");
|
||||
|
||||
NetID&
|
||||
NetID::DefaultValue()
|
||||
{
|
||||
static NetID defaultID(reinterpret_cast<const byte_t*>(llarp::DEFAULT_NETID));
|
||||
return defaultID;
|
||||
}
|
||||
// RouterContact::RouterContact(std::string buf)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// oxenc::bt_list_consumer btlc{buf};
|
||||
|
||||
bool RouterContact::BlockBogons = true;
|
||||
// // signature.from_string(btlc.consume_string());
|
||||
// signed_bt_dict = btlc.consume_string();
|
||||
|
||||
/// 1 day rc lifespan
|
||||
constexpr auto rc_lifetime = 24h;
|
||||
/// an RC inserted long enough ago (4 hrs) is considered stale and is removed
|
||||
constexpr auto rc_stale_age = 4h;
|
||||
/// window of time in which a router wil try to update their RC before it is marked stale
|
||||
constexpr auto rc_update_window = 5min;
|
||||
/// update RCs shortly before they are about to expire
|
||||
constexpr auto rc_update_interval = rc_stale_age - rc_update_window;
|
||||
// // TODO: parse bt dict
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// log::warning(llarp_cat, "Error: RouterContact failed to populate bt encoded contents!");
|
||||
// }
|
||||
// }
|
||||
|
||||
llarp_time_t RouterContact::Lifetime = rc_lifetime;
|
||||
llarp_time_t RouterContact::StaleInsertionAge = rc_stale_age;
|
||||
llarp_time_t RouterContact::UpdateInterval = rc_update_interval;
|
||||
|
||||
/// how many rc lifetime intervals should we wait until purging an rc
|
||||
constexpr auto expiration_lifetime_generations = 10;
|
||||
/// the max age of an rc before we want to expire it
|
||||
constexpr auto rc_expire_age = rc_lifetime * expiration_lifetime_generations;
|
||||
|
||||
NetID::NetID(const byte_t* val)
|
||||
{
|
||||
const size_t len = strnlen(reinterpret_cast<const char*>(val), size());
|
||||
std::copy(val, val + len, begin());
|
||||
}
|
||||
|
||||
NetID::NetID() : NetID(DefaultValue().data())
|
||||
{}
|
||||
|
||||
bool
|
||||
NetID::operator==(const NetID& other) const
|
||||
{
|
||||
return ToString() == other.ToString();
|
||||
}
|
||||
|
||||
std::string
|
||||
NetID::ToString() const
|
||||
{
|
||||
return {begin(), std::find(begin(), end(), '\0')};
|
||||
}
|
||||
|
||||
bool
|
||||
NetID::BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
Zero();
|
||||
llarp_buffer_t strbuf;
|
||||
if (!bencode_read_string(buf, &strbuf))
|
||||
return false;
|
||||
|
||||
if (strbuf.sz > size())
|
||||
return false;
|
||||
|
||||
std::copy(strbuf.base, strbuf.base + strbuf.sz, begin());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NetID::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
auto term = std::find(begin(), end(), '\0');
|
||||
return bencode_write_bytestring(buf, data(), std::distance(begin(), term));
|
||||
}
|
||||
|
||||
RouterContact::RouterContact(std::string buf)
|
||||
{
|
||||
try
|
||||
{
|
||||
oxenc::bt_list_consumer btlc{buf};
|
||||
|
||||
signature.from_string(btlc.consume_string());
|
||||
signed_bt_dict = btlc.consume_string();
|
||||
|
||||
// TODO: parse bt dict
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log::warning(llarp_cat, "Error: RouterContact failed to populate bt encoded contents!");
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
RouterContact::bt_encode() const
|
||||
{
|
||||
oxenc::bt_list_producer btlp;
|
||||
|
||||
try
|
||||
{
|
||||
btlp.append(signature.ToView());
|
||||
btlp.append(signed_bt_dict);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log::warning(llarp_cat, "Error: RouterContact failed to bt encode contents!");
|
||||
}
|
||||
|
||||
return std::move(btlp).str();
|
||||
}
|
||||
// std::string
|
||||
// RouterContact::bt_encode() const
|
||||
// {
|
||||
// oxenc::bt_dict_producer btdp;
|
||||
// bt_encode(btdp);
|
||||
// return std::move(btdp).str();
|
||||
// }
|
||||
|
||||
void
|
||||
RouterContact::bt_encode_subdict(oxenc::bt_list_producer& btlp) const
|
||||
RouterContact::bt_load(oxenc::bt_dict_consumer& data)
|
||||
{
|
||||
btlp.append(signature.ToView());
|
||||
btlp.append(signed_bt_dict);
|
||||
}
|
||||
if (int rc_ver = data.require<uint8_t>(""); rc_ver != RC_VERSION)
|
||||
throw std::runtime_error{"Invalid RC: do not know how to parse v{} RCs"_format(rc_ver)};
|
||||
|
||||
std::string
|
||||
RouterContact::ToTXTRecord() const
|
||||
{
|
||||
std::string result;
|
||||
auto out = std::back_inserter(result);
|
||||
fmt::format_to(out, "addr={}; pk={}", addr.to_string(), pubkey);
|
||||
fmt::format_to(out, "updated={}; onion_pk={}; ", last_updated.count(), enckey.ToHex());
|
||||
if (routerVersion.has_value())
|
||||
fmt::format_to(out, "router_version={}; ", *routerVersion);
|
||||
return result;
|
||||
auto ipv4_port = data.require<std::string_view>("4");
|
||||
|
||||
if (ipv4_port.size() != 6)
|
||||
throw std::runtime_error{
|
||||
"Invalid RC address: expected 6-byte IPv4 IP/port, got {}"_format(ipv4_port.size())};
|
||||
|
||||
sockaddr_in s4;
|
||||
s4.sin_family = AF_INET;
|
||||
|
||||
std::memcpy(&s4.sin_addr.s_addr, ipv4_port.data(), 4);
|
||||
std::memcpy(&s4.sin_port, ipv4_port.data() + 4, 2);
|
||||
|
||||
_addr = oxen::quic::Address{&s4};
|
||||
|
||||
if (!_addr.is_public())
|
||||
throw std::runtime_error{"Invalid RC: IPv4 address is not a publicly routable IP"};
|
||||
|
||||
if (auto ipv6_port = data.maybe<std::string_view>("6"))
|
||||
{
|
||||
if (ipv6_port->size() != 18)
|
||||
throw std::runtime_error{
|
||||
"Invalid RC address: expected 18-byte IPv6 IP/port, got {}"_format(ipv6_port->size())};
|
||||
|
||||
sockaddr_in6 s6{};
|
||||
s6.sin6_family = AF_INET6;
|
||||
|
||||
std::memcpy(&s6.sin6_addr.s6_addr, ipv6_port->data(), 16);
|
||||
std::memcpy(&s6.sin6_port, ipv6_port->data() + 16, 2);
|
||||
|
||||
_addr6.emplace(&s6);
|
||||
if (!_addr6->is_public())
|
||||
throw std::runtime_error{"Invalid RC: IPv6 address is not a publicly routable IP"};
|
||||
}
|
||||
else
|
||||
{
|
||||
_addr6.reset();
|
||||
}
|
||||
|
||||
auto netid = data.maybe<std::string_view>("i").value_or(llarp::LOKINET_DEFAULT_NETID);
|
||||
if (netid != ACTIVE_NETID)
|
||||
throw std::runtime_error{
|
||||
"Invalid RC netid: expected {}, got {}; this is an RC for a different network!"_format(
|
||||
ACTIVE_NETID, netid)};
|
||||
|
||||
auto pk = data.require<std::string_view>("p");
|
||||
|
||||
if (pk.size() != RouterID::SIZE)
|
||||
throw std::runtime_error{"Invalid RC: router id has invalid size {}"_format(pk.size())};
|
||||
|
||||
std::memcpy(_router_id.data(), pk.data(), RouterID::SIZE);
|
||||
|
||||
_timestamp = rc_time{std::chrono::seconds{data.require<int64_t>("t")}};
|
||||
|
||||
auto ver = data.require<ustring_view>("v");
|
||||
|
||||
if (ver.size() != 3)
|
||||
throw std::runtime_error{
|
||||
"Invalid RC router version: received {} bytes (!= 3)"_format(ver.size())};
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
_router_version[i] = ver[i];
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::FromOurNetwork() const
|
||||
RouterContact::write(const fs::path& fname) const
|
||||
{
|
||||
return netID == NetID::DefaultValue();
|
||||
}
|
||||
|
||||
std::string
|
||||
RouterContact::bencode_signed_section() const
|
||||
{
|
||||
oxenc::bt_dict_producer btdp;
|
||||
|
||||
btdp.append("a", addr.to_string());
|
||||
btdp.append("i", netID.ToView());
|
||||
btdp.append("k", pubkey.bt_encode());
|
||||
btdp.append("p", enckey.ToView());
|
||||
btdp.append("r", routerVersion->ToString());
|
||||
|
||||
if (not srvRecords.empty())
|
||||
{
|
||||
auto sublist = btdp.append_list("s");
|
||||
|
||||
for (auto& s : srvRecords)
|
||||
sublist.append(s.bt_encode());
|
||||
}
|
||||
|
||||
btdp.append("u", last_updated.count());
|
||||
|
||||
return std::move(btdp).str();
|
||||
}
|
||||
|
||||
void
|
||||
RouterContact::Clear()
|
||||
{
|
||||
signature.Zero();
|
||||
enckey.Zero();
|
||||
pubkey.Zero();
|
||||
routerVersion = std::optional<RouterVersion>{};
|
||||
last_updated = 0s;
|
||||
srvRecords.clear();
|
||||
version = llarp::constants::proto_version;
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
RouterContact::ExtractStatus() const
|
||||
{
|
||||
util::StatusObject obj{
|
||||
{"lastUpdated", last_updated.count()},
|
||||
{"publicRouter", IsPublicRouter()},
|
||||
{"identity", pubkey.ToString()},
|
||||
{"address", addr.to_string()}};
|
||||
|
||||
if (routerVersion)
|
||||
{
|
||||
obj["routerVersion"] = routerVersion->ToString();
|
||||
}
|
||||
std::vector<util::StatusObject> srv;
|
||||
for (const auto& record : srvRecords)
|
||||
{
|
||||
srv.emplace_back(record.ExtractStatus());
|
||||
}
|
||||
obj["srvRecords"] = srv;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (*buf->cur == 'd') // old format
|
||||
{
|
||||
return DecodeVersion_0(buf);
|
||||
}
|
||||
else if (*buf->cur != 'l') // if not dict, should be new format and start with list
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto bte = view();
|
||||
|
||||
try
|
||||
{
|
||||
std::string_view buf_view(reinterpret_cast<char*>(buf->cur), buf->size_left());
|
||||
oxenc::bt_list_consumer btlist(buf_view);
|
||||
|
||||
uint64_t outer_version = btlist.consume_integer<uint64_t>();
|
||||
|
||||
if (outer_version == 1)
|
||||
{
|
||||
bool decode_result = DecodeVersion_1(btlist);
|
||||
|
||||
// advance the llarp_buffer_t since lokimq serialization is unaware of it.
|
||||
// FIXME: this is broken (current_buffer got dropped), but the whole thing is getting
|
||||
// replaced.
|
||||
// buf->cur += btlist.
|
||||
// current_buffer().data() - buf_view.data() + 1;
|
||||
|
||||
return decode_result;
|
||||
}
|
||||
else
|
||||
{
|
||||
log::warning(logcat, "Received RouterContact with unkown version ({})", outer_version);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::debug(logcat, "RouterContact::BDecode failed: {}", e.what());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::DecodeVersion_0(llarp_buffer_t* buf)
|
||||
{
|
||||
return bencode_decode_dict(*this, buf);
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::DecodeVersion_1(oxenc::bt_list_consumer& btlist)
|
||||
{
|
||||
auto signature_string = btlist.consume_string_view();
|
||||
signed_bt_dict = btlist.consume_dict_data();
|
||||
|
||||
if (not btlist.is_finished())
|
||||
{
|
||||
log::debug(logcat, "RouterContact serialized list too long for specified version.");
|
||||
return false;
|
||||
}
|
||||
|
||||
llarp_buffer_t sigbuf(signature_string.data(), signature_string.size());
|
||||
if (not signature.FromBytestring(&sigbuf))
|
||||
{
|
||||
log::debug(logcat, "RouterContact serialized signature had invalid length.");
|
||||
return false;
|
||||
}
|
||||
|
||||
llarp_buffer_t data_dict_buf(signed_bt_dict.data(), signed_bt_dict.size());
|
||||
return bencode_decode_dict(*this, &data_dict_buf);
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
|
||||
// TOFIX: fuck everything about llarp_buffer_t
|
||||
// if (!BEncodeMaybeReadDictEntry("a", addr, read, key, buf))
|
||||
// return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("i", netID, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("k", pubkey, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (key.startswith("r"))
|
||||
{
|
||||
RouterVersion r;
|
||||
if (not r.BDecode(buf))
|
||||
return false;
|
||||
routerVersion = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (not BEncodeMaybeReadDictList("s", srvRecords, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("p", enckey, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("u", last_updated, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictInt("v", version, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (key.startswith("x") and serializeExit)
|
||||
{
|
||||
return bencode_discard(buf);
|
||||
}
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf))
|
||||
return false;
|
||||
|
||||
return read or bencode_discard(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::IsPublicRouter() const
|
||||
{
|
||||
if (not routerVersion)
|
||||
return false;
|
||||
return addr.is_addressable();
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::IsExpired(llarp_time_t now) const
|
||||
{
|
||||
return Age(now) >= rc_expire_age;
|
||||
}
|
||||
|
||||
llarp_time_t
|
||||
RouterContact::TimeUntilExpires(llarp_time_t now) const
|
||||
{
|
||||
const auto expiresAt = last_updated + Lifetime;
|
||||
return now < expiresAt ? expiresAt - now : 0s;
|
||||
}
|
||||
|
||||
llarp_time_t
|
||||
RouterContact::Age(llarp_time_t now) const
|
||||
{
|
||||
return now > last_updated ? now - last_updated : 0s;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const
|
||||
{
|
||||
return TimeUntilExpires(now) <= dlt;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::Sign(const SecretKey& secretkey)
|
||||
{
|
||||
pubkey = llarp::seckey_topublic(secretkey);
|
||||
signature.Zero();
|
||||
last_updated = time_now_ms();
|
||||
|
||||
signed_bt_dict = bencode_signed_section();
|
||||
|
||||
return crypto::sign(
|
||||
signature,
|
||||
secretkey,
|
||||
reinterpret_cast<uint8_t*>(signed_bt_dict.data()),
|
||||
signed_bt_dict.size());
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::Verify(llarp_time_t now, bool allowExpired) const
|
||||
{
|
||||
if (netID != NetID::DefaultValue())
|
||||
{
|
||||
log::error(
|
||||
logcat, "netid mismatch: '{}' (theirs) != '{}' (ours)", netID, NetID::DefaultValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsExpired(now) and not allowExpired)
|
||||
return false;
|
||||
|
||||
// TODO: make net* overridable
|
||||
const auto* net = net::Platform::Default_ptr();
|
||||
|
||||
if (net->IsBogon(addr.in4()) && BlockBogons)
|
||||
{
|
||||
log::error(logcat, "invalid address info: {}", addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!VerifySignature())
|
||||
{
|
||||
log::error(logcat, "invalid signature: {}", *this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::VerifySignature() const
|
||||
{
|
||||
RouterContact copy;
|
||||
copy = *this;
|
||||
copy.signature.Zero();
|
||||
|
||||
auto bte = copy.bt_encode();
|
||||
return crypto::verify(pubkey, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), signature);
|
||||
}
|
||||
|
||||
static constexpr std::array obsolete_bootstraps = {
|
||||
"7a16ac0b85290bcf69b2f3b52456d7e989ac8913b4afbb980614e249a3723218"sv,
|
||||
"e6b3a6fe5e32c379b64212c72232d65b0b88ddf9bbaed4997409d329f8519e0b"sv,
|
||||
};
|
||||
|
||||
bool
|
||||
RouterContact::IsObsoleteBootstrap() const
|
||||
{
|
||||
for (const auto& k : obsolete_bootstraps)
|
||||
{
|
||||
if (pubkey.ToHex() == k)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::Write(const fs::path& fname) const
|
||||
{
|
||||
std::array<byte_t, MAX_RC_SIZE> tmp;
|
||||
llarp_buffer_t buf(tmp);
|
||||
|
||||
auto bte = bt_encode();
|
||||
buf.write(bte.begin(), bte.end());
|
||||
|
||||
try
|
||||
{
|
||||
util::dump_file(fname, tmp.data(), buf.cur - buf.base);
|
||||
util::buffer_to_file(fname, bte.data(), bte.size());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -452,35 +124,176 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
RouterContact::extract_status() const
|
||||
{
|
||||
util::StatusObject obj{
|
||||
{"lastUpdated", _timestamp.time_since_epoch().count()},
|
||||
{"publicRouter", is_public_router()},
|
||||
{"identity", _router_id.ToString()},
|
||||
{"address", _addr.to_string()}};
|
||||
|
||||
// if (routerVersion)
|
||||
// {
|
||||
// obj["routerVersion"] = routerVersion->ToString();
|
||||
// }
|
||||
// std::vector<util::StatusObject> srv;
|
||||
// for (const auto& record : srvRecords)
|
||||
// {
|
||||
// srv.emplace_back(record.ExtractStatus());
|
||||
// }
|
||||
// obj["srvRecords"] = srv;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::Read(const fs::path& fname)
|
||||
RouterContact::BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
std::array<byte_t, MAX_RC_SIZE> tmp;
|
||||
llarp_buffer_t buf(tmp);
|
||||
try
|
||||
{
|
||||
util::slurp_file(fname, tmp.data(), tmp.size());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::error(logcat, "Failed to read RC from {}: {}", fname, e.what());
|
||||
// TODO: unfuck all of this
|
||||
|
||||
(void)buf;
|
||||
|
||||
// clear();
|
||||
|
||||
// if (*buf->cur == 'd') // old format
|
||||
// {
|
||||
// return DecodeVersion_0(buf);
|
||||
// }
|
||||
// else if (*buf->cur != 'l') // if not dict, should be new format and start with list
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// try
|
||||
// {
|
||||
// std::string_view buf_view(reinterpret_cast<char*>(buf->cur), buf->size_left());
|
||||
// oxenc::bt_list_consumer btlist(buf_view);
|
||||
|
||||
// uint64_t outer_version = btlist.consume_integer<uint64_t>();
|
||||
|
||||
// if (outer_version == 1)
|
||||
// {
|
||||
// bool decode_result = DecodeVersion_1(btlist);
|
||||
|
||||
// // advance the llarp_buffer_t since lokimq serialization is unaware of it.
|
||||
// // FIXME: this is broken (current_buffer got dropped), but the whole thing is getting
|
||||
// // replaced.
|
||||
// // buf->cur += btlist.
|
||||
// // current_buffer().data() - buf_view.data() + 1;
|
||||
|
||||
// return decode_result;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// log::warning(logcat, "Received RouterContact with unkown version ({})", outer_version);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// catch (const std::exception& e)
|
||||
// {
|
||||
// log::debug(logcat, "RouterContact::BDecode failed: {}", e.what());
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
(void)key;
|
||||
|
||||
// TOFIX: fuck everything about llarp_buffer_t
|
||||
|
||||
// if (!BEncodeMaybeReadDictEntry("a", addr, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (!BEncodeMaybeReadDictEntry("i", netID, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (!BEncodeMaybeReadDictEntry("k", _router_id, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (key.startswith("r"))
|
||||
// {
|
||||
// RouterVersion r;
|
||||
// if (not r.BDecode(buf))
|
||||
// return false;
|
||||
// routerVersion = r;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (not BEncodeMaybeReadDictList("s", srvRecords, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (!BEncodeMaybeReadDictEntry("p", enckey, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (!BEncodeMaybeReadDictInt("u", _timestamp, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (!BEncodeMaybeReadDictInt("v", version, read, key, buf))
|
||||
// return false;
|
||||
|
||||
// if (key.startswith("x") and serializeExit)
|
||||
// {
|
||||
// return bencode_discard(buf);
|
||||
// }
|
||||
|
||||
// if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf))
|
||||
// return false;
|
||||
|
||||
return read or bencode_discard(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::is_public_router() const
|
||||
{
|
||||
if (_router_version.empty())
|
||||
return false;
|
||||
}
|
||||
return BDecode(&buf);
|
||||
return _addr.is_addressable();
|
||||
}
|
||||
|
||||
std::string
|
||||
RouterContact::ToString() const
|
||||
bool
|
||||
RouterContact::is_expired(llarp_time_t now) const
|
||||
{
|
||||
return fmt::format(
|
||||
"[RC k={} updated={} netid={} v={} ai={{{}}} e={} z={}]",
|
||||
pubkey,
|
||||
last_updated.count(),
|
||||
netID,
|
||||
version,
|
||||
fmt::format("{}", addr),
|
||||
enckey,
|
||||
signature);
|
||||
return age(now) >= _timestamp.time_since_epoch() + LIFETIME;
|
||||
}
|
||||
|
||||
llarp_time_t
|
||||
RouterContact::time_to_expiry(llarp_time_t now) const
|
||||
{
|
||||
const auto expiry = _timestamp.time_since_epoch() + LIFETIME;
|
||||
return now < expiry ? expiry - now : 0s;
|
||||
}
|
||||
|
||||
llarp_time_t
|
||||
RouterContact::age(llarp_time_t now) const
|
||||
{
|
||||
auto delta = now - _timestamp.time_since_epoch();
|
||||
return delta > 0s ? delta : 0s;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterContact::expires_within_delta(llarp_time_t now, llarp_time_t dlt) const
|
||||
{
|
||||
return time_to_expiry(now) <= dlt;
|
||||
}
|
||||
|
||||
static constexpr std::array obsolete_bootstraps = {
|
||||
"7a16ac0b85290bcf69b2f3b52456d7e989ac8913b4afbb980614e249a3723218"sv,
|
||||
"e6b3a6fe5e32c379b64212c72232d65b0b88ddf9bbaed4997409d329f8519e0b"sv,
|
||||
};
|
||||
|
||||
bool
|
||||
RouterContact::is_obsolete_bootstrap() const
|
||||
{
|
||||
for (const auto& k : obsolete_bootstraps)
|
||||
{
|
||||
if (_router_id.ToHex() == k)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "router_id.hpp"
|
||||
#include "router_version.hpp"
|
||||
|
||||
#include <llarp/constants/version.hpp>
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/dns/srv_data.hpp>
|
||||
#include <llarp/net/exit_info.hpp>
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/bencode.hpp>
|
||||
#include <llarp/util/status.hpp>
|
||||
|
@ -17,128 +17,148 @@
|
|||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#define MAX_RC_SIZE (1024)
|
||||
|
||||
namespace oxenc
|
||||
{
|
||||
class bt_list_consumer;
|
||||
} // namespace oxenc
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
/// NetID
|
||||
struct NetID final : public AlignedBuffer<8>
|
||||
{
|
||||
static NetID&
|
||||
DefaultValue();
|
||||
static auto logcat = log::Cat("RC");
|
||||
|
||||
NetID();
|
||||
using rc_time = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
||||
|
||||
explicit NetID(const byte_t* val);
|
||||
static inline constexpr size_t NETID_SIZE{8};
|
||||
|
||||
NetID(const NetID& other) = default;
|
||||
NetID&
|
||||
operator=(const NetID& other) = default;
|
||||
|
||||
bool
|
||||
operator==(const NetID& other) const;
|
||||
|
||||
bool
|
||||
operator!=(const NetID& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
};
|
||||
/// On the wire we encode the data as a dict containing:
|
||||
/// "" -- the RC format version, which must be == RouterContact::Version for us to attempt to
|
||||
/// parse the reset of the fields. (Future versions might have backwards-compat support
|
||||
/// for lower versions).
|
||||
/// "4" -- 6 byte packed IPv4 address & port: 4 bytes of IPv4 address followed by 2 bytes of
|
||||
/// port, both encoded in network (i.e. big-endian) order.
|
||||
/// "6" -- optional 18 byte IPv6 address & port: 16 byte raw IPv6 address followed by 2 bytes
|
||||
/// of port in network order.
|
||||
/// "i" -- optional network ID string of up to 8 bytes; this is omitted for the default network
|
||||
/// ID ("lokinet") but included for others (such as "gamma" for testnet).
|
||||
/// "p" -- 32-byte router pubkey
|
||||
/// "t" -- timestamp when this RC record was created (which also implicitly determines when it
|
||||
/// goes stale and when it expires).
|
||||
/// "v" -- lokinet version of the router; this is a three-byte packed value of
|
||||
/// MAJOR, MINOR, PATCH, e.g. \x00\x0a\x03 for 0.10.3.
|
||||
/// "~" -- signature of all of the previous serialized data, signed by "p"
|
||||
|
||||
/// RouterContact
|
||||
struct RouterContact
|
||||
{
|
||||
/// for unit tests
|
||||
static bool BlockBogons;
|
||||
static constexpr uint8_t RC_VERSION = 0;
|
||||
|
||||
static llarp_time_t Lifetime;
|
||||
static llarp_time_t UpdateInterval;
|
||||
static llarp_time_t StaleInsertionAge;
|
||||
/// Unit tests disable this to allow private IP ranges in RCs, which normally get rejected.
|
||||
static inline bool BLOCK_BOGONS = true;
|
||||
|
||||
RouterContact()
|
||||
static inline std::string ACTIVE_NETID{LOKINET_DEFAULT_NETID};
|
||||
|
||||
static inline constexpr size_t MAX_RC_SIZE = 1024;
|
||||
|
||||
/// Timespans for RCs:
|
||||
|
||||
/// How long (relative to its timestamp) before an RC becomes stale. Stale records are used
|
||||
/// (e.g. for path building) only if there are no non-stale records available, such as might be
|
||||
/// the case when a client has been turned off for a while.
|
||||
static constexpr auto STALE = 12h;
|
||||
|
||||
/// How long before an RC becomes invalid (and thus deleted).
|
||||
static constexpr auto LIFETIME = 30 * 24h;
|
||||
|
||||
/// How long before a relay updates and re-publish its RC to the network. (Relays can
|
||||
/// re-publish more frequently than this if needed; this is meant to apply only if there are no
|
||||
/// changes i.e. just to push out a new confirmation of the details).
|
||||
static constexpr auto REPUBLISH = STALE / 2 - 5min;
|
||||
|
||||
ustring_view
|
||||
view() const
|
||||
{
|
||||
Clear();
|
||||
return _payload;
|
||||
}
|
||||
|
||||
RouterContact(std::string buf);
|
||||
/// Getters for private attributes
|
||||
const oxen::quic::Address&
|
||||
addr() const
|
||||
{
|
||||
return _addr;
|
||||
}
|
||||
|
||||
const std::optional<oxen::quic::Address>&
|
||||
addr6() const
|
||||
{
|
||||
return _addr6;
|
||||
}
|
||||
|
||||
const RouterID&
|
||||
router_id() const
|
||||
{
|
||||
return _router_id;
|
||||
}
|
||||
|
||||
const rc_time&
|
||||
timestamp() const
|
||||
{
|
||||
return _timestamp;
|
||||
}
|
||||
|
||||
protected:
|
||||
// advertised addresses
|
||||
oxen::quic::Address addr;
|
||||
// network identifier
|
||||
NetID netID;
|
||||
// public encryption public key
|
||||
llarp::PubKey enckey;
|
||||
oxen::quic::Address _addr; // refactor all 15 uses to use addr() method
|
||||
std::optional<oxen::quic::Address> _addr6; // optional ipv6
|
||||
// public signing public key
|
||||
llarp::PubKey pubkey;
|
||||
// signature
|
||||
llarp::Signature signature;
|
||||
RouterID _router_id; // refactor all 103 uses to use router_id() method
|
||||
|
||||
llarp_time_t last_updated = 0s;
|
||||
uint64_t version = llarp::constants::proto_version;
|
||||
std::optional<RouterVersion> routerVersion;
|
||||
rc_time _timestamp{};
|
||||
|
||||
// Lokinet version at the time the RC was produced
|
||||
std::array<uint8_t, 3> _router_version;
|
||||
|
||||
// In both Remote and Local RC's, the entire bt-encoded payload given at construction is
|
||||
// emplaced here.
|
||||
//
|
||||
// In a RemoteRC, this value will be held for the lifetime of the object
|
||||
// s.t. it can be returned upon calls to ::bt_encode.
|
||||
// In a LocalRC, this value will be supplanted any time a mutator is invoked, requiring
|
||||
// the re-signing of the payload.
|
||||
ustring _payload;
|
||||
|
||||
public:
|
||||
/// should we serialize the exit info?
|
||||
const static bool serializeExit = true;
|
||||
|
||||
std::string signed_bt_dict;
|
||||
|
||||
std::vector<dns::SRVData> srvRecords;
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const;
|
||||
|
||||
RouterID
|
||||
router_id() const
|
||||
{
|
||||
return pubkey;
|
||||
}
|
||||
extract_status() const;
|
||||
|
||||
nlohmann::json
|
||||
ToJson() const
|
||||
to_json() const
|
||||
{
|
||||
return ExtractStatus();
|
||||
return extract_status();
|
||||
}
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
virtual std::string
|
||||
to_string() const
|
||||
{
|
||||
return fmt::format(
|
||||
"[RC k={} updated={} v={} addr={}]",
|
||||
_router_id.ToView(),
|
||||
_timestamp.time_since_epoch().count(),
|
||||
RC_VERSION,
|
||||
_addr.to_string());
|
||||
}
|
||||
|
||||
std::string
|
||||
bt_encode() const;
|
||||
|
||||
void
|
||||
bt_encode_subdict(oxenc::bt_list_producer& btlp) const;
|
||||
|
||||
std::string
|
||||
bencode_signed_section() const;
|
||||
|
||||
std::string
|
||||
ToTXTRecord() const;
|
||||
bool
|
||||
write(const fs::path& fname) const;
|
||||
|
||||
bool
|
||||
operator==(const RouterContact& other) const
|
||||
{
|
||||
return addr == other.addr && enckey == other.enckey && pubkey == other.pubkey
|
||||
&& signature == other.signature && last_updated == other.last_updated
|
||||
&& netID == other.netID;
|
||||
return _router_id == other._router_id and _addr == other._addr and _addr6 == other._addr6
|
||||
and _timestamp == other._timestamp and _router_version == other._router_version;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const RouterContact& other) const
|
||||
{
|
||||
return pubkey < other.pubkey;
|
||||
return _router_id < other._router_id;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -147,14 +167,9 @@ namespace llarp
|
|||
return !(*this == other);
|
||||
}
|
||||
|
||||
void
|
||||
Clear();
|
||||
|
||||
bool
|
||||
IsExit() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual void
|
||||
clear()
|
||||
{}
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf);
|
||||
|
@ -163,66 +178,182 @@ namespace llarp
|
|||
decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
IsPublicRouter() const;
|
||||
|
||||
bool
|
||||
Verify(llarp_time_t now, bool allowExpired = true) const;
|
||||
|
||||
bool
|
||||
Sign(const llarp::SecretKey& secret);
|
||||
is_public_router() const;
|
||||
|
||||
/// does this RC expire soon? default delta is 1 minute
|
||||
bool
|
||||
ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 1min) const;
|
||||
expires_within_delta(llarp_time_t now, llarp_time_t dlt = 1min) const;
|
||||
|
||||
/// returns true if this RC is expired and should be removed
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const;
|
||||
is_expired(llarp_time_t now) const;
|
||||
|
||||
/// returns time in ms until we expire or 0 if we have expired
|
||||
llarp_time_t
|
||||
TimeUntilExpires(llarp_time_t now) const;
|
||||
time_to_expiry(llarp_time_t now) const;
|
||||
|
||||
/// get the age of this RC in ms
|
||||
llarp_time_t
|
||||
Age(llarp_time_t now) const;
|
||||
age(llarp_time_t now) const;
|
||||
|
||||
bool
|
||||
OtherIsNewer(const RouterContact& other) const
|
||||
other_is_newer(const RouterContact& other) const
|
||||
{
|
||||
return last_updated < other.last_updated;
|
||||
return _timestamp < other._timestamp;
|
||||
}
|
||||
|
||||
bool
|
||||
Read(const fs::path& fname);
|
||||
is_obsolete_bootstrap() const;
|
||||
|
||||
bool
|
||||
Write(const fs::path& fname) const;
|
||||
void
|
||||
bt_load(oxenc::bt_dict_consumer& data);
|
||||
};
|
||||
|
||||
bool
|
||||
VerifySignature() const;
|
||||
|
||||
/// return true if the netid in this rc is for the network id we are using
|
||||
bool
|
||||
FromOurNetwork() const;
|
||||
|
||||
bool
|
||||
IsObsoleteBootstrap() const;
|
||||
/// Extension of RouterContact used to store a local "RC," and inserts a RouterContact by
|
||||
/// re-parsing and sending it out. This sub-class contains a pubkey and all the other attributes
|
||||
/// required for signing and serialization
|
||||
///
|
||||
/// Note: this class may be entirely superfluous, so it is used here as a placeholder until its
|
||||
/// marginal utility is determined. It may end up as a free-floating method that reads in
|
||||
/// parameters and outputs a bt-serialized string
|
||||
struct LocalRC final : public RouterContact
|
||||
{
|
||||
static LocalRC
|
||||
make(const SecretKey secret, oxen::quic::Address local);
|
||||
|
||||
private:
|
||||
bool
|
||||
DecodeVersion_0(llarp_buffer_t* buf);
|
||||
ustring _signature;
|
||||
SecretKey _secret_key;
|
||||
|
||||
void
|
||||
bt_sign(oxenc::bt_dict_producer& btdp);
|
||||
|
||||
void
|
||||
bt_encode(oxenc::bt_dict_producer& btdp);
|
||||
|
||||
LocalRC(const SecretKey secret, oxen::quic::Address local);
|
||||
|
||||
public:
|
||||
LocalRC() = default;
|
||||
explicit LocalRC(std::string payload, const SecretKey sk);
|
||||
~LocalRC() = default;
|
||||
|
||||
void
|
||||
resign();
|
||||
|
||||
void
|
||||
clear() override
|
||||
{
|
||||
_addr = {};
|
||||
_addr6.reset();
|
||||
_router_id.Zero();
|
||||
_timestamp = {};
|
||||
_router_version.fill(0);
|
||||
_signature.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
DecodeVersion_1(oxenc::bt_list_consumer& btlist);
|
||||
operator==(const LocalRC& other) const
|
||||
{
|
||||
return _router_id == other._router_id and _addr == other._addr and _addr6 == other._addr6
|
||||
and _timestamp == other._timestamp and _router_version == other._router_version
|
||||
and _signature == other._signature;
|
||||
}
|
||||
|
||||
/// Mutators for the private member attributes. Calling on the mutators
|
||||
/// will clear the current signature and re-sign the RC
|
||||
void
|
||||
set_addr(oxen::quic::Address new_addr)
|
||||
{
|
||||
_addr = std::move(new_addr);
|
||||
resign();
|
||||
}
|
||||
|
||||
void
|
||||
set_addr6(oxen::quic::Address new_addr)
|
||||
{
|
||||
_addr6 = std::move(new_addr);
|
||||
resign();
|
||||
}
|
||||
|
||||
void
|
||||
set_router_id(RouterID rid)
|
||||
{
|
||||
_router_id = std::move(rid);
|
||||
resign();
|
||||
}
|
||||
|
||||
void
|
||||
set_timestamp(llarp_time_t ts)
|
||||
{
|
||||
set_timestamp(rc_time{std::chrono::duration_cast<std::chrono::seconds>(ts)});
|
||||
}
|
||||
|
||||
void
|
||||
set_timestamp(rc_time ts)
|
||||
{
|
||||
_timestamp = ts;
|
||||
}
|
||||
|
||||
/// Sets RC timestamp to current system clock time
|
||||
void
|
||||
set_systime_timestamp()
|
||||
{
|
||||
set_timestamp(
|
||||
std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()));
|
||||
}
|
||||
};
|
||||
|
||||
/// Extension of RouterContact used in a "read-only" fashion. Parses the incoming RC to query
|
||||
/// the data in the constructor, eliminating the need for a ::verify method/
|
||||
struct RemoteRC final : public RouterContact
|
||||
{
|
||||
private:
|
||||
void
|
||||
bt_verify(oxenc::bt_dict_consumer& data, bool reject_expired = false) const;
|
||||
|
||||
public:
|
||||
RemoteRC() = default;
|
||||
RemoteRC(std::string_view data) : RemoteRC{oxenc::bt_dict_consumer{data}}
|
||||
{}
|
||||
RemoteRC(ustring_view data) : RemoteRC{oxenc::bt_dict_consumer{data}}
|
||||
{
|
||||
_payload = data;
|
||||
}
|
||||
explicit RemoteRC(oxenc::bt_dict_consumer btdc);
|
||||
~RemoteRC() = default;
|
||||
|
||||
std::string_view
|
||||
view() const
|
||||
{
|
||||
return {reinterpret_cast<const char*>(_payload.data()), _payload.size()};
|
||||
}
|
||||
|
||||
bool
|
||||
verify() const;
|
||||
|
||||
bool
|
||||
read(const fs::path& fname);
|
||||
|
||||
void
|
||||
clear() override
|
||||
{
|
||||
_addr = {};
|
||||
_addr6.reset();
|
||||
_router_id.Zero();
|
||||
_timestamp = {};
|
||||
_router_version.fill(0);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<NetID> = true;
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<RouterContact> = true;
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<RemoteRC> = true;
|
||||
template <>
|
||||
constexpr inline bool IsToStringFormattable<LocalRC> = true;
|
||||
|
||||
using RouterLookupHandler = std::function<void(const std::vector<RouterContact>&)>;
|
||||
using RouterLookupHandler = std::function<void(const std::vector<RemoteRC>&)>;
|
||||
} // namespace llarp
|
||||
|
||||
namespace std
|
||||
|
@ -233,7 +364,7 @@ namespace std
|
|||
size_t
|
||||
operator()(const llarp::RouterContact& r) const
|
||||
{
|
||||
return std::hash<llarp::PubKey>{}(r.pubkey);
|
||||
return std::hash<llarp::PubKey>{}(r.router_id());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
|
138
llarp/router_contact_local.cpp
Normal file
138
llarp/router_contact_local.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
#include "constants/version.hpp"
|
||||
#include "crypto/crypto.hpp"
|
||||
#include "net/net.hpp"
|
||||
#include "router_contact.hpp"
|
||||
#include "util/bencode.hpp"
|
||||
#include "util/buffer.hpp"
|
||||
#include "util/file.hpp"
|
||||
#include "util/time.hpp"
|
||||
|
||||
#include <oxenc/bt_serialize.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
LocalRC
|
||||
LocalRC::make(const SecretKey secret, oxen::quic::Address local)
|
||||
{
|
||||
return *new LocalRC{secret, local};
|
||||
}
|
||||
|
||||
LocalRC::LocalRC(const SecretKey secret, oxen::quic::Address local)
|
||||
: _secret_key{std::move(secret)}
|
||||
{
|
||||
_router_id = llarp::seckey_to_pubkey(_secret_key);
|
||||
_addr = std::move(local);
|
||||
_addr6.emplace(&_addr.in6());
|
||||
resign();
|
||||
}
|
||||
|
||||
LocalRC::LocalRC(std::string payload, const SecretKey sk) : _secret_key{std::move(sk)}
|
||||
{
|
||||
_router_id = llarp::seckey_to_pubkey(_secret_key);
|
||||
|
||||
try
|
||||
{
|
||||
oxenc::bt_dict_consumer btdc{payload};
|
||||
bt_load(btdc);
|
||||
|
||||
btdc.require_signature("~", [this](ustring_view msg, ustring_view sig) {
|
||||
if (sig.size() != 64)
|
||||
throw std::runtime_error{"Invalid signature: not 64 bytes"};
|
||||
|
||||
if (is_expired(time_now_ms()))
|
||||
throw std::runtime_error{"Unable to verify expired RemoteRC!"};
|
||||
|
||||
// TODO: revisit if this is needed; detail from previous implementation
|
||||
const auto* net = net::Platform::Default_ptr();
|
||||
|
||||
if (net->IsBogon(addr().in4()) and BLOCK_BOGONS)
|
||||
{
|
||||
auto err = "Unable to verify expired RemoteRC!";
|
||||
log::info(logcat, err);
|
||||
throw std::runtime_error{err};
|
||||
}
|
||||
|
||||
if (not crypto::verify(router_id(), msg, sig))
|
||||
throw std::runtime_error{"Failed to verify RemoteRC"};
|
||||
});
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::warning(logcat, "Failed to parse LocalRC: {}", e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LocalRC::bt_sign(oxenc::bt_dict_producer& btdp)
|
||||
{
|
||||
_signature.clear();
|
||||
|
||||
btdp.append_signature("~", [this](ustring_view to_sign) {
|
||||
std::array<unsigned char, 64> sig;
|
||||
|
||||
if (!crypto::sign(const_cast<unsigned char*>(sig.data()), _secret_key, to_sign))
|
||||
throw std::runtime_error{"Failed to sign RC"};
|
||||
|
||||
_signature = {sig.data(), sig.size()};
|
||||
return sig;
|
||||
});
|
||||
|
||||
_payload = btdp.view<unsigned char>();
|
||||
}
|
||||
|
||||
void
|
||||
LocalRC::bt_encode(oxenc::bt_dict_producer& btdp)
|
||||
{
|
||||
btdp.append("", RC_VERSION);
|
||||
|
||||
std::array<unsigned char, 18> buf;
|
||||
|
||||
{
|
||||
if (not _addr.is_ipv4())
|
||||
throw std::runtime_error{"Unable to encode RC: addr is not IPv4"};
|
||||
|
||||
auto in4 = _addr.in4();
|
||||
|
||||
std::memcpy(buf.data(), &in4.sin_addr.s_addr, 4);
|
||||
std::memcpy(buf.data() + 4, &in4.sin_port, 2);
|
||||
|
||||
btdp.append("4", ustring_view{buf.data(), 6});
|
||||
}
|
||||
|
||||
if (_addr6)
|
||||
{
|
||||
if (not _addr.is_ipv6())
|
||||
throw std::runtime_error{"Unable to encode RC: addr6 is set but is not IPv6"};
|
||||
|
||||
auto in6 = _addr.in6();
|
||||
|
||||
std::memcpy(buf.data(), &in6.sin6_addr.s6_addr, 16);
|
||||
std::memcpy(buf.data() + 16, &in6.sin6_port, 2);
|
||||
|
||||
btdp.append("6", ustring_view{buf.data(), 18});
|
||||
}
|
||||
|
||||
if (ACTIVE_NETID != llarp::LOKINET_DEFAULT_NETID)
|
||||
btdp.append("i", ACTIVE_NETID);
|
||||
|
||||
btdp.append("p", _router_id.ToView());
|
||||
|
||||
btdp.append("t", _timestamp.time_since_epoch().count());
|
||||
|
||||
static_assert(llarp::LOKINET_VERSION.size() == 3);
|
||||
btdp.append(
|
||||
"v", std::string_view{reinterpret_cast<const char*>(llarp::LOKINET_VERSION.data()), 3});
|
||||
|
||||
bt_sign(btdp);
|
||||
}
|
||||
|
||||
void
|
||||
LocalRC::resign()
|
||||
{
|
||||
set_systime_timestamp();
|
||||
oxenc::bt_dict_producer btdp;
|
||||
bt_encode(btdp);
|
||||
bt_sign(btdp);
|
||||
}
|
||||
} // namespace llarp
|
106
llarp/router_contact_remote.cpp
Normal file
106
llarp/router_contact_remote.cpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
#include "constants/version.hpp"
|
||||
#include "crypto/crypto.hpp"
|
||||
#include "net/net.hpp"
|
||||
#include "router_contact.hpp"
|
||||
#include "util/bencode.hpp"
|
||||
#include "util/buffer.hpp"
|
||||
#include "util/file.hpp"
|
||||
#include "util/time.hpp"
|
||||
|
||||
#include <oxenc/bt_serialize.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
RemoteRC::RemoteRC(oxenc::bt_dict_consumer btdc)
|
||||
{
|
||||
try
|
||||
{
|
||||
bt_load(btdc);
|
||||
|
||||
btdc.require_signature("~", [this](ustring_view msg, ustring_view sig) {
|
||||
if (sig.size() != 64)
|
||||
throw std::runtime_error{"Invalid signature: not 64 bytes"};
|
||||
|
||||
if (is_expired(time_now_ms()))
|
||||
throw std::runtime_error{"Unable to verify expired RemoteRC!"};
|
||||
|
||||
// TODO: revisit if this is needed; detail from previous implementation
|
||||
const auto* net = net::Platform::Default_ptr();
|
||||
|
||||
if (net->IsBogon(addr().in4()) and BLOCK_BOGONS)
|
||||
{
|
||||
auto err = "Unable to verify expired RemoteRC!";
|
||||
log::info(logcat, err);
|
||||
throw std::runtime_error{err};
|
||||
}
|
||||
|
||||
if (not crypto::verify(router_id(), msg, sig))
|
||||
throw std::runtime_error{"Failed to verify RemoteRC"};
|
||||
});
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::warning(logcat, "Failed to parse RemoteRC: {}", e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RemoteRC::bt_verify(oxenc::bt_dict_consumer& data, bool reject_expired) const
|
||||
{
|
||||
data.require_signature("~", [this, reject_expired](ustring_view msg, ustring_view sig) {
|
||||
if (sig.size() != 64)
|
||||
throw std::runtime_error{"Invalid signature: not 64 bytes"};
|
||||
|
||||
if (is_expired(time_now_ms()) and reject_expired)
|
||||
throw std::runtime_error{"Unable to verify expired RemoteRC!"};
|
||||
|
||||
// TODO: revisit if this is needed; detail from previous implementation
|
||||
const auto* net = net::Platform::Default_ptr();
|
||||
|
||||
if (net->IsBogon(addr().in4()) and BLOCK_BOGONS)
|
||||
{
|
||||
auto err = "Unable to verify expired RemoteRC!";
|
||||
log::info(logcat, err);
|
||||
throw std::runtime_error{err};
|
||||
}
|
||||
|
||||
if (not crypto::verify(router_id(), msg, sig))
|
||||
throw std::runtime_error{"Failed to verify RemoteRC"};
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteRC::read(const fs::path& fname)
|
||||
{
|
||||
ustring buf;
|
||||
buf.reserve(MAX_RC_SIZE);
|
||||
|
||||
try
|
||||
{
|
||||
util::file_to_buffer(fname, buf.data(), MAX_RC_SIZE);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::error(logcat, "Failed to read RC from {}: {}", fname, e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
oxenc::bt_dict_consumer btdc{buf};
|
||||
bt_load(btdc);
|
||||
bt_verify(btdc);
|
||||
|
||||
_payload = buf;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteRC::verify() const
|
||||
{
|
||||
oxenc::bt_dict_consumer btdc{_payload};
|
||||
bt_verify(btdc);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
|
@ -3,9 +3,11 @@
|
|||
#include "util/aligned.hpp"
|
||||
#include "util/status.hpp"
|
||||
|
||||
#include <llarp/crypto/types.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct RouterID : public AlignedBuffer<32>
|
||||
struct RouterID : public PubKey
|
||||
{
|
||||
static constexpr size_t SIZE = 32;
|
||||
|
||||
|
@ -13,10 +15,10 @@ namespace llarp
|
|||
|
||||
RouterID() = default;
|
||||
|
||||
RouterID(const byte_t* buf) : AlignedBuffer<SIZE>(buf)
|
||||
RouterID(const byte_t* buf) : PubKey(buf)
|
||||
{}
|
||||
|
||||
RouterID(const Data& data) : AlignedBuffer<SIZE>(data)
|
||||
RouterID(const Data& data) : PubKey(data)
|
||||
{}
|
||||
|
||||
util::StatusObject
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace llarp::rpc
|
|||
{
|
||||
if (auto router = m_Router.lock())
|
||||
{
|
||||
if (not router->IsServiceNode())
|
||||
if (not router->is_service_node())
|
||||
{
|
||||
throw std::runtime_error("we cannot talk to lokid while not a service node");
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ namespace llarp::rpc
|
|||
|
||||
nlohmann::json payload = {
|
||||
{"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())},
|
||||
{"version", {VERSION[0], VERSION[1], VERSION[2]}}};
|
||||
{"version", {LOKINET_VERSION[0], LOKINET_VERSION[1], LOKINET_VERSION[2]}}};
|
||||
|
||||
if (auto err = r->OxendErrorState())
|
||||
payload["error"] = *err;
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace llarp::rpc
|
|||
std::shared_ptr<EndpointBase>
|
||||
GetEndpointByName(Router& r, std::string name)
|
||||
{
|
||||
if (r.IsServiceNode())
|
||||
if (r.is_service_node())
|
||||
{
|
||||
return r.exitContext().GetExitEndpoint(name);
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ namespace llarp::rpc
|
|||
RPCServer::invoke(Version& version)
|
||||
{
|
||||
util::StatusObject result{
|
||||
{"version", llarp::VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
|
||||
{"version", llarp::LOKINET_VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
|
||||
|
||||
SetJSONResponse(result, version.response);
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ namespace llarp::rpc
|
|||
void
|
||||
RPCServer::invoke(LookupSnode& lookupsnode)
|
||||
{
|
||||
if (not m_Router.IsServiceNode())
|
||||
if (not m_Router.is_service_node())
|
||||
{
|
||||
SetJSONError("Not supported", lookupsnode.response);
|
||||
return;
|
||||
|
|
|
@ -206,97 +206,57 @@ namespace llarp::service
|
|||
std::string service,
|
||||
std::function<void(std::vector<dns::SRVData>)> resultHandler)
|
||||
{
|
||||
// handles when we aligned to a loki address
|
||||
auto handleGotPathToService = [resultHandler, service, this](auto addr) {
|
||||
// we can probably get this info before we have a path to them but we do this after we
|
||||
// have a path so when we send the response back they can send shit to them immediately
|
||||
const auto& container = _state->remote_sessions;
|
||||
if (auto itr = container.find(addr); itr != container.end())
|
||||
{
|
||||
// parse the stuff we need from this guy
|
||||
resultHandler(itr->second->GetCurrentIntroSet().GetMatchingSRVRecords(service));
|
||||
return;
|
||||
}
|
||||
resultHandler({});
|
||||
};
|
||||
// A lookup goes through a chain of events:
|
||||
// - see if the name is ONS, and if so resolve it to a ADDR.loki
|
||||
// - once we've resolved to ADDR.loki then initiate a path to it
|
||||
// - once we have a path, consult the remote's introset to pull out the SRV records
|
||||
// If we fail along the way (e.g. it's a .snode, we can't build a path, or whatever else) then
|
||||
// we invoke the resultHandler with an empty vector.
|
||||
lookup_name(
|
||||
name, [this, resultHandler, service = std::move(service)](oxen::quic::message m) mutable {
|
||||
if (!m)
|
||||
return resultHandler({});
|
||||
|
||||
// handles when we resolved a .snode
|
||||
auto handleResolvedSNodeName = [resultHandler, nodedb = router()->node_db()](auto router_id) {
|
||||
std::vector<dns::SRVData> result{};
|
||||
if (auto maybe_rc = nodedb->get_rc(router_id))
|
||||
{
|
||||
result = maybe_rc->srvRecords;
|
||||
}
|
||||
resultHandler(std::move(result));
|
||||
};
|
||||
std::string name;
|
||||
try
|
||||
{
|
||||
oxenc::bt_dict_consumer btdc{m.body()};
|
||||
name = btdc.require<std::string>("NAME");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log::warning(link_cat, "Failed to parse find name response!");
|
||||
throw;
|
||||
}
|
||||
|
||||
// handles when we got a path to a remote thing
|
||||
auto handleGotPathTo = [handleGotPathToService, handleResolvedSNodeName, resultHandler](
|
||||
auto maybe_tag, auto address) {
|
||||
if (not maybe_tag)
|
||||
{
|
||||
resultHandler({});
|
||||
return;
|
||||
}
|
||||
auto saddr = service::Address();
|
||||
if (!saddr.FromString(name))
|
||||
return resultHandler({}); // Not a regular ADDR.loki so doesn't support SRV
|
||||
|
||||
if (auto* addr = std::get_if<Address>(&address))
|
||||
{
|
||||
// .loki case
|
||||
handleGotPathToService(*addr);
|
||||
}
|
||||
else if (auto* router_id = std::get_if<RouterID>(&address))
|
||||
{
|
||||
// .snode case
|
||||
handleResolvedSNodeName(*router_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback case
|
||||
// XXX: never should happen but we'll handle it anyways
|
||||
resultHandler({});
|
||||
}
|
||||
};
|
||||
// initiate path build
|
||||
const auto build_started = EnsurePathTo(
|
||||
saddr,
|
||||
[this, address = std::move(saddr), resultHandler, service = std::move(service)](
|
||||
auto maybe_tag) {
|
||||
if (not maybe_tag)
|
||||
return resultHandler({});
|
||||
|
||||
// handles when we know a long address of a remote resource
|
||||
auto handleGotAddress = [resultHandler, handleGotPathTo, this](AddressVariant_t address) {
|
||||
// we will attempt a build to whatever we looked up
|
||||
const auto result = EnsurePathTo(
|
||||
address,
|
||||
[address, handleGotPathTo](auto maybe_tag) { handleGotPathTo(maybe_tag, address); },
|
||||
PathAlignmentTimeout());
|
||||
// we can probably get this info before we have a path to them but we do this after
|
||||
// we have a path so when we send the DNS response back they can talk to them
|
||||
// immediately
|
||||
const auto& container = _state->remote_sessions;
|
||||
if (auto itr = container.find(address); itr != container.end())
|
||||
// parse the stuff we need from this guy
|
||||
resultHandler(itr->second->GetCurrentIntroSet().GetMatchingSRVRecords(service));
|
||||
else
|
||||
resultHandler({});
|
||||
},
|
||||
PathAlignmentTimeout());
|
||||
|
||||
// on path build start fail short circuit
|
||||
if (not result)
|
||||
resultHandler({});
|
||||
};
|
||||
|
||||
// look up this name async and start the entire chain of events
|
||||
lookup_name(name, [handleGotAddress, resultHandler](oxen::quic::message m) mutable {
|
||||
if (m)
|
||||
{
|
||||
std::string name;
|
||||
try
|
||||
{
|
||||
oxenc::bt_dict_consumer btdc{m.body()};
|
||||
name = btdc.require<std::string>("NAME");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log::warning(link_cat, "Failed to parse find name response!");
|
||||
throw;
|
||||
}
|
||||
|
||||
if (auto saddr = service::Address(); saddr.FromString(name))
|
||||
handleGotAddress(saddr);
|
||||
|
||||
if (auto rid = RouterID(); rid.FromString(name))
|
||||
handleGotAddress(rid);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultHandler({});
|
||||
}
|
||||
});
|
||||
// on path build start fail short circuit
|
||||
if (not build_started)
|
||||
resultHandler({});
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -754,22 +714,22 @@ namespace llarp::service
|
|||
return now >= next_pub;
|
||||
}
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
Endpoint::GetHopsForBuild()
|
||||
{
|
||||
std::unordered_set<RouterID> exclude;
|
||||
ForEachPath([&exclude](auto path) { exclude.insert(path->Endpoint()); });
|
||||
const auto maybe =
|
||||
router()->node_db()->GetRandom([exclude, r = router()](const auto& rc) -> bool {
|
||||
return exclude.count(rc.pubkey) == 0
|
||||
and not r->router_profiling().IsBadForPath(rc.pubkey);
|
||||
router()->node_db()->GetRandom([exclude, r = router()](const RemoteRC& rc) -> bool {
|
||||
const auto& rid = rc.router_id();
|
||||
return exclude.count(rid) == 0 and not r->router_profiling().IsBadForPath(rid);
|
||||
});
|
||||
if (not maybe.has_value())
|
||||
return std::nullopt;
|
||||
return GetHopsForBuildWithEndpoint(maybe->pubkey);
|
||||
return GetHopsForBuildWithEndpoint(maybe->router_id());
|
||||
}
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
Endpoint::GetHopsForBuildWithEndpoint(RouterID endpoint)
|
||||
{
|
||||
return path::Builder::GetHopsAlignedToForBuild(endpoint, SnodeBlacklist());
|
||||
|
|
|
@ -409,10 +409,10 @@ namespace llarp
|
|||
bool
|
||||
HasExit() const;
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
GetHopsForBuild() override;
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
GetHopsForBuildWithEndpoint(RouterID endpoint);
|
||||
|
||||
void
|
||||
|
|
|
@ -4,16 +4,32 @@
|
|||
|
||||
namespace llarp::service
|
||||
{
|
||||
bool
|
||||
Identity::BEncode(llarp_buffer_t* buf) const
|
||||
std::string
|
||||
Identity::bt_encode() const
|
||||
{
|
||||
if (!bencode_start_dict(buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictEntry("s", signkey, buf))
|
||||
return false;
|
||||
if (!BEncodeWriteDictInt("v", version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
oxenc::bt_dict_producer btdp;
|
||||
|
||||
btdp.append("s", signkey.ToView());
|
||||
btdp.append("v", version);
|
||||
|
||||
return std::move(btdp).str();
|
||||
}
|
||||
|
||||
void
|
||||
Identity::bt_decode(std::string buf)
|
||||
{
|
||||
try
|
||||
{
|
||||
oxenc::bt_dict_consumer btdc{buf};
|
||||
|
||||
signkey.from_string(btdc.require<std::string>("s"));
|
||||
version = btdc.require<uint64_t>("v");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log::warning(logcat, "Identity failed to parse bt-encoded contents!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -44,7 +60,7 @@ namespace llarp::service
|
|||
{
|
||||
crypto::identity_keygen(signkey);
|
||||
crypto::encryption_keygen(enckey);
|
||||
pub.Update(seckey_topublic(signkey), seckey_topublic(enckey));
|
||||
pub.Update(seckey_to_pubkey(signkey), seckey_to_pubkey(enckey));
|
||||
crypto::pqe_keygen(pq);
|
||||
if (not crypto::derive_subkey_private(derivedSignKey, signkey, 1))
|
||||
{
|
||||
|
@ -74,7 +90,7 @@ namespace llarp::service
|
|||
// make sure we are empty
|
||||
Clear();
|
||||
|
||||
std::array<byte_t, 4096> tmp;
|
||||
std::string buf;
|
||||
|
||||
// this can throw
|
||||
bool exists = fs::exists(fname);
|
||||
|
@ -88,16 +104,15 @@ namespace llarp::service
|
|||
// check for file
|
||||
if (!exists)
|
||||
{
|
||||
llarp_buffer_t buf{tmp};
|
||||
// regen and encode
|
||||
RegenerateKeys();
|
||||
if (!BEncode(&buf))
|
||||
throw std::length_error("failed to encode new identity");
|
||||
const auto sz = buf.cur - buf.base;
|
||||
|
||||
buf = bt_encode();
|
||||
|
||||
// write
|
||||
try
|
||||
{
|
||||
util::dump_file(fname, tmp.data(), sz);
|
||||
util::buffer_to_file(fname, buf.data(), buf.size());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -114,18 +129,15 @@ namespace llarp::service
|
|||
// read file
|
||||
try
|
||||
{
|
||||
util::slurp_file(fname, tmp.data(), tmp.size());
|
||||
util::file_to_buffer(fname, buf.data(), buf.size());
|
||||
}
|
||||
catch (const std::length_error&)
|
||||
{
|
||||
throw std::length_error{"service identity too big"};
|
||||
}
|
||||
|
||||
// (don't catch io error exceptions)
|
||||
{
|
||||
llarp_buffer_t buf{tmp};
|
||||
if (!bencode_decode_dict(*this, &buf))
|
||||
throw std::length_error{"could not decode service identity"};
|
||||
}
|
||||
bt_decode(buf);
|
||||
|
||||
// ensure that the encryption key is set
|
||||
if (enckey.IsZero())
|
||||
|
@ -139,7 +151,7 @@ namespace llarp::service
|
|||
if (!vanity.IsZero())
|
||||
van = vanity;
|
||||
// update pubkeys
|
||||
pub.Update(seckey_topublic(signkey), seckey_topublic(enckey), van);
|
||||
pub.Update(seckey_to_pubkey(signkey), seckey_to_pubkey(enckey), van);
|
||||
if (not crypto::derive_subkey_private(derivedSignKey, signkey, 1))
|
||||
{
|
||||
throw std::runtime_error("failed to derive subkey");
|
||||
|
@ -163,7 +175,7 @@ namespace llarp::service
|
|||
// set service info
|
||||
i.address_keys = pub;
|
||||
// set public encryption key
|
||||
i.sntru_pubkey = pq_keypair_to_public(pq);
|
||||
i.sntru_pubkey = pq_keypair_to_pubkey(pq);
|
||||
|
||||
auto bte = i.bt_encode();
|
||||
|
||||
|
|
|
@ -31,8 +31,10 @@ namespace llarp::service
|
|||
void
|
||||
RegenerateKeys();
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
std::string
|
||||
bt_encode() const;
|
||||
|
||||
void bt_decode(std::string);
|
||||
|
||||
/// @param needBackup determines whether existing keys will be cycled
|
||||
void
|
||||
|
|
|
@ -350,7 +350,7 @@ namespace llarp::service
|
|||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
OutboundContext::GetHopsForBuild()
|
||||
{
|
||||
if (next_intro.router.IsZero())
|
||||
|
|
|
@ -152,7 +152,7 @@ namespace llarp::service
|
|||
void
|
||||
HandlePathBuildFailedAt(path::Path_ptr path, RouterID hop) override;
|
||||
|
||||
std::optional<std::vector<RouterContact>>
|
||||
std::optional<std::vector<RemoteRC>>
|
||||
GetHopsForBuild() override;
|
||||
|
||||
std::string
|
||||
|
|
|
@ -256,7 +256,7 @@ namespace llarp::service
|
|||
// copy
|
||||
ProtocolFrameMessage frame(self->frame);
|
||||
if (!crypto::pqe_decrypt(
|
||||
self->frame.cipher, K, pq_keypair_to_secret(self->m_LocalIdentity.pq)))
|
||||
self->frame.cipher, K, pq_keypair_to_seckey(self->m_LocalIdentity.pq)))
|
||||
{
|
||||
LogError("pqke failed C=", self->frame.cipher);
|
||||
self->msg.reset();
|
||||
|
|
|
@ -130,12 +130,6 @@ namespace llarp
|
|||
std::string
|
||||
bt_encode() const;
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
return bencode_decode_dict(*this, buf);
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
|
|
|
@ -4,13 +4,10 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::service
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
RouterLookupJob::RouterLookupJob(Endpoint* p, RouterLookupHandler h)
|
||||
: handler(std::move(h)), txid(p->GenTXID()), started(p->Now())
|
||||
{}
|
||||
RouterLookupJob::RouterLookupJob(Endpoint* p, RouterLookupHandler h)
|
||||
: handler(std::move(h)), txid(p->GenTXID()), started(p->Now())
|
||||
{}
|
||||
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
} // namespace llarp::service
|
||||
|
|
|
@ -2,34 +2,31 @@
|
|||
|
||||
#include <llarp/router_contact.hpp>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::service
|
||||
{
|
||||
namespace service
|
||||
struct Endpoint;
|
||||
|
||||
struct RouterLookupJob
|
||||
{
|
||||
struct Endpoint;
|
||||
RouterLookupJob(Endpoint* p, RouterLookupHandler h);
|
||||
|
||||
struct RouterLookupJob
|
||||
RouterLookupHandler handler;
|
||||
uint64_t txid;
|
||||
llarp_time_t started;
|
||||
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const
|
||||
{
|
||||
RouterLookupJob(Endpoint* p, RouterLookupHandler h);
|
||||
if (now < started)
|
||||
return false;
|
||||
return now - started > 30s;
|
||||
}
|
||||
|
||||
RouterLookupHandler handler;
|
||||
uint64_t txid;
|
||||
llarp_time_t started;
|
||||
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const
|
||||
{
|
||||
if (now < started)
|
||||
return false;
|
||||
return now - started > 30s;
|
||||
}
|
||||
|
||||
void
|
||||
InformResult(std::vector<RouterContact> result)
|
||||
{
|
||||
if (handler)
|
||||
handler(result);
|
||||
}
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
void
|
||||
InformResult(std::vector<RemoteRC> result)
|
||||
{
|
||||
if (handler)
|
||||
handler(result);
|
||||
}
|
||||
};
|
||||
} // namespace llarp::service
|
||||
|
|
|
@ -17,16 +17,17 @@ namespace llarp
|
|||
{
|
||||
static auto ben_cat = log::Cat("stupid.bencode");
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
decode_key(oxenc::bt_dict_consumer& btdp, const char* key)
|
||||
{
|
||||
return btdp.require<T>(key);
|
||||
}
|
||||
|
||||
template <typename List_t>
|
||||
bool
|
||||
BEncodeReadList(List_t& result, llarp_buffer_t* buf);
|
||||
|
||||
inline bool
|
||||
BEncodeWriteDictMsgType(llarp_buffer_t* buf, const char* k, const char* t)
|
||||
{
|
||||
return bencode_write_bytestring(buf, k, 1) && bencode_write_bytestring(buf, t, 1);
|
||||
}
|
||||
|
||||
template <typename Obj_t>
|
||||
bool
|
||||
BEncodeWriteDictString(const char* k, const Obj_t& str, llarp_buffer_t* buf)
|
||||
|
@ -320,23 +321,6 @@ namespace llarp
|
|||
buffer);
|
||||
}
|
||||
|
||||
/// write an iterable container as a list
|
||||
template <typename Set_t>
|
||||
bool
|
||||
BEncodeWriteSet(const Set_t& set, llarp_buffer_t* buffer)
|
||||
{
|
||||
if (not bencode_start_list(buffer))
|
||||
return false;
|
||||
|
||||
for (const auto& item : set)
|
||||
{
|
||||
if (not item.bt_encode(buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
return bencode_end(buffer);
|
||||
}
|
||||
|
||||
template <typename List_t>
|
||||
bool
|
||||
BEncodeWriteDictList(const char* k, List_t& list, llarp_buffer_t* buf)
|
||||
|
@ -365,7 +349,7 @@ namespace llarp
|
|||
std::string content;
|
||||
try
|
||||
{
|
||||
content = util::slurp_file(fpath);
|
||||
content = util::file_to_string(fpath);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
|
@ -389,7 +373,7 @@ namespace llarp
|
|||
tmp.resize(buf.cur - buf.base);
|
||||
try
|
||||
{
|
||||
util::dump_file(fpath, tmp);
|
||||
util::buffer_to_file(fpath, tmp);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
namespace llarp::util
|
||||
{
|
||||
static std::streampos
|
||||
slurp_file_open(const fs::path& filename, fs::ifstream& in)
|
||||
file_reader_impl(const fs::path& filename, fs::ifstream& in)
|
||||
{
|
||||
in.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
in.open(filename, std::ios::binary | std::ios::in);
|
||||
|
@ -30,21 +30,21 @@ namespace llarp::util
|
|||
}
|
||||
|
||||
std::string
|
||||
slurp_file(const fs::path& filename)
|
||||
file_to_string(const fs::path& filename)
|
||||
{
|
||||
fs::ifstream in;
|
||||
std::string contents;
|
||||
auto size = slurp_file_open(filename, in);
|
||||
auto size = file_reader_impl(filename, in);
|
||||
contents.resize(size);
|
||||
in.read(contents.data(), size);
|
||||
return contents;
|
||||
}
|
||||
|
||||
size_t
|
||||
slurp_file(const fs::path& filename, char* buffer, size_t buffer_size)
|
||||
file_to_buffer(const fs::path& filename, char* buffer, size_t buffer_size)
|
||||
{
|
||||
fs::ifstream in;
|
||||
auto size = slurp_file_open(filename, in);
|
||||
auto size = file_reader_impl(filename, in);
|
||||
if (static_cast<size_t>(size) > buffer_size)
|
||||
throw std::length_error{"file is too large for buffer"};
|
||||
in.read(buffer, size);
|
||||
|
@ -52,7 +52,7 @@ namespace llarp::util
|
|||
}
|
||||
|
||||
void
|
||||
dump_file(const fs::path& filename, std::string_view contents)
|
||||
buffer_to_file(const fs::path& filename, std::string_view contents)
|
||||
{
|
||||
fs::ofstream out;
|
||||
out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
|
|
|
@ -14,34 +14,34 @@ namespace llarp::util
|
|||
{
|
||||
/// Reads a binary file from disk into a string. Throws on error.
|
||||
std::string
|
||||
slurp_file(const fs::path& filename);
|
||||
file_to_string(const fs::path& filename);
|
||||
|
||||
/// Reads a binary file from disk directly into a buffer. Throws a std::length_error if the
|
||||
/// file is bigger than the buffer. Returns the bytes copied on success.
|
||||
size_t
|
||||
slurp_file(const fs::path& filename, char* buffer, size_t buffer_size);
|
||||
file_to_buffer(const fs::path& filename, char* buffer, size_t buffer_size);
|
||||
|
||||
/// Same, but for some non-char but single-byte char type (e.g. byte_t, std::byte, unsigned char).
|
||||
template <
|
||||
typename Char,
|
||||
std::enable_if_t<sizeof(Char) == 1 and not std::is_same_v<Char, char>, int> = 1>
|
||||
inline size_t
|
||||
slurp_file(const fs::path& filename, Char* buffer, size_t buffer_size)
|
||||
file_to_buffer(const fs::path& filename, Char* buffer, size_t buffer_size)
|
||||
{
|
||||
return slurp_file(filename, reinterpret_cast<char*>(buffer), buffer_size);
|
||||
return file_to_buffer(filename, reinterpret_cast<char*>(buffer), buffer_size);
|
||||
}
|
||||
|
||||
/// Dumps binary string contents to disk. The file is overwritten if it already exists. Throws
|
||||
/// on error.
|
||||
void
|
||||
dump_file(const fs::path& filename, std::string_view contents);
|
||||
buffer_to_file(const fs::path& filename, std::string_view contents);
|
||||
|
||||
/// Same as above, but works via char-like buffer
|
||||
template <typename Char, std::enable_if_t<sizeof(Char) == 1, int> = 0>
|
||||
inline void
|
||||
dump_file(const fs::path& filename, const Char* buffer, size_t buffer_size)
|
||||
buffer_to_file(const fs::path& filename, const Char* buffer, size_t buffer_size)
|
||||
{
|
||||
return dump_file(
|
||||
return buffer_to_file(
|
||||
filename, std::string_view{reinterpret_cast<const char*>(buffer), buffer_size});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue