Compare commits

...

11 Commits

Author SHA1 Message Date
self-related
78dc1b6839 Merge 32a70562c4 into f79a2e81ff 2024-12-05 04:42:46 +00: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
31ff0ff1cb use weak_ptr for transport session 2024-11-29 21:29:03 -05:00
orignal
fcc70025fd use reference instead naked pointer to tunnel in tunnel gateway 2024-11-29 11:31:13 -05:00
orignal
56145d0f3c bind tunnel gateway to transport session 2024-11-28 21:56:26 -05:00
self-related
32a70562c4 Fix UPnP: error 2 2024-08-19 00:07:22 +03:00
12 changed files with 185 additions and 102 deletions

View File

@@ -231,7 +231,7 @@ jobs:
cd MINGW-packages/mingw-w64-boost
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- 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
- name: Build application

View File

@@ -122,7 +122,7 @@ namespace transport
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
#endif
m_upnpUrlsInitialized=err!=0;
if (err == UPNP_IGD_VALID_CONNECTED)
if (err == UPNP_IGD_VALID_CONNECTED || err == UPNP_IGD_VALID_NOT_CONNECTED)
{
#if (MINIUPNPC_API_VERSION < 18)
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);

View File

@@ -42,28 +42,29 @@ namespace transport
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);
// h = SHA256(h || epub)
MixHash (epub, 32);
// x25519 between pub and priv
uint8_t inputKeyMaterial[32];
priv.Agree (pub, inputKeyMaterial);
if (!priv.Agree (pub, inputKeyMaterial)) return false;
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
@@ -74,33 +75,35 @@ namespace transport
// x25519 between remote pub and ephemaral priv
uint8_t inputKeyMaterial[32];
m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial);
if (!m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial)) return false;
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];
i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
if (!i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial)) return false;
MixKey (inputKeyMaterial);
return true;
}
void NTCP2Establisher::KDF3Bob ()
bool NTCP2Establisher::KDF3Bob ()
{
uint8_t inputKeyMaterial[32];
m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial);
if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial)) return false;
MixKey (inputKeyMaterial);
return true;
}
void NTCP2Establisher::CreateEphemeralKey ()
@@ -108,7 +111,7 @@ namespace transport
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
}
void NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng)
bool NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng)
{
// create buffer and fill padding
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.GetIV (m_IV); // save IV for SessionCreated
// encryption key for next block
KDF1Alice ();
if (!KDF1Alice ()) return false;
// fill options
uint8_t options[32]; // actual options size is 16 bytes
memset (options, 0, 16);
@@ -147,9 +150,10 @@ namespace transport
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
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);
m_SessionCreatedBufferLen = paddingLen + 64;
@@ -160,7 +164,7 @@ namespace transport
encryption.SetIV (m_IV);
encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y
// encryption key for next block (m_K)
KDF2Bob ();
if (!KDF2Bob ()) return false;
uint8_t options[16];
memset (options, 0, 16);
htobe16buf (options + 2, paddingLen); // padLen
@@ -169,7 +173,7 @@ namespace transport
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt
return true;
}
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
}
void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce)
bool NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce)
{
// part 2
// update AD again
MixHash (m_SessionConfirmedBuffer, 48);
// encrypt m3p2, it must be filled in SessionRequest
KDF3Alice ();
if (!KDF3Alice ()) return false;
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt
// update h again
MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
return true;
}
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew)
@@ -207,7 +212,11 @@ namespace transport
decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ());
decryption.GetIV (m_IV); // save IV for SessionCreated
// 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
uint8_t nonce[12], options[16];
memset (nonce, 0, 12); // set nonce to zero
@@ -262,7 +271,11 @@ namespace transport
decryption.SetIV (m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
// decryption key for next block (m_K)
KDF2Alice ();
if (!KDF2Alice ())
{
LogPrint (eLogWarning, "NTCP2: SessionCreated KDF failed");
return false;
}
// decrypt and verify MAC
uint8_t payload[16];
uint8_t nonce[12];
@@ -309,7 +322,11 @@ namespace transport
// update AD again
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
// calculate new h again for KDF data
MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
@@ -466,7 +483,12 @@ namespace transport
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
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 (),
@@ -558,7 +580,12 @@ namespace transport
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
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 (),
@@ -637,7 +664,12 @@ namespace transport
CreateNonce (1, nonce); // set nonce to 1
m_Establisher->CreateSessionConfirmedMessagePart1 (nonce);
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
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));
@@ -708,15 +740,8 @@ namespace transport
memset (nonce, 0, 12); // set nonce to 0 again
if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) // TODO:handle in establisher 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);
// payload
// process RI
// payload
// RI block must be first
if (buf[0] != eNTCP2BlkRouterInfo)
{
LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed");
@@ -793,12 +818,20 @@ namespace transport
SendTerminationAndTerminate (eNTCP2Banned);
return;
}
// TODO: process options
// TODO: process options block
// ready to communicate
SetRemoteIdentity (ri1->GetRouterIdentity ());
if (m_Server.AddNTCP2Session (shared_from_this (), true))
{
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);
Established ();
ReceiveLength ();
}

View File

@@ -95,21 +95,21 @@ namespace transport
const uint8_t * GetCK () const { return m_CK; };
const uint8_t * GetH () const { return m_H; };
void KDF1Alice ();
void KDF1Bob ();
void KDF2Alice ();
void KDF2Bob ();
void KDF3Alice (); // for SessionConfirmed part 2
void KDF3Bob ();
bool KDF1Alice ();
bool KDF1Bob ();
bool KDF2Alice ();
bool KDF2Bob ();
bool KDF3Alice (); // for SessionConfirmed part 2
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
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
bool KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
bool KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
void CreateEphemeralKey ();
void CreateSessionRequestMessage (std::mt19937& rng);
void CreateSessionCreatedMessage (std::mt19937& rng);
bool CreateSessionRequestMessage (std::mt19937& rng);
bool CreateSessionCreatedMessage (std::mt19937& rng);
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 ProcessSessionCreatedMessage (uint16_t& paddingLen);

View File

@@ -73,7 +73,7 @@ namespace tunnel
const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {};
layerKey, ivKey), m_Gateway(*this) {};
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void FlushTunnelDataMsgs () override;

View File

@@ -447,28 +447,29 @@ namespace transport
return std::max (bwCongestionLevel, tbwCongestionLevel);
}
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
std::future<std::shared_ptr<TransportSession> > Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
{
if (m_IsOnline)
SendMessages (ident, { msg });
return SendMessages (ident, { msg });
return {}; // invalid future
}
void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
std::future<std::shared_ptr<TransportSession> > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{
std::list<std::shared_ptr<i2p::I2NPMessage> > msgs1;
msgs.swap (msgs1);
SendMessages (ident, std::move (msgs1));
return SendMessages (ident, std::move (msgs1));
}
void Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs)
std::future<std::shared_ptr<TransportSession> > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs)
{
boost::asio::post (*m_Service, [this, ident, msgs = std::move(msgs)] () mutable
return boost::asio::post (*m_Service, boost::asio::use_future ([this, ident, msgs = std::move(msgs)] () mutable
{
PostMessages (ident, msgs);
});
return PostMessages (ident, msgs);
}));
}
void Transports::PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
std::shared_ptr<TransportSession> Transports::PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
{
@@ -476,9 +477,9 @@ namespace transport
for (auto& it: msgs)
m_LoopbackHandler.PutNextMessage (std::move (it));
m_LoopbackHandler.Flush ();
return;
return nullptr;
}
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return;
if(RoutesRestricted() && !IsRestrictedPeer(ident)) return nullptr;
std::shared_ptr<Peer> peer;
{
std::lock_guard<std::mutex> l(m_PeersMutex);
@@ -489,13 +490,13 @@ namespace transport
if (!peer)
{
// check if not banned
if (i2p::data::IsRouterBanned (ident)) return; // don't create peer to unreachable router
if (i2p::data::IsRouterBanned (ident)) return nullptr; // don't create peer to unreachable router
// try to connect
bool connected = false;
try
{
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 nullptr; // router found but non-reachable
peer = std::make_shared<Peer>(r, i2p::util::GetSecondsSinceEpoch ());
{
@@ -509,12 +510,16 @@ namespace transport
{
LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ());
}
if (!connected) return;
if (!connected) return nullptr;
}
if (!peer) return;
if (!peer) return nullptr;
if (peer->IsConnected ())
peer->sessions.front ()->SendI2NPMessages (msgs);
{
auto session = peer->sessions.front ();
if (session) session->SendI2NPMessages (msgs);
return session;
}
else
{
auto sz = peer->delayedMessages.size ();
@@ -527,7 +532,7 @@ namespace transport
LogPrint (eLogWarning, "Transports: Router ", ident.ToBase64 (), " is banned. Peer dropped");
std::lock_guard<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
return;
return nullptr;
}
}
if (sz > MAX_NUM_DELAYED_MESSAGES/2)
@@ -549,6 +554,7 @@ namespace transport
m_Peers.erase (ident);
}
}
return nullptr;
}
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, std::shared_ptr<Peer> peer)

View File

@@ -11,6 +11,7 @@
#include <thread>
#include <mutex>
#include <future>
#include <condition_variable>
#include <functional>
#include <unordered_map>
@@ -143,9 +144,9 @@ namespace transport
std::shared_ptr<i2p::crypto::X25519Keys> GetNextX25519KeysPair ();
void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair);
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
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);
std::future<std::shared_ptr<TransportSession> > SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
std::future<std::shared_ptr<TransportSession> > SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
std::future<std::shared_ptr<TransportSession> > SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs);
void PeerConnected (std::shared_ptr<TransportSession> session);
void PeerDisconnected (std::shared_ptr<TransportSession> session);
@@ -189,7 +190,7 @@ namespace transport
void Run ();
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 PostMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
std::shared_ptr<TransportSession> 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);
void SetPriority (std::shared_ptr<Peer> peer) const;
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);

View File

@@ -139,7 +139,7 @@ namespace tunnel
public:
OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
Tunnel (config), m_Gateway (*this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
void SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
virtual void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs); // multiple messages

View File

@@ -220,21 +220,55 @@ namespace tunnel
void TunnelGateway::SendBuffer ()
{
// create list or tunnel messages
m_Buffer.CompleteCurrentTunnelDataMessage ();
std::list<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
for (auto& tunnelMsg : tunnelDataMsgs)
{
auto newMsg = CreateEmptyTunnelDataMsg (false);
m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg);
htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ());
m_Tunnel.EncryptTunnelMsg (tunnelMsg, newMsg);
htobe32buf (newMsg->GetPayload (), m_Tunnel.GetNextTunnelID ());
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
if (tunnelMsg->onDrop) newMsg->onDrop = tunnelMsg->onDrop;
newTunnelMsgs.push_back (newMsg);
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
}
m_Buffer.ClearTunnelDataMsgs ();
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), std::move (newTunnelMsgs));
// send
auto currentTransport = m_CurrentTransport.lock ();
if (!currentTransport)
{
// try to obtain transport from peding reequest or send thought transport is not complete
if (m_PendingTransport.valid ()) // pending request?
{
if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
// pending request complete
currentTransport = m_PendingTransport.get (); // take tarnsports used in pending request
if (currentTransport)
{
if (currentTransport->IsEstablished ())
m_CurrentTransport = currentTransport;
else
currentTransport = nullptr;
}
}
else // still pending
{
// send through transports, but don't update pedning transport
i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs));
return;
}
}
}
if (currentTransport) // session is good
// send to session directly
currentTransport->SendI2NPMessages (newTunnelMsgs);
else // no session yet
// send through transports
m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs));
}
}
}

View File

@@ -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
*
@@ -12,7 +12,9 @@
#include <inttypes.h>
#include <vector>
#include <memory>
#include <future>
#include "I2NPProtocol.h"
#include "TransportSession.h"
#include "TunnelBase.h"
namespace i2p
@@ -45,7 +47,7 @@ namespace tunnel
{
public:
TunnelGateway (TunnelBase * tunnel):
TunnelGateway (TunnelBase& tunnel):
m_Tunnel (tunnel), m_NumSentBytes (0) {};
void SendTunnelDataMsg (const TunnelMessageBlock& block);
void PutTunnelDataMsg (const TunnelMessageBlock& block);
@@ -54,9 +56,11 @@ namespace tunnel
private:
TunnelBase * m_Tunnel;
TunnelBase& m_Tunnel;
TunnelGatewayBuffer m_Buffer;
size_t m_NumSentBytes;
std::weak_ptr<i2p::transport::TransportSession> m_CurrentTransport;
std::future<std::shared_ptr<i2p::transport::TransportSession> > m_PendingTransport;
};
}
}

View File

@@ -375,10 +375,10 @@ namespace client
}
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):
I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host),
m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ())
I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), m_XI2P (XI2P),
m_HeaderSent (false), m_ResponseHeaderSent (false)
{
if (sslCtx)
SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ());
@@ -448,17 +448,12 @@ namespace client
if (!connection)
m_OutHeader << "Connection: close\r\n";
// add X-I2P fields
if (m_From)
{
m_OutHeader << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(m_From->GetIdentHash ()) << "\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_XI2P;
// end of header
m_OutHeader << "\r\n";
m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
m_InHeader.str ("");
m_From = nullptr;
m_HeaderSent = true;
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)
{
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,

View File

@@ -31,9 +31,9 @@ namespace client
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
// for HTTP tunnels
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
const 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_HASH[] = "X-I2P-DestHash"; // hash in base64
constexpr char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
constexpr char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address
const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192;
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
@@ -107,7 +107,7 @@ namespace client
public:
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);
protected:
@@ -117,10 +117,9 @@ namespace client
private:
std::string m_Host;
std::string m_Host, m_XI2P;
std::stringstream m_InHeader, m_OutHeader;
bool m_HeaderSent, m_ResponseHeaderSent;
std::shared_ptr<const i2p::data::IdentityEx> m_From;
};
class I2PTunnelConnectionIRC: public I2PTunnelConnection
@@ -242,7 +241,8 @@ namespace client
private:
std::string m_Host;
std::string m_Host, m_XI2P;
std::weak_ptr<const i2p::data::IdentityEx> m_From;
};
class I2PServerTunnelIRC: public I2PServerTunnel