Revert "Merge pull request #679 from tewinget/revert-config-refactor"

This reverts commit 2996a7f29c, reversing
changes made to 10df3bd4b3.
pull/685/head
Michael 5 years ago
parent c15fc4c8fb
commit a2326efa37
No known key found for this signature in database
GPG Key ID: 2D51757B47E2434C

@ -4,6 +4,6 @@ function(target_link_libraries_system target)
foreach(lib ${libs})
get_target_property(lib_include_dirs ${lib} INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(${target} SYSTEM PUBLIC ${lib_include_dirs})
target_link_libraries(${target} ${lib})
target_link_libraries(${target} PUBLIC ${lib})
endforeach(lib)
endfunction()

@ -1,9 +1,9 @@
#include <config.hpp> // for ensure_config
#include <config/config.hpp> // for ensure_config
#include <llarp.h>
#include <util/fs.hpp>
#include <util/logger.hpp>
#include <signal.h>
#include <csignal>
#if !defined(_WIN32) && !defined(__OpenBSD__)
#include <wordexp.h>

@ -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;

@ -1,4 +1,6 @@
set(LIB_UTIL_SRC
config/config.cpp
config/ini.cpp
constants/defaults.cpp
constants/link_layer.cpp
constants/path.cpp
@ -13,7 +15,6 @@ set(LIB_UTIL_SRC
util/encode.cpp
util/endian.cpp
util/fs.cpp
util/ini.cpp
util/json.cpp
util/logger.cpp
util/android_logger.cpp
@ -52,6 +53,7 @@ set(LIB_UTIL_SRC
add_library(${UTIL_LIB} STATIC ${LIB_UTIL_SRC})
target_include_directories(${UTIL_LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(${UTIL_LIB} PUBLIC ${CRYPTOGRAPHY_LIB})
target_link_libraries_system(${UTIL_LIB} absl::synchronization absl::hash absl::container nlohmann_json::nlohmann_json)
# cut back on fluff
@ -125,7 +127,6 @@ set(DNSLIB_SRC
set(LIB_SRC
${DNSLIB_SRC}
config.cpp
context.cpp
crypto/constants.cpp
crypto/crypto_libsodium.cpp

@ -1,369 +0,0 @@
#include <config.hpp>
#include <constants/defaults.hpp>
#include <net/net.hpp>
#include <util/fs.hpp>
#include <util/ini.hpp>
#include <util/logger.hpp>
#include <util/mem.hpp>
#include <fstream>
#include <ios>
#include <iostream>
namespace llarp
{
template < typename Config, typename Section >
Section
find_section(Config &c, const std::string &name, const Section &fallback)
{
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;
else
return fallback;
}
bool
Config::Load(const char *fname)
{
ConfigParser parser;
if(!parser.LoadFile(fname))
{
return false;
}
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)
{
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());
};
using namespace std::placeholders;
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));
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));
std::for_each(sections.begin(), sections.end(), [&](const auto &section) {
std::for_each(section.second.begin(), section.second.end(),
std::bind(visitor, section.first.c_str(), _1));
});
}
} // namespace llarp
/// fname should be a relative path (from CWD) or absolute path to the config
/// file
extern "C" bool
llarp_ensure_config(const char *fname, const char *basedir, bool overwrite,
bool asRouter)
{
std::error_code ec;
if(fs::exists(fname, ec) && !overwrite)
{
return true;
}
if(ec)
{
llarp::LogError(ec);
return false;
}
std::string basepath = "";
if(basedir)
{
basepath = basedir;
#ifndef _WIN32
basepath += "/";
#else
basepath += "\\";
#endif
}
llarp::LogInfo("Attempting to create config file ", fname);
// abort if config already exists
if(!asRouter)
{
if(fs::exists(fname, ec) && !overwrite)
{
llarp::LogError(fname, " currently exists, please use -f to overwrite");
return true;
}
if(ec)
{
llarp::LogError(ec);
return false;
}
}
// write fname ini
auto optional_f =
llarp::util::OpenFileStream< std::ofstream >(fname, std::ios::binary);
if(!optional_f || !optional_f.value().is_open())
{
llarp::LogError("failed to open ", fname, " for writing");
return false;
}
auto &f = optional_f.value();
llarp_generic_ensure_config(f, basepath);
if(asRouter)
{
llarp_ensure_router_config(f, basepath);
}
else
{
llarp_ensure_client_config(f, basepath);
}
llarp::LogInfo("Generated new config ", fname);
return true;
}
void
llarp_generic_ensure_config(std::ofstream &f, std::string basepath)
{
f << "# this configuration was auto generated with 'sane' defaults"
<< std::endl;
f << "# change these values as desired" << std::endl;
f << std::endl << std::endl;
f << "[router]" << std::endl;
f << "# number of crypto worker threads " << std::endl;
f << "threads=4" << std::endl;
f << "# path to store signed RC" << std::endl;
f << "contact-file=" << basepath << "self.signed" << std::endl;
f << "# path to store transport private key" << std::endl;
f << "transport-privkey=" << basepath << "transport.private" << std::endl;
f << "# path to store identity signing key" << std::endl;
f << "ident-privkey=" << basepath << "identity.private" << std::endl;
f << "# encryption key for onion routing" << std::endl;
f << "encryption-privkey=" << basepath << "encryption.private" << std::endl;
f << std::endl;
f << "# uncomment following line to set router nickname to 'lokinet'"
<< std::endl;
f << "#nickname=lokinet" << std::endl;
f << std::endl << std::endl;
// logging
f << "[logging]" << std::endl;
f << "level=info" << std::endl;
f << "# uncomment for logging to file" << std::endl;
f << "#type=file" << std::endl;
f << "#file=/path/to/logfile" << std::endl;
f << "# uncomment for syslog logging" << std::endl;
f << "#type=syslog" << std::endl;
// metrics
f << "[metrics]" << std::endl;
f << "json-metrics-path=" << basepath << "metrics.json" << std::endl;
f << std::endl << std::endl;
f << "# admin api (disabled by default)" << std::endl;
f << "[api]" << std::endl;
f << "enabled=false" << std::endl;
f << "#authkey=insertpubkey1here" << std::endl;
f << "#authkey=insertpubkey2here" << std::endl;
f << "#authkey=insertpubkey3here" << std::endl;
f << "bind=127.0.0.1:1190" << std::endl;
f << std::endl << std::endl;
f << "# system settings for privileges and such" << std::endl;
f << "[system]" << std::endl;
f << "user=" << DEFAULT_LOKINET_USER << std::endl;
f << "group=" << DEFAULT_LOKINET_GROUP << std::endl;
f << "pidfile=" << basepath << "lokinet.pid" << std::endl;
f << std::endl << std::endl;
f << "# dns provider configuration section" << std::endl;
f << "[dns]" << std::endl;
f << "# resolver" << std::endl;
f << "upstream=" << DEFAULT_RESOLVER_US << std::endl;
// Make auto-config smarter
// will this break reproducibility rules?
// (probably)
#ifdef __linux__
#ifdef ANDROID
f << "bind=127.0.0.1:1153" << std::endl;
#else
f << "bind=127.3.2.1:53" << std::endl;
#endif
#else
f << "bind=127.0.0.1:53" << std::endl;
#endif
f << std::endl << std::endl;
f << "# network database settings block " << std::endl;
f << "[netdb]" << std::endl;
f << "# directory for network database skiplist storage" << std::endl;
f << "dir=" << basepath << "netdb" << std::endl;
f << std::endl << std::endl;
f << "# bootstrap settings" << std::endl;
f << "[bootstrap]" << std::endl;
f << "# add a bootstrap node's signed identity to the list of nodes we want "
"to bootstrap from"
<< std::endl;
f << "# if we don't have any peers we connect to this router" << std::endl;
f << "add-node=" << basepath << "bootstrap.signed" << std::endl;
// we only process one of these...
// f << "# add another bootstrap node" << std::endl;
// f << "#add-node=/path/to/alternative/self.signed" << std::endl;
f << std::endl << std::endl;
}
void
llarp_ensure_router_config(std::ofstream &f, std::string basepath)
{
f << "# lokid settings (disabled by default)" << std::endl;
f << "[lokid]" << std::endl;
f << "enabled=false" << std::endl;
f << "jsonrpc=127.0.0.1:22023" << std::endl;
f << "#service-node-seed=/path/to/servicenode/seed" << std::endl;
f << std::endl;
f << "# network settings " << std::endl;
f << "[network]" << std::endl;
f << "profiles=" << basepath << "profiles.dat" << std::endl;
// better to let the routers auto-configure
// f << "ifaddr=auto" << std::endl;
// f << "ifname=auto" << std::endl;
f << "enabled=true" << std::endl;
f << "exit=false" << std::endl;
f << "#exit-blacklist=tcp:25" << std::endl;
f << "#exit-whitelist=tcp:*" << std::endl;
f << "#exit-whitelist=udp:*" << std::endl;
f << std::endl;
f << "# ROUTERS ONLY: publish network interfaces for handling inbound traffic"
<< std::endl;
f << "[bind]" << std::endl;
// get ifname
std::string ifname;
if(llarp::GetBestNetIF(ifname, AF_INET))
f << ifname << "=1090" << std::endl;
else
f << "# could not autodetect network interface" << std::endl
<< "#eth0=1090" << std::endl;
f << std::endl;
}
bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath)
{
// write snapp-example.ini
const std::string snappExample_fpath = basepath + "snapp-example.ini";
{
auto stream = llarp::util::OpenFileStream< std::ofstream >(
snappExample_fpath, std::ios::binary);
if(!stream)
return false;
auto &example_f = stream.value();
if(example_f.is_open())
{
// pick ip
// don't revert me
const static std::string ip = "10.33.0.1/16";
/*
std::string ip = llarp::findFreePrivateRange();
if(ip == "")
{
llarp::LogError(
"Couldn't easily detect a private range to map lokinet onto");
return false;
}
*/
example_f << "# this is an example configuration for a snapp"
<< std::endl;
example_f << "[example-snapp]" << std::endl;
example_f << "# keyfile is the path to the private key of the snapp, "
"your .loki is tied to this key, DON'T LOSE IT"
<< std::endl;
example_f << "keyfile=" << basepath << "example-snap-keyfile.private"
<< std::endl;
example_f << "# ifaddr is the ip range to allocate to this snapp"
<< std::endl;
example_f << "ifaddr=" << ip << std::endl;
// probably fine to leave this (and not-auto-detect it) I'm not worried
// about any collisions
example_f << "# ifname is the name to try and give to the network "
"interface this snap owns"
<< std::endl;
example_f << "ifname=snapp-tun0" << std::endl;
}
else
{
llarp::LogError("failed to write ", snappExample_fpath);
}
}
// now do up fname
f << std::endl << std::endl;
f << "# snapps configuration section" << std::endl;
f << "[services]";
f << "# uncomment next line to enable a snapp" << std::endl;
f << "#example-snapp=" << snappExample_fpath << std::endl;
f << std::endl << std::endl;
f << "# network settings " << std::endl;
f << "[network]" << std::endl;
f << "profiles=" << basepath << "profiles.dat" << std::endl;
f << "# uncomment next line to add router with pubkey to list of routers we "
"connect directly to"
<< std::endl;
f << "#strict-connect=pubkey" << std::endl;
f << "# uncomment next line to use router with pubkey as an exit node"
<< std::endl;
f << "#exit-node=pubkey" << std::endl;
// better to set them to auto then to hard code them now
// operating environment may change over time and this will help adapt
// f << "ifname=auto" << std::endl;
// f << "ifaddr=auto" << std::endl;
// should this also be auto? or not declared?
// probably auto in case they want to set up a hidden service
f << "enabled=true" << std::endl;
return true;
}

@ -1,50 +0,0 @@
#ifndef LLARP_CONFIG_HPP
#define LLARP_CONFIG_HPP
#include <functional>
#include <string>
#include <utility>
#include <vector>
namespace llarp
{
struct Config
{
using section_t = std::vector< std::pair< std::string, std::string > >;
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;
bool
Load(const char *fname);
using Visitor = std::function< void(const char *section, const char *key,
const char *val) >;
void
visit(const Visitor &visitor);
};
} // namespace llarp
void
llarp_generic_ensure_config(std::ofstream &f, std::string basepath);
void
llarp_ensure_router_config(std::ofstream &f, std::string basepath);
bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath);
#endif

@ -0,0 +1,704 @@
#include <config/config.hpp>
#include <config/ini.hpp>
#include <constants/defaults.hpp>
#include <net/net.hpp>
#include <util/fs.hpp>
#include <util/logger.hpp>
#include <util/logger_syslog.hpp>
#include <util/mem.hpp>
#include <util/memfn.hpp>
#include <util/str.hpp>
#include <fstream>
#include <ios>
#include <iostream>
namespace llarp
{
bool
RouterConfig::fromSection(string_view key, string_view val)
{
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
{
netConfig.emplace(key, val);
}
return true;
}
bool
NetdbConfig::fromSection(string_view key, string_view val)
{
if(key == "dir")
{
nodedb_dir.assign(val.begin(), val.end());
}
return true;
}
bool
DnsConfig::fromSection(string_view key, string_view val)
{
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);
/// 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;
}
}
}
if(key == "*")
{
m_OutboundPort = proto;
}
else
{
servers.emplace_back(key, AF_INET, proto);
}
return true;
}
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;
}
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 &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
/// fname should be a relative path (from CWD) or absolute path to the config
/// file
extern "C" bool
llarp_ensure_config(const char *fname, const char *basedir, bool overwrite,
bool asRouter)
{
std::error_code ec;
if(fs::exists(fname, ec) && !overwrite)
{
return true;
}
if(ec)
{
llarp::LogError(ec);
return false;
}
std::string basepath = "";
if(basedir)
{
basepath = basedir;
#ifndef _WIN32
basepath += "/";
#else
basepath += "\\";
#endif
}
llarp::LogInfo("Attempting to create config file ", fname);
// abort if config already exists
if(!asRouter)
{
if(fs::exists(fname, ec) && !overwrite)
{
llarp::LogError(fname, " currently exists, please use -f to overwrite");
return true;
}
if(ec)
{
llarp::LogError(ec);
return false;
}
}
// write fname ini
auto optional_f =
llarp::util::OpenFileStream< std::ofstream >(fname, std::ios::binary);
if(!optional_f || !optional_f.value().is_open())
{
llarp::LogError("failed to open ", fname, " for writing");
return false;
}
auto &f = optional_f.value();
llarp_generic_ensure_config(f, basepath);
if(asRouter)
{
llarp_ensure_router_config(f, basepath);
}
else
{
llarp_ensure_client_config(f, basepath);
}
llarp::LogInfo("Generated new config ", fname);
return true;
}
void
llarp_generic_ensure_config(std::ofstream &f, std::string basepath)
{
f << "# this configuration was auto generated with 'sane' defaults"
<< std::endl;
f << "# change these values as desired" << std::endl;
f << std::endl << std::endl;
f << "[router]" << std::endl;
f << "# number of crypto worker threads " << std::endl;
f << "threads=4" << std::endl;
f << "# path to store signed RC" << std::endl;
f << "contact-file=" << basepath << "self.signed" << std::endl;
f << "# path to store transport private key" << std::endl;
f << "transport-privkey=" << basepath << "transport.private" << std::endl;
f << "# path to store identity signing key" << std::endl;
f << "ident-privkey=" << basepath << "identity.private" << std::endl;
f << "# encryption key for onion routing" << std::endl;
f << "encryption-privkey=" << basepath << "encryption.private" << std::endl;
f << std::endl;
f << "# uncomment following line to set router nickname to 'lokinet'"
<< std::endl;
f << "#nickname=lokinet" << std::endl;
f << std::endl << std::endl;
// logging
f << "[logging]" << std::endl;
f << "level=info" << std::endl;
f << "# uncomment for logging to file" << std::endl;
f << "#type=file" << std::endl;
f << "#file=/path/to/logfile" << std::endl;
f << "# uncomment for syslog logging" << std::endl;
f << "#type=syslog" << std::endl;
// metrics
f << "[metrics]" << std::endl;
f << "json-metrics-path=" << basepath << "metrics.json" << std::endl;
f << std::endl << std::endl;
f << "# admin api (disabled by default)" << std::endl;
f << "[api]" << std::endl;
f << "enabled=false" << std::endl;
f << "#authkey=insertpubkey1here" << std::endl;
f << "#authkey=insertpubkey2here" << std::endl;
f << "#authkey=insertpubkey3here" << std::endl;
f << "bind=127.0.0.1:1190" << std::endl;
f << std::endl << std::endl;
f << "# system settings for privileges and such" << std::endl;
f << "[system]" << std::endl;
f << "user=" << DEFAULT_LOKINET_USER << std::endl;
f << "group=" << DEFAULT_LOKINET_GROUP << std::endl;
f << "pidfile=" << basepath << "lokinet.pid" << std::endl;
f << std::endl << std::endl;
f << "# dns provider configuration section" << std::endl;
f << "[dns]" << std::endl;
f << "# resolver" << std::endl;
f << "upstream=" << DEFAULT_RESOLVER_US << std::endl;
// Make auto-config smarter
// will this break reproducibility rules?
// (probably)
#ifdef __linux__
#ifdef ANDROID
f << "bind=127.0.0.1:1153" << std::endl;
#else
f << "bind=127.3.2.1:53" << std::endl;
#endif
#else
f << "bind=127.0.0.1:53" << std::endl;
#endif
f << std::endl << std::endl;
f << "# network database settings block " << std::endl;
f << "[netdb]" << std::endl;
f << "# directory for network database skiplist storage" << std::endl;
f << "dir=" << basepath << "netdb" << std::endl;
f << std::endl << std::endl;
f << "# bootstrap settings" << std::endl;
f << "[bootstrap]" << std::endl;
f << "# add a bootstrap node's signed identity to the list of nodes we want "
"to bootstrap from"
<< std::endl;
f << "# if we don't have any peers we connect to this router" << std::endl;
f << "add-node=" << basepath << "bootstrap.signed" << std::endl;
// we only process one of these...
// f << "# add another bootstrap node" << std::endl;
// f << "#add-node=/path/to/alternative/self.signed" << std::endl;
f << std::endl << std::endl;
}
void
llarp_ensure_router_config(std::ofstream &f, std::string basepath)
{
f << "# lokid settings (disabled by default)" << std::endl;
f << "[lokid]" << std::endl;
f << "enabled=false" << std::endl;
f << "jsonrpc=127.0.0.1:22023" << std::endl;
f << "#service-node-seed=/path/to/servicenode/seed" << std::endl;
f << std::endl;
f << "# network settings " << std::endl;
f << "[network]" << std::endl;
f << "profiles=" << basepath << "profiles.dat" << std::endl;
// better to let the routers auto-configure
// f << "ifaddr=auto" << std::endl;
// f << "ifname=auto" << std::endl;
f << "enabled=true" << std::endl;
f << "exit=false" << std::endl;
f << "#exit-blacklist=tcp:25" << std::endl;
f << "#exit-whitelist=tcp:*" << std::endl;
f << "#exit-whitelist=udp:*" << std::endl;
f << std::endl;
f << "# ROUTERS ONLY: publish network interfaces for handling inbound traffic"
<< std::endl;
f << "[bind]" << std::endl;
// get ifname
std::string ifname;
if(llarp::GetBestNetIF(ifname, AF_INET))
f << ifname << "=1090" << std::endl;
else
f << "# could not autodetect network interface" << std::endl
<< "#eth0=1090" << std::endl;
f << std::endl;
}
bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath)
{
// write snapp-example.ini
const std::string snappExample_fpath = basepath + "snapp-example.ini";
{
auto stream = llarp::util::OpenFileStream< std::ofstream >(
snappExample_fpath, std::ios::binary);
if(!stream)
return false;
auto &example_f = stream.value();
if(example_f.is_open())
{
// pick ip
// don't revert me
const static std::string ip = "10.33.0.1/16";
/*
std::string ip = llarp::findFreePrivateRange();
if(ip == "")
{
llarp::LogError(
"Couldn't easily detect a private range to map lokinet onto");
return false;
}
*/
example_f << "# this is an example configuration for a snapp"
<< std::endl;
example_f << "[example-snapp]" << std::endl;
example_f << "# keyfile is the path to the private key of the snapp, "
"your .loki is tied to this key, DON'T LOSE IT"
<< std::endl;
example_f << "keyfile=" << basepath << "example-snap-keyfile.private"
<< std::endl;
example_f << "# ifaddr is the ip range to allocate to this snapp"
<< std::endl;
example_f << "ifaddr=" << ip << std::endl;
// probably fine to leave this (and not-auto-detect it) I'm not worried
// about any collisions
example_f << "# ifname is the name to try and give to the network "
"interface this snap owns"
<< std::endl;
example_f << "ifname=snapp-tun0" << std::endl;
}
else
{
llarp::LogError("failed to write ", snappExample_fpath);
}
}
// now do up fname
f << std::endl << std::endl;
f << "# snapps configuration section" << std::endl;
f << "[services]";
f << "# uncomment next line to enable a snapp" << std::endl;
f << "#example-snapp=" << snappExample_fpath << std::endl;
f << std::endl << std::endl;
f << "# network settings " << std::endl;
f << "[network]" << std::endl;
f << "profiles=" << basepath << "profiles.dat" << std::endl;
f << "# uncomment next line to add router with pubkey to list of routers we "
"connect directly to"
<< std::endl;
f << "#strict-connect=pubkey" << std::endl;
f << "# uncomment next line to use router with pubkey as an exit node"
<< std::endl;
f << "#exit-node=pubkey" << std::endl;
// better to set them to auto then to hard code them now
// operating environment may change over time and this will help adapt
// f << "ifname=auto" << std::endl;
// f << "ifaddr=auto" << std::endl;
// should this also be auto? or not declared?
// probably auto in case they want to set up a hidden service
f << "enabled=true" << std::endl;
return true;
}

@ -0,0 +1,190 @@
#ifndef 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 <string>
#include <utility>
#include <vector>
namespace llarp
{
struct RouterConfig
{
/// 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";
// 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
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);
};
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;
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
void
llarp_generic_ensure_config(std::ofstream &f, std::string basepath);
void
llarp_ensure_router_config(std::ofstream &f, std::string basepath);
bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath);
#endif

@ -1,8 +1,9 @@
#include <util/ini.hpp>
#include <config/ini.hpp>
#include <util/logger.hpp>
#include <fstream>
#include <list>
#include <iostream>
#include <util/logger.hpp>
#ifdef LoadString
#undef LoadString
@ -11,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);
@ -24,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());

@ -1,9 +1,11 @@
#ifndef LOKINET_BOOTSERV_CONFIG_HPP
#define LOKINET_BOOTSERV_CONFIG_HPP
#include <unordered_map>
#include <util/string_view.hpp>
#include <functional>
#include <memory>
#include <unordered_map>
#include <vector>
namespace llarp
@ -23,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

@ -1,7 +1,7 @@
#include <llarp.hpp>
#include <llarp.h>
#include <config.hpp>
#include <config/config.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <crypto/crypto_noop.hpp>
#include <dht/context.hpp>
@ -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
{

@ -70,8 +70,8 @@ namespace llarp
}
}
llarp::exit::Endpoint*
Context::FindEndpointForPath(const llarp::PathID_t& path) const
exit::Endpoint*
Context::FindEndpointForPath(const PathID_t& path) const
{
auto itr = m_Exits.begin();
while(itr != m_Exits.end())
@ -85,7 +85,7 @@ namespace llarp
}
bool
Context::ObtainNewExit(const llarp::PubKey& pk, const llarp::PathID_t& path,
Context::ObtainNewExit(const PubKey& pk, const PathID_t& path,
bool permitInternet)
{
auto itr = m_Exits.begin();
@ -106,13 +106,13 @@ namespace llarp
auto itr = m_Exits.find(name);
if(itr != m_Exits.end())
{
llarp::LogError("duplicate exit with name ", name);
LogError("duplicate exit with name ", name);
return false;
}
}
std::unique_ptr< llarp::handlers::ExitEndpoint > endpoint;
std::unique_ptr< handlers::ExitEndpoint > endpoint;
// make new endpoint
endpoint.reset(new llarp::handlers::ExitEndpoint(name, m_Router));
endpoint.reset(new handlers::ExitEndpoint(name, m_Router));
// configure
{
auto itr = conf.begin();
@ -120,8 +120,7 @@ namespace llarp
{
if(!endpoint->SetOption(itr->first, itr->second))
{
llarp::LogWarn("Couldn't set option ", itr->first, " to ",
itr->second);
LogWarn("Couldn't set option ", itr->first, " to ", itr->second);
return false;
}
++itr;
@ -130,7 +129,7 @@ namespace llarp
// add endpoint
if(!endpoint->Start())
{
llarp::LogWarn("Couldn't start exit endpoint");
LogWarn("Couldn't start exit endpoint");
return false;
}
m_Exits.emplace(name, std::move(endpoint));

@ -35,11 +35,11 @@ namespace llarp
AddExitEndpoint(const std::string &name, const Config_t &config);
bool
ObtainNewExit(const llarp::PubKey &remote, const llarp::PathID_t &path,
ObtainNewExit(const PubKey &remote, const PathID_t &path,
bool permitInternet);
llarp::exit::Endpoint *
FindEndpointForPath(const llarp::PathID_t &path) const;
exit::Endpoint *
FindEndpointForPath(const PathID_t &path) const;
/// calculate (pk, tx, rx) for all exit traffic
using TrafficStats =
@ -52,9 +52,9 @@ namespace llarp
private:
AbstractRouter *m_Router;
std::unordered_map< std::string,
std::shared_ptr< llarp::handlers::ExitEndpoint > >
std::shared_ptr< handlers::ExitEndpoint > >
m_Exits;
std::list< std::shared_ptr< llarp::handlers::ExitEndpoint > > m_Closed;
std::list< std::shared_ptr< handlers::ExitEndpoint > > m_Closed;
};
} // namespace exit
} // namespace llarp

@ -607,6 +607,7 @@ namespace llarp
pk, path, !wantInternet, ip, this));
m_Paths[path] = pk;
return HasLocalMappedAddrFor(pk);
}

@ -116,7 +116,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;
}

@ -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)

@ -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,

@ -1,6 +1,6 @@
#include <router/router.hpp>
#include <config.hpp>
#include <config/config.hpp>
#include <constants/proto.hpp>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
@ -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,142 @@ 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"))
// set network config
netConfig = conf->network.netConfig;
// 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())
{
if(StrEq(key, "profiling"))
routerProfilesFile = conf->network.routerProfilesFile;
routerProfiling().Load(routerProfilesFile.c_str());
llarp::LogInfo("setting profiles to ", routerProfilesFile);
}
if(!conf->network.strictConnect.empty())
{
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())
{
llarp::LogError("cannot use strict-connect option as service node");
return;
}
llarp::RouterID snode;
llarp::PubKey pk;
if(pk.FromString(val))
if(strictConnectPubkeys.insert(snode).second)
{
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);
}
}
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();
}
llarp::LogWarn("failed to load hidden service config for ",
service.first);
}
}
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 +922,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 +1776,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 +1857,7 @@ namespace llarp
}
bool
Router::LoadHiddenServiceConfig(const char *fname)
Router::LoadHiddenServiceConfig(string_view fname)
{
LogDebug("opening hidden service config ", fname);
service::Config conf;

@ -260,16 +260,15 @@ namespace llarp
ShouldCreateDefaultHiddenService();
const std::string DefaultRPCBindAddr = "127.0.0.1:1190";
bool enableRPCServer = true;
bool enableRPCServer = false;
std::unique_ptr< rpc::Server > rpcServer;
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

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

@ -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;

@ -1,16 +1,16 @@
#include <service/config.hpp>
#include <util/ini.hpp>
#include <config/ini.hpp>
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) {

@ -1,5 +1,8 @@
#ifndef LLARP_SERVICE_CONFIG_HPP
#define LLARP_SERVICE_CONFIG_HPP
#include <util/string_view.hpp>
#include <list>
#include <string>
@ -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

@ -3,25 +3,57 @@
#include <algorithm>
#include <cstring>
#include <string>
#include <set>
namespace llarp
{
bool
IsFalseValue(const char* str)
CaselessCmp::operator()(string_view lhs, string_view rhs) const
{
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";
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 false;
}
}
bool
IsFalseValue(string_view str)
{
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

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

@ -1,6 +1,7 @@
set(TEST_EXE testAll)
list(APPEND TEST_SRC
config/test_llarp_config_ini.cpp
crypto/test_llarp_crypto_types.cpp
crypto/test_llarp_crypto.cpp
dht/test_llarp_dht_bucket.cpp
@ -36,7 +37,6 @@ list(APPEND TEST_SRC
util/test_llarp_util_bencode.cpp
util/test_llarp_util_bits.cpp
util/test_llarp_util_encode.cpp
util/test_llarp_util_ini.cpp
util/test_llarp_util_metrics_core.cpp
util/test_llarp_util_metrics_types.cpp
util/test_llarp_util_memfn.cpp
@ -48,6 +48,7 @@ list(APPEND TEST_SRC
util/test_llarp_util_timerqueue.cpp
util/test_llarp_util_traits.cpp
util/test_llarp_utils_scheduler.cpp
util/test_llarp_utils_str.cpp
)
add_executable(${TEST_EXE}
@ -72,4 +73,4 @@ endif(NOT WIN32)
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
target_link_directories(${TEST_EXE} PRIVATE /usr/local/lib)
endif()
endif()

@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include <util/ini.hpp>
#include <config/ini.hpp>
struct TestINIParser : public ::testing::Test
{

@ -1,15 +1,18 @@
#include <exit/context.hpp>
#include <router/router.hpp>
#include <exit/context.hpp>
#include <gtest/gtest.h>
struct ExitTest : public ::testing::Test
{
ExitTest() : r(nullptr, nullptr, nullptr)
ExitTest() : r(nullptr, nullptr, nullptr), context(&r)
{
}
llarp::Router r;
llarp::exit::Context context;
};
TEST_F(ExitTest, AddMultipleIP)
@ -23,9 +26,10 @@ TEST_F(ExitTest, AddMultipleIP)
conf.emplace("exit", "true");
conf.emplace("type", "null");
conf.emplace("ifaddr", "10.0.0.1/24");
ASSERT_TRUE(r.exitContext().AddExitEndpoint("test-exit", conf));
ASSERT_TRUE(r.exitContext().ObtainNewExit(pk, firstPath, true));
ASSERT_TRUE(r.exitContext().ObtainNewExit(pk, secondPath, true));
ASSERT_TRUE(r.exitContext().FindEndpointForPath(firstPath)->LocalIP()
== r.exitContext().FindEndpointForPath(secondPath)->LocalIP());
ASSERT_TRUE(context.AddExitEndpoint("test-exit", conf));
ASSERT_TRUE(context.ObtainNewExit(pk, firstPath, true));
ASSERT_TRUE(context.ObtainNewExit(pk, secondPath, true));
ASSERT_TRUE(context.FindEndpointForPath(firstPath)->LocalIP()
== context.FindEndpointForPath(secondPath)->LocalIP());
}

@ -0,0 +1,68 @@
#include <util/str.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace llarp;
using namespace ::testing;
struct CmpTestData
{
bool lt;
std::string lhs;
std::string rhs;
};
class CaselessCmpTest : public ::testing::TestWithParam< CmpTestData >
{
};
TEST_P(CaselessCmpTest, test)
{
CaselessCmp cmp;
auto d = GetParam();
ASSERT_EQ(d.lt, cmp(d.lhs, d.rhs));
}
std::vector< CmpTestData > CMPTESTDATA{
{true, "", "1"}, {false, "1", ""}, {true, "abc", "abcd"},
{true, "abc", "abd"}, {false, "11", "1"}, {false, "a", "A"},
{false, "abc", "aBc"}, {false, "ABC", "abc"}};
INSTANTIATE_TEST_SUITE_P(TestStr, CaselessCmpTest, ValuesIn(CMPTESTDATA));
using TestData = std::pair< bool, std::string >;
class TestIsFalseValue : public ::testing::TestWithParam< TestData >
{
};
TEST_P(TestIsFalseValue, test)
{
ASSERT_EQ(GetParam().first, IsFalseValue(GetParam().second));
}
std::vector< TestData > FALSE_DATA{
{true, "false"}, {true, "FaLsE"}, {true, "no"}, {true, "nO"},
{true, "No"}, {true, "NO"}, {true, "NO"}, {true, "0"},
{true, "off"}, {true, "oFF"}, {false, "false y"}, {false, "true"},
{false, "tRue"}, {false, "on"}};
INSTANTIATE_TEST_SUITE_P(TestStr, TestIsFalseValue, ValuesIn(FALSE_DATA));
class TestIsTrueValue : public ::testing::TestWithParam< TestData >
{
};
TEST_P(TestIsTrueValue, test)
{
ASSERT_EQ(GetParam().first, IsTrueValue(GetParam().second));
}
std::vector< TestData > TRUE_DATA{
{true, "true"}, {true, "TruE"}, {true, "yes"}, {true, "yeS"},
{true, "yES"}, {true, "YES"}, {true, "1"}, {false, "0"},
{true, "on"}, {true, "oN"}, {false, "false y"}, {false, "truth"},
{false, "false"}, {false, "off"}};
INSTANTIATE_TEST_SUITE_P(TestStr, TestIsTrueValue, ValuesIn(TRUE_DATA));
Loading…
Cancel
Save