Convert to load config in config loader

pull/669/head
Michael 5 years ago
parent bd78471dae
commit b51f7d8015
No known key found for this signature in database
GPG Key ID: 2D51757B47E2434C

@ -18,11 +18,12 @@ struct llarp_threadpool;
namespace llarp namespace llarp
{ {
class Logic;
struct AbstractRouter;
struct Config; struct Config;
struct Crypto; struct Crypto;
struct CryptoManager; struct CryptoManager;
class Logic; struct MetricsConfig;
struct AbstractRouter;
struct RouterContact; struct RouterContact;
namespace metrics namespace metrics
@ -47,13 +48,8 @@ namespace llarp
std::unique_ptr< metrics::DefaultManagerGuard > m_metricsManager; std::unique_ptr< metrics::DefaultManagerGuard > m_metricsManager;
std::unique_ptr< metrics::PublisherScheduler > m_metricsPublisher; std::unique_ptr< metrics::PublisherScheduler > m_metricsPublisher;
int num_nethreads = 1; int num_nethreads = 1;
bool singleThreaded = false; bool singleThreaded = false;
bool disableMetrics = false;
bool disableMetricLogs = false;
fs::path jsonMetricsPath;
std::string metricTankHost;
std::map< std::string, std::string > metricTags;
std::unique_ptr< Crypto > crypto; std::unique_ptr< Crypto > crypto;
std::unique_ptr< CryptoManager > cryptoManager; std::unique_ptr< CryptoManager > cryptoManager;
@ -111,14 +107,11 @@ namespace llarp
bool bool
ReloadConfig(); ReloadConfig();
void
iter_config(const char *section, const char *key, const char *val);
void void
progress(); progress();
void void
setupMetrics(); setupMetrics(const MetricsConfig &metricsConfig);
std::string configfile; std::string configfile;
std::string pidfile; std::string pidfile;

@ -5,7 +5,10 @@
#include <net/net.hpp> #include <net/net.hpp>
#include <util/fs.hpp> #include <util/fs.hpp>
#include <util/logger.hpp> #include <util/logger.hpp>
#include <util/logger_syslog.hpp>
#include <util/mem.hpp> #include <util/mem.hpp>
#include <util/memfn.hpp>
#include <util/str.hpp>
#include <fstream> #include <fstream>
#include <ios> #include <ios>
@ -13,84 +16,416 @@
namespace llarp namespace llarp
{ {
template < typename Config, typename Section > bool
Section RouterConfig::fromSection(string_view key, string_view val)
find_section(Config &c, const std::string &name, const Section &fallback)
{ {
Section ret; if(key == "netid")
if(c.VisitSection(name.c_str(), {
[&ret](const ConfigParser::Section_t &s) -> bool { if(val.size() <= rc.netID.size())
for(const auto &item : s) {
{ llarp::LogWarn("!!!! you have manually set netid to be '", val,
ret.emplace_back(string_view_string(item.first), "' which does not equal '", Version::LLARP_NET_ID,
string_view_string(item.second)); "' you will run as a different network, good luck "
} "and "
return true; "don't forget: something something MUH traffic "
})) "shape "
return ret; "correlation !!!!");
NetID::DefaultValue() =
NetID(reinterpret_cast< const byte_t * >(std::string(val).c_str()));
// re set netid in our rc
rc.netID = llarp::NetID();
netid.assign(val.begin(), val.end());
}
else
{
llarp::LogError("invalid netid '", val, "', is too long");
}
}
if(key == "max-connections")
{
std::string sVal(val.begin(), val.end());
auto ival = atoi(sVal.c_str());
if(ival > 0)
{
maxConnectedRouters = ival;
LogInfo("max connections set to ", maxConnectedRouters);
}
}
if(key == "min-connections")
{
std::string sVal(val.begin(), val.end());
auto ival = atoi(sVal.c_str());
if(ival > 0)
{
minConnectedRouters = ival;
LogInfo("min connections set to ", minConnectedRouters);
}
}
if(key == "nickname")
{
rc.SetNick(val);
// set logger name here
LogContext::Instance().nodeName = rc.Nick();
}
if(key == "encryption-privkey")
{
encryption_keyfile.assign(val.begin(), val.end());
}
if(key == "contact-file")
{
our_rc_file.assign(val.begin(), val.end());
}
if(key == "transport-privkey")
{
transport_keyfile.assign(val.begin(), val.end());
}
if((key == "identity-privkey" || key == "ident-privkey"))
{
ident_keyfile.assign(val.begin(), val.end());
}
if(key == "public-address" || key == "public-ip")
{
llarp::LogInfo("public ip ", val, " size ", val.size());
if(val.size() < 17)
{
// assume IPv4
llarp::Addr a(val);
llarp::LogInfo("setting public ipv4 ", a);
addrInfo.ip = *a.addr6();
publicOverride = true;
}
// llarp::Addr a(val);
}
if(key == "public-port")
{
llarp::LogInfo("Setting public port ", val);
int p = atoi(std::string(val).c_str());
// Not needed to flip upside-down - this is done in llarp::Addr(const
// AddressInfo&)
ip4addr.sin_port = p;
addrInfo.port = p;
publicOverride = true;
}
if(key == "worker-threads")
{
workerThreads = atoi(std::string(val).c_str());
}
if(key == "net-threads")
{
num_nethreads = atoi(std::string(val).c_str());
if(num_nethreads <= 0)
num_nethreads = 1;
}
return true;
}
bool
NetworkConfig::fromSection(string_view key, string_view val)
{
if(key == "profiling")
{
if(IsTrueValue(val))
{
enableProfiling.emplace(true);
}
else if(IsFalseValue(val))
{
enableProfiling.emplace(false);
}
}
if(key == "profiles")
{
routerProfilesFile.assign(val.begin(), val.end());
llarp::LogInfo("setting profiles to ", routerProfilesFile);
}
else if(key == "strict-connect")
{
strictConnect.assign(val.begin(), val.end());
}
else else
return fallback; {
netConfig.emplace(key, val);
}
return true;
} }
bool bool
Config::Load(const char *fname) NetdbConfig::fromSection(string_view key, string_view val)
{ {
ConfigParser parser; if(key == "dir")
if(!parser.LoadFile(fname))
{ {
return false; nodedb_dir.assign(val.begin(), val.end());
} }
router = find_section(parser, "router", section_t{});
network = find_section(parser, "network", section_t{});
connect = find_section(parser, "connect", section_t{});
netdb = find_section(parser, "netdb", section_t{});
dns = find_section(parser, "dns", section_t{});
iwp_links = find_section(parser, "bind", section_t{});
services = find_section(parser, "services", section_t{});
system = find_section(parser, "system", section_t{});
metrics = find_section(parser, "metrics", section_t{});
api = find_section(parser, "api", section_t{});
lokid = find_section(parser, "lokid", section_t{});
bootstrap = find_section(parser, "bootstrap", section_t{});
logging = find_section(parser, "logging", section_t{});
return true; return true;
} }
void bool
Config::visit(const Visitor &functor) DnsConfig::fromSection(string_view key, string_view val)
{ {
std::unordered_map< std::string, const llarp::Config::section_t & > if(key == "upstream")
sections = {{"network", network}, {
{"connect", connect}, llarp::LogInfo("add upstream resolver ", val);
{"bootstrap", bootstrap}, netConfig.emplace("upstream-dns", val);
{"system", system}, }
{"metrics", metrics}, if(key == "bind")
{"netdb", netdb}, {
{"api", api}, llarp::LogInfo("set local dns to ", val);
{"services", services}}; netConfig.emplace("local-dns", val);
}
auto visitor = [&](const char *name, const auto &item) { return true;
functor(name, item.first.c_str(), item.second.c_str()); }
};
bool
IwpConfig::fromSection(string_view key, string_view val)
{
// try IPv4 first
uint16_t proto = 0;
std::set< std::string > parsed_opts;
std::string v(val.begin(), val.end());
std::string::size_type idx;
do
{
idx = v.find_first_of(',');
if(idx != std::string::npos)
{
parsed_opts.insert(v.substr(0, idx));
v = v.substr(idx + 1);
}
else
{
parsed_opts.insert(v);
}
} while(idx != std::string::npos);
using namespace std::placeholders; /// for each option
for(const auto &item : parsed_opts)
{
/// see if it's a number
auto port = std::atoi(item.c_str());
if(port > 0)
{
/// set port
if(proto == 0)
{
proto = port;
}
}
}
std::for_each(logging.begin(), logging.end(), if(key == "*")
std::bind(visitor, "logging", _1)); {
// end of logging section commit settings and go m_OutboundPort = proto;
functor("logging", "", ""); }
std::for_each(lokid.begin(), lokid.end(), std::bind(visitor, "lokid", _1)); else
std::for_each(router.begin(), router.end(), {
std::bind(visitor, "router", _1)); servers.emplace_back(key, AF_INET, proto);
}
return true;
}
std::for_each(dns.begin(), dns.end(), std::bind(visitor, "dns", _1)); bool
std::for_each(iwp_links.begin(), iwp_links.end(), ConnectConfig::fromSection(ABSL_ATTRIBUTE_UNUSED string_view key,
std::bind(visitor, "bind", _1)); string_view val)
{
routers.emplace_back(val.begin(), val.end());
return true;
}
bool
ServicesConfig::fromSection(string_view key, string_view val)
{
services.emplace_back(std::string(key.begin(), key.end()),
std::string(val.begin(), val.end()));
return true;
}
std::for_each(sections.begin(), sections.end(), [&](const auto &section) { bool
std::for_each(section.second.begin(), section.second.end(), SystemConfig::fromSection(string_view key, string_view val)
std::bind(visitor, section.first.c_str(), _1)); {
}); if(key == "pidfile")
{
pidfile.assign(val.begin(), val.end());
}
return true;
}
bool
MetricsConfig::fromSection(string_view key, string_view val)
{
if(key == "disable-metrics")
{
disableMetrics = true;
}
else if(key == "disable-metrics-log")
{
disableMetricLogs = true;
}
else if(key == "json-metrics-path")
{
jsonMetricsPath.assign(val.begin(), val.end());
}
else if(key == "metric-tank-host")
{
metricTankHost.assign(val.begin(), val.end());
}
else
{
// consume everything else as a metric tag
metricTags[std::string(key)] = std::string(val);
}
return true;
}
bool
ApiConfig::fromSection(string_view key, string_view val)
{
if(key == "enabled")
{
enableRPCServer = IsTrueValue(val);
}
if(key == "bind")
{
rpcBindAddr.assign(val.begin(), val.end());
}
if(key == "authkey")
{
// TODO: add pubkey to whitelist
}
return true;
}
bool
LokidConfig::fromSection(string_view key, string_view val)
{
if(key == "service-node-seed")
{
usingSNSeed = true;
ident_keyfile.assign(val.begin(), val.end());
}
if(key == "enabled")
{
whitelistRouters = IsTrueValue(val);
}
if(key == "jsonrpc" || key == "addr")
{
lokidRPCAddr.assign(val.begin(), val.end());
}
if(key == "username")
{
lokidRPCUser.assign(val.begin(), val.end());
}
if(key == "password")
{
lokidRPCPassword.assign(val.begin(), val.end());
}
return true;
}
bool
BootstrapConfig::fromSection(string_view key, string_view val)
{
if(key == "add-node")
{
routers.emplace_back(val.begin(), val.end());
}
return true;
}
bool
LoggingConfig::fromSection(string_view key, string_view val)
{
if(key == "type" && val == "syslog")
{
// TODO(despair): write event log syslog class
#if defined(_WIN32)
LogError("syslog not supported on win32");
#else
LogInfo("Switching to syslog");
LogContext::Instance().logStream = std::make_unique< SysLogStream >();
#endif
}
if(key == "type" && val == "json")
{
m_LogJSON = true;
}
if(key == "file")
{
LogInfo("open log file: ", val);
std::string fname(val.begin(), val.end());
FILE *const logfile = ::fopen(fname.c_str(), "a");
if(logfile)
{
m_LogFile = logfile;
LogInfo("will log to file ", val);
}
else if(errno)
{
LogError("could not open log file at '", val, "': ", strerror(errno));
errno = 0;
}
else
{
LogError("failed to open log file at '", val,
"' for an unknown reason, bailing tf out kbai");
::abort();
}
}
return true;
}
template < typename Section, typename Config >
Section
find_section(Config &c, const std::string &name)
{
Section ret;
auto visitor = [&ret](const ConfigParser::Section_t &section) -> bool {
for(const auto &sec : section)
{
if(!ret.fromSection(sec.first, sec.second))
{
return false;
}
}
return true;
};
if(c.VisitSection(name.c_str(), visitor))
return ret;
else
return {};
}
bool
Config::Load(const char *fname)
{
ConfigParser parser;
if(!parser.LoadFile(fname))
{
return false;
}
router = find_section< RouterConfig >(parser, "router");
network = find_section< NetworkConfig >(parser, "network");
connect = find_section< ConnectConfig >(parser, "connect");
netdb = find_section< NetdbConfig >(parser, "netdb");
dns = find_section< DnsConfig >(parser, "dns");
iwp_links = find_section< IwpConfig >(parser, "bind");
services = find_section< ServicesConfig >(parser, "services");
system = find_section< SystemConfig >(parser, "system");
metrics = find_section< MetricsConfig >(parser, "metrics");
api = find_section< ApiConfig >(parser, "api");
lokid = find_section< LokidConfig >(parser, "lokid");
bootstrap = find_section< BootstrapConfig >(parser, "bootstrap");
logging = find_section< LoggingConfig >(parser, "logging");
return true;
} }
} // namespace llarp } // namespace llarp

@ -1,6 +1,11 @@
#ifndef LLARP_CONFIG_HPP #ifndef LLARP_CONFIG_HPP
#define LLARP_CONFIG_HPP #define LLARP_CONFIG_HPP
#include <config/ini.hpp>
#include <crypto/types.hpp>
#include <router_contact.hpp>
#include <util/fs.hpp>
#include <functional> #include <functional>
#include <string> #include <string>
#include <utility> #include <utility>
@ -8,32 +13,167 @@
namespace llarp namespace llarp
{ {
struct Config struct RouterConfig
{ {
using section_t = std::vector< std::pair< std::string, std::string > >; /// always maintain this many connections to other routers
size_t minConnectedRouters = 2;
/// hard upperbound limit on the number of router to router connections
size_t maxConnectedRouters = 2000;
std::string netid;
RouterContact rc;
fs::path encryption_keyfile = "encryption.key";
section_t router; // path to write our self signed rc to
section_t network; fs::path our_rc_file = "rc.signed";
section_t netdb;
section_t dns; // transient iwp encryption key
section_t iwp_links; fs::path transport_keyfile = "transport.key";
section_t connect;
section_t services; // long term identity key
section_t system; fs::path ident_keyfile = "identity.key";
section_t metrics;
section_t api; bool publicOverride = false;
section_t lokid; struct sockaddr_in ip4addr;
section_t bootstrap; AddressInfo addrInfo;
section_t logging;
int workerThreads;
int num_nethreads;
bool bool
Load(const char *fname); fromSection(string_view key, string_view val);
};
struct NetworkConfig
{
absl::optional< bool > enableProfiling;
std::string routerProfilesFile = "profiles.dat";
std::string strictConnect;
std::unordered_multimap< std::string, std::string > netConfig;
bool
fromSection(string_view key, string_view val);
};
struct NetdbConfig
{
std::string nodedb_dir;
bool
fromSection(string_view key, string_view val);
};
struct DnsConfig
{
std::unordered_multimap< std::string, std::string > netConfig;
bool
fromSection(string_view key, string_view val);
};
struct IwpConfig
{
uint16_t m_OutboundPort = 0;
std::vector< std::tuple< std::string, int, uint16_t > > servers;
bool
fromSection(string_view key, string_view val);
};
struct ConnectConfig
{
std::vector< std::string > routers;
bool
fromSection(string_view key, string_view val);
};
using Visitor = std::function< void(const char *section, const char *key, struct ServicesConfig
const char *val) >; {
std::vector< std::pair< std::string, std::string > > services;
bool
fromSection(string_view key, string_view val);
};
struct SystemConfig
{
std::string pidfile;
bool
fromSection(string_view key, string_view val);
};
struct MetricsConfig
{
bool disableMetrics = false;
bool disableMetricLogs = false;
fs::path jsonMetricsPath;
std::string metricTankHost;
std::map< std::string, std::string > metricTags;
void bool
visit(const Visitor &visitor); fromSection(string_view key, string_view val);
};
struct ApiConfig
{
bool enableRPCServer = false;
std::string rpcBindAddr;
bool
fromSection(string_view key, string_view val);
};
struct LokidConfig
{
bool usingSNSeed = false;
bool whitelistRouters = false;
fs::path ident_keyfile = "identity.key";
std::string lokidRPCAddr = "127.0.0.1:22023";
std::string lokidRPCUser;
std::string lokidRPCPassword;
bool
fromSection(string_view key, string_view val);
};
struct BootstrapConfig
{
std::vector< std::string > routers;
bool
fromSection(string_view key, string_view val);
};
struct LoggingConfig
{
bool m_LogJSON = false;
FILE *m_LogFile = stdout;
bool
fromSection(string_view key, string_view val);
};
struct Config
{
RouterConfig router;
NetworkConfig network;
ConnectConfig connect;
NetdbConfig netdb;
DnsConfig dns;
IwpConfig iwp_links;
ServicesConfig services;
SystemConfig system;
MetricsConfig metrics;
ApiConfig api;
LokidConfig lokid;
BootstrapConfig bootstrap;
LoggingConfig logging;
bool
Load(const char *fname);
}; };
} // namespace llarp } // namespace llarp

@ -12,10 +12,11 @@
namespace llarp namespace llarp
{ {
bool bool
ConfigParser::LoadFile(const char* fname) ConfigParser::LoadFile(string_view fname)
{ {
std::string name{fname};
{ {
std::ifstream f(fname, std::ios::in | std::ios::binary); std::ifstream f(name, std::ios::in | std::ios::binary);
if(!f.is_open()) if(!f.is_open())
return false; return false;
f.seekg(0, std::ios::end); f.seekg(0, std::ios::end);
@ -25,12 +26,12 @@ namespace llarp
return false; return false;
f.read(m_Data.data(), m_Data.size()); f.read(m_Data.data(), m_Data.size());
} }
m_FileName = fname; m_FileName = name;
return Parse(); return Parse();
} }
bool bool
ConfigParser::LoadString(const std::string& str) ConfigParser::LoadString(string_view str)
{ {
m_Data.resize(str.size()); m_Data.resize(str.size());
std::copy(str.begin(), str.end(), m_Data.begin()); std::copy(str.begin(), str.end(), m_Data.begin());

@ -25,13 +25,13 @@ namespace llarp
/// return true on success /// return true on success
/// return false on error /// return false on error
bool bool
LoadFile(const char* fname); LoadFile(string_view fname);
/// load from string /// load from string
/// return true on success /// return true on success
/// return false on error /// return false on error
bool bool
LoadString(const std::string& str); LoadString(string_view str);
/// iterate all sections and thier values /// iterate all sections and thier values
void void

@ -52,92 +52,49 @@ namespace llarp
llarp::LogError("failed to load config file ", configfile); llarp::LogError("failed to load config file ", configfile);
return false; return false;
} }
config->visit(util::memFn(&Context::iter_config, this));
if(!disableMetrics) // System config
if(!config->system.pidfile.empty())
{ {
setupMetrics(); SetPIDFile(config->system.pidfile);
if(!disableMetricLogs)
{
m_metricsManager->instance()->addGlobalPublisher(
std::make_shared< metrics::StreamPublisher >(std::cerr));
}
} }
return true;
}
void // Router config
Context::iter_config(const char *section, const char *key, const char *val) if(!singleThreaded && config->router.workerThreads > 0 && !worker)
{
if(!strcmp(section, "system"))
{ {
if(!strcmp(key, "pidfile")) worker.reset(
{ llarp_init_threadpool(config->router.workerThreads, "llarp-worker"));
SetPIDFile(val);
}
} }
if(!strcmp(section, "metrics"))
if(singleThreaded)
{ {
if(!strcmp(key, "disable-metrics")) num_nethreads = 0;
{
disableMetrics = true;
}
else if(!strcmp(key, "disable-metrics-log"))
{
disableMetricLogs = true;
}
else if(!strcmp(key, "json-metrics-path"))
{
jsonMetricsPath = val;
}
else if(!strcmp(key, "metric-tank-host"))
{
metricTankHost = val;
}
else
{
// consume everything else as a metric tag
metricTags[key] = val;
}
} }
if(!strcmp(section, "router")) else
{ {
if(!strcmp(key, "worker-threads") && !singleThreaded) num_nethreads = config->router.num_nethreads;
{
int workers = atoi(val);
if(workers > 0 && worker == nullptr)
{
worker.reset(llarp_init_threadpool(workers, "llarp-worker"));
}
}
else if(!strcmp(key, "net-threads"))
{
num_nethreads = atoi(val);
if(num_nethreads <= 0)
num_nethreads = 1;
if(singleThreaded)
num_nethreads = 0;
}
else if(!strcmp(key, "netid"))
{
metricTags["netid"] = val;
}
else if(!strcmp(key, "nickname"))
{
metricTags["nickname"] = val;
}
} }
if(!strcmp(section, "netdb"))
nodedb_dir = config->netdb.nodedb_dir;
if(!config->metrics.disableMetrics)
{ {
if(!strcmp(key, "dir")) auto &metricsConfig = config->metrics;
auto &tags = metricsConfig.metricTags;
tags["netid"] = config->router.netid;
tags["nickname"] = config->router.rc.Nick();
setupMetrics(metricsConfig);
if(!config->metrics.disableMetricLogs)
{ {
nodedb_dir = val; m_metricsManager->instance()->addGlobalPublisher(
std::make_shared< metrics::StreamPublisher >(std::cerr));
} }
} }
return true;
} }
void void
Context::setupMetrics() Context::setupMetrics(const MetricsConfig &metricsConfig)
{ {
if(!m_scheduler) if(!m_scheduler)
{ {
@ -153,15 +110,15 @@ namespace llarp
*m_scheduler, m_metricsManager->instance()); *m_scheduler, m_metricsManager->instance());
} }
if(!jsonMetricsPath.native().empty()) if(!metricsConfig.jsonMetricsPath.native().empty())
{ {
m_metricsManager->instance()->addGlobalPublisher( m_metricsManager->instance()->addGlobalPublisher(
std::make_shared< metrics::JsonPublisher >( std::make_shared< metrics::JsonPublisher >(
std::bind(&metrics::JsonPublisher::directoryPublisher, std::bind(&metrics::JsonPublisher::directoryPublisher,
std::placeholders::_1, jsonMetricsPath))); std::placeholders::_1, metricsConfig.jsonMetricsPath)));
} }
if(!metricTankHost.empty()) if(!metricsConfig.metricTankHost.empty())
{ {
if(std::getenv("LOKINET_ENABLE_METRIC_TANK")) if(std::getenv("LOKINET_ENABLE_METRIC_TANK"))
{ {
@ -186,11 +143,11 @@ __ ___ ____ _ _ ___ _ _ ____
std::cerr << WARNING << '\n'; std::cerr << WARNING << '\n';
std::pair< std::string, std::string > split = std::pair< std::string, std::string > split =
absl::StrSplit(metricTankHost, ':'); absl::StrSplit(metricsConfig.metricTankHost, ':');
m_metricsManager->instance()->addGlobalPublisher( m_metricsManager->instance()->addGlobalPublisher(
std::make_shared< metrics::MetricTankPublisher >( std::make_shared< metrics::MetricTankPublisher >(
metricTags, split.first, stoi(split.second))); metricsConfig.metricTags, split.first, stoi(split.second)));
} }
else else
{ {

@ -104,7 +104,7 @@ namespace llarp
return false; return false;
} }
else if(!GetIFAddr(ifname, m_ourAddr, af)) else if(!GetIFAddr(ifname, m_ourAddr, af))
m_ourAddr = ifname; m_ourAddr = Addr(ifname);
m_ourAddr.port(port); m_ourAddr.port(port);
return llarp_ev_add_udp(m_Loop.get(), &m_udp, m_ourAddr) != -1; return llarp_ev_add_udp(m_Loop.get(), &m_udp, m_ourAddr) != -1;
} }

@ -63,14 +63,14 @@ namespace llarp
return (const in_addr*)&_addr.sin6_addr.s6_addr[12]; return (const in_addr*)&_addr.sin6_addr.s6_addr[12];
} }
Addr::Addr(const std::string str) Addr::Addr(string_view str)
{ {
this->from_char_array(str.c_str()); this->from_char_array(str);
} }
Addr::Addr(const std::string str, const uint16_t p_port) Addr::Addr(string_view str, const uint16_t p_port)
{ {
this->from_char_array(str.c_str()); this->from_char_array(str);
this->port(p_port); this->port(p_port);
} }
@ -81,25 +81,17 @@ namespace llarp
} }
bool bool
Addr::from_char_array(const char* in) Addr::from_char_array(string_view in)
{ {
char* str = (char*)in; auto str = in.begin();
char* pPosition = strchr(str, ':'); auto pPosition = in.find(':');
bool freeStr = false; if(pPosition != string_view::npos)
if(pPosition)
{ {
// parse port // parse port
char buf[6]; uint16_t port =
snprintf(buf, 6, "%s", pPosition + 1); std::atoi(std::string(in.begin() + pPosition + 1, in.end()).c_str());
uint16_t port = std::atoi(buf);
LogDebug("Setting port ", std::to_string(port)); LogDebug("Setting port ", std::to_string(port));
this->port(port); this->port(port);
// trim str
// can't VLA
str = strdup(in); // copy it
str[pPosition - in] = '\0'; // nul terminate it early
LogDebug("Truncating to ", str);
freeStr = true;
} }
Zero(&_addr, sizeof(sockaddr_in6)); Zero(&_addr, sizeof(sockaddr_in6));
struct addrinfo hint, *res = NULL; struct addrinfo hint, *res = NULL;
@ -110,27 +102,30 @@ namespace llarp
hint.ai_family = PF_UNSPEC; hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST; hint.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(str, NULL, &hint, &res); if(pPosition != string_view::npos)
{
ret = getaddrinfo(std::string(in.begin(), in.begin() + pPosition).c_str(),
NULL, &hint, &res);
}
else
{
ret = getaddrinfo(std::string(in).c_str(), NULL, &hint, &res);
}
if(ret) if(ret)
{ {
LogError("failed to determine address family: ", str); LogError("failed to determine address family: ", str);
if(freeStr)
free(str);
return false; return false;
} }
if(res->ai_family == AF_INET6) if(res->ai_family == AF_INET6)
{ {
LogError("IPv6 address not supported yet", str); LogError("IPv6 address not supported yet", str);
if(freeStr)
free(str);
return false; return false;
} }
else if(res->ai_family != AF_INET) else if(res->ai_family != AF_INET)
{ {
LogError("Address family not supported yet", str); LogError("Address family not supported yet", str);
if(freeStr)
free(str);
return false; return false;
} }
@ -139,12 +134,8 @@ namespace llarp
if(inet_aton(str, addr) == 0) if(inet_aton(str, addr) == 0)
{ {
LogError("failed to parse ", str); LogError("failed to parse ", str);
if(freeStr)
free(str);
return false; return false;
} }
if(freeStr)
free(str);
_addr.sin6_family = res->ai_family; _addr.sin6_family = res->ai_family;
_addr4.sin_family = res->ai_family; _addr4.sin_family = res->ai_family;
@ -162,11 +153,6 @@ namespace llarp
return true; return true;
} }
Addr::Addr(const char* str)
{
this->from_char_array(str);
}
bool bool
Addr::from_4int(const uint8_t one, const uint8_t two, const uint8_t three, Addr::from_4int(const uint8_t one, const uint8_t two, const uint8_t three,
const uint8_t four) const uint8_t four)

@ -23,6 +23,12 @@ namespace llarp
Addr(const Addr& other); Addr(const Addr& other);
Addr(string_view str);
Addr(string_view str, const uint16_t p_port);
Addr(string_view addr_str, string_view port_str);
void void
port(uint16_t port); port(uint16_t port);
@ -38,16 +44,8 @@ namespace llarp
const in_addr* const in_addr*
addr4() const; addr4() const;
Addr(const std::string str);
Addr(const std::string str, const uint16_t p_port);
Addr(string_view addr_str, string_view port_str);
bool bool
from_char_array(const char* str); from_char_array(string_view str);
Addr(const char* str);
bool bool
from_4int(const uint8_t one, const uint8_t two, const uint8_t three, from_4int(const uint8_t one, const uint8_t two, const uint8_t three,

@ -464,7 +464,8 @@ namespace llarp
bool bool
Router::Configure(Config *conf) Router::Configure(Config *conf)
{ {
conf->visit(util::memFn(&Router::router_iter_config, this)); fromConfig(conf);
if(!InitOutboundLinks()) if(!InitOutboundLinks())
return false; return false;
if(!Ready()) if(!Ready())
@ -766,260 +767,138 @@ namespace llarp
} }
void void
Router::router_iter_config(const char *section, const char *key, Router::fromConfig(Config *conf)
const char *val)
{ {
llarp::LogDebug(section, " ", key, "=", val); // IWP config
m_OutboundPort = conf->iwp_links.m_OutboundPort;
int af; for(const auto &serverConfig : conf->iwp_links.servers)
uint16_t proto = 0;
std::set< std::string > opts;
if(StrEq(val, "eth"))
{
#ifdef AF_LINK
af = AF_LINK;
#endif
#ifdef AF_PACKET
af = AF_PACKET;
#endif
proto = LLARP_ETH_PROTO;
}
else if(StrEq(section, "bind"))
{ {
// try IPv4 first auto server = llarp::utp::NewServerFromRouter(this);
af = AF_INET; if(!server->EnsureKeys(transport_keyfile.string().c_str()))
std::set< std::string > parsed_opts;
std::string v = val;
std::string::size_type idx;
do
{ {
idx = v.find_first_of(','); llarp::LogError("failed to ensure keyfile ", transport_keyfile);
if(idx != std::string::npos) return;
{ }
parsed_opts.insert(v.substr(0, idx));
v = v.substr(idx + 1);
}
else
parsed_opts.insert(v);
} while(idx != std::string::npos);
/// for each option const auto &key = std::get< 0 >(serverConfig);
for(const auto &item : parsed_opts) int af = std::get< 1 >(serverConfig);
uint16_t port = std::get< 2 >(serverConfig);
if(server->Configure(netloop(), key, af, port))
{ {
/// see if it's a number AddLink(std::move(server), true);
auto port = std::atoi(item.c_str()); return;
if(port > 0)
{
/// set port
if(proto == 0)
proto = port;
} /// otherwise add to opts
else
opts.insert(item);
} }
LogError("failed to bind inbound link on ", key, " port ", port);
} }
if(StrEq(section, "bind")) // Network config
if(conf->network.enableProfiling.has_value())
{ {
if(StrEq(key, "*")) if(conf->network.enableProfiling.value())
{ {
m_OutboundPort = proto; routerProfiling().Enable();
LogInfo("router profiling explicitly enabled");
} }
else else
{ {
auto server = llarp::utp::NewServerFromRouter(this); routerProfiling().Disable();
if(!server->EnsureKeys(transport_keyfile.string().c_str())) LogInfo("router profiling explicitly disabled");
{
llarp::LogError("failed to ensure keyfile ", transport_keyfile);
return;
}
if(server->Configure(netloop(), key, af, proto))
{
AddLink(std::move(server), true);
return;
}
LogError("failed to bind inbound link on ", key, " port ", proto);
} }
} }
else if(StrEq(section, "network"))
if(!conf->network.routerProfilesFile.empty())
{
routerProfilesFile = conf->network.routerProfilesFile;
routerProfiling().Load(routerProfilesFile.c_str());
llarp::LogInfo("setting profiles to ", routerProfilesFile);
}
if(!conf->network.strictConnect.empty())
{ {
if(StrEq(key, "profiling")) const auto &val = conf->network.strictConnect;
if(IsServiceNode())
{ {
if(IsTrueValue(val)) llarp::LogError("cannot use strict-connect option as service node");
{ return;
routerProfiling().Enable();
LogInfo("router profiling explicitly enabled");
}
else if(IsFalseValue(val))
{
routerProfiling().Disable();
LogInfo("router profiling explicitly disabled");
}
} }
if(StrEq(key, "profiles")) llarp::RouterID snode;
llarp::PubKey pk;
if(pk.FromString(val))
{ {
routerProfilesFile = val; if(strictConnectPubkeys.emplace(pk).second)
routerProfiling().Load(val); llarp::LogInfo("added ", pk, " to strict connect list");
llarp::LogInfo("setting profiles to ", routerProfilesFile); else
llarp::LogWarn("duplicate key for strict connect: ", pk);
} }
else if(StrEq(key, "strict-connect")) else if(snode.FromString(val))
{ {
if(IsServiceNode()) if(strictConnectPubkeys.insert(snode).second)
{ {
llarp::LogError("cannot use strict-connect option as service node"); llarp::LogInfo("added ", snode, " to strict connect list");
return; netConfig.emplace("strict-connect", val);
}
llarp::RouterID snode;
llarp::PubKey pk;
if(pk.FromString(val))
{
if(strictConnectPubkeys.emplace(pk).second)
llarp::LogInfo("added ", pk, " to strict connect list");
else
llarp::LogWarn("duplicate key for strict connect: ", pk);
}
else if(snode.FromString(val))
{
if(strictConnectPubkeys.insert(snode).second)
{
llarp::LogInfo("added ", snode, " to strict connect list");
netConfig.emplace(key, val);
}
else
llarp::LogWarn("duplicate key for strict connect: ", snode);
} }
else else
llarp::LogError("invalid key for strict-connect: ", val); llarp::LogWarn("duplicate key for strict connect: ", snode);
} }
else else
{ llarp::LogError("invalid key for strict-connect: ", val);
netConfig.emplace(key, val);
}
}
else if(StrEq(section, "api"))
{
if(StrEq(key, "enabled"))
{
enableRPCServer = IsTrueValue(val);
}
if(StrEq(key, "bind"))
{
rpcBindAddr = val;
}
if(StrEq(key, "authkey"))
{
// TODO: add pubkey to whitelist
}
} }
else if(StrEq(section, "services"))
// API config
enableRPCServer = conf->api.enableRPCServer;
rpcBindAddr = conf->api.rpcBindAddr;
// Services config
for(const auto &service : conf->services.services)
{ {
if(LoadHiddenServiceConfig(val)) if(LoadHiddenServiceConfig(service.second))
{ {
llarp::LogInfo("loaded hidden service config for ", key); llarp::LogInfo("loaded hidden service config for ", service.first);
} }
else else
{ {
llarp::LogWarn("failed to load hidden service config for ", key); llarp::LogWarn("failed to load hidden service config for ",
service.first);
} }
} }
else if(StrEq(section, "logging"))
{ // Logging config
if(strlen(key) == 0 && strlen(val) == 0)
{ auto logfile = conf->logging.m_LogFile;
if(m_LogJSON)
{ if(conf->logging.m_LogJSON)
LogContext::Instance().logStream = std::make_unique< JSONLogStream >(
diskworker(), m_LogFile, 100, m_LogFile != stdout);
}
else if(m_LogFile != stdout)
{
LogContext::Instance().logStream = std::make_unique< FileLogStream >(
diskworker(), m_LogFile, 100, true);
}
}
if(StrEq(key, "type") && StrEq(val, "syslog"))
{
// TODO(despair): write event log syslog class
#if defined(_WIN32)
LogError("syslog not supported on win32");
#else
LogInfo("Switching to syslog");
LogContext::Instance().logStream = std::make_unique< SysLogStream >();
#endif
}
if(StrEq(key, "type") && StrEq(val, "json"))
{
m_LogJSON = true;
}
if(StrEq(key, "file"))
{
LogInfo("open log file: ", val);
FILE *const logfile = ::fopen(val, "a");
if(logfile)
{
m_LogFile = logfile;
LogInfo("will log to file ", val);
}
else if(errno)
{
LogError("could not open log file at '", val, "': ", strerror(errno));
errno = 0;
}
else
{
LogError("failed to open log file at '", val,
"' for an unknown reason, bailing tf out kbai");
::abort();
}
}
}
else if(StrEq(section, "lokid"))
{ {
if(StrEq(key, "service-node-seed")) LogContext::Instance().logStream = std::make_unique< JSONLogStream >(
{ diskworker(), logfile, 100, logfile != stdout);
usingSNSeed = true;
ident_keyfile = val;
}
if(StrEq(key, "enabled"))
{
whitelistRouters = IsTrueValue(val);
}
if(StrEq(key, "jsonrpc") || StrEq(key, "addr"))
{
lokidRPCAddr = val;
}
if(StrEq(key, "username"))
{
lokidRPCUser = val;
}
if(StrEq(key, "password"))
{
lokidRPCPassword = val;
}
} }
else if(StrEq(section, "dns")) else if(logfile != stdout)
{ {
if(StrEq(key, "upstream")) LogContext::Instance().logStream =
{ std::make_unique< FileLogStream >(diskworker(), logfile, 100, true);
llarp::LogInfo("add upstream resolver ", val);
netConfig.emplace("upstream-dns", val);
}
if(StrEq(key, "bind"))
{
llarp::LogInfo("set local dns to ", val);
netConfig.emplace("local-dns", val);
}
} }
else if(StrEq(section, "connect")
|| (StrEq(section, "bootstrap") && StrEq(key, "add-node"))) // Lokid Config
usingSNSeed = conf->lokid.usingSNSeed;
ident_keyfile = conf->lokid.ident_keyfile;
whitelistRouters = conf->lokid.whitelistRouters;
lokidRPCAddr = conf->lokid.lokidRPCAddr;
lokidRPCUser = conf->lokid.lokidRPCUser;
lokidRPCPassword = conf->lokid.lokidRPCPassword;
netConfig.insert(conf->dns.netConfig.begin(), conf->dns.netConfig.end());
std::vector< std::string > configRouters = conf->connect.routers;
configRouters.insert(configRouters.end(), conf->bootstrap.routers.begin(),
conf->bootstrap.routers.end());
for(const auto &router : configRouters)
{ {
// llarp::LogDebug("connect section has ", key, "=", val); // llarp::LogDebug("connect section has ", key, "=", val);
RouterContact rc; RouterContact rc;
if(!rc.Read(val)) if(!rc.Read(router.c_str()))
{ {
llarp::LogWarn("failed to decode bootstrap RC, file='", val, llarp::LogWarn("failed to decode bootstrap RC, file='", router,
"' rc=", rc); "' rc=", rc);
;
return; return;
} }
if(rc.Verify(Now())) if(rc.Verify(Now()))
@ -1039,98 +918,25 @@ namespace llarp
} }
else else
{ {
llarp::LogError("malformed rc file='", val, "' rc=", rc); llarp::LogError("malformed rc file='", router, "' rc=", rc);
} }
} }
} }
else if(StrEq(section, "router"))
// Router config
_rc = conf->router.rc;
maxConnectedRouters = conf->router.maxConnectedRouters;
minConnectedRouters = conf->router.minConnectedRouters;
encryption_keyfile = conf->router.encryption_keyfile;
our_rc_file = conf->router.our_rc_file;
transport_keyfile = conf->router.transport_keyfile;
addrInfo = conf->router.addrInfo;
publicOverride = conf->router.publicOverride;
ip4addr = conf->router.ip4addr;
if(!usingSNSeed)
{ {
if(StrEq(key, "netid")) ident_keyfile = conf->router.ident_keyfile;
{
if(strlen(val) <= _rc.netID.size())
{
llarp::LogWarn("!!!! you have manually set netid to be '", val,
"' which does not equal '", Version::LLARP_NET_ID,
"' you will run as a different network, good luck "
"and "
"don't forget: something something MUH traffic "
"shape "
"correlation !!!!");
llarp::NetID::DefaultValue() =
llarp::NetID(reinterpret_cast< const byte_t * >(strdup(val)));
// re set netid in our rc
_rc.netID = llarp::NetID();
}
else
llarp::LogError("invalid netid '", val, "', is too long");
}
if(StrEq(key, "max-connections"))
{
auto ival = atoi(val);
if(ival > 0)
{
maxConnectedRouters = ival;
LogInfo("max connections set to ", maxConnectedRouters);
}
}
if(StrEq(key, "min-connections"))
{
auto ival = atoi(val);
if(ival > 0)
{
minConnectedRouters = ival;
LogInfo("min connections set to ", minConnectedRouters);
}
}
if(StrEq(key, "nickname"))
{
_rc.SetNick(val);
// set logger name here
LogContext::Instance().nodeName = rc().Nick();
}
if(StrEq(key, "encryption-privkey"))
{
encryption_keyfile = val;
}
if(StrEq(key, "contact-file"))
{
our_rc_file = val;
}
if(StrEq(key, "transport-privkey"))
{
transport_keyfile = val;
}
if((StrEq(key, "identity-privkey") || StrEq(key, "ident-privkey"))
&& !usingSNSeed)
{
ident_keyfile = val;
}
if(StrEq(key, "public-address") || StrEq(key, "public-ip"))
{
llarp::LogInfo("public ip ", val, " size ", strlen(val));
if(strlen(val) < 17)
{
// assume IPv4
// inet_pton(AF_INET, val, &ip4addr.sin_addr);
// struct sockaddr dest;
// sockaddr *dest = (sockaddr *)&ip4addr;
llarp::Addr a(val);
llarp::LogInfo("setting public ipv4 ", a);
addrInfo.ip = *a.addr6();
publicOverride = true;
}
// llarp::Addr a(val);
}
if(StrEq(key, "public-port"))
{
llarp::LogInfo("Setting public port ", val);
int p = atoi(val);
// Not needed to flip upside-down - this is done in llarp::Addr(const
// AddressInfo&)
ip4addr.sin_port = p;
addrInfo.port = p;
publicOverride = true;
}
} }
} }
@ -1966,58 +1772,10 @@ namespace llarp
return _exitContext.AddExitEndpoint("default-connectivity", netConfig); return _exitContext.AddExitEndpoint("default-connectivity", netConfig);
} }
/// validate a new configuration against an already made and running
/// router
struct RouterConfigValidator
{
void
ValidateEntry(const char *section, const char *key, const char *val)
{
if(valid)
{
if(!OnEntry(section, key, val))
{
LogError("invalid entry in section [", section, "]: '", key, "'='",
val, "'");
valid = false;
}
}
}
const Router *router;
Config *config;
bool valid;
RouterConfigValidator(const Router *r, Config *conf)
: router(r), config(conf), valid(true)
{
}
/// checks the (section, key, value) config tuple
/// return false if that entry conflicts
/// with existing configuration in router
bool
OnEntry(const char *, const char *, const char *) const
{
// TODO: implement me
return true;
}
/// do validation
/// return true if this config is valid
/// return false if this config is not valid
bool
Validate()
{
config->visit(util::memFn(&RouterConfigValidator::ValidateEntry, this));
return valid;
}
};
bool bool
Router::ValidateConfig(Config *conf) const Router::ValidateConfig(ABSL_ATTRIBUTE_UNUSED Config *conf) const
{ {
RouterConfigValidator validator(this, conf); return true;
return validator.Validate();
} }
bool bool
@ -2095,7 +1853,7 @@ namespace llarp
} }
bool bool
Router::LoadHiddenServiceConfig(const char *fname) Router::LoadHiddenServiceConfig(string_view fname)
{ {
LogDebug("opening hidden service config ", fname); LogDebug("opening hidden service config ", fname);
service::Config conf; service::Config conf;

@ -265,11 +265,10 @@ namespace llarp
std::string rpcBindAddr = DefaultRPCBindAddr; std::string rpcBindAddr = DefaultRPCBindAddr;
/// lokid caller /// lokid caller
const std::string DefaultLokidRPCAddr = "127.0.0.1:22023";
std::unique_ptr< rpc::Caller > rpcCaller; std::unique_ptr< rpc::Caller > rpcCaller;
std::string lokidRPCAddr = DefaultLokidRPCAddr; std::string lokidRPCAddr = "127.0.0.1:22023";
std::string lokidRPCUser = ""; std::string lokidRPCUser;
std::string lokidRPCPassword = ""; std::string lokidRPCPassword;
using LinkSet = std::set< LinkLayer_ptr, ComparePtr< LinkLayer_ptr > >; using LinkSet = std::set< LinkLayer_ptr, ComparePtr< LinkLayer_ptr > >;
@ -305,11 +304,6 @@ namespace llarp
// set to max value right now // set to max value right now
std::unordered_map< RouterID, llarp_time_t, PubKey::Hash > lokinetRouters; std::unordered_map< RouterID, llarp_time_t, PubKey::Hash > lokinetRouters;
// set to true if we are configured to run with json logging
bool m_LogJSON = false;
// the file we are logging to
FILE *m_LogFile = stdout;
Router(struct llarp_threadpool *tp, llarp_ev_loop_ptr __netloop, Router(struct llarp_threadpool *tp, llarp_ev_loop_ptr __netloop,
std::shared_ptr< Logic > logic); std::shared_ptr< Logic > logic);
@ -344,7 +338,7 @@ namespace llarp
Close(); Close();
bool bool
LoadHiddenServiceConfig(const char *fname); LoadHiddenServiceConfig(string_view fname);
bool bool
AddHiddenService(const service::Config::section_t &config); AddHiddenService(const service::Config::section_t &config);
@ -572,7 +566,7 @@ namespace llarp
} }
void void
router_iter_config(const char *section, const char *key, const char *val); fromConfig(Config *conf);
}; };
} // namespace llarp } // namespace llarp

@ -223,7 +223,7 @@ namespace llarp
} }
void void
RouterContact::SetNick(const std::string &nick) RouterContact::SetNick(string_view nick)
{ {
nickname.Zero(); nickname.Zero();
std::copy(nick.begin(), std::copy(nick.begin(),

@ -162,7 +162,7 @@ namespace llarp
IsPublicRouter() const; IsPublicRouter() const;
void void
SetNick(const std::string &nick); SetNick(string_view nick);
bool bool
Verify(llarp_time_t now, bool allowExpired = true) const; Verify(llarp_time_t now, bool allowExpired = true) const;

@ -7,10 +7,10 @@ namespace llarp
namespace service namespace service
{ {
bool bool
Config::Load(const std::string& fname) Config::Load(string_view fname)
{ {
ConfigParser parser; ConfigParser parser;
if(!parser.LoadFile(fname.c_str())) if(!parser.LoadFile(fname))
return false; return false;
parser.IterAll([&](const ConfigParser::String_t& name, parser.IterAll([&](const ConfigParser::String_t& name,
const ConfigParser::Section_t& section) { const ConfigParser::Section_t& section) {

@ -1,5 +1,8 @@
#ifndef LLARP_SERVICE_CONFIG_HPP #ifndef LLARP_SERVICE_CONFIG_HPP
#define LLARP_SERVICE_CONFIG_HPP #define LLARP_SERVICE_CONFIG_HPP
#include <util/string_view.hpp>
#include <list> #include <list>
#include <string> #include <string>
@ -16,7 +19,7 @@ namespace llarp
std::list< section_t > services; std::list< section_t > services;
bool bool
Load(const std::string& fname); Load(string_view fname);
}; };
} // namespace service } // namespace service
} // namespace llarp } // namespace llarp

@ -3,25 +3,61 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <set>
namespace llarp namespace llarp
{ {
struct CaselessCmp
{
bool
operator()(string_view lhs, string_view rhs) const
{
if(lhs.size() < rhs.size())
{
return true;
}
else if(lhs.size() > rhs.size())
{
return false;
}
else
{
for(size_t i = 0; i < lhs.size(); ++i)
{
auto l = std::tolower(lhs[i]);
auto r = std::tolower(rhs[i]);
if(l < r)
{
return true;
}
else if(l > r)
{
return false;
}
}
}
return true;
}
};
bool bool
IsFalseValue(const char* str) IsFalseValue(string_view str)
{ {
std::string value = str; static const std::set< string_view, CaselessCmp > vals{"no", "false", "0",
std::transform(value.begin(), value.end(), value.begin(), "off"};
[](char ch) -> char { return std::tolower(ch); });
return value == "no" || value == "false" || value == "0" || value == "off"; return vals.count(str) > 0;
} }
bool bool
IsTrueValue(const char* str) IsTrueValue(string_view str)
{ {
std::string value = str; static const std::set< string_view, CaselessCmp > vals{"yes", "true", "1",
std::transform(value.begin(), value.end(), value.begin(), "on"};
[](char ch) -> char { return std::tolower(ch); });
return value == "yes" || value == "true" || value == "1" || value == "on"; return vals.count(str) > 0;
} }
bool bool

@ -1,16 +1,18 @@
#ifndef LLARP_STR_HPP #ifndef LLARP_STR_HPP
#define LLARP_STR_HPP #define LLARP_STR_HPP
#include <util/string_view.hpp>
namespace llarp namespace llarp
{ {
bool bool
StrEq(const char *s1, const char *s2); StrEq(const char *s1, const char *s2);
bool bool
IsFalseValue(const char *str); IsFalseValue(string_view str);
bool bool
IsTrueValue(const char *str); IsTrueValue(string_view str);
} // namespace llarp } // namespace llarp

Loading…
Cancel
Save