mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 13:27:17 +01:00
commit
fb59d80897
2
.dir-locals.el
Normal file
2
.dir-locals.el
Normal file
|
@ -0,0 +1,2 @@
|
|||
((c++-mode . ((indent-tabs-mode . t)))
|
||||
(c-mode . ((mode . c++))))
|
|
@ -1,6 +1,10 @@
|
|||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.10.1] - 2016-11-07
|
||||
### Fixed
|
||||
- Fixed some performance issues for Windows and Android
|
||||
|
||||
## [2.10.0] - 2016-10-17
|
||||
### Added
|
||||
- Datagram i2p tunnels
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace client
|
|||
if (httpProxyKeys.length () > 0)
|
||||
{
|
||||
i2p::data::PrivateKeys keys;
|
||||
if(LoadPrivateKeys (keys, httpProxyKeys))
|
||||
if(LoadPrivateKeys (keys, httpProxyKeys, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1))
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
ReadI2CPOptionsFromConfig ("httpproxy.", params);
|
||||
|
@ -82,7 +82,7 @@ namespace client
|
|||
if (socksProxyKeys.length () > 0)
|
||||
{
|
||||
i2p::data::PrivateKeys keys;
|
||||
if (LoadPrivateKeys (keys, socksProxyKeys))
|
||||
if (LoadPrivateKeys (keys, socksProxyKeys, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1))
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
ReadI2CPOptionsFromConfig ("socksproxy.", params);
|
||||
|
@ -372,6 +372,8 @@ namespace client
|
|||
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
|
||||
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
|
||||
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
|
||||
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
|
||||
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
|
||||
}
|
||||
|
||||
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
|
||||
|
@ -384,7 +386,11 @@ namespace client
|
|||
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;
|
||||
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value))
|
||||
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value))
|
||||
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value;
|
||||
}
|
||||
|
||||
void ClientContext::ReadTunnels ()
|
||||
|
|
12
Config.cpp
12
Config.cpp
|
@ -86,7 +86,9 @@ namespace config {
|
|||
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
|
||||
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
|
||||
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
|
||||
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
|
||||
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
|
||||
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels")
|
||||
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
|
||||
;
|
||||
|
||||
options_description socksproxy("SOCKS Proxy options");
|
||||
|
@ -98,7 +100,9 @@ namespace config {
|
|||
("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.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
|
||||
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels")
|
||||
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels")
|
||||
("socksproxy.outproxy", 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")
|
||||
;
|
||||
|
@ -157,7 +161,8 @@ namespace config {
|
|||
|
||||
options_description reseed("Reseed options");
|
||||
reseed.add_options()
|
||||
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
|
||||
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
|
||||
("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from")
|
||||
("reseed.file", value<std::string>()->default_value(""), "Path to .su3 file")
|
||||
("reseed.urls", value<std::string>()->default_value(
|
||||
"https://reseed.i2p-projekt.de/,"
|
||||
|
@ -165,7 +170,6 @@ namespace config {
|
|||
"https://netdb.i2p2.no/,"
|
||||
"https://us.reseed.i2p2.no:444/,"
|
||||
"https://uk.reseed.i2p2.no:444/,"
|
||||
"https://i2p.manas.ca:8443/,"
|
||||
"https://i2p-0.manas.ca:8443/,"
|
||||
"https://reseed.i2p.vzaws.com:8443/,"
|
||||
"https://download.xxlspeed.com/,"
|
||||
|
|
19
Crypto.cpp
19
Crypto.cpp
|
@ -224,7 +224,7 @@ namespace crypto
|
|||
|
||||
// DH
|
||||
|
||||
DHKeys::DHKeys (): m_IsUpdated (true)
|
||||
DHKeys::DHKeys ()
|
||||
{
|
||||
m_DH = DH_new ();
|
||||
DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg));
|
||||
|
@ -236,7 +236,7 @@ namespace crypto
|
|||
DH_free (m_DH);
|
||||
}
|
||||
|
||||
void DHKeys::GenerateKeys (uint8_t * priv, uint8_t * pub)
|
||||
void DHKeys::GenerateKeys ()
|
||||
{
|
||||
BIGNUM * priv_key = NULL, * pub_key = NULL;
|
||||
#if !defined(__x86_64__) // use short exponent for non x64
|
||||
|
@ -261,20 +261,7 @@ namespace crypto
|
|||
DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key);
|
||||
}
|
||||
|
||||
if (priv) bn2buf (priv_key, priv, 256);
|
||||
if (pub) bn2buf (pub_key, pub, 256);
|
||||
m_IsUpdated = true;
|
||||
}
|
||||
|
||||
const uint8_t * DHKeys::GetPublicKey ()
|
||||
{
|
||||
if (m_IsUpdated)
|
||||
{
|
||||
bn2buf (m_DH->pub_key, m_PublicKey, 256);
|
||||
BN_free (m_DH->pub_key); m_DH->pub_key = NULL;
|
||||
m_IsUpdated= false;
|
||||
}
|
||||
return m_PublicKey;
|
||||
bn2buf (pub_key, m_PublicKey, 256);
|
||||
}
|
||||
|
||||
void DHKeys::Agree (const uint8_t * pub, uint8_t * shared)
|
||||
|
|
21
Crypto.h
21
Crypto.h
|
@ -7,8 +7,10 @@
|
|||
#include <openssl/dh.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "Base.h"
|
||||
|
@ -34,15 +36,14 @@ namespace crypto
|
|||
DHKeys ();
|
||||
~DHKeys ();
|
||||
|
||||
void GenerateKeys (uint8_t * priv = nullptr, uint8_t * pub = nullptr);
|
||||
const uint8_t * GetPublicKey ();
|
||||
void GenerateKeys ();
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||
|
||||
private:
|
||||
|
||||
DH * m_DH;
|
||||
uint8_t m_PublicKey[256];
|
||||
bool m_IsUpdated;
|
||||
};
|
||||
|
||||
// ElGamal
|
||||
|
@ -280,6 +281,8 @@ namespace crypto
|
|||
|
||||
void InitCrypto (bool precomputation);
|
||||
void TerminateCrypto ();
|
||||
}
|
||||
}
|
||||
|
||||
// take care about openssl version
|
||||
#include <openssl/opensslv.h>
|
||||
|
@ -296,6 +299,11 @@ inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
|||
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{ *pr = sig->r; *ps = sig->s; }
|
||||
|
||||
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{ sig->r = r; sig->s = s; return 1; }
|
||||
inline void ECDSA_SIG_get0(const ECDSA_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)
|
||||
|
@ -312,9 +320,10 @@ inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
|
|||
inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
|
||||
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; }
|
||||
|
||||
inline int EVP_PKEY_base_id(const EVP_PKEY *pkey)
|
||||
{ return EVP_PKEY_type(pkey->type); }
|
||||
inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
|
||||
{ return pkey->pkey.rsa; }
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,6 +63,22 @@ namespace client
|
|||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty);
|
||||
if (explicitPeers)
|
||||
m_Pool->SetExplicitPeers (explicitPeers);
|
||||
if(params)
|
||||
{
|
||||
auto itr = params->find(I2CP_PARAM_MAX_TUNNEL_LATENCY);
|
||||
if (itr != params->end()) {
|
||||
auto maxlatency = std::stoi(itr->second);
|
||||
itr = params->find(I2CP_PARAM_MIN_TUNNEL_LATENCY);
|
||||
if (itr != params->end()) {
|
||||
auto minlatency = std::stoi(itr->second);
|
||||
if ( minlatency > 0 && maxlatency > 0 ) {
|
||||
// set tunnel pool latency
|
||||
LogPrint(eLogInfo, "Destination: requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]");
|
||||
m_Pool->RequireLatency(minlatency, maxlatency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaseSetDestination::~LeaseSetDestination ()
|
||||
|
|
|
@ -50,6 +50,12 @@ namespace client
|
|||
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
|
||||
const int DEFAULT_TAGS_TO_SEND = 40;
|
||||
|
||||
// latency
|
||||
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
|
||||
const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
|
||||
const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max";
|
||||
const int DEFAULT_MAX_TUNNEL_LATENCY = 0;
|
||||
|
||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||
|
||||
class LeaseSetDestination: public i2p::garlic::GarlicDestination,
|
||||
|
@ -143,6 +149,7 @@ namespace client
|
|||
|
||||
// for HTTP only
|
||||
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
||||
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; };
|
||||
};
|
||||
|
||||
class ClientDestination: public LeaseSetDestination
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace data
|
|||
if (family) family[0] = 0;
|
||||
}
|
||||
auto pkey = X509_get_pubkey (cert);
|
||||
int keyType = EVP_PKEY_type(pkey->type);
|
||||
int keyType = EVP_PKEY_base_id (pkey);
|
||||
switch (keyType)
|
||||
{
|
||||
case EVP_PKEY_DSA:
|
||||
|
|
|
@ -277,6 +277,7 @@ namespace garlic
|
|||
{
|
||||
newTags->msgID = msgID;
|
||||
m_UnconfirmedTagsMsgs.emplace_back (newTags);
|
||||
newTags = nullptr; // got acquired
|
||||
}
|
||||
m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
|
||||
}
|
||||
|
@ -300,13 +301,14 @@ namespace garlic
|
|||
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
|
||||
(*numCloves)++;
|
||||
}
|
||||
|
||||
memset (payload + size, 0, 3); // certificate of message
|
||||
size += 3;
|
||||
htobe32buf (payload + size, msgID); // MessageID
|
||||
size += 4;
|
||||
htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec
|
||||
size += 8;
|
||||
|
||||
if (newTags) delete newTags; // not acquired, delete
|
||||
return size;
|
||||
}
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ namespace http {
|
|||
else
|
||||
s << numKBytesSent / 1024 / 1024 << " GiB";
|
||||
s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)<br>\r\n";
|
||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n<br>\r\n";
|
||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
||||
s << "<div class='slide'\r\n><label for='slide1'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n";
|
||||
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||
|
@ -253,7 +253,7 @@ namespace http {
|
|||
s << address->host.to_string() << ":" << address->port << "<br>\r\n";
|
||||
}
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
s << "<br>\r\n<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
||||
|
||||
|
@ -287,18 +287,29 @@ namespace http {
|
|||
s << "<b>Base64:</b><br>\r\n<textarea readonly=\"readonly\" cols=\"64\" rows=\"11\" wrap=\"on\">";
|
||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||
s << "<b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i><br>\r\n";
|
||||
if(dest->GetNumRemoteLeaseSets())
|
||||
{
|
||||
s << "<div class='slide'\r\n><label for='slide1'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n";
|
||||
for(auto& it: dest->GetLeaseSets ())
|
||||
s << it.second->GetIdentHash ().ToBase32 () << "<br>\r\n";
|
||||
s << "</p>\r\n</div>\r\n";
|
||||
}
|
||||
auto pool = dest->GetTunnelPool ();
|
||||
if (pool)
|
||||
{
|
||||
s << "<b>Inbound tunnels:</b><br>\r\n";
|
||||
for (auto & it : pool->GetInboundTunnels ()) {
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||
ShowTunnelDetails(s, it->GetState (), it->GetNumReceivedBytes ());
|
||||
}
|
||||
s << "<br>\r\n";
|
||||
s << "<b>Outbound tunnels:</b><br>\r\n";
|
||||
for (auto & it : pool->GetOutboundTunnels ()) {
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||
ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ());
|
||||
}
|
||||
}
|
||||
|
@ -394,12 +405,16 @@ namespace http {
|
|||
s << "<b>Inbound tunnels:</b><br>\r\n";
|
||||
for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) {
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||
ShowTunnelDetails(s, it->GetState (), it->GetNumReceivedBytes ());
|
||||
}
|
||||
s << "<br>\r\n";
|
||||
s << "<b>Outbound tunnels:</b><br>\r\n";
|
||||
for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) {
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||
ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ());
|
||||
}
|
||||
s << "<br>\r\n";
|
||||
|
|
|
@ -488,7 +488,7 @@ namespace data
|
|||
switch (m_Public->GetSigningKeyType ())
|
||||
{
|
||||
case SIGNING_KEY_TYPE_DSA_SHA1:
|
||||
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey));
|
||||
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
|
||||
break;
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||
m_Signer.reset (new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey));
|
||||
|
|
103
NetDb.cpp
103
NetDb.cpp
|
@ -14,6 +14,7 @@
|
|||
#include "RouterContext.h"
|
||||
#include "Garlic.h"
|
||||
#include "NetDb.h"
|
||||
#include "Config.h"
|
||||
|
||||
using namespace i2p::transport;
|
||||
|
||||
|
@ -23,7 +24,7 @@ namespace data
|
|||
{
|
||||
NetDb netdb;
|
||||
|
||||
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_HiddenMode(false)
|
||||
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -140,6 +141,8 @@ namespace data
|
|||
LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed");
|
||||
break;
|
||||
}
|
||||
else // we have peers now
|
||||
m_FloodfillBootstrap = nullptr;
|
||||
if (numRouters < 2500 || ts - lastExploratory >= 90)
|
||||
{
|
||||
numRouters = 800/numRouters;
|
||||
|
@ -185,23 +188,34 @@ namespace data
|
|||
// TODO: check if floodfill has been changed
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64());
|
||||
|
||||
updated = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = std::make_shared<RouterInfo> (buf, len);
|
||||
if (!r->IsUnreachable ())
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||
bool inserted = false;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
m_RouterInfos[r->GetIdentHash ()] = r;
|
||||
inserted = m_RouterInfos.insert ({r->GetIdentHash (), r}).second;
|
||||
}
|
||||
if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
|
||||
if (inserted)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.push_back (r);
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||
if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.push_back (r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Duplicated RouterInfo ", ident.ToBase64());
|
||||
updated = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -295,13 +309,62 @@ namespace data
|
|||
m_Reseeder = new Reseeder ();
|
||||
m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification
|
||||
}
|
||||
int reseedRetries = 0;
|
||||
int reseedRetries = 0;
|
||||
|
||||
// try reseeding from floodfill first if specified
|
||||
std::string riPath;
|
||||
if(i2p::config::GetOption("reseed.floodfill", riPath)) {
|
||||
auto ri = std::make_shared<RouterInfo>(riPath);
|
||||
if (ri->IsFloodfill()) {
|
||||
const uint8_t * riData = ri->GetBuffer();
|
||||
int riLen = ri->GetBufferLen();
|
||||
if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) {
|
||||
// bad router info
|
||||
LogPrint(eLogError, "NetDb: bad router info");
|
||||
return;
|
||||
}
|
||||
m_FloodfillBootstrap = ri;
|
||||
ReseedFromFloodfill(*ri);
|
||||
// don't try reseed servers if trying to boostrap from floodfill
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (reseedRetries < 10 && !m_Reseeder->ReseedNowSU3 ())
|
||||
reseedRetries++;
|
||||
if (reseedRetries >= 10)
|
||||
LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts");
|
||||
}
|
||||
|
||||
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
|
||||
{
|
||||
LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64());
|
||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > requests;
|
||||
|
||||
i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
|
||||
i2p::data::IdentHash ih = ri.GetIdentHash();
|
||||
i2p::data::IdentHash randomIdent;
|
||||
|
||||
// make floodfill lookups
|
||||
while(numFloodfills > 0) {
|
||||
randomIdent.Randomize();
|
||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, false);
|
||||
requests.push_back(msg);
|
||||
numFloodfills --;
|
||||
}
|
||||
|
||||
// make regular router lookups
|
||||
while(numRouters > 0) {
|
||||
randomIdent.Randomize();
|
||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, true);
|
||||
requests.push_back(msg);
|
||||
numRouters --;
|
||||
}
|
||||
|
||||
// send them off
|
||||
i2p::transport::transports.SendMessages(ih, requests);
|
||||
}
|
||||
|
||||
bool NetDb::LoadRouterInfo (const std::string & path)
|
||||
{
|
||||
auto r = std::make_shared<RouterInfo>(path);
|
||||
|
@ -498,6 +561,21 @@ namespace data
|
|||
m_Requests.RequestComplete (destination, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete)
|
||||
{
|
||||
|
||||
auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already");
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64());
|
||||
// direct
|
||||
transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
|
||||
}
|
||||
|
||||
|
||||
void NetDb::HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> m)
|
||||
{
|
||||
|
@ -620,7 +698,7 @@ namespace data
|
|||
if (!dest->IsExploratory ())
|
||||
{
|
||||
// reply to our destination. Try other floodfills
|
||||
if (outbound && inbound )
|
||||
if (outbound && inbound)
|
||||
{
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
auto count = dest->GetExcludedPeers ().size ();
|
||||
|
@ -664,7 +742,7 @@ namespace data
|
|||
// no more requests for detination possible. delete it
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
}
|
||||
else
|
||||
else if(!m_FloodfillBootstrap)
|
||||
LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found");
|
||||
|
||||
// try responses
|
||||
|
@ -681,7 +759,10 @@ namespace data
|
|||
{
|
||||
// router with ident not found or too old (1 hour)
|
||||
LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ...");
|
||||
RequestDestination (router);
|
||||
if(m_FloodfillBootstrap)
|
||||
RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true);
|
||||
else
|
||||
RequestDestination (router);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "NetDb: [:|||:]");
|
||||
|
|
9
NetDb.h
9
NetDb.h
|
@ -60,6 +60,7 @@ namespace data
|
|||
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
|
||||
|
||||
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
|
||||
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
|
@ -98,6 +99,9 @@ namespace data
|
|||
void VisitRouterInfos(RouterInfoVisitor v);
|
||||
/** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */
|
||||
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
|
||||
|
||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||
|
||||
private:
|
||||
|
||||
void Load ();
|
||||
|
@ -110,6 +114,8 @@ namespace data
|
|||
void ManageRequests ();
|
||||
void ManageLookupResponses ();
|
||||
|
||||
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||
|
||||
|
@ -135,6 +141,9 @@ namespace data
|
|||
friend class NetDbRequests;
|
||||
NetDbRequests m_Requests;
|
||||
|
||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
||||
|
||||
std::map<IdentHash, std::pair<std::vector<IdentHash>, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp)
|
||||
|
||||
/** true if in hidden mode */
|
||||
|
|
|
@ -11,10 +11,15 @@ namespace data
|
|||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||
{
|
||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
std::shared_ptr<I2NPMessage> msg;
|
||||
if(replyTunnel)
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
|
||||
&m_ExcludedPeers);
|
||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||
else
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
|
||||
if(router)
|
||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
return msg;
|
||||
}
|
||||
|
|
34
Reseed.cpp
34
Reseed.cpp
|
@ -305,6 +305,34 @@ namespace data
|
|||
if (end - contentPos >= contentLength)
|
||||
break; // we are beyond contentLength
|
||||
}
|
||||
if (numFiles) // check if routers are not outdated
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
int numOutdated = 0;
|
||||
i2p::data::netdb.VisitRouterInfos (
|
||||
[&numOutdated, ts](std::shared_ptr<const RouterInfo> r)
|
||||
{
|
||||
if (r && ts > r->GetTimestamp () + 10*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 270 hours
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours");
|
||||
numOutdated++;
|
||||
}
|
||||
});
|
||||
if (numOutdated > numFiles/2) // more than half
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: mammoth's shit\n"
|
||||
" *_____*\n"
|
||||
" *_*****_*\n"
|
||||
" *_(O)_(O)_*\n"
|
||||
" **____V____**\n"
|
||||
" **_________**\n"
|
||||
" **_________**\n"
|
||||
" *_________*\n"
|
||||
" ***___***");
|
||||
i2p::data::netdb.ClearRouterInfos ();
|
||||
numFiles = 0;
|
||||
}
|
||||
}
|
||||
return numFiles;
|
||||
}
|
||||
|
||||
|
@ -350,9 +378,11 @@ namespace data
|
|||
if (terminator) terminator[0] = 0;
|
||||
}
|
||||
// extract RSA key (we need n only, e = 65537)
|
||||
RSA * key = X509_get_pubkey (cert)->pkey.rsa;
|
||||
RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
|
||||
const BIGNUM * n, * e, * d;
|
||||
RSA_get0_key(key, &n, &e, &d);
|
||||
PublicKey value;
|
||||
i2p::crypto::bn2buf (key->n, value, 512);
|
||||
i2p::crypto::bn2buf (n, value, 512);
|
||||
if (cn)
|
||||
m_SigningKeys[cn] = value;
|
||||
else
|
||||
|
|
18
Signature.h
18
Signature.h
|
@ -77,10 +77,11 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
DSASigner (const uint8_t * signingPrivateKey)
|
||||
DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||
// openssl 1.1 always requires DSA public key even for signing
|
||||
{
|
||||
m_PrivateKey = CreateDSA ();
|
||||
DSA_set0_key (m_PrivateKey, NULL, BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
|
||||
DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
|
||||
}
|
||||
|
||||
~DSASigner ()
|
||||
|
@ -169,8 +170,9 @@ namespace crypto
|
|||
uint8_t digest[Hash::hashLen];
|
||||
Hash::CalculateHash (buf, len, digest);
|
||||
ECDSA_SIG * sig = ECDSA_SIG_new();
|
||||
sig->r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL);
|
||||
sig->s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
|
||||
auto r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL);
|
||||
auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
|
||||
ECDSA_SIG_set0(sig, r, s);
|
||||
// ECDSA verification
|
||||
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey);
|
||||
ECDSA_SIG_free(sig);
|
||||
|
@ -207,9 +209,11 @@ namespace crypto
|
|||
uint8_t digest[Hash::hashLen];
|
||||
Hash::CalculateHash (buf, len, digest);
|
||||
ECDSA_SIG * sig = ECDSA_do_sign (digest, Hash::hashLen, m_PrivateKey);
|
||||
const BIGNUM * r, * s;
|
||||
ECDSA_SIG_get0 (sig, &r, &s);
|
||||
// signatureLen = keyLen
|
||||
bn2buf (sig->r, signature, keyLen/2);
|
||||
bn2buf (sig->s, signature + keyLen/2, keyLen/2);
|
||||
bn2buf (r, signature, keyLen/2);
|
||||
bn2buf (s, signature + keyLen/2, keyLen/2);
|
||||
ECDSA_SIG_free(sig);
|
||||
}
|
||||
|
||||
|
@ -271,7 +275,6 @@ namespace crypto
|
|||
RSAVerifier (const uint8_t * signingKey)
|
||||
{
|
||||
m_PublicKey = RSA_new ();
|
||||
memset (m_PublicKey, 0, sizeof (RSA));
|
||||
RSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, keyLen, NULL) /* n */ , BN_dup (GetRSAE ()) /* d */, NULL);
|
||||
}
|
||||
|
||||
|
@ -304,7 +307,6 @@ namespace crypto
|
|||
RSASigner (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
m_PrivateKey = RSA_new ();
|
||||
memset (m_PrivateKey, 0, sizeof (RSA));
|
||||
RSA_set0_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen, NULL), /* n */
|
||||
BN_dup (GetRSAE ()) /* e */, BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL) /* d */);
|
||||
}
|
||||
|
|
8
Tag.h
8
Tag.h
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <string.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "Base.h"
|
||||
|
||||
namespace i2p {
|
||||
|
@ -49,7 +50,12 @@ public:
|
|||
{
|
||||
memset(m_Buf, c, sz);
|
||||
}
|
||||
|
||||
|
||||
void Randomize()
|
||||
{
|
||||
RAND_bytes(m_Buf, sz);
|
||||
}
|
||||
|
||||
std::string ToBase64 () const
|
||||
{
|
||||
char str[sz*2];
|
||||
|
|
|
@ -108,7 +108,8 @@ namespace transport
|
|||
Transports transports;
|
||||
|
||||
Transports::Transports ():
|
||||
m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_PeerCleanupTimer (m_Service),
|
||||
m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
|
||||
m_PeerCleanupTimer (m_Service), m_PeerTestTimer (m_Service),
|
||||
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
|
||||
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_InBandwidth (0), m_OutBandwidth (0),
|
||||
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
|
||||
|
@ -168,11 +169,14 @@ namespace transport
|
|||
}
|
||||
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||
m_PeerTestTimer.expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
||||
m_PeerTestTimer.async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void Transports::Stop ()
|
||||
{
|
||||
m_PeerCleanupTimer.cancel ();
|
||||
m_PeerTestTimer.cancel ();
|
||||
m_Peers.clear ();
|
||||
if (m_SSUServer)
|
||||
{
|
||||
|
@ -256,7 +260,8 @@ namespace transport
|
|||
{
|
||||
// we send it to ourself
|
||||
for (auto& it: msgs)
|
||||
i2p::HandleI2NPMessage (it);
|
||||
m_LoopbackHandler.PutNextMessage (it);
|
||||
m_LoopbackHandler.Flush ();
|
||||
return;
|
||||
}
|
||||
if(RoutesRestricted() && ! IsRestrictedPeer(ident)) return;
|
||||
|
@ -546,8 +551,7 @@ namespace transport
|
|||
{
|
||||
if (RoutesRestricted()) return;
|
||||
if (m_SSUServer)
|
||||
{
|
||||
|
||||
{
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
|
@ -688,6 +692,16 @@ namespace transport
|
|||
}
|
||||
}
|
||||
|
||||
void Transports::HandlePeerTestTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
PeerTest ();
|
||||
m_PeerTestTimer.expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
||||
m_PeerTestTimer.async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
|
||||
{
|
||||
if (m_Peers.empty ()) return nullptr;
|
||||
|
|
20
Transports.h
20
Transports.h
|
@ -66,6 +66,7 @@ namespace transport
|
|||
};
|
||||
|
||||
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
|
||||
const int PEER_TEST_INTERVAL = 71; // in minutes
|
||||
const int MAX_NUM_DELAYED_MESSAGES = 50;
|
||||
class Transports
|
||||
{
|
||||
|
@ -127,7 +128,8 @@ namespace transport
|
|||
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
||||
|
||||
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
|
||||
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||
|
@ -144,7 +146,7 @@ namespace transport
|
|||
std::thread * m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_service::work m_Work;
|
||||
boost::asio::deadline_timer m_PeerCleanupTimer;
|
||||
boost::asio::deadline_timer m_PeerCleanupTimer, m_PeerTestTimer;
|
||||
|
||||
NTCPServer * m_NTCPServer;
|
||||
SSUServer * m_SSUServer;
|
||||
|
@ -158,13 +160,15 @@ namespace transport
|
|||
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes;
|
||||
uint64_t m_LastBandwidthUpdateTime;
|
||||
|
||||
/** which router families to trust for first hops */
|
||||
std::vector<std::string> m_TrustedFamilies;
|
||||
mutable std::mutex m_FamilyMutex;
|
||||
/** 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;
|
||||
/** which routers for first hop to trust */
|
||||
std::vector<i2p::data::IdentHash> m_TrustedRouters;
|
||||
mutable std::mutex m_TrustedRoutersMutex;
|
||||
|
||||
i2p::I2NPMessagesHandler m_LoopbackHandler;
|
||||
|
||||
public:
|
||||
|
||||
|
|
36
Tunnel.cpp
36
Tunnel.cpp
|
@ -21,6 +21,31 @@ namespace i2p
|
|||
namespace tunnel
|
||||
{
|
||||
|
||||
void TunnelLatency::AddSample(Sample s)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_access);
|
||||
m_samples.push_back(s);
|
||||
}
|
||||
|
||||
bool TunnelLatency::HasSamples() const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_access);
|
||||
return m_samples.size() > 0;
|
||||
}
|
||||
|
||||
TunnelLatency::Latency TunnelLatency::GetMeanLatency() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_access);
|
||||
if (m_samples.size() > 0) {
|
||||
Latency l = 0;
|
||||
for(auto s : m_samples)
|
||||
l += s;
|
||||
return l / m_samples.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
|
||||
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
|
||||
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
|
||||
|
@ -162,6 +187,12 @@ namespace tunnel
|
|||
return established;
|
||||
}
|
||||
|
||||
bool Tunnel::LatencyFitsRange(uint64_t lower, uint64_t upper) const
|
||||
{
|
||||
auto latency = GetMeanLatency();
|
||||
return latency >= lower && latency <= upper;
|
||||
}
|
||||
|
||||
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
|
||||
{
|
||||
const uint8_t * inPayload = in->GetPayload () + 4;
|
||||
|
@ -714,6 +745,8 @@ namespace tunnel
|
|||
|
||||
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
|
||||
tunnel->SetState (eTunnelStateExpiring);
|
||||
else // we don't need to cleanup expiring tunnels
|
||||
tunnel->Cleanup ();
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
@ -763,7 +796,10 @@ namespace tunnel
|
|||
it = m_TransitTunnels.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
tunnel->Cleanup ();
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
28
Tunnel.h
28
Tunnel.h
|
@ -79,6 +79,21 @@ namespace tunnel
|
|||
eTunnelStateExpiring
|
||||
};
|
||||
|
||||
/** @brief for storing latency history */
|
||||
struct TunnelLatency
|
||||
{
|
||||
typedef uint64_t Sample;
|
||||
typedef uint64_t Latency;
|
||||
|
||||
|
||||
void AddSample(Sample s);
|
||||
bool HasSamples() const;
|
||||
Latency GetMeanLatency() const;
|
||||
|
||||
std::vector<Sample> m_samples;
|
||||
mutable std::mutex m_access;
|
||||
};
|
||||
|
||||
class OutboundTunnel;
|
||||
class InboundTunnel;
|
||||
class Tunnel: public TunnelBase
|
||||
|
@ -118,6 +133,14 @@ namespace tunnel
|
|||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||
|
||||
/** @brief add latency sample */
|
||||
void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); }
|
||||
/** @brief get this tunnel's estimated latency */
|
||||
uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); }
|
||||
/** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
|
||||
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
|
||||
|
||||
bool LatencyIsKnown() const { return m_Latency.HasSamples(); }
|
||||
protected:
|
||||
|
||||
void PrintHops (std::stringstream& s) const;
|
||||
|
@ -129,6 +152,7 @@ namespace tunnel
|
|||
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
|
||||
TunnelState m_State;
|
||||
bool m_IsRecreated;
|
||||
TunnelLatency m_Latency;
|
||||
};
|
||||
|
||||
class OutboundTunnel: public Tunnel
|
||||
|
@ -165,6 +189,10 @@ namespace tunnel
|
|||
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
|
||||
void Print (std::stringstream& s) const;
|
||||
bool IsInbound() const { return true; }
|
||||
|
||||
// override TunnelBase
|
||||
void Cleanup () { m_Endpoint.Cleanup (); };
|
||||
|
||||
private:
|
||||
|
||||
TunnelEndpoint m_Endpoint;
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace tunnel
|
|||
m_TunnelID (tunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent),
|
||||
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
|
||||
virtual ~TunnelBase () {};
|
||||
virtual void Cleanup () {};
|
||||
|
||||
virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0;
|
||||
virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "I2NPProtocol.h"
|
||||
#include "Transports.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Timestamp.h"
|
||||
#include "TunnelEndpoint.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -192,7 +193,7 @@ namespace tunnel
|
|||
|
||||
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data)
|
||||
{
|
||||
if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {fragmentNum, isLastFragment, data}}).second)
|
||||
if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {isLastFragment, data, i2p::util::GetMillisecondsSinceEpoch () }}).second)
|
||||
LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID);
|
||||
}
|
||||
|
||||
|
@ -213,30 +214,25 @@ namespace tunnel
|
|||
{
|
||||
auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum});
|
||||
if (it != m_OutOfSequenceFragments.end ())
|
||||
{
|
||||
if (it->second.fragmentNum == msg.nextFragmentNum)
|
||||
{
|
||||
LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found");
|
||||
size_t size = it->second.data->GetLength ();
|
||||
if (msg.data->len + size > msg.data->maxLen)
|
||||
{
|
||||
LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found");
|
||||
size_t size = it->second.data->GetLength ();
|
||||
if (msg.data->len + size > msg.data->maxLen)
|
||||
{
|
||||
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *(msg.data);
|
||||
msg.data = newMsg;
|
||||
}
|
||||
if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment
|
||||
LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
|
||||
if (it->second.isLastFragment)
|
||||
// message complete
|
||||
msg.nextFragmentNum = 0;
|
||||
else
|
||||
msg.nextFragmentNum++;
|
||||
m_OutOfSequenceFragments.erase (it);
|
||||
return true;
|
||||
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *(msg.data);
|
||||
msg.data = newMsg;
|
||||
}
|
||||
if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment
|
||||
LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
|
||||
if (it->second.isLastFragment)
|
||||
// message complete
|
||||
msg.nextFragmentNum = 0;
|
||||
else
|
||||
LogPrint (eLogError, "Tunnel message: next fragment ", (int)it->second.fragmentNum, " of message ", msgID, " mismatch. ", (int)msg.nextFragmentNum, " expected");
|
||||
msg.nextFragmentNum++;
|
||||
m_OutOfSequenceFragments.erase (it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -275,6 +271,19 @@ namespace tunnel
|
|||
default:
|
||||
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
||||
};
|
||||
}
|
||||
|
||||
void TunnelEndpoint::Cleanup ()
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
// out-of-sequence fragments
|
||||
for (auto it = m_OutOfSequenceFragments.begin (); it != m_OutOfSequenceFragments.end ();)
|
||||
{
|
||||
if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
|
||||
it = m_OutOfSequenceFragments.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ namespace tunnel
|
|||
|
||||
struct Fragment
|
||||
{
|
||||
uint8_t fragmentNum;
|
||||
bool isLastFragment;
|
||||
std::shared_ptr<I2NPMessage> data;
|
||||
uint64_t receiveTime; // milliseconds since epoch
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -30,7 +30,8 @@ namespace tunnel
|
|||
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {};
|
||||
~TunnelEndpoint ();
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
|
||||
void Cleanup ();
|
||||
|
||||
void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
private:
|
||||
|
|
|
@ -147,13 +147,13 @@ namespace tunnel
|
|||
|
||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded) const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
return GetNextTunnel (m_OutboundTunnels, excluded);
|
||||
}
|
||||
|
||||
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded) const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
return GetNextTunnel (m_InboundTunnels, excluded);
|
||||
}
|
||||
|
||||
|
@ -167,11 +167,27 @@ namespace tunnel
|
|||
{
|
||||
if (it->IsEstablished () && it != excluded)
|
||||
{
|
||||
if(HasLatencyRequirement() && it->LatencyIsKnown() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) {
|
||||
i ++;
|
||||
continue;
|
||||
}
|
||||
tunnel = it;
|
||||
i++;
|
||||
}
|
||||
if (i > ind && tunnel) break;
|
||||
}
|
||||
if(HasLatencyRequirement() && !tunnel) {
|
||||
ind = rand () % (tunnels.size ()/2 + 1), i = 0;
|
||||
for (const auto& it: tunnels)
|
||||
{
|
||||
if (it->IsEstablished () && it != excluded)
|
||||
{
|
||||
tunnel = it;
|
||||
i++;
|
||||
}
|
||||
if (i > ind && tunnel) break;
|
||||
}
|
||||
}
|
||||
if (!tunnel && excluded && excluded->IsEstablished ()) tunnel = excluded;
|
||||
return tunnel;
|
||||
}
|
||||
|
@ -199,15 +215,6 @@ namespace tunnel
|
|||
void TunnelPool::CreateTunnels ()
|
||||
{
|
||||
int num = 0;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
for (const auto& it : m_InboundTunnels)
|
||||
if (it->IsEstablished ()) num++;
|
||||
}
|
||||
for (int i = num; i < m_NumInboundTunnels; i++)
|
||||
CreateInboundTunnel ();
|
||||
|
||||
num = 0;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
for (const auto& it : m_OutboundTunnels)
|
||||
|
@ -215,6 +222,18 @@ namespace tunnel
|
|||
}
|
||||
for (int i = num; i < m_NumOutboundTunnels; i++)
|
||||
CreateOutboundTunnel ();
|
||||
|
||||
num = 0;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
for (const auto& it : m_InboundTunnels)
|
||||
if (it->IsEstablished ()) num++;
|
||||
}
|
||||
for (int i = num; i < m_NumInboundTunnels; i++)
|
||||
CreateInboundTunnel ();
|
||||
|
||||
if (num > 0 && m_NumInboundHops <= 0 && m_LocalDestination) // zero hops IB
|
||||
m_LocalDestination->SetLeaseSetUpdated (); // update LeaseSet immediately
|
||||
}
|
||||
|
||||
void TunnelPool::TestTunnels ()
|
||||
|
@ -322,7 +341,12 @@ namespace tunnel
|
|||
test.first->SetState (eTunnelStateEstablished);
|
||||
if (test.second->GetState () == eTunnelStateTestFailed)
|
||||
test.second->SetState (eTunnelStateEstablished);
|
||||
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
|
||||
uint64_t dlt = i2p::util::GetMillisecondsSinceEpoch () - timestamp;
|
||||
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", dlt, " milliseconds");
|
||||
// update latency
|
||||
uint64_t latency = dlt / 2;
|
||||
test.first->AddLatencySample(latency);
|
||||
test.second->AddLatencySample(latency);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -523,5 +547,37 @@ namespace tunnel
|
|||
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
|
||||
return m_CustomPeerSelector != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<InboundTunnel> TunnelPool::GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude) const
|
||||
{
|
||||
std::shared_ptr<InboundTunnel> tun = nullptr;
|
||||
std::unique_lock<std::mutex> lock(m_InboundTunnelsMutex);
|
||||
uint64_t min = 1000000;
|
||||
for (const auto & itr : m_InboundTunnels) {
|
||||
if(!itr->LatencyIsKnown()) continue;
|
||||
auto l = itr->GetMeanLatency();
|
||||
if (l >= min) continue;
|
||||
tun = itr;
|
||||
if(tun == exclude) continue;
|
||||
min = l;
|
||||
}
|
||||
return tun;
|
||||
}
|
||||
|
||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude) const
|
||||
{
|
||||
std::shared_ptr<OutboundTunnel> tun = nullptr;
|
||||
std::unique_lock<std::mutex> lock(m_OutboundTunnelsMutex);
|
||||
uint64_t min = 1000000;
|
||||
for (const auto & itr : m_OutboundTunnels) {
|
||||
if(!itr->LatencyIsKnown()) continue;
|
||||
auto l = itr->GetMeanLatency();
|
||||
if (l >= min) continue;
|
||||
tun = itr;
|
||||
if(tun == exclude) continue;
|
||||
min = l;
|
||||
}
|
||||
return tun;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
TunnelPool.h
15
TunnelPool.h
|
@ -69,6 +69,17 @@ namespace tunnel
|
|||
void SetCustomPeerSelector(TunnelPeerSelector selector);
|
||||
void UnsetCustomPeerSelector();
|
||||
bool HasCustomPeerSelector();
|
||||
|
||||
/** @brief make this tunnel pool yield tunnels that fit latency range [min, max] */
|
||||
void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; }
|
||||
|
||||
/** @brief return true if this tunnel pool has a latency requirement */
|
||||
bool HasLatencyRequirement() const { return m_MinLatency > 0 && m_MaxLatency > 0; }
|
||||
|
||||
/** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */
|
||||
std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude=nullptr) const;
|
||||
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
|
||||
|
||||
private:
|
||||
|
||||
void CreateInboundTunnel ();
|
||||
|
@ -94,6 +105,10 @@ namespace tunnel
|
|||
bool m_IsActive;
|
||||
std::mutex m_CustomPeerSelectorMutex;
|
||||
TunnelPeerSelector m_CustomPeerSelector;
|
||||
|
||||
uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
|
||||
uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
|
|
6
debian/changelog
vendored
6
debian/changelog
vendored
|
@ -1,3 +1,9 @@
|
|||
i2pd (2.10.1-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.10.1
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 7 Nov 2016 14:18:30 +0000
|
||||
|
||||
i2pd (2.10.0-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.10.0/0.9.27
|
||||
|
|
|
@ -30,16 +30,16 @@ Where $ARCH is `i686` or `x86_64` (matching your system).
|
|||
- 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
|
||||
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
|
||||
|
||||
|
|
114
docs/hacking.md
Normal file
114
docs/hacking.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
|
||||
# Hacking on I2PD
|
||||
|
||||
This document contains notes compiled from hacking on i2pd
|
||||
|
||||
## prerequisites
|
||||
|
||||
This guide assumes:
|
||||
|
||||
* a decent understanding of c++
|
||||
* basic understanding of how i2p works at i2np level and up
|
||||
|
||||
## general structure
|
||||
|
||||
Notes on multithreading
|
||||
|
||||
* every compontent runs in its own thread
|
||||
|
||||
* each component (usually) has a public function `GetService()` which can be used to obtain the `boost::asio::io_service` that it uses.
|
||||
|
||||
* when talking between components/threads, **always** use `GetService().post()` and be mindfull of stack allocated memory.
|
||||
|
||||
|
||||
### NetDb
|
||||
|
||||
#### NetDb.h
|
||||
|
||||
The `i2p::data::netdb` is a `i2p::data::NetDb` instance processes and dispatches *inbound* i2np messages passed in from transports.
|
||||
|
||||
global singleton at `i2p::data::netdb` as of 2.10.1
|
||||
|
||||
#### NetDbRequests.h
|
||||
|
||||
For Pending RouterInfo/LeaseSet lookup and store requests
|
||||
|
||||
|
||||
### ClientContext
|
||||
|
||||
#### ClientContext.h
|
||||
|
||||
`i2p::client::ClientContext` spawns all destinations used by the i2p router including the shared local destination.
|
||||
|
||||
global singleton at `i2p::client::context` as of 2.10.1
|
||||
|
||||
|
||||
|
||||
### Daemon
|
||||
|
||||
File: Daemon.cpp
|
||||
|
||||
`i2p::util::Daemon_Singleton_Private` subclasses implement the daemon start-up and tear-down, creates Http Webui and i2p control server.
|
||||
|
||||
|
||||
|
||||
|
||||
### Destinations
|
||||
|
||||
#### Destination.h
|
||||
|
||||
each destination runs in its own thread
|
||||
|
||||
##### i2p::client::LeaseSetDestination
|
||||
|
||||
Base for `i2p::client::ClientDestination`
|
||||
|
||||
##### i2p::client::ClientDestination
|
||||
|
||||
Destination capable of creating (tcp/i2p) streams and datagram sessions.
|
||||
|
||||
|
||||
#### Streaming.h
|
||||
|
||||
##### i2p::stream::StreamingDestination
|
||||
|
||||
Does not implement any destination related members, the name is a bit misleading.
|
||||
|
||||
Owns a `i2p::client::ClientDestination` and runs in the destination thread.
|
||||
|
||||
Anyone creating or using streams outside of the destination thread **MUST** be aware of the consequences of multithreaded c++ :^)
|
||||
|
||||
If you use streaming please consider running all code within the destination thread using `ClientDestination::GetService().post()`
|
||||
|
||||
|
||||
#### Garlic.h
|
||||
|
||||
Provides Inter-Destination routing primatives.
|
||||
|
||||
##### i2p::garlic::GarlicDestination
|
||||
|
||||
sublcass of `i2p::client::LeaseSetDestination` for sending messages down shared routing paths.
|
||||
|
||||
##### i2p::garlic::GarlicRoutingSession
|
||||
|
||||
a point to point conversation between us and 1 other destination.
|
||||
|
||||
##### i2p::garlic::GarlicRoutingPath
|
||||
|
||||
A routing path currently used by a routing session. specifies which outbound tunnel to use and which remote lease set to use for `OBEP` to `IBGW` inter tunnel communication.
|
||||
|
||||
members:
|
||||
|
||||
* outboundTunnel (OBEP)
|
||||
* remoteLease (IBGW)
|
||||
* rtt (round trip time)
|
||||
* updatedTime (last time this path's IBGW/OBEP was updated)
|
||||
* numTimesUsesd (number of times this path was used)
|
||||
|
||||
### Transports
|
||||
|
||||
each transport runs in its own thread
|
||||
|
||||
#### Transports.h
|
||||
|
||||
`i2p::transport::Transports` contains NTCP and SSU transport instances
|
|
@ -23,12 +23,12 @@ To display all available options:
|
|||
i2pd can be controlled with signals. Process ID by default is written to file `~/.i2pd/i2pd.pid` or `/var/run/i2pd/i2pd.pid`.
|
||||
You can use `kill` utility to send signals like this:
|
||||
|
||||
kill -TERM $( cat /var/run/i2pd/i2pd.pid )
|
||||
kill -INT $( cat /var/run/i2pd/i2pd.pid )
|
||||
|
||||
i2pd supports the following signals:
|
||||
|
||||
TERM - Graceful shutdown. i2pd will wait for 10 minutes and stop. Send second TERM signal to shutdown i2pd immediately.
|
||||
HUP - Reload configuration files.
|
||||
* INT - Graceful shutdown. i2pd will wait for 10 minutes and stop. Send second INT signal to shutdown i2pd immediately.
|
||||
* HUP - Reload configuration files.
|
||||
|
||||
|
||||
### systemd unit
|
||||
|
@ -48,7 +48,7 @@ Enable/disable i2pd to be started on bootup:
|
|||
|
||||
## Configuring i2pd
|
||||
|
||||
See [configuration page](i2pd.readthedocs.io/page/configuration.html).
|
||||
See [configuration documentation](/page/configuration.html).
|
||||
|
||||
|
||||
## Browsing and hosting websites
|
||||
|
|
Loading…
Reference in a new issue