lokinet/llarp/router/router.hpp
Jason Rhinelander af6caf776a
Config file improvements (#1397)
* Config file API/comment improvements

API improvements:
=================

Make the config API use position-independent tag parameters (Required,
Default{123}, MultiValue) rather than a sequence of bools with
overloads.  For example, instead of:

    conf.defineOption<int>("a", "b", false, true, 123, [] { ... });

you now write:

    conf.defineOption<int>("a", "b", MultiValue, Default{123}, [] { ... });

The tags are:
- Required
- MultiValue
- Default{value}
plus new abilities (see below):
- Hidden
- RelayOnly
- ClientOnly
- Comment{"line1", "line2", "line3"}

Made option definition more powerful:
=====================================

- `Hidden` allows you to define an option that won't show up in the
  generated config file if it isn't set.

- `RelayOnly`/`ClientOnly` sets up an option that is only accepted and
  only shows up for relay or client configs.  (If neither is specified
  the option shows up in both modes).

- `Comment{...}` lets the option comments be specified as part of the
  defineOption.

Comment improvements
====================

- Rewrote comments for various options to expand on details.
- Inlined all the comments with the option definitions.
- Several options that were missing comments got comments added.
- Made various options for deprecated and or internal options hidden by
  default so that they don't show up in a default config file.
- show the section comment (but not option comments) *after* the
  [section] tag instead of before it as it makes more sense that way
  (particularly for the [bind] section which has a new long comment to
  describe how it works).

Disable profiling by default
============================

We had this weird state where we use and store profiling by default but
never *load* it when starting up.  This commit makes us just not use
profiling at all unless explicitly enabled.

Other misc changes:
===================

- change default worker threads to 0 (= num cpus) instead of 1, and fix
  it to allow 0.
- Actually apply worker-threads option
- fixed default data-dir value erroneously having quotes around it
- reordered ifname/ifaddr/mapaddr (was previously mapaddr/ifaddr/ifname)
  as mapaddr is a sort of specialization of ifaddr and so makes more
  sense to come after it (particularly because it now references ifaddr
  in its help message).
- removed peer-stats option (since we always require it for relays and
  never use it for clients)
- removed router profiles filename option (this doesn't need to be
  configurable)
- removed defunct `service-node-seed` option
- Change default logging output file to "" (which means stdout), and
  also made "-" work for stdout.

* Router hive compilation fixes

* Comments for SNApp SRV settings in ini file

* Add extra blank line after section comments

* Better deprecated option handling

Allow {client,relay}-only options in {relay,client} configs to be
specified as implicitly deprecated options: they warn, and don't set
anything.

Add an explicit `Deprecated` tag and move deprecated option handling
into definition.cpp.

* Move backwards compat options into section definitions

Keep the "addBackwardsCompatibleConfigOptions" only for options in
sections that no longer exist.

* Fix INI parsing issues & C++17-ify

- don't allow inline comments because it seems they aren't allowed in
ini formats in general, and is going to cause problems if there is a
comment character in a value (e.g. an exit auth string).  Additionally
it was breaking on a line such as:

    # some comment; see?

because it was treating only `; see?` as the comment and then producing
an error message about the rest of the line being invalid.

- make section parsing stricter: the `[` and `]` have to be at the
beginning at end of the line now (after stripping whitespace).

- Move whitespace stripping to the top since everything in here does it.

- chop off string_view suffix/prefix rather than maintaining position
values

- fix potential infinite loop/segfault when given a line such as `]foo[`

* Make config parsing failure fatal

Load() LogError's and returns false on failure, so we weren't aborting
on config file errors.

* Formatting: allow `{}` for empty functions/structs

Instead of using two lines when empty:

    {
    }

* Make default dns bind 127.0.0.1 on non-Linux

* Don't show empty section; fix tests

We can conceivably have sections that only make sense for clients or
relays, and so want to completely omit that section if we have no
options for the type of config being generated.

Also fixes missing empty lines between tests.

Co-authored-by: Thomas Winget <tewinget@gmail.com>
2020-10-07 18:22:58 -04:00

556 lines
12 KiB
C++

#ifndef LLARP_ROUTER_HPP
#define LLARP_ROUTER_HPP
#include <router/abstractrouter.hpp>
#include <bootstrap.hpp>
#include <config/config.hpp>
#include <config/key_manager.hpp>
#include <constants/link_layer.hpp>
#include <crypto/types.hpp>
#include <ev/ev.h>
#include <exit/context.hpp>
#include <handlers/tun.hpp>
#include <link/link_manager.hpp>
#include <link/server.hpp>
#include <messages/link_message_parser.hpp>
#include <nodedb.hpp>
#include <path/path_context.hpp>
#include <peerstats/peer_db.hpp>
#include <profiling.hpp>
#include <router_contact.hpp>
#include <router/outbound_message_handler.hpp>
#include <router/outbound_session_maker.hpp>
#include <router/rc_gossiper.hpp>
#include <router/rc_lookup_handler.hpp>
#include <router/route_poker.hpp>
#include <routing/handler.hpp>
#include <routing/message_parser.hpp>
#include <rpc/lokid_rpc_client.hpp>
#include <rpc/rpc_server.hpp>
#include <service/context.hpp>
#include <stdexcept>
#include <util/buffer.hpp>
#include <util/fs.hpp>
#include <util/mem.hpp>
#include <util/status.hpp>
#include <util/str.hpp>
#include <util/thread/logic.hpp>
#include <util/time.hpp>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
#include <lokimq/address.h>
namespace llarp
{
struct Router : public AbstractRouter
{
llarp_time_t _lastPump = 0s;
bool ready;
// transient iwp encryption key
fs::path transport_keyfile;
// long term identity key
fs::path ident_keyfile;
fs::path encryption_keyfile;
// path to write our self signed rc to
fs::path our_rc_file;
// use file based logging?
bool m_UseFileLogging = false;
// our router contact
RouterContact _rc;
/// should we obey the service node whitelist?
bool whitelistRouters = false;
LMQ_ptr m_lmq;
LMQ_ptr
lmq() const override
{
return m_lmq;
}
std::shared_ptr<rpc::LokidRpcClient>
RpcClient() const override
{
return m_lokidRpcClient;
}
std::shared_ptr<Logic>
logic() const override
{
return _logic;
}
llarp_dht_context*
dht() const override
{
return _dht;
}
util::StatusObject
ExtractStatus() const override;
llarp_nodedb*
nodedb() const override
{
return _nodedb;
}
const path::PathContext&
pathContext() const override
{
return paths;
}
path::PathContext&
pathContext() override
{
return paths;
}
const RouterContact&
rc() const override
{
return _rc;
}
void
SetRouterWhitelist(const std::vector<RouterID> routers) override;
exit::Context&
exitContext() override
{
return _exitContext;
}
std::shared_ptr<KeyManager>
keyManager() const override
{
return m_keyManager;
}
const SecretKey&
identity() const override
{
return _identity;
}
const SecretKey&
encryption() const override
{
return _encryption;
}
Profiling&
routerProfiling() override
{
return _routerProfiling;
}
llarp_ev_loop_ptr
netloop() const override
{
return _netloop;
}
void
QueueWork(std::function<void(void)> func) override;
void
QueueDiskIO(std::function<void(void)> func) override;
IpAddress _ourAddress;
llarp_ev_loop_ptr _netloop;
std::shared_ptr<Logic> _logic;
path::PathContext paths;
exit::Context _exitContext;
SecretKey _identity;
SecretKey _encryption;
llarp_dht_context* _dht = nullptr;
llarp_nodedb* _nodedb;
llarp_time_t _startedAt;
const lokimq::TaggedThreadID m_DiskThread;
llarp_time_t
Uptime() const override;
bool
Sign(Signature& sig, const llarp_buffer_t& buf) const override;
uint16_t m_OutboundPort = 0;
/// 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;
uint32_t ticker_job_id = 0;
LinkMessageParser inbound_link_msg_parser;
routing::InboundMessageParser inbound_routing_msg_parser;
service::Context _hiddenServiceContext;
service::Context&
hiddenServiceContext() override
{
return _hiddenServiceContext;
}
const service::Context&
hiddenServiceContext() const override
{
return _hiddenServiceContext;
}
llarp_time_t _lastTick = 0s;
std::function<void(void)> _onDown;
void
SetDownHook(std::function<void(void)> hook) override
{
_onDown = hook;
}
bool
LooksAlive() const override
{
const llarp_time_t now = Now();
return now <= _lastTick || (now - _lastTick) <= llarp_time_t{30000};
}
/// bootstrap RCs
BootstrapList bootstrapRCList;
bool
ExitEnabled() const
{
return false; // FIXME - have to fix the FIXME because FIXME
throw std::runtime_error("FIXME: this needs to be derived from config");
/*
// TODO: use equal_range ?
auto itr = netConfig.find("exit");
if (itr == netConfig.end())
return false;
return IsTrueValue(itr->second.c_str());
*/
}
RoutePoker&
routePoker() override
{
return m_RoutePoker;
}
RoutePoker m_RoutePoker;
void
PumpLL() override;
NetworkConfig networkConfig;
DnsConfig dnsConfig;
const lokimq::address DefaultRPCBindAddr = lokimq::address::tcp("127.0.0.1", 1190);
bool enableRPCServer = false;
lokimq::address rpcBindAddr = DefaultRPCBindAddr;
std::unique_ptr<rpc::RpcServer> m_RPCServer;
const llarp_time_t _randomStartDelay;
std::shared_ptr<rpc::LokidRpcClient> m_lokidRpcClient;
lokimq::address lokidRPCAddr;
Profiling _routerProfiling;
std::string routerProfilesFile = "profiles.dat";
OutboundMessageHandler _outboundMessageHandler;
OutboundSessionMaker _outboundSessionMaker;
LinkManager _linkManager;
RCLookupHandler _rcLookupHandler;
RCGossiper _rcGossiper;
using Clock_t = std::chrono::steady_clock;
using TimePoint_t = Clock_t::time_point;
TimePoint_t m_NextExploreAt;
IOutboundMessageHandler&
outboundMessageHandler() override
{
return _outboundMessageHandler;
}
IOutboundSessionMaker&
outboundSessionMaker() override
{
return _outboundSessionMaker;
}
ILinkManager&
linkManager() override
{
return _linkManager;
}
I_RCLookupHandler&
rcLookupHandler() override
{
return _rcLookupHandler;
}
std::shared_ptr<PeerDb>
peerDb() override
{
return m_peerDb;
}
void
GossipRCIfNeeded(const RouterContact rc) override;
explicit Router(llarp_ev_loop_ptr __netloop, std::shared_ptr<Logic> logic);
virtual ~Router() override;
bool
HandleRecvLinkMessageBuffer(ILinkSession* from, const llarp_buffer_t& msg) override;
bool
InitOutboundLinks();
bool
GetRandomGoodRouter(RouterID& r) override;
/// initialize us as a service node
/// return true on success
bool
InitServiceNode();
bool
IsRunning() const override;
/// return true if we are running in service node mode
bool
IsServiceNode() const override;
void
Close();
bool
Configure(std::shared_ptr<Config> conf, bool isRouter, llarp_nodedb* nodedb = nullptr) override;
bool
StartRpcServer() override;
bool
Run() override;
/// stop running the router logic gracefully
void
Stop() override;
/// non graceful stop router
void
Die() override;
/// close all sessions and shutdown all links
void
StopLinks();
void
PersistSessionUntil(const RouterID& remote, llarp_time_t until) override;
bool
EnsureIdentity();
bool
EnsureEncryptionKey();
bool
ConnectionToRouterAllowed(const RouterID& router) const override;
void
HandleSaveRC() const;
bool
SaveRC();
/// return true if we are a client with an exit configured
bool
HasClientExit() const;
const byte_t*
pubkey() const override
{
return seckey_topublic(_identity);
}
void
try_connect(fs::path rcfile);
bool
TryConnectAsync(RouterContact rc, uint16_t tries) override;
/// 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 ILinkMessage* msg, SendStatusHandler handler) override;
void
ForEachPeer(std::function<void(const ILinkSession*, bool)> visit, bool randomize = false)
const override;
void
ForEachPeer(std::function<void(ILinkSession*)> visit);
bool IsBootstrapNode(RouterID) const override;
/// 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) override;
/// called by link when a remote session has no more sessions open
void
SessionClosed(RouterID remote) override;
/// called by link when an unestablished connection times out
void
ConnectionTimedOut(ILinkSession* session);
/// called by link when session is fully established
bool
ConnectionEstablished(ILinkSession* session, bool inbound);
/// call internal router ticker
void
Tick();
llarp_time_t
Now() const override
{
return llarp::time_now_ms();
}
/// schedule ticker to call i ms from now
void
ScheduleTicker(llarp_time_t i = 1s);
/// 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::IMessageHandler* h, const PathID_t& rxid) override;
void
ConnectToRandomRouters(int N) override;
/// count the number of unique service nodes connected via pubkey
size_t
NumberOfConnectedRouters() const override;
/// count the number of unique clients connected by pubkey
size_t
NumberOfConnectedClients() const override;
bool
GetRandomConnectedRouter(RouterContact& result) const override;
void
HandleDHTLookupForExplore(RouterID remote, const std::vector<RouterContact>& results) override;
void
LookupRouter(RouterID remote, RouterLookupHandler resultHandler) override;
bool
HasSessionTo(const RouterID& remote) const override;
std::string
ShortName() const override;
uint32_t
NextPathBuildNumber() override;
void
handle_router_ticker();
void
AfterStopLinks();
void
AfterStopIssued();
std::shared_ptr<Config> m_Config;
std::shared_ptr<Config>
GetConfig() const override
{
return m_Config;
}
private:
std::atomic<bool> _stopping;
std::atomic<bool> _running;
bool m_isServiceNode = false;
llarp_time_t m_LastStatsReport = 0s;
std::shared_ptr<llarp::KeyManager> m_keyManager;
std::shared_ptr<PeerDb> m_peerDb;
uint32_t path_build_count = 0;
bool
ShouldReportStats(llarp_time_t now) const;
void
ReportStats();
bool
UpdateOurRC(bool rotateKeys = false);
bool
FromConfig(const Config& conf);
void
MessageSent(const RouterID& remote, SendStatus status);
protected:
virtual void
HandleRouterEvent(tooling::RouterEventPtr event) const override;
virtual bool
disableGossipingRC_TestingOnly()
{
return false;
};
};
} // namespace llarp
#endif