Local router mode

- Up and running locally, no connections yet
- Next: flip testnet and do the gosh dang thing
pull/2227/head
dr7ana 6 months ago
parent ed6bd28a35
commit cef2ff7782

2
.gitignore vendored

@ -43,7 +43,7 @@ testnet_tmp
vsproject/ vsproject/
.vs .vs
daemon.ini *.ini
.gradle/ .gradle/

@ -77,6 +77,7 @@ namespace llarp
else else
{ {
RemoteRC rc; RemoteRC rc;
if (not rc.read(fpath)) if (not rc.read(fpath))
{ {
throw std::runtime_error{ throw std::runtime_error{

@ -19,14 +19,7 @@
namespace llarp namespace llarp
{ {
// constants for config file default values constexpr int DEFAULT_PUBLIC_PORT = 1090;
constexpr int DefaultMinConnectionsForRouter = 6;
constexpr int DefaultMaxConnectionsForRouter = 60;
constexpr int DefaultMinConnectionsForClient = 4;
constexpr int DefaultMaxConnectionsForClient = 6;
constexpr int DefaultPublicPort = 1090;
using namespace config; using namespace config;
namespace namespace
@ -72,38 +65,44 @@ namespace llarp
net_id = std::move(arg); net_id = std::move(arg);
}); });
int minConnections =
(params.is_relay ? DefaultMinConnectionsForRouter : DefaultMinConnectionsForClient);
conf.define_option<int>( conf.define_option<int>(
"router", "router",
"min-connections", "relay-connections",
Default{minConnections}, Default{CLIENT_ROUTER_CONNECTIONS},
ClientOnly,
Comment{ Comment{
"Minimum number of routers lokinet will attempt to maintain connections to.", "Minimum number of routers lokinet client will attempt to maintain connections to.",
}, },
[=](int arg) { [=](int arg) {
if (arg < minConnections) if (arg < CLIENT_ROUTER_CONNECTIONS)
throw std::invalid_argument{ throw std::invalid_argument{
fmt::format("min-connections must be >= {}", minConnections)}; fmt::format("Client relay connections must be >= {}", CLIENT_ROUTER_CONNECTIONS)};
min_connected_routers = arg; client_router_connections = arg;
});
conf.define_option<int>(
"router",
"min-connections",
Deprecated,
Comment{
"Minimum number of routers lokinet will attempt to maintain connections to.",
},
[=](int) {
log::warning(
logcat, "Router min-connections is deprecated; use relay-connections for clients");
}); });
int maxConnections =
(params.is_relay ? DefaultMaxConnectionsForRouter : DefaultMaxConnectionsForClient);
conf.define_option<int>( conf.define_option<int>(
"router", "router",
"max-connections", "max-connections",
Default{maxConnections}, Deprecated,
Comment{ Comment{
"Maximum number (hard limit) of routers lokinet will be connected to at any time.", "Maximum number (hard limit) of routers lokinet will be connected to at any time.",
}, },
[=](int arg) { [=](int) {
if (arg < maxConnections) log::warning(
throw std::invalid_argument{ logcat, "Router max-connections is deprecated; use relay-connections for clients");
fmt::format("max-connections must be >= {}", maxConnections)};
max_connected_routers = arg;
}); });
conf.define_option<std::string>("router", "nickname", Deprecated); conf.define_option<std::string>("router", "nickname", Deprecated);
@ -159,7 +158,7 @@ namespace llarp
"router", "router",
"public-port", "public-port",
RelayOnly, RelayOnly,
Default{DefaultPublicPort}, Default{DEFAULT_PUBLIC_PORT},
Comment{ Comment{
"When specifying public-ip=, this specifies the public UDP port at which this lokinet", "When specifying public-ip=, this specifies the public UDP port at which this lokinet",
"router is reachable. Required when public-ip is used.", "router is reachable. Required when public-ip is used.",
@ -1162,7 +1161,7 @@ namespace llarp
conf.define_option<bool>( conf.define_option<bool>(
"lokid", "lokid",
"disable-testing", "disable-testing",
Default{true}, Default{false},
Hidden, Hidden,
RelayOnly, RelayOnly,
Comment{ Comment{

@ -35,6 +35,7 @@ namespace llarp
using ConfigMap = llarp::ConfigParser::ConfigMap; using ConfigMap = llarp::ConfigParser::ConfigMap;
inline static constexpr uint16_t DEFAULT_LISTEN_PORT{1090}; inline static constexpr uint16_t DEFAULT_LISTEN_PORT{1090};
constexpr int CLIENT_ROUTER_CONNECTIONS = 4;
// TODO: don't use these maps. they're sloppy and difficult to follow // TODO: don't use these maps. they're sloppy and difficult to follow
/// Small struct to gather all parameters needed for config generation to reduce the number of /// Small struct to gather all parameters needed for config generation to reduce the number of
@ -57,8 +58,7 @@ namespace llarp
struct RouterConfig struct RouterConfig
{ {
size_t min_connected_routers = 0; int client_router_connections{CLIENT_ROUTER_CONNECTIONS};
size_t max_connected_routers = 0;
std::string net_id; std::string net_id;

@ -10,20 +10,20 @@
namespace llarp namespace llarp
{ {
KeyManager::KeyManager() : m_initialized(false), m_needBackup(false) KeyManager::KeyManager() : is_initialized(false), backup_keys(false)
{} {}
bool bool
KeyManager::initialize(const llarp::Config& config, bool genIfAbsent, bool isSNode) KeyManager::initialize(const llarp::Config& config, bool gen_if_absent, bool is_snode)
{ {
if (m_initialized) if (is_initialized)
return false; return false;
if (not isSNode) if (not is_snode)
{ {
crypto::identity_keygen(identityKey); crypto::identity_keygen(identity_key);
crypto::encryption_keygen(encryptionKey); crypto::encryption_keygen(encryption_key);
crypto::encryption_keygen(transportKey); crypto::encryption_keygen(transport_key);
return true; return true;
} }
@ -46,80 +46,87 @@ namespace llarp
} }
}; };
m_rcPath = deriveFile(our_rc_filename, config.router.rc_file); rc_path = deriveFile(our_rc_filename, config.router.rc_file);
m_idKeyPath = deriveFile(our_identity_filename, config.router.idkey_file); idkey_path = deriveFile(our_identity_filename, config.router.idkey_file);
m_encKeyPath = deriveFile(our_enc_key_filename, config.router.enckey_file); enckey_path = deriveFile(our_enc_key_filename, config.router.enckey_file);
m_transportKeyPath = deriveFile(our_transport_key_filename, config.router.transkey_file); transkey_path = deriveFile(our_transport_key_filename, config.router.transkey_file);
RemoteRC rc; RemoteRC rc;
bool exists = rc.read(m_rcPath);
if (not exists and not genIfAbsent)
{
LogError("Could not read RouterContact at path ", m_rcPath);
return false;
}
// we need to back up keys if our self.signed doesn't appear to have a if (auto exists = rc.read(rc_path); not exists)
// valid signature
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
// files that will be overwritten
if (exists and m_needBackup)
{ {
if (!genIfAbsent) if (not gen_if_absent)
{ {
LogError("Our RouterContact ", m_rcPath, " is invalid or out of date"); log::error(logcat, "Could not read RC at path {}", rc_path);
return false; return false;
} }
else }
else
{
if (backup_keys = (is_snode and not rc.verify()); backup_keys)
{ {
LogWarn( auto err = "RC (path:{}) is invalid or out of date"_format(rc_path);
"Our RouterContact ",
m_rcPath,
" seems out of date, backing up and regenerating private keys");
if (!backupKeyFilesByMoving()) if (not gen_if_absent)
{ {
LogError( log::error(logcat, err);
"Could not mv some key files, please ensure key files"
" are backed up if needed and remove");
return false; return false;
} }
}
}
if (not config.router.is_relay) log::warning(logcat, "{}; backing up and regenerating private keys...", err);
{
// load identity key or create if needed if (not copy_backup_keyfiles())
auto identityKeygen = [](llarp::SecretKey& key) { {
// TODO: handle generating from service node seed log::error(logcat, "Failed to copy-backup key files");
llarp::crypto::identity_keygen(key); return false;
}; }
if (not loadOrCreateKey(m_idKeyPath, identityKey, identityKeygen)) }
return false;
} }
// load encryption key // load encryption key
auto encryptionKeygen = [](llarp::SecretKey& key) { llarp::crypto::encryption_keygen(key); }; auto enckey_gen = [](llarp::SecretKey& key) { llarp::crypto::encryption_keygen(key); };
if (not loadOrCreateKey(m_encKeyPath, encryptionKey, encryptionKeygen)) if (not keygen(enckey_path, encryption_key, enckey_gen))
{
log::critical(
logcat, "KeyManager::keygen failed to generate encryption key line:{}", __LINE__);
return false; return false;
}
// TODO: transport key (currently done in LinkLayer) // TODO: transport key (currently done in LinkLayer)
auto transportKeygen = [](llarp::SecretKey& key) { auto transkey_gen = [](llarp::SecretKey& key) {
key.Zero(); key.Zero();
crypto::encryption_keygen(key); crypto::encryption_keygen(key);
}; };
if (not loadOrCreateKey(m_transportKeyPath, transportKey, transportKeygen))
if (not keygen(transkey_path, transport_key, transkey_gen))
{
log::critical(
logcat, "KeyManager::keygen failed to generate transport key line:{}", __LINE__);
return false; return false;
}
m_initialized = true; if (not config.router.is_relay)
{
// load identity key or create if needed
auto idkey_gen = [](llarp::SecretKey& key) {
// TODO: handle generating from service node seed
llarp::crypto::identity_keygen(key);
};
if (not keygen(idkey_path, identity_key, idkey_gen))
{
log::critical(
logcat, "KeyManager::keygen failed to generate identity key line:{}", __LINE__);
return false;
}
}
is_initialized = true;
return true; return true;
} }
bool bool
KeyManager::backupFileByMoving(const fs::path& filepath) KeyManager::copy_backup_keyfile(const fs::path& filepath)
{ {
auto findFreeBackupFilename = [](const fs::path& filepath) { auto findFreeBackupFilename = [](const fs::path& filepath) {
for (int i = 0; i < 9; i++) for (int i = 0; i < 9; i++)
@ -136,6 +143,7 @@ namespace llarp
std::error_code ec; std::error_code ec;
bool exists = fs::exists(filepath, ec); bool exists = fs::exists(filepath, ec);
if (ec) if (ec)
{ {
LogError("Could not determine status of file ", filepath, ": ", ec.message()); LogError("Could not determine status of file ", filepath, ": ", ec.message());
@ -168,13 +176,13 @@ namespace llarp
} }
bool bool
KeyManager::backupKeyFilesByMoving() const KeyManager::copy_backup_keyfiles() const
{ {
std::vector<fs::path> files = {m_rcPath, m_idKeyPath, m_encKeyPath, m_transportKeyPath}; std::vector<fs::path> files = {rc_path, idkey_path, enckey_path, transkey_path};
for (auto& filepath : files) for (auto& filepath : files)
{ {
if (not backupFileByMoving(filepath)) if (not copy_backup_keyfile(filepath))
return false; return false;
} }
@ -182,7 +190,7 @@ namespace llarp
} }
bool bool
KeyManager::loadOrCreateKey( KeyManager::keygen(
fs::path path, llarp::SecretKey& key, std::function<void(llarp::SecretKey& key)> keygen) fs::path path, llarp::SecretKey& key, std::function<void(llarp::SecretKey& key)> keygen)
{ {
if (not fs::exists(path)) if (not fs::exists(path))

@ -29,7 +29,7 @@ namespace llarp
/// @param filepath is the name of the original file to backup. /// @param filepath is the name of the original file to backup.
/// @return true if the file could be moved or didn't exist, false otherwise /// @return true if the file could be moved or didn't exist, false otherwise
static bool static bool
backupFileByMoving(const fs::path& filepath); copy_backup_keyfile(const fs::path& filepath);
/// Constructor /// Constructor
KeyManager(); KeyManager();
@ -52,37 +52,37 @@ namespace llarp
/// @param rc (out) will be modified to contian the RouterContact /// @param rc (out) will be modified to contian the RouterContact
/// @return true on success, false otherwise /// @return true on success, false otherwise
bool bool
getRouterContact(llarp::RouterContact& rc) const; gen_rc(llarp::RouterContact& rc) const;
/// Return whether or not we need to backup keys as we load them /// Return whether or not we need to backup keys as we load them
bool bool
needBackup() const needs_backup() const
{ {
return m_needBackup; return backup_keys;
} }
llarp::SecretKey identityKey; llarp::SecretKey identity_key;
llarp::SecretKey encryptionKey; llarp::SecretKey encryption_key;
llarp::SecretKey transportKey; llarp::SecretKey transport_key;
fs::path m_rcPath; fs::path rc_path;
fs::path m_idKeyPath; fs::path idkey_path;
fs::path m_encKeyPath; fs::path enckey_path;
fs::path m_transportKeyPath; fs::path transkey_path;
private: private:
std::atomic_bool m_initialized; std::atomic_bool is_initialized;
std::atomic_bool m_needBackup; std::atomic_bool backup_keys;
/// Backup each key file (by copying, e.g. foo -> foo.bak) /// Backup each key file (by copying, e.g. foo -> foo.bak)
bool bool
backupKeyFilesByMoving() const; copy_backup_keyfiles() const;
/// Load the key at a given filepath or create it /// Load the key at a given filepath or create it
/// ///
/// @param keygen is a function that will generate the key if needed /// @param keygen is a function that will generate the key if needed
static bool static bool
loadOrCreateKey( keygen(
fs::path filepath, fs::path filepath,
llarp::SecretKey& key, llarp::SecretKey& key,
std::function<void(llarp::SecretKey& key)> keygen); std::function<void(llarp::SecretKey& key)> keygen);

@ -13,19 +13,19 @@ namespace llarp::exit
Context::Tick(llarp_time_t now) Context::Tick(llarp_time_t now)
{ {
{ {
auto itr = m_Exits.begin(); auto itr = _exits.begin();
while (itr != m_Exits.end()) while (itr != _exits.end())
{ {
itr->second->Tick(now); itr->second->Tick(now);
++itr; ++itr;
} }
} }
{ {
auto itr = m_Closed.begin(); auto itr = _closed.begin();
while (itr != m_Closed.end()) while (itr != _closed.end())
{ {
if ((*itr)->ShouldRemove()) if ((*itr)->ShouldRemove())
itr = m_Closed.erase(itr); itr = _closed.erase(itr);
else else
++itr; ++itr;
} }
@ -33,14 +33,14 @@ namespace llarp::exit
} }
void void
Context::Stop() Context::stop()
{ {
auto itr = m_Exits.begin(); auto itr = _exits.begin();
while (itr != m_Exits.end()) while (itr != _exits.end())
{ {
itr->second->Stop(); itr->second->Stop();
m_Closed.emplace_back(std::move(itr->second)); _closed.emplace_back(std::move(itr->second));
itr = m_Exits.erase(itr); itr = _exits.erase(itr);
} }
} }
@ -48,8 +48,8 @@ namespace llarp::exit
Context::ExtractStatus() const Context::ExtractStatus() const
{ {
util::StatusObject obj{}; util::StatusObject obj{};
auto itr = m_Exits.begin(); auto itr = _exits.begin();
while (itr != m_Exits.end()) while (itr != _exits.end())
{ {
obj[itr->first] = itr->second->ExtractStatus(); obj[itr->first] = itr->second->ExtractStatus();
++itr; ++itr;
@ -58,10 +58,10 @@ namespace llarp::exit
} }
void void
Context::CalculateExitTraffic(TrafficStats& stats) Context::calculate_exit_traffic(TrafficStats& stats)
{ {
auto itr = m_Exits.begin(); auto itr = _exits.begin();
while (itr != m_Exits.end()) while (itr != _exits.end())
{ {
itr->second->CalculateTrafficStats(stats); itr->second->CalculateTrafficStats(stats);
++itr; ++itr;
@ -69,10 +69,10 @@ namespace llarp::exit
} }
exit::Endpoint* exit::Endpoint*
Context::FindEndpointForPath(const PathID_t& path) const Context::find_endpoint_for_path(const PathID_t& path) const
{ {
auto itr = m_Exits.begin(); auto itr = _exits.begin();
while (itr != m_Exits.end()) while (itr != _exits.end())
{ {
auto ep = itr->second->FindEndpointByPath(path); auto ep = itr->second->FindEndpointByPath(path);
if (ep) if (ep)
@ -83,10 +83,10 @@ namespace llarp::exit
} }
bool bool
Context::ObtainNewExit(const PubKey& pk, const PathID_t& path, bool permitInternet) Context::obtain_new_exit(const PubKey& pk, const PathID_t& path, bool permitInternet)
{ {
auto itr = m_Exits.begin(); auto itr = _exits.begin();
while (itr != m_Exits.end()) while (itr != _exits.end())
{ {
if (itr->second->AllocateNewExit(pk, path, permitInternet)) if (itr->second->AllocateNewExit(pk, path, permitInternet))
return true; return true;
@ -96,9 +96,9 @@ namespace llarp::exit
} }
std::shared_ptr<handlers::ExitEndpoint> std::shared_ptr<handlers::ExitEndpoint>
Context::GetExitEndpoint(std::string name) const Context::get_exit_endpoint(std::string name) const
{ {
if (auto itr = m_Exits.find(name); itr != m_Exits.end()) if (auto itr = _exits.find(name); itr != _exits.end())
{ {
return itr->second; return itr->second;
} }
@ -106,10 +106,10 @@ namespace llarp::exit
} }
void void
Context::AddExitEndpoint( Context::add_exit_endpoint(
const std::string& name, const NetworkConfig& networkConfig, const DnsConfig& dnsConfig) const std::string& name, const NetworkConfig& networkConfig, const DnsConfig& dnsConfig)
{ {
if (m_Exits.find(name) != m_Exits.end()) if (_exits.find(name) != _exits.end())
throw std::invalid_argument{fmt::format("An exit with name {} already exists", name)}; throw std::invalid_argument{fmt::format("An exit with name {} already exists", name)};
auto endpoint = std::make_unique<handlers::ExitEndpoint>(name, router); auto endpoint = std::make_unique<handlers::ExitEndpoint>(name, router);
@ -119,7 +119,7 @@ namespace llarp::exit
if (!endpoint->Start()) if (!endpoint->Start())
throw std::runtime_error{fmt::format("Failed to start endpoint {}", name)}; throw std::runtime_error{fmt::format("Failed to start endpoint {}", name)};
m_Exits.emplace(name, std::move(endpoint)); _exits.emplace(name, std::move(endpoint));
} }
} // namespace llarp::exit } // namespace llarp::exit

@ -18,37 +18,37 @@ namespace llarp::exit
Tick(llarp_time_t now); Tick(llarp_time_t now);
void void
ClearAllEndpoints(); clear_all_endpoints();
util::StatusObject util::StatusObject
ExtractStatus() const; ExtractStatus() const;
/// send close to all exit sessions and remove all sessions /// send close to all exit sessions and remove all sessions
void void
Stop(); stop();
void void
AddExitEndpoint( add_exit_endpoint(
const std::string& name, const NetworkConfig& networkConfig, const DnsConfig& dnsConfig); const std::string& name, const NetworkConfig& networkConfig, const DnsConfig& dnsConfig);
bool bool
ObtainNewExit(const PubKey& remote, const PathID_t& path, bool permitInternet); obtain_new_exit(const PubKey& remote, const PathID_t& path, bool permitInternet);
exit::Endpoint* exit::Endpoint*
FindEndpointForPath(const PathID_t& path) const; find_endpoint_for_path(const PathID_t& path) const;
/// calculate (pk, tx, rx) for all exit traffic /// calculate (pk, tx, rx) for all exit traffic
using TrafficStats = std::unordered_map<PubKey, std::pair<uint64_t, uint64_t>>; using TrafficStats = std::unordered_map<PubKey, std::pair<uint64_t, uint64_t>>;
void void
CalculateExitTraffic(TrafficStats& stats); calculate_exit_traffic(TrafficStats& stats);
std::shared_ptr<handlers::ExitEndpoint> std::shared_ptr<handlers::ExitEndpoint>
GetExitEndpoint(std::string name) const; get_exit_endpoint(std::string name) const;
private: private:
Router* router; Router* router;
std::unordered_map<std::string, std::shared_ptr<handlers::ExitEndpoint>> m_Exits; std::unordered_map<std::string, std::shared_ptr<handlers::ExitEndpoint>> _exits;
std::list<std::shared_ptr<handlers::ExitEndpoint>> m_Closed; std::list<std::shared_ptr<handlers::ExitEndpoint>> _closed;
}; };
} // namespace llarp::exit } // namespace llarp::exit

@ -5,82 +5,38 @@
namespace llarp namespace llarp
{ {
Contacts::Contacts(const dht::Key_t& k, Router& r) : _local_key{k}, _router{r} Contacts::Contacts(Router& r) : _router{r}, _local_key{r.pubkey()}
{ {
timer_keepalive = std::make_shared<int>(0); timer_keepalive = std::make_shared<int>(0);
_router.loop()->call_every(1s, timer_keepalive, [this]() { on_clean_contacts(); });
_rc_nodes = std::make_unique<dht::Bucket<dht::RCNode>>(_local_key, llarp::randint);
_introset_nodes = std::make_unique<dht::Bucket<dht::ISNode>>(_local_key, llarp::randint); _introset_nodes = std::make_unique<dht::Bucket<dht::ISNode>>(_local_key, llarp::randint);
} }
std::optional<service::EncryptedIntroSet> std::optional<service::EncryptedIntroSet>
Contacts::get_introset_by_location(const dht::Key_t& key) const Contacts::get_introset_by_location(const dht::Key_t& key) const
{ {
return _router.loop()->call_get([this, key]() -> std::optional<service::EncryptedIntroSet> { std::optional<service::EncryptedIntroSet> enc = std::nullopt;
auto& introsets = _introset_nodes->nodes;
if (auto itr = introsets.find(key); itr != introsets.end()) auto& introsets = _introset_nodes->nodes;
return itr->second.introset;
return std::nullopt; if (auto itr = introsets.find(key); itr != introsets.end())
}); enc = itr->second.introset;
}
void
Contacts::on_clean_contacts()
{
const auto now = llarp::time_now_ms();
if (_rc_nodes)
{
auto& nodes = _rc_nodes->nodes;
auto itr = nodes.begin();
while (itr != nodes.end())
{
if (itr->second.rc.is_expired(now))
itr = nodes.erase(itr);
else
++itr;
}
}
if (_introset_nodes) return enc;
{
auto& svcs = _introset_nodes->nodes;
auto itr = svcs.begin();
while (itr != svcs.end())
{
if (itr->second.introset.IsExpired(now))
itr = svcs.erase(itr);
else
++itr;
}
}
} }
util::StatusObject util::StatusObject
Contacts::ExtractStatus() const Contacts::ExtractStatus() const
{ {
util::StatusObject obj{ util::StatusObject obj{
{"nodes", _rc_nodes->ExtractStatus()}, {"services", _introset_nodes->ExtractStatus()}, {"local_key", _local_key.ToHex()}};
{"services", _introset_nodes->ExtractStatus()},
{"local_key", _local_key.ToHex()}};
return obj; return obj;
} }
void void
Contacts::put_rc_node_async(const dht::RCNode& val) Contacts::put_intro(service::EncryptedIntroSet enc)
{
_router.loop()->call([this, val]() { _rc_nodes->PutNode(val); });
}
void
Contacts::delete_rc_node_async(const dht::Key_t& val)
{ {
_router.loop()->call([this, val]() { _rc_nodes->DelNode(val); }); _introset_nodes->PutNode(std::move(enc));
} }
} // namespace llarp } // namespace llarp

@ -15,28 +15,14 @@ namespace llarp
private: private:
// TODO: why was this a shared ptr in the original implementation? revisit this // TODO: why was this a shared ptr in the original implementation? revisit this
std::shared_ptr<int> timer_keepalive; std::shared_ptr<int> timer_keepalive;
const dht::Key_t& _local_key;
Router& _router; Router& _router;
std::atomic<bool> transit_allowed{false}; const dht::Key_t _local_key;
// holds router contacts
std::unique_ptr<dht::Bucket<dht::RCNode>> _rc_nodes;
// holds introsets for remote services // holds introsets for remote services
std::unique_ptr<dht::Bucket<dht::ISNode>> _introset_nodes; std::unique_ptr<dht::Bucket<dht::ISNode>> _introset_nodes;
public: public:
Contacts(const dht::Key_t& local, Router& r); Contacts(Router& r);
/// Sets the value of transit_allowed to the value of `b`. Returns false if the
/// value was already b, true otherwise
bool
set_transit_allowed(bool b)
{
return not transit_allowed.exchange(b) == b;
}
void
on_clean_contacts();
std::optional<service::EncryptedIntroSet> std::optional<service::EncryptedIntroSet>
get_introset_by_location(const dht::Key_t& key) const; get_introset_by_location(const dht::Key_t& key) const;
@ -46,16 +32,7 @@ namespace llarp
ExtractStatus() const; ExtractStatus() const;
void void
put_rc_node_async(const dht::RCNode& val); put_intro(service::EncryptedIntroSet enc);
void
delete_rc_node_async(const dht::Key_t& val);
dht::Bucket<dht::RCNode>*
rc_nodes() const
{
return _rc_nodes.get();
}
dht::Bucket<dht::ISNode>* dht::Bucket<dht::ISNode>*
services() const services() const

@ -183,9 +183,11 @@ namespace llarp
- connection close callback - connection close callback
- stream constructor callback - stream constructor callback
- will return a BTRequestStream on the first call to get_new_stream<BTRequestStream> - will return a BTRequestStream on the first call to get_new_stream<BTRequestStream>
- bt stream construction contains a stream close callback that shuts down the connection
if the btstream closes unexpectedly
*/ */
auto ep = quic->endpoint( auto ep = quic->endpoint(
_router.local_addr(), _router.listen_addr(),
[this](oxen::quic::connection_interface& ci) { return on_conn_open(ci); }, [this](oxen::quic::connection_interface& ci) { return on_conn_open(ci); },
[this](oxen::quic::connection_interface& ci, uint64_t ec) { [this](oxen::quic::connection_interface& ci, uint64_t ec) {
return on_conn_closed(ci, ec); return on_conn_closed(ci, ec);
@ -198,7 +200,14 @@ namespace llarp
std::optional<int64_t> id) -> std::shared_ptr<oxen::quic::Stream> { std::optional<int64_t> id) -> std::shared_ptr<oxen::quic::Stream> {
if (id && id == 0) if (id && id == 0)
{ {
auto s = std::make_shared<oxen::quic::BTRequestStream>(c, e); auto s = std::make_shared<oxen::quic::BTRequestStream>(
c, e, [](oxen::quic::Stream& s, uint64_t error_code) {
log::warning(
logcat,
"BTRequestStream closed unexpectedly (ec:{}); closing connection...",
error_code);
s.conn.close_connection(error_code);
});
register_commands(s); register_commands(s);
return s; return s;
} }
@ -216,6 +225,13 @@ namespace llarp
, ep{startup_endpoint(), *this} , ep{startup_endpoint(), *this}
{} {}
std::unique_ptr<LinkManager>
LinkManager::make(Router& r)
{
std::unique_ptr<LinkManager> p{new LinkManager(r)};
return p;
}
bool bool
LinkManager::send_control_message( LinkManager::send_control_message(
const RouterID& remote, const RouterID& remote,
@ -496,6 +512,7 @@ namespace llarp
{ {
is_stopping = false; is_stopping = false;
node_db = _router.node_db(); node_db = _router.node_db();
client_router_connections = _router.required_num_client_conns();
} }
void void
@ -898,7 +915,7 @@ namespace llarp
"Received PublishIntroMessage in which we are peer index {}.. storing introset", "Received PublishIntroMessage in which we are peer index {}.. storing introset",
relay_order); relay_order);
_router.contacts()->services()->PutNode(dht::ISNode{std::move(enc)}); _router.contacts().put_intro(std::move(enc));
respond(serialize_response({{messages::STATUS_KEY, ""}})); respond(serialize_response({{messages::STATUS_KEY, ""}}));
} }
else else
@ -936,7 +953,7 @@ namespace llarp
{ {
log::info(link_cat, "Received PublishIntroMessage for {} (TXID: {}); we are candidate {}"); log::info(link_cat, "Received PublishIntroMessage for {} (TXID: {}); we are candidate {}");
_router.contacts()->services()->PutNode(dht::ISNode{std::move(enc)}); _router.contacts().put_intro(std::move(enc));
respond(serialize_response({{messages::STATUS_KEY, ""}})); respond(serialize_response({{messages::STATUS_KEY, ""}}));
} }
else else
@ -1064,7 +1081,7 @@ namespace llarp
} }
else else
{ {
if (auto maybe_intro = _router.contacts()->get_introset_by_location(addr)) if (auto maybe_intro = _router.contacts().get_introset_by_location(addr))
respond(serialize_response({{"INTROSET", maybe_intro->bt_encode()}})); respond(serialize_response({{"INTROSET", maybe_intro->bt_encode()}}));
else else
{ {
@ -1102,7 +1119,7 @@ namespace llarp
if (m) if (m)
{ {
service::EncryptedIntroSet enc{payload}; service::EncryptedIntroSet enc{payload};
_router.contacts()->services()->PutNode(std::move(enc)); _router.contacts().put_intro(std::move(enc));
} }
else else
{ {
@ -1114,7 +1131,7 @@ namespace llarp
void void
LinkManager::handle_path_build(oxen::quic::message m, const RouterID& from) LinkManager::handle_path_build(oxen::quic::message m, const RouterID& from)
{ {
if (!_router.path_context().AllowingTransit()) if (!_router.path_context().is_transit_allowed())
{ {
log::warning(link_cat, "got path build request when not permitting transit"); log::warning(link_cat, "got path build request when not permitting transit");
m.respond(serialize_response({{messages::STATUS_KEY, PathBuildMessage::NO_TRANSIT}}), true); m.respond(serialize_response({{messages::STATUS_KEY, PathBuildMessage::NO_TRANSIT}}), true);
@ -1200,7 +1217,7 @@ namespace llarp
hop->info.upstream.from_string(upstream); hop->info.upstream.from_string(upstream);
if (_router.path_context().HasTransitHop(hop->info)) if (_router.path_context().has_transit_hop(hop->info))
{ {
log::warning(link_cat, "Invalid PathID; PathIDs must be unique"); log::warning(link_cat, "Invalid PathID; PathIDs must be unique");
m.respond(serialize_response({{messages::STATUS_KEY, PathBuildMessage::BAD_PATHID}}), true); m.respond(serialize_response({{messages::STATUS_KEY, PathBuildMessage::BAD_PATHID}}), true);
@ -1237,7 +1254,7 @@ namespace llarp
{ {
hop->terminal_hop = true; hop->terminal_hop = true;
// we are terminal hop and everything is okay // we are terminal hop and everything is okay
_router.path_context().PutTransitHop(hop); _router.path_context().put_transit_hop(hop);
m.respond(messages::OK_RESPONSE, false); m.respond(messages::OK_RESPONSE, false);
return; return;
} }
@ -1270,7 +1287,7 @@ namespace llarp
link_cat, link_cat,
"Upstream returned successful path build response; giving hop info to Router, " "Upstream returned successful path build response; giving hop info to Router, "
"then relaying response"); "then relaying response");
_router.path_context().PutTransitHop(hop); _router.path_context().put_transit_hop(hop);
} }
if (m.timed_out) if (m.timed_out)
log::info(link_cat, "Upstream timed out on path build; relaying timeout"); log::info(link_cat, "Upstream timed out on path build; relaying timeout");
@ -1380,7 +1397,7 @@ namespace llarp
auto success = auto success =
(crypto::verify(pubkey, to_usv(dict_data), sig) (crypto::verify(pubkey, to_usv(dict_data), sig)
and _router.exitContext().ObtainNewExit(PubKey{pubkey.data()}, rx_id, flag != 0)); and _router.exitContext().obtain_new_exit(PubKey{pubkey.data()}, rx_id, flag != 0));
m.respond( m.respond(
ObtainExitMessage::sign_and_serialize_response(_router.identity(), tx_id), not success); ObtainExitMessage::sign_and_serialize_response(_router.identity(), tx_id), not success);
@ -1417,7 +1434,7 @@ namespace llarp
throw; throw;
} }
auto path_ptr = _router.path_context().GetPath(PathID_t{to_usv(tx_id).data()}); auto path_ptr = _router.path_context().get_path(PathID_t{to_usv(tx_id).data()});
if (crypto::verify(_router.pubkey(), to_usv(dict_data), sig)) if (crypto::verify(_router.pubkey(), to_usv(dict_data), sig))
path_ptr->enable_exit_traffic(); path_ptr->enable_exit_traffic();
@ -1449,7 +1466,8 @@ namespace llarp
auto transit_hop = auto transit_hop =
_router.path_context().GetTransitHop(_router.pubkey(), PathID_t{to_usv(tx_id).data()}); _router.path_context().GetTransitHop(_router.pubkey(), PathID_t{to_usv(tx_id).data()});
if (auto exit_ep = _router.exitContext().FindEndpointForPath(PathID_t{to_usv(path_id).data()})) if (auto exit_ep =
_router.exitContext().find_endpoint_for_path(PathID_t{to_usv(path_id).data()}))
{ {
if (crypto::verify(exit_ep->PubKey().data(), to_usv(dict_data), sig)) if (crypto::verify(exit_ep->PubKey().data(), to_usv(dict_data), sig))
{ {
@ -1495,7 +1513,7 @@ namespace llarp
return; return;
} }
auto path_ptr = _router.path_context().GetPath(PathID_t{to_usv(tx_id).data()}); auto path_ptr = _router.path_context().get_path(PathID_t{to_usv(tx_id).data()});
if (crypto::verify(_router.pubkey(), to_usv(dict_data), sig)) if (crypto::verify(_router.pubkey(), to_usv(dict_data), sig))
{ {
@ -1536,7 +1554,7 @@ namespace llarp
const auto rx_id = transit_hop->info.rxID; const auto rx_id = transit_hop->info.rxID;
if (auto exit_ep = router().exitContext().FindEndpointForPath(rx_id)) if (auto exit_ep = router().exitContext().find_endpoint_for_path(rx_id))
{ {
if (crypto::verify(exit_ep->PubKey().data(), to_usv(dict_data), sig)) if (crypto::verify(exit_ep->PubKey().data(), to_usv(dict_data), sig))
{ {
@ -1580,7 +1598,7 @@ namespace llarp
return; return;
} }
auto path_ptr = _router.path_context().GetPath(PathID_t{to_usv(tx_id).data()}); auto path_ptr = _router.path_context().get_path(PathID_t{to_usv(tx_id).data()});
if (path_ptr->SupportsAnyRoles(path::ePathRoleExit | path::ePathRoleSVC) if (path_ptr->SupportsAnyRoles(path::ePathRoleExit | path::ePathRoleSVC)
and crypto::verify(_router.pubkey(), to_usv(dict_data), sig)) and crypto::verify(_router.pubkey(), to_usv(dict_data), sig))

@ -30,6 +30,8 @@ namespace llarp
using conn_open_hook = oxen::quic::connection_established_callback; using conn_open_hook = oxen::quic::connection_established_callback;
using conn_closed_hook = oxen::quic::connection_closed_callback; using conn_closed_hook = oxen::quic::connection_closed_callback;
using stream_open_hook = oxen::quic::stream_open_callback;
using stream_closed_hook = oxen::quic::stream_close_callback;
namespace link namespace link
{ {
@ -141,7 +143,8 @@ namespace llarp
struct LinkManager struct LinkManager
{ {
public: public:
explicit LinkManager(Router& r); static std::unique_ptr<LinkManager>
make(Router& r);
bool bool
send_control_message( send_control_message(
@ -160,6 +163,8 @@ namespace llarp
} }
private: private:
explicit LinkManager(Router& r);
bool bool
send_control_message_impl( send_control_message_impl(
const RouterID& remote, const RouterID& remote,
@ -310,11 +315,8 @@ namespace llarp
void void
connect_to_random(int num_conns); connect_to_random(int num_conns);
// TODO: tune these (maybe even remove max?) now that we're switching to quic /// always maintain this many client connections to other routers
/// always maintain this many connections to other routers int client_router_connections = 4;
size_t min_connected_routers = 4;
/// hard upperbound limit on the number of router to router connections
size_t max_connected_routers = 6;
private: private:
// DHT messages // DHT messages

@ -766,8 +766,7 @@ namespace llarp
router_greenlist.clear(); router_greenlist.clear();
router_greenlist.insert(greenlist.begin(), greenlist.end()); router_greenlist.insert(greenlist.begin(), greenlist.end());
log::info( log::info(logcat, "lokinet service node list now has {} active router RIDs", known_rids.size());
logcat, "lokinet service node list now has ", known_rids.size(), " active router RIDs");
} }
std::optional<RouterID> std::optional<RouterID>
@ -843,7 +842,7 @@ namespace llarp
const auto& rid = rc.router_id(); const auto& rid = rc.router_id();
auto [itr, b] = known_rcs.emplace(std::move(rc)); auto [itr, b] = known_rcs.insert(std::move(rc));
rc_lookup.emplace(rid, *itr); rc_lookup.emplace(rid, *itr);
known_rids.insert(rid); known_rids.insert(rid);
@ -930,7 +929,7 @@ namespace llarp
known_rcs.erase(rc); known_rcs.erase(rc);
rc_lookup.erase(rid); rc_lookup.erase(rid);
auto [itr, b] = known_rcs.emplace(std::move(rc)); auto [itr, b] = known_rcs.insert(std::move(rc));
rc_lookup.emplace(rid, *itr); rc_lookup.emplace(rid, *itr);
known_rids.insert(rid); known_rids.insert(rid);
@ -939,9 +938,9 @@ namespace llarp
} }
size_t size_t
NodeDB::num_loaded() const NodeDB::num_rcs() const
{ {
return _router.loop()->call_get([this]() { return known_rcs.size(); }); return known_rcs.size();
} }
bool bool

@ -178,7 +178,7 @@ namespace llarp
fs::path fs::path
get_path_by_pubkey(RouterID pk) const; get_path_by_pubkey(RouterID pk) const;
std::unique_ptr<BootstrapList> _bootstraps; std::unique_ptr<BootstrapList> _bootstraps{};
public: public:
explicit NodeDB( explicit NodeDB(
@ -299,10 +299,28 @@ namespace llarp
return _pinned_edges; return _pinned_edges;
} }
std::unique_ptr<BootstrapList>& size_t
num_bootstraps() const
{
return _bootstraps ? _bootstraps->size() : 0;
}
bool
has_bootstraps() const
{
return _bootstraps ? _bootstraps->empty() : false;
}
const BootstrapList&
bootstrap_list() const
{
return *_bootstraps;
}
BootstrapList&
bootstrap_list() bootstrap_list()
{ {
return _bootstraps; return *_bootstraps;
} }
void void
@ -354,7 +372,7 @@ namespace llarp
/// the number of RCs that are loaded from disk /// the number of RCs that are loaded from disk
size_t size_t
num_loaded() const; num_rcs() const;
/// do periodic tasks like flush to disk and expiration /// do periodic tasks like flush to disk and expiration
void void

@ -13,19 +13,19 @@ namespace llarp::path
{} {}
void void
PathContext::AllowTransit() PathContext::allow_transit()
{ {
m_AllowTransit = true; m_AllowTransit = true;
} }
bool bool
PathContext::AllowingTransit() const PathContext::is_transit_allowed() const
{ {
return m_AllowTransit; return m_AllowTransit;
} }
bool bool
PathContext::CheckPathLimitHitByIP(const IpAddress& ip) PathContext::check_path_limit_hit_by_ip(const IpAddress& ip)
{ {
#ifdef TESTNET #ifdef TESTNET
return false; return false;
@ -39,21 +39,6 @@ namespace llarp::path
#endif #endif
} }
bool
PathContext::CheckPathLimitHitByIP(const std::string& ip)
{
#ifdef TESTNET
return false;
#else
IpAddress remote{ip};
// null out the port -- we don't care about it for path limiting purposes
remote.setPort(0);
// try inserting remote address by ip into decaying hash set
// if it cannot insert it has hit a limit
return not path_limits.Insert(remote);
#endif
}
const EventLoop_ptr& const EventLoop_ptr&
PathContext::loop() PathContext::loop()
{ {
@ -102,7 +87,7 @@ namespace llarp::path
} }
bool bool
PathContext::HasTransitHop(const TransitHopInfo& info) PathContext::has_transit_hop(const TransitHopInfo& info)
{ {
TransitHopID downstream{info.downstream, info.rxID}; TransitHopID downstream{info.downstream, info.rxID};
if (transit_hops.count(downstream)) if (transit_hops.count(downstream))
@ -125,7 +110,7 @@ namespace llarp::path
} }
Path_ptr Path_ptr
PathContext::GetPath(const PathID_t& path_id) PathContext::get_path(const PathID_t& path_id)
{ {
if (auto itr = own_paths.find(path_id); itr != own_paths.end()) if (auto itr = own_paths.find(path_id); itr != own_paths.end())
return itr->second; return itr->second;
@ -186,7 +171,7 @@ namespace llarp::path
} }
void void
PathContext::PutTransitHop(std::shared_ptr<TransitHop> hop) PathContext::put_transit_hop(std::shared_ptr<TransitHop> hop)
{ {
TransitHopID downstream{hop->info.downstream, hop->info.rxID}; TransitHopID downstream{hop->info.downstream, hop->info.rxID};
TransitHopID upstream{hop->info.upstream, hop->info.txID}; TransitHopID upstream{hop->info.upstream, hop->info.txID};

@ -62,28 +62,25 @@ namespace llarp::path
ExpirePaths(llarp_time_t now); ExpirePaths(llarp_time_t now);
void void
AllowTransit(); allow_transit();
void void
RejectTransit(); reject_transit();
bool bool
CheckPathLimitHitByIP(const IpAddress& ip); check_path_limit_hit_by_ip(const IpAddress& ip);
bool bool
CheckPathLimitHitByIP(const std::string& ip); is_transit_allowed() const;
bool bool
AllowingTransit() const; has_transit_hop(const TransitHopInfo& info);
bool
HasTransitHop(const TransitHopInfo& info);
void void
PutTransitHop(std::shared_ptr<TransitHop> hop); put_transit_hop(std::shared_ptr<TransitHop> hop);
Path_ptr Path_ptr
GetPath(const PathID_t& path_id); get_path(const PathID_t& path_id);
bool bool
TransitHopPreviousIsRouter(const PathID_t& path, const RouterID& r); TransitHopPreviousIsRouter(const PathID_t& path, const RouterID& r);

@ -224,7 +224,7 @@ namespace llarp
const auto& rid = rc.router_id(); const auto& rid = rc.router_id();
#ifndef TESTNET #ifndef TESTNET
if (router->IsBootstrapNode(rid)) if (router->is_bootstrap_node(rid))
return; return;
#endif #endif
if (exclude.count(rid)) if (exclude.count(rid))

@ -45,7 +45,7 @@ namespace llarp
, _disk_thread{_lmq->add_tagged_thread("disk")} , _disk_thread{_lmq->add_tagged_thread("disk")}
, _rpc_server{nullptr} , _rpc_server{nullptr}
, _randomStartDelay{platform::is_simulation ? std::chrono::milliseconds{(llarp::randint() % 1250) + 2000} : 0s} , _randomStartDelay{platform::is_simulation ? std::chrono::milliseconds{(llarp::randint() % 1250) + 2000} : 0s}
, _link_manager{*this} // , _link_manager{*this}
, _hidden_service_context{this} , _hidden_service_context{this}
{ {
_key_manager = std::make_shared<KeyManager>(); _key_manager = std::make_shared<KeyManager>();
@ -59,9 +59,7 @@ namespace llarp
} }
Router::~Router() Router::~Router()
{ {}
_contacts.reset();
}
// TODO: investigate changes needed for libquic integration // TODO: investigate changes needed for libquic integration
// still needed at all? // still needed at all?
@ -86,11 +84,10 @@ namespace llarp
return util::StatusObject{ return util::StatusObject{
{"running", true}, {"running", true},
{"numNodesKnown", _node_db->num_loaded()}, {"numNodesKnown", _node_db->num_rcs()},
{"contacts", _contacts->ExtractStatus()},
{"services", _hidden_service_context.ExtractStatus()}, {"services", _hidden_service_context.ExtractStatus()},
{"exit", _exit_context.ExtractStatus()}, {"exit", _exit_context.ExtractStatus()},
{"links", _link_manager.extract_status()}}; {"links", _link_manager->extract_status()}};
} }
// TODO: investigate changes needed for libquic integration // TODO: investigate changes needed for libquic integration
@ -102,7 +99,7 @@ namespace llarp
auto services = _hidden_service_context.ExtractStatus(); auto services = _hidden_service_context.ExtractStatus();
auto link_types = _link_manager.extract_status(); auto link_types = _link_manager->extract_status();
uint64_t tx_rate = 0; uint64_t tx_rate = 0;
uint64_t rx_rate = 0; uint64_t rx_rate = 0;
@ -175,7 +172,7 @@ namespace llarp
{"uptime", to_json(Uptime())}, {"uptime", to_json(Uptime())},
{"numPathsBuilt", pathsCount}, {"numPathsBuilt", pathsCount},
{"numPeersConnected", peers}, {"numPeersConnected", peers},
{"numRoutersKnown", _node_db->num_loaded()}, {"numRoutersKnown", _node_db->num_rcs()},
{"ratio", ratio}, {"ratio", ratio},
{"txRate", tx_rate}, {"txRate", tx_rate},
{"rxRate", rx_rate}, {"rxRate", rx_rate},
@ -227,14 +224,14 @@ namespace llarp
loop()->call([this, &peer_pubkeys]() { loop()->call([this, &peer_pubkeys]() {
for (auto& pk : peer_pubkeys) for (auto& pk : peer_pubkeys)
_link_manager.close_connection(pk); _link_manager->close_connection(pk);
}); });
} }
void void
Router::persist_connection_until(const RouterID& remote, llarp_time_t until) Router::persist_connection_until(const RouterID& remote, llarp_time_t until)
{ {
_link_manager.set_conn_persist(remote, until); _link_manager->set_conn_persist(remote, until);
} }
std::optional<RouterID> std::optional<RouterID>
@ -262,19 +259,19 @@ namespace llarp
void void
Router::connect_to(const RouterID& rid) Router::connect_to(const RouterID& rid)
{ {
_link_manager.connect_to(rid); _link_manager->connect_to(rid);
} }
void void
Router::connect_to(const RemoteRC& rc) Router::connect_to(const RemoteRC& rc)
{ {
_link_manager.connect_to(rc); _link_manager->connect_to(rc);
} }
bool bool
Router::send_data_message(const RouterID& remote, std::string payload) Router::send_data_message(const RouterID& remote, std::string payload)
{ {
return _link_manager.send_data_message(remote, std::move(payload)); return _link_manager->send_data_message(remote, std::move(payload));
} }
bool bool
@ -284,20 +281,20 @@ namespace llarp
std::string body, std::string body,
std::function<void(oxen::quic::message m)> func) std::function<void(oxen::quic::message m)> func)
{ {
return _link_manager.send_control_message( return _link_manager->send_control_message(
remote, std::move(ep), std::move(body), std::move(func)); remote, std::move(ep), std::move(body), std::move(func));
} }
void void
Router::for_each_connection(std::function<void(link::Connection&)> func) Router::for_each_connection(std::function<void(link::Connection&)> func)
{ {
return _link_manager.for_each_connection(func); return _link_manager->for_each_connection(func);
} }
bool bool
Router::EnsureIdentity() Router::EnsureIdentity()
{ {
_encryption = _key_manager->encryptionKey; _encryption = _key_manager->encryption_key;
if (is_service_node()) if (is_service_node())
{ {
@ -340,13 +337,19 @@ namespace llarp
} }
else else
{ {
_identity = _key_manager->identityKey; _identity = _key_manager->identity_key;
} }
if (_identity.IsZero()) if (_identity.IsZero())
{
log::critical(logcat, "FUCK @ line:{}", __LINE__);
return false; return false;
}
if (_encryption.IsZero()) if (_encryption.IsZero())
{
log::critical(logcat, "FUCK @ line:{}", __LINE__);
return false; return false;
}
return true; return true;
} }
@ -435,7 +438,7 @@ namespace llarp
Router::insufficient_peers() const Router::insufficient_peers() const
{ {
constexpr int KnownPeerWarningThreshold = 5; constexpr int KnownPeerWarningThreshold = 5;
return node_db()->num_loaded() < KnownPeerWarningThreshold; return node_db()->num_rcs() < KnownPeerWarningThreshold;
} }
std::optional<std::string> std::optional<std::string>
@ -509,21 +512,22 @@ namespace llarp
} }
size_t size_t
Router::NumberOfConnectedRouters() const Router::num_router_connections() const
{ {
return _link_manager.get_num_connected(); return _link_manager->get_num_connected();
} }
size_t size_t
Router::NumberOfConnectedClients() const Router::num_client_connections() const
{ {
return _link_manager.get_num_connected_clients(); return _link_manager->get_num_connected_clients();
} }
void void
Router::save_rc() Router::save_rc()
{ {
_node_db->put_rc(router_contact.view()); _node_db->put_rc(router_contact.view());
log::info(logcat, "Saving RC file to {}", our_rc_file);
queue_disk_io([&]() { router_contact.write(our_rc_file); }); queue_disk_io([&]() { router_contact.write(our_rc_file); });
} }
@ -552,13 +556,14 @@ namespace llarp
} }
// Router config // Router config
_link_manager.max_connected_routers = conf.router.max_connected_routers; client_router_connections = conf.router.client_router_connections;
_link_manager.min_connected_routers = conf.router.min_connected_routers;
encryption_keyfile = _key_manager->m_encKeyPath; encryption_keyfile = _key_manager->enckey_path;
our_rc_file = _key_manager->m_rcPath; our_rc_file = _key_manager->rc_path;
transport_keyfile = _key_manager->m_transportKeyPath; transport_keyfile = _key_manager->transkey_path;
identity_keyfile = _key_manager->m_idKeyPath; identity_keyfile = _key_manager->idkey_path;
std::optional<SockAddr> _ourAddress;
if (auto maybe_ip = conf.links.public_addr) if (auto maybe_ip = conf.links.public_addr)
_ourAddress = var::visit([](auto&& ip) { return SockAddr{ip}; }, *maybe_ip); _ourAddress = var::visit([](auto&& ip) { return SockAddr{ip}; }, *maybe_ip);
@ -574,11 +579,22 @@ namespace llarp
else else
throw std::runtime_error{"public ip provided without public port"}; throw std::runtime_error{"public ip provided without public port"};
log::debug(logcat, "Using {} for our public address", *_ourAddress); log::debug(logcat, "Using {} for our public address", *_ourAddress);
_public_address = oxen::quic::Address{static_cast<const sockaddr*>(*_ourAddress)};
log::critical(logcat, "PUBLIC ADDR: {}", *_public_address);
} }
else else
log::debug(logcat, "No explicit public address given; will auto-detect during link setup"); {
log::debug(logcat, "No explicit public address given; inferring now...");
_local_addr = conf.links.addr; if (auto maybe_addr = net().GetBestNetIF())
{
_public_address = oxen::quic::Address{static_cast<const sockaddr*>(*maybe_addr)};
log::critical(logcat, "PUBLIC ADDR: {}", *_public_address);
}
}
_listen_addr = conf.links.addr;
RouterContact::BLOCK_BOGONS = conf.router.block_bogons; RouterContact::BLOCK_BOGONS = conf.router.block_bogons;
@ -618,6 +634,26 @@ namespace llarp
auto _bootstrap_rc_list = std::make_unique<BootstrapList>(); auto _bootstrap_rc_list = std::make_unique<BootstrapList>();
auto clear_bad_rcs = [&]() mutable {
// 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 bootstrap 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);
}
};
for (const auto& router : configRouters) for (const auto& router : configRouters)
{ {
log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile); log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile);
@ -629,11 +665,18 @@ namespace llarp
_bootstrap_rc_list->emplace(rc); _bootstrap_rc_list->emplace(rc);
} }
clear_bad_rcs();
if (_bootstrap_rc_list->empty() and not conf.bootstrap.seednode) if (_bootstrap_rc_list->empty() and not conf.bootstrap.seednode)
{ {
auto fallbacks = llarp::load_bootstrap_fallbacks(); auto fallbacks = llarp::load_bootstrap_fallbacks();
if (_bootstrap_rc_list->empty() and not conf.bootstrap.seednode) if (auto itr = fallbacks.find(RouterContact::ACTIVE_NETID); itr != fallbacks.end())
{
_bootstrap_rc_list->merge(itr->second);
}
if (_bootstrap_rc_list->empty())
{ {
// empty after trying fallback, if set // empty after trying fallback, if set
log::error( log::error(
@ -644,35 +687,15 @@ namespace llarp
throw std::runtime_error("No bootstrap nodes available."); throw std::runtime_error("No bootstrap nodes available.");
} }
}
// 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 bootstrap 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: log::info(
it = _bootstrap_rc_list->erase(it); logcat, "Loaded {} default fallback bootstrap routers!", _bootstrap_rc_list->size());
clear_bad_rcs();
node_db()->set_bootstrap_routers(std::move(_bootstrap_rc_list));
} }
node_db()->set_bootstrap_routers(std::move(_bootstrap_rc_list));
if (conf.bootstrap.seednode) if (conf.bootstrap.seednode)
LogInfo("we are a seed node"); log::critical(logcat, "We are a bootstrap seed node!");
else
LogInfo("Loaded ", _bootstrap_rc_list->size(), " bootstrap routers");
// Init components after relevant config settings loaded
_link_manager.init();
// TODO: RC refactor here // TODO: RC refactor here
if (_is_service_node) if (_is_service_node)
@ -713,14 +736,18 @@ namespace llarp
} }
bool bool
Router::IsBootstrapNode(const RouterID r) const Router::is_bootstrap_node(const RouterID r) const
{ {
const auto& b = _node_db->bootstrap_list(); if (_node_db->has_bootstraps())
return std::count_if( {
b->begin(), const auto& b = _node_db->bootstrap_list();
b->end(), return std::count_if(
[r](const RemoteRC& rc) -> bool { return rc.router_id() == r; }) b.begin(),
> 0; b.end(),
[r](const RemoteRC& rc) -> bool { return rc.router_id() == r; })
> 0;
}
return false;
} }
bool bool
@ -737,16 +764,16 @@ namespace llarp
log::info( log::info(
logcat, logcat,
"{} RCs loaded with {} bootstrap peers and {} router connections!", "{} RCs loaded with {} bootstrap peers and {} router connections!",
node_db()->num_loaded(), _node_db->num_rcs(),
_node_db->bootstrap_list()->size(), _node_db->num_bootstraps(),
NumberOfConnectedRouters()); num_router_connections());
if (is_service_node()) if (is_service_node())
{ {
log::info( log::info(
logcat, logcat,
"Local service node has {} client connections since last RC update ({} to expiry)", "Local service node has {} client connections since last RC update ({} to expiry)",
NumberOfConnectedClients(), num_client_connections(),
router_contact.age(now), router_contact.age(now),
router_contact.time_to_expiry(now)); router_contact.time_to_expiry(now));
} }
@ -766,9 +793,9 @@ namespace llarp
fmt::format_to( fmt::format_to(
out, out,
" snode | known/svc/clients: {}/{}/{}", " snode | known/svc/clients: {}/{}/{}",
node_db()->num_loaded(), node_db()->num_rcs(),
NumberOfConnectedRouters(), num_router_connections(),
NumberOfConnectedClients()); num_client_connections());
fmt::format_to( fmt::format_to(
out, out,
" | {} active paths | block {} ", " | {} active paths | block {} ",
@ -784,10 +811,7 @@ namespace llarp
else else
{ {
fmt::format_to( fmt::format_to(
out, out, " client | known/connected: {}/{}", node_db()->num_rcs(), num_router_connections());
" client | known/connected: {}/{}",
node_db()->num_loaded(),
NumberOfConnectedRouters());
if (auto ep = hidden_service_context().GetDefault()) if (auto ep = hidden_service_context().GetDefault())
{ {
@ -850,7 +874,7 @@ namespace llarp
auto view = router_contact.view(); auto view = router_contact.view();
_link_manager.gossip_rc( _link_manager->gossip_rc(
pubkey(), std::string{reinterpret_cast<const char*>(view.data()), view.size()}); pubkey(), std::string{reinterpret_cast<const char*>(view.data()), view.size()});
last_rc_gossip = now_timepoint; last_rc_gossip = now_timepoint;
@ -891,14 +915,14 @@ namespace llarp
// remove RCs for nodes that are no longer allowed by network policy // remove RCs for nodes that are no longer allowed by network policy
node_db()->RemoveIf([&](const RemoteRC& rc) -> bool { node_db()->RemoveIf([&](const RemoteRC& rc) -> bool {
// don't purge bootstrap nodes from nodedb // don't purge bootstrap nodes from nodedb
if (IsBootstrapNode(rc.router_id())) if (is_bootstrap_node(rc.router_id()))
{ {
log::trace(logcat, "Not removing {}: is bootstrap node", rc.router_id()); log::trace(logcat, "Not removing {}: is bootstrap node", rc.router_id());
return false; return false;
} }
// if for some reason we stored an RC that isn't a valid router // if for some reason we stored an RC that isn't a valid router
// purge this entry // purge this entry
if (not rc.is_public_router()) if (not rc.is_public_addressable())
{ {
log::debug(logcat, "Removing {}: not a valid router", rc.router_id()); log::debug(logcat, "Removing {}: not a valid router", rc.router_id());
return true; return true;
@ -956,11 +980,11 @@ namespace llarp
} }
*/ */
_link_manager.check_persisting_conns(now); _link_manager->check_persisting_conns(now);
size_t connected = NumberOfConnectedRouters(); size_t connected = num_router_connections();
size_t connectToNum = _link_manager.min_connected_routers; size_t connectToNum = _link_manager->client_router_connections;
const auto& pinned_edges = _node_db->pinned_edges(); const auto& pinned_edges = _node_db->pinned_edges();
const auto pinned_count = pinned_edges.size(); const auto pinned_count = pinned_edges.size();
@ -989,7 +1013,7 @@ namespace llarp
log::error( log::error(
logcat, logcat,
"We appear to be an active service node, but have only {} known peers.", "We appear to be an active service node, but have only {} known peers.",
node_db()->num_loaded()); node_db()->num_rcs());
_next_decomm_warning = now + DecommissionWarnInterval; _next_decomm_warning = now + DecommissionWarnInterval;
} }
} }
@ -1000,7 +1024,7 @@ namespace llarp
{ {
size_t dlt = connectToNum - connected; size_t dlt = connectToNum - connected;
LogDebug("connecting to ", dlt, " random routers to keep alive"); LogDebug("connecting to ", dlt, " random routers to keep alive");
_link_manager.connect_to_random(dlt); _link_manager->connect_to_random(dlt);
} }
_hidden_service_context.Tick(now); _hidden_service_context.Tick(now);
@ -1023,7 +1047,7 @@ namespace llarp
bool bool
Router::GetRandomConnectedRouter(RemoteRC& result) const Router::GetRandomConnectedRouter(RemoteRC& result) const
{ {
return _link_manager.get_random_connected(result); return _link_manager->get_random_connected(result);
} }
const std::set<RouterID>& const std::set<RouterID>&
@ -1054,16 +1078,22 @@ namespace llarp
bool bool
Router::Run() Router::Run()
{ {
log::critical(logcat, "{} called", __PRETTY_FUNCTION__);
if (is_running || is_stopping) if (is_running || is_stopping)
return false; return false;
// TODO: look at _ourAddress router_contact = LocalRC::make(
identity(), _is_service_node and _public_address ? *_public_address : _listen_addr);
router_contact = LocalRC::make(identity(), local_addr()); _link_manager = LinkManager::make(*this);
if (is_service_node() and not router_contact.is_public_router()) // Init components after relevant config settings loaded
_link_manager->init();
if (is_service_node())
{ {
if (not router_contact.is_public_router()) if (not router_contact.is_public_addressable())
{ {
log::error(logcat, "Router is configured as relay but has no reachable addresses!"); log::error(logcat, "Router is configured as relay but has no reachable addresses!");
return false; return false;
@ -1101,16 +1131,19 @@ namespace llarp
log::info(logcat, "Loading NodeDB from disk..."); log::info(logcat, "Loading NodeDB from disk...");
_node_db->load_from_disk(); _node_db->load_from_disk();
_contacts = std::make_shared<Contacts>(llarp::dht::Key_t(pubkey()), *this); log::info(logcat, "Creating Introset Contacts...");
_contacts = std::make_unique<Contacts>(*this);
for (const auto& rc : *_node_db->bootstrap_list()) if (_node_db->has_bootstraps())
{ {
node_db()->put_rc(rc); for (const auto& rc : _node_db->bootstrap_list())
_contacts->rc_nodes()->PutNode(rc); {
log::info(logcat, "Added bootstrap node (rid: {})", rc.router_id()); node_db()->put_rc(rc);
} log::info(logcat, "Added bootstrap node (rid: {})", rc.router_id());
}
log::info(logcat, "Router populated NodeDB with {} routers", _node_db->num_loaded()); log::info(logcat, "Router populated NodeDB with {} routers", _node_db->num_rcs());
}
_loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); }); _loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); });
@ -1155,7 +1188,7 @@ namespace llarp
// try to make a session to this random router // try to make a session to this random router
// this will do a dht lookup if needed // this will do a dht lookup if needed
_link_manager.test_reachability( _link_manager->test_reachability(
router, router,
[this, rid = router, previous = fails](oxen::quic::connection_interface& conn) { [this, rid = router, previous = fails](oxen::quic::connection_interface& conn) {
log::info( log::info(
@ -1224,7 +1257,7 @@ namespace llarp
void void
Router::StopLinks() Router::StopLinks()
{ {
_link_manager.stop(); _link_manager->stop();
} }
void void
@ -1241,7 +1274,7 @@ namespace llarp
LogWarn("stopping router hard"); LogWarn("stopping router hard");
llarp::sys::service_manager->stopping(); llarp::sys::service_manager->stopping();
hidden_service_context().StopAll(); hidden_service_context().StopAll();
_exit_context.Stop(); _exit_context.stop();
StopLinks(); StopLinks();
Close(); Close();
} }
@ -1261,27 +1294,27 @@ namespace llarp
} }
is_stopping.store(true); is_stopping.store(true);
if (auto level = log::get_level_default(); if (auto level = log::get_level_default();
level > log::Level::info and level != log::Level::off) level > log::Level::info and level != log::Level::off)
log::reset_level(log::Level::info); log::reset_level(log::Level::info);
log::info(logcat, "stopping");
log::info(logcat, "stopping service manager...");
llarp::sys::service_manager->stopping(); llarp::sys::service_manager->stopping();
log::debug(logcat, "stopping hidden service context");
log::debug(logcat, "stopping hidden service context...");
hidden_service_context().StopAll(); hidden_service_context().StopAll();
llarp::sys::service_manager->stopping();
log::debug(logcat, "stopping exit context"); log::debug(logcat, "stopping exit context...");
_exit_context.Stop(); _exit_context.stop();
llarp::sys::service_manager->stopping();
log::debug(logcat, "final upstream pump");
llarp::sys::service_manager->stopping();
log::debug(logcat, "final links pump");
_loop->call_later(200ms, [this] { AfterStopIssued(); }); _loop->call_later(200ms, [this] { AfterStopIssued(); });
} }
bool bool
Router::HasSessionTo(const RouterID& remote) const Router::HasSessionTo(const RouterID& remote) const
{ {
return _link_manager.have_connection_to(remote); return _link_manager->have_connection_to(remote);
} }
std::string std::string
@ -1300,19 +1333,20 @@ namespace llarp
Router::ConnectToRandomRouters(int _want) Router::ConnectToRandomRouters(int _want)
{ {
const size_t want = _want; const size_t want = _want;
auto connected = NumberOfConnectedRouters(); auto connected = num_router_connections();
if (connected >= want) if (connected >= want)
return; return;
_link_manager.connect_to_random(want);
_link_manager->connect_to_random(want);
} }
bool bool
Router::init_service_node() Router::init_service_node()
{ {
LogInfo("accepting transit traffic"); log::info(logcat, "Router accepting transit traffic...");
paths.AllowTransit(); paths.allow_transit();
_contacts->set_transit_allowed(true); _exit_context.add_exit_endpoint("default", _config->network, _config->dns);
_exit_context.AddExitEndpoint("default", _config->network, _config->dns);
return true; return true;
} }
@ -1338,9 +1372,9 @@ namespace llarp
} }
oxen::quic::Address oxen::quic::Address
Router::local_addr() const Router::listen_addr() const
{ {
return _local_addr; return _listen_addr;
} }
void void

@ -91,8 +91,8 @@ namespace llarp
consensus::reachability_testing router_testing; consensus::reachability_testing router_testing;
std::optional<SockAddr> _ourAddress; std::optional<oxen::quic::Address> _public_address; // public addr for relays
oxen::quic::Address _local_addr; oxen::quic::Address _listen_addr;
EventLoop_ptr _loop; EventLoop_ptr _loop;
std::shared_ptr<vpn::Platform> _vpn; std::shared_ptr<vpn::Platform> _vpn;
@ -122,7 +122,9 @@ namespace llarp
oxenmq::address rpc_addr; oxenmq::address rpc_addr;
Profiling _router_profiling; Profiling _router_profiling;
fs::path _profile_file; fs::path _profile_file;
LinkManager _link_manager{*this};
std::unique_ptr<LinkManager> _link_manager;
int client_router_connections;
// should we be sending padded messages every interval? // should we be sending padded messages every interval?
bool send_padding = false; bool send_padding = false;
@ -155,6 +157,12 @@ namespace llarp
std::chrono::system_clock::time_point next_bootstrap_attempt{last_rc_gossip}; std::chrono::system_clock::time_point next_bootstrap_attempt{last_rc_gossip};
public: public:
int
required_num_client_conns() const
{
return client_router_connections;
}
RouterID RouterID
local_rid() const local_rid() const
{ {
@ -176,10 +184,16 @@ namespace llarp
void void
connect_to(const RemoteRC& rc); connect_to(const RemoteRC& rc);
Contacts* const Contacts&
contacts() const contacts() const
{ {
return _contacts.get(); return *_contacts;
}
Contacts&
contacts()
{
return *_contacts;
} }
std::shared_ptr<Config> std::shared_ptr<Config>
@ -212,10 +226,16 @@ namespace llarp
LinkManager& LinkManager&
link_manager() link_manager()
{ {
return _link_manager; return *_link_manager;
}
const LinkManager&
link_manager() const
{
return *_link_manager;
} }
inline int int
outbound_udp_socket() const outbound_udp_socket() const
{ {
return _outbound_udp_socket; return _outbound_udp_socket;
@ -282,7 +302,7 @@ namespace llarp
} }
oxen::quic::Address oxen::quic::Address
local_addr() const; listen_addr() const;
util::StatusObject util::StatusObject
ExtractStatus() const; ExtractStatus() const;
@ -473,7 +493,7 @@ namespace llarp
std::string body, std::string body,
std::function<void(oxen::quic::message m)> func = nullptr); std::function<void(oxen::quic::message m)> func = nullptr);
bool IsBootstrapNode(RouterID) const; bool is_bootstrap_node(RouterID) const;
/// call internal router ticker /// call internal router ticker
void void
@ -490,11 +510,11 @@ namespace llarp
/// count the number of unique service nodes connected via pubkey /// count the number of unique service nodes connected via pubkey
size_t size_t
NumberOfConnectedRouters() const; num_router_connections() const;
/// count the number of unique clients connected by pubkey /// count the number of unique clients connected by pubkey
size_t size_t
NumberOfConnectedClients() const; num_client_connections() const;
bool bool
GetRandomConnectedRouter(RemoteRC& result) const; GetRandomConnectedRouter(RemoteRC& result) const;

@ -102,7 +102,7 @@ namespace llarp
{ {
util::StatusObject obj{ util::StatusObject obj{
{"lastUpdated", _timestamp.time_since_epoch().count()}, {"lastUpdated", _timestamp.time_since_epoch().count()},
{"publicRouter", is_public_router()}, {"publicRouter", is_public_addressable()},
{"identity", _router_id.ToString()}, {"identity", _router_id.ToString()},
{"address", _addr.to_string()}}; {"address", _addr.to_string()}};
@ -221,10 +221,11 @@ namespace llarp
} }
bool bool
RouterContact::is_public_router() const RouterContact::is_public_addressable() const
{ {
if (_router_version.empty()) if (_router_version.empty())
return false; return false;
return _addr.is_addressable(); return _addr.is_addressable();
} }

@ -176,7 +176,7 @@ namespace llarp
decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf); decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf);
bool bool
is_public_router() const; is_public_addressable() const;
/// does this RC expire soon? default delta is 1 minute /// does this RC expire soon? default delta is 1 minute
bool bool

@ -22,7 +22,8 @@ namespace llarp
{ {
_router_id = llarp::seckey_to_pubkey(_secret_key); _router_id = llarp::seckey_to_pubkey(_secret_key);
_addr = std::move(local); _addr = std::move(local);
_addr6.emplace(&_addr.in6()); if (_addr.is_ipv6())
_addr6.emplace(&_addr.in6());
resign(); resign();
} }
@ -123,8 +124,6 @@ namespace llarp
static_assert(llarp::LOKINET_VERSION.size() == 3); static_assert(llarp::LOKINET_VERSION.size() == 3);
btdp.append( btdp.append(
"v", std::string_view{reinterpret_cast<const char*>(llarp::LOKINET_VERSION.data()), 3}); "v", std::string_view{reinterpret_cast<const char*>(llarp::LOKINET_VERSION.data()), 3});
bt_sign(btdp);
} }
void void

@ -89,7 +89,7 @@ namespace llarp
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
log::error(logcat, "Failed to read or validate RC from {}: {}", fname, e.what()); log::warning(logcat, "Failed to read or validate RC from {}: {}", fname, e.what());
return false; return false;
} }

@ -76,7 +76,7 @@ namespace llarp::rpc
{ {
if (r.is_service_node()) if (r.is_service_node())
{ {
return r.exitContext().GetExitEndpoint(name); return r.exitContext().get_exit_endpoint(name);
} }
return r.hidden_service_context().GetEndpointByName(name); return r.hidden_service_context().GetEndpointByName(name);
@ -329,7 +329,7 @@ namespace llarp::rpc
} }
m_Router.loop()->call([&]() { m_Router.loop()->call([&]() {
auto endpoint = m_Router.exitContext().GetExitEndpoint("default"); auto endpoint = m_Router.exitContext().get_exit_endpoint("default");
if (endpoint == nullptr) if (endpoint == nullptr)
{ {

@ -516,7 +516,7 @@ namespace llarp::service
const auto& keyfile = _state->key_file; const auto& keyfile = _state->key_file;
if (!keyfile.empty()) if (!keyfile.empty())
{ {
_identity.EnsureKeys(keyfile, router()->key_manager()->needBackup()); _identity.EnsureKeys(keyfile, router()->key_manager()->needs_backup());
} }
else else
{ {
@ -1310,7 +1310,7 @@ namespace llarp::service
// TODO: if all requests fail, call callback with failure? // TODO: if all requests fail, call callback with failure?
for (const auto& path : paths) for (const auto& path : paths)
{ {
path->find_intro(location, false, 0, [this, hook, got_it](std::string resp) mutable { path->find_intro(location, false, 0, [hook, got_it, this](std::string resp) mutable {
// asking many, use only first successful // asking many, use only first successful
if (*got_it) if (*got_it)
return; return;
@ -1335,7 +1335,7 @@ namespace llarp::service
} }
service::EncryptedIntroSet enc{introset}; service::EncryptedIntroSet enc{introset};
router()->contacts()->services()->PutNode(std::move(enc)); router()->contacts().put_intro(std::move(enc));
// TODO: finish this // TODO: finish this
/* /*

@ -97,7 +97,7 @@ namespace llarp::service
if (exists and needBackup) if (exists and needBackup)
{ {
KeyManager::backupFileByMoving(fname); KeyManager::copy_backup_keyfile(fname);
exists = false; exists = false;
} }

Loading…
Cancel
Save