/* * Copyright (c) 2013-2016, 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 #include #include #include #include #include #include #include #include #include "Config.h" #include "version.h" using namespace boost::program_options; namespace i2p { namespace config { options_description m_OptionsDesc; variables_map m_Options; /* list of renamed options */ std::map remapped_options = { { "tunnelscfg", "tunconf" }, { "v6", "ipv6" }, { "httpaddress", "http.address" }, { "httpport", "http.port" }, { "httpproxyaddress", "httpproxy.address" }, { "httpproxyport", "httpproxy.port" }, { "socksproxyaddress", "socksproxy.address" }, { "socksproxyport", "socksproxy.port" }, { "samaddress", "sam.address" }, { "samport", "sam.port" }, { "bobaddress", "bob.address" }, { "bobport", "bob.port" }, { "i2pcontroladdress", "i2pcontrol.address" }, { "i2pcontroladdress", "i2pcontrol.port" }, { "proxykeys", "httpproxy.keys" }, }; /* list of options, that loose their argument and become simple switch */ std::set boolean_options = { "daemon", "floodfill", "notransit", "service", "ipv6" }; /* this function is a solid piece of shit, remove it after 2.6.0 */ std::pair old_syntax_parser(const std::string& s) { std::string name = ""; std::string value = ""; std::size_t pos = 0; /* shortcuts -- -h */ if (s.length() == 2 && s.at(0) == '-' && s.at(1) != '-') return make_pair(s.substr(1), ""); /* old-style -- -log, /log, etc */ if (s.at(0) == '/' || (s.at(0) == '-' && s.at(1) != '-')) { if ((pos = s.find_first_of("= ")) != std::string::npos) { name = s.substr(1, pos - 1); value = s.substr(pos + 1); } else { name = s.substr(1, pos); value = ""; } if (boolean_options.count(name) > 0 && value != "") std::cerr << "args: don't give an argument to switch option: " << s << std::endl; if (m_OptionsDesc.find_nothrow(name, false)) { std::cerr << "args: option " << s << " style is DEPRECATED, use --" << name << " instead" << std::endl; return std::make_pair(name, value); } if (remapped_options.count(name) > 0) { name = remapped_options[name]; std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl; return std::make_pair(name, value); } /* else */ } /* long options -- --help */ if (s.substr(0, 2) == "--") { if ((pos = s.find_first_of("= ")) != std::string::npos) { name = s.substr(2, pos - 2); value = s.substr(pos + 1); } else { name = s.substr(2, pos); value = ""; } if (boolean_options.count(name) > 0 && value != "") { std::cerr << "args: don't give an argument to switch option: " << s << std::endl; value = ""; } if (m_OptionsDesc.find_nothrow(name, false)) return std::make_pair(name, value); if (remapped_options.count(name) > 0) { name = remapped_options[name]; std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl; return std::make_pair(name, value); } /* else */ } std::cerr << "args: unknown option -- " << s << std::endl; return std::make_pair("", ""); } void Init() { options_description general("General options"); general.add_options() ("help", "Show this message") ("conf", value()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)") ("tunconf", value()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)") ("pidfile", value()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", value()->zero_tokens()->default_value(true), "Enable communication through ipv4") ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") ("daemon", value()->zero_tokens()->default_value(false), "Router will go to background after start") ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") ("notransit", value()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup") ("floodfill", value()->zero_tokens()->default_value(false), "Router will be floodfill") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in kbps or letters: L (32), O (256), P (2048), X (>9000)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something #endif ; options_description limits("Limits options"); limits.add_options() ("limits.transittunnels", value()->default_value(2500), "Maximum active transit sessions (default:2500)") ; options_description httpserver("HTTP Server options"); httpserver.add_options() ("http.enabled", value()->default_value(true), "Enable or disable webconsole") ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") ("http.port", value()->default_value(7070), "Webconsole listen port") ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") ("http.user", value()->default_value("i2pd"), "Username for basic auth") ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") ; options_description httpproxy("HTTP Proxy options"); httpproxy.add_options() ("httpproxy.enabled", value()->default_value(true), "Enable or disable HTTP Proxy") ("httpproxy.address", value()->default_value("127.0.0.1"), "HTTP Proxy listen address") ("httpproxy.port", value()->default_value(4444), "HTTP Proxy listen port") ("httpproxy.keys", value()->default_value(""), "File to persist HTTP Proxy keys") ; options_description socksproxy("SOCKS Proxy options"); socksproxy.add_options() ("socksproxy.enabled", value()->default_value(true), "Enable or disable SOCKS Proxy") ("socksproxy.address", value()->default_value("127.0.0.1"), "SOCKS Proxy listen address") ("socksproxy.port", value()->default_value(4447), "SOCKS Proxy listen port") ("socksproxy.keys", value()->default_value(""), "File to persist SOCKS Proxy keys") ("socksproxy.outproxy", value()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") ("socksproxy.outproxyport", value()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") ; options_description sam("SAM bridge options"); sam.add_options() ("sam.enabled", value()->default_value(false), "Enable or disable SAM Application bridge") ("sam.address", value()->default_value("127.0.0.1"), "SAM listen address") ("sam.port", value()->default_value(7656), "SAM listen port") ; options_description bob("BOB options"); bob.add_options() ("bob.enabled", value()->default_value(false), "Enable or disable BOB command channel") ("bob.address", value()->default_value("127.0.0.1"), "BOB listen address") ("bob.port", value()->default_value(2827), "BOB listen port") ; options_description i2pcontrol("I2PControl options"); i2pcontrol.add_options() ("i2pcontrol.enabled", value()->default_value(false), "Enable or disable I2P Control Protocol") ("i2pcontrol.address", value()->default_value("127.0.0.1"), "I2PCP listen address") ("i2pcontrol.port", value()->default_value(7650), "I2PCP listen port") ("i2pcontrol.password", value()->default_value("itoopie"), "I2PCP access password") ("i2pcontrol.cert", value()->default_value("i2pcontrol.crt.pem"), "I2PCP connection cerificate") ("i2pcontrol.key", value()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key") ; options_description precomputation("Precomputation options"); precomputation.add_options() ("precomputation.elgamal", #if defined(__x86_64__) value()->default_value(false), #else value()->default_value(true), #endif "Enable or disable elgamal precomputation table") ; m_OptionsDesc .add(general) .add(limits) .add(httpserver) .add(httpproxy) .add(socksproxy) .add(sam) .add(bob) .add(i2pcontrol) .add(precomputation) ; } void ParseCmdline(int argc, char* argv[]) { 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; store(parse_command_line(argc, argv, m_OptionsDesc, style, old_syntax_parser), m_Options); } catch (boost::program_options::error& e) { std::cerr << "args: " << e.what() << std::endl; exit(EXIT_FAILURE); } if (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); } } void ParseConfig(const std::string& path) { if (path == "") return; std::ifstream config(path, std::ios::in); if (!config.is_open()) { 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) { 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; } } // namespace config } // namespace i2p