mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 21:37:17 +01:00
Merge pull request #2125 from PurpleI2P/openssl
Some checks failed
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Has been cancelled
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Has been cancelled
Build Debian packages / ${{ matrix.dist }} (buster) (push) Has been cancelled
Build on FreeBSD / with UPnP (push) Has been cancelled
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Has been cancelled
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Has been cancelled
Build on Windows / XP (push) Has been cancelled
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Has been cancelled
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Has been cancelled
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Has been cancelled
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Has been cancelled
Some checks failed
Build Debian packages / ${{ matrix.dist }} (bookworm) (push) Has been cancelled
Build Debian packages / ${{ matrix.dist }} (bullseye) (push) Has been cancelled
Build Debian packages / ${{ matrix.dist }} (buster) (push) Has been cancelled
Build on FreeBSD / with UPnP (push) Has been cancelled
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (no) (push) Has been cancelled
Build on OSX / With USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Has been cancelled
Build on Windows / ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (clang-x86_64, x64-clang, clang, CLANG64) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (i686, x86, gcc, MINGW32) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (ucrt-x86_64, x64-ucrt, gcc, UCRT64) (push) Has been cancelled
Build on Windows / CMake ${{ matrix.arch }} (x86_64, x64, gcc, MINGW64) (push) Has been cancelled
Build on Windows / XP (push) Has been cancelled
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (no) (push) Has been cancelled
Build on Ubuntu / Make with USE_UPNP=${{ matrix.with_upnp }} (yes) (push) Has been cancelled
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (OFF) (push) Has been cancelled
Build on Ubuntu / CMake with -DWITH_UPNP=${{ matrix.with_upnp }} (ON) (push) Has been cancelled
Recent changes
This commit is contained in:
commit
35352f1497
|
@ -1,32 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFgTCCA2mgAwIBAgIETWAY1DANBgkqhkiG9w0BAQ0FADBxMQswCQYDVQQGEwJY
|
|
||||||
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
|
|
||||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBAbWFp
|
|
||||||
bC5pMnAwHhcNMjExMjEzMTU0MDI3WhcNMzExMjExMTU0MDI3WjBxMQswCQYDVQQG
|
|
||||||
EwJYWDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5v
|
|
||||||
bnltb3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBA
|
|
||||||
bWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXnjJ8UQ0f
|
|
||||||
lHHpfPMiHofBPSuL4sbOJY6fOXwPhSg/h6THh9DS/ZWmJXQ3qRD0glDVtv4/Dr/9
|
|
||||||
ldGQ5eltF9iCFXCQlMEy2HjQrBKq0nsl7RpYK12cyMaod0kkzCUk9ITLi9CmHM3Z
|
|
||||||
gQZcmG8TWjFEpDR+idx/QkQt2pcO4vzWlDit3Vh4ivnbX5jGQHbsVjQEMQWxr+pX
|
|
||||||
dsS+YQpjZ6RBmrooGTPO8QDOOeYLAn0lCjmffc/kzIH9E/p4/O0rOpyhVYbdxUD1
|
|
||||||
5wkqN9l4yrtxmORG/PudnRQQ0r4TUq8vsxfGY0Euo9IbhgXF2Parel1ZhDxB1WZV
|
|
||||||
VwWtgLIh9jGA1UMa8SYKnEfp8LWNZ3b3mUUnZb3kMrLk6jGYRWNsHmamhd4mC7AZ
|
|
||||||
qf/8lOkEIw3bPd3YguCDRVcLui5BwIEZmqXg8uoESxfO/sW3pBrN/8M7MkTex9kN
|
|
||||||
vjitGDDXvenK27qmNgZxbBlX72yTSfys7XTYTLnxZC8AwdAo2Wz9Z6HhGiPonf2h
|
|
||||||
vZkc9ZxuE0jFIrsbJra4X7iyjXgi4vV4ARNg/9Ft6F4/OIbECgeDcBQqq4TlT2bZ
|
|
||||||
EfWVrBbqXoj5vNsLigIkd+AyUNwPYEcB5IFSiiOh98pC7BH3pg0m8U5YBjxe1i+9
|
|
||||||
EQOOG0Qtx+JigXZHu6bGE0Twy9zy+UzoKQIDAQABoyEwHzAdBgNVHQ4EFgQUGK1b
|
|
||||||
0DkL6aLalcfBc/Uj/SF08C0wDQYJKoZIhvcNAQENBQADggIBAMpXM82bJDpH1TlH
|
|
||||||
TvhU3Z7nfZdvEhOQfujaFUYiuNripuEKcFGn948+DvAG0FUN+uNlJoqOVs8D7InD
|
|
||||||
gWlA9zpqw5Cl5Hij/Wns9QbXuAHJeA23fVUoaM2A6v9ifcIQ1A+rDuRQAo6/64KW
|
|
||||||
ChTg2e99RBpfGOyqgeh7tLLe0lPPekVpKHFuXabokaKRDuBcVHcUL4tWXe3dcyqa
|
|
||||||
Ej/PJrrS+nWL0EGZ4q80CEd2LPuDzPxNGCJt/R7ZfadENWajcgcXGceh1QBzozrB
|
|
||||||
SL/Ya6wF9SrsB7V/r5wX0LM4ZdDaLWbtmUe5Op0h/ZMH25Sa8xAXVz+O9L6sWSoO
|
|
||||||
FaiYTOvAiyyPz+nsxKa3xYryDHno7eKSt+hGOcaurhxbdZaEFY/CegEc73tCt9xK
|
|
||||||
e9qF8O/WkDLmixuErw3f5en4IfzGR7p3lJAwW/8WD8C6HS39h/eE7dVZNaWgtQnZ
|
|
||||||
SgGjgZMTJqTcQ3aZmfuCZefxGFok8w6AIkdbnd1pdMBRjYu8aXgl2hQSB9ZADDE9
|
|
||||||
R5d3rXi0PkSFLIvsNjVa5KXrZk/tB0Hpfmepq7CufBqjP/LG9TieRoXzLYUKFF74
|
|
||||||
QRwjP+y7AJ+VDUTpY1NV1P+k+2raubU2bOnLF3zL5DtyoyieGPhyeMMvp0fRIxdg
|
|
||||||
bSl5VHgPXHNM8mcnndMAuzvl7jEK
|
|
||||||
-----END CERTIFICATE-----
|
|
|
@ -238,7 +238,6 @@ namespace config {
|
||||||
"http://[324:71e:281a:9ed3::ace]:7070/,"
|
"http://[324:71e:281a:9ed3::ace]:7070/,"
|
||||||
"http://[301:65b9:c7cd:9a36::1]:18801/,"
|
"http://[301:65b9:c7cd:9a36::1]:18801/,"
|
||||||
"http://[320:8936:ec1a:31f1::216]/,"
|
"http://[320:8936:ec1a:31f1::216]/,"
|
||||||
"http://[306:3834:97b9:a00a::1]/,"
|
|
||||||
"http://[316:f9e0:f22e:a74f::216]/"
|
"http://[316:f9e0:f22e:a74f::216]/"
|
||||||
), "Reseed URLs through the Yggdrasil, separated by comma")
|
), "Reseed URLs through the Yggdrasil, separated by comma")
|
||||||
;
|
;
|
||||||
|
|
|
@ -240,17 +240,12 @@ namespace crypto
|
||||||
// x25519
|
// x25519
|
||||||
X25519Keys::X25519Keys ()
|
X25519Keys::X25519Keys ()
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
|
||||||
m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
|
m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
|
||||||
m_Pkey = nullptr;
|
m_Pkey = nullptr;
|
||||||
#else
|
|
||||||
m_Ctx = BN_CTX_new ();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub)
|
X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub)
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
|
||||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||||
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
||||||
if (pub)
|
if (pub)
|
||||||
|
@ -260,29 +255,16 @@ namespace crypto
|
||||||
size_t len = 32;
|
size_t len = 32;
|
||||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
m_Ctx = BN_CTX_new ();
|
|
||||||
memcpy (m_PrivateKey, priv, 32);
|
|
||||||
if (pub)
|
|
||||||
memcpy (m_PublicKey, pub, 32);
|
|
||||||
else
|
|
||||||
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
X25519Keys::~X25519Keys ()
|
X25519Keys::~X25519Keys ()
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
|
||||||
EVP_PKEY_CTX_free (m_Ctx);
|
EVP_PKEY_CTX_free (m_Ctx);
|
||||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||||
#else
|
|
||||||
BN_CTX_free (m_Ctx);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void X25519Keys::GenerateKeys ()
|
void X25519Keys::GenerateKeys ()
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
|
||||||
if (m_Pkey)
|
if (m_Pkey)
|
||||||
{
|
{
|
||||||
EVP_PKEY_free (m_Pkey);
|
EVP_PKEY_free (m_Pkey);
|
||||||
|
@ -294,16 +276,11 @@ namespace crypto
|
||||||
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx?
|
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx?
|
||||||
size_t len = 32;
|
size_t len = 32;
|
||||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||||
#else
|
|
||||||
RAND_bytes (m_PrivateKey, 32);
|
|
||||||
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
|
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
|
||||||
{
|
{
|
||||||
if (!pub || (pub[31] & 0x80)) return false; // not x25519 key
|
if (!pub || (pub[31] & 0x80)) return false; // not x25519 key
|
||||||
#if OPENSSL_X25519
|
|
||||||
EVP_PKEY_derive_init (m_Ctx);
|
EVP_PKEY_derive_init (m_Ctx);
|
||||||
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
|
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
|
||||||
if (!pkey) return false;
|
if (!pkey) return false;
|
||||||
|
@ -311,25 +288,17 @@ namespace crypto
|
||||||
size_t len = 32;
|
size_t len = 32;
|
||||||
EVP_PKEY_derive (m_Ctx, shared, &len);
|
EVP_PKEY_derive (m_Ctx, shared, &len);
|
||||||
EVP_PKEY_free (pkey);
|
EVP_PKEY_free (pkey);
|
||||||
#else
|
|
||||||
GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx);
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X25519Keys::GetPrivateKey (uint8_t * priv) const
|
void X25519Keys::GetPrivateKey (uint8_t * priv) const
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
|
||||||
size_t len = 32;
|
size_t len = 32;
|
||||||
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
|
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
|
||||||
#else
|
|
||||||
memcpy (priv, m_PrivateKey, 32);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic)
|
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic)
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
|
||||||
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
||||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||||
|
@ -339,11 +308,6 @@ namespace crypto
|
||||||
size_t len = 32;
|
size_t len = 32;
|
||||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
memcpy (m_PrivateKey, priv, 32);
|
|
||||||
if (calculatePublic)
|
|
||||||
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ElGamal
|
// ElGamal
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
||||||
# define OPENSSL_HKDF 1
|
# define OPENSSL_HKDF 1
|
||||||
# define OPENSSL_EDDSA 1
|
# define OPENSSL_EDDSA 1
|
||||||
# define OPENSSL_X25519 1
|
|
||||||
# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
|
# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
|
||||||
# define OPENSSL_SIPHASH 1
|
# define OPENSSL_SIPHASH 1
|
||||||
# endif
|
# endif
|
||||||
|
@ -70,13 +69,8 @@ namespace crypto
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_PublicKey[32];
|
uint8_t m_PublicKey[32];
|
||||||
#if OPENSSL_X25519
|
|
||||||
EVP_PKEY_CTX * m_Ctx;
|
EVP_PKEY_CTX * m_Ctx;
|
||||||
EVP_PKEY * m_Pkey;
|
EVP_PKEY * m_Pkey;
|
||||||
#else
|
|
||||||
BN_CTX * m_Ctx;
|
|
||||||
uint8_t m_PrivateKey[32];
|
|
||||||
#endif
|
|
||||||
bool m_IsElligatorIneligible = false; // true if definitely ineligible
|
bool m_IsElligatorIneligible = false; // true if definitely ineligible
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ namespace client
|
||||||
LoadTags ();
|
LoadTags ();
|
||||||
m_Pool->SetLocalDestination (shared_from_this ());
|
m_Pool->SetLocalDestination (shared_from_this ());
|
||||||
m_Pool->SetActive (true);
|
m_Pool->SetActive (true);
|
||||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
m_CleanupTimer.expires_from_now (boost::posix_time::seconds (DESTINATION_CLEANUP_TIMEOUT));
|
||||||
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,24 @@ namespace client
|
||||||
|
|
||||||
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg));
|
if (!msg) return;
|
||||||
|
bool empty = false;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_IncomingMsgsQueueMutex);
|
||||||
|
empty = m_IncomingMsgsQueue.empty ();
|
||||||
|
m_IncomingMsgsQueue.push_back (msg);
|
||||||
|
}
|
||||||
|
if (empty)
|
||||||
|
m_Service.post([s = shared_from_this ()]()
|
||||||
|
{
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > receivedMsgs;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(s->m_IncomingMsgsQueueMutex);
|
||||||
|
s->m_IncomingMsgsQueue.swap (receivedMsgs);
|
||||||
|
}
|
||||||
|
for (auto& it: receivedMsgs)
|
||||||
|
s->HandleGarlicMessage (it);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
|
@ -953,7 +970,8 @@ namespace client
|
||||||
CleanupExpiredTags ();
|
CleanupExpiredTags ();
|
||||||
CleanupRemoteLeaseSets ();
|
CleanupRemoteLeaseSets ();
|
||||||
CleanupDestination ();
|
CleanupDestination ();
|
||||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
m_CleanupTimer.expires_from_now (boost::posix_time::seconds (DESTINATION_CLEANUP_TIMEOUT +
|
||||||
|
(m_Pool ? m_Pool->GetRng ()() % DESTINATION_CLEANUP_TIMEOUT_VARIANCE : 0)));
|
||||||
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
@ -967,7 +985,7 @@ namespace client
|
||||||
{
|
{
|
||||||
if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired
|
if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
LogPrint (eLogDebug, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||||
it = m_RemoteLeaseSets.erase (it);
|
it = m_RemoteLeaseSets.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -988,6 +1006,7 @@ namespace client
|
||||||
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||||
m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED),
|
m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED),
|
||||||
m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED),
|
m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED),
|
||||||
|
m_StreamingMaxConcurrentStreams (DEFAULT_MAX_CONCURRENT_STREAMS),
|
||||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
||||||
m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0),
|
m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0),
|
||||||
m_ReadyChecker(service)
|
m_ReadyChecker(service)
|
||||||
|
@ -1059,6 +1078,8 @@ namespace client
|
||||||
it = params->find (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED);
|
it = params->find (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
m_StreamingInboundSpeed = std::stoi(it->second);
|
m_StreamingInboundSpeed = std::stoi(it->second);
|
||||||
|
if (it != params->end ())
|
||||||
|
m_StreamingMaxConcurrentStreams = std::stoi(it->second);
|
||||||
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
|
m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
|
||||||
|
@ -1514,6 +1535,8 @@ namespace client
|
||||||
RunnableService ("Destination"),
|
RunnableService ("Destination"),
|
||||||
ClientDestination (GetIOService (), keys, isPublic, params)
|
ClientDestination (GetIOService (), keys, isPublic, params)
|
||||||
{
|
{
|
||||||
|
if (!GetNickname ().empty ())
|
||||||
|
RunnableService::SetName (GetNickname ());
|
||||||
}
|
}
|
||||||
|
|
||||||
RunnableClientDestination::~RunnableClientDestination ()
|
RunnableClientDestination::~RunnableClientDestination ()
|
||||||
|
|
|
@ -42,7 +42,8 @@ namespace client
|
||||||
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
|
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
|
||||||
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
||||||
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
||||||
const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes
|
const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds
|
||||||
|
const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds
|
||||||
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
||||||
|
|
||||||
// I2CP
|
// I2CP
|
||||||
|
@ -94,6 +95,8 @@ namespace client
|
||||||
const int STREAMING_PROFILE_BULK = 1; // high bandwidth
|
const int STREAMING_PROFILE_BULK = 1; // high bandwidth
|
||||||
const int STREAMING_PROFILE_INTERACTIVE = 2; // low bandwidth
|
const int STREAMING_PROFILE_INTERACTIVE = 2; // low bandwidth
|
||||||
const int DEFAULT_STREAMING_PROFILE = STREAMING_PROFILE_BULK;
|
const int DEFAULT_STREAMING_PROFILE = STREAMING_PROFILE_BULK;
|
||||||
|
const char I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS[] = "i2p.streaming.maxConcurrentStreams";
|
||||||
|
const int DEFAULT_MAX_CONCURRENT_STREAMS = 2048;
|
||||||
|
|
||||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||||
|
|
||||||
|
@ -197,6 +200,9 @@ namespace client
|
||||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > m_IncomingMsgsQueue;
|
||||||
|
mutable std::mutex m_IncomingMsgsQueueMutex;
|
||||||
|
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||||
std::mutex m_LeaseSetMutex;
|
std::mutex m_LeaseSetMutex;
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> m_LeaseSet;
|
std::shared_ptr<const i2p::data::LocalLeaseSet> m_LeaseSet;
|
||||||
|
@ -269,6 +275,7 @@ namespace client
|
||||||
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
||||||
int GetStreamingOutboundSpeed () const { return m_StreamingOutboundSpeed; }
|
int GetStreamingOutboundSpeed () const { return m_StreamingOutboundSpeed; }
|
||||||
int GetStreamingInboundSpeed () const { return m_StreamingInboundSpeed; }
|
int GetStreamingInboundSpeed () const { return m_StreamingInboundSpeed; }
|
||||||
|
int GetStreamingMaxConcurrentStreams () const { return m_StreamingMaxConcurrentStreams; }
|
||||||
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
|
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
|
||||||
|
|
||||||
// datagram
|
// datagram
|
||||||
|
@ -305,9 +312,7 @@ namespace client
|
||||||
std::unique_ptr<EncryptionKey> m_StandardEncryptionKey;
|
std::unique_ptr<EncryptionKey> m_StandardEncryptionKey;
|
||||||
std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
|
std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
|
||||||
|
|
||||||
int m_StreamingAckDelay;
|
int m_StreamingAckDelay,m_StreamingOutboundSpeed, m_StreamingInboundSpeed, m_StreamingMaxConcurrentStreams;
|
||||||
int m_StreamingOutboundSpeed;
|
|
||||||
int m_StreamingInboundSpeed;
|
|
||||||
bool m_IsStreamingAnswerPings;
|
bool m_IsStreamingAnswerPings;
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||||
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
||||||
|
|
|
@ -1112,6 +1112,8 @@ namespace garlic
|
||||||
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
||||||
{
|
{
|
||||||
CleanupUnconfirmedLeaseSet (ts);
|
CleanupUnconfirmedLeaseSet (ts);
|
||||||
|
if (!m_Destination && ts > m_LastActivityTimestamp + ECIESX25519_SESSION_CREATE_TIMEOUT) return true; // m_LastActivityTimestamp is NS receive time
|
||||||
|
if (m_State != eSessionStateEstablished && m_SessionCreatedTimestamp && ts > m_SessionCreatedTimestamp + ECIESX25519_SESSION_ESTABLISH_TIMEOUT) return true;
|
||||||
return ts > m_LastActivityTimestamp + ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT && // seconds
|
return ts > m_LastActivityTimestamp + ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT && // seconds
|
||||||
ts*1000 > m_LastSentTimestamp + ECIESX25519_SEND_EXPIRATION_TIMEOUT*1000; // milliseconds
|
ts*1000 > m_LastSentTimestamp + ECIESX25519_SEND_EXPIRATION_TIMEOUT*1000; // milliseconds
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ namespace garlic
|
||||||
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||||
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
|
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
|
||||||
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
|
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||||
|
const int ECIESX25519_SESSION_CREATE_TIMEOUT = 3; // in seconds, NSR must be send after NS received
|
||||||
|
const int ECIESX25519_SESSION_ESTABLISH_TIMEOUT = 15; // in seconds
|
||||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds
|
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds
|
||||||
const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds
|
const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds
|
||||||
const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3;
|
const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3;
|
||||||
|
@ -169,7 +171,7 @@ namespace garlic
|
||||||
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
||||||
|
|
||||||
void Terminate () { m_IsTerminated = true; }
|
void Terminate () { m_IsTerminated = true; }
|
||||||
void SetDestination (const i2p::data::IdentHash& dest) // TODO:
|
void SetDestination (const i2p::data::IdentHash& dest)
|
||||||
{
|
{
|
||||||
if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest));
|
if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest));
|
||||||
}
|
}
|
||||||
|
@ -224,7 +226,7 @@ namespace garlic
|
||||||
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds)
|
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds)
|
||||||
m_LastSentTimestamp = 0; // in milliseconds
|
m_LastSentTimestamp = 0; // in milliseconds
|
||||||
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
|
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
|
||||||
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
std::unique_ptr<i2p::data::IdentHash> m_Destination;// must be set for NS if outgoing and NSR if incoming
|
||||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // incoming (tagsetid, index)
|
std::list<std::pair<uint16_t, int> > m_AckRequests; // incoming (tagsetid, index)
|
||||||
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
|
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
|
||||||
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -457,86 +457,6 @@ namespace crypto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !OPENSSL_X25519
|
|
||||||
BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const
|
|
||||||
{
|
|
||||||
BN_CTX_start (ctx);
|
|
||||||
auto x1 = BN_CTX_get (ctx); BN_copy (x1, u);
|
|
||||||
auto x2 = BN_CTX_get (ctx); BN_one (x2);
|
|
||||||
auto z2 = BN_CTX_get (ctx); BN_zero (z2);
|
|
||||||
auto x3 = BN_CTX_get (ctx); BN_copy (x3, u);
|
|
||||||
auto z3 = BN_CTX_get (ctx); BN_one (z3);
|
|
||||||
auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666);
|
|
||||||
auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx);
|
|
||||||
unsigned int swap = 0;
|
|
||||||
auto bits = BN_num_bits (k);
|
|
||||||
while(bits)
|
|
||||||
{
|
|
||||||
--bits;
|
|
||||||
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
|
|
||||||
swap ^= k_t;
|
|
||||||
if (swap)
|
|
||||||
{
|
|
||||||
std::swap (x2, x3);
|
|
||||||
std::swap (z2, z3);
|
|
||||||
}
|
|
||||||
swap = k_t;
|
|
||||||
BN_mod_sub(tmp0, x3, z3, q, ctx);
|
|
||||||
BN_mod_sub(tmp1, x2, z2, q, ctx);
|
|
||||||
BN_mod_add(x2, x2, z2, q, ctx);
|
|
||||||
BN_mod_add(z2, x3, z3, q, ctx);
|
|
||||||
BN_mod_mul(z3, tmp0, x2, q, ctx);
|
|
||||||
BN_mod_mul(z2, z2, tmp1, q, ctx);
|
|
||||||
BN_mod_sqr(tmp0, tmp1, q, ctx);
|
|
||||||
BN_mod_sqr(tmp1, x2, q, ctx);
|
|
||||||
BN_mod_add(x3, z3, z2, q, ctx);
|
|
||||||
BN_mod_sub(z2, z3, z2, q, ctx);
|
|
||||||
BN_mod_mul(x2, tmp1, tmp0, q, ctx);
|
|
||||||
BN_mod_sub(tmp1, tmp1, tmp0, q, ctx);
|
|
||||||
BN_mod_sqr(z2, z2, q, ctx);
|
|
||||||
BN_mod_mul(z3, tmp1, c121666, q, ctx);
|
|
||||||
BN_mod_sqr(x3, x3, q, ctx);
|
|
||||||
BN_mod_add(tmp0, tmp0, z3, q, ctx);
|
|
||||||
BN_mod_mul(z3, x1, z2, q, ctx);
|
|
||||||
BN_mod_mul(z2, tmp1, tmp0, q, ctx);
|
|
||||||
}
|
|
||||||
if (swap)
|
|
||||||
{
|
|
||||||
std::swap (x2, x3);
|
|
||||||
std::swap (z2, z3);
|
|
||||||
}
|
|
||||||
BN_mod_inverse (z2, z2, q, ctx);
|
|
||||||
BIGNUM * res = BN_new (); // not from ctx
|
|
||||||
BN_mod_mul(res, x2, z2, q, ctx);
|
|
||||||
BN_CTX_end (ctx);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
|
|
||||||
{
|
|
||||||
BIGNUM * p1 = DecodeBN<32> (p);
|
|
||||||
uint8_t k[32];
|
|
||||||
memcpy (k, e, 32);
|
|
||||||
k[0] &= 248; k[31] &= 127; k[31] |= 64;
|
|
||||||
BIGNUM * n = DecodeBN<32> (k);
|
|
||||||
BIGNUM * q1 = ScalarMul (p1, n, ctx);
|
|
||||||
EncodeBN (q1, buf, 32);
|
|
||||||
BN_free (p1); BN_free (n); BN_free (q1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
|
|
||||||
{
|
|
||||||
BIGNUM *p1 = BN_new (); BN_set_word (p1, 9);
|
|
||||||
uint8_t k[32];
|
|
||||||
memcpy (k, e, 32);
|
|
||||||
k[0] &= 248; k[31] &= 127; k[31] |= 64;
|
|
||||||
BIGNUM * n = DecodeBN<32> (k);
|
|
||||||
BIGNUM * q1 = ScalarMul (p1, n, ctx);
|
|
||||||
EncodeBN (q1, buf, 32);
|
|
||||||
BN_free (p1); BN_free (n); BN_free (q1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
|
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
|
||||||
{
|
{
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -84,10 +84,7 @@ namespace crypto
|
||||||
EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const;
|
EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const;
|
||||||
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const;
|
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const;
|
||||||
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const;
|
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const;
|
||||||
#if !OPENSSL_X25519
|
|
||||||
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
|
|
||||||
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
|
|
||||||
#endif
|
|
||||||
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
|
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
|
||||||
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
|
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
|
||||||
|
|
||||||
|
@ -115,11 +112,6 @@ namespace crypto
|
||||||
BIGNUM * DecodeBN (const uint8_t * buf) const;
|
BIGNUM * DecodeBN (const uint8_t * buf) const;
|
||||||
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const;
|
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const;
|
||||||
|
|
||||||
#if !OPENSSL_X25519
|
|
||||||
// for x25519
|
|
||||||
BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
BIGNUM * q, * l, * d, * I;
|
BIGNUM * q, * l, * d, * I;
|
||||||
|
|
|
@ -426,7 +426,8 @@ namespace garlic
|
||||||
}
|
}
|
||||||
|
|
||||||
GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
|
GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
|
||||||
m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard
|
m_PayloadBuffer (nullptr), m_LastIncomingSessionTimestamp (0),
|
||||||
|
m_NumRatchetInboundTags (0) // 0 means standard
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,10 +540,18 @@ namespace garlic
|
||||||
else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||||
{
|
{
|
||||||
// otherwise ECIESx25519
|
// otherwise ECIESx25519
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
if (ts > m_LastIncomingSessionTimestamp + INCOMING_SESSIONS_MINIMAL_INTERVAL)
|
||||||
|
{
|
||||||
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
||||||
if (!session->HandleNextMessage (buf, length, nullptr, 0))
|
if (session->HandleNextMessage (buf, length, nullptr, 0))
|
||||||
|
m_LastIncomingSessionTimestamp = ts;
|
||||||
|
else
|
||||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "Garlic: Incoming sessions come too ofter");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Garlic: Failed to decrypt message");
|
LogPrint (eLogError, "Garlic: Failed to decrypt message");
|
||||||
}
|
}
|
||||||
|
@ -737,7 +746,8 @@ namespace garlic
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet,
|
||||||
|
bool requestNewIfNotFound)
|
||||||
{
|
{
|
||||||
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD &&
|
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD &&
|
||||||
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||||
|
@ -752,16 +762,17 @@ namespace garlic
|
||||||
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
|
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Garlic: Session restarted");
|
LogPrint (eLogDebug, "Garlic: Session restarted");
|
||||||
|
requestNewIfNotFound = true; // it's not a new session
|
||||||
session = nullptr;
|
session = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!session)
|
if (!session && requestNewIfNotFound)
|
||||||
{
|
{
|
||||||
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
|
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
|
||||||
session->SetRemoteStaticKey (staticKey);
|
session->SetRemoteStaticKey (staticKey);
|
||||||
}
|
}
|
||||||
if (destination->IsDestination ())
|
if (session && destination->IsDestination ())
|
||||||
session->SetDestination (destination->GetIdentHash ()); // TODO: remove
|
session->SetDestination (destination->GetIdentHash ()); // NS or NSR
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace garlic
|
||||||
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
||||||
const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
||||||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 120; // in seconds
|
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 120; // in seconds
|
||||||
|
const int INCOMING_SESSIONS_MINIMAL_INTERVAL = 200; // in milliseconds
|
||||||
|
|
||||||
struct SessionTag: public i2p::data::Tag<32>
|
struct SessionTag: public i2p::data::Tag<32>
|
||||||
{
|
{
|
||||||
|
@ -234,7 +235,8 @@ namespace garlic
|
||||||
int GetNumTags () const { return m_NumTags; };
|
int GetNumTags () const { return m_NumTags; };
|
||||||
void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; };
|
void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; };
|
||||||
int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; };
|
int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; };
|
||||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||||
|
bool attachLeaseSet, bool requestNewIfNotFound = true);
|
||||||
void CleanupExpiredTags ();
|
void CleanupExpiredTags ();
|
||||||
void RemoveDeliveryStatusSession (uint32_t msgID);
|
void RemoveDeliveryStatusSession (uint32_t msgID);
|
||||||
std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
|
std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
|
@ -284,6 +286,7 @@ namespace garlic
|
||||||
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
||||||
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
||||||
uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet
|
uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet
|
||||||
|
uint64_t m_LastIncomingSessionTimestamp; // in millseconds
|
||||||
// incoming
|
// incoming
|
||||||
int m_NumRatchetInboundTags;
|
int m_NumRatchetInboundTags;
|
||||||
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
||||||
|
|
|
@ -103,6 +103,7 @@ namespace http
|
||||||
|
|
||||||
bool URL::parse(std::string_view url)
|
bool URL::parse(std::string_view url)
|
||||||
{
|
{
|
||||||
|
if (url.empty ()) return false;
|
||||||
std::size_t pos_p = 0; /* < current parse position */
|
std::size_t pos_p = 0; /* < current parse position */
|
||||||
std::size_t pos_c = 0; /* < work position */
|
std::size_t pos_c = 0; /* < work position */
|
||||||
if(url.at(0) != '/' || pos_p > 0)
|
if(url.at(0) != '/' || pos_p > 0)
|
||||||
|
|
|
@ -10,20 +10,15 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Crypto.h"
|
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "Transports.h"
|
#include "TransitTunnel.h"
|
||||||
#include "Garlic.h"
|
|
||||||
#include "ECIESX25519AEADRatchetSession.h"
|
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
using namespace i2p::transport;
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
|
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
|
||||||
|
@ -376,355 +371,6 @@ namespace i2p
|
||||||
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
|
|
||||||
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
|
||||||
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Failed to decrypt tunnel build record");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32) && // if next ident is now ours
|
|
||||||
!(clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG)) // and not endpoint
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Next ident is ours in tunnel build record");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint8_t retCode = 0;
|
|
||||||
// decide if we should accept tunnel
|
|
||||||
bool accept = i2p::context.AcceptsTunnels ();
|
|
||||||
if (accept)
|
|
||||||
{
|
|
||||||
auto congestionLevel = i2p::context.GetCongestionLevel (false);
|
|
||||||
if (congestionLevel >= CONGESTION_LEVEL_MEDIUM)
|
|
||||||
{
|
|
||||||
if (congestionLevel < CONGESTION_LEVEL_FULL)
|
|
||||||
{
|
|
||||||
// random reject depending on congestion level
|
|
||||||
int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM;
|
|
||||||
if (congestionLevel > level)
|
|
||||||
accept = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
accept = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// replace record to reply
|
|
||||||
if (accept)
|
|
||||||
{
|
|
||||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
|
||||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
|
||||||
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
|
||||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
|
||||||
clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
|
||||||
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
|
||||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
|
||||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
|
||||||
if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel))
|
|
||||||
retCode = 30;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
retCode = 30; // always reject with bandwidth reason (30)
|
|
||||||
|
|
||||||
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
|
||||||
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
|
||||||
// encrypt reply
|
|
||||||
i2p::crypto::CBCEncryption encryption;
|
|
||||||
for (int j = 0; j < num; j++)
|
|
||||||
{
|
|
||||||
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
|
||||||
if (j == i)
|
|
||||||
{
|
|
||||||
uint8_t nonce[12];
|
|
||||||
memset (nonce, 0, 12);
|
|
||||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
|
|
||||||
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
|
||||||
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
|
||||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
int num = buf[0];
|
|
||||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
|
||||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
|
|
||||||
if (tunnel)
|
|
||||||
{
|
|
||||||
// endpoint of inbound tunnel
|
|
||||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
|
||||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
|
||||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
|
||||||
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
|
||||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
|
||||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
|
||||||
{
|
|
||||||
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
|
||||||
{
|
|
||||||
// so we send it to reply tunnel
|
|
||||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
|
||||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
|
||||||
eI2NPVariableTunnelBuildReply, buf, len,
|
|
||||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
|
||||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
|
||||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: TunnelBuild is too old for ECIES router");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HandleTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len, bool isShort)
|
|
||||||
{
|
|
||||||
int num = buf[0];
|
|
||||||
LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
|
|
||||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
|
|
||||||
if (len < num*recordSize + 1)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2NP: TunnelBuildReply message of ", num, " records is too short ", len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
|
|
||||||
if (tunnel)
|
|
||||||
{
|
|
||||||
// reply for outbound tunnel
|
|
||||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
|
||||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
|
||||||
i2p::tunnel::tunnels.AddOutboundTunnel (tunnel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
|
||||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
int num = buf[0];
|
|
||||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
|
|
||||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
|
|
||||||
if (tunnel)
|
|
||||||
{
|
|
||||||
// endpoint of inbound tunnel
|
|
||||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
|
||||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
|
||||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
|
||||||
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
|
||||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const uint8_t * record = buf + 1;
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours");
|
|
||||||
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
|
||||||
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
|
||||||
uint8_t replyKey[32]; // AEAD/Chacha20/Poly1305
|
|
||||||
i2p::crypto::AESKey layerKey, ivKey; // AES
|
|
||||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
|
|
||||||
memcpy (replyKey, noiseState.m_CK + 32, 32);
|
|
||||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
|
|
||||||
memcpy (layerKey, noiseState.m_CK + 32, 32);
|
|
||||||
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
|
|
||||||
if (isEndpoint)
|
|
||||||
{
|
|
||||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK);
|
|
||||||
memcpy (ivKey, noiseState.m_CK + 32, 32);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // if next ident is now ours
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Next ident is ours in short request record");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy (ivKey, noiseState.m_CK , 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we accept this tunnel
|
|
||||||
std::shared_ptr<i2p::tunnel::TransitTunnel> transitTunnel;
|
|
||||||
uint8_t retCode = 0;
|
|
||||||
if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL)
|
|
||||||
retCode = 30;
|
|
||||||
if (!retCode)
|
|
||||||
{
|
|
||||||
// create new transit tunnel
|
|
||||||
transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
|
||||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
|
||||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
|
||||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
|
||||||
layerKey, ivKey,
|
|
||||||
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
|
||||||
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
|
||||||
if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel))
|
|
||||||
retCode = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encrypt reply
|
|
||||||
uint8_t nonce[12];
|
|
||||||
memset (nonce, 0, 12);
|
|
||||||
uint8_t * reply = buf + 1;
|
|
||||||
for (int j = 0; j < num; j++)
|
|
||||||
{
|
|
||||||
nonce[4] = j; // nonce is record #
|
|
||||||
if (j == i)
|
|
||||||
{
|
|
||||||
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
|
||||||
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
|
|
||||||
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
|
|
||||||
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
|
||||||
}
|
|
||||||
// send reply
|
|
||||||
auto onDrop = [transitTunnel]()
|
|
||||||
{
|
|
||||||
if (transitTunnel)
|
|
||||||
{
|
|
||||||
auto t = transitTunnel->GetCreationTime ();
|
|
||||||
if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT)
|
|
||||||
// make transit tunnel expired
|
|
||||||
transitTunnel->SetCreationTime (t - i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (isEndpoint)
|
|
||||||
{
|
|
||||||
auto replyMsg = NewI2NPShortMessage ();
|
|
||||||
replyMsg->Concat (buf, len);
|
|
||||||
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
|
||||||
if (transitTunnel) replyMsg->onDrop = onDrop;
|
|
||||||
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
|
|
||||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
|
|
||||||
{
|
|
||||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
|
|
||||||
uint64_t tag;
|
|
||||||
memcpy (&tag, noiseState.m_CK, 8);
|
|
||||||
// we send it to reply tunnel
|
|
||||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
|
||||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
|
||||||
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// IBGW is local
|
|
||||||
uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
|
|
||||||
auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID);
|
|
||||||
if (tunnel)
|
|
||||||
{
|
|
||||||
tunnel->SendTunnelDataMsg (replyMsg);
|
|
||||||
tunnel->FlushTunnelDataMsgs ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto msg = CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
|
|
||||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
|
||||||
if (transitTunnel) msg->onDrop = onDrop;
|
|
||||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, msg);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
|
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
|
||||||
{
|
{
|
||||||
auto msg = NewI2NPTunnelMessage (false);
|
auto msg = NewI2NPTunnelMessage (false);
|
||||||
|
@ -820,41 +466,6 @@ namespace i2p
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
|
||||||
{
|
|
||||||
if (msg)
|
|
||||||
{
|
|
||||||
uint8_t typeID = msg->GetTypeID();
|
|
||||||
uint32_t msgID = msg->GetMsgID();
|
|
||||||
LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
|
||||||
uint8_t * payload = msg->GetPayload();
|
|
||||||
auto size = msg->GetPayloadLength();
|
|
||||||
switch (typeID)
|
|
||||||
{
|
|
||||||
case eI2NPVariableTunnelBuild:
|
|
||||||
HandleVariableTunnelBuildMsg (msgID, payload, size);
|
|
||||||
break;
|
|
||||||
case eI2NPShortTunnelBuild:
|
|
||||||
HandleShortTunnelBuildMsg (msgID, payload, size);
|
|
||||||
break;
|
|
||||||
case eI2NPVariableTunnelBuildReply:
|
|
||||||
HandleTunnelBuildReplyMsg (msgID, payload, size, false);
|
|
||||||
break;
|
|
||||||
case eI2NPShortTunnelBuildReply:
|
|
||||||
HandleTunnelBuildReplyMsg (msgID, payload, size, true);
|
|
||||||
break;
|
|
||||||
case eI2NPTunnelBuild:
|
|
||||||
HandleTunnelBuildMsg (payload, size);
|
|
||||||
break;
|
|
||||||
case eI2NPTunnelBuildReply:
|
|
||||||
// TODO:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
if (msg)
|
if (msg)
|
||||||
|
|
|
@ -316,7 +316,6 @@ namespace tunnel
|
||||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
|
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
|
||||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
|
||||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
class I2NPMessagesHandler
|
class I2NPMessagesHandler
|
||||||
|
|
|
@ -425,6 +425,16 @@ namespace data
|
||||||
if (offset + 1 > len) return 0;
|
if (offset + 1 > len) return 0;
|
||||||
int numLeases = buf[offset]; offset++;
|
int numLeases = buf[offset]; offset++;
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
if (GetExpirationTime () > ts + LEASESET_EXPIRATION_TIME_THRESHOLD)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "LeaseSet2: Expiration time is from future ", GetExpirationTime ()/1000LL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ts > m_PublishedTimestamp*1000LL + LEASESET_EXPIRATION_TIME_THRESHOLD)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "LeaseSet2: Published time is too old ", m_PublishedTimestamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (IsStoreLeases ())
|
if (IsStoreLeases ())
|
||||||
{
|
{
|
||||||
UpdateLeasesBegin ();
|
UpdateLeasesBegin ();
|
||||||
|
@ -435,6 +445,11 @@ namespace data
|
||||||
lease.tunnelGateway = buf + offset; offset += 32; // gateway
|
lease.tunnelGateway = buf + offset; offset += 32; // gateway
|
||||||
lease.tunnelID = bufbe32toh (buf + offset); offset += 4; // tunnel ID
|
lease.tunnelID = bufbe32toh (buf + offset); offset += 4; // tunnel ID
|
||||||
lease.endDate = bufbe32toh (buf + offset)*1000LL; offset += 4; // end date
|
lease.endDate = bufbe32toh (buf + offset)*1000LL; offset += 4; // end date
|
||||||
|
if (lease.endDate > ts + LEASESET_EXPIRATION_TIME_THRESHOLD)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "LeaseSet2: Lease end date is from future ", lease.endDate);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
UpdateLease (lease, ts);
|
UpdateLease (lease, ts);
|
||||||
}
|
}
|
||||||
UpdateLeasesEnd ();
|
UpdateLeasesEnd ();
|
||||||
|
|
|
@ -62,6 +62,7 @@ namespace data
|
||||||
const size_t LEASE_SIZE = 44; // 32 + 4 + 8
|
const size_t LEASE_SIZE = 44; // 32 + 4 + 8
|
||||||
const size_t LEASE2_SIZE = 40; // 32 + 4 + 4
|
const size_t LEASE2_SIZE = 40; // 32 + 4 + 4
|
||||||
const uint8_t MAX_NUM_LEASES = 16;
|
const uint8_t MAX_NUM_LEASES = 16;
|
||||||
|
const uint64_t LEASESET_EXPIRATION_TIME_THRESHOLD = 12*60*1000; // in milliseconds
|
||||||
|
|
||||||
const uint8_t NETDB_STORE_TYPE_LEASESET = 1;
|
const uint8_t NETDB_STORE_TYPE_LEASESET = 1;
|
||||||
class LeaseSet: public RoutingDestination
|
class LeaseSet: public RoutingDestination
|
||||||
|
@ -180,7 +181,7 @@ namespace data
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_StoreType;
|
uint8_t m_StoreType;
|
||||||
uint32_t m_PublishedTimestamp = 0;
|
uint32_t m_PublishedTimestamp = 0; // seconds
|
||||||
bool m_IsPublic = true, m_IsPublishedEncrypted = false;
|
bool m_IsPublic = true, m_IsPublishedEncrypted = false;
|
||||||
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
||||||
CryptoKeyType m_EncryptionType;
|
CryptoKeyType m_EncryptionType;
|
||||||
|
|
|
@ -375,6 +375,8 @@ namespace transport
|
||||||
m_Socket.close ();
|
m_Socket.close ();
|
||||||
transports.PeerDisconnected (shared_from_this ());
|
transports.PeerDisconnected (shared_from_this ());
|
||||||
m_Server.RemoveNTCP2Session (shared_from_this ());
|
m_Server.RemoveNTCP2Session (shared_from_this ());
|
||||||
|
if (!m_IntermediateQueue.empty ())
|
||||||
|
m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue);
|
||||||
for (auto& it: m_SendQueue)
|
for (auto& it: m_SendQueue)
|
||||||
it->Drop ();
|
it->Drop ();
|
||||||
m_SendQueue.clear ();
|
m_SendQueue.clear ();
|
||||||
|
@ -1207,7 +1209,7 @@ namespace transport
|
||||||
void NTCP2Session::MoveSendQueue (std::shared_ptr<NTCP2Session> other)
|
void NTCP2Session::MoveSendQueue (std::shared_ptr<NTCP2Session> other)
|
||||||
{
|
{
|
||||||
if (!other || m_SendQueue.empty ()) return;
|
if (!other || m_SendQueue.empty ()) return;
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
std::list<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
for (auto it: m_SendQueue)
|
for (auto it: m_SendQueue)
|
||||||
if (!it->IsExpired (ts))
|
if (!it->IsExpired (ts))
|
||||||
|
@ -1216,7 +1218,7 @@ namespace transport
|
||||||
it->Drop ();
|
it->Drop ();
|
||||||
m_SendQueue.clear ();
|
m_SendQueue.clear ();
|
||||||
if (!msgs.empty ())
|
if (!msgs.empty ())
|
||||||
other->PostI2NPMessages (msgs);
|
other->SendI2NPMessages (msgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
|
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
|
||||||
|
@ -1297,20 +1299,42 @@ namespace transport
|
||||||
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go
|
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
void NTCP2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs)
|
||||||
{
|
{
|
||||||
m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs));
|
if (m_IsTerminated || msgs.empty ())
|
||||||
|
{
|
||||||
|
msgs.clear ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool empty = false;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
|
||||||
|
empty = m_IntermediateQueue.empty ();
|
||||||
|
m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
|
||||||
|
}
|
||||||
|
if (empty)
|
||||||
|
m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
void NTCP2Session::PostI2NPMessages ()
|
||||||
{
|
{
|
||||||
if (m_IsTerminated) return;
|
if (m_IsTerminated) return;
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
|
||||||
|
m_IntermediateQueue.swap (msgs);
|
||||||
|
}
|
||||||
bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2;
|
bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2;
|
||||||
|
if (isSemiFull)
|
||||||
|
{
|
||||||
for (auto it: msgs)
|
for (auto it: msgs)
|
||||||
if (isSemiFull && it->onDrop)
|
if (it->onDrop)
|
||||||
it->Drop (); // drop earlier because we can handle it
|
it->Drop (); // drop earlier because we can handle it
|
||||||
else
|
else
|
||||||
m_SendQueue.push_back (std::move (it));
|
m_SendQueue.push_back (std::move (it));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_SendQueue.splice (m_SendQueue.end (), msgs);
|
||||||
|
|
||||||
if (!m_IsSending && m_IsEstablished)
|
if (!m_IsSending && m_IsEstablished)
|
||||||
SendQueue ();
|
SendQueue ();
|
||||||
|
|
|
@ -153,7 +153,7 @@ namespace transport
|
||||||
void ServerLogin (); // Bob
|
void ServerLogin (); // Bob
|
||||||
|
|
||||||
void SendLocalRouterInfo (bool update) override; // after handshake or by update
|
void SendLocalRouterInfo (bool update) override; // after handshake or by update
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||||
void MoveSendQueue (std::shared_ptr<NTCP2Session> other);
|
void MoveSendQueue (std::shared_ptr<NTCP2Session> other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -196,7 +196,7 @@ namespace transport
|
||||||
void SendRouterInfo ();
|
void SendRouterInfo ();
|
||||||
void SendTermination (NTCP2TerminationReason reason);
|
void SendTermination (NTCP2TerminationReason reason);
|
||||||
void SendTerminationAndTerminate (NTCP2TerminationReason reason);
|
void SendTerminationAndTerminate (NTCP2TerminationReason reason);
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
void PostI2NPMessages ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -230,6 +230,9 @@ namespace transport
|
||||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
uint64_t m_NextRouterInfoResendTime; // seconds since epoch
|
uint64_t m_NextRouterInfoResendTime; // seconds since epoch
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > m_IntermediateQueue; // from transports
|
||||||
|
mutable std::mutex m_IntermediateQueueMutex;
|
||||||
|
|
||||||
uint16_t m_PaddingSizes[16];
|
uint16_t m_PaddingSizes[16];
|
||||||
int m_NextPaddingSize;
|
int m_NextPaddingSize;
|
||||||
};
|
};
|
||||||
|
|
|
@ -384,8 +384,7 @@ namespace data
|
||||||
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
|
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
|
||||||
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
|
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
|
||||||
{
|
{
|
||||||
if (leaseSet->IsPublic () && !leaseSet->IsExpired () &&
|
if (leaseSet->IsPublic () && !leaseSet->IsExpired ())
|
||||||
i2p::util::GetSecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD > leaseSet->GetPublishedTimestamp ())
|
|
||||||
{
|
{
|
||||||
// TODO: implement actual update
|
// TODO: implement actual update
|
||||||
if (CheckLogLevel (eLogInfo))
|
if (CheckLogLevel (eLogInfo))
|
||||||
|
@ -480,7 +479,7 @@ namespace data
|
||||||
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
|
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "NetDB: Reseeding from floodfill ", ri.GetIdentHashBase64());
|
LogPrint(eLogInfo, "NetDB: Reseeding from floodfill ", ri.GetIdentHashBase64());
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > requests;
|
std::list<std::shared_ptr<i2p::I2NPMessage> > requests;
|
||||||
|
|
||||||
i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
|
i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
|
||||||
i2p::data::IdentHash ih = ri.GetIdentHash();
|
i2p::data::IdentHash ih = ri.GetIdentHash();
|
||||||
|
|
|
@ -206,10 +206,9 @@ namespace data
|
||||||
return m_NumTunnelsNonReplied > 10*(total + 1);
|
return m_NumTunnelsNonReplied > 10*(total + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterProfile::IsDeclinedRecently ()
|
bool RouterProfile::IsDeclinedRecently (uint64_t ts)
|
||||||
{
|
{
|
||||||
if (!m_LastDeclineTime) return false;
|
if (!m_LastDeclineTime) return false;
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL ||
|
if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL ||
|
||||||
ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime)
|
ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime)
|
||||||
m_LastDeclineTime = 0;
|
m_LastDeclineTime = 0;
|
||||||
|
@ -218,7 +217,10 @@ namespace data
|
||||||
|
|
||||||
bool RouterProfile::IsBad ()
|
bool RouterProfile::IsBad ()
|
||||||
{
|
{
|
||||||
if (IsDeclinedRecently () || IsUnreachable () || m_IsDuplicated) return true;
|
if (IsUnreachable () || m_IsDuplicated) return true;
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
if (ts > PEER_PROFILE_MAX_DECLINED_INTERVAL + m_LastDeclineTime) return false;
|
||||||
|
if (IsDeclinedRecently (ts)) return true;
|
||||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,10 +38,12 @@ namespace data
|
||||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 900; // in seconds (15 minutes)
|
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 900; // in seconds (15 minutes)
|
||||||
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT = 5400; // in seconds (1.5 hours)
|
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT = 5400; // in seconds (1.5 hours)
|
||||||
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes)
|
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes)
|
||||||
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
|
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 330; // in seconds (5.5 minutes)
|
||||||
|
const int PEER_PROFILE_MAX_DECLINED_INTERVAL = 4400; // in second (1.5 hours)
|
||||||
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
|
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
|
||||||
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
|
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
|
||||||
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
|
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
|
||||||
|
const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined
|
||||||
|
|
||||||
class RouterProfile
|
class RouterProfile
|
||||||
{
|
{
|
||||||
|
@ -81,7 +83,7 @@ namespace data
|
||||||
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||||
bool IsLowPartcipationRate () const;
|
bool IsLowPartcipationRate () const;
|
||||||
bool IsLowReplyRate () const;
|
bool IsLowReplyRate () const;
|
||||||
bool IsDeclinedRecently ();
|
bool IsDeclinedRecently (uint64_t ts);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -323,9 +323,11 @@ namespace i2p
|
||||||
case eRouterStatusFirewalled:
|
case eRouterStatusFirewalled:
|
||||||
SetUnreachable (true, false); // ipv4
|
SetUnreachable (true, false); // ipv4
|
||||||
break;
|
break;
|
||||||
|
case eRouterStatusMesh:
|
||||||
|
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eReachable);
|
||||||
|
break;
|
||||||
case eRouterStatusProxy:
|
case eRouterStatusProxy:
|
||||||
m_AcceptsTunnels = false;
|
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eUnreachable);
|
||||||
UpdateCongestion ();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
|
@ -1489,7 +1491,7 @@ namespace i2p
|
||||||
void RouterContext::UpdateCongestion ()
|
void RouterContext::UpdateCongestion ()
|
||||||
{
|
{
|
||||||
auto c = i2p::data::RouterInfo::eLowCongestion;
|
auto c = i2p::data::RouterInfo::eLowCongestion;
|
||||||
if (!AcceptsTunnels () || !m_ShareRatio || (m_Error == eRouterErrorSymmetricNAT && !SupportsV6 () && !SupportsMesh ()))
|
if (!AcceptsTunnels () || !m_ShareRatio)
|
||||||
c = i2p::data::RouterInfo::eRejectAll;
|
c = i2p::data::RouterInfo::eRejectAll;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1508,7 +1510,7 @@ namespace i2p
|
||||||
if (m_CleanupTimer)
|
if (m_CleanupTimer)
|
||||||
{
|
{
|
||||||
m_CleanupTimer->cancel ();
|
m_CleanupTimer->cancel ();
|
||||||
m_CleanupTimer->expires_from_now (boost::posix_time::minutes(ROUTER_INFO_CLEANUP_INTERVAL));
|
m_CleanupTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CLEANUP_INTERVAL));
|
||||||
m_CleanupTimer->async_wait (std::bind (&RouterContext::HandleCleanupTimer,
|
m_CleanupTimer->async_wait (std::bind (&RouterContext::HandleCleanupTimer,
|
||||||
this, std::placeholders::_1));
|
this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace garlic
|
||||||
const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
|
const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||||
const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||||
const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
|
const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
|
||||||
const int ROUTER_INFO_CLEANUP_INTERVAL = 5; // in minutes
|
const int ROUTER_INFO_CLEANUP_INTERVAL = 102; // in seconds
|
||||||
|
|
||||||
enum RouterStatus
|
enum RouterStatus
|
||||||
{
|
{
|
||||||
|
|
|
@ -457,13 +457,20 @@ namespace transport
|
||||||
void SSU2Server::InsertToReceivedPacketsQueue (std::list<Packet *>& packets)
|
void SSU2Server::InsertToReceivedPacketsQueue (std::list<Packet *>& packets)
|
||||||
{
|
{
|
||||||
if (packets.empty ()) return;
|
if (packets.empty ()) return;
|
||||||
bool empty = false;
|
size_t queueSize = 0;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(m_ReceivedPacketsQueueMutex);
|
std::lock_guard<std::mutex> l(m_ReceivedPacketsQueueMutex);
|
||||||
empty = m_ReceivedPacketsQueue.empty ();
|
queueSize = m_ReceivedPacketsQueue.size ();
|
||||||
|
if (queueSize < SSU2_MAX_RECEIVED_QUEUE_SIZE)
|
||||||
m_ReceivedPacketsQueue.splice (m_ReceivedPacketsQueue.end (), packets);
|
m_ReceivedPacketsQueue.splice (m_ReceivedPacketsQueue.end (), packets);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "SSU2: Received queue size ", queueSize, " exceeds max size", SSU2_MAX_RECEIVED_QUEUE_SIZE);
|
||||||
|
m_PacketsPool.ReleaseMt (packets);
|
||||||
|
queueSize = 0; // invoke processing just in case
|
||||||
}
|
}
|
||||||
if (empty)
|
}
|
||||||
|
if (!queueSize)
|
||||||
GetService ().post([this]() { HandleReceivedPacketsQueue (); });
|
GetService ().post([this]() { HandleReceivedPacketsQueue (); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace transport
|
||||||
const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024;
|
const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||||
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
||||||
const size_t SSU2_MIN_RECEIVED_PACKET_SIZE = 40; // 16 byte short header + 8 byte minimum payload + 16 byte MAC
|
const size_t SSU2_MIN_RECEIVED_PACKET_SIZE = 40; // 16 byte short header + 8 byte minimum payload + 16 byte MAC
|
||||||
|
const size_t SSU2_MAX_RECEIVED_QUEUE_SIZE = 2500; // in packets
|
||||||
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 = 15; // in seconds
|
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
|
||||||
|
|
|
@ -111,7 +111,6 @@ namespace transport
|
||||||
SendPeerTest (7, buf + offset, len - offset);
|
SendPeerTest (7, buf + offset, len - offset);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6");
|
LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6");
|
||||||
GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ());
|
|
||||||
GetServer ().RequestRemoveSession (GetConnID ());
|
GetServer ().RequestRemoveSession (GetConnID ());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +140,6 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ());
|
|
||||||
GetServer ().RequestRemoveSession (GetConnID ());
|
GetServer ().RequestRemoveSession (GetConnID ());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +186,7 @@ namespace transport
|
||||||
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
|
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
|
||||||
// send
|
// send
|
||||||
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ());
|
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ());
|
||||||
|
UpdateNumSentBytes (payloadSize + 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed)
|
void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed)
|
||||||
|
@ -309,6 +308,7 @@ namespace transport
|
||||||
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
|
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
|
||||||
// send
|
// send
|
||||||
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
|
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
|
||||||
|
UpdateNumSentBytes (payloadSize + 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen)
|
void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen)
|
||||||
|
|
|
@ -293,6 +293,8 @@ namespace transport
|
||||||
m_SentHandshakePacket.reset (nullptr);
|
m_SentHandshakePacket.reset (nullptr);
|
||||||
m_SessionConfirmedFragment.reset (nullptr);
|
m_SessionConfirmedFragment.reset (nullptr);
|
||||||
m_PathChallenge.reset (nullptr);
|
m_PathChallenge.reset (nullptr);
|
||||||
|
if (!m_IntermediateQueue.empty ())
|
||||||
|
m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue);
|
||||||
for (auto& it: m_SendQueue)
|
for (auto& it: m_SendQueue)
|
||||||
it->Drop ();
|
it->Drop ();
|
||||||
m_SendQueue.clear ();
|
m_SendQueue.clear ();
|
||||||
|
@ -335,13 +337,14 @@ namespace transport
|
||||||
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
|
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
|
||||||
SendQueue ();
|
SendQueue ();
|
||||||
transports.PeerConnected (shared_from_this ());
|
transports.PeerConnected (shared_from_this ());
|
||||||
|
|
||||||
|
LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
|
||||||
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established");
|
||||||
if (m_OnEstablished)
|
if (m_OnEstablished)
|
||||||
{
|
{
|
||||||
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 ()
|
||||||
|
@ -372,14 +375,31 @@ namespace transport
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
void SSU2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs)
|
||||||
{
|
{
|
||||||
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this (), msgs));
|
if (m_State == eSSU2SessionStateTerminated || msgs.empty ())
|
||||||
|
{
|
||||||
|
msgs.clear ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool empty = false;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
|
||||||
|
empty = m_IntermediateQueue.empty ();
|
||||||
|
m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
|
||||||
|
}
|
||||||
|
if (empty)
|
||||||
|
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
void SSU2Session::PostI2NPMessages ()
|
||||||
{
|
{
|
||||||
if (m_State == eSSU2SessionStateTerminated) return;
|
if (m_State == eSSU2SessionStateTerminated) return;
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
|
||||||
|
m_IntermediateQueue.swap (msgs);
|
||||||
|
}
|
||||||
uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
|
uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
|
||||||
bool isSemiFull = false;
|
bool isSemiFull = false;
|
||||||
if (m_SendQueue.size ())
|
if (m_SendQueue.size ())
|
||||||
|
@ -393,9 +413,11 @@ namespace transport
|
||||||
" is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")");
|
" is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isSemiFull)
|
||||||
|
{
|
||||||
for (auto it: msgs)
|
for (auto it: msgs)
|
||||||
{
|
{
|
||||||
if (isSemiFull && it->onDrop)
|
if (it->onDrop)
|
||||||
it->Drop (); // drop earlier because we can handle it
|
it->Drop (); // drop earlier because we can handle it
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -403,6 +425,12 @@ namespace transport
|
||||||
m_SendQueue.push_back (std::move (it));
|
m_SendQueue.push_back (std::move (it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& it: msgs) it->SetEnqueueTime (mts);
|
||||||
|
m_SendQueue.splice (m_SendQueue.end (), msgs);
|
||||||
|
}
|
||||||
if (IsEstablished ())
|
if (IsEstablished ())
|
||||||
{
|
{
|
||||||
SendQueue ();
|
SendQueue ();
|
||||||
|
@ -415,7 +443,7 @@ namespace transport
|
||||||
void SSU2Session::MoveSendQueue (std::shared_ptr<SSU2Session> other)
|
void SSU2Session::MoveSendQueue (std::shared_ptr<SSU2Session> other)
|
||||||
{
|
{
|
||||||
if (!other || m_SendQueue.empty ()) return;
|
if (!other || m_SendQueue.empty ()) return;
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
std::list<std::shared_ptr<I2NPMessage> > msgs;
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
for (auto it: m_SendQueue)
|
for (auto it: m_SendQueue)
|
||||||
if (!it->IsExpired (ts))
|
if (!it->IsExpired (ts))
|
||||||
|
@ -424,7 +452,7 @@ namespace transport
|
||||||
it->Drop ();
|
it->Drop ();
|
||||||
m_SendQueue.clear ();
|
m_SendQueue.clear ();
|
||||||
if (!msgs.empty ())
|
if (!msgs.empty ())
|
||||||
other->PostI2NPMessages (msgs);
|
other->SendI2NPMessages (msgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SSU2Session::SendQueue ()
|
bool SSU2Session::SendQueue ()
|
||||||
|
@ -1917,21 +1945,28 @@ namespace transport
|
||||||
void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len)
|
void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
// we are Bob
|
// we are Bob
|
||||||
|
auto mts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
uint32_t nonce = bufbe32toh (buf + 1); // nonce
|
||||||
uint32_t relayTag = bufbe32toh (buf + 5); // relay tag
|
uint32_t relayTag = bufbe32toh (buf + 5); // relay tag
|
||||||
auto session = m_Server.FindRelaySession (relayTag);
|
auto session = m_Server.FindRelaySession (relayTag);
|
||||||
if (!session)
|
if (!session)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found");
|
LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found");
|
||||||
// send relay response back to Alice
|
// send relay response back to Alice
|
||||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
|
||||||
size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
|
packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize);
|
||||||
eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), 0, false);
|
packet->payloadSize += CreateRelayResponseBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize,
|
||||||
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
|
eSSU2RelayResponseCodeBobRelayTagNotFound, nonce, 0, false);
|
||||||
SendData (payload, payloadSize);
|
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
|
||||||
|
uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
|
||||||
|
if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
|
||||||
|
{
|
||||||
|
// sometimes Alice doesn't ack this RelayResponse in older versions
|
||||||
|
packet->sendTime = mts;
|
||||||
|
m_SentPackets.emplace (packetNum, packet);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto mts = i2p::util::GetMillisecondsSinceEpoch ();
|
|
||||||
uint32_t nonce = bufbe32toh (buf + 1);
|
|
||||||
if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second)
|
if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second)
|
||||||
{
|
{
|
||||||
// send relay intro to Charlie
|
// send relay intro to Charlie
|
||||||
|
|
|
@ -261,7 +261,7 @@ namespace transport
|
||||||
void FlushData ();
|
void FlushData ();
|
||||||
void Done () override;
|
void Done () override;
|
||||||
void SendLocalRouterInfo (bool update) override;
|
void SendLocalRouterInfo (bool update) override;
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||||
void MoveSendQueue (std::shared_ptr<SSU2Session> other);
|
void MoveSendQueue (std::shared_ptr<SSU2Session> other);
|
||||||
uint32_t GetRelayTag () const override { return m_RelayTag; };
|
uint32_t GetRelayTag () const override { return m_RelayTag; };
|
||||||
size_t Resend (uint64_t ts); // return number of resent packets
|
size_t Resend (uint64_t ts); // return number of resent packets
|
||||||
|
@ -307,7 +307,7 @@ namespace transport
|
||||||
void Established ();
|
void Established ();
|
||||||
void ScheduleConnectTimer ();
|
void ScheduleConnectTimer ();
|
||||||
void HandleConnectTimer (const boost::system::error_code& ecode);
|
void HandleConnectTimer (const boost::system::error_code& ecode);
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
void PostI2NPMessages ();
|
||||||
bool SendQueue (); // returns true if ack block was sent
|
bool SendQueue (); // returns true if ack block was sent
|
||||||
bool SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
|
bool SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ResendHandshakePacket ();
|
void ResendHandshakePacket ();
|
||||||
|
@ -381,6 +381,8 @@ namespace transport
|
||||||
std::unordered_map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
std::unordered_map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
||||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
i2p::I2NPMessagesHandler m_Handler;
|
i2p::I2NPMessagesHandler m_Handler;
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > m_IntermediateQueue; // from transports
|
||||||
|
mutable std::mutex m_IntermediateQueueMutex;
|
||||||
bool m_IsDataReceived;
|
bool m_IsDataReceived;
|
||||||
double m_RTT;
|
double m_RTT;
|
||||||
int m_MsgLocalExpirationTimeout;
|
int m_MsgLocalExpirationTimeout;
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace stream
|
||||||
m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0),
|
m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0),
|
||||||
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
|
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
|
||||||
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
|
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
|
||||||
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
|
m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
|
||||||
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
|
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
|
||||||
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local),
|
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local),
|
||||||
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service),
|
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service),
|
||||||
|
@ -99,7 +99,7 @@ namespace stream
|
||||||
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0),
|
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0),
|
||||||
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
|
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
|
||||||
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
|
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
|
||||||
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
|
m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
|
||||||
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
|
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
|
||||||
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local),
|
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_LocalDestination (local),
|
||||||
m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
|
m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
|
||||||
|
@ -705,6 +705,7 @@ namespace stream
|
||||||
|
|
||||||
void Stream::SendBuffer ()
|
void Stream::SendBuffer ()
|
||||||
{
|
{
|
||||||
|
if (m_RemoteLeaseSet) // don't scheudle send for first SYN for incoming stream
|
||||||
ScheduleSend ();
|
ScheduleSend ();
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
int numMsgs = m_WindowSize - m_SentPackets.size ();
|
int numMsgs = m_WindowSize - m_SentPackets.size ();
|
||||||
|
@ -756,8 +757,8 @@ namespace stream
|
||||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
|
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
|
||||||
if (m_RemoteLeaseSet)
|
if (m_RemoteLeaseSet)
|
||||||
{
|
{
|
||||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
|
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming);
|
||||||
m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
|
m_MTU = (m_RoutingSession && m_RoutingSession->IsRatchets ()) ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
|
||||||
}
|
}
|
||||||
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
|
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
|
||||||
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
|
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
|
||||||
|
@ -1114,7 +1115,15 @@ namespace stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent
|
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent
|
||||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
|
{
|
||||||
|
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming || m_SequenceNumber > 1);
|
||||||
|
if (!m_RoutingSession)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Streaming: Can't obtain routing session, sSID=", m_SendStreamID);
|
||||||
|
Terminate ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send
|
if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send
|
||||||
{
|
{
|
||||||
// try to get shared path first
|
// try to get shared path first
|
||||||
|
@ -1329,6 +1338,13 @@ namespace stream
|
||||||
void Stream::ResendPacket ()
|
void Stream::ResendPacket ()
|
||||||
{
|
{
|
||||||
// check for resend attempts
|
// check for resend attempts
|
||||||
|
if (m_IsIncoming && m_SequenceNumber == 1 && m_NumResendAttempts > 0)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Streaming: SYNACK packet was not ACKed after ", m_NumResendAttempts, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID);
|
||||||
|
m_Status = eStreamStatusReset;
|
||||||
|
Close ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
|
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID);
|
LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate, rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID);
|
||||||
|
@ -1471,6 +1487,8 @@ namespace stream
|
||||||
if (!remoteLeaseSet)
|
if (!remoteLeaseSet)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found");
|
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found");
|
||||||
|
if (!m_IsIncoming) // outgoing
|
||||||
|
{
|
||||||
if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ())
|
if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ())
|
||||||
{
|
{
|
||||||
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
|
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
|
||||||
|
@ -1483,6 +1501,13 @@ namespace stream
|
||||||
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
|
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // incoming
|
||||||
|
{
|
||||||
|
// just close the socket without sending FIN or RST
|
||||||
|
m_Status = eStreamStatusClosed;
|
||||||
|
AsyncClose ();
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// LeaseSet updated
|
// LeaseSet updated
|
||||||
|
@ -1696,9 +1721,20 @@ namespace stream
|
||||||
DeletePacket (packet); // drop it, because previous should be connected
|
DeletePacket (packet); // drop it, because previous should be connected
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (m_Owner->GetStreamingMaxConcurrentStreams () > 0 && (int)m_Streams.size () > m_Owner->GetStreamingMaxConcurrentStreams ())
|
||||||
|
{
|
||||||
|
LogPrint(eLogWarning, "Streaming: Number of streams exceeds ", m_Owner->GetStreamingMaxConcurrentStreams ());
|
||||||
|
DeletePacket (packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto incomingStream = CreateNewIncomingStream (receiveStreamID);
|
auto incomingStream = CreateNewIncomingStream (receiveStreamID);
|
||||||
incomingStream->HandleNextPacket (packet); // SYN
|
incomingStream->HandleNextPacket (packet); // SYN
|
||||||
auto ident = incomingStream->GetRemoteIdentity();
|
if (!incomingStream->GetRemoteLeaseSet ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Streaming: No remote LeaseSet for incoming stream. Terminated");
|
||||||
|
incomingStream->Terminate (); // can't send FIN anyway
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// handle saved packets if any
|
// handle saved packets if any
|
||||||
{
|
{
|
||||||
|
@ -1800,6 +1836,7 @@ namespace stream
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||||
m_Streams.erase (stream->GetRecvStreamID ());
|
m_Streams.erase (stream->GetRecvStreamID ());
|
||||||
|
if (stream->IsIncoming ())
|
||||||
m_IncomingStreams.erase (stream->GetSendStreamID ());
|
m_IncomingStreams.erase (stream->GetSendStreamID ());
|
||||||
if (m_LastStream == stream) m_LastStream = nullptr;
|
if (m_LastStream == stream) m_LastStream = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,7 @@ namespace stream
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () const { return m_RemoteIdentity; };
|
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () const { return m_RemoteIdentity; };
|
||||||
bool IsOpen () const { return m_Status == eStreamStatusOpen; };
|
bool IsOpen () const { return m_Status == eStreamStatusOpen; };
|
||||||
bool IsEstablished () const { return m_SendStreamID; };
|
bool IsEstablished () const { return m_SendStreamID; };
|
||||||
|
bool IsIncoming () const { return m_IsIncoming; };
|
||||||
StreamStatus GetStatus () const { return m_Status; };
|
StreamStatus GetStatus () const { return m_Status; };
|
||||||
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
||||||
void ResetRoutingPath ();
|
void ResetRoutingPath ();
|
||||||
|
@ -262,6 +263,7 @@ namespace stream
|
||||||
int32_t m_PreviousReceivedSequenceNumber;
|
int32_t m_PreviousReceivedSequenceNumber;
|
||||||
int32_t m_LastConfirmedReceivedSequenceNumber; // for limit inbound speed
|
int32_t m_LastConfirmedReceivedSequenceNumber; // for limit inbound speed
|
||||||
StreamStatus m_Status;
|
StreamStatus m_Status;
|
||||||
|
bool m_IsIncoming;
|
||||||
bool m_IsAckSendScheduled;
|
bool m_IsAckSendScheduled;
|
||||||
bool m_IsNAcked;
|
bool m_IsNAcked;
|
||||||
bool m_IsFirstACK;
|
bool m_IsFirstACK;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -8,9 +8,12 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
|
#include "Crypto.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
|
#include "Garlic.h"
|
||||||
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
#include "TransitTunnel.h"
|
#include "TransitTunnel.h"
|
||||||
|
@ -59,8 +62,7 @@ namespace tunnel
|
||||||
auto num = m_TunnelDataMsgs.size ();
|
auto num = m_TunnelDataMsgs.size ();
|
||||||
if (num > 1)
|
if (num > 1)
|
||||||
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
|
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
|
||||||
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
|
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear
|
||||||
m_TunnelDataMsgs.clear ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,5 +121,334 @@ namespace tunnel
|
||||||
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TransitTunnels::Start ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitTunnels::Stop ()
|
||||||
|
{
|
||||||
|
m_TransitTunnels.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitTunnels::HandleShortTransitTunnelBuildMsg (std::shared_ptr<I2NPMessage>&& msg)
|
||||||
|
{
|
||||||
|
if (!msg) return;
|
||||||
|
uint8_t * buf = msg->GetPayload();
|
||||||
|
size_t len = msg->GetPayloadLength();
|
||||||
|
int num = buf[0];
|
||||||
|
LogPrint (eLogDebug, "TransitTunnel: ShortTunnelBuild ", num, " records");
|
||||||
|
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "TransitTunnel: Too many records in ShortTunnelBuild message ", num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "TransitTunnel: ShortTunnelBuild message of ", num, " records is too short ", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uint8_t * record = buf + 1;
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "TransitTunnel: Short request record ", i, " is ours");
|
||||||
|
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||||
|
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Can't decrypt short request record ", i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||||
|
uint8_t replyKey[32]; // AEAD/Chacha20/Poly1305
|
||||||
|
i2p::crypto::AESKey layerKey, ivKey; // AES
|
||||||
|
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
|
||||||
|
memcpy (replyKey, noiseState.m_CK + 32, 32);
|
||||||
|
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
|
||||||
|
memcpy (layerKey, noiseState.m_CK + 32, 32);
|
||||||
|
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
|
||||||
|
if (isEndpoint)
|
||||||
|
{
|
||||||
|
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK);
|
||||||
|
memcpy (ivKey, noiseState.m_CK + 32, 32);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // if next ident is now ours
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Next ident is ours in short request record");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy (ivKey, noiseState.m_CK , 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we accept this tunnel
|
||||||
|
std::shared_ptr<i2p::tunnel::TransitTunnel> transitTunnel;
|
||||||
|
uint8_t retCode = 0;
|
||||||
|
if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL)
|
||||||
|
retCode = 30;
|
||||||
|
if (!retCode)
|
||||||
|
{
|
||||||
|
// create new transit tunnel
|
||||||
|
transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||||
|
bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||||
|
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
layerKey, ivKey,
|
||||||
|
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
||||||
|
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||||
|
if (!AddTransitTunnel (transitTunnel))
|
||||||
|
retCode = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt reply
|
||||||
|
uint8_t nonce[12];
|
||||||
|
memset (nonce, 0, 12);
|
||||||
|
uint8_t * reply = buf + 1;
|
||||||
|
for (int j = 0; j < num; j++)
|
||||||
|
{
|
||||||
|
nonce[4] = j; // nonce is record #
|
||||||
|
if (j == i)
|
||||||
|
{
|
||||||
|
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||||
|
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||||
|
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Short reply AEAD encryption failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
|
||||||
|
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||||
|
}
|
||||||
|
// send reply
|
||||||
|
auto onDrop = [transitTunnel]()
|
||||||
|
{
|
||||||
|
if (transitTunnel)
|
||||||
|
{
|
||||||
|
auto t = transitTunnel->GetCreationTime ();
|
||||||
|
if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT)
|
||||||
|
// make transit tunnel expired
|
||||||
|
transitTunnel->SetCreationTime (t - i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (isEndpoint)
|
||||||
|
{
|
||||||
|
auto replyMsg = NewI2NPShortMessage ();
|
||||||
|
replyMsg->Concat (buf, len);
|
||||||
|
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
||||||
|
if (transitTunnel) replyMsg->onDrop = onDrop;
|
||||||
|
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
|
||||||
|
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
|
||||||
|
{
|
||||||
|
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
|
||||||
|
uint64_t tag;
|
||||||
|
memcpy (&tag, noiseState.m_CK, 8);
|
||||||
|
// we send it to reply tunnel
|
||||||
|
i2p::transport::transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// IBGW is local
|
||||||
|
uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
|
||||||
|
auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID);
|
||||||
|
if (tunnel)
|
||||||
|
{
|
||||||
|
tunnel->SendTunnelDataMsg (replyMsg);
|
||||||
|
tunnel->FlushTunnelDataMsgs ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto msg = CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
|
||||||
|
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
||||||
|
if (transitTunnel) msg->onDrop = onDrop;
|
||||||
|
i2p::transport::transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, msg);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitTunnels::HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
|
||||||
|
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "TransitTunnel: Build request record ", i, " is ours");
|
||||||
|
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Failed to decrypt tunnel build record");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32) && // if next ident is now ours
|
||||||
|
!(clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG)) // and not endpoint
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Next ident is ours in tunnel build record");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t retCode = 0;
|
||||||
|
// decide if we should accept tunnel
|
||||||
|
bool accept = i2p::context.AcceptsTunnels ();
|
||||||
|
if (accept)
|
||||||
|
{
|
||||||
|
auto congestionLevel = i2p::context.GetCongestionLevel (false);
|
||||||
|
if (congestionLevel >= CONGESTION_LEVEL_MEDIUM)
|
||||||
|
{
|
||||||
|
if (congestionLevel < CONGESTION_LEVEL_FULL)
|
||||||
|
{
|
||||||
|
// random reject depending on congestion level
|
||||||
|
int level = i2p::tunnel::tunnels.GetRng ()() % (CONGESTION_LEVEL_FULL - CONGESTION_LEVEL_MEDIUM) + CONGESTION_LEVEL_MEDIUM;
|
||||||
|
if (congestionLevel > level)
|
||||||
|
accept = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
accept = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// replace record to reply
|
||||||
|
if (accept)
|
||||||
|
{
|
||||||
|
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||||
|
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||||
|
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||||
|
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
||||||
|
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||||
|
if (!AddTransitTunnel (transitTunnel))
|
||||||
|
retCode = 30;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
retCode = 30; // always reject with bandwidth reason (30)
|
||||||
|
|
||||||
|
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||||
|
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||||
|
// encrypt reply
|
||||||
|
i2p::crypto::CBCEncryption encryption;
|
||||||
|
for (int j = 0; j < num; j++)
|
||||||
|
{
|
||||||
|
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
||||||
|
if (j == i)
|
||||||
|
{
|
||||||
|
uint8_t nonce[12];
|
||||||
|
memset (nonce, 0, 12);
|
||||||
|
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||||
|
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TransitTunnel: Reply AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||||
|
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||||
|
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitTunnels::HandleVariableTransitTunnelBuildMsg (std::shared_ptr<I2NPMessage>&& msg)
|
||||||
|
{
|
||||||
|
if (!msg) return;
|
||||||
|
uint8_t * buf = msg->GetPayload();
|
||||||
|
size_t len = msg->GetPayloadLength();
|
||||||
|
int num = buf[0];
|
||||||
|
LogPrint (eLogDebug, "TransitTunnel: VariableTunnelBuild ", num, " records");
|
||||||
|
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "TransitTunnle: Too many records in VaribleTunnelBuild message ", num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "TransitTunnel: VaribleTunnelBuild message of ", num, " records is too short ", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||||
|
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||||
|
{
|
||||||
|
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||||
|
{
|
||||||
|
// so we send it to reply tunnel
|
||||||
|
i2p::transport::transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
eI2NPVariableTunnelBuildReply, buf, len,
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::transport::transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitTunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
|
||||||
|
{
|
||||||
|
if (tunnels.AddTunnel (tunnel))
|
||||||
|
m_TransitTunnels.push_back (tunnel);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "TransitTunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitTunnels::ManageTransitTunnels (uint64_t ts)
|
||||||
|
{
|
||||||
|
for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();)
|
||||||
|
{
|
||||||
|
auto tunnel = *it;
|
||||||
|
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT ||
|
||||||
|
ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "TransitTunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired");
|
||||||
|
tunnels.RemoveTunnel (tunnel->GetTunnelID ());
|
||||||
|
it = m_TransitTunnels.erase (it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tunnel->Cleanup ();
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransitTunnels::GetTransitTunnelsExpirationTimeout ()
|
||||||
|
{
|
||||||
|
int timeout = 0;
|
||||||
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
// TODO: possible race condition with I2PControl
|
||||||
|
for (const auto& it : m_TransitTunnels)
|
||||||
|
{
|
||||||
|
int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts;
|
||||||
|
if (t > timeout) timeout = t;
|
||||||
|
}
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
#define TRANSIT_TUNNEL_H__
|
#define TRANSIT_TUNNEL_H__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <vector>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
|
@ -61,7 +61,7 @@ namespace tunnel
|
||||||
private:
|
private:
|
||||||
|
|
||||||
size_t m_NumTransmittedBytes;
|
size_t m_NumTransmittedBytes;
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
std::list<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TransitTunnelGateway: public TransitTunnel
|
class TransitTunnelGateway: public TransitTunnel
|
||||||
|
@ -108,6 +108,35 @@ namespace tunnel
|
||||||
const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
|
const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
|
||||||
const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey,
|
const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey,
|
||||||
bool isGateway, bool isEndpoint);
|
bool isGateway, bool isEndpoint);
|
||||||
|
|
||||||
|
class TransitTunnels
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void Start ();
|
||||||
|
void Stop ();
|
||||||
|
void ManageTransitTunnels (uint64_t ts);
|
||||||
|
|
||||||
|
size_t GetNumTransitTunnels () const { return m_TransitTunnels.size (); }
|
||||||
|
int GetTransitTunnelsExpirationTimeout ();
|
||||||
|
|
||||||
|
void HandleShortTransitTunnelBuildMsg (std::shared_ptr<I2NPMessage>&& msg);
|
||||||
|
void HandleVariableTransitTunnelBuildMsg (std::shared_ptr<I2NPMessage>&& msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
|
||||||
|
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<TransitTunnel> > m_TransitTunnels;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// for HTTP only
|
||||||
|
auto& GetTransitTunnels () const { return m_TransitTunnels; };
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,8 +144,12 @@ namespace transport
|
||||||
void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; };
|
void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; };
|
||||||
|
|
||||||
virtual uint32_t GetRelayTag () const { return 0; };
|
virtual uint32_t GetRelayTag () const { return 0; };
|
||||||
virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); };
|
virtual void SendLocalRouterInfo (bool update = false)
|
||||||
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
{
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > msgs{ CreateDatabaseStoreMsg () };
|
||||||
|
SendI2NPMessages (msgs);
|
||||||
|
};
|
||||||
|
virtual void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
||||||
virtual bool IsEstablished () const = 0;
|
virtual bool IsEstablished () const = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
template<typename Keys>
|
template<typename Keys>
|
||||||
EphemeralKeysSupplier<Keys>::EphemeralKeysSupplier (int size):
|
EphemeralKeysSupplier<Keys>::EphemeralKeysSupplier (int size):
|
||||||
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
m_QueueSize (size), m_IsRunning (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace transport
|
||||||
void EphemeralKeysSupplier<Keys>::Start ()
|
void EphemeralKeysSupplier<Keys>::Start ()
|
||||||
{
|
{
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this));
|
m_Thread.reset (new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Keys>
|
template<typename Keys>
|
||||||
|
@ -53,8 +53,7 @@ namespace transport
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
{
|
{
|
||||||
m_Thread->join ();
|
m_Thread->join ();
|
||||||
delete m_Thread;
|
m_Thread = nullptr;
|
||||||
m_Thread = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,18 +65,19 @@ namespace transport
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
int num, total = 0;
|
int num, total = 0;
|
||||||
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10)
|
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < m_QueueSize)
|
||||||
{
|
{
|
||||||
CreateEphemeralKeys (num);
|
CreateEphemeralKeys (num);
|
||||||
total += num;
|
total += num;
|
||||||
}
|
}
|
||||||
if (total >= 10)
|
if (total > m_QueueSize)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time");
|
LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time");
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
|
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
m_KeysPool.CleanUpMt ();
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
if (!m_IsRunning) break;
|
if (!m_IsRunning) break;
|
||||||
m_Acquired.wait (l); // wait for element gets acquired
|
m_Acquired.wait (l); // wait for element gets acquired
|
||||||
|
@ -92,7 +92,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
auto pair = std::make_shared<Keys> ();
|
auto pair = m_KeysPool.AcquireSharedMt ();
|
||||||
pair->GenerateKeys ();
|
pair->GenerateKeys ();
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
m_Queue.push (pair);
|
m_Queue.push (pair);
|
||||||
|
@ -114,7 +114,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// queue is empty, create new
|
// queue is empty, create new
|
||||||
auto pair = std::make_shared<Keys> ();
|
auto pair = m_KeysPool.AcquireSharedMt ();
|
||||||
pair->GenerateKeys ();
|
pair->GenerateKeys ();
|
||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ namespace transport
|
||||||
m_Queue.push (pair);
|
m_Queue.push (pair);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint(eLogError, "Transports: Return null DHKeys");
|
LogPrint(eLogError, "Transports: Return null keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::UpdateParams (std::shared_ptr<const i2p::data::RouterInfo> router)
|
void Peer::UpdateParams (std::shared_ptr<const i2p::data::RouterInfo> router)
|
||||||
|
@ -149,7 +149,7 @@ namespace transport
|
||||||
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
|
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
|
||||||
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
|
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
|
||||||
m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
|
m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
|
||||||
m_X25519KeysPairSupplier (15), // 15 pre-generated keys
|
m_X25519KeysPairSupplier (NUM_X25519_PRE_GENERATED_KEYS),
|
||||||
m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
|
m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
|
||||||
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
|
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
|
||||||
m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0),
|
m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0),
|
||||||
|
@ -450,15 +450,25 @@ namespace transport
|
||||||
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
|
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
if (m_IsOnline)
|
if (m_IsOnline)
|
||||||
SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
|
SendMessages (ident, { msg });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
||||||
{
|
{
|
||||||
m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
std::list<std::shared_ptr<i2p::I2NPMessage> > msgs1;
|
||||||
|
msgs.swap (msgs1);
|
||||||
|
SendMessages (ident, std::move (msgs1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
|
void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs)
|
||||||
|
{
|
||||||
|
m_Service->post ([this, ident, msgs = std::move(msgs)] () mutable
|
||||||
|
{
|
||||||
|
PostMessages (ident, msgs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transports::PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
||||||
{
|
{
|
||||||
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
|
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
|
||||||
{
|
{
|
||||||
|
@ -470,8 +480,13 @@ namespace transport
|
||||||
}
|
}
|
||||||
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
|
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
|
||||||
std::shared_ptr<Peer> peer;
|
std::shared_ptr<Peer> peer;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it == m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
|
peer = it->second;
|
||||||
|
}
|
||||||
|
if (!peer)
|
||||||
{
|
{
|
||||||
// check if not banned
|
// check if not banned
|
||||||
if (i2p::data::IsRouterBanned (ident)) return; // don't create peer to unreachable router
|
if (i2p::data::IsRouterBanned (ident)) return; // don't create peer to unreachable router
|
||||||
|
@ -481,10 +496,10 @@ namespace transport
|
||||||
{
|
{
|
||||||
auto r = netdb.FindRouter (ident);
|
auto r = netdb.FindRouter (ident);
|
||||||
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
|
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
|
||||||
|
|
||||||
|
peer = std::make_shared<Peer>(r, i2p::util::GetSecondsSinceEpoch ());
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
peer = std::make_shared<Peer>(r, ts);
|
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
|
||||||
peer = m_Peers.emplace (ident, peer).first->second;
|
peer = m_Peers.emplace (ident, peer).first->second;
|
||||||
}
|
}
|
||||||
if (peer)
|
if (peer)
|
||||||
|
@ -496,8 +511,6 @@ namespace transport
|
||||||
}
|
}
|
||||||
if (!connected) return;
|
if (!connected) return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
peer = it->second;
|
|
||||||
|
|
||||||
if (!peer) return;
|
if (!peer) return;
|
||||||
if (peer->IsConnected ())
|
if (peer->IsConnected ())
|
||||||
|
@ -512,22 +525,27 @@ namespace transport
|
||||||
if (i2p::data::IsRouterBanned (ident))
|
if (i2p::data::IsRouterBanned (ident))
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sz > MAX_NUM_DELAYED_MESSAGES/2)
|
||||||
|
{
|
||||||
for (auto& it1: msgs)
|
for (auto& it1: msgs)
|
||||||
if (sz > MAX_NUM_DELAYED_MESSAGES/2 && it1->onDrop)
|
if (it1->onDrop)
|
||||||
it1->Drop (); // drop earlier because we can handle it
|
it1->Drop (); // drop earlier because we can handle it
|
||||||
else
|
else
|
||||||
peer->delayedMessages.push_back (it1);
|
peer->delayedMessages.push_back (it1);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
peer->delayedMessages.splice (peer->delayedMessages.end (), msgs);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
|
LogPrint (eLogWarning, "Transports: Delayed messages queue size to ",
|
||||||
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
|
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -602,7 +620,7 @@ namespace transport
|
||||||
if (!i2p::context.IsLimitedConnectivity () && peer->router->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
if (!i2p::context.IsLimitedConnectivity () && peer->router->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
||||||
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
|
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
|
||||||
peer->Done ();
|
peer->Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -610,7 +628,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
|
||||||
peer->Done ();
|
peer->Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -706,23 +724,29 @@ namespace transport
|
||||||
|
|
||||||
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
|
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
|
||||||
{
|
{
|
||||||
|
std::shared_ptr<Peer> peer;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
if (r)
|
if (r)
|
||||||
{
|
peer = it->second;
|
||||||
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
|
|
||||||
it->second->SetRouter (r);
|
|
||||||
if (!it->second->IsConnected ())
|
|
||||||
ConnectToPeer (ident, it->second);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "Transports: RouterInfo not found, failed to send messages");
|
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
|
||||||
m_Peers.erase (it);
|
m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (peer && !peer->router && r)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
|
||||||
|
peer->SetRouter (r);
|
||||||
|
if (!peer->IsConnected ())
|
||||||
|
ConnectToPeer (ident, peer);
|
||||||
|
}
|
||||||
|
else if (!r)
|
||||||
|
LogPrint (eLogInfo, "Transports: RouterInfo not found, failed to send messages");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::DetectExternalIP ()
|
void Transports::DetectExternalIP ()
|
||||||
|
@ -865,7 +889,7 @@ namespace transport
|
||||||
if (it->second->delayedMessages.size () > 0)
|
if (it->second->delayedMessages.size () > 0)
|
||||||
{
|
{
|
||||||
// check if first message is our DatabaseStore (publishing)
|
// check if first message is our DatabaseStore (publishing)
|
||||||
auto firstMsg = peer->delayedMessages[0];
|
auto firstMsg = peer->delayedMessages.front ();
|
||||||
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
|
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
|
||||||
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
|
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
|
||||||
sendDatabaseStore = false; // we have it in the list already
|
sendDatabaseStore = false; // we have it in the list already
|
||||||
|
@ -875,8 +899,7 @@ namespace transport
|
||||||
else
|
else
|
||||||
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
|
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
|
||||||
peer->sessions.push_back (session);
|
peer->sessions.push_back (session);
|
||||||
session->SendI2NPMessages (peer->delayedMessages);
|
session->SendI2NPMessages (peer->delayedMessages); // send and clear
|
||||||
peer->delayedMessages.clear ();
|
|
||||||
}
|
}
|
||||||
else // incoming connection or peer test
|
else // incoming connection or peer test
|
||||||
{
|
{
|
||||||
|
@ -887,14 +910,17 @@ namespace transport
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!session->IsOutgoing ()) // incoming
|
if (!session->IsOutgoing ()) // incoming
|
||||||
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
|
{
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > msgs{ CreateDatabaseStoreMsg () };
|
||||||
|
session->SendI2NPMessages (msgs); // send DatabaseStore
|
||||||
|
}
|
||||||
auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
|
auto r = i2p::data::netdb.FindRouter (ident); // router should be in netdb after SessionConfirmed
|
||||||
if (r) r->GetProfile ()->Connected ();
|
if (r) r->GetProfile ()->Connected ();
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
auto peer = std::make_shared<Peer>(r, ts);
|
auto peer = std::make_shared<Peer>(r, ts);
|
||||||
peer->sessions.push_back (session);
|
peer->sessions.push_back (session);
|
||||||
peer->router = nullptr;
|
peer->router = nullptr;
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.emplace (ident, peer);
|
m_Peers.emplace (ident, peer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -923,7 +949,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (it);
|
m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -933,9 +959,13 @@ namespace transport
|
||||||
|
|
||||||
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
|
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
|
#if __cplusplus >= 202002L // C++20
|
||||||
|
return m_Peers.contains (ident);
|
||||||
|
#else
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
return it != m_Peers.end ();
|
return it != m_Peers.end ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
|
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
|
||||||
|
@ -959,7 +989,7 @@ namespace transport
|
||||||
auto profile = i2p::data::GetRouterProfile (it->first);
|
auto profile = i2p::data::GetRouterProfile (it->first);
|
||||||
if (profile) profile->Unreachable ();
|
if (profile) profile->Unreachable ();
|
||||||
} */
|
} */
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
it = m_Peers.erase (it);
|
it = m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1009,7 +1039,7 @@ 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::lock_guard<std::mutex> l(m_PeersMutex);
|
||||||
auto count = m_Peers.size ();
|
auto count = m_Peers.size ();
|
||||||
if(count == 0) return nullptr;
|
if(count == 0) return nullptr;
|
||||||
inds[0] %= count;
|
inds[0] %= count;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
@ -53,9 +54,10 @@ namespace transport
|
||||||
|
|
||||||
const int m_QueueSize;
|
const int m_QueueSize;
|
||||||
std::queue<std::shared_ptr<Keys> > m_Queue;
|
std::queue<std::shared_ptr<Keys> > m_Queue;
|
||||||
|
i2p::util::MemoryPoolMt<Keys> m_KeysPool;
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::unique_ptr<std::thread> m_Thread;
|
||||||
std::condition_variable m_Acquired;
|
std::condition_variable m_Acquired;
|
||||||
std::mutex m_AcquiredMutex;
|
std::mutex m_AcquiredMutex;
|
||||||
};
|
};
|
||||||
|
@ -71,7 +73,7 @@ namespace transport
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> router;
|
std::shared_ptr<const i2p::data::RouterInfo> router;
|
||||||
std::list<std::shared_ptr<TransportSession> > sessions;
|
std::list<std::shared_ptr<TransportSession> > sessions;
|
||||||
uint64_t creationTime, nextRouterInfoUpdateTime, lastSelectionTime;
|
uint64_t creationTime, nextRouterInfoUpdateTime, lastSelectionTime;
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
std::list<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
||||||
std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
|
std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
|
||||||
bool isHighBandwidth, isEligible;
|
bool isHighBandwidth, isEligible;
|
||||||
|
|
||||||
|
@ -108,6 +110,7 @@ namespace transport
|
||||||
const int PEER_TEST_DELAY_INTERVAL_VARIANCE = 30; // in milliseconds
|
const int PEER_TEST_DELAY_INTERVAL_VARIANCE = 30; // in milliseconds
|
||||||
const int MAX_NUM_DELAYED_MESSAGES = 150;
|
const int MAX_NUM_DELAYED_MESSAGES = 150;
|
||||||
const int CHECK_PROFILE_NUM_DELAYED_MESSAGES = 15; // check profile after
|
const int CHECK_PROFILE_NUM_DELAYED_MESSAGES = 15; // check profile after
|
||||||
|
const int NUM_X25519_PRE_GENERATED_KEYS = 25; // pre-generated x25519 keys pairs
|
||||||
|
|
||||||
const int TRAFFIC_SAMPLE_COUNT = 301; // seconds
|
const int TRAFFIC_SAMPLE_COUNT = 301; // seconds
|
||||||
|
|
||||||
|
@ -141,7 +144,8 @@ namespace transport
|
||||||
void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair);
|
void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair);
|
||||||
|
|
||||||
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
void SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
||||||
|
void SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs);
|
||||||
|
|
||||||
void PeerConnected (std::shared_ptr<TransportSession> session);
|
void PeerConnected (std::shared_ptr<TransportSession> session);
|
||||||
void PeerDisconnected (std::shared_ptr<TransportSession> session);
|
void PeerDisconnected (std::shared_ptr<TransportSession> session);
|
||||||
|
@ -185,7 +189,7 @@ namespace transport
|
||||||
void Run ();
|
void Run ();
|
||||||
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
||||||
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
||||||
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
void PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
||||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer);
|
bool ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer);
|
||||||
void SetPriority (std::shared_ptr<Peer> peer) const;
|
void SetPriority (std::shared_ptr<Peer> peer) const;
|
||||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||||
|
|
|
@ -130,7 +130,18 @@ namespace tunnel
|
||||||
|
|
||||||
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
|
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
|
int num = msg[0];
|
||||||
|
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", num, " records.");
|
||||||
|
if (num > MAX_NUM_RECORDS)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Tunnel: Too many records in TunnelBuildResponse", num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (len < num*m_Config->GetRecordSize () + 1)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Tunnel: TunnelBuildResponse of ", num, " records is too short ", len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
TunnelHopConfig * hop = m_Config->GetLastHop ();
|
TunnelHopConfig * hop = m_Config->GetLastHop ();
|
||||||
while (hop)
|
while (hop)
|
||||||
|
@ -152,7 +163,7 @@ namespace tunnel
|
||||||
while (hop1)
|
while (hop1)
|
||||||
{
|
{
|
||||||
auto idx = hop1->recordIndex;
|
auto idx = hop1->recordIndex;
|
||||||
if (idx >= 0 && idx < msg[0])
|
if (idx >= 0 && idx < num)
|
||||||
hop->DecryptRecord (msg + 1, idx);
|
hop->DecryptRecord (msg + 1, idx);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Tunnel: Hop index ", idx, " is out of range");
|
LogPrint (eLogWarning, "Tunnel: Hop index ", idx, " is out of range");
|
||||||
|
@ -368,6 +379,17 @@ namespace tunnel
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Tunnels::AddTunnel (std::shared_ptr<TunnelBase> tunnel)
|
||||||
|
{
|
||||||
|
if (!tunnel) return false;
|
||||||
|
return m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tunnels::RemoveTunnel (uint32_t tunnelID)
|
||||||
|
{
|
||||||
|
m_Tunnels.erase (tunnelID);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<InboundTunnel> Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID)
|
std::shared_ptr<InboundTunnel> Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID)
|
||||||
{
|
{
|
||||||
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
|
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
|
||||||
|
@ -455,26 +477,16 @@ namespace tunnel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
|
|
||||||
{
|
|
||||||
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
|
|
||||||
m_TransitTunnels.push_back (tunnel);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tunnels::Start ()
|
void Tunnels::Start ()
|
||||||
{
|
{
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&Tunnels::Run, this));
|
m_Thread = new std::thread (std::bind (&Tunnels::Run, this));
|
||||||
|
m_TransitTunnels.Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnels::Stop ()
|
void Tunnels::Stop ()
|
||||||
{
|
{
|
||||||
|
m_TransitTunnels.Stop ();
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Queue.WakeUp ();
|
m_Queue.WakeUp ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
|
@ -533,13 +545,21 @@ namespace tunnel
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eI2NPVariableTunnelBuild:
|
|
||||||
case eI2NPVariableTunnelBuildReply:
|
|
||||||
case eI2NPShortTunnelBuild:
|
case eI2NPShortTunnelBuild:
|
||||||
|
HandleShortTunnelBuildMsg (msg);
|
||||||
|
break;
|
||||||
|
case eI2NPVariableTunnelBuild:
|
||||||
|
HandleVariableTunnelBuildMsg (msg);
|
||||||
|
break;
|
||||||
case eI2NPShortTunnelBuildReply:
|
case eI2NPShortTunnelBuildReply:
|
||||||
|
HandleTunnelBuildReplyMsg (msg, true);
|
||||||
|
break;
|
||||||
|
case eI2NPVariableTunnelBuildReply:
|
||||||
|
HandleTunnelBuildReplyMsg (msg, false);
|
||||||
|
break;
|
||||||
case eI2NPTunnelBuild:
|
case eI2NPTunnelBuild:
|
||||||
case eI2NPTunnelBuildReply:
|
case eI2NPTunnelBuildReply:
|
||||||
HandleTunnelBuildI2NPMessage (msg);
|
LogPrint (eLogWarning, "Tunnel: TunnelBuild is too old for ECIES router");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogWarning, "Tunnel: Unexpected message type ", (int) typeID);
|
LogPrint (eLogWarning, "Tunnel: Unexpected message type ", (int) typeID);
|
||||||
|
@ -613,12 +633,84 @@ namespace tunnel
|
||||||
tunnel->SendTunnelDataMsg (msg);
|
tunnel->SendTunnelDataMsg (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tunnels::HandleShortTunnelBuildMsg (std::shared_ptr<I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
if (!msg) return;
|
||||||
|
auto tunnel = GetPendingInboundTunnel (msg->GetMsgID()); // replyMsgID
|
||||||
|
if (tunnel)
|
||||||
|
{
|
||||||
|
// endpoint of inbound tunnel
|
||||||
|
LogPrint (eLogDebug, "Tunnel: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
||||||
|
if (tunnel->HandleTunnelBuildResponse (msg->GetPayload(), msg->GetPayloadLength()))
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||||
|
tunnel->SetState (eTunnelStateEstablished);
|
||||||
|
AddInboundTunnel (tunnel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||||
|
tunnel->SetState (eTunnelStateBuildFailed);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_TransitTunnels.HandleShortTransitTunnelBuildMsg (std::move (msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tunnels::HandleVariableTunnelBuildMsg (std::shared_ptr<I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
auto tunnel = GetPendingInboundTunnel (msg->GetMsgID()); // replyMsgID
|
||||||
|
if (tunnel)
|
||||||
|
{
|
||||||
|
// endpoint of inbound tunnel
|
||||||
|
LogPrint (eLogDebug, "Tunnel: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
||||||
|
if (tunnel->HandleTunnelBuildResponse (msg->GetPayload(), msg->GetPayloadLength()))
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||||
|
tunnel->SetState (eTunnelStateEstablished);
|
||||||
|
AddInboundTunnel (tunnel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Tunnel: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||||
|
tunnel->SetState (eTunnelStateBuildFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_TransitTunnels.HandleVariableTransitTunnelBuildMsg (std::move (msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tunnels::HandleTunnelBuildReplyMsg (std::shared_ptr<I2NPMessage> msg, bool isShort)
|
||||||
|
{
|
||||||
|
auto tunnel = GetPendingOutboundTunnel (msg->GetMsgID()); // replyMsgID
|
||||||
|
if (tunnel)
|
||||||
|
{
|
||||||
|
// reply for outbound tunnel
|
||||||
|
LogPrint (eLogDebug, "Tunnel: TunnelBuildReply for tunnel ", tunnel->GetTunnelID ());
|
||||||
|
if (tunnel->HandleTunnelBuildResponse (msg->GetPayload(), msg->GetPayloadLength()))
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Tunnel: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||||
|
tunnel->SetState (eTunnelStateEstablished);
|
||||||
|
AddOutboundTunnel (tunnel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Tunnel: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||||
|
tunnel->SetState (eTunnelStateBuildFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "Tunnel: Pending tunnel for message ", msg->GetMsgID(), " not found");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Tunnels::ManageTunnels (uint64_t ts)
|
void Tunnels::ManageTunnels (uint64_t ts)
|
||||||
{
|
{
|
||||||
ManagePendingTunnels (ts);
|
ManagePendingTunnels (ts);
|
||||||
ManageInboundTunnels (ts);
|
ManageInboundTunnels (ts);
|
||||||
ManageOutboundTunnels (ts);
|
ManageOutboundTunnels (ts);
|
||||||
ManageTransitTunnels (ts);
|
m_TransitTunnels.ManageTransitTunnels (ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnels::ManagePendingTunnels (uint64_t ts)
|
void Tunnels::ManagePendingTunnels (uint64_t ts)
|
||||||
|
@ -745,7 +837,7 @@ namespace tunnel
|
||||||
auto pool = tunnel->GetTunnelPool ();
|
auto pool = tunnel->GetTunnelPool ();
|
||||||
if (pool)
|
if (pool)
|
||||||
pool->TunnelExpired (tunnel);
|
pool->TunnelExpired (tunnel);
|
||||||
m_Tunnels.erase (tunnel->GetTunnelID ());
|
RemoveTunnel (tunnel->GetTunnelID ());
|
||||||
it = m_InboundTunnels.erase (it);
|
it = m_InboundTunnels.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -807,26 +899,6 @@ namespace tunnel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnels::ManageTransitTunnels (uint64_t ts)
|
|
||||||
{
|
|
||||||
for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();)
|
|
||||||
{
|
|
||||||
auto tunnel = *it;
|
|
||||||
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT ||
|
|
||||||
ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired");
|
|
||||||
m_Tunnels.erase (tunnel->GetTunnelID ());
|
|
||||||
it = m_TransitTunnels.erase (it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tunnel->Cleanup ();
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tunnels::ManageTunnelPools (uint64_t ts)
|
void Tunnels::ManageTunnelPools (uint64_t ts)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PoolsMutex);
|
std::unique_lock<std::mutex> l(m_PoolsMutex);
|
||||||
|
@ -900,7 +972,7 @@ namespace tunnel
|
||||||
|
|
||||||
void Tunnels::AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel)
|
void Tunnels::AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel)
|
||||||
{
|
{
|
||||||
if (m_Tunnels.emplace (newTunnel->GetTunnelID (), newTunnel).second)
|
if (AddTunnel (newTunnel))
|
||||||
{
|
{
|
||||||
m_InboundTunnels.push_back (newTunnel);
|
m_InboundTunnels.push_back (newTunnel);
|
||||||
auto pool = newTunnel->GetTunnelPool ();
|
auto pool = newTunnel->GetTunnelPool ();
|
||||||
|
@ -930,7 +1002,7 @@ namespace tunnel
|
||||||
inboundTunnel->SetTunnelPool (pool);
|
inboundTunnel->SetTunnelPool (pool);
|
||||||
inboundTunnel->SetState (eTunnelStateEstablished);
|
inboundTunnel->SetState (eTunnelStateEstablished);
|
||||||
m_InboundTunnels.push_back (inboundTunnel);
|
m_InboundTunnels.push_back (inboundTunnel);
|
||||||
m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel;
|
AddTunnel (inboundTunnel);
|
||||||
return inboundTunnel;
|
return inboundTunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,21 +1036,12 @@ namespace tunnel
|
||||||
|
|
||||||
int Tunnels::GetTransitTunnelsExpirationTimeout ()
|
int Tunnels::GetTransitTunnelsExpirationTimeout ()
|
||||||
{
|
{
|
||||||
int timeout = 0;
|
return m_TransitTunnels.GetTransitTunnelsExpirationTimeout ();
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
// TODO: possible race condition with I2PControl
|
|
||||||
for (const auto& it : m_TransitTunnels)
|
|
||||||
{
|
|
||||||
int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts;
|
|
||||||
if (t > timeout) timeout = t;
|
|
||||||
}
|
|
||||||
return timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Tunnels::CountTransitTunnels() const
|
size_t Tunnels::CountTransitTunnels() const
|
||||||
{
|
{
|
||||||
// TODO: locking
|
return m_TransitTunnels.GetNumTransitTunnels ();
|
||||||
return m_TransitTunnels.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Tunnels::CountInboundTunnels() const
|
size_t Tunnels::CountInboundTunnels() const
|
||||||
|
|
|
@ -223,8 +223,9 @@ namespace tunnel
|
||||||
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
|
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
|
||||||
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
|
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
|
||||||
std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID);
|
std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID);
|
||||||
|
bool AddTunnel (std::shared_ptr<TunnelBase> tunnel);
|
||||||
|
void RemoveTunnel (uint32_t tunnelID);
|
||||||
int GetTransitTunnelsExpirationTimeout ();
|
int GetTransitTunnelsExpirationTimeout ();
|
||||||
bool AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
|
|
||||||
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
|
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
|
||||||
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
|
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
|
||||||
std::shared_ptr<InboundTunnel> CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel);
|
std::shared_ptr<InboundTunnel> CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel);
|
||||||
|
@ -243,7 +244,7 @@ namespace tunnel
|
||||||
|
|
||||||
void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels);
|
void SetMaxNumTransitTunnels (uint32_t maxNumTransitTunnels);
|
||||||
uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
|
uint32_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
|
||||||
int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.size() / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; }
|
int GetCongestionLevel() const { return m_MaxNumTransitTunnels ? CONGESTION_LEVEL_FULL * m_TransitTunnels.GetNumTransitTunnels () / m_MaxNumTransitTunnels : CONGESTION_LEVEL_FULL; }
|
||||||
|
|
||||||
std::mt19937& GetRng () { return m_Rng; };
|
std::mt19937& GetRng () { return m_Rng; };
|
||||||
|
|
||||||
|
@ -257,12 +258,14 @@ namespace tunnel
|
||||||
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
|
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
|
||||||
|
|
||||||
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
|
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
|
||||||
|
void HandleShortTunnelBuildMsg (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
void HandleVariableTunnelBuildMsg (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
void HandleTunnelBuildReplyMsg (std::shared_ptr<I2NPMessage> msg, bool isShort);
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void ManageTunnels (uint64_t ts);
|
void ManageTunnels (uint64_t ts);
|
||||||
void ManageOutboundTunnels (uint64_t ts);
|
void ManageOutboundTunnels (uint64_t ts);
|
||||||
void ManageInboundTunnels (uint64_t ts);
|
void ManageInboundTunnels (uint64_t ts);
|
||||||
void ManageTransitTunnels (uint64_t ts);
|
|
||||||
void ManagePendingTunnels (uint64_t ts);
|
void ManagePendingTunnels (uint64_t ts);
|
||||||
template<class PendingTunnels>
|
template<class PendingTunnels>
|
||||||
void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts);
|
void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts);
|
||||||
|
@ -297,7 +300,6 @@ namespace tunnel
|
||||||
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
|
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
|
||||||
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
|
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
|
||||||
std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels;
|
std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels;
|
||||||
std::list<std::shared_ptr<TransitTunnel> > m_TransitTunnels;
|
|
||||||
std::unordered_map<uint32_t, std::shared_ptr<TunnelBase> > m_Tunnels; // tunnelID->tunnel known by this id
|
std::unordered_map<uint32_t, std::shared_ptr<TunnelBase> > m_Tunnels; // tunnelID->tunnel known by this id
|
||||||
std::mutex m_PoolsMutex;
|
std::mutex m_PoolsMutex;
|
||||||
std::list<std::shared_ptr<TunnelPool>> m_Pools;
|
std::list<std::shared_ptr<TunnelPool>> m_Pools;
|
||||||
|
@ -311,13 +313,14 @@ namespace tunnel
|
||||||
double m_TunnelCreationSuccessRate;
|
double m_TunnelCreationSuccessRate;
|
||||||
int m_TunnelCreationAttemptsNum;
|
int m_TunnelCreationAttemptsNum;
|
||||||
std::mt19937 m_Rng;
|
std::mt19937 m_Rng;
|
||||||
|
TransitTunnels m_TransitTunnels;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
||||||
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
||||||
const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; };
|
auto& GetTransitTunnels () const { return m_TransitTunnels.GetTransitTunnels (); };
|
||||||
|
|
||||||
size_t CountTransitTunnels() const;
|
size_t CountTransitTunnels() const;
|
||||||
size_t CountInboundTunnels() const;
|
size_t CountInboundTunnels() const;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -181,6 +181,8 @@ namespace tunnel
|
||||||
return peers;
|
return peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetRecordSize () const { return m_IsShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// this constructor can't be called from outside
|
// this constructor can't be called from outside
|
||||||
|
|
|
@ -221,7 +221,7 @@ namespace tunnel
|
||||||
void TunnelGateway::SendBuffer ()
|
void TunnelGateway::SendBuffer ()
|
||||||
{
|
{
|
||||||
m_Buffer.CompleteCurrentTunnelDataMessage ();
|
m_Buffer.CompleteCurrentTunnelDataMessage ();
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
|
std::list<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
|
||||||
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
|
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
|
||||||
for (auto& tunnelMsg : tunnelDataMsgs)
|
for (auto& tunnelMsg : tunnelDataMsgs)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +234,7 @@ namespace tunnel
|
||||||
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
||||||
}
|
}
|
||||||
m_Buffer.ClearTunnelDataMsgs ();
|
m_Buffer.ClearTunnelDataMsgs ();
|
||||||
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), newTunnelMsgs);
|
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -171,6 +171,14 @@ namespace util
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunnableService::SetName (std::string_view name)
|
||||||
|
{
|
||||||
|
if (name.length() < 16)
|
||||||
|
m_Name = name;
|
||||||
|
else
|
||||||
|
m_Name = name.substr(0,15);
|
||||||
|
}
|
||||||
|
|
||||||
void SetThreadName (const char *name) {
|
void SetThreadName (const char *name) {
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
# if (!defined(MAC_OS_X_VERSION_10_6) || \
|
# if (!defined(MAC_OS_X_VERSION_10_6) || \
|
||||||
|
|
|
@ -183,6 +183,8 @@ namespace util
|
||||||
void StartIOService ();
|
void StartIOService ();
|
||||||
void StopIOService ();
|
void StopIOService ();
|
||||||
|
|
||||||
|
void SetName (std::string_view name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
|
|
|
@ -305,7 +305,7 @@ namespace client
|
||||||
identHash = hash;
|
identHash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
|
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false),
|
||||||
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr),
|
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr),
|
||||||
m_IsEnabled (true)
|
m_IsEnabled (true)
|
||||||
{
|
{
|
||||||
|
@ -344,20 +344,28 @@ namespace client
|
||||||
delete m_SubscriptionsUpdateTimer;
|
delete m_SubscriptionsUpdateTimer;
|
||||||
m_SubscriptionsUpdateTimer = nullptr;
|
m_SubscriptionsUpdateTimer = nullptr;
|
||||||
}
|
}
|
||||||
if (m_IsDownloading)
|
bool isDownloading = m_Downloading.valid ();
|
||||||
|
if (isDownloading)
|
||||||
|
{
|
||||||
|
if (m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
|
||||||
|
isDownloading = false;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort");
|
LogPrint (eLogInfo, "Addressbook: Subscriptions are downloading, abort");
|
||||||
for (int i = 0; i < 30; i++)
|
for (int i = 0; i < 30; i++)
|
||||||
{
|
{
|
||||||
if (!m_IsDownloading)
|
if (m_Downloading.wait_for(std::chrono::seconds(1)) == std::future_status::ready) // wait for 1 seconds
|
||||||
{
|
{
|
||||||
|
isDownloading = false;
|
||||||
LogPrint (eLogInfo, "Addressbook: Subscriptions download complete");
|
LogPrint (eLogInfo, "Addressbook: Subscriptions download complete");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for (std::chrono::seconds (1)); // wait for 1 seconds
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!isDownloading)
|
||||||
|
m_Downloading.get ();
|
||||||
|
else
|
||||||
LogPrint (eLogError, "Addressbook: Subscription download timeout");
|
LogPrint (eLogError, "Addressbook: Subscription download timeout");
|
||||||
m_IsDownloading = false;
|
|
||||||
}
|
}
|
||||||
if (m_Storage)
|
if (m_Storage)
|
||||||
{
|
{
|
||||||
|
@ -582,16 +590,15 @@ namespace client
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config file");
|
LogPrint (eLogInfo, "Addressbook: Loading subscriptions from config");
|
||||||
// using config file items
|
// using config file items
|
||||||
std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs);
|
std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs);
|
||||||
std::vector<std::string> subsList;
|
std::vector<std::string> subsList;
|
||||||
boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on);
|
boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on);
|
||||||
|
|
||||||
for (const auto& s: subsList)
|
for (const auto& s: subsList)
|
||||||
{
|
if (!s.empty ())
|
||||||
m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
|
m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
|
||||||
}
|
|
||||||
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
|
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,7 +652,6 @@ namespace client
|
||||||
|
|
||||||
void AddressBook::DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified)
|
void AddressBook::DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified)
|
||||||
{
|
{
|
||||||
m_IsDownloading = false;
|
|
||||||
m_NumRetries++;
|
m_NumRetries++;
|
||||||
int nextUpdateTimeout = m_NumRetries*CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT;
|
int nextUpdateTimeout = m_NumRetries*CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT;
|
||||||
if (m_NumRetries > CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES || nextUpdateTimeout > CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT)
|
if (m_NumRetries > CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES || nextUpdateTimeout > CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT)
|
||||||
|
@ -700,7 +706,13 @@ namespace client
|
||||||
LogPrint(eLogWarning, "Addressbook: Missing local destination, skip subscription update");
|
LogPrint(eLogWarning, "Addressbook: Missing local destination, skip subscription update");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!m_IsDownloading && dest->IsReady ())
|
bool isDownloading = m_Downloading.valid ();
|
||||||
|
if (isDownloading && m_Downloading.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active?
|
||||||
|
{
|
||||||
|
m_Downloading.get ();
|
||||||
|
isDownloading = false;
|
||||||
|
}
|
||||||
|
if (!isDownloading && dest->IsReady ())
|
||||||
{
|
{
|
||||||
if (!m_IsLoaded)
|
if (!m_IsLoaded)
|
||||||
{
|
{
|
||||||
|
@ -709,17 +721,15 @@ namespace client
|
||||||
std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL);
|
std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL);
|
||||||
if (!m_DefaultSubscription)
|
if (!m_DefaultSubscription)
|
||||||
m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, defaultSubURL);
|
m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, defaultSubURL);
|
||||||
m_IsDownloading = true;
|
m_Downloading = std::async (std::launch::async,
|
||||||
std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
|
std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
|
||||||
load_hosts.detach(); // TODO: use join
|
|
||||||
}
|
}
|
||||||
else if (!m_Subscriptions.empty ())
|
else if (!m_Subscriptions.empty ())
|
||||||
{
|
{
|
||||||
// pick random subscription
|
// pick random subscription
|
||||||
auto ind = rand () % m_Subscriptions.size();
|
auto ind = rand () % m_Subscriptions.size();
|
||||||
m_IsDownloading = true;
|
m_Downloading = std::async (std::launch::async,
|
||||||
std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
|
std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
|
||||||
load_hosts.detach(); // TODO: use join
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -823,7 +833,7 @@ namespace client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link):
|
AddressBookSubscription::AddressBookSubscription (AddressBook& book, std::string_view link):
|
||||||
m_Book (book), m_Link (link)
|
m_Book (book), m_Link (link)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <future>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
|
@ -124,7 +126,8 @@ namespace client
|
||||||
std::mutex m_LookupsMutex;
|
std::mutex m_LookupsMutex;
|
||||||
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
|
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
|
||||||
AddressBookStorage * m_Storage;
|
AddressBookStorage * m_Storage;
|
||||||
volatile bool m_IsLoaded, m_IsDownloading;
|
volatile bool m_IsLoaded;
|
||||||
|
std::future<void> m_Downloading;
|
||||||
int m_NumRetries;
|
int m_NumRetries;
|
||||||
std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
|
std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
|
||||||
std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
|
std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
|
||||||
|
@ -136,7 +139,7 @@ namespace client
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AddressBookSubscription (AddressBook& book, const std::string& link);
|
AddressBookSubscription (AddressBook& book, std::string_view link);
|
||||||
void CheckUpdates ();
|
void CheckUpdates ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -421,7 +421,9 @@ namespace client
|
||||||
{ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, "3" },
|
{ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, "3" },
|
||||||
{ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" },
|
{ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" },
|
||||||
{ I2CP_PARAM_LEASESET_TYPE, "3" },
|
{ I2CP_PARAM_LEASESET_TYPE, "3" },
|
||||||
{ I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4" }
|
{ I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "0,4" },
|
||||||
|
{ I2CP_PARAM_OUTBOUND_NICKNAME, "SharedDest" },
|
||||||
|
{ I2CP_PARAM_STREAMING_PROFILE, "2" }
|
||||||
};
|
};
|
||||||
m_SharedLocalDestination = CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
m_SharedLocalDestination = CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, ¶ms); // non-public, EDDSA
|
i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, ¶ms); // non-public, EDDSA
|
||||||
|
@ -473,6 +475,7 @@ namespace client
|
||||||
options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
|
options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
|
||||||
options[I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED);
|
options[I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED);
|
||||||
options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED);
|
options[I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED);
|
||||||
|
options[I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS, DEFAULT_MAX_CONCURRENT_STREAMS);
|
||||||
options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false);
|
options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false);
|
||||||
options[I2CP_PARAM_STREAMING_PROFILE] = GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE);
|
options[I2CP_PARAM_STREAMING_PROFILE] = GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE);
|
||||||
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
||||||
|
@ -595,6 +598,11 @@ namespace client
|
||||||
std::map<std::string, std::string> options;
|
std::map<std::string, std::string> options;
|
||||||
ReadI2CPOptions (section, false, options);
|
ReadI2CPOptions (section, false, options);
|
||||||
|
|
||||||
|
// Set I2CP name if not set
|
||||||
|
auto itopt = options.find (I2CP_PARAM_OUTBOUND_NICKNAME);
|
||||||
|
if (itopt == options.end ())
|
||||||
|
options[I2CP_PARAM_OUTBOUND_NICKNAME] = name;
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
if (keys.length () > 0)
|
if (keys.length () > 0)
|
||||||
{
|
{
|
||||||
|
@ -749,6 +757,11 @@ namespace client
|
||||||
std::map<std::string, std::string> options;
|
std::map<std::string, std::string> options;
|
||||||
ReadI2CPOptions (section, true, options);
|
ReadI2CPOptions (section, true, options);
|
||||||
|
|
||||||
|
// Set I2CP name if not set
|
||||||
|
auto itopt = options.find (I2CP_PARAM_INBOUND_NICKNAME);
|
||||||
|
if (itopt == options.end ())
|
||||||
|
options[I2CP_PARAM_INBOUND_NICKNAME] = name;
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
auto it = destinations.find (keys);
|
auto it = destinations.find (keys);
|
||||||
if (it != destinations.end ())
|
if (it != destinations.end ())
|
||||||
|
@ -896,6 +909,7 @@ namespace client
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
ReadI2CPOptionsFromConfig ("httpproxy.", params);
|
ReadI2CPOptionsFromConfig ("httpproxy.", params);
|
||||||
|
params[I2CP_PARAM_OUTBOUND_NICKNAME] = "HTTPProxy";
|
||||||
localDestination = CreateNewLocalDestination (keys, false, ¶ms);
|
localDestination = CreateNewLocalDestination (keys, false, ¶ms);
|
||||||
if (localDestination) localDestination->Acquire ();
|
if (localDestination) localDestination->Acquire ();
|
||||||
}
|
}
|
||||||
|
@ -944,6 +958,7 @@ namespace client
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
ReadI2CPOptionsFromConfig ("socksproxy.", params);
|
ReadI2CPOptionsFromConfig ("socksproxy.", params);
|
||||||
|
params[I2CP_PARAM_OUTBOUND_NICKNAME] = "SOCKSProxy";
|
||||||
localDestination = CreateNewLocalDestination (keys, false, ¶ms);
|
localDestination = CreateNewLocalDestination (keys, false, ¶ms);
|
||||||
if (localDestination) localDestination->Acquire ();
|
if (localDestination) localDestination->Acquire ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,6 @@ set(test-gost-sig_SRCS
|
||||||
test-gost-sig.cpp
|
test-gost-sig.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(test-x25519_SRCS
|
|
||||||
test-x25519.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(test-aeadchacha20poly1305_SRCS
|
set(test-aeadchacha20poly1305_SRCS
|
||||||
test-aeadchacha20poly1305.cpp
|
test-aeadchacha20poly1305.cpp
|
||||||
)
|
)
|
||||||
|
@ -77,7 +73,6 @@ add_executable(test-http-url ${test-http-url_SRCS})
|
||||||
add_executable(test-base-64 ${test-base-64_SRCS})
|
add_executable(test-base-64 ${test-base-64_SRCS})
|
||||||
add_executable(test-gost ${test-gost_SRCS})
|
add_executable(test-gost ${test-gost_SRCS})
|
||||||
add_executable(test-gost-sig ${test-gost-sig_SRCS})
|
add_executable(test-gost-sig ${test-gost-sig_SRCS})
|
||||||
add_executable(test-x25519 ${test-x25519_SRCS})
|
|
||||||
add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS})
|
add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS})
|
||||||
add_executable(test-blinding ${test-blinding_SRCS})
|
add_executable(test-blinding ${test-blinding_SRCS})
|
||||||
add_executable(test-elligator ${test-elligator_SRCS})
|
add_executable(test-elligator ${test-elligator_SRCS})
|
||||||
|
@ -102,7 +97,6 @@ target_link_libraries(test-http-url ${LIBS})
|
||||||
target_link_libraries(test-base-64 ${LIBS})
|
target_link_libraries(test-base-64 ${LIBS})
|
||||||
target_link_libraries(test-gost ${LIBS})
|
target_link_libraries(test-gost ${LIBS})
|
||||||
target_link_libraries(test-gost-sig ${LIBS})
|
target_link_libraries(test-gost-sig ${LIBS})
|
||||||
target_link_libraries(test-x25519 ${LIBS})
|
|
||||||
target_link_libraries(test-aeadchacha20poly1305 ${LIBS})
|
target_link_libraries(test-aeadchacha20poly1305 ${LIBS})
|
||||||
target_link_libraries(test-blinding ${LIBS})
|
target_link_libraries(test-blinding ${LIBS})
|
||||||
target_link_libraries(test-elligator ${LIBS})
|
target_link_libraries(test-elligator ${LIBS})
|
||||||
|
@ -116,7 +110,6 @@ add_test(test-http-url ${TEST_PATH}/test-http-url)
|
||||||
add_test(test-base-64 ${TEST_PATH}/test-base-64)
|
add_test(test-base-64 ${TEST_PATH}/test-base-64)
|
||||||
add_test(test-gost ${TEST_PATH}/test-gost)
|
add_test(test-gost ${TEST_PATH}/test-gost)
|
||||||
add_test(test-gost-sig ${TEST_PATH}/test-gost-sig)
|
add_test(test-gost-sig ${TEST_PATH}/test-gost-sig)
|
||||||
add_test(test-x25519 ${TEST_PATH}/test-x25519)
|
|
||||||
add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305)
|
add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305)
|
||||||
add_test(test-blinding ${TEST_PATH}/test-blinding)
|
add_test(test-blinding ${TEST_PATH}/test-blinding)
|
||||||
add_test(test-elligator ${TEST_PATH}/test-elligator)
|
add_test(test-elligator ${TEST_PATH}/test-elligator)
|
||||||
|
|
|
@ -7,7 +7,7 @@ LIBI2PD = ../libi2pd.a
|
||||||
|
|
||||||
TESTS = \
|
TESTS = \
|
||||||
test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \
|
test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \
|
||||||
test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding \
|
test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \
|
||||||
test-elligator test-eddsa
|
test-elligator test-eddsa
|
||||||
|
|
||||||
ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
|
ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
|
||||||
|
@ -44,9 +44,6 @@ test-gost: test-gost.cpp $(LIBI2PD)
|
||||||
test-gost-sig: test-gost-sig.cpp $(LIBI2PD)
|
test-gost-sig: test-gost-sig.cpp $(LIBI2PD)
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
test-x25519: test-x25519.cpp $(LIBI2PD)
|
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
|
||||||
|
|
||||||
test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD)
|
test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD)
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include <cassert>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "Ed25519.h"
|
|
||||||
|
|
||||||
const uint8_t k[32] =
|
|
||||||
{
|
|
||||||
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
|
|
||||||
0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
|
|
||||||
0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t u[32] =
|
|
||||||
{
|
|
||||||
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
|
|
||||||
0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
|
|
||||||
0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t p[32] =
|
|
||||||
{
|
|
||||||
0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea,
|
|
||||||
0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c,
|
|
||||||
0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52
|
|
||||||
};
|
|
||||||
|
|
||||||
int main ()
|
|
||||||
{
|
|
||||||
#if !OPENSSL_X25519
|
|
||||||
// we test it for openssl < 1.1.0
|
|
||||||
uint8_t buf[32];
|
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
|
||||||
i2p::crypto::GetEd25519 ()->ScalarMul (u, k, buf, ctx);
|
|
||||||
BN_CTX_free (ctx);
|
|
||||||
assert(memcmp (buf, p, 32) == 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
Loading…
Reference in a new issue