You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lokinet/llarp/router/router.hpp

602 lines
13 KiB
C++

#pragma once
#include <llarp/bootstrap.hpp>
#include <llarp/config/config.hpp>
#include <llarp/config/key_manager.hpp>
#include <llarp/constants/link_layer.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/dht/context.hpp>
#include <llarp/ev/ev.hpp>
#include <llarp/exit/context.hpp>
#include <llarp/handlers/tun.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/messages/link_message_parser.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/peerstats/peer_db.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/consensus/reachability_testing.hpp>
#include <llarp/tooling/router_event.hpp>
#include "outbound_message_handler.hpp"
#include "rc_gossiper.hpp"
#include "rc_lookup_handler.hpp"
#include "route_poker.hpp"
#include <llarp/routing/handler.hpp>
#include <llarp/routing/message_parser.hpp>
#include <llarp/rpc/lokid_rpc_client.hpp>
#include <llarp/rpc/rpc_server.hpp>
#include <llarp/service/context.hpp>
#include <stdexcept>
#include <llarp/util/buffer.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/status.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/time.hpp>
#include <llarp/util/service_manager.hpp>
6 years ago
#include <functional>
#include <list>
#include <map>
#include <memory>
6 years ago
#include <set>
#include <unordered_map>
#include <vector>
6 years ago
#include <oxenmq/address.h>
namespace libquic = oxen::quic;
namespace llarp
{
class RouteManager final /* : public Router */
{
public:
std::shared_ptr<libquic::connection_interface>
get_or_connect();
private:
std::shared_ptr<libquic::Endpoint> ep;
};
struct Router : std::enable_shared_from_this<Router>
{
private:
llarp_time_t last_pump = 0s;
// transient iwp encryption key
fs::path transport_keyfile;
// long term identity key
fs::path identity_keyfile;
fs::path encryption_keyfile;
// path to write our self signed rc to
fs::path our_rc_file;
// use file based logging?
bool use_file_logging = false;
// our router contact
RouterContact router_contact;
/// should we obey the service node whitelist?
bool follow_whitelist = false;
std::shared_ptr<oxenmq::OxenMQ> _lmq;
path::BuildLimiter _pathbuild_limiter;
std::shared_ptr<EventLoopWakeup> loop_wakeup;
std::atomic<bool> is_stopping;
std::atomic<bool> is_running;
int _outbound_udp_socket = -1;
bool is_service_node = false;
std::optional<SockAddr> _ourAddress;
oxen::quic::Address local;
EventLoop_ptr _loop;
std::shared_ptr<vpn::Platform> _vpn;
path::PathContext paths;
exit::Context _exitContext;
SecretKey _identity;
SecretKey _encryption;
std::shared_ptr<dht::AbstractDHTMessageHandler> _dht;
std::shared_ptr<NodeDB> _node_db;
llarp_time_t _startedAt;
const oxenmq::TaggedThreadID _disk_thread;
oxen::quic::Network _net;
llarp_time_t _last_stats_report = 0s;
llarp_time_t next_decomm_warning = time_now_ms() + 15s;
std::shared_ptr<llarp::KeyManager> _key_manager;
std::shared_ptr<PeerDb> _peer_db;
std::shared_ptr<Config> _config;
uint32_t _path_build_count = 0;
consensus::reachability_testing router_testing;
bool
should_report_stats(llarp_time_t now) const;
void
report_stats();
bool
update_rc(bool rotateKeys = false);
bool
from_config(const Config& conf);
void
message_sent(const RouterID& remote, SendStatus status);
bool
insufficient_peers() const;
protected:
void
handle_router_event(tooling::RouterEventPtr event) const;
virtual bool
disableGossipingRC_TestingOnly()
{
return false;
};
public:
std::shared_ptr<Config>
config() const
{
return _config;
}
path::BuildLimiter&
pathbuild_limiter()
{
return _pathbuild_limiter;
}
const llarp::net::Platform&
net() const;
const std::shared_ptr<oxenmq::OxenMQ>&
lmq() const
{
return _lmq;
}
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
3 years ago
const std::shared_ptr<rpc::LokidRpcClient>&
rpc_client() const
{
return _rpc_client;
}
std::shared_ptr<dht::AbstractDHTMessageHandler>
dht() const
{
return _dht;
}
// TOFIX: THIS
OutboundMessageHandler&
outboundMessageHandler()
{
return _outboundMessageHandler;
}
LinkManager&
link_manager()
{
return _link_manager;
}
RCLookupHandler&
rc_lookup_handler()
{
return _rc_lookup_handler;
}
std::shared_ptr<PeerDb>
peer_db()
{
return _peer_db;
}
inline int
outbound_udp_socket() const
{
return _outbound_udp_socket;
}
exit::Context&
exitContext()
{
return _exitContext;
}
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
3 years ago
const std::shared_ptr<KeyManager>&
key_manager() const
{
return _key_manager;
}
const SecretKey&
identity() const
{
return _identity;
}
const SecretKey&
encryption() const
{
return _encryption;
}
Profiling&
router_profiling()
{
return _router_profiling;
}
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
3 years ago
const EventLoop_ptr&
loop() const
{
return _loop;
}
vpn::Platform*
vpn_platform() const
{
return _vpn.get();
}
const std::shared_ptr<NodeDB>&
node_db() const
{
return _node_db;
}
path::PathContext&
path_context()
{
return paths;
}
const RouterContact&
rc() const
{
return router_contact;
}
std::optional<std::variant<nuint32_t, nuint128_t>>
public_ip() const;
util::StatusObject
ExtractStatus() const;
util::StatusObject
ExtractSummaryStatus() const;
std::unordered_set<RouterID>
router_whitelist() const
{
return _rc_lookup_handler.whitelist();
}
void
modify_rc(std::function<std::optional<RouterContact>(RouterContact)> modify);
void
set_router_whitelist(
const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& unfunded);
template <class EventType, class... Params>
void
notify_router_event([[maybe_unused]] Params&&... args) const
{
// TODO: no-op when appropriate
auto event = std::make_unique<EventType>(args...);
handle_router_event(std::move(event));
}
void
queue_work(std::function<void(void)> func);
void
queue_disk_io(std::function<void(void)> func);
/// return true if we look like we are a decommissioned service node
bool
appear_decommed() const;
/// return true if we look like we are a registered, fully-staked service node (either active or
/// decommissioned). This condition determines when we are allowed to (and attempt to) connect
/// to other peers when running as a service node.
bool
appear_funded() const;
/// return true if we a registered service node; not that this only requires a partial stake,
/// and does not imply that this service node is *active* or fully funded.
bool
appear_registered() const;
/// return true if we look like we are allowed and able to test other routers
bool
can_test_routers() const;
llarp_time_t
Uptime() const;
bool
Sign(Signature& sig, const llarp_buffer_t& buf) const;
5 years ago
/// how often do we resign our RC? milliseconds.
// TODO: make configurable
llarp_time_t rcRegenInterval = 1h;
// should we be sending padded messages every interval?
bool sendPadding = false;
LinkMessageParser inbound_link_msg_parser;
routing::InboundMessageParser inbound_routing_msg_parser;
service::Context _hiddenServiceContext;
service::Context&
hiddenServiceContext()
{
return _hiddenServiceContext;
}
const service::Context&
hiddenServiceContext() const
{
return _hiddenServiceContext;
}
llarp_time_t _lastTick = 0s;
std::function<void(void)> _onDown;
void
SetDownHook(std::function<void(void)> hook)
{
_onDown = hook;
}
bool
LooksAlive() const
{
const llarp_time_t now = Now();
return now <= _lastTick || (now - _lastTick) <= llarp_time_t{30000};
}
/// bootstrap RCs
BootstrapList bootstrapRCList;
const std::shared_ptr<RoutePoker>&
routePoker() const
{
return m_RoutePoker;
}
std::shared_ptr<RoutePoker> m_RoutePoker;
5 years ago
void
TriggerPump();
5 years ago
void
PumpLL();
std::unique_ptr<rpc::RPCServer> m_RPCServer;
const llarp_time_t _randomStartDelay;
std::shared_ptr<rpc::LokidRpcClient> _rpc_client;
oxenmq::address lokidRPCAddr;
Profiling _router_profiling;
fs::path _profilesFile;
OutboundMessageHandler _outboundMessageHandler;
LinkManager _link_manager{*this};
RCLookupHandler _rc_lookup_handler;
4 years ago
RCGossiper _rcGossiper;
6 years ago
std::string
status_line();
using TimePoint_t = std::chrono::steady_clock::time_point;
5 years ago
TimePoint_t m_NextExploreAt;
4 years ago
void
GossipRCIfNeeded(const RouterContact rc);
4 years ago
3 years ago
explicit Router(EventLoop_ptr loop, std::shared_ptr<vpn::Platform> vpnPlatform);
~Router();
6 years ago
bool
HandleRecvLinkMessageBuffer(AbstractLinkSession* from, const llarp_buffer_t& msg);
void
InitInboundLinks();
void
6 years ago
InitOutboundLinks();
6 years ago
bool
GetRandomGoodRouter(RouterID& r);
6 years ago
/// initialize us as a service node
/// return true on success
bool
InitServiceNode();
bool
IsRunning() const;
/// return true if we are running in service node mode
bool
IsServiceNode() const;
std::optional<std::string>
OxendErrorState() const;
void
Close();
bool
Configure(std::shared_ptr<Config> conf, bool isSNode, std::shared_ptr<NodeDB> nodedb);
6 years ago
bool
StartRpcServer();
void
Freeze();
void
Thaw();
bool
Run();
/// stop running the router logic gracefully
void
Stop();
/// non graceful stop router
void
Die();
/// close all sessions and shutdown all links
void
StopLinks();
void
PersistSessionUntil(const RouterID& remote, llarp_time_t until);
bool
EnsureIdentity();
bool
EnsureEncryptionKey();
6 years ago
bool
SessionToRouterAllowed(const RouterID& router) const;
bool
PathToRouterAllowed(const RouterID& router) const;
void
HandleSaveRC() const;
bool
SaveRC();
/// return true if we are a client with an exit configured
bool
HasClientExit() const;
const byte_t*
pubkey() const
{
return seckey_topublic(_identity);
}
void
try_connect(fs::path rcfile);
bool
TryConnectAsync(RouterContact rc, uint16_t tries);
/// send to remote router or queue for sending
/// returns false on overflow
/// returns true on successful queue
/// NOT threadsafe
/// MUST be called in the logic thread
bool
SendToOrQueue(
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler handler);
void
ForEachPeer(
std::function<void(const AbstractLinkSession*, bool)> visit, bool randomize = false) const;
void
10 months ago
ForEachPeer(std::function<void(AbstractLinkSession*)> visit);
bool IsBootstrapNode(RouterID) const;
/// check if newRc matches oldRC and update local rc for this remote contact
/// if valid
/// returns true on valid and updated
/// returns false otherwise
bool
CheckRenegotiateValid(RouterContact newRc, RouterContact oldRC);
/// called by link when a remote session has no more sessions open
void
SessionClosed(RouterID remote);
/// called by link when an unestablished connection times out
void
10 months ago
ConnectionTimedOut(AbstractLinkSession* session);
/// called by link when session is fully established
bool
10 months ago
ConnectionEstablished(AbstractLinkSession* session, bool inbound);
/// call internal router ticker
void
Tick();
6 years ago
llarp_time_t
Now() const
{
return llarp::time_now_ms();
}
/// parse a routing message in a buffer and handle it with a handler if
/// successful parsing return true on parse and handle success otherwise
/// return false
bool
ParseRoutingMessageBuffer(
const llarp_buffer_t& buf, routing::AbstractRoutingMessageHandler* h, const PathID_t& rxid);
void
ConnectToRandomRouters(int N);
/// count the number of unique service nodes connected via pubkey
size_t
NumberOfConnectedRouters() const;
/// count the number of unique clients connected by pubkey
size_t
NumberOfConnectedClients() const;
bool
GetRandomConnectedRouter(RouterContact& result) const;
void
HandleDHTLookupForExplore(RouterID remote, const std::vector<RouterContact>& results);
void
LookupRouter(RouterID remote, RouterLookupHandler resultHandler);
bool
HasSessionTo(const RouterID& remote) const;
std::string
ShortName() const;
uint32_t
NextPathBuildNumber();
void
AfterStopLinks();
void
AfterStopIssued();
};
} // namespace llarp