Merge branch 'openssl' of github.com:PurpleI2P/i2pd into OSX_Native_App

This commit is contained in:
Mikal Villa 2016-04-26 19:47:33 +02:00
commit cca6f97e7b
42 changed files with 649 additions and 313 deletions

View file

@ -343,10 +343,11 @@ namespace client
} }
} }
void AddressBook::LoadHostsFromStream (std::istream& f) bool AddressBook::LoadHostsFromStream (std::istream& f)
{ {
std::unique_lock<std::mutex> l(m_AddressBookMutex); std::unique_lock<std::mutex> l(m_AddressBookMutex);
int numAddresses = 0; int numAddresses = 0;
bool incomplete = false;
std::string s; std::string s;
while (!f.eof ()) while (!f.eof ())
{ {
@ -370,15 +371,21 @@ namespace client
numAddresses++; numAddresses++;
} }
else else
{
LogPrint (eLogError, "Addressbook: malformed address ", addr, " for ", name); LogPrint (eLogError, "Addressbook: malformed address ", addr, " for ", name);
incomplete = f.eof ();
} }
} }
else
incomplete = f.eof ();
}
LogPrint (eLogInfo, "Addressbook: ", numAddresses, " addresses processed"); LogPrint (eLogInfo, "Addressbook: ", numAddresses, " addresses processed");
if (numAddresses > 0) if (numAddresses > 0)
{ {
m_IsLoaded = true; if (!incomplete) m_IsLoaded = true;
m_Storage->Save (m_Addresses); m_Storage->Save (m_Addresses);
} }
return !incomplete;
} }
void AddressBook::LoadSubscriptions () void AddressBook::LoadSubscriptions ()
@ -776,13 +783,12 @@ namespace client
i2p::data::GzipInflator inflator; i2p::data::GzipInflator inflator;
inflator.Inflate (s, uncompressed); inflator.Inflate (s, uncompressed);
if (!uncompressed.fail ()) if (!uncompressed.fail ())
m_Book.LoadHostsFromStream (uncompressed); return m_Book.LoadHostsFromStream (uncompressed);
else else
return false; return false;
} }
else else
m_Book.LoadHostsFromStream (s); return m_Book.LoadHostsFromStream (s);
return true;
} }
AddressResolver::AddressResolver (std::shared_ptr<ClientDestination> destination): AddressResolver::AddressResolver (std::shared_ptr<ClientDestination> destination):

View file

@ -66,7 +66,7 @@ namespace client
void InsertAddress (const std::string& address, const std::string& base64); // for jump service void InsertAddress (const std::string& address, const std::string& base64); // for jump service
void InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address); void InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
void LoadHostsFromStream (std::istream& f); bool LoadHostsFromStream (std::istream& f);
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified); void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
//This method returns the ".b32.i2p" address //This method returns the ".b32.i2p" address
std::string ToAddress(const i2p::data::IdentHash& ident) { return GetB32Address(ident); } std::string ToAddress(const i2p::data::IdentHash& ident) { return GetB32Address(ident); }

View file

@ -52,8 +52,12 @@ namespace client
LoadPrivateKeys (keys, httpProxyKeys); LoadPrivateKeys (keys, httpProxyKeys);
localDestination = CreateNewLocalDestination (keys, false); localDestination = CreateNewLocalDestination (keys, false);
} }
try {
m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination);
m_HttpProxy->Start(); m_HttpProxy->Start();
} catch (std::exception& e) {
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
}
} }
bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy); bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy);
@ -70,8 +74,12 @@ namespace client
LoadPrivateKeys (keys, socksProxyKeys); LoadPrivateKeys (keys, socksProxyKeys);
localDestination = CreateNewLocalDestination (keys, false); localDestination = CreateNewLocalDestination (keys, false);
} }
try {
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination);
m_SocksProxy->Start(); m_SocksProxy->Start();
} catch (std::exception& e) {
LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what());
}
} }
// I2P tunnels // I2P tunnels
@ -83,8 +91,12 @@ namespace client
std::string samAddr; i2p::config::GetOption("sam.address", samAddr); std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
uint16_t samPort; i2p::config::GetOption("sam.port", samPort); uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort); LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
try {
m_SamBridge = new SAMBridge (samAddr, samPort); m_SamBridge = new SAMBridge (samAddr, samPort);
m_SamBridge->Start (); m_SamBridge->Start ();
} catch (std::exception& e) {
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
}
} }
// BOB // BOB
@ -93,8 +105,12 @@ namespace client
std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr); std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr);
uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort); uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort);
LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort); LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort);
try {
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
m_BOBCommandChannel->Start (); m_BOBCommandChannel->Start ();
} catch (std::exception& e) {
LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what());
}
} }
m_AddressBook.StartResolvers (); m_AddressBook.StartResolvers ();
@ -312,7 +328,8 @@ namespace client
localDestination = CreateNewLocalDestination (k, false, &options); localDestination = CreateNewLocalDestination (k, false, &options);
} }
auto clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); auto clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort);
if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr<I2PClientTunnel>(clientTunnel))).second) if (m_ClientTunnels.insert (std::make_pair (clientTunnel->GetAcceptor ().local_endpoint (),
std::unique_ptr<I2PClientTunnel>(clientTunnel))).second)
clientTunnel->Start (); clientTunnel->Start ();
else else
LogPrint (eLogError, "Clients: I2P client tunnel with port ", port, " already exists"); LogPrint (eLogError, "Clients: I2P client tunnel with port ", port, " already exists");
@ -366,7 +383,7 @@ namespace client
serverTunnel->SetAccessList (idents); serverTunnel->SetAccessList (idents);
} }
if (m_ServerTunnels.insert (std::make_pair ( if (m_ServerTunnels.insert (std::make_pair (
std::make_tuple (localDestination->GetIdentHash (), inPort), std::make_pair (localDestination->GetIdentHash (), inPort),
std::unique_ptr<I2PServerTunnel>(serverTunnel))).second) std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
serverTunnel->Start (); serverTunnel->Start ();
else else

View file

@ -2,9 +2,9 @@
#define CLIENT_CONTEXT_H__ #define CLIENT_CONTEXT_H__
#include <map> #include <map>
#include <tuple>
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <boost/asio.hpp>
#include "Destination.h" #include "Destination.h"
#include "HTTPProxy.h" #include "HTTPProxy.h"
#include "SOCKS.h" #include "SOCKS.h"
@ -78,8 +78,8 @@ namespace client
i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::HTTPProxy * m_HttpProxy;
i2p::proxy::SOCKSProxy * m_SocksProxy; i2p::proxy::SOCKSProxy * m_SocksProxy;
std::map<int, std::unique_ptr<I2PClientTunnel> > m_ClientTunnels; // port->tunnel std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PClientTunnel> > m_ClientTunnels; // local endpoint->tunnel
std::map<std::tuple<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
SAMBridge * m_SamBridge; SAMBridge * m_SamBridge;
BOBCommandChannel * m_BOBCommandChannel; BOBCommandChannel * m_BOBCommandChannel;

View file

@ -123,14 +123,19 @@ namespace config {
("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") ("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'")
("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup") ("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") ("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill")
("bandwidth", value<char>()->default_value('-'), "Bandwidth limiting: L - 32kbps, O - 256Kbps, P - unlimited") ("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in kbps or letters: L (32), O (256), P (2048), X (>9000)")
#ifdef _WIN32 #ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')") ("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping") ("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping")
("close", value<std::string>()->default_value("ask"), "On close action") // minimize, exit, ask TODO: add custom validator or something ("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something
#endif #endif
; ;
options_description limits("Limits options");
limits.add_options()
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
;
options_description httpserver("HTTP Server options"); options_description httpserver("HTTP Server options");
httpserver.add_options() httpserver.add_options()
("http.enabled", value<bool>()->default_value(true), "Enable or disable webconsole") ("http.enabled", value<bool>()->default_value(true), "Enable or disable webconsole")
@ -180,14 +185,27 @@ namespace config {
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key") ("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key")
; ;
options_description precomputation("Precomputation options");
precomputation.add_options()
("precomputation.elgamal",
#if defined(__x86_64__)
value<bool>()->default_value(false),
#else
value<bool>()->default_value(true),
#endif
"Enable or disable elgamal precomputation table")
;
m_OptionsDesc m_OptionsDesc
.add(general) .add(general)
.add(limits)
.add(httpserver) .add(httpserver)
.add(httpproxy) .add(httpproxy)
.add(socksproxy) .add(socksproxy)
.add(sam) .add(sam)
.add(bob) .add(bob)
.add(i2pcontrol) .add(i2pcontrol)
.add(precomputation)
; ;
} }

View file

@ -146,9 +146,87 @@ namespace crypto
} }
// DH/ElGamal // DH/ElGamal
const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226;
const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1;
const int ELGAMAL_FULL_EXPONENT_NUM_BITS = 2048;
const int ELGAMAL_FULL_EXPONENT_NUM_BYTES = ELGAMAL_FULL_EXPONENT_NUM_BITS/8;
#define elgp GetCryptoConstants ().elgp #define elgp GetCryptoConstants ().elgp
#define elgg GetCryptoConstants ().elgg #define elgg GetCryptoConstants ().elgg
static BN_MONT_CTX * g_MontCtx = nullptr;
static void PrecalculateElggTable (BIGNUM * table[][255], int len) // table is len's array of array of 255 bignums
{
if (len <= 0) return;
BN_CTX * ctx = BN_CTX_new ();
g_MontCtx = BN_MONT_CTX_new ();
BN_MONT_CTX_set (g_MontCtx, elgp, ctx);
auto montCtx = BN_MONT_CTX_new ();
BN_MONT_CTX_copy (montCtx, g_MontCtx);
for (int i = 0; i < len; i++)
{
table[i][0] = BN_new ();
if (!i)
BN_to_montgomery (table[0][0], elgg, montCtx, ctx);
else
BN_mod_mul_montgomery (table[i][0], table[i-1][254], table[i-1][0], montCtx, ctx);
for (int j = 1; j < 255; j++)
{
table[i][j] = BN_new ();
BN_mod_mul_montgomery (table[i][j], table[i][j-1], table[i][0], montCtx, ctx);
}
}
BN_MONT_CTX_free (montCtx);
BN_CTX_free (ctx);
}
static void DestroyElggTable (BIGNUM * table[][255], int len)
{
for (int i = 0; i < len; i++)
for (int j = 0; j < 255; j++)
{
BN_free (table[i][j]);
table[i][j] = nullptr;
}
BN_MONT_CTX_free (g_MontCtx);
}
static BIGNUM * ElggPow (const uint8_t * exp, int len, BIGNUM * table[][255], BN_CTX * ctx)
// exp is in Big Endian
{
if (len <= 0) return nullptr;
auto montCtx = BN_MONT_CTX_new ();
BN_MONT_CTX_copy (montCtx, g_MontCtx);
BIGNUM * res = nullptr;
for (int i = 0; i < len; i++)
{
if (res)
{
if (exp[i])
BN_mod_mul_montgomery (res, res, table[len-1-i][exp[i]-1], montCtx, ctx);
}
else if (exp[i])
res = BN_dup (table[len-i-1][exp[i]-1]);
}
if (res)
BN_from_montgomery (res, res, montCtx, ctx);
BN_MONT_CTX_free (montCtx);
return res;
}
static BIGNUM * ElggPow (const BIGNUM * exp, BIGNUM * table[][255], BN_CTX * ctx)
{
auto len = BN_num_bytes (exp);
uint8_t * buf = new uint8_t[len];
BN_bn2bin (exp, buf);
auto ret = ElggPow (buf, len, table, ctx);
delete[] buf;
return ret;
}
static BIGNUM * (* g_ElggTable)[255] = nullptr;
// DH // DH
DHKeys::DHKeys (): m_IsUpdated (true) DHKeys::DHKeys (): m_IsUpdated (true)
@ -169,7 +247,23 @@ namespace crypto
{ {
if (m_DH->priv_key) { BN_free (m_DH->priv_key); m_DH->priv_key = NULL; }; if (m_DH->priv_key) { BN_free (m_DH->priv_key); m_DH->priv_key = NULL; };
if (m_DH->pub_key) { BN_free (m_DH->pub_key); m_DH->pub_key = NULL; }; if (m_DH->pub_key) { BN_free (m_DH->pub_key); m_DH->pub_key = NULL; };
#if !defined(__x86_64__) // use short exponent for non x64
m_DH->priv_key = BN_new ();
BN_rand (m_DH->priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
#endif
if (g_ElggTable)
{
#if defined(__x86_64__)
m_DH->priv_key = BN_new ();
BN_rand (m_DH->priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1);
#endif
auto ctx = BN_CTX_new ();
m_DH->pub_key = ElggPow (m_DH->priv_key, g_ElggTable, ctx);
BN_CTX_free (ctx);
}
else
DH_generate_key (m_DH); DH_generate_key (m_DH);
if (priv) bn2buf (m_DH->priv_key, priv, 256); if (priv) bn2buf (m_DH->priv_key, priv, 256);
if (pub) bn2buf (m_DH->pub_key, pub, 256); if (pub) bn2buf (m_DH->pub_key, pub, 256);
m_IsUpdated = true; m_IsUpdated = true;
@ -200,11 +294,18 @@ namespace crypto
ctx = BN_CTX_new (); ctx = BN_CTX_new ();
// select random k // select random k
BIGNUM * k = BN_new (); BIGNUM * k = BN_new ();
BN_rand_range (k, elgp); #if defined(__x86_64__)
if (BN_is_zero (k)) BN_one (k); BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64
// caulculate a #else
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
#endif
// calculate a
a = BN_new (); a = BN_new ();
if (g_ElggTable)
a = ElggPow (k, g_ElggTable, ctx);
else
BN_mod_exp (a, elgg, k, elgp, ctx); BN_mod_exp (a, elgg, k, elgp, ctx);
BIGNUM * y = BN_new (); BIGNUM * y = BN_new ();
BN_bin2bn (key, 256, y); BN_bin2bn (key, 256, y);
// calculate b1 // calculate b1
@ -279,6 +380,14 @@ namespace crypto
{ {
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) #if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
RAND_bytes (priv, 256); RAND_bytes (priv, 256);
#else
// lower 226 bits (28 bytes and 2 bits) only. short exponent
auto numBytes = (ELGAMAL_SHORT_EXPONENT_NUM_BITS)/8 + 1; // 29
auto numZeroBytes = 256 - numBytes;
RAND_bytes (priv + numZeroBytes, numBytes);
memset (priv, 0, numZeroBytes);
priv[numZeroBytes] &= 0x03;
#endif
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BIGNUM * p = BN_new (); BIGNUM * p = BN_new ();
BN_bin2bn (priv, 256, p); BN_bin2bn (priv, 256, p);
@ -286,11 +395,6 @@ namespace crypto
bn2buf (p, pub, 256); bn2buf (p, pub, 256);
BN_free (p); BN_free (p);
BN_CTX_free (ctx); BN_CTX_free (ctx);
#else
DHKeys dh;
dh.GenerateKeys (priv, pub);
#endif
} }
// HMAC // HMAC
@ -695,17 +799,38 @@ namespace crypto
} }
}*/ }*/
void InitCrypto () void InitCrypto (bool precomputation)
{ {
SSL_library_init (); SSL_library_init ();
/* auto numLocks = CRYPTO_num_locks(); /* auto numLocks = CRYPTO_num_locks();
for (int i = 0; i < numLocks; i++) for (int i = 0; i < numLocks; i++)
m_OpenSSLMutexes.emplace_back (new std::mutex); m_OpenSSLMutexes.emplace_back (new std::mutex);
CRYPTO_set_locking_callback (OpensslLockingCallback);*/ CRYPTO_set_locking_callback (OpensslLockingCallback);*/
if (precomputation)
{
#if defined(__x86_64__)
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
#else
g_ElggTable = new BIGNUM * [ELGAMAL_SHORT_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_SHORT_EXPONENT_NUM_BYTES);
#endif
}
} }
void TerminateCrypto () void TerminateCrypto ()
{ {
if (g_ElggTable)
{
DestroyElggTable (g_ElggTable,
#if defined(__x86_64__)
ELGAMAL_FULL_EXPONENT_NUM_BYTES
#else
ELGAMAL_SHORT_EXPONENT_NUM_BYTES
#endif
);
delete[] g_ElggTable; g_ElggTable = nullptr;
}
/* CRYPTO_set_locking_callback (nullptr); /* CRYPTO_set_locking_callback (nullptr);
m_OpenSSLMutexes.clear ();*/ m_OpenSSLMutexes.clear ();*/
} }

View file

@ -273,7 +273,7 @@ namespace crypto
#endif #endif
}; };
void InitCrypto (); void InitCrypto (bool precomputation);
void TerminateCrypto (); void TerminateCrypto ();
} }
} }

View file

@ -117,7 +117,8 @@ namespace i2p
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir); LogPrint(eLogDebug, "FS: data directory: ", datadir);
i2p::crypto::InitCrypto (); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
i2p::crypto::InitCrypto (precomputation);
i2p::context.Init (); i2p::context.Init ();
uint16_t port; i2p::config::GetOption("port", port); uint16_t port; i2p::config::GetOption("port", port);
@ -140,36 +141,50 @@ namespace i2p
i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV6 (ipv6);
i2p::context.SetSupportsV4 (ipv4); i2p::context.SetSupportsV4 (ipv4);
i2p::context.SetAcceptsTunnels (!transit); i2p::context.SetAcceptsTunnels (!transit);
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
SetMaxNumTransitTunnels (transitTunnels);
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
char bandwidth; i2p::config::GetOption("bandwidth", bandwidth); if (isFloodfill) {
if (isFloodfill)
{
LogPrint(eLogInfo, "Daemon: router will be floodfill"); LogPrint(eLogInfo, "Daemon: router will be floodfill");
i2p::context.SetFloodfill (true); i2p::context.SetFloodfill (true);
} else {
i2p::context.SetFloodfill (false);
}
/* this section also honors 'floodfill' flag, if set above */
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
if (bandwidth.length () > 0)
{
if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
{
i2p::context.SetBandwidth (bandwidth[0]);
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
} }
else else
i2p::context.SetFloodfill (false);
if (bandwidth != '-')
{ {
LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth); auto value = std::atoi(bandwidth.c_str());
if (bandwidth > 'O') if (value > 0)
i2p::context.SetExtraBandwidth (); {
else if (bandwidth > 'L') i2p::context.SetBandwidth (value);
i2p::context.SetHighBandwidth (); LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps");
}
else else
i2p::context.SetLowBandwidth (); {
LogPrint(eLogInfo, "Daemon: unexpected bandwidth ", bandwidth, ". Set to 'low'");
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2);
}
}
} }
else if (isFloodfill) else if (isFloodfill)
{ {
LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'"); LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
i2p::context.SetExtraBandwidth (); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1);
} }
else else
{ {
LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'"); LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'");
i2p::context.SetLowBandwidth (); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2);
} }
std::string family; i2p::config::GetOption("family", family); std::string family; i2p::config::GetOption("family", family);

View file

@ -65,12 +65,17 @@ namespace i2p
bool start(); bool start();
bool stop(); bool stop();
; void run (); void run ();
private: private:
std::string pidfile; std::string pidfile;
int pidFH; int pidFH;
public:
int gracefullShutdownInterval; // in seconds
}; };
#endif #endif
} }

View file

@ -12,6 +12,7 @@
#include "Config.h" #include "Config.h"
#include "FS.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "RouterContext.h"
void handle_signal(int sig) void handle_signal(int sig)
{ {
@ -21,9 +22,18 @@ void handle_signal(int sig)
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log..."); LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log...");
i2p::log::Logger().Reopen (); i2p::log::Logger().Reopen ();
break; break;
case SIGINT:
if (i2p::context.AcceptsTunnels () && !Daemon.gracefullShutdownInterval)
{
i2p::context.SetAcceptsTunnels (false);
Daemon.gracefullShutdownInterval = 10*60; // 10 minutes
LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefullShutdownInterval, " seconds");
}
else
Daemon.running = 0;
break;
case SIGABRT: case SIGABRT:
case SIGTERM: case SIGTERM:
case SIGINT:
Daemon.running = 0; // Exit loop Daemon.running = 0; // Exit loop
break; break;
} }
@ -96,6 +106,7 @@ namespace i2p
return false; return false;
} }
} }
gracefullShutdownInterval = 0; // not specified
// Signal handler // Signal handler
struct sigaction sa; struct sigaction sa;
@ -122,6 +133,15 @@ namespace i2p
while (running) while (running)
{ {
std::this_thread::sleep_for (std::chrono::seconds(1)); std::this_thread::sleep_for (std::chrono::seconds(1));
if (gracefullShutdownInterval)
{
gracefullShutdownInterval--; // - 1 second
if (gracefullShutdownInterval <= 0)
{
LogPrint(eLogInfo, "Graceful shutdown");
return;
}
}
} }
} }
} }

View file

@ -780,5 +780,19 @@ namespace client
} }
LogPrint(eLogError, "Destinations: Can't save keys to ", path); LogPrint(eLogError, "Destinations: Can't save keys to ", path);
} }
std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const
{
std::vector<std::shared_ptr<const i2p::stream::Stream> > ret;
if (m_StreamingDestination)
{
for (auto& it: m_StreamingDestination->GetStreams ())
ret.push_back (it.second);
}
for (auto& it: m_StreamingDestinationsByPorts)
for (auto& it1: it.second->GetStreams ())
ret.push_back (it1.second);
return ret;
}
} }
} }

View file

@ -159,6 +159,7 @@ namespace client
// for HTTP only // for HTTP only
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
}; };
} }
} }

View file

@ -1,7 +1,6 @@
#include <ctime> #include <ctime>
#include <iomanip> #include <iomanip>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include "Base.h" #include "Base.h"
#include "FS.h" #include "FS.h"
@ -24,7 +23,6 @@ namespace i2p
{ {
namespace util namespace util
{ {
const std::string HTTPConnection::itoopieImage = const std::string HTTPConnection::itoopieImage =
"<img alt=\"ICToopie Icon\" src=\"data:image/png;base64," "<img alt=\"ICToopie Icon\" src=\"data:image/png;base64,"
"iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXM" "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXM"
@ -206,7 +204,6 @@ namespace util
const char HTTP_COMMAND_JUMPSERVICES[] = "jumpservices="; const char HTTP_COMMAND_JUMPSERVICES[] = "jumpservices=";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
namespace misc_strings namespace misc_strings
{ {
@ -609,19 +606,19 @@ namespace util
s << "<th>Status</th>"; s << "<th>Status</th>";
s << "</tr>"; s << "</tr>";
for (auto it: dest->GetStreamingDestination ()->GetStreams ()) for (auto it: dest->GetAllStreams ())
{ {
s << "<tr>"; s << "<tr>";
s << "<td>" << it.first << "</td>"; s << "<td>" << it->GetSendStreamID () << "</td>";
s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << "</td>"; s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "</td>";
s << "<td>" << it.second->GetNumSentBytes () << "</td>"; s << "<td>" << it->GetNumSentBytes () << "</td>";
s << "<td>" << it.second->GetNumReceivedBytes () << "</td>"; s << "<td>" << it->GetNumReceivedBytes () << "</td>";
s << "<td>" << it.second->GetSendQueueSize () << "</td>"; s << "<td>" << it->GetSendQueueSize () << "</td>";
s << "<td>" << it.second->GetReceiveQueueSize () << "</td>"; s << "<td>" << it->GetReceiveQueueSize () << "</td>";
s << "<td>" << it.second->GetSendBufferSize () << "</td>"; s << "<td>" << it->GetSendBufferSize () << "</td>";
s << "<td>" << it.second->GetRTT () << "</td>"; s << "<td>" << it->GetRTT () << "</td>";
s << "<td>" << it.second->GetWindowSize () << "</td>"; s << "<td>" << it->GetWindowSize () << "</td>";
s << "<td>" << (int)it.second->GetStatus () << "</td>"; s << "<td>" << (int)it->GetStatus () << "</td>";
s << "</tr><br>\r\n" << std::endl; s << "</tr><br>\r\n" << std::endl;
} }
} }
@ -749,7 +746,7 @@ namespace util
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">"; s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
s << "<b>Streams:</b><br>\r\n"; s << "<b>Streams:</b><br>\r\n";
for (auto it: session->sockets) for (auto it: session->ListSockets())
{ {
switch (it->GetSocketType ()) switch (it->GetSocketType ())
{ {
@ -777,20 +774,20 @@ namespace util
s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n"; s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetClientTunnels ()) for (auto& it: i2p::client::context.GetClientTunnels ())
{ {
s << it.second->GetName () << "";
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION; s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">"; s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
s << it.second->GetName () << "</a> ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</a><br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
} }
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n"; s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetServerTunnels ()) for (auto& it: i2p::client::context.GetServerTunnels ())
{ {
s << it.second->GetName () << "";
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION; s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">"; s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
s << it.second->GetName () << "</a> ⇒ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort (); s << ":" << it.second->GetLocalPort ();
s << "</a><br>\r\n"<< std::endl; s << "</a><br>\r\n"<< std::endl;
@ -831,7 +828,7 @@ namespace util
if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination)) if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
{ {
LogPrint (eLogWarning, "HTTPServer: Unknown address ", address); LogPrint (eLogWarning, "HTTPServer: Unknown address ", address);
SendReply ("<html>" + itoopieImage + "<br>\r\nUnknown address " + address + "</html>", 404); SendError ("Unknown address " + address);
return; return;
} }
@ -855,11 +852,13 @@ namespace util
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
if (leaseSet && !leaseSet->IsExpired ()) if (leaseSet && !leaseSet->IsExpired ()) {
SendToDestination (leaseSet, port, buf, len); SendToDestination (leaseSet, port, buf, len);
else } else if (leaseSet) {
// still no LeaseSet SendError ("LeaseSet expired");
SendReply (leaseSet ? "<html>" + itoopieImage + "<br>\r\nLeases expired</html>" : "<html>" + itoopieImage + "LeaseSet not found</html>", 504); } else {
SendError ("LeaseSet not found");
}
} }
} }
@ -893,7 +892,7 @@ namespace util
else else
{ {
if (ecode == boost::asio::error::timed_out) if (ecode == boost::asio::error::timed_out)
SendReply ("<html>" + itoopieImage + "<br>\r\nNot responding</html>", 504); SendError ("Host not responding");
else if (ecode != boost::asio::error::operation_aborted) else if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
@ -911,7 +910,7 @@ namespace util
m_Reply.headers[0].name = "Date"; m_Reply.headers[0].name = "Date";
m_Reply.headers[0].value = std::string(time_buff); m_Reply.headers[0].value = std::string(time_buff);
m_Reply.headers[1].name = "Content-Length"; m_Reply.headers[1].name = "Content-Length";
m_Reply.headers[1].value = boost::lexical_cast<std::string>(m_Reply.content.size()); m_Reply.headers[1].value = std::to_string(m_Reply.content.size());
m_Reply.headers[2].name = "Content-Type"; m_Reply.headers[2].name = "Content-Type";
m_Reply.headers[2].value = "text/html"; m_Reply.headers[2].value = "text/html";
} }
@ -920,6 +919,11 @@ namespace util
std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1)); std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1));
} }
void HTTPConnection::SendError(const std::string& content)
{
SendReply ("<html>" + itoopieImage + "<br>\r\n" + content + "</html>", 504);
}
HTTPServer::HTTPServer (const std::string& address, int port): HTTPServer::HTTPServer (const std::string& address, int port):
m_Thread (nullptr), m_Work (m_Service), m_Thread (nullptr), m_Work (m_Service),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)) m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port))
@ -978,6 +982,3 @@ namespace util
} }
} }
} }

View file

@ -59,6 +59,7 @@ namespace util
void HandleWriteReply(const boost::system::error_code& ecode); void HandleWriteReply(const boost::system::error_code& ecode);
void HandleWrite (const boost::system::error_code& ecode); void HandleWrite (const boost::system::error_code& ecode);
void SendReply (const std::string& content, int status = 200); void SendReply (const std::string& content, int status = 200);
void SendError (const std::string& message);
void HandleRequest (const std::string& address); void HandleRequest (const std::string& address);
void HandleCommand (const std::string& command, std::stringstream& s); void HandleCommand (const std::string& command, std::stringstream& s);

View file

@ -286,6 +286,16 @@ namespace i2p
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
} }
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{
if (maxNumTransitTunnels > 0 && maxNumTransitTunnels <= 10000 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
{
LogPrint (eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
g_MaxNumTransitTunnels = maxNumTransitTunnels;
}
}
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{ {
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
@ -298,7 +308,7 @@ namespace i2p
i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText); i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText);
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && if (i2p::context.AcceptsTunnels () &&
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= MAX_NUM_TRANSIT_TUNNELS && i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded ()) !i2p::transport::transports.IsBandwidthExceeded ())
{ {
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (

View file

@ -97,8 +97,6 @@ namespace i2p
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000 const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100 const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
const unsigned int MAX_NUM_TRANSIT_TUNNELS = 2500;
namespace tunnel namespace tunnel
{ {
class InboundTunnel; class InboundTunnel;
@ -259,6 +257,9 @@ namespace tunnel
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs; std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
}; };
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
} }
#endif #endif

View file

@ -83,6 +83,10 @@ namespace client
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler; m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler; m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler; m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
// NetworkSetting
m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlService::InboundBandwidthLimit;
m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlService::OutboundBandwidthLimit;
} }
I2PControlService::~I2PControlService () I2PControlService::~I2PControlService ()
@ -496,6 +500,22 @@ namespace client
} }
} }
void I2PControlService::InboundBandwidthLimit (const std::string& value, std::ostringstream& results)
{
if (value != "null")
i2p::context.SetBandwidth (std::atoi(value.c_str()));
int bw = i2p::context.GetBandwidthLimit();
InsertParam (results, "i2p.router.net.bw.in", bw);
}
void I2PControlService::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results)
{
if (value != "null")
i2p::context.SetBandwidth (std::atoi(value.c_str()));
int bw = i2p::context.GetBandwidthLimit();
InsertParam (results, "i2p.router.net.bw.out", bw);
}
// certificate // certificate
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path) void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
{ {

View file

@ -94,6 +94,8 @@ namespace client
// NetworkSetting // NetworkSetting
typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results); typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
void InboundBandwidthLimit (const std::string& value, std::ostringstream& results);
void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results);
private: private:

View file

@ -118,6 +118,9 @@ namespace client
void Start (); void Start ();
//If you override this make sure you call it from the children //If you override this make sure you call it from the children
void Stop (); void Stop ();
const boost::asio::ip::tcp::acceptor& GetAcceptor () const { return m_Acceptor; };
protected: protected:
virtual std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0; virtual std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0;
virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; }

View file

@ -311,18 +311,18 @@ namespace data
switch (keyType) switch (keyType)
{ {
case SIGNING_KEY_TYPE_DSA_SHA1: case SIGNING_KEY_TYPE_DSA_SHA1:
m_Verifier.reset (new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey)); UpdateVerifier (new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey));
break; break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{ {
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
m_Verifier.reset (new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding)); UpdateVerifier (new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding));
break; break;
} }
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{ {
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96 size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
m_Verifier.reset (new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding)); UpdateVerifier (new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding));
break; break;
} }
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
@ -331,7 +331,7 @@ namespace data
memcpy (signingKey, m_StandardIdentity.signingKey, 128); memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128 size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier.reset (new i2p::crypto::ECDSAP521Verifier (signingKey)); UpdateVerifier (new i2p::crypto::ECDSAP521Verifier (signingKey));
break; break;
} }
case SIGNING_KEY_TYPE_RSA_SHA256_2048: case SIGNING_KEY_TYPE_RSA_SHA256_2048:
@ -340,7 +340,7 @@ namespace data
memcpy (signingKey, m_StandardIdentity.signingKey, 128); memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::RSASHA2562048_KEY_LENGTH - 128; // 128 = 256- 128 size_t excessLen = i2p::crypto::RSASHA2562048_KEY_LENGTH - 128; // 128 = 256- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier.reset (new i2p::crypto:: RSASHA2562048Verifier (signingKey)); UpdateVerifier (new i2p::crypto:: RSASHA2562048Verifier (signingKey));
break; break;
} }
case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA384_3072:
@ -349,7 +349,7 @@ namespace data
memcpy (signingKey, m_StandardIdentity.signingKey, 128); memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::RSASHA3843072_KEY_LENGTH - 128; // 256 = 384- 128 size_t excessLen = i2p::crypto::RSASHA3843072_KEY_LENGTH - 128; // 256 = 384- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier.reset (new i2p::crypto:: RSASHA3843072Verifier (signingKey)); UpdateVerifier (new i2p::crypto:: RSASHA3843072Verifier (signingKey));
break; break;
} }
case SIGNING_KEY_TYPE_RSA_SHA512_4096: case SIGNING_KEY_TYPE_RSA_SHA512_4096:
@ -358,13 +358,13 @@ namespace data
memcpy (signingKey, m_StandardIdentity.signingKey, 128); memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::RSASHA5124096_KEY_LENGTH - 128; // 384 = 512- 128 size_t excessLen = i2p::crypto::RSASHA5124096_KEY_LENGTH - 128; // 384 = 512- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier.reset (new i2p::crypto:: RSASHA5124096Verifier (signingKey)); UpdateVerifier (new i2p::crypto:: RSASHA5124096Verifier (signingKey));
break; break;
} }
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
{ {
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
m_Verifier.reset (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding)); UpdateVerifier (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding));
break; break;
} }
default: default:
@ -372,6 +372,14 @@ namespace data
} }
} }
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
{
if (!m_Verifier || !verifier)
m_Verifier.reset (verifier);
else
delete verifier;
}
void IdentityEx::DropVerifier () const void IdentityEx::DropVerifier () const
{ {
// TODO: potential race condition with Verify // TODO: potential race condition with Verify

View file

@ -95,6 +95,7 @@ namespace data
private: private:
void CreateVerifier () const; void CreateVerifier () const;
void UpdateVerifier (i2p::crypto::Verifier * verifier) const;
private: private:

View file

@ -15,14 +15,11 @@ Donations
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59 LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
Downloads Documentation:
------------ --------------
http://i2pd.readthedocs.org
Official binary releases could be found at:
http://i2pd.website/releases/
older releases
http://download.i2p.io/purplei2p/i2pd/releases/
Supported OS Supported OS
------------ ------------

View file

@ -166,31 +166,46 @@ namespace i2p
} }
} }
void RouterContext::SetHighBandwidth () void RouterContext::SetBandwidth (char L) {
uint16_t limit = 0;
enum { low, high, extra } type = high;
/* detect parameters */
switch (L)
{ {
if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ()) case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break;
{ case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = 48; type = low; break;
m_RouterInfo.SetCaps ((m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth) & ~i2p::data::RouterInfo::eExtraBandwidth); case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break;
UpdateRouterInfo (); case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break;
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = 256; type = high; break;
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break;
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 9999; type = extra; break;
default:
limit = 48; type = low;
} }
/* update caps & flags in RI */
auto caps = m_RouterInfo.GetCaps ();
caps &= ~i2p::data::RouterInfo::eHighBandwidth;
caps &= ~i2p::data::RouterInfo::eExtraBandwidth;
switch (type)
{
case low : /* not set */; break;
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break;
}
m_RouterInfo.SetCaps (caps);
UpdateRouterInfo ();
m_BandwidthLimit = limit;
} }
void RouterContext::SetLowBandwidth () void RouterContext::SetBandwidth (int limit)
{ {
if (m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ()) if (limit > 2000) { SetBandwidth('X'); }
{ else if (limit > 256) { SetBandwidth('P'); }
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth & ~i2p::data::RouterInfo::eExtraBandwidth); else if (limit > 128) { SetBandwidth('O'); }
UpdateRouterInfo (); else if (limit > 64) { SetBandwidth('N'); }
} else if (limit > 48) { SetBandwidth('M'); }
} else if (limit > 12) { SetBandwidth('L'); }
else { SetBandwidth('K'); }
void RouterContext::SetExtraBandwidth ()
{
if (!m_RouterInfo.IsExtraBandwidth () || !m_RouterInfo.IsHighBandwidth ())
{
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eExtraBandwidth | i2p::data::RouterInfo::eHighBandwidth);
UpdateRouterInfo ();
}
} }
bool RouterContext::IsUnreachable () const bool RouterContext::IsUnreachable () const
@ -341,8 +356,10 @@ namespace i2p
delete[] buf; delete[] buf;
} }
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); // TODO
m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.SetRouterIdentity (GetIdentity ());
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
if (!routerInfo.IsUnreachable ()) // router.info looks good
{
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION); m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
m_RouterInfo.SetProperty ("router.version", I2P_VERSION); m_RouterInfo.SetProperty ("router.version", I2P_VERSION);
@ -350,6 +367,12 @@ namespace i2p
// Migration to 0.9.24. TODO: remove later // Migration to 0.9.24. TODO: remove later
m_RouterInfo.DeleteProperty ("coreVersion"); m_RouterInfo.DeleteProperty ("coreVersion");
m_RouterInfo.DeleteProperty ("stat_uptime"); m_RouterInfo.DeleteProperty ("stat_uptime");
}
else
{
LogPrint (eLogError, ROUTER_INFO, " is malformed. Creating new");
NewRouterInfo ();
}
if (IsUnreachable ()) if (IsUnreachable ())
SetReachable (); // we assume reachable until we discover firewall through peer tests SetReachable (); // we assume reachable until we discover firewall through peer tests

View file

@ -45,6 +45,7 @@ namespace i2p
uint32_t GetUptime () const; uint32_t GetUptime () const;
uint32_t GetStartupTime () const { return m_StartupTime; }; uint32_t GetStartupTime () const { return m_StartupTime; };
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
RouterStatus GetStatus () const { return m_Status; }; RouterStatus GetStatus () const { return m_Status; };
void SetStatus (RouterStatus status); void SetStatus (RouterStatus status);
@ -58,9 +59,8 @@ namespace i2p
bool IsFloodfill () const { return m_IsFloodfill; }; bool IsFloodfill () const { return m_IsFloodfill; };
void SetFloodfill (bool floodfill); void SetFloodfill (bool floodfill);
void SetFamily (const std::string& family); void SetFamily (const std::string& family);
void SetHighBandwidth (); void SetBandwidth (int limit); /* in kilobytes */
void SetLowBandwidth (); void SetBandwidth (char L); /* by letter */
void SetExtraBandwidth ();
bool AcceptsTunnels () const { return m_AcceptsTunnels; }; bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
@ -101,6 +101,7 @@ namespace i2p
uint64_t m_LastUpdateTime; uint64_t m_LastUpdateTime;
bool m_AcceptsTunnels, m_IsFloodfill; bool m_AcceptsTunnels, m_IsFloodfill;
uint64_t m_StartupTime; // in seconds since epoch uint64_t m_StartupTime; // in seconds since epoch
uint32_t m_BandwidthLimit; // allowed bandwidth
RouterStatus m_Status; RouterStatus m_Status;
std::mutex m_GarlicMutex; std::mutex m_GarlicMutex;
}; };

View file

@ -77,7 +77,7 @@ namespace data
bool RouterInfo::LoadFile () bool RouterInfo::LoadFile ()
{ {
std::ifstream s(m_FullPath.c_str (), std::ifstream::binary); std::ifstream s(m_FullPath, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
{ {
s.seekg (0,std::ios::end); s.seekg (0,std::ios::end);
@ -104,6 +104,8 @@ namespace data
{ {
if (LoadFile ()) if (LoadFile ())
ReadFromBuffer (false); ReadFromBuffer (false);
else
m_IsUnreachable = true;
} }
void RouterInfo::ReadFromBuffer (bool verifySignature) void RouterInfo::ReadFromBuffer (bool verifySignature)
@ -333,16 +335,19 @@ namespace data
void RouterInfo::UpdateCapsProperty () void RouterInfo::UpdateCapsProperty ()
{ {
std::string caps; std::string caps;
if (m_Caps & eFloodfill) if (m_Caps & eFloodfill) {
{
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
caps += CAPS_FLAG_FLOODFILL; // floodfill caps += CAPS_FLAG_FLOODFILL; // floodfill
caps += (m_Caps & eExtraBandwidth)
? CAPS_FLAG_EXTRA_BANDWIDTH1 // 'P'
: CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
} else {
if (m_Caps & eExtraBandwidth) {
caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
} else if (m_Caps & eHighBandwidth) {
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
} else {
caps += CAPS_FLAG_LOW_BANDWIDTH2; // 'L'
} }
else
{
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1;
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth
} }
if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
@ -511,19 +516,20 @@ namespace data
m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen (); m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen ();
} }
void RouterInfo::SaveToFile (const std::string& fullPath) bool RouterInfo::SaveToFile (const std::string& fullPath)
{ {
m_FullPath = fullPath; m_FullPath = fullPath;
if (m_Buffer) if (!m_Buffer) {
{
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
if (f.is_open ())
f.write ((char *)m_Buffer, m_BufferLen);
else
LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
}
else
LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL"); LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
return false;
}
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
if (!f.is_open ()) {
LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
return false;
}
f.write ((char *)m_Buffer, m_BufferLen);
return true;
} }
size_t RouterInfo::ReadString (char * str, std::istream& s) size_t RouterInfo::ReadString (char * str, std::istream& s)

View file

@ -24,13 +24,14 @@ namespace data
const char CAPS_FLAG_HIDDEN = 'H'; const char CAPS_FLAG_HIDDEN = 'H';
const char CAPS_FLAG_REACHABLE = 'R'; const char CAPS_FLAG_REACHABLE = 'R';
const char CAPS_FLAG_UNREACHABLE = 'U'; const char CAPS_FLAG_UNREACHABLE = 'U';
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* bandwidth flags */
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
const char CAPS_FLAG_SSU_TESTING = 'B'; const char CAPS_FLAG_SSU_TESTING = 'B';
const char CAPS_FLAG_SSU_INTRODUCER = 'C'; const char CAPS_FLAG_SSU_INTRODUCER = 'C';
@ -160,7 +161,7 @@ namespace data
bool IsUpdated () const { return m_IsUpdated; }; bool IsUpdated () const { return m_IsUpdated; };
void SetUpdated (bool updated) { m_IsUpdated = updated; }; void SetUpdated (bool updated) { m_IsUpdated = updated; };
void SaveToFile (const std::string& fullPath); bool SaveToFile (const std::string& fullPath);
std::shared_ptr<RouterProfile> GetProfile () const; std::shared_ptr<RouterProfile> GetProfile () const;
void SaveProfile () { if (m_Profile) m_Profile->Save (); }; void SaveProfile () { if (m_Profile) m_Profile->Save (); };
@ -174,7 +175,6 @@ namespace data
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; };
bool IsDestination () const { return false; }; bool IsDestination () const { return false; };
private: private:
bool LoadFile (); bool LoadFile ();

44
SAM.cpp
View file

@ -48,14 +48,14 @@ namespace client
case eSAMSocketTypeStream: case eSAMSocketTypeStream:
{ {
if (m_Session) if (m_Session)
m_Session->sockets.remove (shared_from_this ()); m_Session->DelSocket (shared_from_this ());
break; break;
} }
case eSAMSocketTypeAcceptor: case eSAMSocketTypeAcceptor:
{ {
if (m_Session) if (m_Session)
{ {
m_Session->sockets.remove (shared_from_this ()); m_Session->DelSocket (shared_from_this ());
m_Session->localDestination->StopAcceptingStreams (); m_Session->localDestination->StopAcceptingStreams ();
} }
break; break;
@ -64,7 +64,8 @@ namespace client
; ;
} }
m_SocketType = eSAMSocketTypeTerminated; m_SocketType = eSAMSocketTypeTerminated;
m_Socket.close (); if (m_Socket.is_open()) m_Socket.close ();
m_Session = nullptr;
} }
void SAMSocket::ReceiveHandshake () void SAMSocket::ReceiveHandshake ()
@ -369,7 +370,7 @@ namespace client
void SAMSocket::Connect (std::shared_ptr<const i2p::data::LeaseSet> remote) void SAMSocket::Connect (std::shared_ptr<const i2p::data::LeaseSet> remote)
{ {
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_Session->sockets.push_back (shared_from_this ()); m_Session->AddSocket (shared_from_this ());
m_Stream = m_Session->localDestination->CreateStream (remote); m_Stream = m_Session->localDestination->CreateStream (remote);
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
I2PReceive (); I2PReceive ();
@ -402,7 +403,7 @@ namespace client
if (!m_Session->localDestination->IsAcceptingStreams ()) if (!m_Session->localDestination->IsAcceptingStreams ())
{ {
m_SocketType = eSAMSocketTypeAcceptor; m_SocketType = eSAMSocketTypeAcceptor;
m_Session->sockets.push_back (shared_from_this ()); m_Session->AddSocket (shared_from_this ());
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1)); m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
@ -676,19 +677,20 @@ namespace client
SAMSession::~SAMSession () SAMSession::~SAMSession ()
{ {
for (auto it: sockets) CloseStreams();
it->SetSocketType (eSAMSocketTypeTerminated);
i2p::client::context.DeleteLocalDestination (localDestination); i2p::client::context.DeleteLocalDestination (localDestination);
} }
void SAMSession::CloseStreams () void SAMSession::CloseStreams ()
{ {
for (auto it: sockets)
{ {
it->CloseStream (); std::lock_guard<std::mutex> lock(m_SocketsMutex);
it->SetSocketType (eSAMSocketTypeTerminated); for (auto sock : m_Sockets) {
sock->CloseStream();
} }
sockets.clear (); }
// XXX: should this be done inside locked parts?
m_Sockets.clear();
} }
SAMBridge::SAMBridge (const std::string& address, int port): SAMBridge::SAMBridge (const std::string& address, int port):
@ -717,7 +719,7 @@ namespace client
m_IsRunning = false; m_IsRunning = false;
m_Acceptor.cancel (); m_Acceptor.cancel ();
for (auto it: m_Sessions) for (auto it: m_Sessions)
delete it.second; it.second->CloseStreams ();
m_Sessions.clear (); m_Sessions.clear ();
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
@ -771,7 +773,7 @@ namespace client
Accept (); Accept ();
} }
SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination, std::shared_ptr<SAMSession> SAMBridge::CreateSession (const std::string& id, const std::string& destination,
const std::map<std::string, std::string> * params) const std::map<std::string, std::string> * params)
{ {
std::shared_ptr<ClientDestination> localDestination = nullptr; std::shared_ptr<ClientDestination> localDestination = nullptr;
@ -796,8 +798,9 @@ namespace client
} }
if (localDestination) if (localDestination)
{ {
auto session = std::make_shared<SAMSession>(localDestination);
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
auto ret = m_Sessions.insert (std::pair<std::string, SAMSession *>(id, new SAMSession (localDestination))); auto ret = m_Sessions.insert (std::make_pair(id, session));
if (!ret.second) if (!ret.second)
LogPrint (eLogWarning, "SAM: Session ", id, " already exists"); LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
return ret.first->second; return ret.first->second;
@ -806,20 +809,25 @@ namespace client
} }
void SAMBridge::CloseSession (const std::string& id) void SAMBridge::CloseSession (const std::string& id)
{
std::shared_ptr<SAMSession> session;
{ {
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
auto it = m_Sessions.find (id); auto it = m_Sessions.find (id);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
{ {
auto session = it->second; session = it->second;
m_Sessions.erase (it);
}
}
if (session)
{
session->localDestination->StopAcceptingStreams (); session->localDestination->StopAcceptingStreams ();
session->CloseStreams (); session->CloseStreams ();
m_Sessions.erase (it);
delete session;
} }
} }
SAMSession * SAMBridge::FindSession (const std::string& id) const std::shared_ptr<SAMSession> SAMBridge::FindSession (const std::string& id) const
{ {
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
auto it = m_Sessions.find (id); auto it = m_Sessions.find (id);

33
SAM.h
View file

@ -128,13 +128,36 @@ namespace client
std::string m_ID; // nickname std::string m_ID; // nickname
bool m_IsSilent; bool m_IsSilent;
std::shared_ptr<i2p::stream::Stream> m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
SAMSession * m_Session; std::shared_ptr<SAMSession> m_Session;
}; };
struct SAMSession struct SAMSession
{ {
std::shared_ptr<ClientDestination> localDestination; std::shared_ptr<ClientDestination> localDestination;
std::list<std::shared_ptr<SAMSocket> > sockets; std::list<std::shared_ptr<SAMSocket> > m_Sockets;
std::mutex m_SocketsMutex;
/** safely add a socket to this session */
void AddSocket(std::shared_ptr<SAMSocket> sock) {
std::lock_guard<std::mutex> lock(m_SocketsMutex);
m_Sockets.push_back(sock);
}
/** safely remove a socket from this session */
void DelSocket(std::shared_ptr<SAMSocket> sock) {
std::lock_guard<std::mutex> lock(m_SocketsMutex);
m_Sockets.remove(sock);
}
/** get a list holding a copy of all sam sockets from this session */
std::list<std::shared_ptr<SAMSocket> > ListSockets() {
std::list<std::shared_ptr<SAMSocket> > l;
{
std::lock_guard<std::mutex> lock(m_SocketsMutex);
for( auto & sock : m_Sockets ) l.push_back(sock);
}
return l;
}
SAMSession (std::shared_ptr<ClientDestination> dest); SAMSession (std::shared_ptr<ClientDestination> dest);
~SAMSession (); ~SAMSession ();
@ -153,10 +176,10 @@ namespace client
void Stop (); void Stop ();
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
SAMSession * CreateSession (const std::string& id, const std::string& destination, // empty string means transient std::shared_ptr<SAMSession> CreateSession (const std::string& id, const std::string& destination, // empty string means transient
const std::map<std::string, std::string> * params); const std::map<std::string, std::string> * params);
void CloseSession (const std::string& id); void CloseSession (const std::string& id);
SAMSession * FindSession (const std::string& id) const; std::shared_ptr<SAMSession> FindSession (const std::string& id) const;
private: private:
@ -177,7 +200,7 @@ namespace client
boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint;
boost::asio::ip::udp::socket m_DatagramSocket; boost::asio::ip::udp::socket m_DatagramSocket;
mutable std::mutex m_SessionsMutex; mutable std::mutex m_SessionsMutex;
std::map<std::string, SAMSession *> m_Sessions; std::map<std::string, std::shared_ptr<SAMSession> > m_Sessions;
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
public: public:

View file

@ -435,8 +435,13 @@ namespace crypto
std::unique_ptr<Ed25519>& GetEd25519 () std::unique_ptr<Ed25519>& GetEd25519 ()
{ {
if (!g_Ed25519) if (!g_Ed25519)
g_Ed25519.reset (new Ed25519()); {
auto c = new Ed25519();
if (!g_Ed25519) // make sure it was not created already
g_Ed25519.reset (c);
else
delete c;
}
return g_Ed25519; return g_Ed25519;
} }

View file

@ -200,9 +200,9 @@ namespace transport
bool Transports::IsBandwidthExceeded () const bool Transports::IsBandwidthExceeded () const
{ {
if (i2p::context.GetRouterInfo ().IsExtraBandwidth ()) return false; auto limit = i2p::context.GetBandwidthLimit() * 1024; // convert to bytes
auto bw = std::max (m_InBandwidth, m_OutBandwidth); auto bw = std::max (m_InBandwidth, m_OutBandwidth);
return bw > (i2p::context.GetRouterInfo ().IsHighBandwidth () ? HIGH_BANDWIDTH_LIMIT : LOW_BANDWIDTH_LIMIT); return bw > limit;
} }
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg) void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)

View file

@ -66,8 +66,6 @@ namespace transport
}; };
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs
const uint32_t HIGH_BANDWIDTH_LIMIT = 256*1024; // 256KBs
class Transports class Transports
{ {
public: public:
@ -94,8 +92,8 @@ namespace transport
void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; }; void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; };
uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; }; uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; };
uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; }; uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; };
uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second uint32_t GetInBandwidth () const { return m_InBandwidth; };
uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second uint32_t GetOutBandwidth () const { return m_OutBandwidth; };
bool IsBandwidthExceeded () const; bool IsBandwidthExceeded () const;
size_t GetNumPeers () const { return m_Peers.size (); }; size_t GetNumPeers () const { return m_Peers.size (); };
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const; std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
@ -138,7 +136,7 @@ namespace transport
DHKeysPairSupplier m_DHKeysPairSupplier; DHKeysPairSupplier m_DHKeysPairSupplier;
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes; std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes;
uint32_t m_InBandwidth, m_OutBandwidth; uint32_t m_InBandwidth, m_OutBandwidth; // bytes per second
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes;
uint64_t m_LastBandwidthUpdateTime; uint64_t m_LastBandwidthUpdateTime;

View file

@ -119,7 +119,7 @@ namespace tunnel
if (ret.second) if (ret.second)
HandleOutOfSequenceFragment (msgID, ret.first->second); HandleOutOfSequenceFragment (msgID, ret.first->second);
else else
LogPrint (eLogError, "TunnelMessage: Incomplete message ", msgID, "already exists"); LogPrint (eLogError, "TunnelMessage: Incomplete message ", msgID, " already exists");
} }
else else
{ {

View file

@ -52,8 +52,8 @@ END
// Icon with lowest ID value placed first to ensure application icon // Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems. // remains consistent on all systems.
//MAINICON ICON "ictoopie.ico" MAINICON ICON "ictoopie.ico"
MAINICON ICON "anke.ico" //MAINICON ICON "anke.ico"
MASCOT BITMAP "Anke_700px.bmp" MASCOT BITMAP "Anke_700px.bmp"

View file

@ -28,7 +28,11 @@ namespace api
i2p::fs::DetectDataDir(datadir, false); i2p::fs::DetectDataDir(datadir, false);
i2p::fs::Init(); i2p::fs::Init();
i2p::crypto::InitCrypto (); #if defined(__x86_64__)
i2p::crypto::InitCrypto (false);
#else
i2p::crypto::InitCrypto (true);
#endif
i2p::context.Init (); i2p::context.Init ();
} }

View file

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBxDCCAWmgAwIBAgIJAJnJIdKHYwWcMAoGCCqGSM49BAMCMGcxCzAJBgNVBAYT
AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
aXRzIFB0eSBMdGQxIDAeBgNVBAMMF3ZvbGF0aWxlLmZhbWlseS5pMnAubmV0MB4X
DTE2MDQyNjE1MjAyNloXDTI2MDQyNDE1MjAyNlowZzELMAkGA1UEBhMCQVUxEzAR
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
IEx0ZDEgMB4GA1UEAwwXdm9sYXRpbGUuZmFtaWx5LmkycC5uZXQwWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAARf6LBfbbfL6HInvC/4wAGaN3rj0eeLE/OdBpA93R3L
s8EUp0YTEJHWPo9APiKMmAwQSsMJfjhNrbp+UWEnnx2LMAoGCCqGSM49BAMCA0kA
MEYCIQDpQu2KPV5G1JOFLoZvdj+rcvEnjxM/FxkaqikwkVx8FAIhANP7DkUal+GT
SuiCtcqM4QyIBsfsCJBWEMzovft164Bo
-----END CERTIFICATE-----

6
debian/copyright vendored
View file

@ -3,9 +3,9 @@ Upstream-Name: i2pd
Source: https://github.com/PurpleI2P Source: https://github.com/PurpleI2P
Files: * Files: *
Copyright: 2013-2015 PurpleI2P Copyright: 2013-2016 PurpleI2P
License: BSD-3-clause License: BSD-3-clause
Copyright (c) 2013-2015, The PurpleI2P Project Copyright (c) 2013-2016, The PurpleI2P Project
. .
All rights reserved. All rights reserved.
. .
@ -34,7 +34,7 @@ License: BSD-3-clause
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Files: debian/* Files: debian/*
Copyright: 2014-2015 hagen <hagen@i2pmail.org> Copyright: 2014-2016 hagen <hagen@i2pmail.org>
2013-2015 Kill Your TV <killyourtv@i2pmail.org> 2013-2015 Kill Your TV <killyourtv@i2pmail.org>
License: GPL-2.0+ License: GPL-2.0+
This package is free software; you can redistribute it and/or modify This package is free software; you can redistribute it and/or modify

107
debian/i2pd.1 vendored
View file

@ -5,7 +5,7 @@ i2pd \- Load-balanced unspoofable packet switching network
.SH SYNOPSIS .SH SYNOPSIS
.B i2pd .B i2pd
[\fIOPTION1\fR) [\fIOPTION2\fR]... [\fIOPTION1\fR] [\fIOPTION2\fR]...
.SH DESCRIPTION .SH DESCRIPTION
i2pd i2pd
@ -18,59 +18,58 @@ network is both distributed and dynamic, with no trusted parties.
Any of the configuration options below can be used in the \fBDAEMON_ARGS\fR variable in \fI/etc/default/i2pd\fR. Any of the configuration options below can be used in the \fBDAEMON_ARGS\fR variable in \fI/etc/default/i2pd\fR.
.BR .BR
.TP .TP
\fB\-\-host=\fR \fB\-\-help\fR
The external IP (deprecated) Show available options.
.TP
\fB\-\-port=\fR
The external port to listen on
.TP
\fB\-\-httpport=\fR
The HTTP port to listen on
.TP
\fB\-\-log=\fR[\fI1\fR|\fI0\fR]
.br
Enable of disable logging to a file. \fI1\fR for yes, \fI0\fR for no. (default: \fI0\fR, off)
.TP
\fB\-\-daemon=\fR[\fI1\fR|\fI0\fR]
Enable or disable daemon mode. Daemon mode is enabled with \fI1\fR and disabled with \fI0\fR. (default: \fI0\fR, off)
.TP
\fB\-\-service=\fR[\fI1\fR|\fI0\fR]
If enabled, system folders (\fB/var/run/i2pd.pid\fR, \fB/var/log/i2pd.log\fR, \fB/var/lib/i2pd\fR) will be used. If off, \fB$HOME/.i2pd\fR will be used instead. (default: \fI0\fR, off).
.TP
\fB\-\-unreachable=\fR[\fI1\fR|\fI0\fR]
\fI1\fR if router is declared as unreachable and works through introducers. (default: \fI0\fR, off)
.TP
\fB\-\-v6=\fR[\fI1\fR|\fI0\fR]
\fI1\fR if \fBi2pd\fR should communicate via IPv6. (default: \fI0\fR, off)
.TP
\fB\-\-floodfill=\fR[\fI1\fR|\fI0\fR]
\fI1\fR if \fBi2pd\fR should become a floodfill. (default: \fI0\fR, off)
.TP
\fB\-\-bandwidth=\fR[\fI1\fR|\fI0\fR]
\fIL\fR if \fBi2pd\fR should be limited to 32KiB/s. Enabling floodfill will automatically set this to \fI0\fR (default: \fI0\fR, no limit)
.TP
\fB\-\-httpproxyport=\fR
The local port for the HTTP Proxy to listen on (default: \fI4446\fR)
.TP
\fB\-\-socksproxyport=\fR
The local port for the SOCKS proxy to listen on (default: \fI4447\fR)
.TP
\fB\-\-proxykeys=\fR
An optional keys file for tunnel local destination (both HTTP and SOCKS)
.TP
\fB\-\-samport=\fR
Port of SAM bridge. Usually \fI7656\fR. SAM will not be enabled if this is not set. (default: unset)
.TP
\fB\-\-bobport=\fR
Port of BOB command channel. Usually \fI2827\fR. BOB will not be enabled if this is not set. (default: unset)
.TP
\fB\-\-i2pcontrolport=\fR
Port of I2P control service. Usually \fI7650\fR. I2PControl will not be enabled if this is not set. (default: unset)
.TP .TP
\fB\-\-conf=\fR \fB\-\-conf=\fR
Config file (default: \fI~/.i2pd/i2pd.conf\fR or \fI/var/lib/i2pd/i2pd.conf\fR) Config file (default: \fI~/.i2pd/i2pd.conf\fR or \fI/var/lib/i2pd/i2pd.conf\fR)
.BR
This parameter will be silently ignored if the specified config file does not exist. This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file. Options specified on the command line take precedence over those in the config file.
.TP
\fB\-\-tunconf=\fR
Tunnels config file (default: \fI~/.i2pd/tunnels.conf\fR or \fI/var/lib/i2pd/tunnels.conf\fR)
.TP
\fB\-\-pidfile=\fR
Where to write pidfile (don\'t write by default)
.TP
\fB\-\-log=\fR
Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not set, \fIfile\fR - otherwise, for compatibility)
.TP
\fB\-\-loglevel=\fR
Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR)
.TP
\fB\-\-datadir=\fR
Path to storage of i2pd data (RI, keys, peer profiles, ...)
.TP
\fB\-\-host=\fR
The external IP address
.TP
\fB\-\-port=\fR
The port to listen on for incoming connections
.TP
\fB\-\-daemon\fR
Router will go to background after start
.TP
\fB\-\-service\fR
Router will use system folders like \fI/var/lib/i2pd\fR
.TP
\fB\-\-ipv6\fR
Enable communication through ipv6. false by default
.TP
\fB\-\-notransit\fR
Router will not accept transit tunnels at startup
.TP
\fB\-\-floodfill\fR
Router will be floodfill
.TP
\fB\-\-bandwidth=\fR
Bandwidth limit: integer in KBps or letter aliases: \fIL (32KBps)\fR, O (256), P (2048), X (>9000)
.TP
\fB\-\-family=\fR
Name of a family, router belongs to.
.PP
See service-specific parameters in page \fIdocs/configuration.md\fR or in example config file \fIdocs/i2pd.conf\fR
.SH FILES .SH FILES
.PP .PP
@ -82,10 +81,10 @@ i2pd configuration files (when running as a system service)
.PP .PP
/var/lib/i2pd/ /var/lib/i2pd/
.RS 4 .RS 4
i2pd profile directory (when running as a system service, see \fB\-\-service=\fR above) i2pd profile directory (when running as a system service, see \fB\-\-service\fR above)
.RE .RE
.PP .PP
$HOME/.i2pd $HOME/.i2pd/
.RS 4 .RS 4
i2pd profile directory (when running as a normal user) i2pd profile directory (when running as a normal user)
.RE .RE
@ -95,7 +94,9 @@ i2pd profile directory (when running as a normal user)
default I2P hosts file default I2P hosts file
.SH AUTHOR .SH AUTHOR
This manual page was written by kytv <killyourtv@i2pmail.org> for the Debian system (but may be used by others). This manual page was written by kytv <killyourtv@i2pmail.org> for the Debian system (but may be used by others).
.BR .PP
Updated by hagen <hagen@i2pmail.org> in 2016.
.PP
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation
.BR .BR
On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL On Debian systems, the complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fR

19
debian/i2pd.conf vendored
View file

@ -1,19 +0,0 @@
ipv6
[httpproxy]
address = 127.0.0.1
port = 4444
# other services (disabled by default)
#
#[sam]
#address = 127.0.0.1
#port = 7656
#
#[bob]
#address = 127.0.0.1
#port = 2827
#
#[i2pcontrol]
#address = 127.0.0.1
#port = 7650

2
debian/i2pd.install vendored
View file

@ -1,5 +1,5 @@
i2pd usr/sbin/ i2pd usr/sbin/
debian/i2pd.conf etc/i2pd/ docs/i2pd.conf etc/i2pd/
debian/tunnels.conf etc/i2pd/ debian/tunnels.conf etc/i2pd/
debian/subscriptions.txt etc/i2pd/ debian/subscriptions.txt etc/i2pd/
contrib/certificates/ usr/share/i2pd/ contrib/certificates/ usr/share/i2pd/

View file

@ -16,16 +16,21 @@ If you are upgrading your very old router (< 2.3.0) see also [this](config_opts_
* --logfile= - Path to logfile (default - autodetect) * --logfile= - Path to logfile (default - autodetect)
* --loglevel= - Log messages above this level (debug, *info, warn, error) * --loglevel= - Log messages above this level (debug, *info, warn, error)
* --datadir= - Path to storage of i2pd data (RI, keys, peer profiles, ...) * --datadir= - Path to storage of i2pd data (RI, keys, peer profiles, ...)
* --host= - The external IP * --host= - Router external IP for incoming connections
* --port= - The port to listen on * --port= - Port to listen for incoming connections (default: auto)
* --daemon - Router will go to background after start * --daemon - Router will go to background after start
* --service - Router will use system folders like '/var/lib/i2pd' * --service - Router will use system folders like '/var/lib/i2pd'
* --ipv6 - Enable communication through ipv6. false by default * --ipv6 - Enable communication through ipv6. false by default
* --notransit - Router will not accept transit tunnels at startup. false by default * --notransit - Router will not accept transit tunnels at startup. false by default
* --floodfill - Router will be floodfill. false by default * --floodfill - Router will be floodfill. false by default
* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited * --bandwidth= - Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)
* --family= - Name of a family, router belongs to * --family= - Name of a family, router belongs to
Windows-specific options:
* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove") * --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove")
* --insomnia - Prevent system from sleeping
* --close= - Action on close: minimize, exit, ask
All options below still possible in cmdline, but better write it in config file: All options below still possible in cmdline, but better write it in config file:
@ -56,6 +61,10 @@ All options below still possible in cmdline, but better write it in config file:
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
* --i2pcontrol.enabled= - If I2P control is enabled. false by default * --i2pcontrol.enabled= - If I2P control is enabled. false by default
* --precomputation.elgamal= - Use ElGamal precomputated tables. false for x64 and true for other platforms by default
* --limits.transittunnels= - Override maximum number of transit tunnels. 2500 by default
Config files Config files
------------ ------------

View file

@ -69,8 +69,8 @@ port = 7070
## Uncomment and set to 'false' to disable HTTP Proxy ## Uncomment and set to 'false' to disable HTTP Proxy
# enabled = true # enabled = true
## Address and port service will listen on ## Address and port service will listen on
# address = 127.0.0.1 address = 127.0.0.1
# port = 4444 port = 4444
## Optional keys file for proxy local destination ## Optional keys file for proxy local destination
# keys = http-proxy-keys.dat # keys = http-proxy-keys.dat

View file

@ -1,14 +1,14 @@
#ifndef _VERSION_H_ #ifndef _VERSION_H_
#define _VERSION_H_ #define _VERSION_H_
#define CODENAME "Purple" #define CODENAME "Bora Bora"
#define STRINGIZE(x) #x #define STRINGIZE(x) #x
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 5 #define I2PD_VERSION_MINOR 6
#define I2PD_VERSION_MICRO 1 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
#define VERSION I2PD_VERSION #define VERSION I2PD_VERSION