Compare commits

...

12 Commits

Author SHA1 Message Date
orignal
d610e6c4c1 Merge pull request #2132 from PurpleI2P/openssl
recent changes
2024-12-06 20:14:40 -05:00
orignal
13604ccbb6 Changing the window calculation algorithm, increasing the minimum window size 2024-12-05 22:15:11 -05:00
orignal
e996db03c0 process SessionConfirmed in establisher's thread 2024-12-05 20:57:40 -05:00
orignal
f79a2e81ff calculate data phase keys after verification 2024-12-04 18:36:57 -05:00
orignal
4b1ac7420c Merge branch 'openssl' of https://github.com/PurpleI2P/i2pd into openssl 2024-12-02 19:06:04 -05:00
orignal
e518b92a89 calculate X_I2P_DEST* headers once for series of HTTP requests 2024-12-02 19:05:12 -05:00
R4SAS
1a32ed9088 [gha] winxp: fix option order 2024-12-03 00:44:14 +03:00
R4SAS
b17bbd754a [gha] winxp: forced overwrite files from boost package 2024-12-03 00:40:30 +03:00
orignal
7b0ff2850c close session if x25519 fails 2024-12-01 16:53:08 -05:00
orignal
35352f1497 Merge pull request #2125 from PurpleI2P/openssl
Recent changes
2024-11-19 18:27:05 -05:00
orignal
e695f1e060 Merge pull request #2118 from PurpleI2P/openssl
recent changes
2024-10-28 20:33:07 -04:00
orignal
ecc635e9bc Merge pull request #2105 from PurpleI2P/openssl
2.54.0
2024-10-08 10:01:35 -04:00
7 changed files with 260 additions and 184 deletions

View File

@@ -231,7 +231,7 @@ jobs:
cd MINGW-packages/mingw-w64-boost cd MINGW-packages/mingw-w64-boost
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- name: Install boost package - name: Install boost package
run: pacman --noconfirm -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst run: pacman --noconfirm -U --overwrite MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst
# Building i2pd # Building i2pd
- name: Build application - name: Build application

View File

@@ -42,28 +42,29 @@ namespace transport
delete[] m_SessionConfirmedBuffer; delete[] m_SessionConfirmedBuffer;
} }
void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub) bool NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub)
{ {
i2p::crypto::InitNoiseXKState (*this, rs); i2p::crypto::InitNoiseXKState (*this, rs);
// h = SHA256(h || epub) // h = SHA256(h || epub)
MixHash (epub, 32); MixHash (epub, 32);
// x25519 between pub and priv // x25519 between pub and priv
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
priv.Agree (pub, inputKeyMaterial); if (!priv.Agree (pub, inputKeyMaterial)) return false;
MixKey (inputKeyMaterial); MixKey (inputKeyMaterial);
return true;
} }
void NTCP2Establisher::KDF1Alice () bool NTCP2Establisher::KDF1Alice ()
{ {
KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ()); return KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ());
} }
void NTCP2Establisher::KDF1Bob () bool NTCP2Establisher::KDF1Bob ()
{ {
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); return KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
} }
void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) bool NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
{ {
MixHash (sessionRequest + 32, 32); // encrypted payload MixHash (sessionRequest + 32, 32); // encrypted payload
@@ -74,33 +75,35 @@ namespace transport
// x25519 between remote pub and ephemaral priv // x25519 between remote pub and ephemaral priv
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial); if (!m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial)) return false;
MixKey (inputKeyMaterial); MixKey (inputKeyMaterial);
return true;
} }
void NTCP2Establisher::KDF2Alice () bool NTCP2Establisher::KDF2Alice ()
{ {
KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ()); return KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ());
} }
void NTCP2Establisher::KDF2Bob () bool NTCP2Establisher::KDF2Bob ()
{ {
KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); return KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ());
} }
void NTCP2Establisher::KDF3Alice () bool NTCP2Establisher::KDF3Alice ()
{ {
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial); if (!i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial)) return false;
MixKey (inputKeyMaterial); MixKey (inputKeyMaterial);
return true;
} }
void NTCP2Establisher::KDF3Bob () bool NTCP2Establisher::KDF3Bob ()
{ {
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial); if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial)) return false;
MixKey (inputKeyMaterial); MixKey (inputKeyMaterial);
return true;
} }
void NTCP2Establisher::CreateEphemeralKey () void NTCP2Establisher::CreateEphemeralKey ()
@@ -108,7 +111,7 @@ namespace transport
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
} }
void NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng) bool NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng)
{ {
// create buffer and fill padding // create buffer and fill padding
auto paddingLength = rng () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes auto paddingLength = rng () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes
@@ -121,7 +124,7 @@ namespace transport
encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X
encryption.GetIV (m_IV); // save IV for SessionCreated encryption.GetIV (m_IV); // save IV for SessionCreated
// encryption key for next block // encryption key for next block
KDF1Alice (); if (!KDF1Alice ()) return false;
// fill options // fill options
uint8_t options[32]; // actual options size is 16 bytes uint8_t options[32]; // actual options size is 16 bytes
memset (options, 0, 16); memset (options, 0, 16);
@@ -147,9 +150,10 @@ namespace transport
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero memset (nonce, 0, 12); // set nonce to zero
i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt
return true;
} }
void NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng) bool NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng)
{ {
auto paddingLen = rng () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64); auto paddingLen = rng () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64);
m_SessionCreatedBufferLen = paddingLen + 64; m_SessionCreatedBufferLen = paddingLen + 64;
@@ -160,7 +164,7 @@ namespace transport
encryption.SetIV (m_IV); encryption.SetIV (m_IV);
encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y
// encryption key for next block (m_K) // encryption key for next block (m_K)
KDF2Bob (); if (!KDF2Bob ()) return false;
uint8_t options[16]; uint8_t options[16];
memset (options, 0, 16); memset (options, 0, 16);
htobe16buf (options + 2, paddingLen); // padLen htobe16buf (options + 2, paddingLen); // padLen
@@ -169,7 +173,7 @@ namespace transport
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero memset (nonce, 0, 12); // set nonce to zero
i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt
return true;
} }
void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce) void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce)
@@ -184,17 +188,18 @@ namespace transport
i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt
} }
void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) bool NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce)
{ {
// part 2 // part 2
// update AD again // update AD again
MixHash (m_SessionConfirmedBuffer, 48); MixHash (m_SessionConfirmedBuffer, 48);
// encrypt m3p2, it must be filled in SessionRequest // encrypt m3p2, it must be filled in SessionRequest
KDF3Alice (); if (!KDF3Alice ()) return false;
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt
// update h again // update h again
MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext) MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
return true;
} }
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew) bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew)
@@ -207,7 +212,11 @@ namespace transport
decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ());
decryption.GetIV (m_IV); // save IV for SessionCreated decryption.GetIV (m_IV); // save IV for SessionCreated
// decryption key for next block // decryption key for next block
KDF1Bob (); if (!KDF1Bob ())
{
LogPrint (eLogWarning, "NTCP2: SessionRequest KDF failed");
return false;
}
// verify MAC and decrypt options block (32 bytes), use m_H as AD // verify MAC and decrypt options block (32 bytes), use m_H as AD
uint8_t nonce[12], options[16]; uint8_t nonce[12], options[16];
memset (nonce, 0, 12); // set nonce to zero memset (nonce, 0, 12); // set nonce to zero
@@ -262,7 +271,11 @@ namespace transport
decryption.SetIV (m_IV); decryption.SetIV (m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ()); decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
// decryption key for next block (m_K) // decryption key for next block (m_K)
KDF2Alice (); if (!KDF2Alice ())
{
LogPrint (eLogWarning, "NTCP2: SessionCreated KDF failed");
return false;
}
// decrypt and verify MAC // decrypt and verify MAC
uint8_t payload[16]; uint8_t payload[16];
uint8_t nonce[12]; uint8_t nonce[12];
@@ -309,7 +322,11 @@ namespace transport
// update AD again // update AD again
MixHash (m_SessionConfirmedBuffer, 48); MixHash (m_SessionConfirmedBuffer, 48);
KDF3Bob (); if (!KDF3Bob ())
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 KDF failed");
return false;
}
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
// calculate new h again for KDF data // calculate new h again for KDF data
MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext) MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
@@ -327,6 +344,7 @@ namespace transport
m_Server (server), m_Socket (m_Server.GetService ()), m_Server (server), m_Socket (m_Server.GetService ()),
m_IsEstablished (false), m_IsTerminated (false), m_IsEstablished (false), m_IsTerminated (false),
m_Establisher (new NTCP2Establisher), m_Establisher (new NTCP2Establisher),
m_SendKey (nullptr), m_ReceiveKey (nullptr),
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH
m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr), m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr),
#else #else
@@ -466,7 +484,12 @@ namespace transport
void NTCP2Session::SendSessionRequest () void NTCP2Session::SendSessionRequest ()
{ {
m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ()); if (!m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ()))
{
LogPrint (eLogWarning, "NTCP2: Send SessionRequest KDF failed");
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
return;
}
// send message // send message
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch (); m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (),
@@ -558,7 +581,12 @@ namespace transport
void NTCP2Session::SendSessionCreated () void NTCP2Session::SendSessionCreated ()
{ {
m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ()); if (!m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ()))
{
LogPrint (eLogWarning, "NTCP2: Send SessionCreated KDF failed");
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
return;
}
// send message // send message
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch (); m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (),
@@ -637,7 +665,12 @@ namespace transport
CreateNonce (1, nonce); // set nonce to 1 CreateNonce (1, nonce); // set nonce to 1
m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); m_Establisher->CreateSessionConfirmedMessagePart1 (nonce);
memset (nonce, 0, 12); // set nonce back to 0 memset (nonce, 0, 12); // set nonce back to 0
m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); if (!m_Establisher->CreateSessionConfirmedMessagePart2 (nonce))
{
LogPrint (eLogWarning, "NTCP2: Send SessionConfirmed Part2 KDF failed");
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
return;
}
// send message // send message
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@@ -689,6 +722,7 @@ namespace transport
void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
(void) bytes_transferred;
if (ecode) if (ecode)
{ {
LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ());
@@ -697,122 +731,143 @@ namespace transport
else else
{ {
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval; m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); boost::asio::post (m_Server.GetEstablisherService (),
// part 1 [s = shared_from_this ()] ()
uint8_t nonce[12];
CreateNonce (1, nonce);
if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce))
{
// part 2
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
memset (nonce, 0, 12); // set nonce to 0 again
if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) // TODO:handle in establisher thread
{ {
KeyDerivationFunctionDataPhase (); s->ProcessSessionConfirmed ();;
// Bob data phase keys });
m_SendKey = m_Kba;
m_ReceiveKey = m_Kab;
SetSipKeys (m_Sipkeysba, m_Sipkeysab);
memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
// payload
// process RI
if (buf[0] != eNTCP2BlkRouterInfo)
{
LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed");
Terminate ();
return;
}
auto size = bufbe16toh (buf.data () + 1);
if (size > buf.size () - 3 || size > i2p::data::MAX_RI_BUFFER_SIZE + 1)
{
LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
Terminate ();
return;
}
// TODO: check flag
i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
if (ri.IsUnreachable ())
{
LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ());
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
return;
}
LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (),
" (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
{
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
SendTerminationAndTerminate (eNTCP2Message3Error);
return;
}
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
{
LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds");
SendTerminationAndTerminate (eNTCP2Message3Error);
return;
}
// update RouterInfo in netdb
auto ri1 = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); // ri1 points to one from netdb now
if (!ri1)
{
LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb");
Terminate ();
return;
}
std::shared_ptr<i2p::data::RouterProfile> profile; // not null if older
if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ())
{
// received RouterInfo is older than one in netdb
profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile
if (profile && profile->IsDuplicated ())
{
SendTerminationAndTerminate (eNTCP2Banned);
return;
}
}
auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () :
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ());
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
{
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
Terminate ();
return;
}
if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
(!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
{
if (profile) // older router?
profile->Duplicated (); // mark router as duplicated in profile
else
LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ());
SendTerminationAndTerminate (eNTCP2Banned);
return;
}
// TODO: process options
// ready to communicate
SetRemoteIdentity (ri1->GetRouterIdentity ());
if (m_Server.AddNTCP2Session (shared_from_this (), true))
{
Established ();
ReceiveLength ();
}
else
Terminate ();
}
else
Terminate ();
}
else
Terminate ();
} }
} }
void NTCP2Session::ProcessSessionConfirmed ()
{
// run on establisher thread
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
// part 1
uint8_t nonce[12];
CreateNonce (1, nonce);
if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce))
{
// part 2
auto buf = std::make_shared<std::vector<uint8_t> > (m_Establisher->m3p2Len - 16); // -MAC
memset (nonce, 0, 12); // set nonce to 0 again
if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf->data ())) // TODO:handle in establisher thread
{
// payload
// RI block must be first
if ((*buf)[0] != eNTCP2BlkRouterInfo)
{
LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)(*buf)[0], " in SessionConfirmed");
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
return;
}
auto size = bufbe16toh (buf->data () + 1);
if (size > buf->size () - 3 || size > i2p::data::MAX_RI_BUFFER_SIZE + 1)
{
LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
return;
}
boost::asio::post (m_Server.GetService (),
[s = shared_from_this (), buf, size] ()
{
s->EstablishSessionAfterSessionConfirmed (buf, size);
});
}
else
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
}
else
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
}
void NTCP2Session::EstablishSessionAfterSessionConfirmed (std::shared_ptr<std::vector<uint8_t> > buf, size_t size)
{
// run on main NTCP2 thread
KeyDerivationFunctionDataPhase ();
// Bob data phase keys
m_SendKey = m_Kba;
m_ReceiveKey = m_Kab;
SetSipKeys (m_Sipkeysba, m_Sipkeysab);
memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
// we need to set keys for SendTerminationAndTerminate
// TODO: check flag
i2p::data::RouterInfo ri (buf->data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
if (ri.IsUnreachable ())
{
LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ());
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
return;
}
LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (),
" (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
{
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
SendTerminationAndTerminate (eNTCP2Message3Error);
return;
}
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
{
LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds");
SendTerminationAndTerminate (eNTCP2Message3Error);
return;
}
// update RouterInfo in netdb
auto ri1 = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); // ri1 points to one from netdb now
if (!ri1)
{
LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb");
Terminate ();
return;
}
std::shared_ptr<i2p::data::RouterProfile> profile; // not null if older
if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ())
{
// received RouterInfo is older than one in netdb
profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile
if (profile && profile->IsDuplicated ())
{
SendTerminationAndTerminate (eNTCP2Banned);
return;
}
}
auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () :
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ());
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
{
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
Terminate ();
return;
}
if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
(!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
{
if (profile) // older router?
profile->Duplicated (); // mark router as duplicated in profile
else
LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ());
SendTerminationAndTerminate (eNTCP2Banned);
return;
}
// TODO: process options block
// ready to communicate
SetRemoteIdentity (ri1->GetRouterIdentity ());
if (m_Server.AddNTCP2Session (shared_from_this (), true))
{
Established ();
ReceiveLength ();
}
else
Terminate ();
}
void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey) void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey)
{ {
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH

View File

@@ -95,21 +95,21 @@ namespace transport
const uint8_t * GetCK () const { return m_CK; }; const uint8_t * GetCK () const { return m_CK; };
const uint8_t * GetH () const { return m_H; }; const uint8_t * GetH () const { return m_H; };
void KDF1Alice (); bool KDF1Alice ();
void KDF1Bob (); bool KDF1Bob ();
void KDF2Alice (); bool KDF2Alice ();
void KDF2Bob (); bool KDF2Bob ();
void KDF3Alice (); // for SessionConfirmed part 2 bool KDF3Alice (); // for SessionConfirmed part 2
void KDF3Bob (); bool KDF3Bob ();
void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH bool KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate bool KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
void CreateEphemeralKey (); void CreateEphemeralKey ();
void CreateSessionRequestMessage (std::mt19937& rng); bool CreateSessionRequestMessage (std::mt19937& rng);
void CreateSessionCreatedMessage (std::mt19937& rng); bool CreateSessionCreatedMessage (std::mt19937& rng);
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); bool CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew); bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew);
bool ProcessSessionCreatedMessage (uint16_t& paddingLen); bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
@@ -180,7 +180,9 @@ namespace transport
void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void ProcessSessionConfirmed ();
void EstablishSessionAfterSessionConfirmed (std::shared_ptr<std::vector<uint8_t> > buf, size_t size);
// data // data
void ReceiveLength (); void ReceiveLength ();
void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred);

View File

@@ -73,7 +73,7 @@ namespace stream
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
m_Status (eStreamStatusNew), m_IsIncoming (false), 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_DoubleWinIncCounter (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),
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0),
@@ -101,7 +101,7 @@ namespace stream
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
m_Status (eStreamStatusNew), m_IsIncoming (true), 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_DoubleWinIncCounter (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),
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT),
m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0),
@@ -495,6 +495,7 @@ namespace stream
return; return;
} }
int rttSample = INT_MAX; int rttSample = INT_MAX;
int incCounter = 0;
m_IsNAcked = false; m_IsNAcked = false;
m_IsResendNeeded = false; m_IsResendNeeded = false;
int nackCount = packet->GetNACKCount (); int nackCount = packet->GetNACKCount ();
@@ -537,8 +538,7 @@ namespace stream
m_LocalDestination.DeletePacket (sentPacket); m_LocalDestination.DeletePacket (sentPacket);
acknowledged = true; acknowledged = true;
if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK)
if (m_RTT < m_LocalDestination.GetRandom () % INITIAL_RTO) // dirty incCounter++;
m_WindowIncCounter++;
} }
else else
break; break;
@@ -552,7 +552,7 @@ namespace stream
m_SlowRTT2 = rttSample; m_SlowRTT2 = rttSample;
m_PrevRTTSample = rttSample; m_PrevRTTSample = rttSample;
m_Jitter = rttSample / 10; // 10% m_Jitter = rttSample / 10; // 10%
m_Jitter += 5; // for low-latency connections m_Jitter += 15; // for low-latency connections
m_IsFirstRttSample = false; m_IsFirstRttSample = false;
} }
else else
@@ -569,9 +569,23 @@ namespace stream
jitter = m_PrevRTTSample - rttSample; jitter = m_PrevRTTSample - rttSample;
else else
jitter = rttSample / 10; // 10% jitter = rttSample / 10; // 10%
jitter += 5; // for low-latency connections jitter += 15; // for low-latency connections
m_Jitter = (0.05 * jitter) + (1.0 - 0.05) * m_Jitter; m_Jitter = (0.05 * jitter) + (1.0 - 0.05) * m_Jitter;
} }
if (rttSample > m_SlowRTT)
{
incCounter = 0;
m_DoubleWinIncCounter = 1;
}
else if (rttSample < m_SlowRTT)
{
if (m_DoubleWinIncCounter)
{
incCounter = incCounter * 2;
m_DoubleWinIncCounter = 0;
}
}
m_WindowIncCounter = m_WindowIncCounter + incCounter;
// //
// delay-based CC // delay-based CC
if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection
@@ -1297,8 +1311,6 @@ namespace stream
else if (m_IsResendNeeded) // resend packets else if (m_IsResendNeeded) // resend packets
ResendPacket (); ResendPacket ();
// delay-based CC // delay-based CC
else if (!m_IsWinDropped && int(m_SentPackets.size ()) == m_WindowSize) // we sending packets too fast, early detection
ProcessWindowDrop ();
else if (m_WindowSize > int(m_SentPackets.size ())) // send packets else if (m_WindowSize > int(m_SentPackets.size ())) // send packets
SendBuffer (); SendBuffer ();
} }

View File

@@ -19,6 +19,7 @@
#include <mutex> #include <mutex>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Base.h" #include "Base.h"
#include "Gzip.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -54,7 +55,7 @@ namespace stream
const size_t COMPRESSION_THRESHOLD_SIZE = 66; const size_t COMPRESSION_THRESHOLD_SIZE = 66;
const int MAX_NUM_RESEND_ATTEMPTS = 10; const int MAX_NUM_RESEND_ATTEMPTS = 10;
const int INITIAL_WINDOW_SIZE = 10; const int INITIAL_WINDOW_SIZE = 10;
const int MIN_WINDOW_SIZE = 2; const int MIN_WINDOW_SIZE = 3;
const int MAX_WINDOW_SIZE = 512; const int MAX_WINDOW_SIZE = 512;
const double RTT_EWMA_ALPHA = 0.25; const double RTT_EWMA_ALPHA = 0.25;
const double SLOWRTT_EWMA_ALPHA = 0.05; const double SLOWRTT_EWMA_ALPHA = 0.05;
@@ -274,6 +275,7 @@ namespace stream
bool m_IsTimeOutResend; bool m_IsTimeOutResend;
bool m_IsImmediateAckRequested; bool m_IsImmediateAckRequested;
bool m_IsRemoteLeaseChangeInProgress; bool m_IsRemoteLeaseChangeInProgress;
bool m_DoubleWinIncCounter;
StreamingDestination& m_LocalDestination; StreamingDestination& m_LocalDestination;
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity; std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key

View File

@@ -375,10 +375,10 @@ namespace client
} }
I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
const boost::asio::ip::tcp::endpoint& target, const std::string& host, const boost::asio::ip::tcp::endpoint& target, const std::string& host, const std::string& XI2P,
std::shared_ptr<boost::asio::ssl::context> sslCtx): std::shared_ptr<boost::asio::ssl::context> sslCtx):
I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), m_XI2P (XI2P),
m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ()) m_HeaderSent (false), m_ResponseHeaderSent (false)
{ {
if (sslCtx) if (sslCtx)
SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ()); SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ());
@@ -448,17 +448,12 @@ namespace client
if (!connection) if (!connection)
m_OutHeader << "Connection: close\r\n"; m_OutHeader << "Connection: close\r\n";
// add X-I2P fields // add X-I2P fields
if (m_From) m_OutHeader << m_XI2P;
{ // end of header
m_OutHeader << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(m_From->GetIdentHash ()) << "\r\n"; m_OutHeader << "\r\n";
m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n";
m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n";
}
m_OutHeader << "\r\n"; // end of header
m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
m_InHeader.str (""); m_InHeader.str ("");
m_From = nullptr;
m_HeaderSent = true; m_HeaderSent = true;
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
} }
@@ -876,7 +871,17 @@ namespace client
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream) std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{ {
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream, GetEndpoint (), m_Host, GetSSLCtx ()); if (m_XI2P.empty () || stream->GetRemoteIdentity () != m_From.lock ())
{
auto from = stream->GetRemoteIdentity ();
m_From = from;
std::stringstream ss;
ss << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(from->GetIdentHash ()) << "\r\n";
ss << X_I2P_DEST_HASH << ": " << from->GetIdentHash ().ToBase64 () << "\r\n";
ss << X_I2P_DEST_B64 << ": " << from->ToBase64 () << "\r\n";
m_XI2P = ss.str ();
}
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream, GetEndpoint (), m_Host, m_XI2P, GetSSLCtx ());
} }
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,

View File

@@ -31,9 +31,9 @@ namespace client
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
// for HTTP tunnels // for HTTP tunnels
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64 constexpr char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64 constexpr char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address constexpr char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address
const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192; const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192;
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection> class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
@@ -107,7 +107,7 @@ namespace client
public: public:
I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
const boost::asio::ip::tcp::endpoint& target, const std::string& host, const boost::asio::ip::tcp::endpoint& target, const std::string& host, const std::string& XI2P,
std::shared_ptr<boost::asio::ssl::context> sslCtx = nullptr); std::shared_ptr<boost::asio::ssl::context> sslCtx = nullptr);
protected: protected:
@@ -117,10 +117,9 @@ namespace client
private: private:
std::string m_Host; std::string m_Host, m_XI2P;
std::stringstream m_InHeader, m_OutHeader; std::stringstream m_InHeader, m_OutHeader;
bool m_HeaderSent, m_ResponseHeaderSent; bool m_HeaderSent, m_ResponseHeaderSent;
std::shared_ptr<const i2p::data::IdentityEx> m_From;
}; };
class I2PTunnelConnectionIRC: public I2PTunnelConnection class I2PTunnelConnectionIRC: public I2PTunnelConnection
@@ -242,7 +241,8 @@ namespace client
private: private:
std::string m_Host; std::string m_Host, m_XI2P;
std::weak_ptr<const i2p::data::IdentityEx> m_From;
}; };
class I2PServerTunnelIRC: public I2PServerTunnel class I2PServerTunnelIRC: public I2PServerTunnel