Browse Source

Merge branch 'new-cmdline' into openssl

Conflicts:
	ClientContext.cpp
	Daemon.cpp
	I2PControl.cpp
	I2PControl.h
	docs/configuration.md
pull/358/head
hagen 9 years ago
parent
commit
900fc1cb46
  1. 2
      AddressBook.cpp
  2. 51
      ClientContext.cpp
  3. 225
      Config.cpp
  4. 100
      Config.h
  5. 119
      Daemon.cpp
  6. 6
      DaemonLinux.cpp
  7. 3
      DaemonWin32.cpp
  8. 293
      I2PControl.cpp
  9. 58
      I2PControl.h
  10. 8
      RouterContext.cpp
  11. 5
      api.cpp
  12. 1
      build/CMakeLists.txt
  13. 23
      debian/i2pd.conf
  14. 2
      debian/i2pd.init
  15. 6
      debian/i2pd.upstart
  16. 6
      debian/postinst
  17. 43
      docs/config_opts_after_2.3.0.md
  18. 78
      docs/configuration.md
  19. 4
      filelist.mk
  20. 121
      util.cpp
  21. 8
      util.h

2
AddressBook.cpp

@ -396,7 +396,7 @@ namespace client
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
} }
else else
LogPrint (eLogWarning, "Addresbook: subscriptions.txt not found"); LogPrint (eLogWarning, "Addresbook: subscriptions.txt not found in datadir");
} }
else else
LogPrint (eLogError, "Addressbook: subscriptions already loaded"); LogPrint (eLogError, "Addressbook: subscriptions already loaded");

51
ClientContext.cpp

@ -2,6 +2,7 @@
#include <iostream> #include <iostream>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include "Config.h"
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
#include "Identity.h" #include "Identity.h"
@ -37,46 +38,58 @@ namespace client
} }
std::shared_ptr<ClientDestination> localDestination; std::shared_ptr<ClientDestination> localDestination;
// proxies bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", ""); if (httproxy) {
if (proxyKeys.length () > 0) std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr);
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
if (httpProxyKeys.length () > 0)
{ {
i2p::data::PrivateKeys keys; i2p::data::PrivateKeys keys;
LoadPrivateKeys (keys, proxyKeys); LoadPrivateKeys (keys, httpProxyKeys);
localDestination = CreateNewLocalDestination (keys, false); localDestination = CreateNewLocalDestination (keys, false);
} }
std::string httpProxyAddr = i2p::util::config::GetArg("-httpproxyaddress", "127.0.0.1");
uint16_t httpProxyPort = i2p::util::config::GetArg("-httpproxyport", 4444);
LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination);
m_HttpProxy->Start(); m_HttpProxy->Start();
}
std::string socksProxyAddr = i2p::util::config::GetArg("-socksproxyaddress", "127.0.0.1"); bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy);
uint16_t socksProxyPort = i2p::util::config::GetArg("-socksproxyport", 4447); if (socksproxy) {
std::string socksOutProxyAddr = i2p::util::config::GetArg("-socksoutproxyaddress", ""); std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys);
uint16_t socksOutProxyPort = i2p::util::config::GetArg("-socksoutproxyport", 0); std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr);
uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort);
std::string socksOutProxyAddr; i2p::config::GetOption("socksproxy.outproxy", socksOutProxyAddr);
uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort);
LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort);
if (socksProxyKeys.length () > 0)
{
i2p::data::PrivateKeys keys;
LoadPrivateKeys (keys, socksProxyKeys);
localDestination = CreateNewLocalDestination (keys, false);
}
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination);
m_SocksProxy->Start(); m_SocksProxy->Start();
}
// I2P tunnels // I2P tunnels
ReadTunnels (); ReadTunnels ();
// SAM // SAM
std::string samAddr = i2p::util::config::GetArg("-samaddress", "127.0.0.1"); bool sam; i2p::config::GetOption("sam.enabled", sam);
uint16_t samPort = i2p::util::config::GetArg("-samport", 0); if (sam) {
if (samPort) std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
{ uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort); LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
m_SamBridge = new SAMBridge (samAddr, samPort); m_SamBridge = new SAMBridge (samAddr, samPort);
m_SamBridge->Start (); m_SamBridge->Start ();
} }
// BOB // BOB
std::string bobAddr = i2p::util::config::GetArg("-bobaddress", "127.0.0.1"); bool bob; i2p::config::GetOption("bob.enabled", bob);
uint16_t bobPort = i2p::util::config::GetArg("-bobport", 0); if (bob) {
if (bobPort) std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr);
{ uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort);
LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort); LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort);
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
m_BOBCommandChannel->Start (); m_BOBCommandChannel->Start ();

225
Config.cpp

@ -0,0 +1,225 @@
/*
* 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 <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 "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<std::string, std::string> 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<std::string> boolean_options = {
"daemon", "floodfill", "notransit", "service", "ipv6"
};
/* this function is a solid piece of shit, remove it after 2.6.0 */
std::pair<std::string, std::string> 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<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)")
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)")
("pidfile", value<std::string>()->default_value(""), "Write pidfile to given path")
("log", value<std::string>()->default_value(""), "Write logs to file instead stdout")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
("host", value<std::string>()->default_value(""), "External IP (deprecated)")
("port", value<uint16_t>()->default_value(4567), "Port to listen for incoming connections")
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
("daemon", value<bool>()->zero_tokens()->default_value(false), "Router will go to background after start")
("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'")
("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not forward transit traffic")
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will try to become floodfill")
("bandwidth", value<char>()->default_value('O'), "Bandwidth limiting: L - 32kbps, O - 256Kbps, P - unlimited (ignored if floodfill)")
;
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")
;
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("httpproxy-keys.dat"), "HTTP Proxy encryption keys")
;
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("socksproxy-keys.dat"), "SOCKS Proxy encryption keys")
;
options_description sam("SAM bridge options");
sam.add_options()
("sam.enabled", value<bool>()->default_value(false), "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")
;
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 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 cerificate")
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key")
;
m_OptionsDesc
.add(general)
.add(httpserver)
.add(httpproxy)
.add(socksproxy)
.add(sam)
.add(bob)
.add(i2pcontrol)
;
}
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);
};
} // namespace config
} // namespace i2p

100
Config.h

@ -0,0 +1,100 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <string>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
/**
* Functions to parse and store i2pd parameters
*
* General usage flow:
* Init() -- early as possible
* ParseCmdline() -- somewhere close to main()
* ParseConfig() -- after detecting path to config
* Finalize() -- right after all Parse*() functions called
* GetOption() -- may be called after Finalize()
*/
namespace i2p {
namespace config {
extern boost::program_options::variables_map m_Options;
/**
* @brief Initialize list of acceptable parameters
*
* Should be called before any Parse* functions.
*/
void Init();
/**
* @brief Parse cmdline parameters, and show help if requested
* @param argc Cmdline arguments count, should be passed from main().
* @param argv Cmdline parameters array, should be passed from main()
*
* If --help is given in parameters, shows it's list with description
* terminates the program with exitcode 0.
*
* In case of parameter misuse boost throws an exception.
* We internally handle type boost::program_options::unknown_option,
* and then terminate program with exitcode 1.
*
* Other exceptions will be passed to higher level.
*/
void ParseCmdline(int argc, char* argv[]);
/**
* @brief Load and parse given config file
* @param path Path to config file
*
* If error occured when opening file path is points to,
* we show the error message and terminate program.
*
* In case of parameter misuse boost throws an exception.
* We internally handle type boost::program_options::unknown_option,
* and then terminate program with exitcode 1.
*
* Other exceptions will be passed to higher level.
*/
void ParseConfig(const std::string& path);
/**
* @brief Used to combine options from cmdline, config and default values
*/
void Finalize();
/* @brief Accessor to parameters by name
* @param name Name of the requested parameter
* @param value Variable where to store option
* @return this function returns false if parameter not found
*
* @example uint16_t port; GetOption("sam.port", port);
*/
template<typename T>
bool GetOption(const char *name, T& value) {
if (!m_Options.count(name))
return false;
value = m_Options[name].as<T>();
return true;
}
/**
* @brief Set value of given parameter
* @param name Name of settable parameter
* @param value New parameter value
* @return true if value set up successful, false otherwise
*
* @example uint16_t port = 2827; SetOption("bob.port", port);
*/
template<typename T>
bool SetOption(const char *name, const T& value) {
if (!m_Options.count(name))
return false;
m_Options[name] = value;
notify(m_Options);
return true;
}
}
}
#endif // CONFIG_H

119
Daemon.cpp

@ -3,6 +3,7 @@
#include "Daemon.h" #include "Daemon.h"
#include "Config.h"
#include "Log.h" #include "Log.h"
#include "Base.h" #include "Base.h"
#include "version.h" #include "version.h"
@ -50,78 +51,106 @@ namespace i2p
bool Daemon_Singleton::IsService () const bool Daemon_Singleton::IsService () const
{ {
bool service = false;
#ifndef _WIN32 #ifndef _WIN32
return i2p::util::config::GetArg("-service", 0); i2p::config::GetOption("service", service);
#else
return false;
#endif #endif
return service;
} }
bool Daemon_Singleton::init(int argc, char* argv[]) bool Daemon_Singleton::init(int argc, char* argv[])
{ {
std::string config = i2p::util::filesystem::GetConfigFile().string();
std::string tunconf = i2p::util::filesystem::GetTunnelsConfigFile().string();
std::string datadir = i2p::util::filesystem::GetDataDir().string();
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: tunnels config: ", tunconf);
LogPrint(eLogDebug, "FS: data directory: ", datadir);
i2p::config::Init();
i2p::config::ParseCmdline(argc, argv);
i2p::config::ParseConfig(config);
i2p::config::Finalize();
i2p::crypto::InitCrypto (); i2p::crypto::InitCrypto ();
i2p::util::config::OptionParser(argc, argv);
i2p::context.Init (); i2p::context.Init ();
LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); i2p::config::GetOption("daemon", isDaemon);
LogPrint(eLogDebug, "FS: data directory: ", i2p::util::filesystem::GetDataDir().string());
i2p::util::config::ReadConfigFile(i2p::util::filesystem::GetConfigFile());
isDaemon = i2p::util::config::GetArg("-daemon", 0); // temporary hack
isLogging = i2p::util::config::GetArg("-log", (int)isDaemon); std::string logs = "";
i2p::config::GetOption("log", logs);
if (logs != "")
isLogging = true;
int port = i2p::util::config::GetArg("-port", 0); uint16_t port; i2p::config::GetOption("port", port);
if (port) LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
i2p::context.UpdatePort (port); i2p::context.UpdatePort (port);
std::string host = i2p::util::config::GetArg("-host", "");
if (host != "") std::string host; i2p::config::GetOption("host", host);
if (host != "") {
LogPrint(eLogInfo, "Daemon: address for incoming connections is ", host);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host)); i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
}
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0)); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
i2p::context.SetAcceptsTunnels (!i2p::util::config::GetArg("-notransit", 0)); bool transit; i2p::config::GetOption("notransit", transit);
bool isFloodfill = i2p::util::config::GetArg("-floodfill", 0); i2p::context.SetSupportsV6 (ipv6);
i2p::context.SetFloodfill (isFloodfill); i2p::context.SetAcceptsTunnels (!transit);
auto bandwidth = i2p::util::config::GetArg("-bandwidth", "");
if (bandwidth.length () > 0) bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
{ char bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
if (bandwidth[0] > 'O')
if (isFloodfill) {
LogPrint(eLogInfo, "Daemon: router will be floodfill, bandwidth set to 'extra'");
i2p::context.SetFloodfill (true);
i2p::context.SetExtraBandwidth (); i2p::context.SetExtraBandwidth ();
else if (bandwidth[0] > 'L') } else if (bandwidth != '-') {
i2p::context.SetHighBandwidth (); LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth);
else switch (bandwidth) {
i2p::context.SetLowBandwidth (); case 'P' : i2p::context.SetExtraBandwidth (); break;
case 'L' : i2p::context.SetHighBandwidth (); break;
default : i2p::context.SetLowBandwidth (); break;
}
} }
else if (isFloodfill)
i2p::context.SetExtraBandwidth ();
LogPrint(eLogDebug, "Daemon: CMD parameters:");
for (int i = 0; i < argc; ++i)
LogPrint(eLogDebug, i, ": ", argv[i]);
return true; return true;
} }
bool Daemon_Singleton::start() bool Daemon_Singleton::start()
{ {
// initialize log
if (isLogging) if (isLogging)
{ {
std::string logfile_path = IsService () ? "/var/log/i2pd" : i2p::util::filesystem::GetDataDir().string(); // set default to stdout
std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
if (isDaemon && logfile == "") {
// can't log to stdout, use autodetect of logfile
if (IsService ()) {
logfile = "/var/log";
} else {
logfile = i2p::util::filesystem::GetDataDir().string();
}
#ifndef _WIN32 #ifndef _WIN32
logfile_path.append("/i2pd.log"); logfile.append("/i2pd.log");
#else #else
logfile_path.append("\\i2pd.log"); logfile.append("\\i2pd.log");
#endif #endif
StartLog (logfile_path);
} }
else StartLog (logfile);
StartLog (""); // write to stdout g_Log->SetLogLevel(loglevel);
g_Log->SetLogLevel(i2p::util::config::GetArg("-loglevel", "info")); }
std::string httpAddr = i2p::util::config::GetArg("-httpaddress", "127.0.0.1"); bool http; i2p::config::GetOption("http.enabled", http);
uint16_t httpPort = i2p::util::config::GetArg("-httpport", 7070); if (http) {
LogPrint(eLogInfo, "Daemon: staring HTTP Server at ", httpAddr, ":", httpPort); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(httpAddr, httpPort)); d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(httpAddr, httpPort));
d.httpServer->Start(); d.httpServer->Start();
}
LogPrint(eLogInfo, "Daemon: starting NetDB"); LogPrint(eLogInfo, "Daemon: starting NetDB");
i2p::data::netdb.Start(); i2p::data::netdb.Start();
@ -140,10 +169,10 @@ namespace i2p
i2p::client::context.Start (); i2p::client::context.Start ();
// I2P Control Protocol // I2P Control Protocol
std::string i2pcpAddr = i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"); bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
uint16_t i2pcpPort = i2p::util::config::GetArg("-i2pcontrolport", 0); if (i2pcontrol) {
if (i2pcpPort) std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
{ uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort);
LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort); LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
d.m_I2PControlService->Start (); d.m_I2PControlService->Start ();

6
DaemonLinux.cpp

@ -8,10 +8,10 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "Config.h"
#include "Log.h" #include "Log.h"
#include "util.h" #include "util.h"
void handle_signal(int sig) void handle_signal(int sig)
{ {
switch (sig) switch (sig)
@ -28,7 +28,6 @@ void handle_signal(int sig)
} }
} }
namespace i2p namespace i2p
{ {
namespace util namespace util
@ -74,7 +73,7 @@ namespace i2p
// Pidfile // Pidfile
// this code is c-styled and a bit ugly, but we need fd for locking pidfile // this code is c-styled and a bit ugly, but we need fd for locking pidfile
pidfile = i2p::util::config::GetArg("-pidfile", ""); std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
if (pidfile == "") { if (pidfile == "") {
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string(); pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string();
pidfile.append("/i2pd.pid"); pidfile.append("/i2pd.pid");
@ -120,7 +119,6 @@ namespace i2p
return Daemon_Singleton::stop(); return Daemon_Singleton::stop();
} }
} }
} }

3
DaemonWin32.cpp

@ -1,3 +1,4 @@
#include "Config.h"
#include "Daemon.h" #include "Daemon.h"
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
@ -23,7 +24,7 @@ namespace i2p
else else
isDaemon = 0; isDaemon = 0;
std::string serviceControl = i2p::util::config::GetArg("-svcctl", ""); std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl);
if (serviceControl == "install") if (serviceControl == "install")
{ {
LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service");

293
I2PControl.cpp

@ -1,5 +1,3 @@
// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
#include <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include <openssl/x509.h> #include <openssl/x509.h>
@ -8,10 +6,15 @@
#include <boost/date_time/local_time/local_time.hpp> #include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
#if !GCC47_BOOST149 #if !GCC47_BOOST149
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#endif #endif
#include "Log.h" #include "Log.h"
#include "Config.h"
#include "NetDb.h" #include "NetDb.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "Daemon.h" #include "Daemon.h"
@ -26,58 +29,56 @@ namespace i2p
namespace client namespace client
{ {
I2PControlService::I2PControlService (const std::string& address, int port): I2PControlService::I2PControlService (const std::string& address, int port):
m_Password (I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning (false), m_Thread (nullptr), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
m_SSLContext (m_Service, boost::asio::ssl::context::sslv23), m_SSLContext (m_Service, boost::asio::ssl::context::sslv23),
m_ShutdownTimer (m_Service) m_ShutdownTimer (m_Service)
{ {
LoadConfig (); i2p::config::GetOption("i2pcontrol.password", m_Password);
// certificate
// certificate / keys
std::string i2pcp_crt; i2p::config::GetOption("i2pcontrol.cert", i2pcp_crt);
std::string i2pcp_key; i2p::config::GetOption("i2pcontrol.key", i2pcp_key);
// TODO: properly handle absolute paths
auto path = GetPath (); auto path = GetPath ();
if (!boost::filesystem::exists (path)) if (!boost::filesystem::exists (path / i2pcp_crt) ||
{ !boost::filesystem::exists (path / i2pcp_key))
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create i2pcontrol directory");
}
if (!boost::filesystem::exists (path / I2P_CONTROL_KEY_FILE) ||
!boost::filesystem::exists (path / I2P_CONTROL_CERT_FILE))
{ {
// create new certificate LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection");
CreateCertificate (); CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
LogPrint (eLogInfo, "I2PControl certificates created");
} }
m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use);
m_SSLContext.use_certificate_file ((path / I2P_CONTROL_CERT_FILE).string (), boost::asio::ssl::context::pem); m_SSLContext.use_certificate_file ((path / i2pcp_crt).string (), boost::asio::ssl::context::pem);
m_SSLContext.use_private_key_file ((path / I2P_CONTROL_KEY_FILE).string (), boost::asio::ssl::context::pem); m_SSLContext.use_private_key_file ((path / i2pcp_crt).string (), boost::asio::ssl::context::pem);
// handlers // handlers
m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler; m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler; m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler; m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler; m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler; m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler; m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
// I2PControl // I2PControl
m_I2PControlHandlers[I2P_CONTROL_I2PCONTROL_PASSWORD] = &I2PControlService::PasswordHandler; m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
// RouterInfo // RouterInfo
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler; m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler; m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler; m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler; m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler; m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler; m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler; m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ; m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ; m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_TOTAL_RB] = &I2PControlService::NetTotalReceivedBytes; m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_TOTAL_SB] = &I2PControlService::NetTotalSentBytes; m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
// RouterManager // RouterManager
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler; m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler; m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler; m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
} }
I2PControlService::~I2PControlService () I2PControlService::~I2PControlService ()
@ -85,49 +86,6 @@ namespace client
Stop (); Stop ();
} }
void I2PControlService::LoadConfig ()
{
auto path = GetPath ();
if (!boost::filesystem::exists (path))
{
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create i2pcontrol directory");
}
boost::property_tree::ptree pt;
auto filename = path / I2P_CONTROL_CONFIG_FILE;
bool isNew = true;
if (boost::filesystem::exists (filename))
{
try
{
boost::property_tree::read_ini (filename.string (), pt);
isNew = false;
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ());
}
}
m_Password = pt.get (I2P_CONTROL_I2PCONTROL_PASSWORD, I2P_CONTROL_DEFAULT_PASSWORD);
if (isNew) SaveConfig ();
}
void I2PControlService::SaveConfig ()
{
boost::property_tree::ptree pt;
pt.put (I2P_CONTROL_I2PCONTROL_PASSWORD, m_Password);
auto filename = GetPath () / I2P_CONTROL_CONFIG_FILE;
// we take care about directory in LoadConfig
try
{
boost::property_tree::write_ini (filename.string (), pt);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
}
}
void I2PControlService::Start () void I2PControlService::Start ()
{ {
if (!m_IsRunning) if (!m_IsRunning)
@ -158,13 +116,10 @@ namespace client
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
try try {
{
m_Service.run (); m_Service.run ();
} } catch (std::exception& ex) {
catch (std::exception& ex) LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ());
{
LogPrint (eLogError, "I2PControl: ", ex.what ());
} }
} }
} }
@ -181,13 +136,12 @@ namespace client
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Accept (); Accept ();
if (!ecode) if (ecode) {
{ LogPrint (eLogError, "I2PControl: accept error: ", ecode.message ());
LogPrint (eLogInfo, "New I2PControl request from ", socket->lowest_layer ().remote_endpoint ()); return;
Handshake (socket);
} }
else LogPrint (eLogDebug, "I2PControl: new request from ", socket->lowest_layer ().remote_endpoint ());
LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); Handshake (socket);
} }
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket) void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
@ -198,14 +152,13 @@ namespace client
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket) void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
{ {
if (!ecode) if (ecode) {
{ LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ());
return;
}
//std::this_thread::sleep_for (std::chrono::milliseconds(5)); //std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket); ReadRequest (socket);
} }
else
LogPrint (eLogError, "I2PControl handshake error: ", ecode.message ());
}
void I2PControlService::ReadRequest (std::shared_ptr<ssl_socket> socket) void I2PControlService::ReadRequest (std::shared_ptr<ssl_socket> socket)
{ {
@ -224,12 +177,10 @@ namespace client
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket, size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf) std::shared_ptr<I2PControlBuffer> buf)
{ {
if (ecode) if (ecode) {
{ LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); return;
} } else {
else
{
try try
{ {
bool isHtml = !memcmp (buf->data (), "POST", 4); bool isHtml = !memcmp (buf->data (), "POST", 4);
@ -264,14 +215,14 @@ namespace client
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
boost::property_tree::read_json (ss, pt); boost::property_tree::read_json (ss, pt);
std::string method = pt.get<std::string>(I2P_CONTROL_PROPERTY_METHOD); std::string id = pt.get<std::string>("id");
std::string method = pt.get<std::string>("method");
auto it = m_MethodHandlers.find (method); auto it = m_MethodHandlers.find (method);
if (it != m_MethodHandlers.end ()) if (it != m_MethodHandlers.end ())
{ {
std::ostringstream response; std::ostringstream response;
response << "{\"id\":" << pt.get<std::string>(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{"; response << "{\"id\":" << id << ",\"result\":{";
(this->*(it->second))(pt.get_child ("params"), response);
(this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response);
response << "},\"jsonrpc\":\"2.0\"}"; response << "},\"jsonrpc\":\"2.0\"}";
SendResponse (socket, buf, response, isHtml); SendResponse (socket, buf, response, isHtml);
} }
@ -338,33 +289,34 @@ namespace client
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf) std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf)
{ {
if (ecode) if (ecode) {
LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: write error: ", ecode.message ());
}
} }
// handlers // handlers
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
int api = params.get<int> (I2P_CONTROL_PARAM_API); int api = params.get<int> ("API");
auto password = params.get<std::string> (I2P_CONTROL_PARAM_PASSWORD); auto password = params.get<std::string> ("Password");
LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password); LogPrint (eLogDebug, "I2PControl: Authenticate API=", api, " Password=", password);
if (password != m_Password) { if (password != m_Password) {
LogPrint (eLogError, "I2PControl: Authenticate - Invalid password: ", password); LogPrint (eLogError, "I2PControl: Authenticate - Invalid password: ", password);
return; return;
} }
InsertParam (results, I2P_CONTROL_PARAM_API, api); InsertParam (results, "API", api);
results << ","; results << ",";
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ()); std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
m_Tokens.insert (token); m_Tokens.insert (token);
InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token); InsertParam (results, "Token", token);
} }
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
auto echo = params.get<std::string> (I2P_CONTROL_PARAM_ECHO); auto echo = params.get<std::string> ("Echo");
LogPrint (eLogDebug, "I2PControl Echo Echo=", echo); LogPrint (eLogDebug, "I2PControl Echo Echo=", echo);
InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo); InsertParam (results, "Result", echo);
} }
@ -372,10 +324,9 @@ namespace client
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
LogPrint (eLogDebug, "I2PControl I2PControl");
for (auto& it: params) for (auto& it: params)
{ {
LogPrint (eLogDebug, it.first); LogPrint (eLogDebug, "I2PControl: I2PControl request: ", it.first);
auto it1 = m_I2PControlHandlers.find (it.first); auto it1 = m_I2PControlHandlers.find (it.first);
if (it1 != m_I2PControlHandlers.end ()) if (it1 != m_I2PControlHandlers.end ())
{ {
@ -383,26 +334,24 @@ namespace client
InsertParam (results, it.first, ""); InsertParam (results, it.first, "");
} }
else else
LogPrint (eLogError, "I2PControl I2PControl unknown request ", it.first); LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first);
} }
} }
void I2PControlService::PasswordHandler (const std::string& value) void I2PControlService::PasswordHandler (const std::string& value)
{ {
LogPrint (eLogDebug, "I2PControl new password=", value); LogPrint (eLogWarning, "I2PControl: new password=", value, ", to make it persistent you should update your config!");
m_Password = value; m_Password = value;
m_Tokens.clear (); m_Tokens.clear ();
SaveConfig ();
} }
// RouterInfo // RouterInfo
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
LogPrint (eLogDebug, "I2PControl RouterInfo");
for (auto it = params.begin (); it != params.end (); it++) for (auto it = params.begin (); it != params.end (); it++)
{ {
LogPrint (eLogDebug, it->first); LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
auto it1 = m_RouterInfoHandlers.find (it->first); auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ()) if (it1 != m_RouterInfoHandlers.end ())
{ {
@ -410,87 +359,89 @@ namespace client
(this->*(it1->second))(results); (this->*(it1->second))(results);
} }
else else
LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first); LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first);
} }
} }
void I2PControlService::UptimeHandler (std::ostringstream& results) void I2PControlService::UptimeHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000); InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000);
} }
void I2PControlService::VersionHandler (std::ostringstream& results) void I2PControlService::VersionHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION); InsertParam (results, "i2p.router.version", VERSION);
} }
void I2PControlService::StatusHandler (std::ostringstream& results) void I2PControlService::StatusHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO: InsertParam (results, "i2p.router.status", "???"); // TODO:
} }
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results) void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ()); InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
} }
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results) void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ()); InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
} }
void I2PControlService::NetStatusHandler (std::ostringstream& results) void I2PControlService::NetStatusHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ()); InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ());
} }
void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results) void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ()); int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size ();
InsertParam (results, "i2p.router.net.tunnels.participating", transit);
} }
void I2PControlService::InboundBandwidth1S (std::ostringstream& results) void I2PControlService::InboundBandwidth1S (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ()); double bw = i2p::transport::transports.GetInBandwidth ();
InsertParam (results, "i2p.router.net.bw.inbound.1s", bw);
} }
void I2PControlService::OutboundBandwidth1S (std::ostringstream& results) void I2PControlService::OutboundBandwidth1S (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ()); double bw = i2p::transport::transports.GetOutBandwidth ();
InsertParam (results, "i2p.router.net.bw.outbound.1s", bw);
} }
void I2PControlService::NetTotalReceivedBytes (std::ostringstream& results) void I2PControlService::NetTotalReceivedBytes (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_TOTAL_RB, (double)i2p::transport::transports.GetTotalReceivedBytes ()); InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ());
} }
void I2PControlService::NetTotalSentBytes (std::ostringstream& results) void I2PControlService::NetTotalSentBytes (std::ostringstream& results)
{ {
InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_TOTAL_SB, (double)i2p::transport::transports.GetTotalSentBytes ()); InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
} }
// RouterManager // RouterManager
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
LogPrint (eLogDebug, "I2PControl RouterManager");
for (auto it = params.begin (); it != params.end (); it++) for (auto it = params.begin (); it != params.end (); it++)
{ {
if (it != params.begin ()) results << ","; if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, it->first); LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
auto it1 = m_RouterManagerHandlers.find (it->first); auto it1 = m_RouterManagerHandlers.find (it->first);
if (it1 != m_RouterManagerHandlers.end ()) if (it1 != m_RouterManagerHandlers.end ()) {
(this->*(it1->second))(results); (this->*(it1->second))(results);
else } else
LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first); LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);
} }
} }
void I2PControlService::ShutdownHandler (std::ostringstream& results) void I2PControlService::ShutdownHandler (std::ostringstream& results)
{ {
LogPrint (eLogInfo, "Shutdown requested"); LogPrint (eLogInfo, "I2PControl: Shutdown requested");
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); InsertParam (results, "Shutdown", "");
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
m_ShutdownTimer.async_wait ( m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode) [](const boost::system::error_code& ecode)
@ -503,8 +454,8 @@ namespace client
{ {
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout (); int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout ();
LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); LogPrint (eLogInfo, "I2PControl: Graceful shutdown requested, ", timeout, " seconds remains");
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, ""); InsertParam (results, "ShutdownGraceful", "");
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
m_ShutdownTimer.async_wait ( m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode) [](const boost::system::error_code& ecode)
@ -515,30 +466,30 @@ namespace client
void I2PControlService::ReseedHandler (std::ostringstream& results) void I2PControlService::ReseedHandler (std::ostringstream& results)
{ {
LogPrint (eLogInfo, "Reseed requested"); LogPrint (eLogInfo, "I2PControl: Reseed requested");
InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); InsertParam (results, "Reseed", "");
i2p::data::netdb.Reseed (); i2p::data::netdb.Reseed ();
} }
// network setting // network setting
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
LogPrint (eLogDebug, "I2PControl NetworkSetting");
for (auto it = params.begin (); it != params.end (); it++) for (auto it = params.begin (); it != params.end (); it++)
{ {
if (it != params.begin ()) results << ","; if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, it->first); LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
auto it1 = m_NetworkSettingHandlers.find (it->first); auto it1 = m_NetworkSettingHandlers.find (it->first);
if (it1 != m_NetworkSettingHandlers.end ()) if (it1 != m_NetworkSettingHandlers.end ()) {
(this->*(it1->second))(it->second.data (), results); (this->*(it1->second))(it->second.data (), results);
else } else
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first); LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
} }
} }
// certificate // certificate
void I2PControlService::CreateCertificate () void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
{ {
FILE *f = NULL;
EVP_PKEY * pkey = EVP_PKEY_new (); EVP_PKEY * pkey = EVP_PKEY_new ();
RSA * rsa = RSA_new (); RSA * rsa = RSA_new ();
BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ()); BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ());
@ -558,34 +509,30 @@ namespace client
X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name
X509_set_issuer_name (x509, name); // set issuer to ourselves X509_set_issuer_name (x509, name); // set issuer to ourselves
X509_sign (x509, pkey, EVP_sha1 ()); // sign X509_sign (x509, pkey, EVP_sha1 ()); // sign
// save key and certificate
// keys // save cert
auto filename = GetPath () / I2P_CONTROL_KEY_FILE; if ((f = fopen (crt_path, "wb")) != NULL) {
FILE * f= fopen (filename.string ().c_str (), "wb"); LogPrint (eLogInfo, "I2PControl: saving new cert to ", crt_path);
if (f) PEM_write_X509 (f, x509);
{
PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
fclose (f); fclose (f);
} else {
LogPrint (eLogError, "I2PControl: can't write cert: ", strerror(errno));
} }
else
LogPrint (eLogError, "Can't open file ", filename); // save key
// certificate if ((f = fopen (key_path, "wb")) != NULL) {
filename = GetPath () / I2P_CONTROL_CERT_FILE; LogPrint (eLogInfo, "I2PControl: saving cert key to : ", key_path);
f= fopen (filename.string ().c_str (), "wb"); PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
if (f)
{
PEM_write_X509 (f, x509);
fclose (f); fclose (f);
} else {
LogPrint (eLogError, "I2PControl: can't write key: ", strerror(errno));
} }
else
LogPrint (eLogError, "Can't open file ", filename);
X509_free (x509); X509_free (x509);
} else {
LogPrint (eLogError, "I2PControl: can't create RSA key for certificate");
} }
else
LogPrint (eLogError, "Couldn't create RSA key for certificate");
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
} }
} }
} }

58
I2PControl.h

@ -22,56 +22,6 @@ namespace client
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024; const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer; typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
const char I2P_CONTROL_PATH[] = "ipcontrol";
const char I2P_CONTROL_KEY_FILE[] = "key.pem";
const char I2P_CONTROL_CERT_FILE[] = "cert.pem";
const char I2P_CONTROL_CONFIG_FILE[] = "i2pcontrol.conf";
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
const char I2P_CONTROL_PROPERTY_ID[] = "id";
const char I2P_CONTROL_PROPERTY_METHOD[] = "method";
const char I2P_CONTROL_PROPERTY_PARAMS[] = "params";
const char I2P_CONTROL_PROPERTY_RESULT[] = "result";
// methods
const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate";
const char I2P_CONTROL_METHOD_ECHO[] = "Echo";
const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl";
const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo";
const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager";
const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting";
// params
const char I2P_CONTROL_PARAM_API[] = "API";
const char I2P_CONTROL_PARAM_PASSWORD[] = "Password";
const char I2P_CONTROL_PARAM_TOKEN[] = "Token";
const char I2P_CONTROL_PARAM_ECHO[] = "Echo";
const char I2P_CONTROL_PARAM_RESULT[] = "Result";
// I2PControl
const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address";
const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password";
const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port";
// RouterInfo requests
const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime";
const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version";
const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status";
const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers";
const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers";
const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
const char I2P_CONTROL_ROUTER_INFO_NET_TOTAL_RB[] = "i2p.router.net.total.received.bytes";
const char I2P_CONTROL_ROUTER_INFO_NET_TOTAL_SB[] = "i2p.router.net.total.sent.bytes";
// RouterManager requests
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown";
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
// Certificate
const long I2P_CONTROL_CERTIFICATE_VALIDITY = 365*10; // 10 years const long I2P_CONTROL_CERTIFICATE_VALIDITY = 365*10; // 10 years
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol"; const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P"; const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
@ -89,9 +39,6 @@ namespace client
private: private:
void LoadConfig ();
void SaveConfig ();
void Run (); void Run ();
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
@ -105,9 +52,8 @@ namespace client
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf); std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / I2P_CONTROL_PATH; }; boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir(); };
void CreateCertificate (); void CreateCertificate (const char *crt_path, const char *key_path);
private: private:

8
RouterContext.cpp

@ -1,5 +1,6 @@
#include <fstream> #include <fstream>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "Config.h"
#include "Crypto.h" #include "Crypto.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@ -43,11 +44,12 @@ namespace i2p
{ {
i2p::data::RouterInfo routerInfo; i2p::data::RouterInfo routerInfo;
routerInfo.SetRouterIdentity (GetIdentity ()); routerInfo.SetRouterIdentity (GetIdentity ());
int port = i2p::util::config::GetArg("-port", 0); uint16_t port; i2p::config::GetOption("port", port);
if (!port) if (!port)
port = rand () % (30777 - 9111) + 9111; // I2P network ports range port = rand () % (30777 - 9111) + 9111; // I2P network ports range
routerInfo.AddSSUAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port, routerInfo.GetIdentHash ()); std::string host; i2p::config::GetOption("host", host);
routerInfo.AddNTCPAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port); routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
routerInfo.AddNTCPAddress (host.c_str(), port);
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID)); routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID));

5
api.cpp

@ -1,5 +1,6 @@
#include <string> #include <string>
#include <map> #include <map>
#include "Config.h"
#include "Log.h" #include "Log.h"
#include "NetDb.h" #include "NetDb.h"
#include "Transports.h" #include "Transports.h"
@ -18,7 +19,9 @@ namespace api
void InitI2P (int argc, char* argv[], const char * appName) void InitI2P (int argc, char* argv[], const char * appName)
{ {
i2p::util::filesystem::SetAppName (appName); i2p::util::filesystem::SetAppName (appName);
i2p::util::config::OptionParser(argc, argv); i2p::config::Init ();
i2p::config::ParseCmdline (argc, argv);
i2p::config::Finalize ();
i2p::crypto::InitCrypto (); i2p::crypto::InitCrypto ();
i2p::context.Init (); i2p::context.Init ();
} }

1
build/CMakeLists.txt

@ -17,6 +17,7 @@ set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
set ( CMAKE_SOURCE_DIR ".." ) set ( CMAKE_SOURCE_DIR ".." )
set (LIBI2PD_SRC set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/Config.cpp"
"${CMAKE_SOURCE_DIR}/Crypto.cpp" "${CMAKE_SOURCE_DIR}/Crypto.cpp"
"${CMAKE_SOURCE_DIR}/Garlic.cpp" "${CMAKE_SOURCE_DIR}/Garlic.cpp"
"${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp" "${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp"

23
debian/i2pd.conf vendored

@ -1,16 +1,19 @@
floodfill=0 ipv6
v6=0
httpproxyaddress=127.0.0.1 [httpproxy]
httpproxyport=4444 address = 127.0.0.1
port = 4444
# other services (disabled by default) # other services (disabled by default)
# #
# samaddress=127.0.0.1 #[sam]
# samport=7656 #address = 127.0.0.1
#port = 7656
# #
# bobaddress=127.0.0.1 #[bob]
# bobport=2827 #address = 127.0.0.1
#port = 2827
# #
# i2pcontroladdress=127.0.0.1 #[i2pcontrol]
# i2pcontrolport=7650 #address = 127.0.0.1
#port = 7650

2
debian/i2pd.init vendored

@ -46,7 +46,7 @@ do_start()
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" --test > /dev/null \ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" --test > /dev/null \
|| return 1 || return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \
--service=1 --daemon=1 --log=1 --conf=$I2PCONF --tunnelscfg=$TUNCONF \ --service --daemon --log --conf=$I2PCONF --tunconf=$TUNCONF \
--port=$I2PD_PORT $DAEMON_OPTS > /dev/null 2>&1 \ --port=$I2PD_PORT $DAEMON_OPTS > /dev/null 2>&1 \
|| return 2 || return 2
return $? return $?

6
debian/i2pd.upstart vendored

@ -4,7 +4,7 @@ start on runlevel [2345]
stop on runlevel [016] or unmounting-filesystem stop on runlevel [016] or unmounting-filesystem
# these can be overridden in /etc/init/i2pd.override # these can be overridden in /etc/init/i2pd.override
env I2P_HOST="1.2.3.4" env I2PD_HOST="1.2.3.4"
env I2P_PORT="4567" env I2PD_PORT="4567"
exec /usr/sbin/i2pd --daemon=0 --log=1 --host=$I2P_HOST --port=$I2P_PORT exec /usr/sbin/i2pd --daemon --log --host=$I2PD_HOST --port=$I2PD_PORT

6
debian/postinst vendored

@ -1,6 +1,7 @@
#!/bin/sh #!/bin/sh
set -e set -e
LOGFILE='/var/log/i2pd.log'
I2PDHOME='/var/lib/i2pd' I2PDHOME='/var/lib/i2pd'
I2PDUSER='i2pd' I2PDUSER='i2pd'
@ -16,8 +17,9 @@ case "$1" in
adduser --system --quiet --group --home $I2PDHOME $I2PDUSER adduser --system --quiet --group --home $I2PDHOME $I2PDUSER
fi fi
touch /var/log/i2pd.log touch $LOGFILE
chown -f ${I2PDUSER}:adm /var/log/i2pd.log chmod 640 $LOGFILE
chown -f ${I2PDUSER}:adm $LOGFILE
mkdir -p -m0750 $I2PDHOME mkdir -p -m0750 $I2PDHOME
chown -f -R -P ${I2PDUSER}:${I2PDUSER} ${I2PDHOME} chown -f -R -P ${I2PDUSER}:${I2PDUSER} ${I2PDHOME}
;; ;;

43
docs/config_opts_after_2.3.0.md

@ -0,0 +1,43 @@
Изменения обработки параметров в релизах > 2.3.0
------------------------------------------------
Система параметров отличается от того, что было ранее и достаточно сильно:
* изменения имён и стиля параметров
Все параметры теперь в виде --help (gnu-style), у некоторых есть шорткаты в виде -h (unix-style).
Это касается всех систем, в том числе винды.
--daemon=1 и подобное -> просто --daemon, без параметра. Нет опции - false, есть - true
--notransit=1 -> --notransit, то же что и выше: есть опция - false, нет - true
--v6 -> --ipv6 (первое было похоже на версию какого-то своего протокола, типа socksproxy --v5)
--tunnelscfg -> --tunconf (имя параметра было слишком длинным, cfg переделан на conf - единообразно с --conf)
--sockskeys -> разделён на два, для socks и httpproxy по-отдельности
* поддержка секций в основном конфиге
Выглядит это так:
# основные опции
pidfile = /var/run/i2pd.pid
#
# настройки конкретного модуля
[httproxy]
address = 1.2.3.4
port = 4446
keys = httproxy-keys.dat
# и так далее
[sam]
enabled = no
addresss = 127.0.0.2
# ^^ переопределяется только адрес, остальное берётся из дефолта
Точно так же сейчас работает конфиг туннелей: секция до точки - имя, после - параметр
* поддержка выключения отдельных сервисов "на корню" см sam.enabled и подобное
Это позволило задать дефолт для номера порта и не писать его руками для включения.
* добавлен --help (см #110)
* присутствует некая валидация параметров, --port=abcd - не прокатит, --port=100500 - тоже

78
docs/configuration.md

@ -4,46 +4,68 @@ i2pd configuration
Command line options Command line options
-------------------- --------------------
* --port= - The port to listen on
* --httpaddress= - The address to listen on (HTTP server)
* --httpport= - The port to listen on (HTTP server)
* --loglevel= - Log messages above this level (debug, *info, warn, error)
* --pidfile= - Where to write pidfile (dont write by default)
* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no. 0 by default
* --log= - Enable or disable logging to the file. 1 for daemon, 0 for non-daemon by default
* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove")
* --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd/i2pd.log, /var/lib/i2pd).
* --v6= - 1 if supports communication through ipv6, off by default
* --floodfill= - 1 if router is floodfill, off by default
* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited
* --notransit= - 1 if router doesn't accept transit tunnels at startup. 0 by default
* --httpproxyaddress= - The address to listen on (HTTP Proxy)
* --httpproxyport= - The port to listen on (HTTP Proxy) 4446 by default
* --socksproxyaddress= - The address to listen on (SOCKS Proxy)
* --socksproxyport= - The port to listen on (SOCKS Proxy). 4447 by default
* --proxykeys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --samaddress= - The address to listen on (SAM bridge)
* --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified
* --bobaddress= - The address to listen on (BOB command channel)
* --bobport= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --i2pcontroladdress= - The address to listen on (I2P control service)
* --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
* --tunnelscfg= - Tunnels Config file (default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)
* --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf) * --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)
This parameter will be silently ignored if the specified config file does not exist. This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file. Options specified on the command line take precedence over those in the config file.
* --tunconf= - Tunnels Config file (default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)
* --pidfile= - Where to write pidfile (dont write by default)
* --log - Enable or disable logging to file. 1 for yes, 0 for no.
* --logfile= - Path to logfile (stdout if not set, autodetect if daemon)
* --loglevel= - Log messages above this level (debug, *info, warn, error)
* --host= - The external IP (deprecated)
* --port= - The port to listen on
* --daemon - Enable or disable daemon mode. 1 for yes, 0 for no.
* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove")
* --service - Use system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd).
* --ipv6 - Enable communication through ipv6, off by default
* --notransit - Router will not accept transit tunnels at startup. 0 by default
* --floodfill - Router will be floodfill, off by default
* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited
This option will be ignored if --floodfill given
* --http.address= - The address to listen on (HTTP server)
* --http.port= - The port to listen on (HTTP server)
* --httpproxy.address= - The address to listen on (HTTP Proxy)
* --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default
* --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --socksproxy.address= - The address to listen on (SOCKS Proxy)
* --socksproxy.port= - The port to listen on (SOCKS Proxy). 4447 by default
* --socksproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there
* --socksproxy.outproxyport= - Outproxy remote port
* --sam.address= - The address to listen on (SAM bridge)
* --sam.port= - Port of SAM bridge. Usually 7656. SAM is off if not specified
* --bob.address= - The address to listen on (BOB command channel)
* --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --i2pcontrol.address= - The address to listen on (I2P control service)
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
Config files Config files
------------ ------------
INI-like, syntax is the following : <key> = <value>. INI-like, syntax is the following : <key> = <value>.
Comments are "#", not ";" as you may expect. See [boost ticket](https://svn.boost.org/trac/boost/ticket/808) Comments are "#", not ";" as you may expect. See [boost ticket](https://svn.boost.org/trac/boost/ticket/808)
All command-line parameters are allowed as keys, for example: All command-line parameters are allowed as keys, but note for those which contains dot (.).
For example:
i2p.conf: i2p.conf:
log = 1 # comment
v6 = 0 log = yes
ipv6 = yes
# settings for specific module
[httpproxy]
port = 4444
# ^^ this will be --httproxy.port= in cmdline
# another one
[sam]
enabled = yes
tunnels.cfg (filename of this config is subject of change): tunnels.cfg (filename of this config is subject of change):

4
filelist.mk

@ -8,9 +8,9 @@ LIB_SRC = \
LIB_CLIENT_SRC = \ LIB_CLIENT_SRC = \
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \
SAM.cpp SOCKS.cpp HTTPProxy.cpp SAM.cpp SOCKS.cpp HTTPProxy.cpp Config.cpp
# also: Daemon{Linux,Win32}.cpp will be added later # also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = \ DAEMON_SRC = \
HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp Config.cpp i2pd.cpp

121
util.cpp

@ -13,6 +13,7 @@
#include <boost/program_options/detail/config_file.hpp> #include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp> #include <boost/program_options/parsers.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "Config.h"
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
@ -66,86 +67,6 @@ namespace i2p
{ {
namespace util namespace util
{ {
namespace config
{
std::map<std::string, std::string> mapArgs;
void OptionParser(int argc, const char* const argv[])
{
mapArgs.clear();
for (int i = 1; i < argc; i++)
{
std::string strKey (argv[i]);
std::string strValue;
size_t has_data = strKey.find('=');
if (has_data != std::string::npos)
{
strValue = strKey.substr(has_data+1);
strKey = strKey.substr(0, has_data);
}
#ifdef WIN32
boost::to_lower(strKey);
if (boost::algorithm::starts_with(strKey, "/"))
strKey = "-" + strKey.substr(1);
#endif
if (strKey[0] != '-')
break;
mapArgs[strKey] = strValue;
}
BOOST_FOREACH(PAIRTYPE(const std::string,std::string)& entry, mapArgs)
{
std::string name = entry.first;
// interpret --foo as -foo (as long as both are not set)
if (name.find("--") == 0)
{
std::string singleDash(name.begin()+1, name.end());
if (mapArgs.count(singleDash) == 0)
mapArgs[singleDash] = entry.second;
name = singleDash;
}
}
}
std::string GetArg(const std::string& strArg, const std::string& strDefault)
{
if (mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
}
int GetArg(const std::string& strArg, int nDefault)
{
if (mapArgs.count(strArg))
return atoi(mapArgs[strArg].c_str());
return nDefault;
}
void ReadConfigFile(boost::filesystem::path path)
{
boost::filesystem::ifstream streamConfig(path);
if (!streamConfig.good())
return; // No i2pd.conf file is OK
std::set<std::string> setOptions;
setOptions.insert("*");
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
// Don't overwrite existing settings so command line settings override i2pd.conf
std::string strKey = std::string("-") + it->string_key;
if (mapArgs.count(strKey) == 0)
{
mapArgs[strKey] = it->value[0];
}
}
}
}
namespace filesystem namespace filesystem
{ {
std::string appName ("i2pd"); std::string appName ("i2pd");
@ -166,8 +87,10 @@ namespace filesystem
// TODO: datadir parameter is useless because GetDataDir is called before OptionParser // TODO: datadir parameter is useless because GetDataDir is called before OptionParser
// and mapArgs is not initialized yet // and mapArgs is not initialized yet
/*if (i2p::util::config::mapArgs.count("-datadir")) /*
path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); std::string datadir; i2p::config::GetOption("datadir", datadir);
if (datadir != "")
path = boost::filesystem::system_complete(datadir);
else */ else */
path = GetDefaultDataDir(); path = GetDefaultDataDir();
@ -200,17 +123,34 @@ namespace filesystem
boost::filesystem::path GetConfigFile() boost::filesystem::path GetConfigFile()
{ {
boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); std::string config; i2p::config::GetOption("conf", config);
if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; if (config != "") {
return pathConfigFile; /* config file set with cmdline */
boost::filesystem::path path(config);
return path;
}
/* else - try autodetect */
boost::filesystem::path path("i2p.conf");
path = GetDataDir() / path;
if (!boost::filesystem::exists(path))
path = ""; /* reset */
return path;
} }
boost::filesystem::path GetTunnelsConfigFile() boost::filesystem::path GetTunnelsConfigFile()
{ {
boost::filesystem::path pathTunnelsConfigFile(i2p::util::config::GetArg("-tunnelscfg", "tunnels.cfg")); std::string tunconf; i2p::config::GetOption("tunconf", tunconf);
if (!pathTunnelsConfigFile.is_complete()) if (tunconf != "") {
pathTunnelsConfigFile = GetDataDir() / pathTunnelsConfigFile; /* config file set with cmdline */
return pathTunnelsConfigFile; boost::filesystem::path path(tunconf);
return path;
}
/* else - try autodetect */
boost::filesystem::path path("tunnels.cfg");
path = GetDataDir() / path;
if (!boost::filesystem::exists(path))
path = ""; /* reset */
return path;
} }
boost::filesystem::path GetDefaultDataDir() boost::filesystem::path GetDefaultDataDir()
@ -225,7 +165,8 @@ namespace filesystem
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData); SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
return boost::filesystem::path(std::string(localAppData) + "\\" + appName); return boost::filesystem::path(std::string(localAppData) + "\\" + appName);
#else /* UNIX */ #else /* UNIX */
if (i2p::util::config::GetArg("-service", 0)) // use system folder bool service; i2p::config::GetOption("service", service);
if (service) // use system folder
return boost::filesystem::path(std::string ("/var/lib/") + appName); return boost::filesystem::path(std::string ("/var/lib/") + appName);
boost::filesystem::path pathRet; boost::filesystem::path pathRet;
char* pszHome = getenv("HOME"); char* pszHome = getenv("HOME");

8
util.h

@ -14,14 +14,6 @@ namespace i2p
{ {
namespace util namespace util
{ {
namespace config
{
void OptionParser(int argc, const char* const argv[]);
int GetArg(const std::string& strArg, int nDefault);
std::string GetArg(const std::string& strArg, const std::string& strDefault);
void ReadConfigFile(boost::filesystem::path path);
}
namespace filesystem namespace filesystem
{ {
void SetAppName (const std::string& name); void SetAppName (const std::string& name);

Loading…
Cancel
Save