mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
23 KiB
415 lines
23 KiB
/* |
|
* Copyright (c) 2013-2020, The PurpleI2P Project |
|
* |
|
* This file is part of Purple i2pd project and licensed under BSD3 |
|
* |
|
* See full license text in LICENSE file at top of project tree |
|
*/ |
|
|
|
#include <cstdlib> |
|
#include <iostream> |
|
#include <fstream> |
|
#include <map> |
|
#include <string> |
|
#include <boost/program_options/cmdline.hpp> |
|
#include <boost/program_options/options_description.hpp> |
|
#include <boost/program_options/parsers.hpp> |
|
#include <boost/program_options/variables_map.hpp> |
|
|
|
#include "Identity.h" |
|
#include "Config.h" |
|
#include "version.h" |
|
#include "Log.h" |
|
|
|
using namespace boost::program_options; |
|
|
|
namespace i2p { |
|
namespace config { |
|
options_description m_OptionsDesc; |
|
variables_map m_Options; |
|
|
|
void Init() |
|
{ |
|
options_description general("General options"); |
|
general.add_options() |
|
("help", "Show this message") |
|
("version", "Show i2pd version") |
|
("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)") |
|
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)") |
|
("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d") |
|
("certsdir", value<std::string>()->default_value(""), "Path to certificates used for verifying .su3, families (default: ~/.i2pd/certificates or /var/lib/i2pd/certificates") |
|
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") |
|
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") |
|
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") |
|
("loglevel", value<std::string>()->default_value("warn"), "Set the minimal level of log messages (debug, info, warn, error, none)") |
|
("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)") |
|
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to") |
|
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") |
|
("host", value<std::string>()->default_value("0.0.0.0"), "External IP") |
|
("ifname", value<std::string>()->default_value(""), "Network interface to bind to") |
|
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4") |
|
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6") |
|
("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") |
|
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)") |
|
("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") |
|
("address4", value<std::string>()->default_value(""), "Local address to bind ipv4 transport sockets to") |
|
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") |
|
("address6", value<std::string>()->default_value(""), "Local address to bind ipv6 transport sockets to") |
|
("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") |
|
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") |
|
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") |
|
("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") |
|
("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)") |
|
("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") |
|
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") |
|
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") |
|
("ntcp", bool_switch()->default_value(false), "Ignored. Always false") |
|
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") |
|
("ntcpproxy", value<std::string>()->default_value(""), "Ignored") |
|
#ifdef _WIN32 |
|
("svcctl", value<std::string>()->default_value(""), "Ignored") |
|
("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") |
|
("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask") |
|
#endif |
|
; |
|
|
|
options_description limits("Limits options"); |
|
limits.add_options() |
|
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") |
|
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)") |
|
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)") |
|
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)") |
|
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)") |
|
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)") |
|
; |
|
|
|
options_description httpserver("HTTP Server options"); |
|
httpserver.add_options() |
|
("http.enabled", value<bool>()->default_value(true), "Enable or disable webconsole") |
|
("http.address", value<std::string>()->default_value("127.0.0.1"), "Webconsole listen address") |
|
("http.port", value<uint16_t>()->default_value(7070), "Webconsole listen port") |
|
("http.auth", value<bool>()->default_value(false), "Enable Basic HTTP auth for webconsole") |
|
("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth") |
|
("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)") |
|
("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI") |
|
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI") |
|
("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )") |
|
("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )") |
|
; |
|
|
|
options_description httpproxy("HTTP Proxy options"); |
|
httpproxy.add_options() |
|
("httpproxy.enabled", value<bool>()->default_value(true), "Enable or disable HTTP Proxy") |
|
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address") |
|
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port") |
|
("httpproxy.keys", value<std::string>()->default_value("transient-proxy"), "File to persist HTTP Proxy keys. Transient by default") |
|
("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()-> |
|
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") |
|
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length") |
|
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length") |
|
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity") |
|
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity") |
|
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels") |
|
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels") |
|
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url") |
|
("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper") |
|
("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type") |
|
("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type") |
|
("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key") |
|
; |
|
|
|
options_description socksproxy("SOCKS Proxy options"); |
|
socksproxy.add_options() |
|
("socksproxy.enabled", value<bool>()->default_value(true), "Enable or disable SOCKS Proxy") |
|
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address") |
|
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port") |
|
("socksproxy.keys", value<std::string>()->default_value("transient-proxy"), "File to persist SOCKS Proxy keys. Transient by default") |
|
("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()-> |
|
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") |
|
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length") |
|
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length") |
|
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity") |
|
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity") |
|
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels") |
|
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels") |
|
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy") |
|
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") |
|
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") |
|
("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type") |
|
("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type") |
|
("socksproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key") |
|
; |
|
|
|
options_description sam("SAM bridge options"); |
|
sam.add_options() |
|
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge") |
|
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address") |
|
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port") |
|
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread") |
|
; |
|
|
|
options_description bob("BOB options"); |
|
bob.add_options() |
|
("bob.enabled", value<bool>()->default_value(false), "Enable or disable BOB command channel") |
|
("bob.address", value<std::string>()->default_value("127.0.0.1"), "BOB listen address") |
|
("bob.port", value<uint16_t>()->default_value(2827), "BOB listen port") |
|
; |
|
|
|
options_description i2cp("I2CP options"); |
|
i2cp.add_options() |
|
("i2cp.enabled", value<bool>()->default_value(false), "Enable or disable I2CP") |
|
("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address") |
|
("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port") |
|
("i2cp.singlethread", value<bool>()->default_value(true), "Destinations run in the I2CP server's thread") |
|
; |
|
|
|
options_description i2pcontrol("I2PControl options"); |
|
i2pcontrol.add_options() |
|
("i2pcontrol.enabled", value<bool>()->default_value(false), "Enable or disable I2P Control Protocol") |
|
("i2pcontrol.address", value<std::string>()->default_value("127.0.0.1"), "I2PCP listen address") |
|
("i2pcontrol.port", value<uint16_t>()->default_value(7650), "I2PCP listen port") |
|
("i2pcontrol.password", value<std::string>()->default_value("itoopie"), "I2PCP access password") |
|
("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"), "I2PCP connection certificate") |
|
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection certificate key") |
|
; |
|
|
|
bool upnp_default = false; |
|
#if (defined(USE_UPNP) && (defined(WIN32_APP) || defined(ANDROID))) |
|
upnp_default = true; // enable UPNP for windows GUI and android by default |
|
#endif |
|
options_description upnp("UPnP options"); |
|
upnp.add_options() |
|
("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding") |
|
("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwarding list") |
|
; |
|
|
|
options_description precomputation("Precomputation options"); |
|
precomputation.add_options() |
|
("precomputation.elgamal", |
|
#if defined(__x86_64__) |
|
value<bool>()->default_value(false), |
|
#else |
|
value<bool>()->default_value(true), |
|
#endif |
|
"Enable or disable elgamal precomputation table") |
|
; |
|
|
|
options_description reseed("Reseed options"); |
|
reseed.add_options() |
|
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature") |
|
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed") |
|
("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from") |
|
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from") |
|
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from") |
|
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks") |
|
("reseed.urls", value<std::string>()->default_value( |
|
"https://reseed.i2p-projekt.de/," |
|
"https://reseed.diva.exchange/," |
|
"https://reseed-fr.i2pd.xyz/," |
|
"https://reseed.memcpy.io/," |
|
"https://reseed.onion.im/," |
|
"https://i2pseed.creativecowpat.net:8443/," |
|
"https://reseed.i2pgit.org/," |
|
"https://i2p.novg.net/" |
|
), "Reseed URLs, separated by comma") |
|
("reseed.yggurls", value<std::string>()->default_value( |
|
"http://[324:71e:281a:9ed3::ace]:7070/" |
|
), "Reseed URLs through the Yggdrasil, separated by comma") |
|
; |
|
|
|
options_description addressbook("AddressBook options"); |
|
addressbook.add_options() |
|
("addressbook.defaulturl", value<std::string>()->default_value( |
|
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt" |
|
), "AddressBook subscription URL for initial setup") |
|
("addressbook.subscriptions", value<std::string>()->default_value("http://reg.i2p/hosts.txt"), "AddressBook subscriptions URLs, separated by comma") |
|
("addressbook.hostsfile", value<std::string>()->default_value(""), "File to dump addresses in hosts.txt format"); |
|
|
|
options_description trust("Trust options"); |
|
trust.add_options() |
|
("trust.enabled", value<bool>()->default_value(false), "Enable explicit trust options") |
|
("trust.family", value<std::string>()->default_value(""), "Router Family to trust for first hops") |
|
("trust.routers", value<std::string>()->default_value(""), "Only Connect to these routers") |
|
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?") |
|
; |
|
|
|
// Save deprecated websocket options for compatibility |
|
options_description websocket("Websocket Options"); |
|
websocket.add_options() |
|
("websockets.enabled", value<bool>()->default_value(false), "Deprecated option") |
|
("websockets.address", value<std::string>()->default_value(""), "Deprecated option") |
|
("websockets.port", value<uint16_t>()->default_value(0), "Deprecated option") |
|
; |
|
|
|
options_description exploratory("Exploratory Options"); |
|
exploratory.add_options() |
|
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length") |
|
("exploratory.outbound.length", value<int>()->default_value(2), "Exploratory outbound tunnel length") |
|
("exploratory.inbound.quantity", value<int>()->default_value(3), "Exploratory inbound tunnels quantity") |
|
("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity") |
|
; |
|
|
|
options_description ntcp2("NTCP2 Options"); |
|
ntcp2.add_options() |
|
("ntcp2.enabled", value<bool>()->default_value(true), "Enable NTCP2 (default: enabled)") |
|
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)") |
|
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") |
|
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to publish NTCP2 with") |
|
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport") |
|
; |
|
|
|
options_description nettime("Time sync options"); |
|
nettime.add_options() |
|
("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)") |
|
("nettime.ntpservers", value<std::string>()->default_value( |
|
"0.pool.ntp.org," |
|
"1.pool.ntp.org," |
|
"2.pool.ntp.org," |
|
"3.pool.ntp.org" |
|
), "Comma separated list of NTCP servers") |
|
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)") |
|
; |
|
|
|
options_description persist("Network information persisting options"); |
|
persist.add_options() |
|
("persist.profiles", value<bool>()->default_value(true), "Persist peer profiles (default: true)") |
|
("persist.addressbook", value<bool>()->default_value(true), "Persist full addresses (default: true)") |
|
; |
|
|
|
options_description cpuext("CPU encryption extensions options"); |
|
cpuext.add_options() |
|
("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used") |
|
("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used") |
|
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") |
|
; |
|
|
|
options_description meshnets("Meshnet transports options"); |
|
meshnets.add_options() |
|
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)") |
|
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish") |
|
; |
|
|
|
m_OptionsDesc |
|
.add(general) |
|
.add(limits) |
|
.add(httpserver) |
|
.add(httpproxy) |
|
.add(socksproxy) |
|
.add(sam) |
|
.add(bob) |
|
.add(i2cp) |
|
.add(i2pcontrol) |
|
.add(upnp) |
|
.add(precomputation) |
|
.add(reseed) |
|
.add(addressbook) |
|
.add(trust) |
|
.add(websocket) // deprecated |
|
.add(exploratory) |
|
.add(ntcp2) |
|
.add(nettime) |
|
.add(persist) |
|
.add(cpuext) |
|
.add(meshnets) |
|
; |
|
} |
|
|
|
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown) |
|
{ |
|
try |
|
{ |
|
auto style = boost::program_options::command_line_style::unix_style |
|
| boost::program_options::command_line_style::allow_long_disguise; |
|
style &= ~ boost::program_options::command_line_style::allow_guessing; |
|
if (ignoreUnknown) |
|
store(command_line_parser(argc, argv).options(m_OptionsDesc).style (style).allow_unregistered().run(), m_Options); |
|
else |
|
store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options); |
|
} |
|
catch (boost::program_options::error& e) |
|
{ |
|
ThrowFatal ("Error while parsing arguments: ", e.what()); |
|
std::cerr << "args: " << e.what() << std::endl; |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
if (!ignoreUnknown && (m_Options.count("help") || m_Options.count("h"))) |
|
{ |
|
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; |
|
std::cout << m_OptionsDesc; |
|
exit(EXIT_SUCCESS); |
|
} |
|
else if (m_Options.count("version")) |
|
{ |
|
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; |
|
std::cout << "Boost version " |
|
<< BOOST_VERSION / 100000 << "." // maj. version |
|
<< BOOST_VERSION / 100 % 1000 << "." // min. version |
|
<< BOOST_VERSION % 100 // patch version |
|
<< std::endl; |
|
#if defined(OPENSSL_VERSION_TEXT) |
|
std::cout << OPENSSL_VERSION_TEXT << std::endl; |
|
#endif |
|
#if defined(LIBRESSL_VERSION_TEXT) |
|
std::cout << LIBRESSL_VERSION_TEXT << std::endl; |
|
#endif |
|
|
|
exit(EXIT_SUCCESS); |
|
} |
|
} |
|
|
|
void ParseConfig(const std::string& path) |
|
{ |
|
if (path == "") return; |
|
|
|
std::ifstream config(path, std::ios::in); |
|
|
|
if (!config.is_open()) |
|
{ |
|
ThrowFatal ("Missing or unreadable config file: ", path); |
|
std::cerr << "missing/unreadable config file: " << path << std::endl; |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
try |
|
{ |
|
store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options); |
|
} |
|
catch (boost::program_options::error& e) |
|
{ |
|
ThrowFatal ("Error while parsing config file: ", e.what()); |
|
std::cerr << e.what() << std::endl; |
|
exit(EXIT_FAILURE); |
|
}; |
|
} |
|
|
|
void Finalize() |
|
{ |
|
notify(m_Options); |
|
} |
|
|
|
bool IsDefault(const char *name) |
|
{ |
|
if (!m_Options.count(name)) |
|
throw "try to check non-existent option"; |
|
|
|
if (m_Options[name].defaulted()) |
|
return true; |
|
return false; |
|
} |
|
|
|
bool GetOptionAsAny(const char *name, boost::any& value) |
|
{ |
|
if (!m_Options.count(name)) |
|
return false; |
|
value = m_Options[name]; |
|
return true; |
|
} |
|
|
|
bool GetOptionAsAny(const std::string& name, boost::any& value) |
|
{ |
|
return GetOptionAsAny (name.c_str (), value); |
|
} |
|
|
|
} // namespace config |
|
} // namespace i2p
|
|
|