From b51f7d8015b5308c24f537d1ee290be2e0e59175 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 Jun 2019 11:10:01 +0100 Subject: [PATCH] Convert to load config in config loader --- include/llarp.hpp | 19 +- llarp/config/config.cpp | 459 +++++++++++++++++++++++++++++++++------ llarp/config/config.hpp | 180 +++++++++++++-- llarp/config/ini.cpp | 9 +- llarp/config/ini.hpp | 4 +- llarp/context.cpp | 105 +++------ llarp/link/server.cpp | 2 +- llarp/net/net_addr.cpp | 54 ++--- llarp/net/net_addr.hpp | 16 +- llarp/router/router.cpp | 458 +++++++++----------------------------- llarp/router/router.hpp | 16 +- llarp/router_contact.cpp | 2 +- llarp/router_contact.hpp | 2 +- llarp/service/config.cpp | 4 +- llarp/service/config.hpp | 5 +- llarp/util/str.cpp | 56 ++++- llarp/util/str.hpp | 6 +- 17 files changed, 800 insertions(+), 597 deletions(-) diff --git a/include/llarp.hpp b/include/llarp.hpp index 56d3aa322..da5aa4f8d 100644 --- a/include/llarp.hpp +++ b/include/llarp.hpp @@ -18,11 +18,12 @@ struct llarp_threadpool; namespace llarp { + class Logic; + struct AbstractRouter; struct Config; struct Crypto; struct CryptoManager; - class Logic; - struct AbstractRouter; + struct MetricsConfig; struct RouterContact; namespace metrics @@ -47,13 +48,8 @@ namespace llarp std::unique_ptr< metrics::DefaultManagerGuard > m_metricsManager; std::unique_ptr< metrics::PublisherScheduler > m_metricsPublisher; - int num_nethreads = 1; - bool singleThreaded = false; - bool disableMetrics = false; - bool disableMetricLogs = false; - fs::path jsonMetricsPath; - std::string metricTankHost; - std::map< std::string, std::string > metricTags; + int num_nethreads = 1; + bool singleThreaded = false; std::unique_ptr< Crypto > crypto; std::unique_ptr< CryptoManager > cryptoManager; @@ -111,14 +107,11 @@ namespace llarp bool ReloadConfig(); - void - iter_config(const char *section, const char *key, const char *val); - void progress(); void - setupMetrics(); + setupMetrics(const MetricsConfig &metricsConfig); std::string configfile; std::string pidfile; diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 8ac10897c..d7092a4d5 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -5,7 +5,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -13,84 +16,416 @@ namespace llarp { - template < typename Config, typename Section > - Section - find_section(Config &c, const std::string &name, const Section &fallback) + bool + RouterConfig::fromSection(string_view key, string_view val) { - Section ret; - if(c.VisitSection(name.c_str(), - [&ret](const ConfigParser::Section_t &s) -> bool { - for(const auto &item : s) - { - ret.emplace_back(string_view_string(item.first), - string_view_string(item.second)); - } - return true; - })) - return ret; + if(key == "netid") + { + if(val.size() <= 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 !!!!"); + 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 - return fallback; + { + netConfig.emplace(key, val); + } + return true; } bool - Config::Load(const char *fname) + NetdbConfig::fromSection(string_view key, string_view val) { - ConfigParser parser; - if(!parser.LoadFile(fname)) + if(key == "dir") { - 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; } - void - Config::visit(const Visitor &functor) + bool + DnsConfig::fromSection(string_view key, string_view val) { - std::unordered_map< std::string, const llarp::Config::section_t & > - sections = {{"network", network}, - {"connect", connect}, - {"bootstrap", bootstrap}, - {"system", system}, - {"metrics", metrics}, - {"netdb", netdb}, - {"api", api}, - {"services", services}}; - - auto visitor = [&](const char *name, const auto &item) { - functor(name, item.first.c_str(), item.second.c_str()); - }; + if(key == "upstream") + { + llarp::LogInfo("add upstream resolver ", val); + netConfig.emplace("upstream-dns", val); + } + if(key == "bind") + { + llarp::LogInfo("set local dns to ", val); + netConfig.emplace("local-dns", val); + } + return true; + } + + 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(), - std::bind(visitor, "logging", _1)); - // end of logging section commit settings and go - functor("logging", "", ""); - std::for_each(lokid.begin(), lokid.end(), std::bind(visitor, "lokid", _1)); - std::for_each(router.begin(), router.end(), - std::bind(visitor, "router", _1)); + if(key == "*") + { + m_OutboundPort = proto; + } + else + { + servers.emplace_back(key, AF_INET, proto); + } + return true; + } - std::for_each(dns.begin(), dns.end(), std::bind(visitor, "dns", _1)); - std::for_each(iwp_links.begin(), iwp_links.end(), - std::bind(visitor, "bind", _1)); + bool + ConnectConfig::fromSection(ABSL_ATTRIBUTE_UNUSED string_view key, + 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 §ion) { - std::for_each(section.second.begin(), section.second.end(), - std::bind(visitor, section.first.c_str(), _1)); - }); + bool + SystemConfig::fromSection(string_view key, string_view val) + { + 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 §ion) -> 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 diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 520733bd9..3cbe53c75 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -1,6 +1,11 @@ #ifndef LLARP_CONFIG_HPP #define LLARP_CONFIG_HPP +#include +#include +#include +#include + #include #include #include @@ -8,32 +13,167 @@ 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; - section_t network; - section_t netdb; - section_t dns; - section_t iwp_links; - section_t connect; - section_t services; - section_t system; - section_t metrics; - section_t api; - section_t lokid; - section_t bootstrap; - section_t logging; + // path to write our self signed rc to + fs::path our_rc_file = "rc.signed"; + + // transient iwp encryption key + fs::path transport_keyfile = "transport.key"; + + // long term identity key + fs::path ident_keyfile = "identity.key"; + + bool publicOverride = false; + struct sockaddr_in ip4addr; + AddressInfo addrInfo; + + int workerThreads; + int num_nethreads; 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, - const char *val) >; + struct ServicesConfig + { + 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 - visit(const Visitor &visitor); + bool + 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 diff --git a/llarp/config/ini.cpp b/llarp/config/ini.cpp index 22b5d7892..70f8df1ae 100644 --- a/llarp/config/ini.cpp +++ b/llarp/config/ini.cpp @@ -12,10 +12,11 @@ namespace llarp { 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()) return false; f.seekg(0, std::ios::end); @@ -25,12 +26,12 @@ namespace llarp return false; f.read(m_Data.data(), m_Data.size()); } - m_FileName = fname; + m_FileName = name; return Parse(); } bool - ConfigParser::LoadString(const std::string& str) + ConfigParser::LoadString(string_view str) { m_Data.resize(str.size()); std::copy(str.begin(), str.end(), m_Data.begin()); diff --git a/llarp/config/ini.hpp b/llarp/config/ini.hpp index 3e7a845d1..1610dcea6 100644 --- a/llarp/config/ini.hpp +++ b/llarp/config/ini.hpp @@ -25,13 +25,13 @@ namespace llarp /// return true on success /// return false on error bool - LoadFile(const char* fname); + LoadFile(string_view fname); /// load from string /// return true on success /// return false on error bool - LoadString(const std::string& str); + LoadString(string_view str); /// iterate all sections and thier values void diff --git a/llarp/context.cpp b/llarp/context.cpp index 717c8ff3f..28c41c677 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -52,92 +52,49 @@ namespace llarp llarp::LogError("failed to load config file ", configfile); return false; } - config->visit(util::memFn(&Context::iter_config, this)); - if(!disableMetrics) + // System config + if(!config->system.pidfile.empty()) { - setupMetrics(); - if(!disableMetricLogs) - { - m_metricsManager->instance()->addGlobalPublisher( - std::make_shared< metrics::StreamPublisher >(std::cerr)); - } + SetPIDFile(config->system.pidfile); } - return true; - } - void - Context::iter_config(const char *section, const char *key, const char *val) - { - if(!strcmp(section, "system")) + // Router config + if(!singleThreaded && config->router.workerThreads > 0 && !worker) { - if(!strcmp(key, "pidfile")) - { - SetPIDFile(val); - } + worker.reset( + llarp_init_threadpool(config->router.workerThreads, "llarp-worker")); } - if(!strcmp(section, "metrics")) + + if(singleThreaded) { - if(!strcmp(key, "disable-metrics")) - { - 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; - } + num_nethreads = 0; } - if(!strcmp(section, "router")) + else { - if(!strcmp(key, "worker-threads") && !singleThreaded) - { - 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; - } + num_nethreads = config->router.num_nethreads; } - 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 - Context::setupMetrics() + Context::setupMetrics(const MetricsConfig &metricsConfig) { if(!m_scheduler) { @@ -153,15 +110,15 @@ namespace llarp *m_scheduler, m_metricsManager->instance()); } - if(!jsonMetricsPath.native().empty()) + if(!metricsConfig.jsonMetricsPath.native().empty()) { m_metricsManager->instance()->addGlobalPublisher( std::make_shared< metrics::JsonPublisher >( 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")) { @@ -186,11 +143,11 @@ __ ___ ____ _ _ ___ _ _ ____ std::cerr << WARNING << '\n'; std::pair< std::string, std::string > split = - absl::StrSplit(metricTankHost, ':'); + absl::StrSplit(metricsConfig.metricTankHost, ':'); m_metricsManager->instance()->addGlobalPublisher( std::make_shared< metrics::MetricTankPublisher >( - metricTags, split.first, stoi(split.second))); + metricsConfig.metricTags, split.first, stoi(split.second))); } else { diff --git a/llarp/link/server.cpp b/llarp/link/server.cpp index 676eb8988..8bde2e224 100644 --- a/llarp/link/server.cpp +++ b/llarp/link/server.cpp @@ -104,7 +104,7 @@ namespace llarp return false; } else if(!GetIFAddr(ifname, m_ourAddr, af)) - m_ourAddr = ifname; + m_ourAddr = Addr(ifname); m_ourAddr.port(port); return llarp_ev_add_udp(m_Loop.get(), &m_udp, m_ourAddr) != -1; } diff --git a/llarp/net/net_addr.cpp b/llarp/net/net_addr.cpp index 383c73ce8..ac33a7f33 100644 --- a/llarp/net/net_addr.cpp +++ b/llarp/net/net_addr.cpp @@ -63,14 +63,14 @@ namespace llarp 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); } @@ -81,25 +81,17 @@ namespace llarp } bool - Addr::from_char_array(const char* in) + Addr::from_char_array(string_view in) { - char* str = (char*)in; - char* pPosition = strchr(str, ':'); - bool freeStr = false; - if(pPosition) + auto str = in.begin(); + auto pPosition = in.find(':'); + if(pPosition != string_view::npos) { // parse port - char buf[6]; - snprintf(buf, 6, "%s", pPosition + 1); - uint16_t port = std::atoi(buf); + uint16_t port = + std::atoi(std::string(in.begin() + pPosition + 1, in.end()).c_str()); LogDebug("Setting port ", std::to_string(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)); struct addrinfo hint, *res = NULL; @@ -110,27 +102,30 @@ namespace llarp hint.ai_family = PF_UNSPEC; 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) { LogError("failed to determine address family: ", str); - if(freeStr) - free(str); return false; } if(res->ai_family == AF_INET6) { LogError("IPv6 address not supported yet", str); - if(freeStr) - free(str); return false; } else if(res->ai_family != AF_INET) { LogError("Address family not supported yet", str); - if(freeStr) - free(str); return false; } @@ -139,12 +134,8 @@ namespace llarp if(inet_aton(str, addr) == 0) { LogError("failed to parse ", str); - if(freeStr) - free(str); return false; } - if(freeStr) - free(str); _addr.sin6_family = res->ai_family; _addr4.sin_family = res->ai_family; @@ -162,11 +153,6 @@ namespace llarp return true; } - Addr::Addr(const char* str) - { - this->from_char_array(str); - } - bool Addr::from_4int(const uint8_t one, const uint8_t two, const uint8_t three, const uint8_t four) diff --git a/llarp/net/net_addr.hpp b/llarp/net/net_addr.hpp index c469ae0d2..8ee0691d0 100644 --- a/llarp/net/net_addr.hpp +++ b/llarp/net/net_addr.hpp @@ -23,6 +23,12 @@ namespace llarp 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 port(uint16_t port); @@ -38,16 +44,8 @@ namespace llarp const in_addr* 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 - from_char_array(const char* str); - - Addr(const char* str); + from_char_array(string_view str); bool from_4int(const uint8_t one, const uint8_t two, const uint8_t three, diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 3d2f3491c..535e15061 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -464,7 +464,8 @@ namespace llarp bool Router::Configure(Config *conf) { - conf->visit(util::memFn(&Router::router_iter_config, this)); + fromConfig(conf); + if(!InitOutboundLinks()) return false; if(!Ready()) @@ -766,260 +767,138 @@ namespace llarp } void - Router::router_iter_config(const char *section, const char *key, - const char *val) + Router::fromConfig(Config *conf) { - llarp::LogDebug(section, " ", key, "=", val); + // IWP config + m_OutboundPort = conf->iwp_links.m_OutboundPort; - int af; - 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")) + for(const auto &serverConfig : conf->iwp_links.servers) { - // try IPv4 first - af = AF_INET; - std::set< std::string > parsed_opts; - std::string v = val; - std::string::size_type idx; - do + auto server = llarp::utp::NewServerFromRouter(this); + if(!server->EnsureKeys(transport_keyfile.string().c_str())) { - 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); + llarp::LogError("failed to ensure keyfile ", transport_keyfile); + return; + } - /// for each option - for(const auto &item : parsed_opts) + const auto &key = std::get< 0 >(serverConfig); + 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 - auto port = std::atoi(item.c_str()); - if(port > 0) - { - /// set port - if(proto == 0) - proto = port; - } /// otherwise add to opts - else - opts.insert(item); + AddLink(std::move(server), true); + return; } + 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 { - auto server = llarp::utp::NewServerFromRouter(this); - if(!server->EnsureKeys(transport_keyfile.string().c_str())) - { - 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); + routerProfiling().Disable(); + LogInfo("router profiling explicitly disabled"); } } - 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)) - { - routerProfiling().Enable(); - LogInfo("router profiling explicitly enabled"); - } - else if(IsFalseValue(val)) - { - routerProfiling().Disable(); - LogInfo("router profiling explicitly disabled"); - } + llarp::LogError("cannot use strict-connect option as service node"); + return; } - if(StrEq(key, "profiles")) + llarp::RouterID snode; + llarp::PubKey pk; + if(pk.FromString(val)) { - routerProfilesFile = val; - routerProfiling().Load(val); - llarp::LogInfo("setting profiles to ", routerProfilesFile); + if(strictConnectPubkeys.emplace(pk).second) + llarp::LogInfo("added ", pk, " to strict connect list"); + 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"); - return; - } - 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); + llarp::LogInfo("added ", snode, " to strict connect list"); + netConfig.emplace("strict-connect", val); } else - llarp::LogError("invalid key for strict-connect: ", val); + llarp::LogWarn("duplicate key for strict connect: ", snode); } else - { - 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 - } + llarp::LogError("invalid key for strict-connect: ", val); } - 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 { - 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")) - { - if(strlen(key) == 0 && strlen(val) == 0) - { - if(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")) + + // Logging config + + auto logfile = conf->logging.m_LogFile; + + if(conf->logging.m_LogJSON) { - if(StrEq(key, "service-node-seed")) - { - 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; - } + LogContext::Instance().logStream = std::make_unique< JSONLogStream >( + diskworker(), logfile, 100, logfile != stdout); } - else if(StrEq(section, "dns")) + else if(logfile != stdout) { - if(StrEq(key, "upstream")) - { - 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); - } + LogContext::Instance().logStream = + std::make_unique< FileLogStream >(diskworker(), logfile, 100, true); } - 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); 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); - ; return; } if(rc.Verify(Now())) @@ -1039,98 +918,25 @@ namespace llarp } 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")) - { - 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; - } + ident_keyfile = conf->router.ident_keyfile; } } @@ -1966,58 +1772,10 @@ namespace llarp 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 - Router::ValidateConfig(Config *conf) const + Router::ValidateConfig(ABSL_ATTRIBUTE_UNUSED Config *conf) const { - RouterConfigValidator validator(this, conf); - return validator.Validate(); + return true; } bool @@ -2095,7 +1853,7 @@ namespace llarp } bool - Router::LoadHiddenServiceConfig(const char *fname) + Router::LoadHiddenServiceConfig(string_view fname) { LogDebug("opening hidden service config ", fname); service::Config conf; diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 57381576d..a0eace817 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -265,11 +265,10 @@ namespace llarp std::string rpcBindAddr = DefaultRPCBindAddr; /// lokid caller - const std::string DefaultLokidRPCAddr = "127.0.0.1:22023"; std::unique_ptr< rpc::Caller > rpcCaller; - std::string lokidRPCAddr = DefaultLokidRPCAddr; - std::string lokidRPCUser = ""; - std::string lokidRPCPassword = ""; + std::string lokidRPCAddr = "127.0.0.1:22023"; + std::string lokidRPCUser; + std::string lokidRPCPassword; using LinkSet = std::set< LinkLayer_ptr, ComparePtr< LinkLayer_ptr > >; @@ -305,11 +304,6 @@ namespace llarp // set to max value right now 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, std::shared_ptr< Logic > logic); @@ -344,7 +338,7 @@ namespace llarp Close(); bool - LoadHiddenServiceConfig(const char *fname); + LoadHiddenServiceConfig(string_view fname); bool AddHiddenService(const service::Config::section_t &config); @@ -572,7 +566,7 @@ namespace llarp } void - router_iter_config(const char *section, const char *key, const char *val); + fromConfig(Config *conf); }; } // namespace llarp diff --git a/llarp/router_contact.cpp b/llarp/router_contact.cpp index 8321f756c..973ec7a92 100644 --- a/llarp/router_contact.cpp +++ b/llarp/router_contact.cpp @@ -223,7 +223,7 @@ namespace llarp } void - RouterContact::SetNick(const std::string &nick) + RouterContact::SetNick(string_view nick) { nickname.Zero(); std::copy(nick.begin(), diff --git a/llarp/router_contact.hpp b/llarp/router_contact.hpp index 4226ab02e..fb31d6db4 100644 --- a/llarp/router_contact.hpp +++ b/llarp/router_contact.hpp @@ -162,7 +162,7 @@ namespace llarp IsPublicRouter() const; void - SetNick(const std::string &nick); + SetNick(string_view nick); bool Verify(llarp_time_t now, bool allowExpired = true) const; diff --git a/llarp/service/config.cpp b/llarp/service/config.cpp index fbb08a316..a33dcfd95 100644 --- a/llarp/service/config.cpp +++ b/llarp/service/config.cpp @@ -7,10 +7,10 @@ namespace llarp namespace service { bool - Config::Load(const std::string& fname) + Config::Load(string_view fname) { ConfigParser parser; - if(!parser.LoadFile(fname.c_str())) + if(!parser.LoadFile(fname)) return false; parser.IterAll([&](const ConfigParser::String_t& name, const ConfigParser::Section_t& section) { diff --git a/llarp/service/config.hpp b/llarp/service/config.hpp index 1f8d9cbe2..ec0401bc8 100644 --- a/llarp/service/config.hpp +++ b/llarp/service/config.hpp @@ -1,5 +1,8 @@ #ifndef LLARP_SERVICE_CONFIG_HPP #define LLARP_SERVICE_CONFIG_HPP + +#include + #include #include @@ -16,7 +19,7 @@ namespace llarp std::list< section_t > services; bool - Load(const std::string& fname); + Load(string_view fname); }; } // namespace service } // namespace llarp diff --git a/llarp/util/str.cpp b/llarp/util/str.cpp index ed911975b..f2aa99b06 100644 --- a/llarp/util/str.cpp +++ b/llarp/util/str.cpp @@ -3,25 +3,61 @@ #include #include #include +#include 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 - IsFalseValue(const char* str) + IsFalseValue(string_view str) { - std::string value = str; - std::transform(value.begin(), value.end(), value.begin(), - [](char ch) -> char { return std::tolower(ch); }); - return value == "no" || value == "false" || value == "0" || value == "off"; + static const std::set< string_view, CaselessCmp > vals{"no", "false", "0", + "off"}; + + return vals.count(str) > 0; } bool - IsTrueValue(const char* str) + IsTrueValue(string_view str) { - std::string value = str; - std::transform(value.begin(), value.end(), value.begin(), - [](char ch) -> char { return std::tolower(ch); }); - return value == "yes" || value == "true" || value == "1" || value == "on"; + static const std::set< string_view, CaselessCmp > vals{"yes", "true", "1", + "on"}; + + return vals.count(str) > 0; } bool diff --git a/llarp/util/str.hpp b/llarp/util/str.hpp index 505de5292..ed104a1e9 100644 --- a/llarp/util/str.hpp +++ b/llarp/util/str.hpp @@ -1,16 +1,18 @@ #ifndef LLARP_STR_HPP #define LLARP_STR_HPP +#include + namespace llarp { bool StrEq(const char *s1, const char *s2); bool - IsFalseValue(const char *str); + IsFalseValue(string_view str); bool - IsTrueValue(const char *str); + IsTrueValue(string_view str); } // namespace llarp