mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-10 19:38:28 +01:00
Merge branch 'PurpleI2P:openssl' into fuzzing-1
This commit is contained in:
commit
800ea5f8be
26 changed files with 277 additions and 141 deletions
2
.github/workflows/build-windows-msvc.yml
vendored
2
.github/workflows/build-windows-msvc.yml
vendored
|
@ -29,7 +29,7 @@ jobs:
|
||||||
- name: Install Boost
|
- name: Install Boost
|
||||||
uses: crazy-max/ghaction-chocolatey@v2
|
uses: crazy-max/ghaction-chocolatey@v2
|
||||||
with:
|
with:
|
||||||
args: install boost-msvc-14.3
|
args: install boost-msvc-14.3 --version=1.81.0
|
||||||
|
|
||||||
- name: Install OpenSSL
|
- name: Install OpenSSL
|
||||||
uses: crazy-max/ghaction-chocolatey@v2
|
uses: crazy-max/ghaction-chocolatey@v2
|
||||||
|
|
|
@ -145,18 +145,19 @@ namespace win32
|
||||||
s << bytes << " Bytes\n";
|
s << bytes << " Bytes\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status)
|
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing)
|
||||||
{
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case eRouterStatusOK: s << "OK"; break;
|
case eRouterStatusOK: s << "OK"; break;
|
||||||
case eRouterStatusTesting: s << "Test"; break;
|
|
||||||
case eRouterStatusFirewalled: s << "FW"; break;
|
case eRouterStatusFirewalled: s << "FW"; break;
|
||||||
case eRouterStatusUnknown: s << "Unk"; break;
|
case eRouterStatusUnknown: s << "Unk"; break;
|
||||||
case eRouterStatusProxy: s << "Proxy"; break;
|
case eRouterStatusProxy: s << "Proxy"; break;
|
||||||
case eRouterStatusMesh: s << "Mesh"; break;
|
case eRouterStatusMesh: s << "Mesh"; break;
|
||||||
default: s << "Unk";
|
default: s << "Unk";
|
||||||
};
|
};
|
||||||
|
if (testing)
|
||||||
|
s << " (Test)";
|
||||||
if (i2p::context.GetError () != eRouterErrorNone)
|
if (i2p::context.GetError () != eRouterErrorNone)
|
||||||
{
|
{
|
||||||
switch (i2p::context.GetError ())
|
switch (i2p::context.GetError ())
|
||||||
|
@ -179,11 +180,11 @@ namespace win32
|
||||||
{
|
{
|
||||||
s << "\n";
|
s << "\n";
|
||||||
s << "Status: ";
|
s << "Status: ";
|
||||||
ShowNetworkStatus (s, i2p::context.GetStatus ());
|
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting ());
|
||||||
if (i2p::context.SupportsV6 ())
|
if (i2p::context.SupportsV6 ())
|
||||||
{
|
{
|
||||||
s << " / ";
|
s << " / ";
|
||||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
|
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6 ());
|
||||||
}
|
}
|
||||||
s << "; ";
|
s << "; ";
|
||||||
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
||||||
|
|
|
@ -222,18 +222,19 @@ namespace http {
|
||||||
s << "<b>" << tr("ERROR") << ":</b> " << string << "<br>\r\n";
|
s << "<b>" << tr("ERROR") << ":</b> " << string << "<br>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error)
|
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error)
|
||||||
{
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case eRouterStatusOK: s << tr("OK"); break;
|
case eRouterStatusOK: s << tr("OK"); break;
|
||||||
case eRouterStatusTesting: s << tr("Testing"); break;
|
|
||||||
case eRouterStatusFirewalled: s << tr("Firewalled"); break;
|
case eRouterStatusFirewalled: s << tr("Firewalled"); break;
|
||||||
case eRouterStatusUnknown: s << tr("Unknown"); break;
|
case eRouterStatusUnknown: s << tr("Unknown"); break;
|
||||||
case eRouterStatusProxy: s << tr("Proxy"); break;
|
case eRouterStatusProxy: s << tr("Proxy"); break;
|
||||||
case eRouterStatusMesh: s << tr("Mesh"); break;
|
case eRouterStatusMesh: s << tr("Mesh"); break;
|
||||||
default: s << tr("Unknown");
|
default: s << tr("Unknown");
|
||||||
}
|
}
|
||||||
|
if (testing)
|
||||||
|
s << " (" << tr("Testing") << ")";
|
||||||
if (error != eRouterErrorNone)
|
if (error != eRouterErrorNone)
|
||||||
{
|
{
|
||||||
switch (error)
|
switch (error)
|
||||||
|
@ -264,12 +265,12 @@ namespace http {
|
||||||
ShowUptime(s, i2p::context.GetUptime ());
|
ShowUptime(s, i2p::context.GetUptime ());
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
s << "<b>" << tr("Network status") << ":</b> ";
|
s << "<b>" << tr("Network status") << ":</b> ";
|
||||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
|
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ());
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
if (i2p::context.SupportsV6 ())
|
if (i2p::context.SupportsV6 ())
|
||||||
{
|
{
|
||||||
s << "<b>" << tr("Network status v6") << ":</b> ";
|
s << "<b>" << tr("Network status v6") << ":</b> ";
|
||||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
|
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ());
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
}
|
}
|
||||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||||
|
|
|
@ -187,6 +187,9 @@ namespace data
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if(*InBuffer == P64)
|
||||||
|
return 0;
|
||||||
|
|
||||||
ps = (unsigned char *)(InBuffer + InCount - 1);
|
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||||
while ( *ps-- == P64 )
|
while ( *ps-- == P64 )
|
||||||
outCount--;
|
outCount--;
|
||||||
|
@ -298,7 +301,7 @@ namespace data
|
||||||
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
|
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
|
||||||
{
|
{
|
||||||
size_t ret = 0, pos = 1;
|
size_t ret = 0, pos = 1;
|
||||||
int bits = 8, tmp = inBuf[0];
|
unsigned int bits = 8, tmp = inBuf[0];
|
||||||
while (ret < outLen && (bits > 0 || pos < len))
|
while (ret < outLen && (bits > 0 || pos < len))
|
||||||
{
|
{
|
||||||
if (bits < 5)
|
if (bits < 5)
|
||||||
|
|
|
@ -991,7 +991,7 @@ namespace crypto
|
||||||
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
|
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
|
||||||
EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen);
|
EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen);
|
||||||
EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen);
|
EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen);
|
||||||
EVP_EncryptFinal_ex(ctx, buf, &outlen);
|
EVP_EncryptFinal_ex(ctx, buf + outlen, &outlen);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -581,7 +581,7 @@ namespace data
|
||||||
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
|
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
|
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
|
||||||
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
|
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
|
||||||
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
|
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey + (sizeof(Identity::signingKey) - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH))); // TODO: remove public key check
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// public key is not required
|
// public key is not required
|
||||||
|
|
|
@ -375,7 +375,16 @@ namespace transport
|
||||||
m_Server.RemoveNTCP2Session (shared_from_this ());
|
m_Server.RemoveNTCP2Session (shared_from_this ());
|
||||||
m_SendQueue.clear ();
|
m_SendQueue.clear ();
|
||||||
m_SendQueueSize = 0;
|
m_SendQueueSize = 0;
|
||||||
LogPrint (eLogDebug, "NTCP2: Session terminated");
|
auto remoteIdentity = GetRemoteIdentity ();
|
||||||
|
if (remoteIdentity)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (), " terminated");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,13 +700,22 @@ namespace transport
|
||||||
i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
|
i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
|
||||||
if (ri.IsUnreachable ())
|
if (ri.IsUnreachable ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed");
|
LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ());
|
||||||
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
|
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (i2p::util::GetMillisecondsSinceEpoch () > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed");
|
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
|
||||||
|
SendTerminationAndTerminate (eNTCP2Message3Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds");
|
||||||
SendTerminationAndTerminate (eNTCP2Message3Error);
|
SendTerminationAndTerminate (eNTCP2Message3Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -884,7 +902,7 @@ namespace transport
|
||||||
auto size = bufbe16toh (frame + offset);
|
auto size = bufbe16toh (frame + offset);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
|
LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
|
||||||
if (size > len)
|
if (offset + size > len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
|
LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
|
||||||
break;
|
break;
|
||||||
|
@ -1402,7 +1420,8 @@ namespace transport
|
||||||
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
|
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
|
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
|
||||||
GetService ().post([this, conn]()
|
GetService ().post([this, conn]()
|
||||||
{
|
{
|
||||||
if (this->AddNTCP2Session (conn))
|
if (this->AddNTCP2Session (conn))
|
||||||
|
@ -1458,7 +1477,8 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ());
|
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
|
||||||
conn->ClientLogin ();
|
conn->ClientLogin ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace data
|
||||||
{
|
{
|
||||||
Reseed ();
|
Reseed ();
|
||||||
}
|
}
|
||||||
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
|
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, false))
|
||||||
Reseed (); // we don't have a router we can connect to. Trying to reseed
|
Reseed (); // we don't have a router we can connect to. Trying to reseed
|
||||||
|
|
||||||
auto it = m_RouterInfos.find (i2p::context.GetIdentHash ());
|
auto it = m_RouterInfos.find (i2p::context.GetIdentHash ());
|
||||||
|
@ -424,12 +424,9 @@ namespace data
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
r->SetUnreachable (unreachable);
|
r->SetUnreachable (unreachable);
|
||||||
if (unreachable)
|
|
||||||
{
|
|
||||||
auto profile = r->GetProfile ();
|
auto profile = r->GetProfile ();
|
||||||
if (profile)
|
if (profile)
|
||||||
profile->Unreachable ();
|
profile->Unreachable (unreachable);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1203,15 +1200,17 @@ namespace data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
|
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
|
||||||
|
bool reverse, bool endpoint) const
|
||||||
{
|
{
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[compatibleWith, reverse](std::shared_ptr<const RouterInfo> router)->bool
|
[compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
{
|
{
|
||||||
return !router->IsHidden () && router != compatibleWith &&
|
return !router->IsHidden () && router != compatibleWith &&
|
||||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)):
|
||||||
router->IsReachableFrom (*compatibleWith)) &&
|
router->IsReachableFrom (*compatibleWith)) &&
|
||||||
router->IsECIES () && !router->IsHighCongestion (false);
|
router->IsECIES () && !router->IsHighCongestion (false) &&
|
||||||
|
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1235,17 +1234,20 @@ namespace data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
|
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
|
||||||
|
bool reverse, bool endpoint) const
|
||||||
{
|
{
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[compatibleWith, reverse](std::shared_ptr<const RouterInfo> router)->bool
|
[compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
{
|
{
|
||||||
return !router->IsHidden () && router != compatibleWith &&
|
return !router->IsHidden () && router != compatibleWith &&
|
||||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)) :
|
||||||
router->IsReachableFrom (*compatibleWith)) &&
|
router->IsReachableFrom (*compatibleWith)) &&
|
||||||
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
||||||
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
||||||
router->IsECIES () && !router->IsHighCongestion (true);
|
router->IsECIES () && !router->IsHighCongestion (true) &&
|
||||||
|
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1257,7 +1259,9 @@ namespace data
|
||||||
uint16_t inds[3];
|
uint16_t inds[3];
|
||||||
RAND_bytes ((uint8_t *)inds, sizeof (inds));
|
RAND_bytes ((uint8_t *)inds, sizeof (inds));
|
||||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||||
inds[0] %= m_RouterInfos.size ();
|
auto count = m_RouterInfos.size ();
|
||||||
|
if(count == 0) return nullptr;
|
||||||
|
inds[0] %= count;
|
||||||
auto it = m_RouterInfos.begin ();
|
auto it = m_RouterInfos.begin ();
|
||||||
std::advance (it, inds[0]);
|
std::advance (it, inds[0]);
|
||||||
// try random router
|
// try random router
|
||||||
|
|
|
@ -84,8 +84,8 @@ namespace data
|
||||||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||||
|
|
|
@ -165,9 +165,9 @@ namespace data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterProfile::Unreachable ()
|
void RouterProfile::Unreachable (bool unreachable)
|
||||||
{
|
{
|
||||||
m_LastUnreachableTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastUnreachableTime = unreachable ? i2p::util::GetSecondsSinceEpoch () : 0;
|
||||||
UpdateTime ();
|
UpdateTime ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace data
|
||||||
void TunnelBuildResponse (uint8_t ret);
|
void TunnelBuildResponse (uint8_t ret);
|
||||||
void TunnelNonReplied ();
|
void TunnelNonReplied ();
|
||||||
|
|
||||||
void Unreachable ();
|
void Unreachable (bool unreachable);
|
||||||
void Connected ();
|
void Connected ();
|
||||||
|
|
||||||
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
|
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||||
|
|
|
@ -31,7 +31,8 @@ namespace i2p
|
||||||
RouterContext::RouterContext ():
|
RouterContext::RouterContext ():
|
||||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||||
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
|
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
|
||||||
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID),
|
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone),
|
||||||
|
m_Testing (false), m_TestingV6 (false), m_NetID (I2PD_NET_ID),
|
||||||
m_PublishReplyToken (0), m_IsHiddenMode (false)
|
m_PublishReplyToken (0), m_IsHiddenMode (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -277,8 +278,29 @@ namespace i2p
|
||||||
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterContext::SetTesting (bool testing)
|
||||||
|
{
|
||||||
|
if (testing != m_Testing)
|
||||||
|
{
|
||||||
|
m_Testing = testing;
|
||||||
|
if (m_Testing)
|
||||||
|
m_Error = eRouterErrorNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouterContext::SetTestingV6 (bool testing)
|
||||||
|
{
|
||||||
|
if (testing != m_TestingV6)
|
||||||
|
{
|
||||||
|
m_TestingV6 = testing;
|
||||||
|
if (m_TestingV6)
|
||||||
|
m_ErrorV6 = eRouterErrorNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RouterContext::SetStatus (RouterStatus status)
|
void RouterContext::SetStatus (RouterStatus status)
|
||||||
{
|
{
|
||||||
|
SetTesting (false);
|
||||||
if (status != m_Status)
|
if (status != m_Status)
|
||||||
{
|
{
|
||||||
m_Status = status;
|
m_Status = status;
|
||||||
|
@ -290,9 +312,6 @@ namespace i2p
|
||||||
case eRouterStatusFirewalled:
|
case eRouterStatusFirewalled:
|
||||||
SetUnreachable (true, false); // ipv4
|
SetUnreachable (true, false); // ipv4
|
||||||
break;
|
break;
|
||||||
case eRouterStatusTesting:
|
|
||||||
m_Error = eRouterErrorNone;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -301,6 +320,7 @@ namespace i2p
|
||||||
|
|
||||||
void RouterContext::SetStatusV6 (RouterStatus status)
|
void RouterContext::SetStatusV6 (RouterStatus status)
|
||||||
{
|
{
|
||||||
|
SetTestingV6 (false);
|
||||||
if (status != m_StatusV6)
|
if (status != m_StatusV6)
|
||||||
{
|
{
|
||||||
m_StatusV6 = status;
|
m_StatusV6 = status;
|
||||||
|
@ -312,9 +332,6 @@ namespace i2p
|
||||||
case eRouterStatusFirewalled:
|
case eRouterStatusFirewalled:
|
||||||
SetUnreachable (false, true); // ipv6
|
SetUnreachable (false, true); // ipv6
|
||||||
break;
|
break;
|
||||||
case eRouterStatusTesting:
|
|
||||||
m_ErrorV6 = eRouterErrorNone;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,10 @@ namespace garlic
|
||||||
enum RouterStatus
|
enum RouterStatus
|
||||||
{
|
{
|
||||||
eRouterStatusOK = 0,
|
eRouterStatusOK = 0,
|
||||||
eRouterStatusTesting = 1,
|
eRouterStatusFirewalled = 1,
|
||||||
eRouterStatusFirewalled = 2,
|
eRouterStatusUnknown = 2,
|
||||||
eRouterStatusUnknown = 3,
|
eRouterStatusProxy = 3,
|
||||||
eRouterStatusProxy = 4,
|
eRouterStatusMesh = 4
|
||||||
eRouterStatusMesh = 5
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RouterError
|
enum RouterError
|
||||||
|
@ -121,10 +120,14 @@ namespace garlic
|
||||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||||
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
|
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
|
||||||
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
|
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
|
||||||
|
bool GetTesting () const { return m_Testing; };
|
||||||
|
void SetTesting (bool testing);
|
||||||
RouterStatus GetStatus () const { return m_Status; };
|
RouterStatus GetStatus () const { return m_Status; };
|
||||||
void SetStatus (RouterStatus status);
|
void SetStatus (RouterStatus status);
|
||||||
RouterError GetError () const { return m_Error; };
|
RouterError GetError () const { return m_Error; };
|
||||||
void SetError (RouterError error) { m_Error = error; };
|
void SetError (RouterError error) { m_Error = error; };
|
||||||
|
bool GetTestingV6 () const { return m_TestingV6; };
|
||||||
|
void SetTestingV6 (bool testing);
|
||||||
RouterStatus GetStatusV6 () const { return m_StatusV6; };
|
RouterStatus GetStatusV6 () const { return m_StatusV6; };
|
||||||
void SetStatusV6 (RouterStatus status);
|
void SetStatusV6 (RouterStatus status);
|
||||||
RouterError GetErrorV6 () const { return m_ErrorV6; };
|
RouterError GetErrorV6 () const { return m_ErrorV6; };
|
||||||
|
@ -231,6 +234,7 @@ namespace garlic
|
||||||
int m_ShareRatio;
|
int m_ShareRatio;
|
||||||
RouterStatus m_Status, m_StatusV6;
|
RouterStatus m_Status, m_StatusV6;
|
||||||
RouterError m_Error, m_ErrorV6;
|
RouterError m_Error, m_ErrorV6;
|
||||||
|
bool m_Testing, m_TestingV6;
|
||||||
int m_NetID;
|
int m_NetID;
|
||||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||||
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
|
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
|
||||||
|
|
|
@ -579,7 +579,7 @@ namespace data
|
||||||
int numValid = 0;
|
int numValid = 0;
|
||||||
for (auto& it: address->ssu->introducers)
|
for (auto& it: address->ssu->introducers)
|
||||||
{
|
{
|
||||||
if (it.iTag && ts < it.iExp)
|
if (it.iTag && ts < it.iExp && !it.iH.IsZero ())
|
||||||
numValid++;
|
numValid++;
|
||||||
else
|
else
|
||||||
it.iTag = 0;
|
it.iTag = 0;
|
||||||
|
@ -995,6 +995,7 @@ namespace data
|
||||||
|
|
||||||
bool RouterInfo::IsPublished (bool v4) const
|
bool RouterInfo::IsPublished (bool v4) const
|
||||||
{
|
{
|
||||||
|
if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addreses are not published
|
||||||
auto addr = GetAddresses ();
|
auto addr = GetAddresses ();
|
||||||
if (v4)
|
if (v4)
|
||||||
return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
|
return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
|
||||||
|
@ -1320,6 +1321,7 @@ namespace data
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
for (const auto& introducer: address.ssu->introducers)
|
||||||
{
|
{
|
||||||
|
if (!introducer.iTag) continue;
|
||||||
if (introducer.iExp) // expiration is specified
|
if (introducer.iExp) // expiration is specified
|
||||||
{
|
{
|
||||||
WriteString ("iexp" + boost::lexical_cast<std::string>(i), properties);
|
WriteString ("iexp" + boost::lexical_cast<std::string>(i), properties);
|
||||||
|
@ -1332,6 +1334,7 @@ namespace data
|
||||||
i = 0;
|
i = 0;
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
for (const auto& introducer: address.ssu->introducers)
|
||||||
{
|
{
|
||||||
|
if (!introducer.iTag) continue;
|
||||||
WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
|
WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
char value[64];
|
char value[64];
|
||||||
|
@ -1344,6 +1347,7 @@ namespace data
|
||||||
i = 0;
|
i = 0;
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
for (const auto& introducer: address.ssu->introducers)
|
||||||
{
|
{
|
||||||
|
if (!introducer.iTag) continue;
|
||||||
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
|
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
|
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace data
|
||||||
|
|
||||||
struct Introducer
|
struct Introducer
|
||||||
{
|
{
|
||||||
Introducer (): iTag (0), iExp (0) {};
|
Introducer (): iTag (0), iExp (0) { iH.Fill(0); };
|
||||||
IdentHash iH;
|
IdentHash iH;
|
||||||
uint32_t iTag;
|
uint32_t iTag;
|
||||||
uint32_t iExp;
|
uint32_t iExp;
|
||||||
|
|
|
@ -983,7 +983,7 @@ namespace transport
|
||||||
void SSU2Server::UpdateIntroducers (bool v4)
|
void SSU2Server::UpdateIntroducers (bool v4)
|
||||||
{
|
{
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::list<i2p::data::IdentHash> newList;
|
std::list<i2p::data::IdentHash> newList, impliedList;
|
||||||
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::set<i2p::data::IdentHash> excluded;
|
||||||
for (const auto& it : introducers)
|
for (const auto& it : introducers)
|
||||||
|
@ -995,12 +995,19 @@ namespace transport
|
||||||
session = it1->second;
|
session = it1->second;
|
||||||
excluded.insert (it);
|
excluded.insert (it);
|
||||||
}
|
}
|
||||||
if (session && session->IsEstablished ())
|
if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) // still session with introducer?
|
||||||
{
|
{
|
||||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
||||||
|
{
|
||||||
session->SendKeepAlive ();
|
session->SendKeepAlive ();
|
||||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||||
newList.push_back (it);
|
newList.push_back (it);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
impliedList.push_back (it); // keep in introducers list, but not publish
|
||||||
|
session = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
session = nullptr;
|
session = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1014,31 +1021,33 @@ namespace transport
|
||||||
{
|
{
|
||||||
// bump creation time for previous introducers if no new sessions found
|
// bump creation time for previous introducers if no new sessions found
|
||||||
LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing");
|
LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing");
|
||||||
|
impliedList.clear ();
|
||||||
for (auto& it : introducers)
|
for (auto& it : introducers)
|
||||||
{
|
{
|
||||||
auto it1 = m_SessionsByRouterHash.find (it);
|
auto it1 = m_SessionsByRouterHash.find (it);
|
||||||
if (it1 != m_SessionsByRouterHash.end ())
|
if (it1 != m_SessionsByRouterHash.end ())
|
||||||
{
|
{
|
||||||
auto session = it1->second;
|
auto session = it1->second;
|
||||||
if (session->IsEstablished ())
|
if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ())
|
||||||
{
|
{
|
||||||
session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
|
session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
|
||||||
if (std::find (newList.begin (), newList.end (), it) == newList.end ())
|
if (std::find (newList.begin (), newList.end (), it) == newList.end ())
|
||||||
{
|
|
||||||
newList.push_back (it);
|
|
||||||
sessions.push_back (session);
|
sessions.push_back (session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& it : sessions)
|
for (const auto& it : sessions)
|
||||||
{
|
{
|
||||||
|
uint32_t tag = it->GetRelayTag ();
|
||||||
|
uint32_t exp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
||||||
|
if (!tag || ts + SSU2_TO_INTRODUCER_SESSION_DURATION/2 > exp)
|
||||||
|
continue; // don't pick too old session for introducer
|
||||||
i2p::data::RouterInfo::Introducer introducer;
|
i2p::data::RouterInfo::Introducer introducer;
|
||||||
introducer.iTag = it->GetRelayTag ();
|
introducer.iTag = tag;
|
||||||
introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
|
introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
|
||||||
introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
introducer.iExp = exp;
|
||||||
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
|
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
|
||||||
if (i2p::context.AddSSU2Introducer (introducer, v4))
|
if (i2p::context.AddSSU2Introducer (introducer, v4))
|
||||||
{
|
{
|
||||||
|
@ -1072,13 +1081,15 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
introducers.splice (introducers.end (), impliedList); // insert non-published, but non-expired introducers back
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Server::ScheduleIntroducersUpdateTimer ()
|
void SSU2Server::ScheduleIntroducersUpdateTimer ()
|
||||||
{
|
{
|
||||||
if (m_IsPublished)
|
if (m_IsPublished)
|
||||||
{
|
{
|
||||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
|
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
||||||
|
SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
||||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, true));
|
this, std::placeholders::_1, true));
|
||||||
}
|
}
|
||||||
|
@ -1091,7 +1102,8 @@ namespace transport
|
||||||
m_IntroducersUpdateTimer.cancel ();
|
m_IntroducersUpdateTimer.cancel ();
|
||||||
i2p::context.ClearSSU2Introducers (true);
|
i2p::context.ClearSSU2Introducers (true);
|
||||||
m_Introducers.clear ();
|
m_Introducers.clear ();
|
||||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
|
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
||||||
|
(SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
||||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, true));
|
this, std::placeholders::_1, true));
|
||||||
}
|
}
|
||||||
|
@ -1101,7 +1113,8 @@ namespace transport
|
||||||
{
|
{
|
||||||
if (m_IsPublished)
|
if (m_IsPublished)
|
||||||
{
|
{
|
||||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
|
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
||||||
|
SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
||||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, false));
|
this, std::placeholders::_1, false));
|
||||||
}
|
}
|
||||||
|
@ -1114,7 +1127,8 @@ namespace transport
|
||||||
m_IntroducersUpdateTimerV6.cancel ();
|
m_IntroducersUpdateTimerV6.cancel ();
|
||||||
i2p::context.ClearSSU2Introducers (false);
|
i2p::context.ClearSSU2Introducers (false);
|
||||||
m_IntroducersV6.clear ();
|
m_IntroducersV6.clear ();
|
||||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
|
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
||||||
|
(SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
||||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||||
this, std::placeholders::_1, false));
|
this, std::placeholders::_1, false));
|
||||||
}
|
}
|
||||||
|
@ -1127,7 +1141,7 @@ namespace transport
|
||||||
// timeout expired
|
// timeout expired
|
||||||
if (v4)
|
if (v4)
|
||||||
{
|
{
|
||||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
if (i2p::context.GetTesting ())
|
||||||
{
|
{
|
||||||
// we still don't know if we need introducers
|
// we still don't know if we need introducers
|
||||||
ScheduleIntroducersUpdateTimer ();
|
ScheduleIntroducersUpdateTimer ();
|
||||||
|
@ -1150,7 +1164,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
if (i2p::context.GetTestingV6 ())
|
||||||
{
|
{
|
||||||
// we still don't know if we need introducers
|
// we still don't know if we need introducers
|
||||||
ScheduleIntroducersUpdateTimerV6 ();
|
ScheduleIntroducersUpdateTimerV6 ();
|
||||||
|
|
|
@ -29,7 +29,8 @@ namespace transport
|
||||||
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
||||||
const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
||||||
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
|
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
|
||||||
const int SSU2_KEEP_ALIVE_INTERVAL = 30; // in seconds
|
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
|
||||||
|
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
|
||||||
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
||||||
|
|
||||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||||
|
|
|
@ -114,6 +114,8 @@ namespace transport
|
||||||
{
|
{
|
||||||
if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived)
|
if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived)
|
||||||
{
|
{
|
||||||
|
LogPrint(eLogDebug, "SSU2: Connecting to ", GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ")");
|
||||||
ScheduleConnectTimer ();
|
ScheduleConnectTimer ();
|
||||||
auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint);
|
auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint);
|
||||||
if (token)
|
if (token)
|
||||||
|
@ -243,7 +245,7 @@ namespace transport
|
||||||
if (IsEstablished ())
|
if (IsEstablished ())
|
||||||
{
|
{
|
||||||
uint8_t payload[20];
|
uint8_t payload[20];
|
||||||
size_t payloadSize = CreatePaddingBlock (payload, 20, 5);
|
size_t payloadSize = CreatePaddingBlock (payload, 20, 8);
|
||||||
SendData (payload, payloadSize);
|
SendData (payload, payloadSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,7 +271,16 @@ namespace transport
|
||||||
m_ReceivedI2NPMsgIDs.clear ();
|
m_ReceivedI2NPMsgIDs.clear ();
|
||||||
m_Server.RemoveSession (m_SourceConnID);
|
m_Server.RemoveSession (m_SourceConnID);
|
||||||
transports.PeerDisconnected (shared_from_this ());
|
transports.PeerDisconnected (shared_from_this ());
|
||||||
LogPrint (eLogDebug, "SSU2: Session terminated");
|
auto remoteIdentity = GetRemoteIdentity ();
|
||||||
|
if (remoteIdentity)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,6 +309,8 @@ namespace transport
|
||||||
m_OnEstablished ();
|
m_OnEstablished ();
|
||||||
m_OnEstablished = nullptr;
|
m_OnEstablished = nullptr;
|
||||||
}
|
}
|
||||||
|
LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::Done ()
|
void SSU2Session::Done ()
|
||||||
|
@ -1053,6 +1066,17 @@ namespace transport
|
||||||
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
|
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
|
if (ts > ri->GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is too old for ", (ts - ri->GetTimestamp ())/1000LL, " seconds");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri->GetTimestamp ()) // 2 minutes
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
||||||
if (!m_Address || memcmp (S, m_Address->s, 32))
|
if (!m_Address || memcmp (S, m_Address->s, 32))
|
||||||
{
|
{
|
||||||
|
@ -1486,7 +1510,7 @@ namespace transport
|
||||||
auto size = bufbe16toh (buf + offset);
|
auto size = bufbe16toh (buf + offset);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size);
|
LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size);
|
||||||
if (size > len)
|
if (offset + size > len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU2: Unexpected block length ", size);
|
LogPrint (eLogError, "SSU2: Unexpected block length ", size);
|
||||||
break;
|
break;
|
||||||
|
@ -1532,7 +1556,9 @@ namespace transport
|
||||||
break;
|
break;
|
||||||
case eSSU2BlkTermination:
|
case eSSU2BlkTermination:
|
||||||
{
|
{
|
||||||
uint8_t rsn = buf[11]; // reason
|
if (size >= 9)
|
||||||
|
{
|
||||||
|
uint8_t rsn = buf[offset + 8]; // reason
|
||||||
LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn);
|
LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn);
|
||||||
if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived)
|
if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived)
|
||||||
RequestTermination (eSSU2TerminationReasonTerminationReceived);
|
RequestTermination (eSSU2TerminationReasonTerminationReceived);
|
||||||
|
@ -1542,6 +1568,9 @@ namespace transport
|
||||||
m_State = eSSU2SessionStateClosingConfirmed;
|
m_State = eSSU2SessionStateClosingConfirmed;
|
||||||
Done ();
|
Done ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogWarning, "SSU2: Unexpected termination block size ", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eSSU2BlkRelayRequest:
|
case eSSU2BlkRelayRequest:
|
||||||
|
@ -1635,8 +1664,8 @@ namespace transport
|
||||||
break;
|
break;
|
||||||
case eSSU2SessionStateSessionCreatedReceived:
|
case eSSU2SessionStateSessionCreatedReceived:
|
||||||
case eSSU2SessionStateTokenReceived:
|
case eSSU2SessionStateTokenReceived:
|
||||||
if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) ||
|
if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetTesting ()) ||
|
||||||
(m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting))
|
(m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetTestingV6 ()))
|
||||||
{
|
{
|
||||||
if (m_Server.IsSyncClockFromPeers ())
|
if (m_Server.IsSyncClockFromPeers ())
|
||||||
{
|
{
|
||||||
|
@ -1734,14 +1763,14 @@ namespace transport
|
||||||
LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4));
|
LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4));
|
||||||
if (isV4)
|
if (isV4)
|
||||||
{
|
{
|
||||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
if (i2p::context.GetTesting ())
|
||||||
i2p::context.SetError (eRouterErrorSymmetricNAT);
|
i2p::context.SetError (eRouterErrorSymmetricNAT);
|
||||||
else if (m_State == eSSU2SessionStatePeerTest)
|
else if (m_State == eSSU2SessionStatePeerTest)
|
||||||
i2p::context.SetError (eRouterErrorFullConeNAT);
|
i2p::context.SetError (eRouterErrorFullConeNAT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
if (i2p::context.GetTestingV6 ())
|
||||||
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
|
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
|
||||||
else if (m_State == eSSU2SessionStatePeerTest)
|
else if (m_State == eSSU2SessionStatePeerTest)
|
||||||
i2p::context.SetErrorV6 (eRouterErrorFullConeNAT);
|
i2p::context.SetErrorV6 (eRouterErrorFullConeNAT);
|
||||||
|
@ -2214,7 +2243,7 @@ namespace transport
|
||||||
if (buf[1] == eSSU2PeerTestCodeAccept)
|
if (buf[1] == eSSU2PeerTestCodeAccept)
|
||||||
{
|
{
|
||||||
if (GetRouterStatus () == eRouterStatusUnknown)
|
if (GetRouterStatus () == eRouterStatusUnknown)
|
||||||
SetRouterStatus (eRouterStatusTesting);
|
SetTestingState (true);
|
||||||
auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
|
auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
|
||||||
if (r && it->second.first)
|
if (r && it->second.first)
|
||||||
{
|
{
|
||||||
|
@ -2240,7 +2269,10 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (GetRouterStatus () == eRouterStatusTesting)
|
if (GetTestingState ())
|
||||||
|
{
|
||||||
|
SetTestingState (false);
|
||||||
|
if (GetRouterStatus () != eRouterStatusFirewalled)
|
||||||
{
|
{
|
||||||
SetRouterStatus (eRouterStatusFirewalled);
|
SetRouterStatus (eRouterStatusFirewalled);
|
||||||
if (m_Address->IsV4 ())
|
if (m_Address->IsV4 ())
|
||||||
|
@ -2249,6 +2281,7 @@ namespace transport
|
||||||
m_Server.RescheduleIntroducersUpdateTimerV6 ();
|
m_Server.RescheduleIntroducersUpdateTimerV6 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()),
|
LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()),
|
||||||
" with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3)));
|
" with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3)));
|
||||||
}
|
}
|
||||||
|
@ -2275,7 +2308,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ",
|
LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ",
|
||||||
i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3)));
|
i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3)));
|
||||||
if (GetRouterStatus () == eRouterStatusTesting)
|
if (GetTestingState ())
|
||||||
SetRouterStatus (eRouterStatusUnknown);
|
SetRouterStatus (eRouterStatusUnknown);
|
||||||
it->second.first->Done ();
|
it->second.first->Done ();
|
||||||
}
|
}
|
||||||
|
@ -2429,6 +2462,29 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SSU2Session::GetTestingState () const
|
||||||
|
{
|
||||||
|
if (m_Address)
|
||||||
|
{
|
||||||
|
if (m_Address->IsV4 ())
|
||||||
|
return i2p::context.GetTesting ();
|
||||||
|
if (m_Address->IsV6 ())
|
||||||
|
return i2p::context.GetTestingV6 ();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSU2Session::SetTestingState (bool testing) const
|
||||||
|
{
|
||||||
|
if (m_Address)
|
||||||
|
{
|
||||||
|
if (m_Address->IsV4 ())
|
||||||
|
i2p::context.SetTesting (testing);
|
||||||
|
else if (m_Address->IsV6 ())
|
||||||
|
i2p::context.SetTestingV6 (testing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep)
|
size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep)
|
||||||
{
|
{
|
||||||
if (len < 9) return 0;
|
if (len < 9) return 0;
|
||||||
|
@ -2841,7 +2897,7 @@ namespace transport
|
||||||
|
|
||||||
void SSU2Session::SendPathResponse (const uint8_t * data, size_t len)
|
void SSU2Session::SendPathResponse (const uint8_t * data, size_t len)
|
||||||
{
|
{
|
||||||
if (len < 8 || len > m_MaxPayloadSize - 3)
|
if (len > m_MaxPayloadSize - 3)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len);
|
LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len);
|
||||||
return;
|
return;
|
||||||
|
@ -2850,7 +2906,10 @@ namespace transport
|
||||||
payload[0] = eSSU2BlkPathResponse;
|
payload[0] = eSSU2BlkPathResponse;
|
||||||
htobe16buf (payload + 1, len);
|
htobe16buf (payload + 1, len);
|
||||||
memcpy (payload + 3, data, len);
|
memcpy (payload + 3, data, len);
|
||||||
SendData (payload, len + 3);
|
size_t payloadSize = len + 3;
|
||||||
|
if (payloadSize < m_MaxPayloadSize)
|
||||||
|
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, payloadSize < 8 ? 8 : 0);
|
||||||
|
SendData (payload, payloadSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::SendPathChallenge ()
|
void SSU2Session::SendPathChallenge ()
|
||||||
|
@ -2868,7 +2927,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
len += 3;
|
len += 3;
|
||||||
if (len < m_MaxPayloadSize)
|
if (len < m_MaxPayloadSize)
|
||||||
len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len);
|
len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len, len < 8 ? 8 : 0);
|
||||||
SendData (payload, len);
|
SendData (payload, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -308,6 +308,8 @@ namespace transport
|
||||||
void AdjustMaxPayloadSize ();
|
void AdjustMaxPayloadSize ();
|
||||||
RouterStatus GetRouterStatus () const;
|
RouterStatus GetRouterStatus () const;
|
||||||
void SetRouterStatus (RouterStatus status) const;
|
void SetRouterStatus (RouterStatus status) const;
|
||||||
|
bool GetTestingState () const;
|
||||||
|
void SetTestingState(bool testing) const;
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
|
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
|
||||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||||
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
|
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
|
||||||
|
|
|
@ -650,8 +650,8 @@ namespace transport
|
||||||
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
|
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
|
||||||
if (router)
|
if (router)
|
||||||
{
|
{
|
||||||
if (i2p::context.GetStatus () != eRouterStatusTesting)
|
if (!i2p::context.GetTesting ())
|
||||||
i2p::context.SetStatus (eRouterStatusTesting);
|
i2p::context.SetTesting (true);
|
||||||
m_SSU2Server->StartPeerTest (router, true);
|
m_SSU2Server->StartPeerTest (router, true);
|
||||||
excluded.insert (router->GetIdentHash ());
|
excluded.insert (router->GetIdentHash ());
|
||||||
}
|
}
|
||||||
|
@ -669,8 +669,8 @@ namespace transport
|
||||||
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
|
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
|
||||||
if (router)
|
if (router)
|
||||||
{
|
{
|
||||||
if (i2p::context.GetStatusV6 () != eRouterStatusTesting)
|
if (!i2p::context.GetTestingV6 ())
|
||||||
i2p::context.SetStatusV6 (eRouterStatusTesting);
|
i2p::context.SetTestingV6 (true);
|
||||||
m_SSU2Server->StartPeerTest (router, false);
|
m_SSU2Server->StartPeerTest (router, false);
|
||||||
excluded.insert (router->GetIdentHash ());
|
excluded.insert (router->GetIdentHash ());
|
||||||
}
|
}
|
||||||
|
@ -716,6 +716,7 @@ namespace transport
|
||||||
if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
|
if (transport == i2p::data::RouterInfo::eNTCP2V4 ||
|
||||||
transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
|
transport == i2p::data::RouterInfo::eNTCP2V6 || transport == i2p::data::RouterInfo::eNTCP2V6Mesh)
|
||||||
it->second.router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real
|
it->second.router->GetProfile ()->Connected (); // outgoing NTCP2 connection if always real
|
||||||
|
i2p::data::netdb.SetUnreachable (ident, false); // clear unreachable
|
||||||
}
|
}
|
||||||
it->second.numAttempts = 0;
|
it->second.numAttempts = 0;
|
||||||
it->second.router = nullptr; // we don't need RouterInfo after successive connect
|
it->second.router = nullptr; // we don't need RouterInfo after successive connect
|
||||||
|
@ -831,8 +832,8 @@ namespace transport
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting;
|
bool ipv4Testing = i2p::context.GetTesting ();
|
||||||
bool ipv6Testing = i2p::context.GetStatusV6 () == eRouterStatusTesting;
|
bool ipv6Testing = i2p::context.GetTestingV6 ();
|
||||||
// if still testing, repeat peer test
|
// if still testing, repeat peer test
|
||||||
if (ipv4Testing || ipv6Testing)
|
if (ipv4Testing || ipv6Testing)
|
||||||
PeerTest (ipv4Testing, ipv6Testing);
|
PeerTest (ipv4Testing, ipv6Testing);
|
||||||
|
@ -861,7 +862,9 @@ namespace transport
|
||||||
uint16_t inds[3];
|
uint16_t inds[3];
|
||||||
RAND_bytes ((uint8_t *)inds, sizeof (inds));
|
RAND_bytes ((uint8_t *)inds, sizeof (inds));
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
inds[0] %= m_Peers.size ();
|
auto count = m_Peers.size ();
|
||||||
|
if(count == 0) return nullptr;
|
||||||
|
inds[0] %= count;
|
||||||
auto it = m_Peers.begin ();
|
auto it = m_Peers.begin ();
|
||||||
std::advance (it, inds[0]);
|
std::advance (it, inds[0]);
|
||||||
// try random peer
|
// try random peer
|
||||||
|
|
|
@ -709,7 +709,7 @@ namespace tunnel
|
||||||
auto inboundTunnel = GetNextInboundTunnel ();
|
auto inboundTunnel = GetNextInboundTunnel ();
|
||||||
auto router = i2p::transport::transports.RoutesRestricted() ?
|
auto router = i2p::transport::transports.RoutesRestricted() ?
|
||||||
i2p::transport::transports.GetRestrictedPeer() :
|
i2p::transport::transports.GetRestrictedPeer() :
|
||||||
i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false); // reachable by us
|
i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true); // reachable by us
|
||||||
if (!inboundTunnel || !router) return;
|
if (!inboundTunnel || !router) return;
|
||||||
LogPrint (eLogDebug, "Tunnel: Creating one hop outbound tunnel");
|
LogPrint (eLogDebug, "Tunnel: Creating one hop outbound tunnel");
|
||||||
CreateTunnel<OutboundTunnel> (
|
CreateTunnel<OutboundTunnel> (
|
||||||
|
@ -781,7 +781,7 @@ namespace tunnel
|
||||||
auto router = i2p::transport::transports.RoutesRestricted() ?
|
auto router = i2p::transport::transports.RoutesRestricted() ?
|
||||||
i2p::transport::transports.GetRestrictedPeer() :
|
i2p::transport::transports.GetRestrictedPeer() :
|
||||||
// should be reachable by us because we send build request directly
|
// should be reachable by us because we send build request directly
|
||||||
i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false);
|
i2p::data::netdb.GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, true);
|
||||||
if (!router) {
|
if (!router) {
|
||||||
LogPrint (eLogWarning, "Tunnel: Can't find any router, skip creating tunnel");
|
LogPrint (eLogWarning, "Tunnel: Can't find any router, skip creating tunnel");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -296,10 +296,12 @@ namespace tunnel
|
||||||
for (const auto& it : m_InboundTunnels)
|
for (const auto& it : m_InboundTunnels)
|
||||||
if (it->IsEstablished ()) num++;
|
if (it->IsEstablished ()) num++;
|
||||||
}
|
}
|
||||||
if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0)
|
if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0 &&
|
||||||
|
m_NumInboundHops == m_NumOutboundHops)
|
||||||
{
|
{
|
||||||
for (auto it: m_OutboundTunnels)
|
for (auto it: m_OutboundTunnels)
|
||||||
{
|
{
|
||||||
|
// try to create inbound tunnel through the same path as succesive outbound
|
||||||
CreatePairedInboundTunnel (it);
|
CreatePairedInboundTunnel (it);
|
||||||
num++;
|
num++;
|
||||||
if (num >= m_NumInboundTunnels) break;
|
if (num >= m_NumInboundTunnels) break;
|
||||||
|
@ -470,13 +472,14 @@ namespace tunnel
|
||||||
return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ();
|
return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const
|
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop,
|
||||||
|
bool reverse, bool endpoint) const
|
||||||
{
|
{
|
||||||
auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse):
|
auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint):
|
||||||
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse);
|
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint);
|
||||||
|
|
||||||
if (!hop || hop->GetProfile ()->IsBad ())
|
if (!hop || hop->GetProfile ()->IsBad ())
|
||||||
hop = i2p::data::netdb.GetRandomRouter (prevHop, reverse);
|
hop = i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint);
|
||||||
return hop;
|
return hop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +511,7 @@ namespace tunnel
|
||||||
|
|
||||||
for(int i = start; i < numHops; i++ )
|
for(int i = start; i < numHops; i++ )
|
||||||
{
|
{
|
||||||
auto hop = nextHop (prevHop, inbound);
|
auto hop = nextHop (prevHop, inbound, i == numHops - 1);
|
||||||
if (!hop && !i) // if no suitable peer found for first hop, try already connected
|
if (!hop && !i) // if no suitable peer found for first hop, try already connected
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected");
|
LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected");
|
||||||
|
@ -520,11 +523,6 @@ namespace tunnel
|
||||||
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
|
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((i == numHops - 1) && (!hop->IsV4 () || (inbound && !hop->IsPublished (true)))) // IBGW is not published ipv4
|
|
||||||
{
|
|
||||||
auto hop1 = nextHop (prevHop, inbound);
|
|
||||||
if (hop1) hop = hop1;
|
|
||||||
}
|
|
||||||
prevHop = hop;
|
prevHop = hop;
|
||||||
path.Add (hop);
|
path.Add (hop);
|
||||||
}
|
}
|
||||||
|
@ -566,14 +564,15 @@ namespace tunnel
|
||||||
if (m_CustomPeerSelector)
|
if (m_CustomPeerSelector)
|
||||||
return m_CustomPeerSelector->SelectPeers(path, numHops, isInbound);
|
return m_CustomPeerSelector->SelectPeers(path, numHops, isInbound);
|
||||||
}
|
}
|
||||||
return StandardSelectPeers(path, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, std::placeholders::_1, std::placeholders::_2));
|
return StandardSelectPeers(path, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this,
|
||||||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TunnelPool::SelectExplicitPeers (Path& path, bool isInbound)
|
bool TunnelPool::SelectExplicitPeers (Path& path, bool isInbound)
|
||||||
{
|
{
|
||||||
|
if (!m_ExplicitPeers->size ()) return false;
|
||||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||||
if (numHops > (int)m_ExplicitPeers->size ()) numHops = m_ExplicitPeers->size ();
|
if (numHops > (int)m_ExplicitPeers->size ()) numHops = m_ExplicitPeers->size ();
|
||||||
if (!numHops) return false;
|
|
||||||
for (int i = 0; i < numHops; i++)
|
for (int i = 0; i < numHops; i++)
|
||||||
{
|
{
|
||||||
auto& ident = (*m_ExplicitPeers)[i];
|
auto& ident = (*m_ExplicitPeers)[i];
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace tunnel
|
||||||
|
|
||||||
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
|
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
|
||||||
{
|
{
|
||||||
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc;
|
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool, bool)> SelectHopFunc;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels,
|
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels,
|
||||||
|
@ -112,7 +112,7 @@ namespace tunnel
|
||||||
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude = nullptr) const;
|
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude = nullptr) const;
|
||||||
|
|
||||||
// for overriding tunnel peer selection
|
// for overriding tunnel peer selection
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const;
|
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse, bool endpoint) const;
|
||||||
bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
|
bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -357,13 +357,13 @@ namespace client
|
||||||
os << data << std::endl;
|
os << data << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out)
|
void BOBCommandSession::BuildStatusLine(bool currentTunnel, std::shared_ptr<BOBDestination> dest, std::string &out)
|
||||||
{
|
{
|
||||||
// helper lambdas
|
// helper lambdas
|
||||||
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
|
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
|
||||||
const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
|
const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
|
||||||
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
|
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
|
||||||
const auto destReady = [](const BOBDestination * const dest) { return dest->IsRunning(); };
|
const auto destReady = [](const BOBDestination * const dest) { return dest && dest->IsRunning(); };
|
||||||
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
|
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
|
||||||
|
|
||||||
// tunnel info
|
// tunnel info
|
||||||
|
@ -373,9 +373,9 @@ namespace client
|
||||||
const std::string outhost = issetStr(currentTunnel ? m_OutHost : dest->GetOutHost());
|
const std::string outhost = issetStr(currentTunnel ? m_OutHost : dest->GetOutHost());
|
||||||
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
|
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
|
||||||
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
|
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
|
||||||
const bool keys = destExists(dest); // key must exist when destination is created
|
const bool keys = destExists(dest.get ()); // key must exist when destination is created
|
||||||
const bool starting = destExists(dest) && !destReady(dest);
|
const bool starting = destExists(dest.get ()) && !destReady(dest.get ());
|
||||||
const bool running = destExists(dest) && destReady(dest);
|
const bool running = destExists(dest.get ()) && destReady(dest.get ());
|
||||||
const bool stopping = false;
|
const bool stopping = false;
|
||||||
|
|
||||||
// build line
|
// build line
|
||||||
|
@ -446,7 +446,7 @@ namespace client
|
||||||
|
|
||||||
if (!m_CurrentDestination)
|
if (!m_CurrentDestination)
|
||||||
{
|
{
|
||||||
m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command
|
m_CurrentDestination = std::make_shared<BOBDestination> (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command
|
||||||
m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet);
|
m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet);
|
||||||
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
|
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,13 @@ namespace client
|
||||||
SendReplyError ("Address Not found");
|
SendReplyError ("Address Not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
|
auto localDestination = (m_CurrentDestination && m_CurrentDestination->IsRunning ()) ?
|
||||||
|
m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
|
||||||
|
if (!localDestination)
|
||||||
|
{
|
||||||
|
SendReplyError ("No local destination");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (addr->IsIdentHash ())
|
if (addr->IsIdentHash ())
|
||||||
{
|
{
|
||||||
// we might have leaseset already
|
// we might have leaseset already
|
||||||
|
@ -875,8 +881,6 @@ namespace client
|
||||||
{
|
{
|
||||||
if (IsRunning ())
|
if (IsRunning ())
|
||||||
Stop ();
|
Stop ();
|
||||||
for (const auto& it: m_Destinations)
|
|
||||||
delete it.second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandChannel::Start ()
|
void BOBCommandChannel::Start ()
|
||||||
|
@ -893,9 +897,9 @@ namespace client
|
||||||
StopIOService ();
|
StopIOService ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
|
void BOBCommandChannel::AddDestination (const std::string& name, std::shared_ptr<BOBDestination> dest)
|
||||||
{
|
{
|
||||||
m_Destinations[name] = dest;
|
m_Destinations.emplace (name, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandChannel::DeleteDestination (const std::string& name)
|
void BOBCommandChannel::DeleteDestination (const std::string& name)
|
||||||
|
@ -904,12 +908,11 @@ namespace client
|
||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
{
|
{
|
||||||
it->second->Stop ();
|
it->second->Stop ();
|
||||||
delete it->second;
|
|
||||||
m_Destinations.erase (it);
|
m_Destinations.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOBDestination * BOBCommandChannel::FindDestination (const std::string& name)
|
std::shared_ptr<BOBDestination> BOBCommandChannel::FindDestination (const std::string& name)
|
||||||
{
|
{
|
||||||
auto it = m_Destinations.find (name);
|
auto it = m_Destinations.find (name);
|
||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
|
|
|
@ -228,7 +228,7 @@ namespace client
|
||||||
void SendReplyError (const char * msg);
|
void SendReplyError (const char * msg);
|
||||||
void SendRaw (const char * data);
|
void SendRaw (const char * data);
|
||||||
|
|
||||||
void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out);
|
void BuildStatusLine(bool currentTunnel, std::shared_ptr<BOBDestination> destination, std::string &out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ namespace client
|
||||||
uint16_t m_InPort, m_OutPort;
|
uint16_t m_InPort, m_OutPort;
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
std::map<std::string, std::string> m_Options;
|
std::map<std::string, std::string> m_Options;
|
||||||
BOBDestination * m_CurrentDestination;
|
std::shared_ptr<BOBDestination> m_CurrentDestination;
|
||||||
};
|
};
|
||||||
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
|
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
|
||||||
|
|
||||||
|
@ -255,9 +255,9 @@ namespace client
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||||
void AddDestination (const std::string& name, BOBDestination * dest);
|
void AddDestination (const std::string& name, std::shared_ptr<BOBDestination> dest);
|
||||||
void DeleteDestination (const std::string& name);
|
void DeleteDestination (const std::string& name);
|
||||||
BOBDestination * FindDestination (const std::string& name);
|
std::shared_ptr<BOBDestination> FindDestination (const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ namespace client
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
std::map<std::string, BOBDestination *> m_Destinations;
|
std::map<std::string, std::shared_ptr<BOBDestination> > m_Destinations;
|
||||||
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
|
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
|
||||||
std::map<std::string, std::string> m_HelpStrings;
|
std::map<std::string, std::string> m_HelpStrings;
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,8 @@ namespace client
|
||||||
{
|
{
|
||||||
auto pool = GetTunnelPool();
|
auto pool = GetTunnelPool();
|
||||||
if(!pool || !pool->StandardSelectPeers(path, hops, inbound,
|
if(!pool || !pool->StandardSelectPeers(path, hops, inbound,
|
||||||
std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1, std::placeholders::_2)))
|
std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1,
|
||||||
|
std::placeholders::_2, std::placeholders::_3)))
|
||||||
return false;
|
return false;
|
||||||
// more here for outbound tunnels
|
// more here for outbound tunnels
|
||||||
if(!inbound && m_RemoteLeaseSet)
|
if(!inbound && m_RemoteLeaseSet)
|
||||||
|
|
Loading…
Add table
Reference in a new issue