Message method implementation continued

- tons of surrounding stupid refactoring required
This commit is contained in:
dr7ana 2023-09-29 14:00:13 -07:00
parent ad007ff832
commit 1a9f977208
37 changed files with 839 additions and 572 deletions

View File

@ -149,19 +149,18 @@ add_library(lokinet-consensus
# lokinet-dht holds all logic related to interacting with and participating in the DHT hashring
add_library(lokinet-dht
STATIC
dht/dht.cpp
dht/explorenetworkjob.cpp
dht/localtaglookup.cpp
dht/localrouterlookup.cpp
dht/localserviceaddresslookup.cpp
dht/message.cpp
dht/messages/findintro.cpp
dht/messages/findrouter.cpp
dht/messages/gotintro.cpp
dht/messages/gotrouter.cpp
dht/messages/pubintro.cpp
dht/messages/findname.cpp
dht/messages/gotname.cpp
# dht/messages/findintro.cpp
# dht/messages/findrouter.cpp
# dht/messages/gotintro.cpp
# dht/messages/gotrouter.cpp
# dht/messages/pubintro.cpp
# dht/messages/findname.cpp
# dht/messages/gotname.cpp
dht/publishservicejob.cpp
dht/recursiverouterlookup.cpp
dht/serviceaddresslookup.cpp
@ -197,6 +196,7 @@ add_library(lokinet-layer-onion
add_library(lokinet-layer-link
STATIC
link/connection.cpp
link/contacts.cpp
link/link_manager.cpp
messages/link_intro.cpp
)
@ -220,7 +220,6 @@ add_library(lokinet-context
STATIC
context.cpp
link/link_manager.cpp
router/outbound_message_handler.cpp
router/rc_lookup_handler.cpp
router/rc_gossiper.cpp
router/router.cpp

View File

@ -3,8 +3,7 @@
#include "constants/evloop.hpp"
#include "config/config.hpp"
#include "crypto/crypto_libsodium.hpp"
#include "dht/context.hpp"
#include "crypto/crypto.hpp"
#include "ev/ev.hpp"
#include <memory>
#include "nodedb.hpp"
@ -75,7 +74,7 @@ namespace llarp
loop = EventLoop::create(jobQueueSize);
}
crypto = std::make_shared<sodium::CryptoLibSodium>();
crypto = std::make_shared<Crypto>();
cryptoManager = std::make_shared<CryptoManager>(crypto.get());
router = makeRouter(loop);

View File

@ -22,6 +22,14 @@ namespace llarp
return true;
}
PubKey
PubKey::from_string(const std::string& s)
{
PubKey p;
oxenc::from_hex(s.begin(), s.end(), p.begin());
return p;
}
std::string
PubKey::ToString() const
{

View File

@ -33,6 +33,9 @@ namespace llarp
bool
FromString(const std::string& str);
static PubKey
from_string(const std::string& s);
operator RouterID() const
{
return {as_array()};

View File

@ -1,6 +1,5 @@
#pragma once
#include "dht.h"
#include "key.hpp"
#include <llarp/messages/link_message.hpp>
#include <llarp/path/path_types.hpp>
@ -39,16 +38,6 @@ namespace llarp::dht
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) = 0;
// methods we do not want to inherit onwards from AbstractSerializable
void
bt_encode(oxenc::bt_list_producer&) const final
{
throw std::runtime_error{"Error: DHT messages should encode directly to a bt dict producer!"};
}
void
bt_encode(llarp_buffer&) const final
{
throw std::runtime_error{"Error: DHT messages should encode directly to a bt dict producer!"};
}
std::string
bt_encode() const final
{

105
llarp/link/contacts.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "contacts.hpp"
#include <llarp/messages/dht.hpp>
#include <llarp/router/router.hpp>
namespace llarp
{
Contacts::Contacts(const dht::Key_t& k, Router& r) : _local_key{k}, _router{r}
{
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);
}
std::optional<service::EncryptedIntroSet>
Contacts::get_introset_by_location(const dht::Key_t& key) const
{
auto& introsets = _introset_nodes->nodes;
if (auto itr = introsets.find(key); itr != introsets.end())
return itr->second.introset;
return std::nullopt;
}
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.IsExpired(now))
itr = nodes.erase(itr);
else
++itr;
}
}
if (_introset_nodes)
{
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
Contacts::extract_status() const
{
util::StatusObject obj{
{"nodes", _rc_nodes->ExtractStatus()},
{"services", _introset_nodes->ExtractStatus()},
{"local_key", _local_key.ToHex()}};
return obj;
}
bool
Contacts::lookup_router(
const RouterID& rid, std::function<void(const std::vector<RouterContact>&)> func)
{
dht::Key_t ask_peer;
if (not _rc_nodes->FindClosest(dht::Key_t{rid}, ask_peer))
return false;
_router.loop()->call([this, rid, func]() {
pending_lookups[rid] = [](const std::vector<RouterContact>&) {
// TODO: combine this concept with service::Endpoint introset lookups?
};
_router.send_control_message(
rid, "find_router", FindRouterMessage::serialize(rid, false, false, 0));
});
return true;
}
void
Contacts::put_rc_node_async(const dht::RCNode& val)
{
_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); });
}
} // namespace llarp

78
llarp/link/contacts.hpp Normal file
View File

@ -0,0 +1,78 @@
#pragma once
#include <llarp/dht/bucket.hpp>
#include <llarp/dht/node.hpp>
namespace llarp
{
struct Router;
/// This class mediates storage, retrieval, and functionality for the various types
/// of contact information that needs to be stored locally by the link manager and
/// router, like RouterContacts and introsets for example
struct Contacts
{
private:
// TODO: why was this a shared ptr in the original implementation? revisit this
std::shared_ptr<int> timer_keepalive;
const dht::Key_t& _local_key;
Router& _router;
std::atomic<bool> transit_allowed{false};
// holds router contacts
std::unique_ptr<dht::Bucket<dht::RCNode>> _rc_nodes;
// holds introsets for remote services
std::unique_ptr<dht::Bucket<dht::ISNode>> _introset_nodes;
public:
Contacts(const dht::Key_t& local, 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;
}
std::unordered_map<RouterID, std::function<void(const std::vector<RouterContact>&)>>
pending_lookups;
void
on_clean_contacts();
std::optional<service::EncryptedIntroSet>
get_introset_by_location(const dht::Key_t& key) const;
util::StatusObject
extract_status() const;
bool
lookup_router(const RouterID&, std::function<void(const std::vector<RouterContact>&)>);
void
put_rc_node_async(const dht::RCNode& val);
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>*
services() const
{
return _introset_nodes.get();
}
Router*
router() const
{
return &_router;
}
};
} // namespace llarp

View File

@ -1,4 +0,0 @@
#include "link_endpoints.hpp"
namespace llarp
{} // namespace llarp

View File

@ -1,4 +0,0 @@
#pragma once
namespace llarp
{} // namespace llarp

View File

@ -1,5 +1,6 @@
#include "link_manager.hpp"
#include "connection.hpp"
#include "contacts.hpp"
#include <llarp/router/router.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
@ -150,24 +151,27 @@ namespace llarp
- stream constructor callback
- will return a BTRequestStream on the first call to get_new_stream<BTRequestStream>
*/
return quic->endpoint(
auto ep = quic->endpoint(
router.public_ip(),
[this](oxen::quic::connection_interface& ci) { return on_conn_open(ci); },
[this](oxen::quic::connection_interface& ci, uint64_t ec) {
return on_conn_closed(ci, ec);
},
[this](oxen::quic::dgram_interface& di, bstring dgram) { recv_data_message(di, dgram); },
[this](oxen::quic::dgram_interface& di, bstring dgram) { recv_data_message(di, dgram); });
ep->listen(
tls_creds,
[&](oxen::quic::Connection& c,
oxen::quic::Endpoint& e,
std::optional<int64_t> id) -> std::shared_ptr<oxen::quic::Stream> {
if (id && id == 0)
{
auto s = std::make_shared<oxen::quic::BTRequestStream>();
auto s = std::make_shared<oxen::quic::BTRequestStream>(c, e);
register_commands(s);
return s;
}
return std::make_shared<oxen::quic::Stream>(c, e);
});
return ep;
}
LinkManager::LinkManager(Router& r)
@ -185,10 +189,37 @@ namespace llarp
std::string endpoint,
std::string body,
std::function<void(oxen::quic::message m)> func)
{
if (func)
return send_control_message_impl(
remote, std::move(endpoint), std::move(body), std::move(func));
if (auto itr = rpc_responses.find(endpoint); itr != rpc_responses.end())
return send_control_message_impl(
remote, std::move(endpoint), std::move(body), [&](oxen::quic::message m) {
return std::invoke(itr->second, this, std::move(m));
});
return send_control_message_impl(remote, std::move(endpoint), std::move(body));
}
bool
LinkManager::send_control_message_impl(
const RouterID& remote,
std::string endpoint,
std::string body,
std::function<void(oxen::quic::message m)> func)
{
if (is_stopping)
return false;
auto cb = [this, f = std::move(func), endpoint](oxen::quic::message m) {
f(m);
if (auto itr = rpc_responses.find(endpoint); itr != rpc_responses.end())
std::invoke(itr->second, this, std::move(m));
};
if (auto conn = ep.get_conn(remote); conn)
{
conn->control_stream->command(endpoint, body, std::move(func));
@ -290,7 +321,7 @@ namespace llarp
// TODO: confirm remote end is using the expected pubkey (RouterID).
// TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation)
if (auto rv = ep.establish_connection(remote_addr, rc, tls_creds); rv)
if (auto rv = ep.establish_connection(remote_addr, rc); rv)
{
log::info(quic_cat, "Connection to {} successfully established!", remote_addr);
return;
@ -493,14 +524,14 @@ namespace llarp
LinkManager::handle_find_name(oxen::quic::message m)
{
std::string name_hash;
uint64_t tx_id;
[[maybe_unused]] uint64_t tx_id;
try
{
oxenc::bt_dict_consumer btdp{m.body()};
safe_fetch_value(btdp, "H", name_hash);
safe_fetch_value(btdp, "T", tx_id);
name_hash = btdp.require<std::string>("H");
tx_id = btdp.require<uint64_t>("T");
}
catch (const std::exception& e)
{
@ -510,11 +541,10 @@ namespace llarp
router.rpc_client()->lookup_ons_hash(
name_hash, [this, msg = std::move(m)](std::optional<service::EncryptedName> maybe) mutable {
if (maybe.has_value())
msg.respond(serialize_response(true, {"NAME", maybe->ciphertext.c_str()}));
msg.respond(serialize_response(true, {{"NAME", maybe->ciphertext.c_str()}}));
else
msg.respond(serialize_response(false, {"STATUS", "NOT FOUND"}), true);
msg.respond(serialize_response(false, {{"STATUS", "NOT FOUND"}}), true);
});
}
@ -527,24 +557,21 @@ namespace llarp
void
LinkManager::handle_find_router(oxen::quic::message m)
{
ustring target_key;
uint64_t is_exploratory, is_iterative, tx_id;
std::string target_key;
uint64_t is_exploratory, is_iterative;
try
{
oxenc::bt_dict_consumer btdc{m.body()};
safe_fetch_value(btdc, "E", is_exploratory);
safe_fetch_value(btdc, "I", is_iterative);
safe_fetch_value(btdc, "K", target_key);
safe_fetch_value(btdc, "T", tx_id);
is_exploratory = btdc.require<uint64_t>("E");
is_iterative = btdc.require<uint64_t>("I");
target_key = btdc.require<std::string>("E");
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
@ -552,15 +579,82 @@ namespace llarp
// TODO: do we need a replacement for dht.pendingIntroSetLookups() etc here?
const auto target_addr = dht::Key_t{};
RouterID target_rid;
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_key = dht::Key_t{local_rid};
if (is_exploratory)
{
std::string neighbors{};
const auto closest_rcs =
router.node_db()->FindManyClosestTo(target_addr, RC_LOOKUP_STORAGE_REDUNDANCY);
for (const auto& rc : closest_rcs)
{
const auto& rid = rc.pubkey;
if (router.router_profiling().IsBadForConnect(rid) || target_rid == rid || local_rid == rid)
continue;
neighbors += oxenc::bt_serialize(rid.ToString());
}
m.respond(
serialize_response(
false, {{"STATUS", "RETRY EXPLORATORY"}, {"ROUTERS", neighbors.c_str()}}),
true);
}
else
{
const auto closest_rc = router.node_db()->FindClosestTo(target_addr);
const auto& closest_rid = closest_rc.pubkey;
const auto closest_key = dht::Key_t{closest_rid};
if (target_addr == closest_key)
{
if (closest_rc.ExpiresSoon(llarp::time_now_ms()))
{
send_control_message_impl(
target_rid, "find_router", m.body_str(), [this](oxen::quic::message m) {
return handle_find_router_response(std::move(m));
});
}
else
{
m.respond(serialize_response(true, {{"RC", closest_rc.ToString().c_str()}}));
}
}
else if (not is_iterative)
{
if ((closest_key ^ target_addr) < (local_key ^ target_addr))
{
send_control_message_impl(
closest_rc.pubkey, "find_router", m.body_str(), [this](oxen::quic::message m) {
return handle_find_router_response(std::move(m));
});
}
else
{
m.respond(serialize_response(false, {{"STATUS", "RETRY ITERATIVE"}}), true);
}
}
else
{
m.respond(
serialize_response(
false,
{{"STATUS", "RETRY NEW RECIPIENT"},
{"RECIPIENT", reinterpret_cast<const char*>(closest_rid.data())}}),
true);
}
}
}
void
LinkManager::handle_publish_intro(oxen::quic::message m)
{
std::string introset, derived_signing_key, sig;
std::string introset, derived_signing_key, payload, sig, nonce;
uint64_t is_relayed, relay_order, tx_id;
std::chrono::milliseconds signed_at;
@ -568,21 +662,23 @@ namespace llarp
{
oxenc::bt_dict_consumer btdc_a{m.body()};
safe_fetch_value(btdc_a, "I", introset);
safe_fetch_value(btdc_a, "O", relay_order);
safe_fetch_value(btdc_a, "R", is_relayed);
safe_fetch_value(btdc_a, "T", tx_id);
introset = btdc_a.require<std::string>("I");
relay_order = btdc_a.require<uint64_t>("O");
is_relayed = btdc_a.require<uint64_t>("R");
tx_id = btdc_a.require<uint64_t>("T");
oxenc::bt_dict_consumer btdc_b{introset};
oxenc::bt_dict_consumer btdc_b{introset.data()};
safe_fetch_value(btdc_b, "d", derived_signing_key);
safe_fetch_value(btdc_b, "s", signed_at);
safe_fetch_value(btdc_b, "z", sig);
derived_signing_key = btdc_b.require<std::string>("d");
nonce = btdc_b.require<std::string>("n");
signed_at = std::chrono::milliseconds{btdc_b.require<uint64_t>("s")};
payload = btdc_b.require<std::string>("x");
sig = btdc_b.require<std::string>("z");
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
@ -593,14 +689,14 @@ namespace llarp
if (not service::EncryptedIntroSet::verify(introset, derived_signing_key, sig))
{
log::error(link_cat, "Received PublishIntroMessage with invalid introset: {}", introset);
m.respond(serialize_response(false, {"STATUS", "INVALID INTROSET"}), true);
m.respond(serialize_response(false, {{"STATUS", "INVALID INTROSET"}}), true);
return;
}
if (now + service::MAX_INTROSET_TIME_DELTA > signed_at + path::DEFAULT_LIFETIME)
{
log::error(link_cat, "Received PublishIntroMessage with expired introset: {}", introset);
m.respond(serialize_response(false, {"STATUS", "EXPIRED INTROSET"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXPIRED INTROSET"}}), true);
return;
}
@ -610,17 +706,19 @@ namespace llarp
{
log::error(
link_cat, "Received PublishIntroMessage but only know {} nodes", closest_rcs.size());
m.respond(serialize_response(false, {"STATUS", "INSUFFICIENT NODES"}), true);
m.respond(serialize_response(false, {{"STATUS", "INSUFFICIENT NODES"}}), true);
return;
}
service::EncryptedIntroSet enc{derived_signing_key, signed_at, payload, nonce, sig};
if (is_relayed)
{
if (relay_order >= INTROSET_STORAGE_REDUNDANCY)
{
log::error(
link_cat, "Received PublishIntroMessage with invalide relay order: {}", relay_order);
m.respond(serialize_response(false, {"STATUS", "INVALID ORDER"}), true);
m.respond(serialize_response(false, {{"STATUS", "INVALID ORDER"}}), true);
return;
}
@ -636,8 +734,7 @@ namespace llarp
"Received PublishIntroMessage in which we are peer index {}.. storing introset",
relay_order);
// TODO: replace this concept
// dht->services()->PutNode(introset);
router.contacts()->services()->PutNode(dht::ISNode{std::move(enc)});
m.respond(serialize_response(true));
}
else
@ -645,7 +742,7 @@ namespace llarp
log::info(
link_cat, "Received PublishIntroMessage; propagating to peer index {}", relay_order);
send_control_message(
send_control_message_impl(
peer_key, "publish_intro", m.body_str(), [this](oxen::quic::message m) {
return handle_publish_intro_response(std::move(m));
});
@ -669,8 +766,8 @@ namespace llarp
if (rc_index >= 0)
{
log::info(link_cat, "Received PublishIntroMessage for {} (TXID: {}); we are candidate {}");
// TODO: replace this concept
// dht->services()->PutNode(introset);
router.contacts()->services()->PutNode(dht::ISNode{std::move(enc)});
m.respond(serialize_response(true));
}
else
@ -690,17 +787,16 @@ namespace llarp
{
oxenc::bt_dict_consumer btdc{m.body()};
safe_fetch_value(btdc, "N", tag_name);
safe_fetch_value(btdc, "O", relay_order);
safe_fetch_value(btdc, "R", is_relayed);
safe_fetch_value(btdc, "S", location);
safe_fetch_value(btdc, "T", tx_id);
safe_fetch_value(btdc, "N", tag_name);
tag_name = btdc.require<std::string>("N");
relay_order = btdc.require<uint64_t>("O");
is_relayed = btdc.require<uint64_t>("R");
location = btdc.require<std::string>("S");
tx_id = btdc.require<uint64_t>("T");
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
@ -714,7 +810,7 @@ namespace llarp
{
log::warning(
link_cat, "Received FindIntroMessage with invalid relay order: {}", relay_order);
m.respond(serialize_response(false, {"STATUS", "INVALID ORDER"}), true);
m.respond(serialize_response(false, {{"STATUS", "INVALID ORDER"}}), true);
return;
}
@ -724,7 +820,7 @@ namespace llarp
{
log::error(
link_cat, "Received FindIntroMessage but only know {} nodes", closest_rcs.size());
m.respond(serialize_response(false, {"STATUS", "INSUFFICIENT NODES"}), true);
m.respond(serialize_response(false, {{"STATUS", "INSUFFICIENT NODES"}}), true);
return;
}
@ -733,15 +829,16 @@ namespace llarp
const auto& peer_rc = closest_rcs[relay_order];
const auto& peer_key = peer_rc.pubkey;
send_control_message(peer_key, "find_intro", m.body_str(), [this](oxen::quic::message m) {
return handle_find_intro_response(std::move(m));
});
send_control_message_impl(
peer_key, "find_intro", m.body_str(), [this](oxen::quic::message m) {
return handle_find_intro_response(std::move(m));
});
return;
}
// TODO: replace this concept and add it to the response
// const auto maybe = dht.GetIntroSetByLocation(location);
m.respond(serialize_response(true, {"INTROSET", ""}));
m.respond(serialize_response(true, {{"INTROSET", ""}}));
}
void
@ -754,7 +851,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -769,7 +866,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -784,7 +881,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -792,16 +889,30 @@ namespace llarp
void
LinkManager::handle_obtain_exit(oxen::quic::message m)
{
// TODO: implement transit_hop things like nextseqno(), info.rxID, etc
std::string payload{m.body_str()}, pubkey;
[[maybe_unused]] uint64_t flag, tx_id, seq_no;
try
{
oxenc::bt_dict_consumer btdc{m.body()};
oxenc::bt_dict_consumer btdc{payload};
flag = btdc.require<uint64_t>("E");
pubkey = btdc.require<std::string>("I");
seq_no = btdc.require<uint64_t>("S");
tx_id = btdc.require<uint64_t>("T");
}
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
RouterID target;
target.FromString(pubkey);
// auto handler = router.path_context().GetByDownstream(target, tx_id);
}
void
@ -814,7 +925,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -829,7 +940,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -844,7 +955,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -859,7 +970,7 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
}
@ -874,8 +985,10 @@ namespace llarp
catch (const std::exception& e)
{
log::warning(link_cat, "Exception: {}", e.what());
m.respond(serialize_response(false, {"STATUS", "EXCEPTION"}), true);
m.respond(serialize_response(false, {{"STATUS", "EXCEPTION"}}), true);
return;
}
// check if we have any pending intro lookups in contacts
}
} // namespace llarp

View File

@ -1,7 +1,6 @@
#pragma once
#include "connection.hpp"
#include "link_endpoints.hpp"
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/router_contact.hpp>
@ -140,7 +139,6 @@ namespace llarp
public:
explicit LinkManager(Router& r);
// set is_request to true for RPC requests, false for RPC commands
bool
send_control_message(
const RouterID& remote,
@ -152,6 +150,13 @@ namespace llarp
send_data_message(const RouterID& remote, std::string data);
private:
bool
send_control_message_impl(
const RouterID& remote,
std::string endpoint,
std::string body,
std::function<void(oxen::quic::message)> = nullptr);
friend struct link::Endpoint;
std::atomic<bool> is_stopping;
@ -302,34 +307,20 @@ namespace llarp
{"obtain_exit", &LinkManager::handle_obtain_exit},
{"close_exit", &LinkManager::handle_close_exit}};
std::unordered_map<std::string, void (LinkManager::*)(oxen::quic::message)> rpc_responses = {
{"find_name", &LinkManager::handle_find_name_response},
{"find_router", &LinkManager::handle_find_router_response},
{"publish_intro", &LinkManager::handle_publish_intro_response},
{"find_intro", &LinkManager::handle_find_intro_response}};
// response handling functions
void handle_publish_intro_response(oxen::quic::message);
void handle_find_name_response(oxen::quic::message); // not used?
void handle_find_name_response(oxen::quic::message); // not used?
void handle_find_router_response(oxen::quic::message);
void handle_find_intro_response(oxen::quic::message);
std::string
serialize_response(bool success, oxenc::bt_dict supplement = {});
/** Searches the bt dict held by a dict consumer for a specific key `k`, setting
the value at `dest` and throwing if not found. This is equivalent to calling:
if (not bdca.skip_until(k))
throw std::invalid_argument{"..."};
dest = btdc.consume_integer<int_type>() OR btdc.consume_string();
*/
template <typename T>
void
safe_fetch_value(oxenc::bt_dict_consumer& btdc, const char* k, T& dest)
{
if (not btdc.skip_until(k))
throw std::invalid_argument{""};
if constexpr (std::is_integral_v<T>)
dest = btdc.consume_integer<T>();
else
dest = btdc.consume_string();
}
};
namespace link
@ -346,11 +337,11 @@ namespace llarp
// emplace immediately for connection open callback to find scid
connid_map.emplace(conn_interface->scid(), rc.pubkey);
auto [itr, b] = conns.emplace(rc.pubkey);
auto [itr, b] = conns.emplace(rc.pubkey, nullptr);
auto control_stream =
conn_interface->template get_new_stream<oxen::quic::BTRequestStream>();
itr->second = std::make_shared<link::Connection>(conn_interface, rc, control_stream);
itr->second = std::make_shared<link::Connection>(conn_interface, control_stream, rc);
return true;
}

View File

@ -18,11 +18,7 @@ namespace llarp
virtual std::string
bt_encode() const = 0;
virtual void
bt_encode(llarp_buffer& b) const = 0;
virtual void
bt_encode(oxenc::bt_dict_producer& btdp) const = 0;
virtual void
bt_encode(oxenc::bt_list_producer& btlp) const = 0;
};
struct AbstractMessageHandler

72
llarp/messages/dht.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include "common.hpp"
#include <llarp/dht/key.hpp>
#include <llarp/router_id.hpp>
#include <llarp/util/bencode.hpp>
#include <llarp/path/path_types.hpp>
#include <vector>
namespace llarp
{
struct DHTMessage : public AbstractSerializable
{};
struct FindRouterMessage : public DHTMessage
{
private:
RouterID target;
bool is_iterative{false};
bool is_exploratory{false};
uint64_t tx_id{0};
public:
explicit FindRouterMessage(const RouterID& rid, bool is_itr, bool is_exp, uint64_t tx)
: target{rid}, is_iterative{is_itr}, is_exploratory{is_exp}, tx_id{tx}
{}
std::string
bt_encode() const override
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("A", "R");
btdp.append("E", is_exploratory ? 1 : 0);
btdp.append("I", is_iterative ? 1 : 0);
btdp.append("K", target.ToView());
btdp.append("T", tx_id);
}
catch (...)
{
log::error(link_cat, "Error: FindRouterMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
static std::string
serialize(const RouterID& rid, bool is_itr, bool is_exp, uint64_t tx)
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("A", "R");
btdp.append("E", is_exp ? 1 : 0);
btdp.append("I", is_itr ? 1 : 0);
btdp.append("K", rid.ToView());
btdp.append("T", tx);
}
catch (...)
{
log::error(link_cat, "Error: FindRouterMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
};
} // namespace llarp

View File

@ -95,7 +95,8 @@ namespace llarp
{
if (!verify())
return false;
return conn->GotLIM(this);
return true;
// return conn->GotLIM(this);
}
void

View File

@ -54,22 +54,11 @@ namespace llarp
// methods we do not want to inherit onwards from AbstractSerializable
void
bt_encode(llarp_buffer&) const final
{
throw std::runtime_error{"Error: Link messages should not encode directly to a buffer!"};
}
void
bt_encode(oxenc::bt_dict_producer&) const final
{
throw std::runtime_error{
"Error: Link messages should not encode directly to a bt list producer!"};
}
void
bt_encode(oxenc::bt_list_producer&) const final
{
throw std::runtime_error{
"Error: Link messages should not encode directly to a bt list producer!"};
}
};
struct AbstractDataMessage : public AbstractLinkMessage

View File

@ -193,16 +193,16 @@ namespace llarp
// the actual hop
std::shared_ptr<Hop> hop;
const std::optional<IpAddress> fromAddr;
oxen::quic::Address from_addr;
LRCMFrameDecrypt(Context* ctx, Decrypter_ptr dec, const LR_CommitMessage* commit)
: decrypter(std::move(dec))
, frames(commit->frames)
, context(ctx)
, hop(std::make_shared<Hop>())
, fromAddr(
commit->conn->remote_rc.IsPublicRouter() ? std::optional<oxen::quic::Address>{}
: commit->conn->remote_rc.addr)
, from_addr{
commit->conn->remote_rc.IsPublicRouter() ? oxen::quic::Address{}
: commit->conn->remote_rc.addr}
{
hop->info.downstream = commit->conn->remote_rc.pubkey;
}
@ -268,14 +268,14 @@ namespace llarp
return;
}
if (self->fromAddr)
if (self->from_addr.is_addressable())
{
// only do ip limiting from non service nodes
#ifndef LOKINET_HIVE
if (self->context->CheckPathLimitHitByIP(*self->fromAddr))
if (self->context->CheckPathLimitHitByIP(self->from_addr.to_string()))
{
// we hit a limit so tell it to slow tf down
llarp::LogError("client path build hit limit ", *self->fromAddr);
llarp::LogError("client path build hit limit ", self->from_addr);
OnForwardLRCMResult(
self->context->router(),
self->hop,
@ -413,7 +413,7 @@ namespace llarp
return;
}
// generate hash of hop key for nonce mutation
crypto->shorthash(self->hop->nonceXOR, llarp_buffer_t(self->hop->pathKey));
crypto->shorthash(self->hop->nonceXOR, self->hop->pathKey.data(), self->hop->pathKey.size());
if (self->record.work && self->record.work->IsValid(now))
{
llarp::LogDebug(

View File

@ -249,8 +249,10 @@ namespace llarp
// send the status message to previous hop
// if it fails we are hitting a failure case we can't cope with so ... drop.
if (not router->SendToOrQueue(nextHop, *msg, resultCallback))
resultCallback(SendStatus::Congestion);
// TODO: replace with new message serialization
// if (not router->SendToOrQueue(nextHop, *msg, resultCallback))
// resultCallback(SendStatus::Congestion);
// trigger idempotent pump to make sure stuff gets sent
router->TriggerPump();

View File

@ -78,11 +78,6 @@ namespace llarp
fromString(addr, false);
}
SockAddr::SockAddr(const AddressInfo& info) : SockAddr{info.ip}
{
setPort(huint16_t{info.port});
}
SockAddr::SockAddr(const SockAddr& other)
{
*this = other;

View File

@ -17,8 +17,6 @@
namespace llarp
{
struct AddressInfo;
/// A simple SockAddr wrapper which provides a sockaddr_in (IPv4). Memory management is handled
/// in constructor and destructor (if needed) and copying is disabled.
struct SockAddr
@ -39,8 +37,6 @@ namespace llarp
SockAddr(std::string_view addr);
SockAddr(std::string_view addr, huint16_t port); // port is in native (host) order
SockAddr(const AddressInfo&);
SockAddr(const SockAddr&);
SockAddr&
operator=(const SockAddr&);

View File

@ -10,7 +10,7 @@ namespace llarp::path
static constexpr auto DefaultPathBuildLimit = 500ms;
PathContext::PathContext(Router* router)
: _router(router), m_AllowTransit(false), m_PathLimits(DefaultPathBuildLimit)
: _router(router), m_AllowTransit(false), path_limits(DefaultPathBuildLimit)
{}
void
@ -36,7 +36,22 @@ namespace llarp::path
remote.setPort(0);
// try inserting remote address by ip into decaying hash set
// if it cannot insert it has hit a limit
return not m_PathLimits.Insert(remote);
return not path_limits.Insert(remote);
#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
}
@ -85,7 +100,9 @@ namespace llarp::path
LogDebug("forwarding LRCM to ", nextHop);
return _router->SendToOrQueue(nextHop, msg, handler);
// TODO: replace with new message serialization for LRCM
// return _router->SendToOrQueue(nextHop, msg, handler);
return true;
}
template <
@ -340,7 +357,7 @@ namespace llarp::path
PathContext::ExpirePaths(llarp_time_t now)
{
// decay limits
m_PathLimits.Decay(now);
path_limits.Decay(now);
{
SyncTransitMap_t::Lock_t lock(m_TransitPaths.first);
@ -350,7 +367,8 @@ namespace llarp::path
{
if (itr->second->Expired(now))
{
_router->outboundMessageHandler().RemovePath(itr->first);
// TODO: this
// _router->outboundMessageHandler().RemovePath(itr->first);
itr = map.erase(itr);
}
else

View File

@ -53,6 +53,9 @@ namespace llarp
bool
CheckPathLimitHitByIP(const IpAddress& ip);
bool
CheckPathLimitHitByIP(const std::string& ip);
bool
AllowingTransit() const;
@ -185,7 +188,7 @@ namespace llarp
SyncTransitMap_t m_TransitPaths;
SyncOwnedPathsMap_t m_OurPaths;
bool m_AllowTransit;
util::DecayingHashSet<IpAddress> m_PathLimits;
util::DecayingHashSet<IpAddress> path_limits;
};
} // namespace path
} // namespace llarp

View File

@ -57,7 +57,7 @@ namespace llarp
return;
}
// generate nonceXOR valueself->hop->pathKey
crypto->shorthash(hop.nonceXOR, llarp_buffer_t(hop.shared));
crypto->shorthash(hop.nonceXOR, hop.shared.data(), hop.shared.size());
++idx;
bool isFarthestHop = idx == path->hops.size();

View File

@ -7,149 +7,145 @@
#include <atomic>
#include <set>
namespace llarp
namespace llarp::path
{
namespace path
// milliseconds waiting between builds on a path per router
static constexpr auto MIN_PATH_BUILD_INTERVAL = 500ms;
static constexpr auto PATH_BUILD_RATE = 100ms;
/// limiter for path builds
/// prevents overload and such
class BuildLimiter
{
// milliseconds waiting between builds on a path per router
static constexpr auto MIN_PATH_BUILD_INTERVAL = 500ms;
static constexpr auto PATH_BUILD_RATE = 100ms;
util::DecayingHashSet<RouterID> m_EdgeLimiter;
/// limiter for path builds
/// prevents overload and such
class BuildLimiter
public:
/// attempt a build
/// return true if we are allowed to continue
bool
Attempt(const RouterID& router);
/// decay limit entries
void
Decay(llarp_time_t now);
/// return true if this router is currently limited
bool
Limited(const RouterID& router) const;
};
struct Builder : public PathSet
{
private:
llarp_time_t m_LastWarn = 0s;
protected:
/// flag for PathSet::Stop()
std::atomic<bool> _run;
virtual bool
UrgentBuild(llarp_time_t now) const;
/// return true if we hit our soft limit for building paths too fast on a first hop
bool
BuildCooldownHit(RouterID edge) const;
private:
void
DoPathBuildBackoff();
public:
Router* const m_router;
SecretKey enckey;
size_t numHops;
llarp_time_t lastBuild = 0s;
llarp_time_t buildIntervalLimit = MIN_PATH_BUILD_INTERVAL;
/// construct
Builder(Router* p_router, size_t numDesiredPaths, size_t numHops);
virtual ~Builder() = default;
util::StatusObject
ExtractStatus() const;
bool
ShouldBuildMore(llarp_time_t now) const override;
/// should we bundle RCs in builds?
virtual bool
ShouldBundleRC() const = 0;
void
ResetInternalState() override;
/// return true if we hit our soft limit for building paths too fast
bool
BuildCooldownHit(llarp_time_t now) const;
/// get roles for this path builder
virtual PathRole
GetRoles() const
{
util::DecayingHashSet<RouterID> m_EdgeLimiter;
return ePathRoleAny;
}
public:
/// attempt a build
/// return true if we are allowed to continue
bool
Attempt(const RouterID& router);
/// decay limit entries
void
Decay(llarp_time_t now);
/// return true if this router is currently limited
bool
Limited(const RouterID& router) const;
};
struct Builder : public PathSet
BuildStats
CurrentBuildStats() const
{
private:
llarp_time_t m_LastWarn = 0s;
return m_BuildStats;
}
protected:
/// flag for PathSet::Stop()
std::atomic<bool> _run;
bool
Stop() override;
virtual bool
UrgentBuild(llarp_time_t now) const;
bool
IsStopped() const override;
/// return true if we hit our soft limit for building paths too fast on a first hop
bool
BuildCooldownHit(RouterID edge) const;
bool
ShouldRemove() const override;
private:
void
DoPathBuildBackoff();
llarp_time_t
Now() const override;
public:
Router* const m_router;
SecretKey enckey;
size_t numHops;
llarp_time_t lastBuild = 0s;
llarp_time_t buildIntervalLimit = MIN_PATH_BUILD_INTERVAL;
void
Tick(llarp_time_t now) override;
/// construct
Builder(Router* p_router, size_t numDesiredPaths, size_t numHops);
void
BuildOne(PathRole roles = ePathRoleAny) override;
virtual ~Builder() = default;
bool
BuildOneAlignedTo(const RouterID endpoint) override;
util::StatusObject
ExtractStatus() const;
std::optional<std::vector<RouterContact>>
GetHopsAlignedToForBuild(RouterID endpoint, const std::set<RouterID>& exclude = {});
bool
ShouldBuildMore(llarp_time_t now) const override;
void
Build(std::vector<RouterContact> hops, PathRole roles = ePathRoleAny) override;
/// should we bundle RCs in builds?
virtual bool
ShouldBundleRC() const = 0;
/// pick a first hop
std::optional<RouterContact>
SelectFirstHop(const std::set<RouterID>& exclude = {}) const;
void
ResetInternalState() override;
std::optional<std::vector<RouterContact>>
GetHopsForBuild() override;
/// return true if we hit our soft limit for building paths too fast
bool
BuildCooldownHit(llarp_time_t now) const;
void
ManualRebuild(size_t N, PathRole roles = ePathRoleAny);
/// get roles for this path builder
virtual PathRole
GetRoles() const
{
return ePathRoleAny;
}
const SecretKey&
GetTunnelEncryptionSecretKey() const;
BuildStats
CurrentBuildStats() const
{
return m_BuildStats;
}
void
HandlePathBuilt(Path_ptr p) override;
bool
Stop() override;
void
HandlePathBuildTimeout(Path_ptr p) override;
bool
IsStopped() const override;
void
HandlePathBuildFailedAt(Path_ptr p, RouterID hop) override;
};
bool
ShouldRemove() const override;
using Builder_ptr = std::shared_ptr<Builder>;
llarp_time_t
Now() const override;
virtual void
Tick(llarp_time_t now) override;
void
BuildOne(PathRole roles = ePathRoleAny) override;
bool
BuildOneAlignedTo(const RouterID endpoint) override;
std::optional<std::vector<RouterContact>>
GetHopsAlignedToForBuild(RouterID endpoint, const std::set<RouterID>& exclude = {});
void
Build(std::vector<RouterContact> hops, PathRole roles = ePathRoleAny) override;
/// pick a first hop
std::optional<RouterContact>
SelectFirstHop(const std::set<RouterID>& exclude = {}) const;
virtual std::optional<std::vector<RouterContact>>
GetHopsForBuild() override;
void
ManualRebuild(size_t N, PathRole roles = ePathRoleAny);
virtual const SecretKey&
GetTunnelEncryptionSecretKey() const;
virtual void
HandlePathBuilt(Path_ptr p) override;
virtual void
HandlePathBuildTimeout(Path_ptr p) override;
virtual void
HandlePathBuildFailedAt(Path_ptr p, RouterID hop) override;
};
using Builder_ptr = std::shared_ptr<Builder>;
} // namespace path
} // namespace llarp
} // namespace llarp::path

View File

@ -92,7 +92,7 @@ namespace llarp::path
}
void
PathSet::ExpirePaths(llarp_time_t now, Router* router)
PathSet::ExpirePaths(llarp_time_t now, [[maybe_unused]] Router* router)
{
Lock_t l(m_PathsMutex);
if (m_Paths.size() == 0)
@ -102,10 +102,11 @@ namespace llarp::path
{
if (itr->second->Expired(now))
{
// TODO: this
PathID_t txid = itr->second->TXID();
router->outboundMessageHandler().RemovePath(std::move(txid));
// router->outboundMessageHandler().RemovePath(std::move(txid));
PathID_t rxid = itr->second->RXID();
router->outboundMessageHandler().RemovePath(std::move(rxid));
// router->outboundMessageHandler().RemovePath(std::move(rxid));
itr = m_Paths.erase(itr);
}
else

View File

@ -29,19 +29,11 @@ namespace llarp
return false;
ShortHash digest;
std::array<byte_t, MaxSize> tmp;
llarp_buffer_t buf(tmp);
auto buf = bt_encode();
auto bte = bt_encode();
if (auto b = buf.write(bte.begin(), bte.end()); not b)
return false;
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// hash
if (!CryptoManager::instance()->shorthash(digest, buf))
if (!CryptoManager::instance()->shorthash(
digest, reinterpret_cast<uint8_t*>(buf.data()), buf.size()))
return false;
// check bytes required
uint32_t required = std::floor(std::log(extendedLifetime.count()));

View File

@ -1,6 +1,7 @@
#include <chrono>
#include "rc_lookup_handler.hpp"
#include <llarp/link/contacts.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/service/context.hpp>
@ -8,7 +9,6 @@
#include <llarp/util/types.hpp>
#include <llarp/util/thread/threading.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/dht/context.hpp>
#include "router.hpp"
#include <iterator>
@ -113,7 +113,7 @@ namespace llarp
LogWarn("cannot lookup ", router, " anonymously");
}
if (!dht->LookupRouter(router, fn))
if (not contacts->lookup_router(router, fn))
{
finalize_request(router, nullptr, RCRequestResult::RouterNotFound);
}
@ -195,11 +195,11 @@ namespace llarp
{
if (not is_session_allowed(rc.pubkey))
{
dht->DelRCNodeAsync(dht::Key_t{rc.pubkey});
contacts->delete_rc_node_async(dht::Key_t{rc.pubkey});
return false;
}
if (not rc.Verify(dht->Now()))
if (not rc.Verify(llarp::time_now_ms()))
{
LogWarn("RC for ", RouterID(rc.pubkey), " is invalid");
return false;
@ -210,7 +210,7 @@ namespace llarp
{
LogDebug("Adding or updating RC for ", RouterID(rc.pubkey), " to nodedb and dht.");
loop->call([rc, n = node_db] { n->PutIfNewer(rc); });
dht->PutRCNodeAsync(rc);
contacts->put_rc_node_async(rc);
}
return true;
@ -251,9 +251,9 @@ namespace llarp
work_func(func);
// update dht if required
if (dht->Nodes()->HasNode(dht::Key_t{newrc.pubkey}))
if (contacts->rc_nodes()->HasNode(dht::Key_t{newrc.pubkey}))
{
dht->Nodes()->PutNode(newrc);
contacts->rc_nodes()->PutNode(newrc);
}
// TODO: check for other places that need updating the RC
@ -295,7 +295,8 @@ namespace llarp
for (const auto& rc : bootstrap_rc_list)
{
LogInfo("Doing explore via bootstrap node: ", RouterID(rc.pubkey));
dht->ExploreNetworkVia(dht::Key_t{rc.pubkey});
// TODO: replace this concept
// dht->ExploreNetworkVia(dht::Key_t{rc.pubkey});
}
}
@ -332,7 +333,7 @@ namespace llarp
return;
}
// service nodes gossip, not explore
if (dht->GetRouter()->IsServiceNode())
if (contacts->router()->IsServiceNode())
return;
// explore via every connected peer
@ -356,7 +357,7 @@ namespace llarp
void
RCLookupHandler::init(
std::shared_ptr<dht::AbstractDHTMessageHandler> d,
std::shared_ptr<Contacts> c,
std::shared_ptr<NodeDB> nodedb,
EventLoop_ptr l,
worker_func dowork,
@ -367,7 +368,7 @@ namespace llarp
bool useWhitelist_arg,
bool isServiceNode_arg)
{
dht = d;
contacts = c;
node_db = std::move(nodedb);
loop = std::move(l);
work_func = std::move(dowork);

View File

@ -24,9 +24,9 @@ namespace llarp
namespace service
{
struct Context;
} // namespace service
struct Contacts;
struct LinkManager;
struct RouterContact;
@ -109,7 +109,7 @@ namespace llarp
void
init(
std::shared_ptr<dht::AbstractDHTMessageHandler> dht,
std::shared_ptr<Contacts> contacts,
std::shared_ptr<NodeDB> nodedb,
std::shared_ptr<EventLoop> loop,
worker_func dowork,
@ -143,7 +143,7 @@ namespace llarp
mutable util::Mutex _mutex; // protects pendingCallbacks, whitelistRouters
std::shared_ptr<dht::AbstractDHTMessageHandler> dht = nullptr;
std::shared_ptr<Contacts> contacts = nullptr;
std::shared_ptr<NodeDB> node_db;
std::shared_ptr<EventLoop> loop;
worker_func work_func = nullptr;

View File

@ -5,10 +5,9 @@
#include <llarp/constants/proto.hpp>
#include <llarp/constants/files.hpp>
#include <llarp/constants/time.hpp>
#include <llarp/crypto/crypto_libsodium.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/dht/context.hpp>
#include <llarp/dht/node.hpp>
#include <llarp/link/contacts.hpp>
#include <llarp/messages/link_message.hpp>
#include <llarp/net/net.hpp>
#include <stdexcept>
@ -46,16 +45,16 @@ 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)}
: _route_poker{std::make_shared<RoutePoker>(*this)}
, _lmq{std::make_shared<oxenmq::OxenMQ>()}
, _loop{std::move(loop)}
, _vpn{std::move(vpnPlatform)}
, paths{this}
, _exit_context{this}
, _dht{dht::make_handler()}
, _disk_thread{_lmq->add_tagged_thread("disk")}
, _rpc_server{nullptr}
, _randomStartDelay{platform::is_simulation ? std::chrono::milliseconds{(llarp::randint() % 1250) + 2000} : 0s}
, _link_manager{*this}
, _hidden_service_context{this}
{
_key_manager = std::make_shared<KeyManager>();
@ -70,7 +69,7 @@ namespace llarp
Router::~Router()
{
_dht.reset();
_contacts.reset();
}
// TODO: investigate changes needed for libquic integration
@ -97,7 +96,7 @@ namespace llarp
return util::StatusObject{
{"running", true},
{"numNodesKnown", _node_db->NumLoaded()},
{"dht", _dht->ExtractStatus()},
{"contacts", _contacts->extract_status()},
{"services", _hidden_service_context.ExtractStatus()},
{"exit", _exit_context.ExtractStatus()},
{"links", _link_manager.extract_status()},
@ -238,9 +237,6 @@ namespace llarp
void
Router::GossipRCIfNeeded(const RouterContact rc)
{
if (disableGossipingRC_TestingOnly())
return;
/// if we are not a service node forget about gossip
if (not IsServiceNode())
return;
@ -272,23 +268,21 @@ namespace llarp
loop_wakeup->Trigger();
}
bool
Router::SendToOrQueue(
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler handler)
{
return _outboundMessageHandler.QueueMessage(remote, msg, handler);
}
bool
Router::send_data_message(const RouterID& remote, const AbstractDataMessage& msg)
{
return _link_manager.send_or_queue_data(remote, msg.bt_encode());
return _link_manager.send_data_message(remote, msg.bt_encode());
}
bool
Router::send_control_message(const RouterID& remote, const AbstractLinkMessage& msg)
Router::send_control_message(
const RouterID& remote,
std::string ep,
std::string body,
std::function<void(oxen::quic::message m)> func)
{
return _link_manager.send_or_queue_data(remote, msg.bt_encode());
return _link_manager.send_control_message(
remote, std::move(ep), std::move(body), std::move(func));
}
void
@ -754,10 +748,9 @@ namespace llarp
LogInfo("Loaded ", bootstrap_rc_list.size(), " bootstrap routers");
// Init components after relevant config settings loaded
_outboundMessageHandler.Init(this);
_link_manager.init(&_rc_lookup_handler);
_rc_lookup_handler.init(
_dht,
_contacts,
_node_db,
_loop,
util::memFn(&Router::queue_work, this),
@ -832,7 +825,7 @@ namespace llarp
void
Router::report_stats()
{
const auto now = now();
const auto now = llarp::time_now_ms();
LogInfo(node_db()->NumLoaded(), " RCs loaded");
LogInfo(bootstrap_rc_list.size(), " bootstrap peers");
LogInfo(NumberOfConnectedRouters(), " router connections");
@ -905,7 +898,7 @@ namespace llarp
if (is_stopping)
return;
// LogDebug("tick router");
const auto now = now();
const auto now = llarp::time_now_ms();
if (const auto delta = now - _last_tick; _last_tick != 0s and delta > TimeskipDetectedDuration)
{
// we detected a time skip into the futre, thaw the network
@ -1111,7 +1104,7 @@ namespace llarp
for_each_connection(
[&peer_keys](link::Connection& conn) { peer_keys.emplace(conn.remote_rc.pubkey); });
dht()->Nodes()->RemoveIf(
_contacts->rc_nodes()->RemoveIf(
[&peer_keys](const dht::Key_t& k) -> bool { return peer_keys.count(k) == 0; });
paths.ExpirePaths(now);
@ -1120,12 +1113,6 @@ namespace llarp
_last_tick = llarp::time_now_ms();
}
bool
Router::Sign(Signature& sig, const llarp_buffer_t& buf) const
{
return CryptoManager::instance()->sign(sig, identity(), buf);
}
void
Router::modify_rc(std::function<std::optional<RouterContact>(RouterContact)> modify)
{
@ -1271,12 +1258,12 @@ namespace llarp
_node_db->LoadFromDisk();
}
_dht->Init(llarp::dht::Key_t(pubkey()), this);
_contacts = std::make_shared<Contacts>(llarp::dht::Key_t(pubkey()), *this);
for (const auto& rc : bootstrap_rc_list)
{
node_db()->Put(rc);
_dht->Nodes()->PutNode(rc);
_contacts->rc_nodes()->PutNode(rc);
LogInfo("added bootstrap node ", RouterID{rc.pubkey});
}
@ -1494,7 +1481,7 @@ namespace llarp
{
LogInfo("accepting transit traffic");
paths.AllowTransit();
_dht->AllowTransit() = true;
_contacts->set_transit_allowed(true);
_exit_context.AddExitEndpoint("default", _config->network, _config->dns);
return true;
}
@ -1549,63 +1536,63 @@ namespace llarp
void
Router::InitInboundLinks()
{
auto addrs = _config->links.InboundListenAddrs;
if (is_service_node and addrs.empty())
{
LogInfo("Inferring Public Address");
// auto addrs = _config->links.InboundListenAddrs;
// if (is_service_node and addrs.empty())
// {
// LogInfo("Inferring Public Address");
auto maybe_port = _config->links.PublicPort;
if (_config->router.PublicPort and not maybe_port)
maybe_port = _config->router.PublicPort;
if (not maybe_port)
maybe_port = net::port_t::from_host(constants::DefaultInboundIWPPort);
// auto maybe_port = _config->links.PublicPort;
// if (_config->router.PublicPort and not maybe_port)
// maybe_port = _config->router.PublicPort;
// if (not maybe_port)
// maybe_port = net::port_t::from_host(constants::DefaultInboundIWPPort);
if (auto maybe_addr = net().MaybeInferPublicAddr(*maybe_port))
{
LogInfo("Public Address looks to be ", *maybe_addr);
addrs.emplace_back(std::move(*maybe_addr));
}
}
if (is_service_node and addrs.empty())
throw std::runtime_error{"we are a service node and we have no inbound links configured"};
// if (auto maybe_addr = net().MaybeInferPublicAddr(*maybe_port))
// {
// LogInfo("Public Address looks to be ", *maybe_addr);
// addrs.emplace_back(std::move(*maybe_addr));
// }
// }
// if (is_service_node and addrs.empty())
// throw std::runtime_error{"we are a service node and we have no inbound links configured"};
// create inbound links, if we are a service node
for (auto bind_addr : addrs)
{
if (bind_addr.getPort() == 0)
throw std::invalid_argument{"inbound link cannot use port 0"};
// // create inbound links, if we are a service node
// for (auto bind_addr : addrs)
// {
// if (bind_addr.getPort() == 0)
// throw std::invalid_argument{"inbound link cannot use port 0"};
if (net().IsWildcardAddress(bind_addr.getIP()))
{
if (auto maybe_ip = public_ip())
bind_addr.setIP(*maybe_ip);
else
throw std::runtime_error{"no public ip provided for inbound socket"};
}
// if (net().IsWildcardAddress(bind_addr.getIP()))
// {
// if (auto maybe_ip = public_ip())
// bind_addr.setIP(public_ip().host());
// else
// throw std::runtime_error{"no public ip provided for inbound socket"};
// }
AddressInfo ai;
ai.fromSockAddr(bind_addr);
// AddressInfo ai;
// ai.fromSockAddr(bind_addr);
_link_manager.connect_to({ai.IPString(), ai.port}, true);
// _link_manager.connect_to({ai.IPString(), ai.port}, true);
ai.pubkey = llarp::seckey_topublic(_identity);
ai.dialect = "quicinet"; // FIXME: constant, also better name?
ai.rank = 2; // FIXME: hardcoded from the beginning...keep?
AddAddressToRC(ai);
}
// ai.pubkey = llarp::seckey_topublic(_identity);
// ai.dialect = "quicinet"; // FIXME: constant, also better name?
// ai.rank = 2; // FIXME: hardcoded from the beginning...keep?
// AddAddressToRC(ai);
// }
}
void
Router::InitOutboundLinks()
{
auto addrs = config()->links.OutboundLinks;
if (addrs.empty())
addrs.emplace_back(net().Wildcard());
// auto addrs = config()->links.OutboundLinks;
// if (addrs.empty())
// addrs.emplace_back(net().Wildcard());
for (auto& bind_addr : addrs)
{
_link_manager.connect_to({bind_addr.ToString()}, false);
}
// for (auto& bind_addr : addrs)
// {
// _link_manager.connect_to({bind_addr.ToString()}, false);
// }
}
const llarp::net::Platform&

View File

@ -64,6 +64,10 @@ namespace llarp
static constexpr size_t INTROSET_STORAGE_REDUNDANCY =
(INTROSET_RELAY_REDUNDANCY * INTROSET_REQS_PER_RELAY);
static constexpr size_t RC_LOOKUP_STORAGE_REDUNDANCY{4};
struct Contacts;
class RouteManager final /* : public Router */
{
public:
@ -118,7 +122,8 @@ namespace llarp
exit::Context _exit_context;
SecretKey _identity;
SecretKey _encryption;
std::shared_ptr<dht::AbstractDHTMessageHandler> _dht;
std::shared_ptr<dht::AbstractDHTMessageHandler> _dh_t;
std::shared_ptr<Contacts> _contacts;
std::shared_ptr<NodeDB> _node_db;
llarp_time_t _started_at;
const oxenmq::TaggedThreadID _disk_thread;
@ -140,7 +145,6 @@ namespace llarp
oxenmq::address rpc_addr;
Profiling _router_profiling;
fs::path _profile_file;
OutboundMessageHandler _outboundMessageHandler;
LinkManager _link_manager{*this};
RCLookupHandler _rc_lookup_handler;
RCGossiper _rcGossiper;
@ -178,16 +182,16 @@ namespace llarp
void
handle_router_event(std::unique_ptr<tooling::RouterEvent> event) const;
virtual bool
disableGossipingRC_TestingOnly()
{
return false;
};
public:
void
for_each_connection(std::function<void(link::Connection&)> func);
Contacts*
contacts() const
{
return _contacts.get();
}
std::shared_ptr<Config>
config() const
{
@ -215,22 +219,6 @@ namespace llarp
return _rpc_client;
}
std::shared_ptr<dht::AbstractDHTMessageHandler>
dht() const
{
return _dht;
}
/** TOFIX: this
- refactor path types (path_context, pathset) to use unified ID type, not PathID_t
- refactor all callers to use new implementation of remove_path
*/
OutboundMessageHandler&
outboundMessageHandler()
{
return _outboundMessageHandler;
}
LinkManager&
link_manager()
{
@ -376,9 +364,6 @@ namespace llarp
llarp_time_t
Uptime() const;
bool
Sign(Signature& sig, const llarp_buffer_t& buf) const;
service::Context&
hidden_service_context()
{
@ -530,7 +515,11 @@ namespace llarp
send_data_message(const RouterID& remote, const AbstractDataMessage& msg);
bool
send_control_message(const RouterID& remote, const AbstractLinkMessage& msg);
send_control_message(
const RouterID& remote,
std::string endpoint,
std::string body,
std::function<void(oxen::quic::message m)> func = nullptr);
bool IsBootstrapNode(RouterID) const;

View File

@ -136,95 +136,33 @@ namespace llarp
return netID == NetID::DefaultValue();
}
bool
RouterContact::BEncodeSignedSection(llarp_buffer_t* buf) const
std::string
RouterContact::bencode_signed_section() const
{
/* write dict begin */
if (!bencode_start_dict(buf))
return false;
oxenc::bt_dict_producer btdp;
/* write ai if they exist */
if (!bencode_write_bytestring(buf, "a", 1))
return false;
if (!BEncodeWriteList(addrs.begin(), addrs.end(), buf))
return false;
btdp.append("a", addr.to_string());
btdp.append("i", netID.ToView());
btdp.append("k", pubkey.bt_encode());
/* write netid */
if (!bencode_write_bytestring(buf, "i", 1))
return false;
if (!netID.BEncode(buf))
return false;
/* write signing pubkey */
if (!bencode_write_bytestring(buf, "k", 1))
return false;
if (!pubkey.bt_encode(buf))
return false;
auto n = Nick();
if (not n.empty())
btdp.append("n", n);
std::string nick = Nick();
if (!nick.empty())
btdp.append("p", enckey.ToView());
btdp.append("r", routerVersion);
if (not srvRecords.empty())
{
/* write nickname */
if (!bencode_write_bytestring(buf, "n", 1))
{
return false;
}
if (!bencode_write_bytestring(buf, nick.c_str(), nick.size()))
{
return false;
}
auto sublist = btdp.append_list("s");
for (auto& s : srvRecords)
sublist.append(s.bt_encode());
}
/* write encryption pubkey */
if (!bencode_write_bytestring(buf, "p", 1))
return false;
if (!enckey.bt_encode(buf))
return false;
btdp.append("u", last_updated.count());
// write router version if present
if (routerVersion)
{
if (not BEncodeWriteDictEntry("r", *routerVersion, buf))
return false;
}
if (version > 0)
{
// srv records if present
if (not BEncodeWriteDictList("s", srvRecords, buf))
return false;
}
/* write last updated */
if (!bencode_write_bytestring(buf, "u", 1))
return false;
if (!bencode_write_uint64(buf, last_updated.count()))
return false;
/* write versions */
if (!bencode_write_uint64_entry(buf, "v", 1, version))
return false;
// D We can delete this?
if (serializeExit)
{
/* write xi if they exist */
if (!bencode_write_bytestring(buf, "x", 1))
return false;
/* no exits anymore in RCs */
const std::vector<AlignedBuffer<8>> exits{};
if (!BEncodeWriteList(exits.begin(), exits.end(), buf))
return false;
}
if (version == 0)
{
/* write signature */
if (!bencode_write_bytestring(buf, "z", 1))
return false;
if (!signature.bt_encode(buf))
return false;
}
return bencode_end(buf);
return std::move(btdp).str();
}
void
@ -458,26 +396,16 @@ namespace llarp
RouterContact::Sign(const SecretKey& secretkey)
{
pubkey = llarp::seckey_topublic(secretkey);
std::array<byte_t, MAX_RC_SIZE> tmp;
llarp_buffer_t buf(tmp);
signature.Zero();
last_updated = time_now_ms();
if (!BEncodeSignedSection(&buf))
{
return false;
}
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
signed_bt_dict = bencode_signed_section();
signed_bt_dict = std::string(reinterpret_cast<char*>(buf.base), buf.sz);
if (version == 0 or version == 1)
{
return CryptoManager::instance()->sign(signature, secretkey, buf);
}
return false;
return CryptoManager::instance()->sign(
signature,
secretkey,
reinterpret_cast<uint8_t*>(signed_bt_dict.data()),
signed_bt_dict.size());
}
bool

View File

@ -116,8 +116,8 @@ namespace llarp
void
bt_encode_subdict(oxenc::bt_list_producer& btlp) const;
bool
BEncodeSignedSection(llarp_buffer_t* buf) const;
std::string
bencode_signed_section() const;
std::string
ToTXTRecord() const;

View File

@ -42,17 +42,6 @@ namespace llarp
// methods we do not want to inherit onwards from AbstractSerializable
void
bt_encode(oxenc::bt_list_producer&) const final
{
throw std::runtime_error{
"Error: Routing messages should not encode directly to a bt list producer!"};
}
void
bt_encode(llarp_buffer&) const final
{
throw std::runtime_error{"Error: Routing messages should not encode directly to a buffer!"};
}
void
bt_encode(oxenc::bt_dict_producer&) const final
{
throw std::runtime_error{

View File

@ -1,7 +1,6 @@
#include "endpoint.hpp"
#include "endpoint_state.hpp"
#include "endpoint_util.hpp"
#include "hidden_service_address_lookup.hpp"
#include "auth.hpp"
#include "llarp/util/logging.hpp"
#include "outbound_context.hpp"
@ -11,7 +10,6 @@
#include <llarp/net/ip.hpp>
#include <llarp/net/ip_range.hpp>
#include <llarp/dht/context.hpp>
#include <llarp/dht/key.hpp>
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/messages/findname.hpp>
@ -408,7 +406,7 @@ namespace llarp
std::set<EncryptedIntroSet> remote;
for (const auto& introset : msg->found)
{
if (not introset.Verify(Now()))
if (not introset.verify(Now()))
{
LogError(Name(), " got invalid introset");
return false;
@ -425,7 +423,7 @@ namespace llarp
}
std::unique_ptr<IServiceLookup> lookup = std::move(itr->second);
lookups.erase(itr);
lookup->HandleIntrosetResponse(remote);
// lookup->HandleIntrosetResponse(remote);
return true;
}
@ -716,43 +714,31 @@ namespace llarp
auto* r = router();
const auto paths = GetManyPathsWithUniqueEndpoints(
this,
llarp::dht::INTROSET_RELAY_REDUNDANCY,
dht::Key_t{introset.derivedSigningKey.as_array()});
this, INTROSET_RELAY_REDUNDANCY, dht::Key_t{introset.derivedSigningKey.as_array()});
if (paths.size() != llarp::dht::INTROSET_RELAY_REDUNDANCY)
if (paths.size() != INTROSET_RELAY_REDUNDANCY)
{
LogWarn(
"Cannot publish intro set because we only have ",
paths.size(),
" paths, but need ",
llarp::dht::INTROSET_RELAY_REDUNDANCY);
INTROSET_RELAY_REDUNDANCY);
return false;
}
// do publishing for each path selected
size_t published = 0;
for (const auto& path : paths)
{
for (size_t i = 0; i < llarp::dht::INTROSET_REQS_PER_RELAY; ++i)
for (size_t i = 0; i < INTROSET_REQS_PER_RELAY; ++i)
{
r->notify_router_event<tooling::PubIntroSentEvent>(
r->pubkey(),
llarp::dht::Key_t{introset.derivedSigningKey.as_array()},
RouterID(path->hops[path->hops.size() - 1].rc.pubkey),
published);
if (PublishIntroSetVia(introset, r, path, published))
published++;
RouterID(path->hops[path->hops.size() - 1].rc.pubkey));
m_router->send_control_message(path->Upstream(), "publish_intro", introset.bt_encode());
}
}
if (published != llarp::dht::INTROSET_STORAGE_REDUNDANCY)
LogWarn(
"Publish introset failed: could only publish ",
published,
" copies but wanted ",
llarp::dht::INTROSET_STORAGE_REDUNDANCY);
return published == llarp::dht::INTROSET_STORAGE_REDUNDANCY;
return true;
}
struct PublishIntroSetJob : public IServiceLookup

View File

@ -6,6 +6,19 @@
namespace llarp::service
{
EncryptedIntroSet::EncryptedIntroSet(
std::string signing_key,
std::chrono::milliseconds signed_at,
std::string enc_payload,
std::string nonce,
std::string s)
: signedAt{signed_at}, nounce{reinterpret_cast<uint8_t*>(nonce.data())}
{
derivedSigningKey = PubKey::from_string(signing_key);
introsetPayload = oxenc::bt_deserialize<std::vector<uint8_t>>(enc_payload);
sig.from_string(std::move(s));
}
util::StatusObject
EncryptedIntroSet::ExtractStatus() const
{
@ -132,6 +145,12 @@ namespace llarp::service
derivedSigningKey, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
bool
EncryptedIntroSet::verify(uint8_t* introset, size_t introset_size, uint8_t* key, uint8_t* sig)
{
return CryptoManager::instance()->verify(key, introset, introset_size, sig);
}
bool
EncryptedIntroSet::verify(std::string introset, std::string key, std::string sig)
{

View File

@ -139,6 +139,15 @@ namespace llarp::service
std::optional<Tag> topic;
Signature sig;
EncryptedIntroSet() = default;
explicit EncryptedIntroSet(
std::string signing_key,
std::chrono::milliseconds signed_at,
std::string enc_payload,
std::string nonce,
std::string sig);
bool
Sign(const PrivateKey& k);
@ -164,6 +173,9 @@ namespace llarp::service
bool
verify(llarp_time_t now) const;
static bool
verify(uint8_t* introset, size_t introset_size, uint8_t* key, uint8_t* sig);
static bool
verify(std::string introset, std::string key, std::string sig);

View File

@ -56,13 +56,13 @@ namespace llarp
explicit AlignedBuffer(const std::array<byte_t, SIZE>& buf)
{
m_data = buf;
_data = buf;
}
AlignedBuffer&
operator=(const byte_t* data)
{
std::memcpy(m_data.data(), data, sz);
std::memcpy(_data.data(), data, sz);
return *this;
}
@ -79,37 +79,37 @@ namespace llarp
bool
operator==(const AlignedBuffer& other) const
{
return m_data == other.m_data;
return _data == other._data;
}
bool
operator!=(const AlignedBuffer& other) const
{
return m_data != other.m_data;
return _data != other._data;
}
bool
operator<(const AlignedBuffer& other) const
{
return m_data < other.m_data;
return _data < other._data;
}
bool
operator>(const AlignedBuffer& other) const
{
return m_data > other.m_data;
return _data > other._data;
}
bool
operator<=(const AlignedBuffer& other) const
{
return m_data <= other.m_data;
return _data <= other._data;
}
bool
operator>=(const AlignedBuffer& other) const
{
return m_data >= other.m_data;
return _data >= other._data;
}
AlignedBuffer
@ -126,7 +126,7 @@ namespace llarp
// Mutate in place instead.
for (size_t i = 0; i < sz; ++i)
{
m_data[i] ^= other.m_data[i];
_data[i] ^= other._data[i];
}
return *this;
}
@ -135,14 +135,14 @@ namespace llarp
operator[](size_t idx)
{
assert(idx < SIZE);
return m_data[idx];
return _data[idx];
}
const byte_t&
operator[](size_t idx) const
{
assert(idx < SIZE);
return m_data[idx];
return _data[idx];
}
static constexpr size_t
@ -154,31 +154,31 @@ namespace llarp
void
Fill(byte_t f)
{
m_data.fill(f);
_data.fill(f);
}
std::array<byte_t, SIZE>&
as_array()
{
return m_data;
return _data;
}
const std::array<byte_t, SIZE>&
as_array() const
{
return m_data;
return _data;
}
byte_t*
data()
{
return m_data.data();
return _data.data();
}
const byte_t*
data() const
{
return m_data.data();
return _data.data();
}
bool
@ -196,7 +196,7 @@ namespace llarp
void
Zero()
{
m_data.fill(0);
_data.fill(0);
}
virtual void
@ -208,25 +208,25 @@ namespace llarp
typename std::array<byte_t, SIZE>::iterator
begin()
{
return m_data.begin();
return _data.begin();
}
typename std::array<byte_t, SIZE>::iterator
end()
{
return m_data.end();
return _data.end();
}
typename std::array<byte_t, SIZE>::const_iterator
begin() const
{
return m_data.cbegin();
return _data.cbegin();
}
typename std::array<byte_t, SIZE>::const_iterator
end() const
{
return m_data.cend();
return _data.cend();
}
bool
@ -241,6 +241,19 @@ namespace llarp
return true;
}
bool
from_string(std::string b)
{
if (b.size() != sz)
{
log::error(util_cat, "Error: buffer size mismatch in aligned buffer!");
return false;
}
std::memcpy(_data.data(), b.data(), b.size());
return true;
}
bool
bt_encode(llarp_buffer_t* buf) const
{
@ -292,7 +305,7 @@ namespace llarp
}
private:
std::array<byte_t, SIZE> m_data;
std::array<byte_t, SIZE> _data;
};
namespace detail

View File

@ -15,6 +15,11 @@ namespace llarp
namespace log = oxen::log;
}
namespace
{
static auto util_cat = llarp::log::Cat("lokinet.util");
} // namespace
// Not ready to pollute these deprecation warnings everywhere yet
#if 0
#define LOKINET_LOG_DEPRECATED(Meth) \