Merge pull request #700 from PurpleI2P/openssl

recent changes
pull/63/merge
orignal 8 years ago committed by GitHub
commit 4a4292a0dc

@ -1,7 +1,7 @@
#include <string.h>
#include <boost/lexical_cast.hpp>
#include "Log.h"
#include "ClientContext.h"
#include "util.h"
#include "BOB.h"
namespace i2p
@ -459,7 +459,7 @@ namespace client
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outport ", operand);
m_OutPort = boost::lexical_cast<int>(operand);
m_OutPort = std::stoi(operand);
if (m_OutPort >= 0)
SendReplyOK ("outbound port set");
else
@ -476,7 +476,7 @@ namespace client
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inport ", operand);
m_InPort = boost::lexical_cast<int>(operand);
m_InPort = std::stoi(operand);
if (m_InPort >= 0)
SendReplyOK ("inbound port set");
else

@ -1,6 +1,21 @@
# for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog
## [2.10.0] - 2016-10-17
### Added
- Datagram i2p tunnels
- Unique local addresses for server tunnels
- Configurable list of reseed servers and initial addressbook
- Configurable netid
- Initial iOS support
### Changed
- Reduced file descriptiors usage
- Strict reseed checks enabled by default
## Fixed
- Multiple fixes in I2CP and BOB implementations
## [2.9.0] - 2016-08-12
### Changed
- Proxy refactoring & speedup

@ -53,7 +53,11 @@ namespace client
{
i2p::data::PrivateKeys keys;
if(LoadPrivateKeys (keys, httpProxyKeys))
localDestination = CreateNewLocalDestination (keys, false);
{
std::map<std::string, std::string> params;
ReadI2CPOptionsFromConfig ("httpproxy.", params);
localDestination = CreateNewLocalDestination (keys, false, &params);
}
else
LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
}
@ -65,8 +69,10 @@ namespace client
}
}
localDestination = nullptr;
bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy);
if (socksproxy) {
if (socksproxy)
{
std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys);
std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr);
uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort);
@ -76,8 +82,14 @@ namespace client
if (socksProxyKeys.length () > 0)
{
i2p::data::PrivateKeys keys;
LoadPrivateKeys (keys, socksProxyKeys);
localDestination = CreateNewLocalDestination (keys, false);
if (LoadPrivateKeys (keys, socksProxyKeys))
{
std::map<std::string, std::string> params;
ReadI2CPOptionsFromConfig ("socksproxy.", params);
localDestination = CreateNewLocalDestination (keys, false, &params);
}
else
LogPrint(eLogError, "Clients: failed to load SOCKS Proxy key");
}
try {
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination);
@ -290,7 +302,7 @@ namespace client
}
return infos;
}
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
const std::map<std::string, std::string> * params)
{
@ -362,6 +374,19 @@ namespace client
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
}
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
{
std::string value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value))
options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value))
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value))
options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value))
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value;
}
void ClientContext::ReadTunnels ()
{
boost::property_tree::ptree pt;

@ -68,14 +68,15 @@ namespace client
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
std::vector<std::shared_ptr<DatagramSessionInfo> > GetForwardInfosFor(const i2p::data::IdentHash & destination);
private:
void ReadTunnels ();
template<typename Section, typename Type>
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const;
template<typename Section>
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const;
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const;
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const;
void CleanupUDP(const boost::system::error_code & ecode);
void ScheduleCleanupUDP();
@ -110,6 +111,7 @@ namespace client
const decltype(m_ServerTunnels)& GetServerTunnels () const { return m_ServerTunnels; };
const decltype(m_ClientForwards)& GetClientForwards () const { return m_ClientForwards; }
const decltype(m_ServerForwards)& GetServerForwards () const { return m_ServerForwards; }
const i2p::proxy::HTTPProxy * GetHttpProxy () const { return m_HttpProxy; }
};
extern ClientContext context;

@ -27,10 +27,6 @@ namespace config {
variables_map m_Options;
void Init() {
bool nat = true;
#ifdef MESHNET
nat = false;
#endif
options_description general("General options");
general.add_options()
@ -44,8 +40,8 @@ namespace config {
("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")
("nat", value<bool>()->zero_tokens()->default_value(nat), "should we assume we are behind NAT?")
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
("nat", value<bool>()->zero_tokens()->default_value(true), "Should we assume we are behind NAT?")
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
("ipv4", value<bool>()->zero_tokens()->default_value(true), "Enable communication through ipv4")
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
@ -55,8 +51,8 @@ namespace config {
("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup")
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill")
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in kbps or letters: L (32), O (256), P (2048), X (>9000)")
("ntcp", value<bool>()->zero_tokens()->default_value(true), "enable ntcp transport")
("ssu", value<bool>()->zero_tokens()->default_value(true), "enable ssu transport")
("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport")
("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport")
#ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping")
@ -66,6 +62,8 @@ namespace config {
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)")
;
@ -85,6 +83,10 @@ namespace config {
("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(""), "File to persist HTTP Proxy keys")
("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")
;
options_description socksproxy("SOCKS Proxy options");
@ -93,7 +95,11 @@ namespace config {
("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(""), "File to persist SOCKS Proxy keys")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
("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.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")
;
@ -153,9 +159,6 @@ namespace config {
reseed.add_options()
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
("reseed.file", value<std::string>()->default_value(""), "Path to .su3 file")
#ifdef MESHNET
("reseed.urls", value<std::string>()->default_value("https://reseed.i2p.rocks:8443/"), "Reseed URLs, separated by comma")
#else
("reseed.urls", value<std::string>()->default_value(
"https://reseed.i2p-projekt.de/,"
"https://i2p.mooo.com/netDb/,"
@ -169,7 +172,6 @@ namespace config {
"https://reseed-ru.lngserv.ru/,"
"https://reseed.atomike.ninja/"
), "Reseed URLs, separated by comma")
#endif
;
options_description addressbook("AddressBook options");
@ -182,10 +184,17 @@ namespace config {
options_description trust("Trust options");
trust.add_options()
("trust.enabled", value<bool>()->default_value(false), "enable explicit trust options")
("trust.enabled", value<bool>()->default_value(false), "Enable explicit trust options")
("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops")
("trust.hidden", value<bool>()->default_value(false), "should we hide our router from other routers?");
("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?");
options_description websocket("Websocket Options");
websocket.add_options()
("websockets.enabled", value<bool>()->default_value(false), "enable websocket server")
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "address to bind websocket server on")
("websockets.port", value<uint16_t>()->default_value(7666), "port to bind websocket server on");
m_OptionsDesc
.add(general)
.add(limits)
@ -200,7 +209,8 @@ namespace config {
.add(precomputation)
.add(reseed)
.add(addressbook)
.add(trust)
.add(trust)
.add(websocket)
;
}

@ -78,6 +78,12 @@ namespace config {
return true;
}
template<typename T>
bool GetOption(const std::string& name, T& value)
{
return GetOption (name.c_str (), value);
}
/**
* @brief Set value of given parameter
* @param name Name of settable parameter
@ -93,7 +99,7 @@ namespace config {
m_Options.at(name).value() = value;
notify(m_Options);
return true;
}
}
/**
* @brief Check is value explicitly given or default

@ -7,6 +7,7 @@
#include <openssl/dh.h>
#include <openssl/aes.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
@ -284,8 +285,21 @@ namespace crypto
#include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL
// define getters and setters introduced in 1.1.0
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { d->p = p; d->q = q; d->g = g; return 1; }
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { d->pub_key = pub_key; d->priv_key = priv_key; return 1; }
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ d->p = p; d->q = q; d->g = g; return 1; }
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{ d->pub_key = pub_key; d->priv_key = priv_key; return 1; }
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = d->pub_key; *priv_key = d->priv_key; }
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{ sig->r = r; sig->s = s; return 1; }
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; }
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{ r->n = n; r->e = e; r->d = d; return 1; }
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{ *n = r->n; *e = r->e; *d = r->d; }
#endif

@ -25,6 +25,9 @@
#include "UPnP.h"
#include "util.h"
#include "Event.h"
#include "Websocket.h"
namespace i2p
{
namespace util
@ -38,6 +41,9 @@ namespace i2p
std::unique_ptr<i2p::http::HTTPServer> httpServer;
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
std::unique_ptr<i2p::transport::UPnP> UPnP;
#ifdef WITH_EVENTS
std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer;
#endif
};
Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), d(*new Daemon_Singleton_Private()) {}
@ -115,6 +121,9 @@ namespace i2p
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
i2p::crypto::InitCrypto (precomputation);
int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID);
i2p::context.Init ();
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
@ -191,12 +200,40 @@ namespace i2p
{
LogPrint(eLogInfo, "Daemon: explicit trust enabled");
std::string fam; i2p::config::GetOption("trust.family", fam);
std::string routers; i2p::config::GetOption("trust.routers", routers);
bool restricted = false;
if (fam.length() > 0)
{
LogPrint(eLogInfo, "Daemon: setting restricted routes to use family ", fam);
i2p::transport::transports.RestrictRoutes({fam});
} else
LogPrint(eLogError, "Daemon: no family specified for restricted routes");
std::set<std::string> fams;
size_t pos = 0, comma;
do
{
comma = fam.find (',', pos);
fams.insert (fam.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
pos = comma + 1;
}
while (comma != std::string::npos);
i2p::transport::transports.RestrictRoutesToFamilies(fams);
restricted = fams.size() > 0;
}
if (routers.length() > 0) {
std::set<i2p::data::IdentHash> idents;
size_t pos = 0, comma;
do
{
comma = routers.find (',', pos);
i2p::data::IdentHash ident;
ident.FromBase64 (routers.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
idents.insert (ident);
pos = comma + 1;
}
while (comma != std::string::npos);
LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routesrs");
i2p::transport::transports.RestrictRoutesToRouters(idents);
restricted = idents.size() > 0;
}
if(!restricted)
LogPrint(eLogError, "Daemon: no trusted routers of families specififed");
}
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
if (hidden)
@ -259,12 +296,27 @@ namespace i2p
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
d.m_I2PControlService->Start ();
}
#ifdef WITH_EVENTS
bool websocket; i2p::config::GetOption("websockets.enabled", websocket);
if(websocket) {
std::string websocketAddr; i2p::config::GetOption("websockets.address", websocketAddr);
uint16_t websocketPort; i2p::config::GetOption("websockets.port", websocketPort);
LogPrint(eLogInfo, "Daemon: starting Websocket server at ", websocketAddr, ":", websocketPort);
d.m_WebsocketServer = std::unique_ptr<i2p::event::WebsocketServer>(new i2p::event::WebsocketServer (websocketAddr, websocketPort));
d.m_WebsocketServer->Start();
i2p::event::core.SetListener(d.m_WebsocketServer->ToListener());
}
#endif
return true;
}
bool Daemon_Singleton::stop()
{
#ifdef WITH_EVENTS
i2p::event::core.SetListener(nullptr);
#endif
LogPrint(eLogInfo, "Daemon: shutting down");
LogPrint(eLogInfo, "Daemon: stopping Client");
i2p::client::context.Stop();
@ -290,10 +342,17 @@ namespace i2p
LogPrint(eLogInfo, "Daemon: stopping I2PControl");
d.m_I2PControlService->Stop ();
d.m_I2PControlService = nullptr;
}
}
#ifdef WITH_EVENTS
if (d.m_WebsocketServer) {
LogPrint(eLogInfo, "Daemon: stopping Websocket server");
d.m_WebsocketServer->Stop();
d.m_WebsocketServer = nullptr;
}
#endif
i2p::crypto::TerminateCrypto ();
return true;
}
}
}
}

@ -97,7 +97,7 @@ namespace i2p
public:
int gracefullShutdownInterval; // in seconds
int gracefulShutdownInterval; // in seconds
};
#endif

@ -8,6 +8,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include "Config.h"
#include "FS.h"
@ -25,11 +26,11 @@ void handle_signal(int sig)
i2p::client::context.ReloadConfig();
break;
case SIGINT:
if (i2p::context.AcceptsTunnels () && !Daemon.gracefullShutdownInterval)
if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval)
{
i2p::context.SetAcceptsTunnels (false);
Daemon.gracefullShutdownInterval = 10*60; // 10 minutes
LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefullShutdownInterval, " seconds");
Daemon.gracefulShutdownInterval = 10*60; // 10 minutes
LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds");
}
else
Daemon.running = 0;
@ -83,6 +84,42 @@ namespace i2p
#endif
}
// set proc limits
struct rlimit limit;
uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles);
getrlimit(RLIMIT_NOFILE, &limit);
if (nfiles == 0) {
LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files");
} else if (nfiles <= limit.rlim_max) {
limit.rlim_cur = nfiles;
if (setrlimit(RLIMIT_NOFILE, &limit) == 0) {
LogPrint(eLogInfo, "Daemon: set max number of open files to ",
nfiles, " (system limit is ", limit.rlim_max, ")");
} else {
LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno));
}
} else {
LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max);
}
uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize);
if (cfsize) // core file size set
{
cfsize *= 1024;
getrlimit(RLIMIT_CORE, &limit);
if (cfsize <= limit.rlim_max) {
limit.rlim_cur = cfsize;
if (setrlimit(RLIMIT_CORE, &limit) != 0) {
LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno));
} else if (cfsize == 0) {
LogPrint(eLogInfo, "Daemon: coredumps disabled");
} else {
LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb");
}
} else {
LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max);
}
}
// Pidfile
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
@ -110,7 +147,7 @@ namespace i2p
return false;
}
}
gracefullShutdownInterval = 0; // not specified
gracefulShutdownInterval = 0; // not specified
// Signal handler
struct sigaction sa;
@ -137,10 +174,10 @@ namespace i2p
while (running)
{
std::this_thread::sleep_for (std::chrono::seconds(1));
if (gracefullShutdownInterval)
if (gracefulShutdownInterval)
{
gracefullShutdownInterval--; // - 1 second
if (gracefullShutdownInterval <= 0)
gracefulShutdownInterval--; // - 1 second
if (gracefulShutdownInterval <= 0)
{
LogPrint(eLogInfo, "Graceful shutdown");
return;

@ -1,6 +1,5 @@
#include <algorithm>
#include <cassert>
#include <boost/lexical_cast.hpp>
#include "Crypto.h"
#include "Log.h"
#include "FS.h"
@ -18,83 +17,50 @@ namespace client
m_PublishReplyToken (0), m_PublishConfirmationTimer (m_Service),
m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service)
{
int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY;
int outboundTunnelsQuantity = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY;
int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
int numTags = DEFAULT_TAGS_TO_SEND;
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
if (params)
{
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
if (it != params->end ())
{
int len = i2p::util::lexical_cast<int>(it->second, inboundTunnelLen);
if (len >= 0)
{
inboundTunnelLen = len;
}
LogPrint (eLogInfo, "Destination: Inbound tunnel length set to ", inboundTunnelLen);
}
it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH);
if (it != params->end ())
{
int len = i2p::util::lexical_cast<int>(it->second, outboundTunnelLen);
if (len >= 0)
{
outboundTunnelLen = len;
}
LogPrint (eLogInfo, "Destination: Outbound tunnel length set to ", outboundTunnelLen);
}
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
{
int quantity = i2p::util::lexical_cast<int>(it->second, inboundTunnelsQuantity);
if (quantity > 0)
{
inboundTunnelsQuantity = quantity;
LogPrint (eLogInfo, "Destination: Inbound tunnels quantity set to ", quantity);
}
}
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
{
int quantity = i2p::util::lexical_cast<int>(it->second, outboundTunnelsQuantity);
if (quantity > 0)
{
outboundTunnelsQuantity = quantity;
LogPrint (eLogInfo, "Destination: Outbound tunnels quantity set to ", quantity);
}
}
it = params->find (I2CP_PARAM_TAGS_TO_SEND);
if (it != params->end ())
{
int tagsToSend = i2p::util::lexical_cast<int>(it->second, numTags);
if (tagsToSend > 0)
{
numTags = tagsToSend;
LogPrint (eLogInfo, "Destination: Tags to send set to ", tagsToSend);
}
}
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
if (it != params->end ())
{
explicitPeers = std::make_shared<std::vector<i2p::data::IdentHash> >();
std::stringstream ss(it->second);
std::string b64;
while (std::getline (ss, b64, ','))
try {
if (params) {
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
if (it != params->end ())
inLen = std::stoi(it->second);
it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH);
if (it != params->end ())
outLen = std::stoi(it->second);
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
inQty = std::stoi(it->second);
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
outQty = std::stoi(it->second);
it = params->find (I2CP_PARAM_TAGS_TO_SEND);
if (it != params->end ())
numTags = std::stoi(it->second);
LogPrint (eLogInfo, "Destination: parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags");
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
if (it != params->end ())
{
i2p::data::IdentHash ident;
ident.FromBase64 (b64);
explicitPeers->push_back (ident);
explicitPeers = std::make_shared<std::vector<i2p::data::IdentHash> >();
std::stringstream ss(it->second);
std::string b64;
while (std::getline (ss, b64, ','))
{
i2p::data::IdentHash ident;
ident.FromBase64 (b64);
explicitPeers->push_back (ident);
LogPrint (eLogInfo, "Destination: Added to explicit peers list: ", b64);
}
}
LogPrint (eLogInfo, "Destination: Explicit peers set to ", it->second);
}
}
} catch (std::exception & ex) {
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
}
SetNumTags (numTags);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty);
if (explicitPeers)
m_Pool->SetExplicitPeers (explicitPeers);
}
@ -202,7 +168,12 @@ namespace client
return remoteLS;
}
else
{
LogPrint (eLogWarning, "Destination: remote LeaseSet expired");
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets.erase (ident);
return nullptr;
}
}
else
{
@ -223,12 +194,16 @@ namespace client
if (!m_Pool) return nullptr;
if (!m_LeaseSet)
UpdateLeaseSet ();
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
return m_LeaseSet;
}
void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet)
{
m_LeaseSet.reset (newLeaseSet);
{
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
m_LeaseSet.reset (newLeaseSet);
}
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
if (m_IsPublic)
{
@ -305,7 +280,7 @@ namespace client
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet
{
LogPrint (eLogDebug, "Remote LeaseSet");
LogPrint (eLogDebug, "Destination: Remote LeaseSet");
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET);
if (it != m_RemoteLeaseSets.end ())
@ -315,16 +290,16 @@ namespace client
{
leaseSet->Update (buf + offset, len - offset);
if (leaseSet->IsValid ())
LogPrint (eLogDebug, "Remote LeaseSet updated");
LogPrint (eLogDebug, "Destination: Remote LeaseSet updated");
else
{
LogPrint (eLogDebug, "Remote LeaseSet update failed");
LogPrint (eLogDebug, "Destination: Remote LeaseSet update failed");
m_RemoteLeaseSets.erase (it);
leaseSet = nullptr;
}
}
else
LogPrint (eLogDebug, "Remote LeaseSet is older. Not updated");
LogPrint (eLogDebug, "Destination: Remote LeaseSet is older. Not updated");
}
else
{
@ -333,15 +308,15 @@ namespace client
{
if (leaseSet->GetIdentHash () != GetIdentHash ())
{
LogPrint (eLogDebug, "New remote LeaseSet added");
LogPrint (eLogDebug, "Destination: New remote LeaseSet added");
m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet;
}
else
LogPrint (eLogDebug, "Own remote LeaseSet dropped");
LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped");
}
else
{
LogPrint (eLogError, "New remote LeaseSet failed");
LogPrint (eLogError, "Destination: New remote LeaseSet failed");
leaseSet = nullptr;
}
}
@ -371,14 +346,14 @@ namespace client
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
{
for (int i = 0; i < num; i++)
{
i2p::data::IdentHash peerHash (buf + 33 + i*32);
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
{
i2p::data::IdentHash peerHash (buf + 33 + i*32);
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
{
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message
i2p::data::netdb.RequestDestination (peerHash);
}
}
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message
i2p::data::netdb.RequestDestination (peerHash);
}
}
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
if (floodfill)

@ -131,6 +131,7 @@ namespace client
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
std::mutex m_LeaseSetMutex;
std::shared_ptr<i2p::data::LocalLeaseSet> m_LeaseSet;
bool m_IsPublic;
uint32_t m_PublishReplyToken;

@ -0,0 +1,32 @@
#include "Event.h"
#include "Log.h"
namespace i2p
{
namespace event
{
#ifdef WITH_EVENTS
EventCore core;
#endif
void EventCore::SetListener(EventListener * l)
{
m_listener = l;
LogPrint(eLogInfo, "Event: listener set");
}
void EventCore::QueueEvent(const EventType & ev)
{
if(m_listener)
m_listener->HandleEvent(ev);
}
}
}
void EmitEvent(const EventType & e)
{
#ifdef WITH_EVENTS
i2p::event::core.QueueEvent(e);
#endif
}

@ -0,0 +1,37 @@
#ifndef EVENT_H__
#define EVENT_H__
#include <map>
#include <string>
#include <memory>
#include <boost/asio.hpp>
typedef std::map<std::string, std::string> EventType;
namespace i2p
{
namespace event
{
class EventListener {
public:
virtual ~EventListener() {};
virtual void HandleEvent(const EventType & ev) = 0;
};
class EventCore
{
public:
void QueueEvent(const EventType & ev);
void SetListener(EventListener * l);
private:
EventListener * m_listener = nullptr;
};
#ifdef WITH_EVENTS
extern EventCore core;
#endif
}
}
void EmitEvent(const EventType & ev);
#endif

@ -45,18 +45,18 @@ namespace fs {
return;
}
#if defined(WIN32) || defined(_WIN32)
char localAppData[MAX_PATH];
// check executable directory first
GetModuleFileName (NULL, localAppData, MAX_PATH);
auto execPath = boost::filesystem::path(localAppData).parent_path();
// if config file exists in .exe's folder use it
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
dataDir = execPath.string ();
else
{
// otherwise %appdata%
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
dataDir = std::string(localAppData) + "\\" + appName;
char localAppData[MAX_PATH];
// check executable directory first
GetModuleFileName (NULL, localAppData, MAX_PATH);
auto execPath = boost::filesystem::path(localAppData).parent_path();
// if config file exists in .exe's folder use it
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
dataDir = execPath.string ();
else
{
// otherwise %appdata%
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
dataDir = std::string(localAppData) + "\\" + appName;
}
return;
#elif defined(MAC_OSX)
@ -66,9 +66,11 @@ namespace fs {
return;
#else /* other unix */
#if defined(ANDROID)
if (boost::filesystem::exists("/sdcard"))
const char * ext = getenv("EXTERNAL_STORAGE");
if (!ext) ext = "/sdcard";
if (boost::filesystem::exists(ext))
{
dataDir = "/sdcard/" + appName;
dataDir = std::string (ext) + "/" + appName;
return;
}
// otherwise use /data/files

@ -105,7 +105,9 @@ namespace garlic
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
};
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);

@ -196,7 +196,7 @@ namespace http {
}
s << "<br>\r\n";
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
if (auto remains = Daemon.gracefullShutdownInterval) {
if (auto remains = Daemon.gracefulShutdownInterval) {
s << "<b>Stopping in:</b> ";
s << remains << " seconds";
s << "<br>\r\n";
@ -416,13 +416,13 @@ namespace http {
else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "\">Accept transit tunnels</a><br>\r\n";
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
if (Daemon.gracefullShutdownInterval)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "\">Cancel gracefull shutdown</a><br>";
if (Daemon.gracefulShutdownInterval)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "\">Cancel graceful shutdown</a><br>";
else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Start gracefull shutdown</a><br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Start graceful shutdown</a><br>\r\n";
#endif
#ifdef WIN32_APP
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Gracefull shutdown</a><br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Graceful shutdown</a><br>\r\n";
#endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "\">Force shutdown</a><br>\r\n";
}
@ -549,6 +549,15 @@ namespace http {
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl;
}
auto httpProxy = i2p::client::context.GetHttpProxy ();
if (httpProxy)
{
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "HTTP Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl;
}
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetServerTunnels ())
{
@ -755,7 +764,7 @@ namespace http {
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
i2p::context.SetAcceptsTunnels (false);
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefullShutdownInterval = 10*60;
Daemon.gracefulShutdownInterval = 10*60;
#endif
#ifdef WIN32_APP
i2p::win32::GracefulShutdown ();
@ -763,7 +772,7 @@ namespace http {
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
i2p::context.SetAcceptsTunnels (true);
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefullShutdownInterval = 0;
Daemon.gracefulShutdownInterval = 0;
#endif
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
Daemon.running = false;

@ -547,7 +547,6 @@ namespace i2p
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
uint8_t * buf = msg + I2NP_HEADER_SIZE;
int size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
switch (typeID)

@ -38,6 +38,7 @@ namespace client
}
inline std::shared_ptr<ClientDestination> GetLocalDestination () { return m_LocalDestination; }
inline std::shared_ptr<const ClientDestination> GetLocalDestination () const { return m_LocalDestination; }
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest) { m_LocalDestination = dest; }
void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);

@ -238,8 +238,8 @@ namespace client
if (line == "\r") endOfHeader = true;
else
{
if (line.find ("Host:") != std::string::npos)
m_OutHeader << "Host: " << m_Host << "\r\n";
if (m_Host.length () > 0 && line.find ("Host:") != std::string::npos)
m_OutHeader << "Host: " << m_Host << "\r\n"; // override host
else
m_OutHeader << line << "\n";
}
@ -275,26 +275,24 @@ namespace client
void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len)
{
if (m_NeedsWebIrc) {
m_OutPacket.str ("");
if (m_NeedsWebIrc)
{
m_NeedsWebIrc = false;
m_OutPacket.str ("");
m_OutPacket << "WEBIRC " << this->m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n";
I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n";
}
std::string line;
m_OutPacket.str ("");
m_InPacket.clear ();
m_InPacket.write ((const char *)buf, len);
while (!m_InPacket.eof () && !m_InPacket.fail ())
{
std::string line;
std::getline (m_InPacket, line);
if (line.length () == 0 && m_InPacket.eof ()) {
if (line.length () == 0 && m_InPacket.eof ())
m_InPacket.str ("");
}
auto pos = line.find ("USER");
if (pos != std::string::npos && pos == 0)
if (!pos) // start of line
{
pos = line.find (" ");
pos++;
@ -304,9 +302,9 @@ namespace client
m_OutPacket << line.substr (0, pos);
m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
m_OutPacket << line.substr (nextpos) << '\n';
} else {
}
else
m_OutPacket << line << '\n';
}
}
I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
}
@ -503,7 +501,7 @@ namespace client
int port, std::shared_ptr<ClientDestination> localDestination,
const std::string& host, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_Host (host.length () > 0 ? host : address)
m_Host (host)
{
}

@ -385,7 +385,14 @@ namespace data
else
{
delete verifier;
while (!m_Verifier) ; // spin lock
int count = 0;
while (!m_Verifier && count < 500) // 5 seconds
{
std::this_thread::sleep_for (std::chrono::milliseconds(10));
count++;
}
if (!m_Verifier)
LogPrint (eLogError, "Identity: couldn't get verifier in 5 seconds");
}
}
else

@ -22,6 +22,22 @@ namespace log {
"debug" // eLogDebug
};
/**
* @brief Colorize log output -- array of terminal control sequences
* @note Using ISO 6429 (ANSI) color sequences
*/
#ifdef _WIN32
static const char *LogMsgColors[] = { "", "", "", "", "" };
#else /* UNIX */
static const char *LogMsgColors[] = {
[eLogError] = "\033[1;31m", /* red */
[eLogWarning] = "\033[1;33m", /* yellow */
[eLogInfo] = "\033[1;36m", /* cyan */
[eLogDebug] = "\033[1;34m", /* blue */
[eNumLogLevels] = "\033[0m", /* reset */
};
#endif
#ifndef _WIN32
/**
* @brief Maps our log levels to syslog one
@ -42,7 +58,7 @@ namespace log {
Log::Log():
m_Destination(eLogStdout), m_MinLevel(eLogInfo),
m_LogStream (nullptr), m_Logfile(""), m_IsReady(false)
m_LogStream (nullptr), m_Logfile(""), m_IsReady(false), m_HasColors(true)
{
}
@ -117,7 +133,7 @@ namespace log {
default:
std::cout << TimeAsString(msg->timestamp)
<< "@" << short_tid
<< "/" << g_LogLevelStr[msg->level]
<< "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels]
<< " - " << msg->text << std::endl;
break;
} // switch
@ -138,6 +154,7 @@ namespace log {
auto os = std::make_shared<std::ofstream> (path, flags);
if (os->is_open ())
{
m_HasColors = false;
m_Logfile = path;
m_Destination = eLogFile;
m_LogStream = os;
@ -147,12 +164,14 @@ namespace log {
}
void Log::SendTo (std::shared_ptr<std::ostream> os) {
m_HasColors = false;
m_Destination = eLogStream;
m_LogStream = os;
}
#ifndef _WIN32
void Log::SendTo(const char *name, int facility) {
m_HasColors = false;
m_Destination = eLogSyslog;
m_LogStream = nullptr;
openlog(name, LOG_CONS | LOG_PID, facility);

23
Log.h

@ -40,17 +40,6 @@ enum LogType {
#endif
};
#ifdef _WIN32
const char LOG_COLOR_ERROR[] = "";
const char LOG_COLOR_WARNING[] = "";
const char LOG_COLOR_RESET[] = "";
#else
const char LOG_COLOR_ERROR[] = "\033[1;31m";
const char LOG_COLOR_WARNING[] = "\033[1;33m";
const char LOG_COLOR_RESET[] = "\033[0m";
#endif
namespace i2p {
namespace log {
@ -68,6 +57,7 @@ namespace log {
char m_LastDateTime[64];
i2p::util::Queue<std::shared_ptr<LogMsg> > m_Queue;
volatile bool m_IsReady;
bool m_HasColors;
mutable std::mutex m_OutputLock;
private:
@ -152,13 +142,13 @@ namespace log {
std::string text; /**< message text as single string */
LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {};
};
Log & Logger();
} // log
} // i2p
}
/** internal usage only -- folding args array to single string */
template<typename TValue>
@ -190,15 +180,8 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
// fold message to single string
std::stringstream ss("");
if(level == eLogError) // if log level is ERROR color log message red
ss << LOG_COLOR_ERROR;
else if (level == eLogWarning) // if log level is WARN color log message yellow
ss << LOG_COLOR_WARNING;
LogPrint (ss, std::forward<TArgs>(args)...);
// reset color
ss << LOG_COLOR_RESET;
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
msg->tid = std::this_thread::get_id();
log.Append(msg);

@ -4,7 +4,7 @@ ARLIB := libi2pd.a
SHLIB_CLIENT := libi2pdclient.so
ARLIB_CLIENT := libi2pdclient.a
I2PD := i2pd
GREP := fgrep
GREP := grep
DEPS := obj/make.dep
include filelist.mk
@ -14,6 +14,11 @@ USE_STATIC := no
USE_MESHNET := no
USE_UPNP := no
ifeq ($(WEBSOCKETS),1)
NEEDED_CXXFLAGS += -DWITH_EVENTS
DAEMON_SRC += Websocket.cpp
endif
ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp
ifeq ($(HOMEBREW),1)
@ -89,10 +94,15 @@ strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
strip $^
LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl)
BRANCH=$(shell git branch --no-color | cut -c 3-)
dist:
git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
last-dist:
git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(BRANCH) -o ../i2pd_$(LATEST_TAG).orig.tar.gz
doxygen:
doxygen -s docs/Doxyfile

@ -39,7 +39,7 @@ ifeq ($(USE_STATIC),yes)
LDLIBS += $(LIBDIR)/libssl.a
LDLIBS += $(LIBDIR)/libcrypto.a
LDLIBS += $(LIBDIR)/libz.a
LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt
LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt -ldl
USE_AESNI := no
else
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
@ -55,7 +55,7 @@ IS_64 := $(shell $(CXX) -dumpmachine 2>&1 | $(GREP) -c "64")
ifeq ($(USE_AESNI),yes)
ifeq ($(IS_64),1)
#check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
CPU_FLAGS = -maes -DAESNI
endif
endif

@ -11,6 +11,9 @@
#include "Transports.h"
#include "NetDb.h"
#include "NTCPSession.h"
#ifdef WITH_EVENTS
#include "Event.h"
#endif
using namespace i2p::crypto;
@ -604,7 +607,12 @@ namespace transport
if (!memcmp (m_NextMessage->buf + m_NextMessageOffset - 4, checksum, 4))
{
if (!m_NextMessage->IsExpired ())
{
#ifdef WITH_EVENTS
EmitEvent({{"type", "transport.recvmsg"} , {"ident", GetIdentHashBase64()}, {"number", "1"}});
#endif
m_Handler.PutNextMessage (m_NextMessage);
}
else
LogPrint (eLogInfo, "NTCP: message expired");
}

@ -126,10 +126,8 @@ namespace data
i2p::context.CleanupDestination ();
lastDestinationCleanup = ts;
}
// if we're in hidden mode don't publish or explore
// if (m_HiddenMode) continue;
if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // publish
if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL && !m_HiddenMode) // publish
{
Publish ();
lastPublish = ts;
@ -147,8 +145,9 @@ namespace data
numRouters = 800/numRouters;
if (numRouters < 1) numRouters = 1;
if (numRouters > 9) numRouters = 9;
m_Requests.ManageRequests ();
Explore (numRouters);
m_Requests.ManageRequests ();
if(!m_HiddenMode)
Explore (numRouters);
lastExploratory = ts;
}
}

@ -1,5 +1,4 @@
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "Config.h"
#include "Crypto.h"
#include "Timestamp.h"
@ -77,7 +76,6 @@ namespace i2p
}
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
i2p::config::GetOption("netid", m_NetID);
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
routerInfo.SetProperty ("router.version", I2P_VERSION);
routerInfo.CreateBuffer (m_Keys);
@ -358,8 +356,8 @@ namespace i2p
if (m_IsFloodfill)
{
// update routers and leasesets
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumLeaseSets ()));
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumRouters ()));
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, std::to_string(i2p::data::netdb.GetNumLeaseSets ()));
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, std::to_string(i2p::data::netdb.GetNumRouters ()));
UpdateRouterInfo ();
}
}

@ -3,12 +3,12 @@
#ifdef _MSC_VER
#include <stdlib.h>
#endif
#include <boost/lexical_cast.hpp>
#include "Base.h"
#include "Identity.h"
#include "Log.h"
#include "Destination.h"
#include "ClientContext.h"
#include "util.h"
#include "SAM.h"
namespace i2p
@ -420,7 +420,7 @@ namespace client
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
std::map<std::string, std::string> params;
ExtractParams (buf, params);
size_t size = boost::lexical_cast<int>(params[SAM_PARAM_SIZE]), offset = data - buf;
size_t size = std::stoi(params[SAM_PARAM_SIZE]), offset = data - buf;
if (offset + size <= len)
{
if (m_Session)
@ -587,10 +587,28 @@ namespace client
void SAMSocket::I2PReceive ()
{
if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE),
std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2),
SAM_SOCKET_CONNECTION_MAX_IDLE);
{
if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew ||
m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular
{
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE),
std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2),
SAM_SOCKET_CONNECTION_MAX_IDLE);
}
else // closed by peer
{
// get remaning data
auto len = m_Stream->ReadSome (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE);
if (len > 0) // still some data
{
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len),
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
}
else // no more data
Terminate ();
}
}
}
void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@ -599,6 +617,14 @@ namespace client
{
LogPrint (eLogError, "SAM: stream read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
if (bytes_transferred > 0)
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); // postpone termination
else
Terminate ();
}
else
Terminate ();
}
else
@ -793,7 +819,7 @@ namespace client
auto it = params->find (SAM_PARAM_SIGNATURE_TYPE);
if (it != params->end ())
// TODO: extract string values
signatureType = boost::lexical_cast<int> (it->second);
signatureType = std::stoi(it->second);
}
localDestination = i2p::client::context.CreateNewLocalDestination (true, signatureType, params);
}

@ -10,6 +10,7 @@
#include "I2PEndian.h"
#include "I2PTunnel.h"
#include "I2PService.h"
#include "util.h"
namespace i2p
{
@ -638,7 +639,7 @@ namespace proxy
{
LogPrint(eLogInfo, "SOCKS: forwarding to upstream");
EnterState(UPSTREAM_RESOLVE);
boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress,boost::lexical_cast<std::string>(m_UpstreamProxyPort) );
boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort));
m_proxy_resolver.async_resolve(q, std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
}

@ -5,6 +5,9 @@
#include "NetDb.h"
#include "SSU.h"
#include "SSUData.h"
#ifdef WITH_EVENTS
#include "Event.h"
#endif
namespace i2p
{
@ -234,8 +237,13 @@ namespace transport
{
m_ReceivedMessages.insert (msgID);
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
if (!msg->IsExpired ())
if (!msg->IsExpired ())
{
#ifdef WITH_EVENTS
EmitEvent({{"type", "transport.recvmsg"} , {"ident", m_Session.GetIdentHashBase64()}, {"number", "1"}});
#endif
m_Handler.PutNextMessage (msg);
}
else
LogPrint (eLogDebug, "SSU: message expired");
}

@ -944,7 +944,7 @@ namespace transport
// existing test
case ePeerTestParticipantAlice1:
{
if (m_State == eSessionStateEstablished)
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
{
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK
@ -953,6 +953,8 @@ namespace transport
else
{
LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice");
if (m_State == eSessionStateEstablished)
LogPrint (eLogWarning, "SSU: first peer test from Charlie through established session. We are Alice");
i2p::context.SetStatus (eRouterStatusOK);
m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
@ -961,7 +963,7 @@ namespace transport
}
case ePeerTestParticipantAlice2:
{
if (m_State == eSessionStateEstablished)
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
else
{

@ -43,7 +43,7 @@ namespace crypto
DSAVerifier (const uint8_t * signingKey)
{
m_PublicKey = CreateDSA ();
m_PublicKey->pub_key = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL);
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
}
~DSAVerifier ()
@ -58,8 +58,7 @@ namespace crypto
SHA1 (buf, len, digest);
// signature
DSA_SIG * sig = DSA_SIG_new();
sig->r = BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL);
sig->s = BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL);
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL));
// DSA verification
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
DSA_SIG_free(sig);
@ -81,7 +80,7 @@ namespace crypto
DSASigner (const uint8_t * signingPrivateKey)
{
m_PrivateKey = CreateDSA ();
m_PrivateKey->priv_key = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL);
DSA_set0_key (m_PrivateKey, NULL, BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
}
~DSASigner ()
@ -94,8 +93,10 @@ namespace crypto
uint8_t digest[20];
SHA1 (buf, len, digest);
DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey);
bn2buf (sig->r, signature, DSA_SIGNATURE_LENGTH/2);
bn2buf (sig->s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
const BIGNUM * r, * s;
DSA_SIG_get0 (sig, &r, &s);
bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2);
bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
DSA_SIG_free(sig);
}
@ -108,10 +109,11 @@ namespace crypto
{
DSA * dsa = CreateDSA ();
DSA_generate_key (dsa);
bn2buf (dsa->priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
bn2buf (dsa->pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
DSA_free (dsa);
const BIGNUM * pub_key, * priv_key;
DSA_get0_key(dsa, &pub_key, &priv_key);
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
DSA_free (dsa);
}
struct SHA256Hash
@ -270,8 +272,7 @@ namespace crypto
{
m_PublicKey = RSA_new ();
memset (m_PublicKey, 0, sizeof (RSA));
m_PublicKey->e = BN_dup (GetRSAE ());
m_PublicKey->n = BN_bin2bn (signingKey, keyLen, NULL);
RSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, keyLen, NULL) /* n */ , BN_dup (GetRSAE ()) /* d */, NULL);
}
~RSAVerifier ()
@ -304,9 +305,8 @@ namespace crypto
{
m_PrivateKey = RSA_new ();
memset (m_PrivateKey, 0, sizeof (RSA));
m_PrivateKey->e = BN_dup (GetRSAE ());
m_PrivateKey->n = BN_bin2bn (signingPrivateKey, keyLen, NULL);
m_PrivateKey->d = BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL);
RSA_set0_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen, NULL), /* n */
BN_dup (GetRSAE ()) /* e */, BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL) /* d */);
}
~RSASigner ()
@ -332,9 +332,11 @@ namespace crypto
RSA * rsa = RSA_new ();
BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const
RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL);
bn2buf (rsa->n, signingPrivateKey, publicKeyLen);
bn2buf (rsa->d, signingPrivateKey + publicKeyLen, publicKeyLen);
bn2buf (rsa->n, signingPublicKey, publicKeyLen);
const BIGNUM * n, * d, * e1;
RSA_get0_key (rsa, &n, &e1, &d);
bn2buf (n, signingPrivateKey, publicKeyLen);
bn2buf (d, signingPrivateKey + publicKeyLen, publicKeyLen);
bn2buf (n, signingPublicKey, publicKeyLen);
BN_free (e); // this e is not assigned to rsa->e
RSA_free (rsa);
}

@ -637,7 +637,8 @@ namespace stream
}
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (!m_CurrentRemoteLease || ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD)
if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate || // excluded from LeaseSet
ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD)
UpdateCurrentRemoteLease (true);
if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD)
{
@ -656,16 +657,43 @@ namespace stream
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
}
else
LogPrint (eLogWarning, "Streaming: All leases are expired, sSID=", m_SendStreamID);
{
LogPrint (eLogWarning, "Streaming: Remote lease is not available, sSID=", m_SendStreamID);
if (m_RoutingSession)
m_RoutingSession->SetSharedRoutingPath (nullptr); // invalidate routing path
}
}
void Stream::SendUpdatedLeaseSet ()
{
if (m_RoutingSession)
{
if (m_RoutingSession->IsLeaseSetNonConfirmed ())
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASET_CONFIRMATION_TIMEOUT)
{
// LeaseSet was not confirmed, should try other tunnels
LogPrint (eLogWarning, "Streaming: LeaseSet was not confrimed in ", i2p::garlic::LEASET_CONFIRMATION_TIMEOUT, " milliseconds. Trying to resubmit");
m_RoutingSession->SetSharedRoutingPath (nullptr);
m_CurrentOutboundTunnel = nullptr;
m_CurrentRemoteLease = nullptr;
SendQuickAck ();
}
}
else if (m_RoutingSession->IsLeaseSetUpdated ())
{
LogPrint (eLogDebug, "Streaming: sending updated LeaseSet");
SendQuickAck ();
}
}
}
void Stream::ScheduleResend ()
{
m_ResendTimer.cancel ();
// check for invalid value
if (m_RTO <= 0)
m_RTO = 1;
if (m_RTO <= 0) m_RTO = INITIAL_RTO;
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(m_RTO));
m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer,
shared_from_this (), std::placeholders::_1));
@ -760,7 +788,10 @@ namespace stream
{
m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
if (!m_RemoteLeaseSet)
{
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
}
}
if (m_RemoteLeaseSet)
{
@ -797,17 +828,22 @@ namespace stream
}
else
{
LogPrint (eLogWarning, "Streaming: All remote leases are expired");
m_RemoteLeaseSet = nullptr;
m_CurrentRemoteLease = nullptr;
// we have requested expired before, no need to do it twice
}
}
else
{
LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found");
m_CurrentRemoteLease = nullptr;
}
}
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
m_LastIncomingReceiveStreamID (0),
m_PendingIncomingTimer (m_Owner->GetService ()),
m_ConnTrackTimer(m_Owner->GetService()),
m_ConnsPerMinute(DEFAULT_MAX_CONNS_PER_MIN),
@ -863,8 +899,15 @@ namespace stream
{
if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream
{
auto incomingStream = CreateNewIncomingStream ();
uint32_t receiveStreamID = packet->GetReceiveStreamID ();
/* if (receiveStreamID == m_LastIncomingReceiveStreamID)
{
// already pending
LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists");
delete packet; // drop it, because previous should be connected
return;
} */
auto incomingStream = CreateNewIncomingStream ();
incomingStream->HandleNextPacket (packet); // SYN
auto ident = incomingStream->GetRemoteIdentity();
if(ident)
@ -878,6 +921,8 @@ namespace stream
return;
}
}
m_LastIncomingReceiveStreamID = receiveStreamID;
// handle saved packets if any
{
auto it = m_SavedPackets.find (receiveStreamID);

@ -51,6 +51,7 @@ namespace stream
const int INITIAL_RTO = 9000; // in milliseconds
const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
const int MAX_RECEIVE_TIMEOUT = 30; // in seconds
/** i2cp option for limiting inbound stremaing connections */
const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns";
@ -161,6 +162,7 @@ namespace stream
void SendClose ();
bool SendPacket (Packet * packet);
void SendPackets (const std::vector<Packet *>& packets);
void SendUpdatedLeaseSet ();
void SavePacket (Packet * packet);
void ProcessPacket (Packet * packet);
@ -170,7 +172,7 @@ namespace stream
void UpdateCurrentRemoteLease (bool expired = false);
template<typename Buffer, typename ReceiveHandler>
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler);
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout);
void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode);
@ -251,6 +253,7 @@ namespace stream
std::mutex m_StreamsMutex;
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams; // sendStreamID->stream
Acceptor m_Acceptor;
uint32_t m_LastIncomingReceiveStreamID;
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
boost::asio::deadline_timer m_PendingIncomingTimer;
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
@ -282,18 +285,19 @@ namespace stream
m_Service.post ([=](void)
{
if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset)
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler);
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler, 0);
else
{
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t));
s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ s->HandleReceiveTimer (ecode, buffer, handler); });
{ s->HandleReceiveTimer (ecode, buffer, handler, timeout - t); });
}
});
}
template<typename Buffer, typename ReceiveHandler>
void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler)
void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout)
{
size_t received = ConcatenatePackets (boost::asio::buffer_cast<uint8_t *>(buffer), boost::asio::buffer_size(buffer));
if (received > 0)
@ -307,8 +311,17 @@ namespace stream
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0);
}
else
{
// timeout expired
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
if (remainingTimeout <= 0)
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
else
{
// itermediate iterrupt
SendUpdatedLeaseSet (); // send our leaseset if applicable
AsyncReceive (buffer, handler, remainingTimeout);
}
}
}
}
}

@ -1,6 +1,7 @@
#include <inttypes.h>
#include <string.h>
#include <boost/asio.hpp>
#include "Log.h"
#include "I2PEndian.h"
#include "Timestamp.h"
@ -8,7 +9,7 @@ namespace i2p
{
namespace util
{
std::chrono::system_clock::duration g_TimeOffset = std::chrono::system_clock::duration::zero ();
static int64_t g_TimeOffset = 0; // in seconds
void SyncTimeWithNTP (const std::string& address)
{
@ -23,25 +24,34 @@ namespace util
socket.open (boost::asio::ip::udp::v4 (), ec);
if (!ec)
{
uint8_t request[48];// 48 bytes NTP request
memset (request, 0, 48);
request[0] = 0x80; // client mode, version 0
uint8_t * response = new uint8_t[1500]; // MTU
uint8_t buf[48];// 48 bytes NTP request/response
memset (buf, 0, 48);
htobe32buf (buf, (3 << 27) | (3 << 24)); // RFC 4330
size_t len = 0;
try
{
socket.send_to (boost::asio::buffer (request, 48), ep);
len = socket.receive_from (boost::asio::buffer (response, 1500), ep);
socket.send_to (boost::asio::buffer (buf, 48), ep);
int i = 0;
while (!socket.available() && i < 10) // 10 seconds max
{
std::this_thread::sleep_for (std::chrono::seconds(1));
i++;
}
if (socket.available ())
len = socket.receive_from (boost::asio::buffer (buf, 48), ep);
}
catch (std::exception& e)
{
LogPrint (eLogError, "NTP error: ", e.what ());
}
if (len >= 8)
{
uint32_t ts = bufbe32toh (response + 4);
auto ourTs = GetSecondsSinceEpoch ();
uint32_t ts = bufbe32toh (buf + 32);
if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900
g_TimeOffset = ts - ourTs;
LogPrint (eLogInfo, address, " time offset from system time is ", g_TimeOffset, " seconds");
}
delete[] response;
}
}
}

@ -8,8 +8,6 @@ namespace i2p
{
namespace util
{
extern std::chrono::system_clock::duration g_TimeOffset;
inline uint64_t GetMillisecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(

@ -64,6 +64,8 @@ namespace transport
virtual ~TransportSession () {};
virtual void Done () = 0;
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; };
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; };

@ -4,6 +4,11 @@
#include "I2NPProtocol.h"
#include "NetDb.h"
#include "Transports.h"
#include "Config.h"
#ifdef WITH_EVENTS
#include "Event.h"
#include "util.h"
#endif
using namespace i2p::data;
@ -229,6 +234,9 @@ namespace transport
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{
#ifdef WITH_EVENTS
EmitEvent({{"type" , "transport.sendmsg"}, {"ident", ident.ToBase64()}, {"number", std::to_string(msgs.size())}});
#endif
m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs));
}
@ -240,7 +248,8 @@ namespace transport
for (auto& it: msgs)
i2p::HandleI2NPMessage (it);
return;
}
}
if(RoutesRestricted() && ! IsRestrictedPeer(ident)) return;
auto it = m_Peers.find (ident);
if (it == m_Peers.end ())
{
@ -494,12 +503,17 @@ namespace transport
void Transports::DetectExternalIP ()
{
if (RoutesRestricted())
{
LogPrint(eLogInfo, "Transports: restricted routes enabled, not detecting ip");
i2p::context.SetStatus (eRouterStatusOK);
return;
}
if (m_SSUServer)
{
#ifndef MESHNET
i2p::context.SetStatus (eRouterStatusTesting);
#endif
bool nat; i2p::config::GetOption("nat", nat);
if (nat)
i2p::context.SetStatus (eRouterStatusTesting);
for (int i = 0; i < 5; i++)
{
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
@ -520,8 +534,10 @@ namespace transport
void Transports::PeerTest ()
{
if (RoutesRestricted()) return;
if (m_SSUServer)
{
bool statusChanged = false;
for (int i = 0; i < 5; i++)
{
@ -559,6 +575,9 @@ namespace transport
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
{
#ifdef WITH_EVENTS
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "false"}});
#endif
bool sendDatabaseStore = true;
if (it->second.delayedMessages.size () > 0)
{
@ -578,20 +597,32 @@ namespace transport
}
else // incoming connection
{
if(RoutesRestricted() && ! IsRestrictedPeer(ident)) {
// not trusted
LogPrint(eLogWarning, "Transports: closing untrusted inbound connection from ", ident.ToBase64());
session->Done();
return;
}
#ifdef WITH_EVENTS
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}});
#endif
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
}
});
});
}
void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session)
{
m_Service.post([session, this]()
{
{
auto remoteIdentity = session->GetRemoteIdentity ();
if (!remoteIdentity) return;
auto ident = remoteIdentity->GetIdentHash ();
#ifdef WITH_EVENTS
EmitEvent({{"type" , "transport.disconnected"}, {"ident", ident.ToBase64()}});
#endif
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
{
@ -655,30 +686,79 @@ namespace transport
std::advance (it, rand () % m_Peers.size ());
return it != m_Peers.end () ? it->second.router : nullptr;
}
void Transports::RestrictRoutes(std::vector<std::string> families)
{
std::lock_guard<std::mutex> lock(m_FamilyMutex);
m_TrustedFamilies.clear();
for ( const auto& fam : families )
m_TrustedFamilies.push_back(fam);
}
bool Transports::RoutesRestricted() const {
std::lock_guard<std::mutex> lock(m_FamilyMutex);
return m_TrustedFamilies.size() > 0;
}
/** XXX: if routes are not restricted this dies */
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRestrictedPeer() const {
std::string fam;
{
std::lock_guard<std::mutex> lock(m_FamilyMutex);
// TODO: random family (?)
fam = m_TrustedFamilies[0];
}
boost::to_lower(fam);
return i2p::data::netdb.GetRandomRouterInFamily(fam);
}
void Transports::RestrictRoutesToFamilies(std::set<std::string> families)
{
std::lock_guard<std::mutex> lock(m_FamilyMutex);
m_TrustedFamilies.clear();
for ( const auto& fam : families )
m_TrustedFamilies.push_back(fam);
}
void Transports::RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers)
{
std::unique_lock<std::mutex> lock(m_TrustedRoutersMutex);
m_TrustedRouters.clear();
for (const auto & ri : routers )
m_TrustedRouters.push_back(ri);
}
bool Transports::RoutesRestricted() const {
std::unique_lock<std::mutex> famlock(m_FamilyMutex);
std::unique_lock<std::mutex> routerslock(m_TrustedRoutersMutex);
return m_TrustedFamilies.size() > 0 || m_TrustedRouters.size() > 0;
}
/** XXX: if routes are not restricted this dies */
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRestrictedPeer() const
{
{
std::lock_guard<std::mutex> l(m_FamilyMutex);
std::string fam;
auto sz = m_TrustedFamilies.size();
if(sz > 1)
{
auto it = m_TrustedFamilies.begin ();
std::advance(it, rand() % sz);
fam = *it;
boost::to_lower(fam);
}
else if (sz == 1)
{
fam = m_TrustedFamilies[0];
}
if (fam.size())
return i2p::data::netdb.GetRandomRouterInFamily(fam);
}
{
std::unique_lock<std::mutex> l(m_TrustedRoutersMutex);
auto sz = m_TrustedRouters.size();
if (sz)
{
if(sz == 1)
return i2p::data::netdb.FindRouter(m_TrustedRouters[0]);
auto it = m_TrustedRouters.begin();
std::advance(it, rand() % sz);
return i2p::data::netdb.FindRouter(*it);
}
}
return nullptr;
}
bool Transports::IsRestrictedPeer(const i2p::data::IdentHash & ih) const
{
{
std::unique_lock<std::mutex> l(m_TrustedRoutersMutex);
for (const auto & r : m_TrustedRouters )
if ( r == ih ) return true;
}
{
std::unique_lock<std::mutex> l(m_FamilyMutex);
auto ri = i2p::data::netdb.FindRouter(ih);
for (const auto & fam : m_TrustedFamilies)
if(ri->IsFamily(fam)) return true;
}
return false;
}
}
}

@ -110,7 +110,11 @@ namespace transport
/** do we want to use restricted routes? */
bool RoutesRestricted() const;
/** restrict routes to use only these router families for first hops */
void RestrictRoutes(std::vector<std::string> families);
void RestrictRoutesToFamilies(std::set<std::string> families);
/** restrict routes to use only these routers for first hops */
void RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers);
bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const;
void PeerTest ();
@ -157,6 +161,10 @@ namespace transport
/** which router families to trust for first hops */
std::vector<std::string> m_TrustedFamilies;
mutable std::mutex m_FamilyMutex;
/** which routers for first hop to trust */
std::vector<i2p::data::IdentHash> m_TrustedRouters;
mutable std::mutex m_TrustedRoutersMutex;
public:

@ -11,6 +11,10 @@
#include "Transports.h"
#include "NetDb.h"
#include "Tunnel.h"
#include "TunnelPool.h"
#ifdef WITH_EVENTS
#include "Event.h"
#endif
namespace i2p
{
@ -29,12 +33,14 @@ namespace tunnel
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
{
#ifdef WITH_EVENTS
std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64();
#endif
auto numHops = m_Config->GetNumHops ();
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
auto msg = NewI2NPShortMessage ();
*msg->GetPayload () = numRecords;
msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1;
// shuffle records
std::vector<int> recordIndicies;
for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i);
@ -55,8 +61,14 @@ namespace tunnel
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID);
hop->recordIndex = idx;
i++;
#ifdef WITH_EVENTS
peers += ":" + hop->ident->GetIdentHash().ToBase64();
#endif
hop = hop->next;
}
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnel.build", this, peers);
#endif
// fill up fake records with random data
for (int i = numHops; i < numRecords; i++)
{
@ -182,12 +194,22 @@ namespace tunnel
return ret;
}
void Tunnel::SetState(TunnelState state)
{
m_State = state;
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnel.state", this, state);
#endif
}
void Tunnel::PrintHops (std::stringstream& s) const
{
for (auto& it: m_Hops)
// hops are in inverted order, we must print in direct order
for (auto it = m_Hops.rbegin (); it != m_Hops.rend (); it++)
{
s << " &#8658; ";
s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ());
s << i2p::data::GetIdentHashAbbreviation ((*it)->ident->GetIdentHash ());
}
}
@ -581,6 +603,9 @@ namespace tunnel
hop = hop->next;
}
}
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed);
#endif
// delete
it = pendingTunnels.erase (it);
m_NumFailedTunnelCreations++;
@ -590,6 +615,9 @@ namespace tunnel
break;
case eTunnelStateBuildFailed:
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted");
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed);
#endif
it = pendingTunnels.erase (it);
m_NumFailedTunnelCreations++;
break;
@ -640,11 +668,13 @@ namespace tunnel
}
}
if (m_OutboundTunnels.size () < 5)
if (m_OutboundTunnels.size () < 3)
{
// trying to create one more oubound tunnel
auto inboundTunnel = GetNextInboundTunnel ();
auto router = i2p::data::netdb.GetRandomRouter ();
auto router = i2p::transport::transports.RoutesRestricted() ?
i2p::transport::transports.GetRestrictedPeer() :
i2p::data::netdb.GetRandomRouter ();
if (!inboundTunnel || !router) return;
LogPrint (eLogDebug, "Tunnel: creating one hop outbound tunnel");
CreateTunnel<OutboundTunnel> (
@ -697,16 +727,18 @@ namespace tunnel
CreateZeroHopsOutboundTunnel ();
if (!m_ExploratoryPool)
{
m_ExploratoryPool = CreateTunnelPool (2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
m_ExploratoryPool = CreateTunnelPool (2, 2, 3, 3); // 2-hop exploratory, 3 tunnels
m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ());
}
return;
}
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5)
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3)
{
// trying to create one more inbound tunnel
auto router = i2p::data::netdb.GetRandomRouter ();
auto router = i2p::transport::transports.RoutesRestricted() ?
i2p::transport::transports.GetRestrictedPeer() :
i2p::data::netdb.GetRandomRouter ();
if (!router) {
LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel");
return;
@ -771,7 +803,7 @@ namespace tunnel
std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{
if (config)
if (config)
return CreateTunnel<InboundTunnel>(config, outboundTunnel);
else
return CreateZeroHopsInboundTunnel ();

@ -19,11 +19,49 @@
#include "TunnelGateway.h"
#include "TunnelBase.h"
#include "I2NPProtocol.h"
#include "Event.h"
namespace i2p
{
namespace tunnel
{
{
template<typename TunnelT>
static void EmitTunnelEvent(const std::string & ev, const TunnelT & t)
{
#ifdef WITH_EVENTS
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}});
#else
(void) ev;
(void) t;
#endif
}
template<typename TunnelT, typename T>
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val)
{
#ifdef WITH_EVENTS
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", std::to_string(val)}, {"inbound", std::to_string(t->IsInbound())}});
#else
(void) ev;
(void) t;
(void) val;
#endif
}
template<typename TunnelT>
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const std::string & val)
{
#ifdef WITH_EVENTS
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", val}, {"inbound", std::to_string(t->IsInbound())}});
#else
(void) ev;
(void) t;
(void) val;
#endif
}
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
@ -40,7 +78,7 @@ namespace tunnel
eTunnelStateFailed,
eTunnelStateExpiring
};
class OutboundTunnel;
class InboundTunnel;
class Tunnel: public TunnelBase
@ -62,12 +100,13 @@ namespace tunnel
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const;
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
TunnelState GetState () const { return m_State; };
void SetState (TunnelState state) { m_State = state; };
void SetState (TunnelState state);
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
bool IsFailed () const { return m_State == eTunnelStateFailed; };
bool IsRecreated () const { return m_IsRecreated; };
void SetIsRecreated () { m_IsRecreated = true; };
virtual bool IsInbound() const = 0;
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
@ -107,6 +146,8 @@ namespace tunnel
// implements TunnelBase
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
bool IsInbound() const { return false; }
private:
@ -123,7 +164,7 @@ namespace tunnel
void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg);
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
void Print (std::stringstream& s) const;
bool IsInbound() const { return true; }
private:
TunnelEndpoint m_Endpoint;

@ -48,7 +48,7 @@ namespace tunnel
uint32_t GetCreationTime () const { return m_CreationTime; };
void SetCreationTime (uint32_t t) { m_CreationTime = t; };
private:
uint32_t m_TunnelID, m_NextTunnelID;

@ -7,12 +7,18 @@
#include "Garlic.h"
#include "Transports.h"
#include "Log.h"
#include "Tunnel.h"
#include "TunnelPool.h"
#include "Destination.h"
#ifdef WITH_EVENTS
#include "Event.h"
#endif
namespace i2p
{
namespace tunnel
{
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true),
@ -67,6 +73,9 @@ namespace tunnel
{
if (!m_IsActive) return;
{
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.created", createdTunnel);
#endif
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
m_InboundTunnels.insert (createdTunnel);
}
@ -77,7 +86,10 @@ namespace tunnel
void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel)
{
if (expiredTunnel)
{
{
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.expired", expiredTunnel);
#endif
expiredTunnel->SetTunnelPool (nullptr);
for (auto& it: m_Tests)
if (it.second.second == expiredTunnel) it.second.second = nullptr;
@ -91,6 +103,9 @@ namespace tunnel
{
if (!m_IsActive) return;
{
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.created", createdTunnel);
#endif
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
m_OutboundTunnels.insert (createdTunnel);
}
@ -101,6 +116,9 @@ namespace tunnel
{
if (expiredTunnel)
{
#ifdef WITH_EVENTS
EmitTunnelEvent("tunnels.expired", expiredTunnel);
#endif
expiredTunnel->SetTunnelPool (nullptr);
for (auto& it: m_Tests)
if (it.second.first == expiredTunnel) it.second.first = nullptr;

@ -0,0 +1,137 @@
#include "Websocket.h"
#include "Log.h"
#include <set>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <boost/property_tree/ini_parser.hpp>
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
#if !GCC47_BOOST149
#include <boost/property_tree/json_parser.hpp>
#endif
#include <stdexcept>
namespace i2p
{
namespace event
{
typedef websocketpp::server<websocketpp::config::asio> ServerImpl;
typedef websocketpp::connection_hdl ServerConn;
class WebsocketServerImpl : public EventListener
{
private:
typedef ServerImpl::message_ptr MessagePtr;
public:
WebsocketServerImpl(const std::string & addr, int port) : m_run(false), m_thread(nullptr)
{
m_server.init_asio();
m_server.set_open_handler(std::bind(&WebsocketServerImpl::ConnOpened, this, std::placeholders::_1));
m_server.set_close_handler(std::bind(&WebsocketServerImpl::ConnClosed, this, std::placeholders::_1));
m_server.set_message_handler(std::bind(&WebsocketServerImpl::OnConnMessage, this, std::placeholders::_1, std::placeholders::_2));
m_server.listen(boost::asio::ip::address::from_string(addr), port);
}
~WebsocketServerImpl()
{
}
void Start() {
m_run = true;
m_server.start_accept();
m_thread = new std::thread([&] () {
while(m_run) {
try {
m_server.run();
} catch (std::exception & e ) {
LogPrint(eLogError, "Websocket server: ", e.what());
}
}
});
}
void Stop() {
m_run = false;
m_server.stop();
if(m_thread) {
m_thread->join();
delete m_thread;
}
m_thread = nullptr;
}
void ConnOpened(ServerConn c)
{
std::lock_guard<std::mutex> lock(m_connsMutex);
m_conns.insert(c);
}
void ConnClosed(ServerConn c)
{
std::lock_guard<std::mutex> lock(m_connsMutex);
m_conns.erase(c);
}
void OnConnMessage(ServerConn conn, ServerImpl::message_ptr msg)
{
(void) conn;
(void) msg;
}
void HandleEvent(const EventType & ev)
{
std::lock_guard<std::mutex> lock(m_connsMutex);
LogPrint(eLogDebug, "websocket event");
boost::property_tree::ptree event;
for (const auto & item : ev) {
event.put(item.first, item.second);
}
std::ostringstream ss;
write_json(ss, event);
std::string s = ss.str();
ConnList::iterator it;
for (it = m_conns.begin(); it != m_conns.end(); ++it) {
ServerImpl::connection_ptr con = m_server.get_con_from_hdl(*it);
con->send(s);
}
}
private:
typedef std::set<ServerConn, std::owner_less<ServerConn> > ConnList;
bool m_run;
std::thread * m_thread;
std::mutex m_connsMutex;
ConnList m_conns;
ServerImpl m_server;
};
WebsocketServer::WebsocketServer(const std::string & addr, int port) : m_impl(new WebsocketServerImpl(addr, port)) {}
WebsocketServer::~WebsocketServer()
{
delete m_impl;
}
void WebsocketServer::Start()
{
m_impl->Start();
}
void WebsocketServer::Stop()
{
m_impl->Stop();
}
EventListener * WebsocketServer::ToListener()
{
return m_impl;
}
}
}

@ -0,0 +1,28 @@
#ifndef WEBSOCKET_H__
#define WEBSOCKET_H__
#include "Event.h"
namespace i2p
{
namespace event
{
class WebsocketServerImpl;
class WebsocketServer
{
public:
WebsocketServer(const std::string & addr, int port);
~WebsocketServer();
void Start();
void Stop();
EventListener * ToListener();
private:
WebsocketServerImpl * m_impl;
};
}
}
#endif

@ -58,6 +58,7 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
../../TunnelGateway.cpp \
../../TunnelPool.cpp \
../../Timestamp.cpp \
../../Event.cpp \
../../util.cpp \
../../i2pd.cpp ../../UPnP.cpp

@ -18,6 +18,8 @@ option(WITH_GUI "Include GUI (currently MS Windows only)" ON)
option(WITH_MESHNET "Build for cjdns test network" OFF)
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
option(WITH_I2LUA "Build for i2lua" OFF)
option(WITH_WEBSOCKETS "Build with websocket ui" OFF)
# paths
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
@ -58,12 +60,22 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/Signature.cpp"
"${CMAKE_SOURCE_DIR}/Timestamp.cpp"
"${CMAKE_SOURCE_DIR}/api.cpp"
"${CMAKE_SOURCE_DIR}/Event.cpp"
)
if (WITH_WEBSOCKETS)
add_definitions(-DWITH_EVENTS)
find_package(websocketpp REQUIRED)
endif ()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
endif ()
if (WITH_I2LUA)
add_definitions(-DI2LUA)
endif()
add_library(libi2pd ${LIBI2PD_SRC})
set_target_properties(libi2pd PROPERTIES PREFIX "")
install(TARGETS libi2pd
@ -87,6 +99,9 @@ set (CLIENT_SRC
"${CMAKE_SOURCE_DIR}/I2CP.cpp"
)
if(WITH_WEBSOCKETS)
list (APPEND CLIENT_SRC "${CMAKE_SOURCE_DIR}/Websocket.cpp")
endif ()
add_library(i2pdclient ${CLIENT_SRC})
set (DAEMON_SRC
@ -361,6 +376,8 @@ message(STATUS " PCH : ${WITH_PCH}")
message(STATUS " MESHNET : ${WITH_MESHNET}")
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
message(STATUS " THEADSANITIZER : ${WITH_THREADSANITIZER}")
message(STATUS " I2LUA : ${WITH_I2LUA}")
message(STATUS " WEBSOCKETS : ${WITH_WEBSOCKETS}")
message(STATUS "---------------------------------------")
#Handle paths nicely

@ -0,0 +1,2 @@
This forder contain systemd unit files.
To use systemd daemon control, place files from this directory to debian folder.

@ -0,0 +1,25 @@
[Unit]
Description=I2P Router written in C++
After=network.target
[Service]
User=i2pd
Group=i2pd
Type=forking
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/i2pd/i2pd.pid
### Uncomment, if auto restart needed
#Restart=on-failure
### Use SIGINT for gracefull stop daemon.
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die.
KillSignal=SIGINT
TimeoutStopSec=10m
# If you have problems with hunging i2pd, you can try enable this
#LimitNOFILE=4096
PrivateDevices=yes
[Install]
WantedBy=multi-user.target

@ -0,0 +1,2 @@
d /var/run/i2pd 0755 i2pd i2pd - -
d /var/log/i2pd 0755 i2pd i2pd - -

9
debian/.gitignore vendored

@ -0,0 +1,9 @@
files
i2pd-dbg.substvars
i2pd-dbg/
i2pd.postinst.debhelper
i2pd.postrm.debhelper
i2pd.prerm.debhelper
i2pd.substvars
i2pd/

@ -6,3 +6,6 @@ I2PD_ENABLED="yes"
# Additional options that are passed to the Daemon.
# see possible switches in /usr/share/doc/i2pd/configuration.md.gz
DAEMON_OPTS=""
# If you have problems with hunging i2pd, you can try enable this
#ulimit -n 4096

8
debian/i2pd.init vendored

@ -15,10 +15,10 @@ DESC=i2pd # Introduce a short description here
NAME=i2pd # Introduce the short server's name here
DAEMON=/usr/sbin/$NAME # Introduce the server's location here
DAEMON_OPTS="" # Arguments to run the daemon with
PIDFILE=/var/run/$NAME.pid
PIDFILE=/var/run/$NAME/$NAME.pid
I2PCONF=/etc/$NAME/i2pd.conf
TUNCONF=/etc/$NAME/tunnels.conf
LOGFILE=/var/log/$NAME.log
LOGFILE=/var/log/$NAME/$NAME.log
USER="i2pd"
# Exit if the package is not installed
@ -41,9 +41,11 @@ do_start()
return 2
fi
test -e /var/run/i2pd || install -m 755 -o i2pd -g i2pd -d /var/run/i2pd
touch "$PIDFILE"
chown -f $USER:adm "$PIDFILE"
test -e /var/log/i2pd || install -m 755 -o i2pd -g i2pd -d /var/log/i2pd
touch "$LOGFILE"
chown -f $USER:adm "$LOGFILE"
@ -99,7 +101,7 @@ case "$1" in
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
reload)
reload|force-reload)
log_daemon_msg "Reloading $DESC" "$NAME"
do_reload
log_end_msg $?

@ -1,7 +1,7 @@
#!/sbin/openrc-run
pidfile="/var/run/i2pd.pid"
logfile="/var/log/i2pd.log"
pidfile="/var/run/i2pd/i2pd.pid"
logfile="/var/log/i2pd/i2pd.log"
mainconf="/etc/i2pd/i2pd.conf"
tunconf="/etc/i2pd/tunnels.conf"
@ -32,9 +32,6 @@ start_pre() {
checkpath -f -o i2pd:adm $logfile
checkpath -f -o i2pd:adm $pidfile
if [ -n "$I2PD_PORT" -a "$I2PD_PORT" -gt 0 ]; then
command_args="$command_args --port=$I2PD_PORT"
fi
if [ -n "$DAEMON_OPTS" ]; then
command_args="$command_args $DAEMON_OPTS"
fi

@ -4,7 +4,7 @@ start on runlevel [2345]
stop on runlevel [016] or unmounting-filesystem
# these can be overridden in /etc/init/i2pd.override
env LOGFILE="/var/log/i2pd.log"
env LOGFILE="/var/log/i2pd/i2pd.log"
expect fork

2
debian/logrotate vendored

@ -1,4 +1,4 @@
/var/log/i2pd.log {
/var/log/i2pd/i2pd.log {
rotate 6
daily
missingok

@ -1,5 +1,5 @@
diff --git a/Makefile b/Makefile
index 7d04ba0..33ee184 100644
index b6fc795..abc3ace 100644
--- a/Makefile
+++ b/Makefile
@@ -9,10 +9,10 @@ DEPS := obj/make.dep
@ -10,8 +10,7 @@ index 7d04ba0..33ee184 100644
+USE_AESNI := no
USE_STATIC := no
USE_MESHNET := no
-USE_UPNP := no
+USE_UPNP := yes
ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp
USE_UPNP := no
ifeq ($(WEBSOCKETS),1)
NEEDED_CXXFLAGS += -DWITH_EVENTS

4
debian/postinst vendored

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

4
debian/postrm vendored

@ -2,9 +2,11 @@
set -e
if [ "$1" = "purge" ]; then
rm -f /etc/default/i2pd /var/log/i2pd.log
rm -f /etc/default/i2pd
rm -rf /etc/i2pd
rm -rf /var/lib/i2pd
rm -rf /var/log/i2pd
rm -rf /var/run/i2pd
fi
#DEBHELPER#

3
debian/rules vendored

@ -15,3 +15,6 @@ PREFIX=/usr
override_dh_strip:
dh_strip --dbg-package=i2pd-dbg
override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info

@ -1,57 +0,0 @@
Building on Android
===================
There are two versions: with QT and without QT.
Pre-requesties
--------------
You need to install Android SDK, NDK and QT with android support.
- [SDK](https://developer.android.com/studio/index.html) (choose command line tools only)
- [NDK](https://developer.android.com/ndk/downloads/index.html)
- [QT](https://www.qt.io/download-open-source/)(for QT only). Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run )
You also need Java JDK and Ant.
QT-Creator (for QT only)
------------------------
Open QT-creator that should be installed with QT.
Go to Settings/Anndroid and specify correct paths to SDK and NDK.
If everything is correct you will see two set avaiable:
Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt).
Dependencies
--------------
Take following pre-compiled binaries from PurpleI2P's repositories.
```bash
git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
git clone https://github.com/PurpleI2P/android-ifaddrs.git
```
Building the app with QT
------------------------
- Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator
- Change line MAIN_PATH = /path/to/libraries to an actual path where you put the dependancies to
- Select appropriate project (usually armeabi-v7a) and build
- You will find an .apk file in android-build/bin folder
Building the app without QT
---------------------------
- Change line I2PD_LIBS_PATH in android/jni/Application.mk to an actual path where you put the dependancies to
- Run 'ndk-build -j4' from andorid folder
- Create or edit file 'local.properties'. Place 'sdk.dir=<path to SDK>' and 'ndk.dir=<path to NDK>'
- Run 'ant clean debug'
Creating release .apk
----------------------
In order to create release .apk you must obtain a Java keystore file(.jks). Either you have in already, or you can generate it yourself using keytool, or from one of you existing well-know ceritificates. For example, i2pd release are signed with this [certificate](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/certificates/router/orignal_at_mail.i2p.crt).
Create file 'ant.propeties'
key.store='path to keystore file'
key.alias='alias name'
key.store.password='keystore password'
key.alias.password='alias password'
Run 'ant clean release'

@ -1,75 +0,0 @@
Cross compilation notes
=======================
Static 64 bit windows binary on Ubuntu 15.10 (Wily Werewolf)
---------------------------------------------------------------------
Install cross compiler and friends
```sh
sudo apt-get install g++-mingw-w64-x86-64
```
Default is to use Win32 threading model which lacks std::mutex and such. So we change defaults
```sh
sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
```
From now on we assume we have everything in `~/dev/`. Get Boost sources unpacked into `~/dev/boost_1_60_0/`
and change directory to it.
Now add out cross compiler configuration. Warning: the following will wipe out whatever you had in there.
```sh
echo "using gcc : mingw : x86_64-w64-mingw32-g++ ;" > ~/user-config.jam
```
Proceed with building Boost normal way, but let's define dedicated staging directory
```sh
./bootstrap.sh
./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \
--build-type=minimal --with-filesystem --with-program_options --with-date_time \
--stagedir=stage-mingw-64
cd ..
```
Now we get & build OpenSSL
```sh
git clone https://github.com/openssl/openssl
cd openssl
git checkout OpenSSL_1_0_2g
./Configure mingw64 no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 \
no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp \
--prefix=~/dev/stage --cross-compile-prefix=x86_64-w64-mingw32-
make depend
make
make install
cd ..
```
and Zlib
```sh
git clone https://github.com/madler/zlib
cd zlib
git checkout v1.2.8
CC=x86_64-w64-mingw32-gcc CFLAGS=-O3 ./configure --static --64 --prefix=~/dev/stage
make
make install
cd ..
```
Now we prepare cross toolchain hint file for CMake, let's name it `~/dev/toolchain-mingw.cmake`
```cmake
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
```
Download miniupnpc, unpack, and symlink it into `~/dev/miniupnpc/`.
Finally, we can build i2pd with all that goodness
```sh
git clone https://github.com/PurpleI2P/i2pd
mkdir i2pd-mingw-64-build
cd i2pd-mingw-64-build
BOOST_ROOT=~/dev/boost_1_60_0 cmake -G 'Unix Makefiles' ~/dev/i2pd/build -DBUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=~/dev/toolchain-mingw.cmake -DWITH_AESNI=ON -DWITH_UPNP=ON -DWITH_STATIC=ON \
-DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=~/dev/i2pd-mingw-64-static \
-DZLIB_ROOT=~/dev/stage -DBOOST_LIBRARYDIR:PATH=~/dev/boost_1_60_0/stage-mingw-64/lib \
-DOPENSSL_ROOT_DIR:PATH=~/dev/stage
make
x86_64-w64-mingw32-strip i2pd.exe
```
By now, you should have a release build with stripped symbols.

@ -1,148 +0,0 @@
Building on Unix systems
=============================
First of all we need to make sure that all dependencies are satisfied.
This doc is trying to cover:
* [Debian/Ubuntu](#debian-ubuntu) (contains packaging instructions)
* [Fedora/Centos](#fedora-centos)
* [Fedora/Centos](#mac-os-x)
* [FreeBSD](#freebsd)
Make sure you have all required dependencies for your system successfully installed.
If so then we are ready to go!
Let's clone the repository and start building the i2pd:
```bash
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd/build
cmake -DCMAKE_BUILD_TYPE=Release # more options could be passed, see "CMake Options"
make # you may add VERBOSE=1 to cmdline for debugging
```
After successfull build i2pd could be installed with:
```bash
make install
```
or you can just use 'make' once you have all dependencies (boost and openssl) installed
```bash
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd
make
```
Debian/Ubuntu
-------------
You will need a compiler and other tools that could be installed with `build-essential` package:
```bash
sudo apt-get install build-essential
```
Also you will need a bunch of development libraries:
```bash
sudo apt-get install \
libboost-chrono-dev \
libboost-date-time-dev \
libboost-filesystem-dev \
libboost-program-options-dev \
libboost-system-dev \
libboost-thread-dev \
libssl-dev
```
If you need UPnP support (don't forget to run CMake with `WITH_UPNP=ON`) miniupnpc development library should be installed:
```bash
sudo apt-get install libminiupnpc-dev
```
You may also build deb-package with the following:
```bash
sudo apt-get install fakeroot devscripts
cd i2pd
debuild --no-tgz-check
```
Fedora/Centos
-------------
You will need a compiler and other tools to perform a build:
```bash
sudo yum install make cmake gcc gcc-c++
```
*Latest Fedora system using [DNF](https://en.wikipedia.org/wiki/DNF_(software)) instead of YUM by default, you may prefer to use DNF, but YUM should be ok*
Also you will need a bunch of development libraries
```bash
sudo yum install boost-devel openssl-devel
```
If you need UPnP support (don't forget to run CMake with `WITH_UPNP=ON`) miniupnpc development library should be installed:
```bash
miniupnpc-devel
```
> *Centos 7 has CMake 2.8.11 in the official repositories that too old to build i2pd, CMake >=2.8.12 is required.*
>
> But you can use cmake3 from the epel repository:
> ```bash
> yum install epel-release -y
> yum install make cmake3 gcc gcc-c++ miniupnpc-devel boost-devel openssl-devel -y
> cmake3 -DWITH_LIBRARY=OFF -DWITH_UPNP=ON -DWITH_HARDENING=ON -DBUILD_SHARED_LIBS:BOOL=OFF
> make
> ```
MAC OS X
--------
Requires [homebrew](http://brew.sh/)
```bash
brew install libressl boost
```
Then build:
```bash
make HOMEBREW=1
```
FreeBSD
-------
For 10.X use clang. You would also need boost and openssl ports.
Type gmake, it invokes Makefile.bsd, make necessary changes there is required.
Branch 9.X has gcc v4.2, that knows nothing about required c++11 standart.
Required ports:
* `devel/cmake`
* `devel/boost-libs`
* `lang/gcc47`(or later version)
To use newer compiler you should set these variables(replace "47" with your actual gcc version):
```bash
export CC=/usr/local/bin/gcc47
export CXX=/usr/local/bin/g++47
```
CMake Options
-------------
Available CMake options(each option has a form of `<key>=<value>`, for more information see `man 1 cmake`):
* `CMAKE_BUILD_TYPE` build profile (Debug/Release)
* `WITH_BINARY` build i2pd itself
* `WITH_LIBRARY` build libi2pd
* `WITH_STATIC` build static versions of library and i2pd binary
* `WITH_UPNP` build with UPnP support (requires libupnp)
* `WITH_AESNI` build with AES-NI support (ON/OFF)
* `WITH_HARDENING` enable hardening features (ON/OFF) (gcc only)
* `WITH_PCH` use pre-compiled header (experimental, speeds up build)
Also there is `-L` flag for CMake that could be used to list current cached options:
```bash
cmake -L
```

@ -1,15 +0,0 @@
Build requirements
============
Linux/FreeBSD/OSX
-----------------
GCC 4.7 or newer, Boost 1.49 or newer, openssl, zlib. Clang can be used instead of GCC.
Windows
-------
VS2013 (known to work with 12.0.21005.1 or newer), Boost 1.46 or newer,
crypto++ 5.62. See Win32/README-Build.txt for instructions on how to build i2pd
and its dependencies.

@ -0,0 +1,65 @@
Building on Android
===================
There are two versions: with QT and without QT.
Pre-requesties
--------------
You need to install Android SDK, NDK and QT with android support.
- [SDK](https://developer.android.com/studio/index.html) (choose command line tools only)
- [NDK](https://developer.android.com/ndk/downloads/index.html)
- [QT](https://www.qt.io/download-open-source/)(for QT only).
Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run)
You also need Java JDK and Ant.
QT-Creator (for QT only)
------------------------
Open QT-creator that should be installed with QT.
Go to Settings/Anndroid and specify correct paths to SDK and NDK.
If everything is correct you will see two set avaiable:
Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt).
Dependencies
--------------
Take following pre-compiled binaries from PurpleI2P's repositories.
git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
git clone https://github.com/PurpleI2P/android-ifaddrs.git
Building the app with QT
------------------------
- Open `qt/i2pd_qt/i2pd_qt.pro` in the QT-creator
- Change line `MAIN_PATH = /path/to/libraries` to an actual path where you put the dependancies to
- Select appropriate project (usually armeabi-v7a) and build
- You will find an .apk file in `android-build/bin` folder
Building the app without QT
---------------------------
- Change line `I2PD_LIBS_PATH` in `android/jni/Application.mk` to an actual path where you put the dependancies to
- Run `ndk-build -j4` from andorid folder
- Create or edit file 'local.properties'. Place 'sdk.dir=<path to SDK>' and 'ndk.dir=<path to NDK>'
- Run `ant clean debug`
Creating release .apk
----------------------
In order to create release .apk you must obtain a Java keystore file(.jks). Either you have in already, or you can generate it yourself using keytool, or from one of you existing well-know ceritificates.
For example, i2pd release are signed with this [certificate](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/certificates/router/orignal_at_mail.i2p.crt).
Create file 'ant.propeties':
key.store='path to keystore file'
key.alias='alias name'
key.store.password='keystore password'
key.alias.password='alias password'
Run `ant clean release`

@ -0,0 +1,74 @@
Cross compilation notes
=======================
Static 64 bit windows binary on Ubuntu 15.10 (Wily Werewolf)
------------------------------------------------------------
Install cross compiler and friends
sudo apt-get install g++-mingw-w64-x86-64
Default is to use Win32 threading model which lacks std::mutex and such. So we change defaults
sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
From now on we assume we have everything in `~/dev/`. Get Boost sources unpacked into `~/dev/boost_1_60_0/` and change directory to it.
Now add out cross compiler configuration. Warning: the following will wipe out whatever you had in there.
echo "using gcc : mingw : x86_64-w64-mingw32-g++ ;" > ~/user-config.jam
Proceed with building Boost normal way, but let's define dedicated staging directory
./bootstrap.sh
./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \
--build-type=minimal --with-filesystem --with-program_options --with-date_time \
--stagedir=stage-mingw-64
cd ..
Now we get & build OpenSSL
git clone https://github.com/openssl/openssl
cd openssl
git checkout OpenSSL_1_0_2g
./Configure mingw64 no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 \
no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp \
--prefix=~/dev/stage --cross-compile-prefix=x86_64-w64-mingw32-
make depend
make
make install
cd ..
...and zlib
git clone https://github.com/madler/zlib
cd zlib
git checkout v1.2.8
CC=x86_64-w64-mingw32-gcc CFLAGS=-O3 ./configure --static --64 --prefix=~/dev/stage
make
make install
cd ..
Now we prepare cross toolchain hint file for CMake, let's name it `~/dev/toolchain-mingw.cmake`
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
Download miniupnpc, unpack and symlink it into `~/dev/miniupnpc/`.
Finally, we can build i2pd with all that goodness
git clone https://github.com/PurpleI2P/i2pd
mkdir i2pd-mingw-64-build
cd i2pd-mingw-64-build
BOOST_ROOT=~/dev/boost_1_60_0 cmake -G 'Unix Makefiles' ~/dev/i2pd/build -DBUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=~/dev/toolchain-mingw.cmake -DWITH_AESNI=ON -DWITH_UPNP=ON -DWITH_STATIC=ON \
-DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=~/dev/i2pd-mingw-64-static \
-DZLIB_ROOT=~/dev/stage -DBOOST_LIBRARYDIR:PATH=~/dev/boost_1_60_0/stage-mingw-64/lib \
-DOPENSSL_ROOT_DIR:PATH=~/dev/stage
make
x86_64-w64-mingw32-strip i2pd.exe
By now, you should have a release build with stripped symbols.

@ -9,31 +9,30 @@ Prerequisites
XCode7+, cmake 3.2+
Dependencies
--------------
------------
- precompiled openssl
- precompiled boost with modules `filesystem`, `program_options`, `date_time` and `system`
- ios-cmake toolchain from https://github.com/vovasty/ios-cmake.git
- ios-cmake toolchain from `https://github.com/vovasty/ios-cmake.git`
Building
------------------------
Assume you have folder structure
--------
```
lib
libboost_date_time.a
libboost_filesystem.a
libboost_program_options.a
libboost_system.a
libboost.a
libcrypto.a
libssl.a
include
boost
openssl
ios-cmake
i2pd
```
Assume you have folder structure
lib/
libboost_date_time.a
libboost_filesystem.a
libboost_program_options.a
libboost_system.a
libboost.a
libcrypto.a
libssl.a
include/
boost/
openssl/
ios-cmake/
i2pd/
```bash
mkdir -p build/simulator/lib build/ios/lib include/i2pd
@ -77,9 +76,10 @@ cp i2pd/*.h include/i2pd
```
Include into project
---------------------------
1. add all libraries in `lib` folder to `Project linked frameworks`.
2. add `libc++` and `libz` libraries from system libraries to `Project linked frameworks`.
3. add path to i2p headers to your `Headers search paths`
--------------------
- add all libraries in `lib` folder to `Project linked frameworks`.
- add `libc++` and `libz` libraries from system libraries to `Project linked frameworks`.
- add path to i2p headers to your `Headers search paths`
Alternatively you may use swift wrapper https://github.com/vovasty/SwiftyI2P.git
Alternatively you may use swift wrapper `https://github.com/vovasty/SwiftyI2P.git`

@ -0,0 +1,15 @@
Build requirements
==================
In general, for building i2pd you need several things:
* compiler with c++11 support (for example: gcc >= 4.7, clang)
* boost >= 1.49
* openssl library
* zlib library (openssl already depends on it)
Optional tools:
* cmake >= 2.8 (or 3.3+ if you want to use precompiled headers on windows)
* miniupnp library (for upnp support)
* [websocketpp](https://github.com/zaphoyd/websocketpp/) (for websocket ui)

@ -0,0 +1,138 @@
Building on Unix systems
=============================
First of all we need to make sure that all dependencies are satisfied.
This doc is trying to cover:
* [Debian/Ubuntu](#debian-ubuntu) (contains packaging instructions)
* [Fedora/Centos](#fedora-centos)
* [Fedora/Centos](#mac-os-x)
* [FreeBSD](#freebsd)
Make sure you have all required dependencies for your system successfully installed.
See [this](requirements.md) page for common requirements.
If so then we are ready to go!
Let's clone the repository and start building the i2pd:
git clone https://github.com/PurpleI2P/i2pd.git
Generic build process looks like this (with cmake):
cd i2pd/build
cmake <cmake options> . # see "CMake Options" section below
make # you may add VERBOSE=1 to cmdline for debugging
..or with quick-and-dirty way with just make:
cd i2pd/
make
After successfull build i2pd could be installed with:
make install
CMake Options
-------------
Available CMake options(each option has a form of `<key>=<value>`, for more information see `man 1 cmake`):
* `CMAKE_BUILD_TYPE` build profile (Debug/Release)
* `WITH_BINARY` build i2pd itself
* `WITH_LIBRARY` build libi2pd
* `WITH_STATIC` build static versions of library and i2pd binary
* `WITH_UPNP` build with UPnP support (requires libminiupnp)
* `WITH_AESNI` build with AES-NI support (ON/OFF)
* `WITH_HARDENING` enable hardening features (ON/OFF) (gcc only)
* `WITH_PCH` use pre-compiled header (experimental, speeds up build)
* `WITH_I2LUA` used when building i2lua
* `WITH_WEBSOCKETS` enable websocket server
Also there is `-L` flag for CMake that could be used to list current cached options:
cmake -L
Debian/Ubuntu
-------------
You will need a compiler and other tools that could be installed with `build-essential` package:
sudo apt-get install build-essential
Also you will need a bunch of development libraries:
sudo apt-get install \
libboost-chrono-dev \
libboost-date-time-dev \
libboost-filesystem-dev \
libboost-program-options-dev \
libboost-system-dev \
libboost-thread-dev \
libssl-dev
If you need UPnP support miniupnpc development library should be installed (don't forget to rerun CMake with needed option):
sudo apt-get install libminiupnpc-dev
You may also build deb-package with the following:
sudo apt-get install fakeroot devscripts
cd i2pd
debuild --no-tgz-check
Fedora/Centos
-------------
You will need a compiler and other tools to perform a build:
sudo yum install make cmake gcc gcc-c++
Also you will need a bunch of development libraries
sudo yum install boost-devel openssl-devel
If you need UPnP support miniupnpc development library should be installed (don't forget to rerun CMake with needed option):
sudo yum install miniupnpc-devel
Latest Fedora systems using [DNF](https://en.wikipedia.org/wiki/DNF_(software)) instead of YUM by default, you may prefer to use DNF, but YUM should be ok
Centos 7 has CMake 2.8.11 in the official repositories that too old to build i2pd, CMake >=2.8.12 is required.
But you can use cmake3 from the epel repository:
yum install epel-release -y
yum install make cmake3 gcc gcc-c++ miniupnpc-devel boost-devel openssl-devel -y
...and then use 'cmake3' instead 'cmake'.
MAC OS X
--------
Requires [homebrew](http://brew.sh)
brew install boost libressl
Then build:
make HOMEBREW=1
FreeBSD
-------
For 10.X use clang. You would also need devel/boost-libs, security/openssl and devel/gmake ports.
Type gmake, it invokes Makefile.bsd, make necessary changes there is required.
Branch 9.X has gcc v4.2, that is too old (not supports -std=c++11)
Required ports:
* `devel/cmake`
* `devel/boost-libs`
* `lang/gcc47`(or later version)
To use newer compiler you should set these variables(replace "47" with your actual gcc version):
export CC=/usr/local/bin/gcc47
export CXX=/usr/local/bin/g++47

@ -3,7 +3,7 @@ Building on Windows
There are two approaches available to build i2pd on Windows. The best
one depends on your needs and personal preferences. One is to use
msys2 and [unix alike infrastructure](build_notes_unix.md). Another
msys2 and [unix alike infrastructure](unix.md). Another
one is to use Visual Studio. While there might be no difference for
end users of i2pd daemon, developers, however, shall be wary of
differences in C++ name mangling between the two compilers when making
@ -20,86 +20,58 @@ development location for the sake of convenience. Adjust paths
accordingly if it is not the case. Note that msys uses unix-alike
paths like /c/dev/ for C:\dev\.
msys2
-----
### x86 (32-bit architecture)
Get install file msys2-i686-*.exe from https://msys2.github.io.
open MSYS2 Shell (from Start menu).
Install all prerequisites and download i2pd source:
```bash
pacman -S mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc git make
mkdir -p /c/dev/i2pd
cd /c/dev/i2pd
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd
export PATH=/mingw32/bin:/usr/bin # we need compiler on PATH which is usually heavily cluttered on Windows
make
```
Get install file `msys2-$ARCH-*.exe` from `https://msys2.github.io`
Where $ARCH is `i686` or `x86_64` (matching your system).
### x64 (64-bit architecture)
Get install file msys2-x86_64-*.exe from https://msys2.github.io.
open MSYS2 Shell (from Start menu).
Install all prerequisites and download i2pd source:
```bash
pacman -S mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-gcc git make
mkdir -p /c/dev/i2pd
cd /c/dev/i2pd
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd
export PATH=/mingw64/bin:/usr/bin # we need compiler on PATH which is usually heavily cluttered on Windows
make
```
- Open MSYS2 Shell (from Start menu).
- Install all prerequisites and download i2pd source:
export ARCH='i686' # or 'x86_64'
export MINGW='mingw32' # or 'mingw64'
pacman -S mingw-w64-$ARCH-boost mingw-w64-$ARCH-openssl mingw-w64-$ARCH-gcc git make
mkdir -p /c/dev/i2pd
cd /c/dev/i2pd
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd
# we need compiler on PATH which is usually heavily cluttered on Windows
export PATH=/$MINGW/bin:/usr/bin
make
### Caveats
It is important to restrict PATH as described above. If you have
Strawberry Perl and/or Mercurial installed, it will pick up gcc &
openssl from the wrong places.
If you do use precompiled headers to speed up compilation
(recommended), things can go wrong if compiler options have changed
for whatever reason. Just delete `stdafx.h.gch` found in your build
folder, note the file extension.
It is important to restrict PATH as described above.
If you have Strawberry Perl and/or Mercurial installed,
it will pick up gcc & openssl from the wrong places.
If you are an Arch Linux user, refrain from updating system with
`pacman -Syu`. Always update runtime separately as described on the
home page, otherwise you might end up with DLLs incompatibility
problems.
If you do use precompiled headers to speed up compilation (recommended),
things can go wrong if compiler options have changed for whatever reason.
Just delete `stdafx.h.gch` found in your build folder, note the file extension.
If you are an Arch Linux user, refrain from updating system with `pacman -Syu`.
Always update runtime separately as described on the home page,
otherwise you might end up with DLLs incompatibility problems.
### AES-NI
If your processor has
[AES instruction set](https://en.wikipedia.org/wiki/AES_instruction_set),
you use `make USE_AESNI=1`. No check is done however, it
will compile, but it might crash with `Illegal instruction` if not supported.
If your processor has [AES instruction set](https://en.wikipedia.org/wiki/AES_instruction_set),
use `make USE_AESNI=1` instead just `make`. No check is done however, it will compile,
but it might crash with `Illegal instruction` if this feature is not supported by your processor.
You should be able to run ./i2pd . If you need to start from the new
shell, consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell* as
it adds`/minw32/bin` to the PATH.
You should be able to run ./i2pd . If you need to start from the new shell,
consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell*
as it adds `/minw32/bin` to the PATH.
### UPnP
You can install it through the MSYS2
and build with USE_UPNP key.
```bash
pacman -S mingw-w64-i686-miniupnpc
make USE_UPNP=yes
```
or
```bash
pacman -S mingw-w64-x86_64-miniupnpc
make USE_UPNP=yes
```
You can install it through the MSYS2 and build with `USE_UPNP` key.
export ARCH='i686' # or 'x86_64'
pacman -S mingw-w64-$ARCH-miniupnpc
make USE_UPNP=yes
Using Visual Studio
-------------------
@ -114,7 +86,6 @@ Requirements for building:
* [Netwide assembler](http://www.nasm.us/)
* Strawberry Perl or ActiveState Perl, do NOT try msys2 perl, it won't work
### Building Boost
Open a Command Prompt (there is no need to start Visual Studio command
@ -131,11 +102,9 @@ If you are on 64-bit Windows and you want to build 64-bit version as well
After Boost is compiled, set the environment variable `BOOST_ROOT` to
the directory Boost was unpacked to, e.g., C:\dev\boost.
If you are planning on building only particular variant, e.g. Debug
only and static linking, and/or you are out of space/time, you might
consider `--build-type=minimal`. Take a look at
[appveyor.yml](../appveyor.yml) for details on how test builds are done.
If you are planning on building only particular variant, e.g. Debug only and static linking,
and/or you are out of space/time, you might consider `--build-type=minimal`.
Take a look at [appveyor.yml](../appveyor.yml) for details on how test builds are done.
### Building OpenSSL
@ -155,23 +124,19 @@ Now open Visual Studio command prompt and change directory to that with OpenSSL
You should have it installed into C:\OpenSSL-Win32 by now.
Note that you might consider providing `-DOPENSSL_ROOT_DIR` to CMake
and/or create a symlink (with mklink /J) to C:\OpenSSL if you plan on
maintaining multiple versions, e.g. 64 bit and/or
static/shared. Consult `C:\Program Files
(x86)\CMake\share\cmake-3.3\Modules\FindOpenSSL.cmake` for details.
Note that you might consider providing `-DOPENSSL_ROOT_DIR` to CMake and/or
create a symlink (with mklink /J) to C:\OpenSSL if you plan on maintain
multiple versions, e.g. 64 bit and/or static/shared.
See `C:\Program Files (x86)\CMake\share\cmake-3.3\Modules\FindOpenSSL.cmake` for details.
### Get miniupnpc
If you are behind a UPnP enabled router and don't feel like manually
configuring port forwarding, you should consider using
[MiniUPnP](http://miniupnp.free.fr) client. I2pd can be built capable
of using miniupnpc shared library (DLL) to open up necessary
port. You'd want to have include headers around to build i2pd with
support for this. Unpack client source code in a sibling folder,
e.g. C:\dev\miniupnpc . You may want to remove version number from
folder name included in downloaded archive.
If you are behind a UPnP enabled router and don't feel like manually configuring port forwarding,
you should consider using [MiniUPnP](http://miniupnp.free.fr) client.
I2pd can be built capable of using miniupnpc shared library (DLL) to open up necessary port.
You'd want to have include headers around to build i2pd with support for this.
Unpack client source code to subdir, e.g. `C:\dev\miniupnpc`.
You may want to remove version number from folder name included in downloaded archive.
### Creating Visual Studio project
@ -179,19 +144,16 @@ Start CMake GUI, navigate to i2pd directory, choose building directory, e.g. ./
Alternatively, if you feel adventurous, try that from the command line
```
cd <i2pd_dir>
mkdir out
cd out
cmake ..\build -G "Visual Studio 12 2013" -DWITH_UPNP=ON -DWITH_PCH=ON -DCMAKE_INSTALL_PREFIX:PATH=C:\dev\Debug_Win32_stage
```
WITH_UPNP will stay off, if necessary files are not found.
mkdir i2pd\out
cd i2pd\out
cmake ..\build -G "Visual Studio 12 2013" -DWITH_UPNP=ON -DWITH_PCH=ON -DCMAKE_INSTALL_PREFIX:PATH=C:\dev\Debug_Win32_stage
If necessary files are not found `WITH_UPNP` will stay off.
### Building i2pd
You can open generated solution/project with Visual Studio and build
from there, alternatively you can use `cmake --build . --config Release --target install` or
You can open generated solution/project with Visual Studio and build from there,
alternatively you can use `cmake --build . --config Release --target install` or
[MSBuild tool](https://msdn.microsoft.com/en-us/library/dd293626.aspx)
`msbuild i2pd.sln /p:Configuration=Release`.
msbuild i2pd.sln /p:Configuration=Release

@ -41,17 +41,25 @@ All options below still possible in cmdline, but better write it in config file:
* --http.user= - Username for basic auth (default: i2pd)
* --http.pass= - Password for basic auth (default: random, see logs)
* --httpproxy.address= - The address to listen on (HTTP Proxy)
* --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default
* --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --httpproxy.enabled= - If HTTP proxy is enabled. true by default
* --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.enabled= - If SOCKS proxy is enabled. true by default
* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there
* --socksproxy.outproxyport= - Outproxy remote port
* --httpproxy.enabled= - If HTTP proxy is enabled. true by default
* --httpproxy.address= - The address to listen on (HTTP Proxy)
* --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default
* --httpproxy.keys= - optional keys file for HTTP proxy local destination
* --httpproxy.inbound.length= - Inbound tunnels length if keys is set. 3 by default
* --httpproxy.inbound.quantity= - Inbound tunnels quantity if keys is set. 5 by default
* --httpproxy.outbound.length= - Outbound tunnels length if keys is set. 3 by default
* --httpproxy.outbound.quantity= - Outbound tunnels quantity if keys is set. 5 by default
* --socksproxy.enabled= - If SOCKS proxy is enabled. true by default
* --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 SOCKS proxy local destination
* --socksproxy.inbound.length= - Inbound tunnels length if keys is set. 3 by default
* --socksproxy.inbound.quantity= - Inbound tunnels quantity if keys is set. 5 by default
* --socksproxy.outbound.length= - Outbound tunnels length if keys is set. 3 by default
* --socksproxy.outbound.quantity= - Outbound tunnels quantity if keys is set. 5 by default
* --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
@ -80,6 +88,8 @@ All options below still possible in cmdline, but better write it in config file:
* --addressbook.subscriptions= - AddressBook subscriptions URLs, separated by comma
* --limits.transittunnels= - Override maximum number of transit tunnels. 2500 by default
* --limits.openfiles= - Maximum size of corefile in Kb (0 - use system limit)
* --limits.coresize= - Maximum size of corefile in Kb (0 - use system limit)
Config files
------------

@ -29,14 +29,13 @@ Contents:
.. toctree::
:maxdepth: 2
build_requirements
build_notes_unix
build_notes_windows
build_notes_cross
build_notes_android
build_notes_ios
building/requirements
building/unix
building/windows
building/cross
building/android
building/ios
configuration
family
usage

@ -5,7 +5,7 @@ LIB_SRC = \
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp
Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp
LIB_CLIENT_SRC = \
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \

@ -36,7 +36,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \
../../i2pd.cpp
../../Event.cpp ../../i2pd.cpp
HEADERS += DaemonQT.h mainwindow.h \
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
@ -50,7 +50,7 @@ HEADERS += DaemonQT.h mainwindow.h \
../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \
../../util.h ../../version.h ../../Gzip.h ../../Tag.h
../../util.h ../../version.h ../../Gzip.h ../../Tag.h ../../Event.h
FORMS += mainwindow.ui

@ -5,9 +5,9 @@
#include <string>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#ifdef ANDROID
#include <boost/lexical_cast.hpp>
namespace std
{
template <typename T>
@ -15,6 +15,11 @@ std::string to_string(T value)
{
return boost::lexical_cast<std::string>(value);
}
inline int stoi(const std::string& str)
{
return boost::lexical_cast<int>(str);
}
}
#endif
@ -22,18 +27,6 @@ namespace i2p
{
namespace util
{
/**
wrapper arround boost::lexical_cast that "never" fails
*/
template <typename T>
T lexical_cast(const std::string & str, const T fallback) {
try {
return boost::lexical_cast<T>(str);
} catch ( ... ) {
return fallback;
}
}
namespace net
{
int GetMTU (const boost::asio::ip::address& localAddress);

Loading…
Cancel
Save