Review fixes + misc fixes

pull/2218/head
dr7ana 7 months ago
parent 8b70e0ad2b
commit af0ac28119

@ -91,7 +91,6 @@ add_dependencies(lokinet-utils genversion)
lokinet_add_library(lokinet-time-place
ev/ev.cpp
ev/libuv.cpp
net/exit_info.cpp # only router_contact
net/ip.cpp
net/ip_address.cpp
net/ip_packet.cpp

@ -31,7 +31,7 @@ namespace llarp
oxenc::bt_list_producer btlp{};
for (const auto& it : *this)
btlp.append(it.bt_encode());
btlp.append(it.view());
return btlp.view();
}

@ -628,8 +628,7 @@ namespace llarp
|| local_rid == rid)
continue;
neighbors +=
rid.bt_encode(); // TODO: refactor to use reference to bt_dict_producer subdict
neighbors += rid.bt_encode();
}
m.respond(

@ -1,121 +0,0 @@
#ifndef _WIN32
#include <arpa/inet.h>
#endif
#include "exit_info.hpp"
#include <llarp/util/bencode.h>
#include <cstring>
namespace llarp
{
bool
ExitInfo::bt_encode(llarp_buffer_t* buf) const
{
SockAddr exitaddr = ipAddress.createSockAddr();
const auto* exitaddr6 = static_cast<const sockaddr_in6*>(exitaddr);
SockAddr netmaskaddr = netmask.createSockAddr();
const auto* netmaskaddr6 = static_cast<const sockaddr_in6*>(netmaskaddr);
char tmp[128] = {0};
if (!bencode_start_dict(buf))
return false;
if (!inet_ntop(AF_INET6, &exitaddr6->sin6_addr, tmp, sizeof(tmp)))
return false;
if (!BEncodeWriteDictString("a", std::string(tmp), buf))
return false;
if (!inet_ntop(AF_INET6, &netmaskaddr6->sin6_addr, tmp, sizeof(tmp)))
return false;
if (!BEncodeWriteDictString("b", std::string(tmp), buf))
return false;
if (!BEncodeWriteDictEntry("k", pubkey, buf))
return false;
if (!BEncodeWriteDictInt("v", version, buf))
return false;
return bencode_end(buf);
}
static bool
bdecode_ip_string(llarp_buffer_t* buf, in6_addr& ip)
{
char tmp[128] = {0};
llarp_buffer_t strbuf;
if (!bencode_read_string(buf, &strbuf))
return false;
if (strbuf.sz >= sizeof(tmp))
return false;
memcpy(tmp, strbuf.base, strbuf.sz);
tmp[strbuf.sz] = 0;
return inet_pton(AF_INET6, tmp, &ip.s6_addr[0]) == 1;
}
bool
ExitInfo::decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("k", pubkey, read, k, buf))
return false;
if (!BEncodeMaybeReadDictInt("v", version, read, k, buf))
return false;
if (k.startswith("a"))
{
in6_addr tmp;
if (not bdecode_ip_string(buf, tmp))
return false;
SockAddr addr(tmp);
ipAddress = IpAddress(addr);
return true;
}
if (k.startswith("b"))
{
in6_addr tmp;
if (not bdecode_ip_string(buf, tmp))
return false;
SockAddr addr(tmp);
netmask = IpAddress(addr);
return true;
}
return read;
}
std::string
ExitInfo::ToString() const
{
/*
// TODO: derive these from ipAdress
throw std::runtime_error("FIXME: need in6_addr and netmask from IpAddress");
in6_addr address;
in6_addr netmask;
Printer printer(stream, level, spaces);
std::ostringstream ss;
char tmp[128] = {0};
if (inet_ntop(AF_INET6, (void*)&address, tmp, sizeof(tmp)))
ss << tmp;
else
return stream;
ss << std::string("/");
#if defined(ANDROID)
snprintf(tmp, sizeof(tmp), "%zu", llarp::bits::count_array_bits(netmask.s6_addr));
ss << tmp;
#else
ss << std::to_string(llarp::bits::count_array_bits(netmask.s6_addr));
#endif
printer.printValue(ss.str());
*/
return fmt::format("[Exit {}]", ipAddress.ToString());
}
} // namespace llarp

@ -1,51 +0,0 @@
#pragma once
#include "ip_address.hpp"
#include <llarp/crypto/types.hpp>
#include <llarp/util/bencode.hpp>
#include <iosfwd>
/**
* exit_info.h
*
* utilities for handling exits on the llarp network
*/
/// Exit info model
namespace llarp
{
/// deprecated don't use me , this is only for backwards compat
struct ExitInfo
{
IpAddress ipAddress;
IpAddress netmask;
PubKey pubkey;
uint64_t version = llarp::constants::proto_version;
ExitInfo() = default;
ExitInfo(const PubKey& pk, const IpAddress& address) : ipAddress(address), pubkey(pk)
{}
bool
bt_encode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf)
{
return bencode_decode_dict(*this, buf);
}
bool
decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf);
std::string
ToString() const;
};
template <>
constexpr inline bool IsToStringFormattable<ExitInfo> = true;
} // namespace llarp

@ -278,7 +278,8 @@ namespace llarp
{
for (const auto& rc : bootstrap_rc_list)
{
log::info(link_cat, "Doing explore via bootstrap node: {}", RouterID(rc.router_id()));
const auto& rid = rc.router_id();
log::info(link_cat, "Doing explore via bootstrap node: {}", rid);
// TODO: replace this concept
// dht->ExploreNetworkVia(dht::Key_t{rc.pubkey});

@ -539,15 +539,19 @@ namespace llarp
return _link_manager.get_num_connected_clients();
}
void
Router::save_rc()
{
_node_db->put_rc(router_contact.view());
queue_disk_io([&]() { router_contact.write(our_rc_file); });
}
bool
Router::update_rc()
{
router_contact.resign();
if (is_service_node())
{
_node_db->put_rc(router_contact.view());
queue_disk_io([&]() { router_contact.write(our_rc_file); });
}
save_rc();
return true;
}
@ -756,17 +760,24 @@ namespace llarp
Router::report_stats()
{
const auto now = llarp::time_now_ms();
LogInfo(node_db()->num_loaded(), " RCs loaded");
LogInfo(bootstrap_rc_list.size(), " bootstrap peers");
LogInfo(NumberOfConnectedRouters(), " router connections");
log::info(
logcat,
"{} RCs loaded with {} bootstrap peers and {} router connections!",
node_db()->num_loaded(),
bootstrap_rc_list.size(),
NumberOfConnectedRouters());
if (is_service_node())
{
LogInfo(NumberOfConnectedClients(), " client connections");
LogInfo(ToString(router_contact.age(now)), " since we last updated our RC");
LogInfo(ToString(router_contact.time_to_expiry(now)), " until our RC expires");
log::info(
logcat,
"Local service node has {} client connections since last RC update ({} to expiry)",
NumberOfConnectedClients(),
router_contact.age(now),
router_contact.time_to_expiry(now));
}
if (_last_stats_report > 0s)
LogInfo(ToString(now - _last_stats_report), " last reported stats");
log::info(logcat, "Last reported stats time {}", now - _last_stats_report);
_last_stats_report = now;
}
@ -939,7 +950,7 @@ namespace llarp
// mark peers as de-registered
for (auto& peer : close_peers)
_link_manager.deregister_peer(std::move(peer));
_link_manager.deregister_peer(peer);
}
_link_manager.check_persisting_conns(now);
@ -1049,83 +1060,48 @@ namespace llarp
if (is_running || is_stopping)
return false;
// TODO: replace all this logic with construction of LocalRC
router_contact = LocalRC::make(identity(), public_ip());
/* // set public signing key
router_contact._router_id = seckey_topublic(identity());
// set router version if service node
if (IsServiceNode())
if (is_service_node() and not router_contact.is_public_router())
{
router_contact.routerVersion =
RouterVersion(llarp::LOKINET_VERSION, llarp::constants::proto_version);
}
if (IsServiceNode() and not router_contact.is_public_router())
{
LogError("we are configured as relay but have no reachable addresses");
return false;
}
// set public encryption key
router_contact.enckey = seckey_topublic(encryption());
LogInfo("Signing rc...");
if (!router_contact.sign(identity()))
{
LogError("failed to sign rc");
return false;
}
if (IsServiceNode())
{
if (!SaveRC())
if (not router_contact.is_public_router())
{
LogError("failed to save RC");
log::error(logcat, "Router is configured as relay but has no reachable addresses!");
return false;
}
}
if (IsServiceNode())
{
// initialize as service node
if (!InitServiceNode())
save_rc();
if (not init_service_node())
{
LogError("Failed to initialize service node");
log::error(logcat, "Router failed to initialize service node!");
return false;
}
log::info(logcat, "Router initialized as service node!");
const RouterID us = pubkey();
LogInfo("initalized service node: ", us);
// init gossiper here
_rcGossiper.Init(&_link_manager, us, this);
// relays do not use profiling
router_profiling().Disable();
}
else
{
// we are a client
// regenerate keys and resign rc before everything else
// we are a client, regenerate keys and resign rc before everything else
crypto::identity_keygen(_identity);
crypto::encryption_keygen(_encryption);
router_contact._router_id = seckey_topublic(identity());
router_contact.enckey = seckey_topublic(encryption());
if (!router_contact.sign(identity()))
{
LogError("failed to regenerate keys and sign RC");
return false;
}
} */
router_contact.set_router_id(seckey_to_pubkey(identity())); // resigns RC
}
log::info(logcat, "Starting hidden service context...");
LogInfo("starting hidden service context...");
if (!hidden_service_context().StartAll())
{
LogError("Failed to start hidden service context");
log::error(logcat, "Failed to start hidden service context!");
return false;
}
{
LogInfo("Loading nodedb from disk...");
_node_db->load_from_disk();
}
log::info(logcat, "Loading NodeDB from disk...");
_node_db->load_from_disk();
_contacts = std::make_shared<Contacts>(llarp::dht::Key_t(pubkey()), *this);
@ -1133,15 +1109,16 @@ namespace llarp
{
node_db()->put_rc(rc);
_contacts->rc_nodes()->PutNode(rc);
LogInfo("added bootstrap node ", RouterID{rc.router_id()});
log::info(logcat, "Added bootstrap node (rid: {})", rc.router_id());
}
LogInfo("have ", _node_db->num_loaded(), " routers");
log::info(logcat, "Router populated NodeDB with {} routers", _node_db->num_loaded());
_loop->call_every(ROUTER_TICK_INTERVAL, weak_from_this(), [this] { Tick(); });
_route_poker->start();
is_running.store(true);
_started_at = now();
if (is_service_node())
{
// do service node testing if we are in service node whitelist mode
@ -1163,13 +1140,16 @@ namespace llarp
{
if (not SessionToRouterAllowed(router))
{
LogDebug(
router,
" is no longer a registered service node so we remove it from the testing list");
log::debug(
logcat,
"{} is no longer a registered service node; dropping from test list",
router);
router_testing.remove_node_from_failing(router);
continue;
}
LogDebug("Establishing session to ", router, " for SN testing");
log::debug(logcat, "Establishing session to {} for service node testing", router);
// try to make a session to this random router
// this will do a dht lookup if needed
_link_manager.connect_to(router);
@ -1346,7 +1326,7 @@ namespace llarp
}
bool
Router::InitServiceNode()
Router::init_service_node()
{
LogInfo("accepting transit traffic");
paths.AllowTransit();

@ -147,6 +147,9 @@ namespace llarp
void
report_stats();
void
save_rc();
bool
update_rc();
@ -392,7 +395,7 @@ namespace llarp
/// initialize us as a service node
/// return true on success
bool
InitServiceNode();
init_service_node();
bool
IsRunning() const;

@ -110,7 +110,7 @@ namespace llarp
bool
RouterContact::write(const fs::path& fname) const
{
auto bte = bt_encode();
auto bte = view();
try
{
@ -124,26 +124,6 @@ namespace llarp
return true;
}
// std::string
// RouterContact::bencode_signed_section() const
// {
// oxenc::bt_dict_producer btdp;
// btdp.append("4", _addr.to_string());
// if (_addr6)
// btdp.append("6", _addr6->to_string());
// if (ACTIVE_NETID != llarp::LOKINET_DEFAULT_NETID)
// btdp.append("i", ACTIVE_NETID);
// btdp.append("p", _router_id.bt_encode());
// btdp.append("t", _timestamp.time_since_epoch().count());
// btdp.append("v", _router_version.data());
// return std::move(btdp).str();
// }
util::StatusObject
RouterContact::extract_status() const
{

@ -6,7 +6,6 @@
#include <llarp/constants/version.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/dns/srv_data.hpp>
#include <llarp/net/exit_info.hpp>
#include <llarp/util/aligned.hpp>
#include <llarp/util/bencode.hpp>
#include <llarp/util/status.hpp>
@ -18,24 +17,6 @@
#include <functional>
#include <vector>
// namespace oxenc
// {
// class bt_list_consumer;
// } // namespace oxenc
/*
- figure out where we do bt_encoding of RC's
- maybe dump secret key from bt_encode
- it's weird to pass the secret key contextually
- suspicion we will need optional signature as an optional(?) string with serialized data
- resetting signature would be string::clear() instead
- ::sign() will cache serialized value
- do timestamp stuff
- bt_encode that takes bt_dict_producer requires reference to subdict
- presumably to be done in endpoints
- will be used for get_multi_rc endpoint
*/
namespace llarp
{
static auto logcat = log::Cat("RC");
@ -44,25 +25,28 @@ namespace llarp
static inline constexpr size_t NETID_SIZE{8};
/// On the wire we encode the data as a dict containing:
/// "" -- the RC format version, which must be == RouterContact::Version for us to attempt to
/// parse the reset of the fields. (Future versions might have backwards-compat support
/// for lower versions).
/// "4" -- 6 byte packed IPv4 address & port: 4 bytes of IPv4 address followed by 2 bytes of
/// port, both encoded in network (i.e. big-endian) order.
/// "6" -- optional 18 byte IPv6 address & port: 16 byte raw IPv6 address followed by 2 bytes
/// of port in network order.
/// "i" -- optional network ID string of up to 8 bytes; this is omitted for the default network
/// ID ("lokinet") but included for others (such as "gamma" for testnet).
/// "p" -- 32-byte router pubkey
/// "t" -- timestamp when this RC record was created (which also implicitly determines when it
/// goes stale and when it expires).
/// "v" -- lokinet version of the router; this is a three-byte packed value of
/// MAJOR, MINOR, PATCH, e.g. \x00\x0a\x03 for 0.10.3.
/// "~" -- signature of all of the previous serialized data, signed by "p"
/// RouterContact
struct RouterContact
{
static constexpr uint8_t RC_VERSION = 0;
/// Constructs an empty RC
// RouterContact() = default;
// RouterContact(std::string)
// {
// log::error(logcat, "ERROR: SUPPLANT THIS CONSTRUCTOR");
// }
// RouterContact(std::string buf);
/// RC version that we support; we fail to load RCs that don't have the same version as that
/// means they are incompatible with us.
// static constexpr uint8_t VERSION = 0;
/// Unit tests disable this to allow private IP ranges in RCs, which normally get rejected.
static inline bool BLOCK_BOGONS = true;
@ -85,6 +69,12 @@ namespace llarp
/// changes i.e. just to push out a new confirmation of the details).
static constexpr auto REPUBLISH = STALE / 2 - 5min;
ustring_view
view() const
{
return _payload;
}
/// Getters for private attributes
const oxen::quic::Address&
addr() const
@ -158,29 +148,6 @@ namespace llarp
bool
write(const fs::path& fname) const;
/// On the wire we encode the data as a dict containing:
/// "" -- the RC format version, which must be == RouterContact::Version for us to attempt to
/// parse the reset of the fields. (Future versions might have backwards-compat support
/// for lower versions).
/// "4" -- 6 byte packed IPv4 address & port: 4 bytes of IPv4 address followed by 2 bytes of
/// port, both encoded in network (i.e. big-endian) order.
/// "6" -- optional 18 byte IPv6 address & port: 16 byte raw IPv6 address followed by 2 bytes
/// of port in network order.
/// "i" -- optional network ID string of up to 8 bytes; this is omitted for the default network
/// ID ("lokinet") but included for others (such as "gamma" for testnet).
/// "p" -- 32-byte router pubkey
/// "t" -- timestamp when this RC record was created (which also implicitly determines when it
/// goes stale and when it expires).
/// "v" -- lokinet version of the router; this is a three-byte packed value of
/// MAJOR, MINOR, PATCH, e.g. \x00\x0a\x03 for 0.10.3.
/// "~" -- signature of all of the previous serialized data, signed by "p"
virtual ustring_view
bt_encode() const
{
log::warning(logcat, "ERROR: SUPPLANT THIS METHOD");
return {};
}
bool
operator==(const RouterContact& other) const
{
@ -251,16 +218,20 @@ namespace llarp
/// parameters and outputs a bt-serialized string
struct LocalRC final : public RouterContact
{
static LocalRC
make(const SecretKey secret, oxen::quic::Address local);
private:
ustring _signature;
const SecretKey _secret_key;
SecretKey _secret_key;
// TODO: fix these parameters
void
bt_sign(oxenc::bt_dict_producer& btdp);
void
bt_encode(oxenc::bt_dict_producer& btdp) const;
bt_encode(oxenc::bt_dict_producer& btdp);
LocalRC(const SecretKey secret, oxen::quic::Address local);
public:
LocalRC() = default;
@ -270,15 +241,6 @@ namespace llarp
void
resign();
ustring_view
bt_encode() const override;
ustring_view
view() const
{
return _payload;
}
void
clear() override
{
@ -347,7 +309,6 @@ namespace llarp
struct RemoteRC final : public RouterContact
{
private:
// TODO: fix these parameters
void
bt_verify(oxenc::bt_dict_consumer& data, bool reject_expired = false) const;
@ -362,12 +323,6 @@ namespace llarp
explicit RemoteRC(oxenc::bt_dict_consumer btdc);
~RemoteRC() = default;
ustring_view
bt_encode() const override
{
return _payload;
}
std::string_view
view() const
{

@ -11,6 +11,21 @@
namespace llarp
{
LocalRC
LocalRC::make(const SecretKey secret, oxen::quic::Address local)
{
return *new LocalRC{secret, local};
}
LocalRC::LocalRC(const SecretKey secret, oxen::quic::Address local)
: _secret_key{std::move(secret)}
{
_router_id = llarp::seckey_to_pubkey(_secret_key);
_addr = std::move(local);
_addr6.emplace(&_addr.in6());
resign();
}
LocalRC::LocalRC(std::string payload, const SecretKey sk) : _secret_key{std::move(sk)}
{
_router_id = llarp::seckey_to_pubkey(_secret_key);
@ -66,16 +81,8 @@ namespace llarp
_payload = btdp.view<unsigned char>();
}
ustring_view
LocalRC::bt_encode() const
{
oxenc::bt_dict_producer btdp;
bt_encode(btdp);
return btdp.view<unsigned char>();
}
void
LocalRC::bt_encode(oxenc::bt_dict_producer& btdp) const
LocalRC::bt_encode(oxenc::bt_dict_producer& btdp)
{
btdp.append("", RC_VERSION);
@ -117,14 +124,7 @@ namespace llarp
btdp.append(
"v", std::string_view{reinterpret_cast<const char*>(llarp::LOKINET_VERSION.data()), 3});
btdp.append_signature("~", [this](ustring_view to_sign) {
std::array<unsigned char, 64> sig;
if (!crypto::sign(sig.data(), _secret_key, to_sign))
throw std::runtime_error{"Failed to sign LocalRC"};
return sig;
});
bt_sign(btdp);
}
void

@ -4,16 +4,32 @@
namespace llarp::service
{
bool
Identity::BEncode(llarp_buffer_t* buf) const
std::string
Identity::bt_encode() const
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictEntry("s", signkey, buf))
return false;
if (!BEncodeWriteDictInt("v", version, buf))
return false;
return bencode_end(buf);
oxenc::bt_dict_producer btdp;
btdp.append("s", signkey.ToView());
btdp.append("v", version);
return std::move(btdp).str();
}
void
Identity::bt_decode(std::string buf)
{
try
{
oxenc::bt_dict_consumer btdc{buf};
signkey.from_string(btdc.require<std::string>("s"));
version = btdc.require<uint64_t>("v");
}
catch (...)
{
log::warning(logcat, "Identity failed to parse bt-encoded contents!");
throw;
}
}
bool
@ -74,7 +90,7 @@ namespace llarp::service
// make sure we are empty
Clear();
std::array<byte_t, 4096> tmp;
std::string buf;
// this can throw
bool exists = fs::exists(fname);
@ -88,16 +104,15 @@ namespace llarp::service
// check for file
if (!exists)
{
llarp_buffer_t buf{tmp};
// regen and encode
RegenerateKeys();
if (!BEncode(&buf))
throw std::length_error("failed to encode new identity");
const auto sz = buf.cur - buf.base;
buf = bt_encode();
// write
try
{
util::buffer_to_file(fname, tmp.data(), sz);
util::buffer_to_file(fname, buf.data(), buf.size());
}
catch (const std::exception& e)
{
@ -114,18 +129,15 @@ namespace llarp::service
// read file
try
{
util::file_to_buffer(fname, tmp.data(), tmp.size());
util::file_to_buffer(fname, buf.data(), buf.size());
}
catch (const std::length_error&)
{
throw std::length_error{"service identity too big"};
}
// (don't catch io error exceptions)
{
llarp_buffer_t buf{tmp};
if (!bencode_decode_dict(*this, &buf))
throw std::length_error{"could not decode service identity"};
}
bt_decode(buf);
// ensure that the encryption key is set
if (enckey.IsZero())

@ -31,8 +31,10 @@ namespace llarp::service
void
RegenerateKeys();
bool
BEncode(llarp_buffer_t* buf) const;
std::string
bt_encode() const;
void bt_decode(std::string);
/// @param needBackup determines whether existing keys will be cycled
void

@ -130,12 +130,6 @@ namespace llarp
std::string
bt_encode() const;
bool
BDecode(llarp_buffer_t* buf)
{
return bencode_decode_dict(*this, buf);
}
void
clear()
{

@ -17,16 +17,17 @@ namespace llarp
{
static auto ben_cat = log::Cat("stupid.bencode");
template <typename T>
T
decode_key(oxenc::bt_dict_consumer& btdp, const char* key)
{
return btdp.require<T>(key);
}
template <typename List_t>
bool
BEncodeReadList(List_t& result, llarp_buffer_t* buf);
inline bool
BEncodeWriteDictMsgType(llarp_buffer_t* buf, const char* k, const char* t)
{
return bencode_write_bytestring(buf, k, 1) && bencode_write_bytestring(buf, t, 1);
}
template <typename Obj_t>
bool
BEncodeWriteDictString(const char* k, const Obj_t& str, llarp_buffer_t* buf)
@ -320,23 +321,6 @@ namespace llarp
buffer);
}
/// write an iterable container as a list
template <typename Set_t>
bool
BEncodeWriteSet(const Set_t& set, llarp_buffer_t* buffer)
{
if (not bencode_start_list(buffer))
return false;
for (const auto& item : set)
{
if (not item.bt_encode(buffer))
return false;
}
return bencode_end(buffer);
}
template <typename List_t>
bool
BEncodeWriteDictList(const char* k, List_t& list, llarp_buffer_t* buf)

Loading…
Cancel
Save